si.c revision 105215
110015Speter/* 212496Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 310015Speter * 434832Speter * Copyright (C) 1990, 1992, 1998 Specialix International, 510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 656505Speter * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au> 710015Speter * 810015Speter * Originally derived from: SunOS 4.x version 910015Speter * Ported from BSDI version to FreeBSD by Peter Wemm. 1010015Speter * 1110015Speter * Redistribution and use in source and binary forms, with or without 1210015Speter * modification, are permitted provided that the following conditions 1310015Speter * are met: 1410015Speter * 1. Redistributions of source code must retain the above copyright 1510015Speter * notices, this list of conditions and the following disclaimer. 1610015Speter * 2. Redistributions in binary form must reproduce the above copyright 1710015Speter * notices, this list of conditions and the following disclaimer in the 1810015Speter * documentation and/or other materials provided with the distribution. 1910015Speter * 3. All advertising materials mentioning features or use of this software 2010015Speter * must display the following acknowledgement: 2110015Speter * This product includes software developed by Andy Rutter of 2210015Speter * Advanced Methods and Tools Ltd. based on original information 2310015Speter * from Specialix International. 2410015Speter * 4. Neither the name of Advanced Methods and Tools, nor Specialix 2510015Speter * International may be used to endorse or promote products derived from 2610015Speter * this software without specific prior written permission. 2710015Speter * 2810015Speter * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 2910015Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 3010015Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 3110015Speter * NO EVENT SHALL THE AUTHORS BE LIABLE. 3210015Speter * 3350477Speter * $FreeBSD: head/sys/dev/si/si.c 105215 2002-10-16 08:48:39Z phk $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3734832Speterstatic const char si_copyright1[] = "@(#) Copyright (C) Specialix International, 1990,1992,1998", 3834832Speter si_copyright2[] = "@(#) Copyright (C) Andy Rutter 1993", 3956505Speter si_copyright3[] = "@(#) Copyright (C) Peter Wemm 2000"; 4010015Speter#endif /* not lint */ 4110015Speter 4231778Seivind#include "opt_compat.h" 4332929Seivind#include "opt_debug_si.h" 4431778Seivind 4510015Speter#include <sys/param.h> 4610015Speter#include <sys/systm.h> 4724207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 4824207Sbde#include <sys/ioctl_compat.h> 4924207Sbde#endif 5010015Speter#include <sys/tty.h> 5110015Speter#include <sys/conf.h> 5224131Sbde#include <sys/fcntl.h> 5310015Speter#include <sys/dkstat.h> 5410015Speter#include <sys/kernel.h> 5510015Speter#include <sys/malloc.h> 5615683Speter#include <sys/sysctl.h> 5756498Speter#include <sys/bus.h> 5856498Speter#include <machine/bus.h> 5956498Speter#include <sys/rman.h> 6056498Speter#include <machine/resource.h> 6110015Speter 6210015Speter 6312659Sbde#include <vm/vm.h> 6412662Sdg#include <vm/pmap.h> 6512659Sbde 6613353Speter#include <machine/stdarg.h> 6710015Speter 6856498Speter#include <dev/si/sireg.h> 6956505Speter#include <dev/si/sivar.h> 7056498Speter#include <dev/si/si.h> 7156498Speter 7210015Speter/* 7310015Speter * This device driver is designed to interface the Specialix International 7434832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 7534832Speter * EISA or PCI bus machine. 7610015Speter * 7734832Speter * The controller is interfaced to the host via dual port RAM 7834832Speter * and an interrupt. 7933395Speter * 8034832Speter * The code for the Host 1 (very old ISA cards) has not been tested. 8110015Speter */ 8210015Speter 8317547Speter#define POLL /* turn on poller to scan for lost interrupts */ 8417547Speter#define REALPOLL /* on each poll, scan for work regardless */ 8517547Speter#define POLLHZ (hz/10) /* 10 times per second */ 8612496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8734832Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 8834832Speter#define JET_INT_COUNT 100 /* max of 100 ints per second */ 8915639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 9010015Speter 9110015Speterenum si_mctl { GET, SET, BIS, BIC }; 9210015Speter 9356498Speterstatic void si_command(struct si_port *, int, int); 9456498Speterstatic int si_modem(struct si_port *, enum si_mctl, int); 9556498Speterstatic void si_write_enable(struct si_port *, int); 9683366Sjulianstatic int si_Sioctl(dev_t, u_long, caddr_t, int, struct thread *); 9756498Speterstatic void si_start(struct tty *); 9856498Speterstatic void si_stop(struct tty *, int); 9925047Sbdestatic timeout_t si_lstart; 10056498Speterstatic void si_disc_optim(struct tty *tp, struct termios *t,struct si_port *pp); 10156498Speterstatic void sihardclose(struct si_port *pp); 10256498Speterstatic void sidtrwakeup(void *chan); 10310015Speter 10456505Speter#ifdef SI_DEBUG 10556505Speterstatic char *si_mctl2str(enum si_mctl cmd); 10656505Speter#endif 10756505Speter 10856498Speterstatic int siparam(struct tty *, struct termios *); 10910015Speter 11056498Speterstatic void si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip); 11156498Speterstatic char * si_modulename(int host_type, int uart_type); 11210708Speter 11312675Sjulianstatic d_open_t siopen; 11412675Sjulianstatic d_close_t siclose; 11512675Sjulianstatic d_write_t siwrite; 11612675Sjulianstatic d_ioctl_t siioctl; 11712675Sjulian 11838485Sbde#define CDEV_MAJOR 68 11947625Sphkstatic struct cdevsw si_cdevsw = { 12047625Sphk /* open */ siopen, 12147625Sphk /* close */ siclose, 12251756Sphk /* read */ ttyread, 12347625Sphk /* write */ siwrite, 12447625Sphk /* ioctl */ siioctl, 12551654Sphk /* poll */ ttypoll, 12647625Sphk /* mmap */ nommap, 12747625Sphk /* strategy */ nostrategy, 12847625Sphk /* name */ "si", 12947625Sphk /* maj */ CDEV_MAJOR, 13047625Sphk /* dump */ nodump, 13147625Sphk /* psize */ nopsize, 13272521Sjlemon /* flags */ D_TTY | D_KQFILTER, 13372521Sjlemon /* kqfilter */ ttykqfilter, 13438485Sbde}; 13512675Sjulian 13610962Speterstatic int si_Nports; 13710962Speterstatic int si_Nmodules; 13810962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 13910015Speter 14034832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 141100743SpeterTUNABLE_INT("machdep.si_debug", &si_debug); 14234832Speter 14356498Speterstatic int si_numunits; 14410044Speter 14556505Speterdevclass_t si_devclass; 14656498Speter 14712174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 14810015Speter# define B2000 2000 14910015Speter#endif 15010015Speterstatic struct speedtab bdrates[] = { 15150442Speter { B75, CLK75, }, /* 0x0 */ 15250442Speter { B110, CLK110, }, /* 0x1 */ 15350442Speter { B150, CLK150, }, /* 0x3 */ 15450442Speter { B300, CLK300, }, /* 0x4 */ 15550442Speter { B600, CLK600, }, /* 0x5 */ 15650442Speter { B1200, CLK1200, }, /* 0x6 */ 15750442Speter { B2000, CLK2000, }, /* 0x7 */ 15850442Speter { B2400, CLK2400, }, /* 0x8 */ 15950442Speter { B4800, CLK4800, }, /* 0x9 */ 16050442Speter { B9600, CLK9600, }, /* 0xb */ 16150442Speter { B19200, CLK19200, }, /* 0xc */ 16250442Speter { B38400, CLK38400, }, /* 0x2 (out of order!) */ 16350442Speter { B57600, CLK57600, }, /* 0xd */ 16450442Speter { B115200, CLK110, }, /* 0x1 (dupe!, 110 baud on "si") */ 16550442Speter { -1, -1 }, 16610015Speter}; 16710015Speter 16810015Speter 16910015Speter/* populated with approx character/sec rates - translated at card 17010015Speter * initialisation time to chars per tick of the clock */ 17110015Speterstatic int done_chartimes = 0; 17210015Speterstatic struct speedtab chartimes[] = { 17350442Speter { B75, 8, }, 17450442Speter { B110, 11, }, 17550442Speter { B150, 15, }, 17650442Speter { B300, 30, }, 17750442Speter { B600, 60, }, 17850442Speter { B1200, 120, }, 17950442Speter { B2000, 200, }, 18050442Speter { B2400, 240, }, 18150442Speter { B4800, 480, }, 18250442Speter { B9600, 960, }, 18350442Speter { B19200, 1920, }, 18450442Speter { B38400, 3840, }, 18550442Speter { B57600, 5760, }, 18650442Speter { B115200, 11520, }, 18750442Speter { -1, -1 }, 18810015Speter}; 18910015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 19010015Speter 19110015Speter#ifdef POLL 19215683Speterstatic int si_pollrate; /* in addition to irq */ 19356498Speterstatic int si_realpoll = 0; /* poll HW on timer */ 19415639Speter 19516403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 19617547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 19750442Speter 19810015Speterstatic int init_finished = 0; 19956498Speterstatic void si_poll(void *); 20010015Speter#endif 20110015Speter 20210015Speter/* 20310015Speter * Array of adapter types and the corresponding RAM size. The order of 20410015Speter * entries here MUST match the ordinal of the adapter type. 20510015Speter */ 20610015Speterstatic char *si_type[] = { 20710015Speter "EMPTY", 20810015Speter "SIHOST", 20934832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 21010015Speter "SIHOST2", 21110015Speter "SIEISA", 21233395Speter "SIPCI", 21333395Speter "SXPCI", 21433395Speter "SXISA", 21510015Speter}; 21610015Speter 21756498Speter/* 21856498Speter * We have to make an 8 bit version of bcopy, since some cards can't 21956498Speter * deal with 32 bit I/O 22056498Speter */ 22156498Speterstatic void __inline 22256498Spetersi_bcopy(const void *src, void *dst, size_t len) 22356498Speter{ 22456498Speter while (len--) 22556498Speter *(((u_char *)dst)++) = *(((const u_char *)src)++); 22656498Speter} 22756498Speterstatic void __inline 22856498Spetersi_vbcopy(const volatile void *src, void *dst, size_t len) 22956498Speter{ 23056498Speter while (len--) 23156498Speter *(((u_char *)dst)++) = *(((const volatile u_char *)src)++); 23256498Speter} 23356498Speterstatic void __inline 23456498Spetersi_bcopyv(const void *src, volatile void *dst, size_t len) 23556498Speter{ 23656498Speter while (len--) 23756498Speter *(((volatile u_char *)dst)++) = *(((const u_char *)src)++); 23856498Speter} 23956498Speter 24056498Speter 24134832Speter/* 24210015Speter * Attach the device. Initialize the card. 24310015Speter */ 24456505Speterint 24556498Spetersiattach(device_t dev) 24610015Speter{ 24756498Speter int unit; 24856498Speter struct si_softc *sc; 24910015Speter struct si_port *pp; 25010015Speter volatile struct si_channel *ccbp; 25110015Speter volatile struct si_reg *regp; 25210015Speter volatile caddr_t maddr; 25310015Speter struct si_module *modp; 25410015Speter struct speedtab *spt; 25510015Speter int nmodule, nport, x, y; 25612174Speter int uart_type; 25710015Speter 25856498Speter sc = device_get_softc(dev); 25956498Speter unit = device_get_unit(dev); 26010015Speter 26156505Speter sc->sc_typename = si_type[sc->sc_type]; 26256505Speter if (si_numunits < unit + 1) 26356505Speter si_numunits = unit + 1; 26456505Speter 26556498Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", unit)); 26610015Speter 26756498Speter#ifdef POLL 26856498Speter if (si_pollrate == 0) { 26956498Speter si_pollrate = POLLHZ; /* in addition to irq */ 27056498Speter#ifdef REALPOLL 27156498Speter si_realpoll = 1; /* scan always */ 27256498Speter#endif 27356498Speter } 27456498Speter#endif 27556498Speter 27633395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 27733395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 27833395Speter 27910015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 28010015Speter 28110015Speter maddr = sc->sc_maddr; 28210015Speter 28334832Speter /* Stop the CPU first so it won't stomp around while we load */ 28434832Speter 28534832Speter switch (sc->sc_type) { 28634832Speter case SIEISA: 28756498Speter outb(sc->sc_iobase + 2, sc->sc_irq << 4); 28834832Speter break; 28934832Speter case SIPCI: 29034832Speter *(maddr+SIPCIRESET) = 0; 29134832Speter break; 29234832Speter case SIJETPCI: /* fall through to JET ISA */ 29334832Speter case SIJETISA: 29434832Speter *(maddr+SIJETCONFIG) = 0; 29534832Speter break; 29634832Speter case SIHOST2: 29734832Speter *(maddr+SIPLRESET) = 0; 29834832Speter break; 29934832Speter case SIHOST: 30034832Speter *(maddr+SIRESET) = 0; 30134832Speter break; 30234832Speter default: /* this should never happen */ 30334832Speter printf("si%d: unsupported configuration\n", unit); 30456498Speter return EINVAL; 30534832Speter break; 30634832Speter } 30734832Speter 30834832Speter /* OK, now lets download the download code */ 30934832Speter 31036956Ssteve if (SI_ISJET(sc->sc_type)) { 31133395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 31256498Speter unit, si3_t225_dsize)); 31334832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 31434832Speter si3_t225_dsize); 31534832Speter DPRINT((0, DBG_DOWNLOAD, 31634832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 31756498Speter unit, si3_t225_bsize, si3_t225_bootloadaddr)); 31834832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 31934832Speter si3_t225_bsize); 32034832Speter } else { 32133395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 32256498Speter unit, si2_z280_dsize)); 32334832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 32434832Speter si2_z280_dsize); 32533395Speter } 32610015Speter 32734832Speter /* Now start the CPU */ 32834832Speter 32910015Speter switch (sc->sc_type) { 33010015Speter case SIEISA: 33134832Speter /* modify the download code to tell it that it's on an EISA */ 33234832Speter *(maddr + 0x42) = 1; 33356498Speter outb(sc->sc_iobase + 2, (sc->sc_irq << 4) | 4); 33456498Speter (void)inb(sc->sc_iobase + 3); /* reset interrupt */ 33510015Speter break; 33633395Speter case SIPCI: 33734832Speter /* modify the download code to tell it that it's on a PCI */ 33833395Speter *(maddr+0x42) = 1; 33933395Speter *(maddr+SIPCIRESET) = 1; 34033395Speter *(maddr+SIPCIINTCL) = 0; 34133395Speter break; 34233395Speter case SIJETPCI: 34333395Speter *(maddr+SIJETRESET) = 0; 34433395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 34533395Speter break; 34633395Speter case SIJETISA: 34733395Speter *(maddr+SIJETRESET) = 0; 34834832Speter switch (sc->sc_irq) { 34956498Speter case 9: 35034832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 35134832Speter break; 35256498Speter case 10: 35334832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 35434832Speter break; 35556498Speter case 11: 35634832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 35734832Speter break; 35856498Speter case 12: 35934832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 36034832Speter break; 36156498Speter case 15: 36234832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 36334832Speter break; 36434832Speter } 36533395Speter break; 36610015Speter case SIHOST: 36710015Speter *(maddr+SIRESET_CL) = 0; 36810015Speter *(maddr+SIINTCL_CL) = 0; 36910015Speter break; 37010015Speter case SIHOST2: 37110015Speter *(maddr+SIPLRESET) = 0x10; 37210015Speter switch (sc->sc_irq) { 37356498Speter case 11: 37410015Speter *(maddr+SIPLIRQ11) = 0x10; 37510015Speter break; 37656498Speter case 12: 37710015Speter *(maddr+SIPLIRQ12) = 0x10; 37810015Speter break; 37956498Speter case 15: 38010015Speter *(maddr+SIPLIRQ15) = 0x10; 38110015Speter break; 38210015Speter } 38310015Speter *(maddr+SIPLIRQCLR) = 0x10; 38410015Speter break; 38534832Speter default: /* this should _REALLY_ never happen */ 38634832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 38756498Speter return EINVAL; 38810015Speter } 38910015Speter 39010015Speter DELAY(1000000); /* wait around for a second */ 39110015Speter 39210015Speter regp = (struct si_reg *)maddr; 39310015Speter y = 0; 39410015Speter /* wait max of 5 sec for init OK */ 39510015Speter while (regp->initstat == 0 && y++ < 10) { 39610015Speter DELAY(500000); 39710015Speter } 39810015Speter switch (regp->initstat) { 39910015Speter case 0: 40010015Speter printf("si%d: startup timeout - aborting\n", unit); 40112174Speter sc->sc_type = SIEMPTY; 40256498Speter return EINVAL; 40310015Speter case 1: 40436956Ssteve if (SI_ISJET(sc->sc_type)) { 40534832Speter /* set throttle to 100 times per second */ 40634832Speter regp->int_count = JET_INT_COUNT; 40734832Speter /* rx_intr_count is a NOP in Jet */ 40834832Speter } else { 40934832Speter /* set throttle to 125 times per second */ 41034832Speter regp->int_count = INT_COUNT; 41134832Speter /* rx intr max of 25 times per second */ 41234832Speter regp->rx_int_count = RXINT_COUNT; 41334832Speter } 41410015Speter regp->int_pending = 0; /* no intr pending */ 41510015Speter regp->int_scounter = 0; /* reset counter */ 41610015Speter break; 41710015Speter case 0xff: 41810015Speter /* 41910015Speter * No modules found, so give up on this one. 42010015Speter */ 42110015Speter printf("si%d: %s - no ports found\n", unit, 42210015Speter si_type[sc->sc_type]); 42310015Speter return 0; 42410015Speter default: 42534832Speter printf("si%d: download code version error - initstat %x\n", 42610015Speter unit, regp->initstat); 42756498Speter return EINVAL; 42810015Speter } 42910015Speter 43010015Speter /* 43110015Speter * First time around the ports just count them in order 43210015Speter * to allocate some memory. 43310015Speter */ 43410015Speter nport = 0; 43510015Speter modp = (struct si_module *)(maddr + 0x80); 43610015Speter for (;;) { 43712174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 43834832Speter switch (modp->sm_type) { 43934832Speter case TA4: 44010015Speter DPRINT((0, DBG_DOWNLOAD, 44134832Speter "si%d: Found old TA4 module, 4 ports\n", 44234832Speter unit)); 44334832Speter x = 4; 44410015Speter break; 44534832Speter case TA8: 44634832Speter DPRINT((0, DBG_DOWNLOAD, 44734832Speter "si%d: Found old TA8 module, 8 ports\n", 44834832Speter unit)); 44934832Speter x = 8; 45034832Speter break; 45134832Speter case TA4_ASIC: 45234832Speter DPRINT((0, DBG_DOWNLOAD, 45334832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 45434832Speter unit)); 45534832Speter x = 4; 45634832Speter break; 45734832Speter case TA8_ASIC: 45834832Speter DPRINT((0, DBG_DOWNLOAD, 45934832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 46034832Speter unit)); 46134832Speter x = 8; 46234832Speter break; 46334832Speter case MTA: 46434832Speter DPRINT((0, DBG_DOWNLOAD, 46534832Speter "si%d: Found CD1400 module, 8 ports\n", 46634832Speter unit)); 46734832Speter x = 8; 46834832Speter break; 46934832Speter case SXDC: 47034832Speter DPRINT((0, DBG_DOWNLOAD, 47134832Speter "si%d: Found SXDC module, 8 ports\n", 47234832Speter unit)); 47334832Speter x = 8; 47434832Speter break; 47510015Speter default: 47610015Speter printf("si%d: unknown module type %d\n", 47710015Speter unit, modp->sm_type); 47834832Speter goto try_next; 47910015Speter } 48034832Speter 48134832Speter /* this was limited in firmware and is also a driver issue */ 48234832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 48334832Speter printf("si%d: extra ports ignored\n", unit); 48434832Speter goto try_next; 48534832Speter } 48634832Speter 48734832Speter nport += x; 48834832Speter si_Nports += x; 48934832Speter si_Nmodules++; 49034832Speter 49134832Spetertry_next: 49210015Speter if (modp->sm_next == 0) 49310015Speter break; 49410015Speter modp = (struct si_module *) 49510015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 49610015Speter } 49710015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 49869781Sdwmalone M_DEVBUF, M_NOWAIT | M_ZERO); 49910015Speter if (sc->sc_ports == 0) { 50010015Speter printf("si%d: fail to malloc memory for port structs\n", 50110015Speter unit); 50256498Speter return EINVAL; 50310015Speter } 50410015Speter sc->sc_nport = nport; 50510015Speter 50610015Speter /* 50710015Speter * Scan round the ports again, this time initialising. 50810015Speter */ 50910015Speter pp = sc->sc_ports; 51010015Speter nmodule = 0; 51110015Speter modp = (struct si_module *)(maddr + 0x80); 51234832Speter uart_type = 1000; /* arbitary, > uchar_max */ 51310015Speter for (;;) { 51434832Speter switch (modp->sm_type) { 51534832Speter case TA4: 51634832Speter nport = 4; 51710015Speter break; 51834832Speter case TA8: 51934832Speter nport = 8; 52034832Speter break; 52134832Speter case TA4_ASIC: 52234832Speter nport = 4; 52334832Speter break; 52434832Speter case TA8_ASIC: 52534832Speter nport = 8; 52634832Speter break; 52734832Speter case MTA: 52834832Speter nport = 8; 52934832Speter break; 53034832Speter case SXDC: 53134832Speter nport = 8; 53234832Speter break; 53310015Speter default: 53434832Speter goto try_next2; 53510015Speter } 53634832Speter nmodule++; 53734832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 53834832Speter if (uart_type == 1000) 53934832Speter uart_type = ccbp->type; 54034832Speter else if (uart_type != ccbp->type) 54134832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 54234832Speter unit, nmodule, 54334832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 54434832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 54534832Speter 54634832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 54734832Speter pp->sp_ccb = ccbp; /* save the address */ 54872685Speter pp->sp_tty = ttymalloc(NULL); 54934832Speter pp->sp_pend = IDLE_CLOSE; 55034832Speter pp->sp_state = 0; /* internal flag */ 55134832Speter pp->sp_dtr_wait = 3 * hz; 55234832Speter pp->sp_iin.c_iflag = TTYDEF_IFLAG; 55334832Speter pp->sp_iin.c_oflag = TTYDEF_OFLAG; 55434832Speter pp->sp_iin.c_cflag = TTYDEF_CFLAG; 55534832Speter pp->sp_iin.c_lflag = TTYDEF_LFLAG; 55634832Speter termioschars(&pp->sp_iin); 55734832Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 55834832Speter TTYDEF_SPEED;; 55934832Speter pp->sp_iout = pp->sp_iin; 56034832Speter } 56134832Spetertry_next2: 56210015Speter if (modp->sm_next == 0) { 56334832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 56410015Speter unit, 56510015Speter sc->sc_typename, 56610015Speter sc->sc_nport, 56712174Speter nmodule, 56834832Speter uart_type, 56934832Speter si_modulename(sc->sc_type, uart_type)); 57010015Speter break; 57110015Speter } 57210015Speter modp = (struct si_module *) 57310015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 57410015Speter } 57510015Speter if (done_chartimes == 0) { 57610015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 57710015Speter if ((spt->sp_code /= hz) == 0) 57810015Speter spt->sp_code = 1; 57910015Speter } 58010015Speter done_chartimes = 1; 58110015Speter } 58212502Sjulian 58312675Sjulian/* path name devsw minor type uid gid perm*/ 58450442Speter for (x = 0; x < sc->sc_nport; x++) { 58534735Speter /* sync with the manuals that start at 1 */ 58656498Speter y = x + 1 + unit * (1 << SI_CARDSHIFT); 58750442Speter make_dev(&si_cdevsw, x, 0, 0, 0600, "ttyA%02d", y); 58850442Speter make_dev(&si_cdevsw, x + 0x00080, 0, 0, 0600, "cuaA%02d", y); 58950442Speter make_dev(&si_cdevsw, x + 0x10000, 0, 0, 0600, "ttyiA%02d", y); 59050442Speter make_dev(&si_cdevsw, x + 0x10080, 0, 0, 0600, "cuaiA%02d", y); 59150442Speter make_dev(&si_cdevsw, x + 0x20000, 0, 0, 0600, "ttylA%02d", y); 59250442Speter make_dev(&si_cdevsw, x + 0x20080, 0, 0, 0600, "cualA%02d", y); 59312675Sjulian } 59450254Sphk make_dev(&si_cdevsw, 0x40000, 0, 0, 0600, "si_control"); 59556498Speter return (0); 59610015Speter} 59710015Speter 59812675Sjulianstatic int 59983366Sjuliansiopen(dev_t dev, int flag, int mode, struct thread *td) 60010015Speter{ 60110015Speter int oldspl, error; 60210015Speter int card, port; 60356498Speter struct si_softc *sc; 60456498Speter struct tty *tp; 60510015Speter volatile struct si_channel *ccbp; 60610015Speter struct si_port *pp; 60710015Speter int mynor = minor(dev); 60810015Speter 60910015Speter /* quickly let in /dev/si_control */ 61010015Speter if (IS_CONTROLDEV(mynor)) { 61193593Sjhb if ((error = suser(td))) 61210015Speter return(error); 61310015Speter return(0); 61410015Speter } 61510015Speter 61610015Speter card = SI_CARD(mynor); 61756498Speter sc = devclass_get_softc(si_devclass, card); 61856498Speter if (sc == NULL) 61910015Speter return (ENXIO); 62010015Speter 62112174Speter if (sc->sc_type == SIEMPTY) { 62212174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 62310015Speter card, sc->sc_typename)); 62410015Speter return(ENXIO); 62510015Speter } 62610015Speter 62710015Speter port = SI_PORT(mynor); 62810015Speter if (port >= sc->sc_nport) { 62912174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 63010015Speter card, sc->sc_nport)); 63110015Speter return(ENXIO); 63210015Speter } 63310015Speter 63410015Speter#ifdef POLL 63510015Speter /* 63610015Speter * We've now got a device, so start the poller. 63710015Speter */ 63810015Speter if (init_finished == 0) { 63915639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 64010015Speter init_finished = 1; 64110015Speter } 64210015Speter#endif 64310015Speter 64410015Speter /* initial/lock device */ 64510015Speter if (IS_STATE(mynor)) { 64610015Speter return(0); 64710015Speter } 64810015Speter 64910015Speter pp = sc->sc_ports + port; 65010015Speter tp = pp->sp_tty; /* the "real" tty */ 65151654Sphk dev->si_tty = tp; 65210015Speter ccbp = pp->sp_ccb; /* Find control block */ 65350016Snsayer DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%s,%x,%x,%x)\n", 65483366Sjulian devtoname(dev), flag, mode, td)); 65510015Speter 65610015Speter oldspl = spltty(); /* Keep others out */ 65710015Speter error = 0; 65810015Speter 65910015Speteropen_top: 66010015Speter while (pp->sp_state & SS_DTR_OFF) { 66110015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 66210015Speter if (error != 0) 66310015Speter goto out; 66410015Speter } 66510015Speter 66610015Speter if (tp->t_state & TS_ISOPEN) { 66710015Speter /* 66810015Speter * The device is open, so everything has been initialised. 66910015Speter * handle conflicts. 67010015Speter */ 67110015Speter if (IS_CALLOUT(mynor)) { 67210015Speter if (!pp->sp_active_out) { 67310015Speter error = EBUSY; 67410015Speter goto out; 67510015Speter } 67610015Speter } else { 67710015Speter if (pp->sp_active_out) { 67810015Speter if (flag & O_NONBLOCK) { 67910015Speter error = EBUSY; 68010015Speter goto out; 68110015Speter } 68210015Speter error = tsleep(&pp->sp_active_out, 68310015Speter TTIPRI|PCATCH, "sibi", 0); 68410015Speter if (error != 0) 68510015Speter goto out; 68610015Speter goto open_top; 68710015Speter } 68810015Speter } 68943425Sphk if (tp->t_state & TS_XCLUDE && 69093593Sjhb suser(td)) { 69110015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 69210015Speter "already open and EXCLUSIVE set\n")); 69310015Speter error = EBUSY; 69410015Speter goto out; 69510015Speter } 69610015Speter } else { 69710015Speter /* 69810015Speter * The device isn't open, so there are no conflicts. 69910015Speter * Initialize it. Avoid sleep... :-) 70010015Speter */ 70110015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 70210015Speter tp->t_oproc = si_start; 70351654Sphk tp->t_stop = si_stop; 70410015Speter tp->t_param = siparam; 70510015Speter tp->t_dev = dev; 70610015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 70710015Speter ? pp->sp_iout : pp->sp_iin; 70810015Speter 70910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 71010015Speter 71110015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 71210015Speter 71310015Speter error = siparam(tp, &tp->t_termios); 71410015Speter 71510015Speter --pp->sp_wopeners; 71610015Speter if (error != 0) 71710015Speter goto out; 71810015Speter /* XXX: we should goto_top if siparam slept */ 71910015Speter 72010015Speter /* set initial DCD state */ 72110015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 72210015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 72310015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 72410015Speter } 72510015Speter } 72610015Speter 72710015Speter /* whoops! we beat the close! */ 72810015Speter if (pp->sp_state & SS_CLOSING) { 72910015Speter /* try and stop it from proceeding to bash the hardware */ 73010015Speter pp->sp_state &= ~SS_CLOSING; 73110015Speter } 73210015Speter 73310015Speter /* 73410015Speter * Wait for DCD if necessary 73510015Speter */ 73650442Speter if (!(tp->t_state & TS_CARR_ON) && 73750442Speter !IS_CALLOUT(mynor) && 73850442Speter !(tp->t_cflag & CLOCAL) && 73950442Speter !(flag & O_NONBLOCK)) { 74010015Speter ++pp->sp_wopeners; 74110015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 74210015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 74310015Speter --pp->sp_wopeners; 74410015Speter if (error != 0) 74510015Speter goto out; 74610015Speter goto open_top; 74710015Speter } 74810015Speter 74910015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 75010015Speter si_disc_optim(tp, &tp->t_termios, pp); 75110015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 75210015Speter pp->sp_active_out = TRUE; 75310015Speter 75410015Speter pp->sp_state |= SS_OPEN; /* made it! */ 75510015Speter 75610015Speterout: 75710015Speter splx(oldspl); 75810015Speter 75910015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 76010015Speter 76110015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 76210015Speter sihardclose(pp); 76310015Speter 76410015Speter return(error); 76510015Speter} 76610015Speter 76712675Sjulianstatic int 76883366Sjuliansiclose(dev_t dev, int flag, int mode, struct thread *td) 76910015Speter{ 77056498Speter struct si_port *pp; 77156498Speter struct tty *tp; 77210015Speter int oldspl; 77310015Speter int error = 0; 77410015Speter int mynor = minor(dev); 77510015Speter 77610015Speter if (IS_SPECIAL(mynor)) 77710015Speter return(0); 77810015Speter 77910015Speter oldspl = spltty(); 78010015Speter 78110015Speter pp = MINOR2PP(mynor); 78210015Speter tp = pp->sp_tty; 78310015Speter 78450016Snsayer DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%s,%x,%x,%x) sp_state:%x\n", 78583366Sjulian devtoname(dev), flag, mode, td, pp->sp_state)); 78610015Speter 78710015Speter /* did we sleep and loose a race? */ 78810015Speter if (pp->sp_state & SS_CLOSING) { 78910015Speter /* error = ESOMETING? */ 79010015Speter goto out; 79110015Speter } 79210015Speter 79310015Speter /* begin race detection.. */ 79410015Speter pp->sp_state |= SS_CLOSING; 79510015Speter 79610015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 79710015Speter 79810015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 79910015Speter (*linesw[tp->t_line].l_close)(tp, flag); 80010015Speter 80110015Speter si_write_enable(pp, 1); 80210015Speter 80310015Speter /* did we sleep and somebody started another open? */ 80410015Speter if (!(pp->sp_state & SS_CLOSING)) { 80510015Speter /* error = ESOMETING? */ 80610015Speter goto out; 80710015Speter } 80810015Speter /* ok. we are now still on the right track.. nuke the hardware */ 80910015Speter 81010015Speter if (pp->sp_state & SS_LSTART) { 81129677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 81210015Speter pp->sp_state &= ~SS_LSTART; 81310015Speter } 81410015Speter 81551654Sphk si_stop(tp, FREAD | FWRITE); 81610015Speter 81710015Speter sihardclose(pp); 81810015Speter ttyclose(tp); 81910015Speter pp->sp_state &= ~SS_OPEN; 82010015Speter 82110015Speterout: 82210015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 82310015Speter splx(oldspl); 82410015Speter return(error); 82510015Speter} 82610015Speter 82710015Speterstatic void 82856498Spetersihardclose(struct si_port *pp) 82910015Speter{ 83010015Speter int oldspl; 83110015Speter struct tty *tp; 83210015Speter volatile struct si_channel *ccbp; 83310015Speter 83410015Speter oldspl = spltty(); 83510015Speter 83610015Speter tp = pp->sp_tty; 83710015Speter ccbp = pp->sp_ccb; /* Find control block */ 83850442Speter if (tp->t_cflag & HUPCL || 83950442Speter (!pp->sp_active_out && 84050442Speter !(ccbp->hi_ip & IP_DCD) && 84150442Speter !(pp->sp_iin.c_cflag && CLOCAL)) || 84250442Speter !(tp->t_state & TS_ISOPEN)) { 84310015Speter 84410015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 84510015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 84610015Speter 84710015Speter if (pp->sp_dtr_wait != 0) { 84810015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 84910015Speter pp->sp_state |= SS_DTR_OFF; 85010015Speter } 85110015Speter 85210015Speter } 85310015Speter pp->sp_active_out = FALSE; 85410015Speter wakeup((caddr_t)&pp->sp_active_out); 85510015Speter wakeup(TSA_CARR_ON(tp)); 85610015Speter 85710015Speter splx(oldspl); 85810015Speter} 85910015Speter 86010015Speter 86110015Speter/* 86210015Speter * called at splsoftclock()... 86310015Speter */ 86410015Speterstatic void 86556498Spetersidtrwakeup(void *chan) 86610015Speter{ 86710015Speter struct si_port *pp; 86810015Speter int oldspl; 86910015Speter 87010015Speter oldspl = spltty(); 87110015Speter 87210015Speter pp = (struct si_port *)chan; 87310015Speter pp->sp_state &= ~SS_DTR_OFF; 87410015Speter wakeup(&pp->sp_dtr_wait); 87510015Speter 87610015Speter splx(oldspl); 87710015Speter} 87810015Speter 87912675Sjulianstatic int 88056498Spetersiwrite(dev_t dev, struct uio *uio, int flag) 88110015Speter{ 88256498Speter struct si_port *pp; 88356498Speter struct tty *tp; 88410015Speter int error = 0; 88510015Speter int mynor = minor(dev); 88610015Speter int oldspl; 88710015Speter 88810015Speter if (IS_SPECIAL(mynor)) { 88910015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 89010015Speter return(ENODEV); 89110015Speter } 89210015Speter pp = MINOR2PP(mynor); 89310015Speter tp = pp->sp_tty; 89450016Snsayer DPRINT((pp, DBG_WRITE, "siwrite(%s,%x,%x)\n", devtoname(dev), uio, flag)); 89510015Speter 89610015Speter oldspl = spltty(); 89710015Speter /* 89810015Speter * If writes are currently blocked, wait on the "real" tty 89910015Speter */ 90010015Speter while (pp->sp_state & SS_BLOCKWRITE) { 90110015Speter pp->sp_state |= SS_WAITWRITE; 90210015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 90318515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 90418515Speter "siwrite", tp->t_timeout))) { 90517291Speter if (error == EWOULDBLOCK) 90617290Speter error = EIO; 90710015Speter goto out; 90817290Speter } 90910015Speter } 91010015Speter 91110015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 91210015Speterout: 91310015Speter splx(oldspl); 91410015Speter return (error); 91510015Speter} 91610015Speter 91710015Speter 91812675Sjulianstatic int 91983366Sjuliansiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 92010015Speter{ 92110015Speter struct si_port *pp; 92256498Speter struct tty *tp; 92310015Speter int error; 92410015Speter int mynor = minor(dev); 92510015Speter int oldspl; 92610015Speter int blocked = 0; 92710015Speter#if defined(COMPAT_43) 92838351Sbde u_long oldcmd; 92910015Speter struct termios term; 93010015Speter#endif 93110015Speter 93210015Speter if (IS_SI_IOCTL(cmd)) 93383366Sjulian return(si_Sioctl(dev, cmd, data, flag, td)); 93410015Speter 93510015Speter pp = MINOR2PP(mynor); 93610015Speter tp = pp->sp_tty; 93710015Speter 93850016Snsayer DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%s,%lx,%x,%x)\n", 93950016Snsayer devtoname(dev), cmd, data, flag)); 94010015Speter if (IS_STATE(mynor)) { 94110015Speter struct termios *ct; 94210015Speter 94310015Speter switch (mynor & SI_STATE_MASK) { 94410015Speter case SI_INIT_STATE_MASK: 94510015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 94610015Speter break; 94710015Speter case SI_LOCK_STATE_MASK: 94816839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 94910015Speter break; 95010015Speter default: 95110015Speter return (ENODEV); 95210015Speter } 95310015Speter switch (cmd) { 95410015Speter case TIOCSETA: 95593593Sjhb error = suser(td); 95610015Speter if (error != 0) 95710015Speter return (error); 95810015Speter *ct = *(struct termios *)data; 95910015Speter return (0); 96010015Speter case TIOCGETA: 96110015Speter *(struct termios *)data = *ct; 96210015Speter return (0); 96310015Speter case TIOCGETD: 96410015Speter *(int *)data = TTYDISC; 96510015Speter return (0); 96610015Speter case TIOCGWINSZ: 96710015Speter bzero(data, sizeof(struct winsize)); 96810015Speter return (0); 96910015Speter default: 97010015Speter return (ENOTTY); 97110015Speter } 97210015Speter } 97310015Speter /* 97410015Speter * Do the old-style ioctl compat routines... 97510015Speter */ 97610015Speter#if defined(COMPAT_43) 97710015Speter term = tp->t_termios; 97810015Speter oldcmd = cmd; 97910015Speter error = ttsetcompat(tp, &cmd, data, &term); 98010015Speter if (error != 0) 98110015Speter return (error); 98210015Speter if (cmd != oldcmd) 98310015Speter data = (caddr_t)&term; 98410015Speter#endif 98510015Speter /* 98610015Speter * Do the initial / lock state business 98710015Speter */ 98810015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 98910015Speter int cc; 99010015Speter struct termios *dt = (struct termios *)data; 99110015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 99210015Speter ? &pp->sp_lout : &pp->sp_lin; 99310015Speter 99450442Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) | 99550442Speter (dt->c_iflag & ~lt->c_iflag); 99650442Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) | 99750442Speter (dt->c_oflag & ~lt->c_oflag); 99850442Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) | 99950442Speter (dt->c_cflag & ~lt->c_cflag); 100050442Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) | 100150442Speter (dt->c_lflag & ~lt->c_lflag); 100210015Speter for (cc = 0; cc < NCCS; ++cc) 100310015Speter if (lt->c_cc[cc] != 0) 100410015Speter dt->c_cc[cc] = tp->t_cc[cc]; 100510015Speter if (lt->c_ispeed != 0) 100610015Speter dt->c_ispeed = tp->t_ispeed; 100710015Speter if (lt->c_ospeed != 0) 100810015Speter dt->c_ospeed = tp->t_ospeed; 100910015Speter } 101010015Speter 101110015Speter /* 101210015Speter * Block user-level writes to give the ttywait() 101310015Speter * a chance to completely drain for commands 101410015Speter * that require the port to be in a quiescent state. 101510015Speter */ 101610015Speter switch (cmd) { 101734832Speter case TIOCSETAW: 101834832Speter case TIOCSETAF: 101917396Speter case TIOCDRAIN: 102017396Speter#ifdef COMPAT_43 102117396Speter case TIOCSETP: 102217396Speter#endif 102310015Speter blocked++; /* block writes for ttywait() and siparam() */ 102410015Speter si_write_enable(pp, 0); 102510015Speter } 102610015Speter 102783366Sjulian error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 102831577Sbde if (error != ENOIOCTL) 102910015Speter goto out; 103010015Speter 103110015Speter oldspl = spltty(); 103210015Speter 103310015Speter error = ttioctl(tp, cmd, data, flag); 103410015Speter si_disc_optim(tp, &tp->t_termios, pp); 103550435Speter if (error != ENOIOCTL) { 103650435Speter splx(oldspl); 103750435Speter goto out; 103850435Speter } 103910015Speter 104050435Speter error = 0; 104110015Speter switch (cmd) { 104210015Speter case TIOCSBRK: 104316575Speter si_command(pp, SBREAK, SI_WAIT); 104410015Speter break; 104510015Speter case TIOCCBRK: 104616575Speter si_command(pp, EBREAK, SI_WAIT); 104710015Speter break; 104810015Speter case TIOCSDTR: 104910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 105010015Speter break; 105110015Speter case TIOCCDTR: 105210015Speter (void) si_modem(pp, SET, 0); 105310015Speter break; 105410015Speter case TIOCMSET: 105510015Speter (void) si_modem(pp, SET, *(int *)data); 105610015Speter break; 105710015Speter case TIOCMBIS: 105810015Speter (void) si_modem(pp, BIS, *(int *)data); 105910015Speter break; 106010015Speter case TIOCMBIC: 106110015Speter (void) si_modem(pp, BIC, *(int *)data); 106210015Speter break; 106310015Speter case TIOCMGET: 106410015Speter *(int *)data = si_modem(pp, GET, 0); 106510015Speter break; 106610015Speter case TIOCMSDTRWAIT: 106710015Speter /* must be root since the wait applies to following logins */ 106893593Sjhb error = suser(td); 106950435Speter if (error == 0) 107050435Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 107110015Speter break; 107210015Speter case TIOCMGDTRWAIT: 107310015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 107410015Speter break; 107510015Speter default: 107610015Speter error = ENOTTY; 107710015Speter } 107810015Speter splx(oldspl); 107950435Speter 108010015Speterout: 108110015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 108210015Speter if (blocked) 108310015Speter si_write_enable(pp, 1); 108410015Speter return(error); 108510015Speter} 108610015Speter 108710015Speter/* 108810015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 108910015Speter */ 109010015Speterstatic int 109183366Sjuliansi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 109210015Speter{ 109310015Speter struct si_softc *xsc; 109456498Speter struct si_port *xpp; 109510015Speter volatile struct si_reg *regp; 109610015Speter struct si_tcsi *dp; 109710044Speter struct si_pstat *sps; 109811872Sphk int *ip, error = 0; 109910015Speter int oldspl; 110010015Speter int card, port; 110110015Speter int mynor = minor(dev); 110210015Speter 110350016Snsayer DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n", 110450016Snsayer devtoname(dev), cmd, data, flag)); 110510015Speter 110610044Speter#if 1 110710044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 110810044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 110910044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 111010044Speter#endif 111110044Speter 111210015Speter if (!IS_CONTROLDEV(mynor)) { 111310015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 111410015Speter return(ENODEV); 111510015Speter } 111610015Speter 111710015Speter oldspl = spltty(); /* better safe than sorry */ 111810015Speter 111910015Speter ip = (int *)data; 112010015Speter 112193593Sjhb#define SUCHECK if ((error = suser(td))) goto out 112210015Speter 112310015Speter switch (cmd) { 112410015Speter case TCSIPORTS: 112510015Speter *ip = si_Nports; 112610015Speter goto out; 112710015Speter case TCSIMODULES: 112810015Speter *ip = si_Nmodules; 112910015Speter goto out; 113010015Speter case TCSISDBG_ALL: 113110015Speter SUCHECK; 113210015Speter si_debug = *ip; 113310015Speter goto out; 113410015Speter case TCSIGDBG_ALL: 113510015Speter *ip = si_debug; 113610015Speter goto out; 113710015Speter default: 113810015Speter /* 113910015Speter * Check that a controller for this port exists 114010015Speter */ 114110044Speter 114210044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 114310044Speter 114410015Speter dp = (struct si_tcsi *)data; 114510044Speter sps = (struct si_pstat *)data; 114610015Speter card = dp->tc_card; 114756498Speter xsc = devclass_get_softc(si_devclass, card); /* check.. */ 114856498Speter if (xsc == NULL || xsc->sc_type == SIEMPTY) { 114910015Speter error = ENOENT; 115010015Speter goto out; 115110015Speter } 115210015Speter /* 115310015Speter * And check that a port exists 115410015Speter */ 115510015Speter port = dp->tc_port; 115610015Speter if (port < 0 || port >= xsc->sc_nport) { 115710015Speter error = ENOENT; 115810015Speter goto out; 115910015Speter } 116010015Speter xpp = xsc->sc_ports + port; 116110015Speter regp = (struct si_reg *)xsc->sc_maddr; 116210015Speter } 116310015Speter 116410015Speter switch (cmd) { 116510015Speter case TCSIDEBUG: 116610015Speter#ifdef SI_DEBUG 116710015Speter SUCHECK; 116810015Speter if (xpp->sp_debug) 116910015Speter xpp->sp_debug = 0; 117010015Speter else { 117110015Speter xpp->sp_debug = DBG_ALL; 117210015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 117310015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 117410015Speter } 117510015Speter break; 117610015Speter#else 117710015Speter error = ENODEV; 117810015Speter goto out; 117910015Speter#endif 118010015Speter case TCSISDBG_LEVEL: 118110015Speter case TCSIGDBG_LEVEL: 118210015Speter#ifdef SI_DEBUG 118310015Speter if (cmd == TCSIGDBG_LEVEL) { 118410015Speter dp->tc_dbglvl = xpp->sp_debug; 118510015Speter } else { 118610015Speter SUCHECK; 118710015Speter xpp->sp_debug = dp->tc_dbglvl; 118810015Speter } 118910015Speter break; 119010015Speter#else 119110015Speter error = ENODEV; 119210015Speter goto out; 119310015Speter#endif 119410015Speter case TCSIGRXIT: 119510015Speter dp->tc_int = regp->rx_int_count; 119610015Speter break; 119710015Speter case TCSIRXIT: 119810015Speter SUCHECK; 119910015Speter regp->rx_int_count = dp->tc_int; 120010015Speter break; 120110015Speter case TCSIGIT: 120210015Speter dp->tc_int = regp->int_count; 120310015Speter break; 120410015Speter case TCSIIT: 120510015Speter SUCHECK; 120610015Speter regp->int_count = dp->tc_int; 120710015Speter break; 120810044Speter case TCSISTATE: 120910044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 121010015Speter break; 121110044Speter /* these next three use a different structure */ 121210044Speter case TCSI_PORT: 121310015Speter SUCHECK; 121434832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 121510015Speter break; 121610044Speter case TCSI_CCB: 121710044Speter SUCHECK; 121850442Speter si_vbcopy(xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 121910015Speter break; 122010044Speter case TCSI_TTY: 122110044Speter SUCHECK; 122234832Speter si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 122310015Speter break; 122410015Speter default: 122510015Speter error = EINVAL; 122610015Speter goto out; 122710015Speter } 122810015Speterout: 122910015Speter splx(oldspl); 123010015Speter return(error); /* success */ 123110015Speter} 123210015Speter 123310015Speter/* 123410015Speter * siparam() : Configure line params 123510015Speter * called at spltty(); 123610015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 123710015Speter * caller must arrange this if it's important.. 123810015Speter */ 123912724Sphkstatic int 124056498Spetersiparam(struct tty *tp, struct termios *t) 124110015Speter{ 124256498Speter struct si_port *pp = TP2PP(tp); 124310015Speter volatile struct si_channel *ccbp; 124410015Speter int oldspl, cflag, iflag, oflag, lflag; 124510015Speter int error = 0; /* shutup gcc */ 124610015Speter int ispeed = 0; /* shutup gcc */ 124710015Speter int ospeed = 0; /* shutup gcc */ 124810161Speter BYTE val; 124910015Speter 125010015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 125110015Speter cflag = t->c_cflag; 125210015Speter iflag = t->c_iflag; 125310015Speter oflag = t->c_oflag; 125410015Speter lflag = t->c_lflag; 125510044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 125610044Speter oflag, cflag, iflag, lflag)); 125710015Speter 125834832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 125910015Speter 126010015Speter /* if not hung up.. */ 126110015Speter if (t->c_ospeed != 0) { 126210015Speter /* translate baud rate to firmware values */ 126310015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 126410015Speter ispeed = t->c_ispeed ? 126510015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 126610015Speter 126710015Speter /* enforce legit baud rate */ 126810015Speter if (ospeed < 0 || ispeed < 0) 126910015Speter return (EINVAL); 127010015Speter } 127110015Speter 127210015Speter oldspl = spltty(); 127310015Speter 127410015Speter ccbp = pp->sp_ccb; 127510015Speter 127610161Speter /* ========== set hi_break ========== */ 127710161Speter val = 0; 127810161Speter if (iflag & IGNBRK) /* Breaks */ 127910161Speter val |= BR_IGN; 128010161Speter if (iflag & BRKINT) /* Interrupt on break? */ 128110161Speter val |= BR_INT; 128210161Speter if (iflag & PARMRK) /* Parity mark? */ 128310161Speter val |= BR_PARMRK; 128410161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 128510161Speter val |= BR_PARIGN; 128610161Speter ccbp->hi_break = val; 128710161Speter 128810161Speter /* ========== set hi_csr ========== */ 128910015Speter /* if not hung up.. */ 129010015Speter if (t->c_ospeed != 0) { 129110015Speter /* Set I/O speeds */ 129210161Speter val = (ispeed << 4) | ospeed; 129310015Speter } 129410161Speter ccbp->hi_csr = val; 129510015Speter 129610161Speter /* ========== set hi_mr2 ========== */ 129710161Speter val = 0; 129810015Speter if (cflag & CSTOPB) /* Stop bits */ 129910161Speter val |= MR2_2_STOP; 130010015Speter else 130110161Speter val |= MR2_1_STOP; 130210161Speter /* 130310161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 130410161Speter * a DCE, hence the reverse sense of RTS and CTS 130510161Speter */ 130610161Speter /* Output Flow - RTS must be raised before data can be sent */ 130710161Speter if (cflag & CCTS_OFLOW) 130810161Speter val |= MR2_RTSCONT; 130910161Speter 131016575Speter ccbp->hi_mr2 = val; 131110161Speter 131210161Speter /* ========== set hi_mr1 ========== */ 131310161Speter val = 0; 131410015Speter if (!(cflag & PARENB)) /* Parity */ 131510161Speter val |= MR1_NONE; 131610015Speter else 131710161Speter val |= MR1_WITH; 131810015Speter if (cflag & PARODD) 131910161Speter val |= MR1_ODD; 132010015Speter 132110015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 132210161Speter val |= MR1_8_BITS; 132310015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 132410161Speter val |= MR1_7_BITS; 132510015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 132610161Speter val |= MR1_6_BITS; 132710015Speter } else { /* Must be 5 */ 132810161Speter val |= MR1_5_BITS; 132910015Speter } 133010161Speter /* 133110161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 133210161Speter * a DCE, hence the reverse sense of RTS and CTS 133310161Speter */ 133410161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 133510161Speter if (cflag & CRTS_IFLOW) 133610161Speter val |= MR1_CTSCONT; 133710015Speter 133810161Speter ccbp->hi_mr1 = val; 133910161Speter 134010161Speter /* ========== set hi_mask ========== */ 134110161Speter val = 0xff; 134210161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 134310161Speter val &= 0xFF; 134410161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 134510161Speter val &= 0x7F; 134610161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 134710161Speter val &= 0x3F; 134810161Speter } else { /* Must be 5 */ 134910161Speter val &= 0x1F; 135010161Speter } 135110015Speter if (iflag & ISTRIP) 135210161Speter val &= 0x7F; 135310015Speter 135410161Speter ccbp->hi_mask = val; 135510161Speter 135610161Speter /* ========== set hi_prtcl ========== */ 135756592Speter val = SP_DCEN; /* Monitor DCD always, or TIOCMGET misses it */ 135810161Speter if (iflag & IXANY) 135910161Speter val |= SP_TANY; 136010161Speter if (iflag & IXON) 136110161Speter val |= SP_TXEN; 136210161Speter if (iflag & IXOFF) 136310161Speter val |= SP_RXEN; 136410161Speter if (iflag & INPCK) 136510161Speter val |= SP_PAEN; 136610015Speter 136710161Speter ccbp->hi_prtcl = val; 136810161Speter 136910161Speter 137010161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 137110161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 137210015Speter ccbp->hi_txon = t->c_cc[VSTART]; 137310015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 137410015Speter 137510015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 137610015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 137710015Speter 137810161Speter /* ========== send settings to the card ========== */ 137910015Speter /* potential sleep here */ 138010015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 138110015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 138210015Speter else 138310015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 138410015Speter 138510161Speter /* ========== set DTR etc ========== */ 138610015Speter /* Hangup if ospeed == 0 */ 138710015Speter if (t->c_ospeed == 0) { 138810015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 138910015Speter } else { 139010015Speter /* 139110015Speter * If the previous speed was 0, may need to re-enable 139234832Speter * the modem signals 139334832Speter */ 139410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 139510015Speter } 139610015Speter 139710044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 139810044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 139910015Speter 140010015Speter splx(oldspl); 140110015Speter return(error); 140210015Speter} 140310015Speter 140410015Speter/* 140510015Speter * Enable or Disable the writes to this channel... 140610015Speter * "state" -> enabled = 1; disabled = 0; 140710015Speter */ 140810015Speterstatic void 140956498Spetersi_write_enable(struct si_port *pp, int state) 141010015Speter{ 141110015Speter int oldspl; 141210015Speter 141310015Speter oldspl = spltty(); 141410015Speter 141510015Speter if (state) { 141610015Speter pp->sp_state &= ~SS_BLOCKWRITE; 141710015Speter if (pp->sp_state & SS_WAITWRITE) { 141810015Speter pp->sp_state &= ~SS_WAITWRITE; 141910015Speter /* thunder away! */ 142010015Speter wakeup((caddr_t)pp); 142110015Speter } 142210015Speter } else { 142310015Speter pp->sp_state |= SS_BLOCKWRITE; 142410015Speter } 142510015Speter 142610015Speter splx(oldspl); 142710015Speter} 142810015Speter 142910015Speter/* 143010015Speter * Set/Get state of modem control lines. 143110015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 143210015Speter * TIOCM_DTR DSR 143310015Speter * TIOCM_RTS CTS 143410015Speter */ 143510015Speterstatic int 143656498Spetersi_modem(struct si_port *pp, enum si_mctl cmd, int bits) 143710015Speter{ 143810015Speter volatile struct si_channel *ccbp; 143910015Speter int x; 144010015Speter 144110015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 144210015Speter ccbp = pp->sp_ccb; /* Find channel address */ 144310015Speter switch (cmd) { 144410015Speter case GET: 144510015Speter x = ccbp->hi_ip; 144610015Speter bits = TIOCM_LE; 144710015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 144810015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 144910015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 145010015Speter if (x & IP_RI) bits |= TIOCM_RI; 145110015Speter return(bits); 145210015Speter case SET: 145310015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 145410015Speter /* fall through */ 145510015Speter case BIS: 145610015Speter x = 0; 145710015Speter if (bits & TIOCM_DTR) 145810015Speter x |= OP_DSR; 145910015Speter if (bits & TIOCM_RTS) 146010015Speter x |= OP_CTS; 146110015Speter ccbp->hi_op |= x; 146210015Speter break; 146310015Speter case BIC: 146410015Speter if (bits & TIOCM_DTR) 146510015Speter ccbp->hi_op &= ~OP_DSR; 146610015Speter if (bits & TIOCM_RTS) 146710015Speter ccbp->hi_op &= ~OP_CTS; 146810015Speter } 146910015Speter return 0; 147010015Speter} 147110015Speter 147210015Speter/* 147310015Speter * Handle change of modem state 147410015Speter */ 147510015Speterstatic void 147656498Spetersi_modem_state(struct si_port *pp, struct tty *tp, int hi_ip) 147710015Speter{ 147810015Speter /* if a modem dev */ 147910015Speter if (hi_ip & IP_DCD) { 148050442Speter if (!(pp->sp_last_hi_ip & IP_DCD)) { 148110015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 148210015Speter tp->t_line)); 148310015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 148410015Speter } 148510015Speter } else { 148610015Speter if (pp->sp_last_hi_ip & IP_DCD) { 148710015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 148810015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 148910015Speter (void) si_modem(pp, SET, 0); 149010015Speter } 149110015Speter } 149210015Speter pp->sp_last_hi_ip = hi_ip; 149310015Speter 149410015Speter} 149510015Speter 149610015Speter/* 149710015Speter * Poller to catch missed interrupts. 149812174Speter * 149912496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 150012496Speter * better response. We could really use a "periodic" version timeout(). :-) 150110015Speter */ 150210015Speter#ifdef POLL 150310708Speterstatic void 150410015Spetersi_poll(void *nothing) 150510015Speter{ 150656498Speter struct si_softc *sc; 150756498Speter int i; 150810015Speter volatile struct si_reg *regp; 150956498Speter struct si_port *pp; 151012174Speter int lost, oldspl, port; 151110015Speter 151210015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 151311609Speter oldspl = spltty(); 151410015Speter if (in_intr) 151510015Speter goto out; 151610015Speter lost = 0; 151756498Speter for (i = 0; i < si_numunits; i++) { 151856498Speter sc = devclass_get_softc(si_devclass, i); 151956498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 152010015Speter continue; 152110015Speter regp = (struct si_reg *)sc->sc_maddr; 152234832Speter 152310015Speter /* 152410015Speter * See if there has been a pending interrupt for 2 seconds 152533395Speter * or so. The test (int_scounter >= 200) won't correspond 152610015Speter * to 2 seconds if int_count gets changed. 152710015Speter */ 152810015Speter if (regp->int_pending != 0) { 152910015Speter if (regp->int_scounter >= 200 && 153010015Speter regp->initstat == 1) { 153112174Speter printf("si%d: lost intr\n", i); 153210015Speter lost++; 153310015Speter } 153410015Speter } else { 153510015Speter regp->int_scounter = 0; 153610015Speter } 153710015Speter 153812174Speter /* 153912174Speter * gripe about no input flow control.. 154012174Speter */ 154112174Speter pp = sc->sc_ports; 154212174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 154312174Speter if (pp->sp_delta_overflows > 0) { 154412174Speter printf("si%d: %d tty level buffer overflows\n", 154512174Speter i, pp->sp_delta_overflows); 154612174Speter pp->sp_delta_overflows = 0; 154712174Speter } 154812174Speter } 154910015Speter } 155017547Speter if (lost || si_realpoll) 155156498Speter si_intr(NULL); /* call intr with fake vector */ 155211609Speterout: 155310015Speter splx(oldspl); 155410015Speter 155515639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 155610015Speter} 155710015Speter#endif /* ifdef POLL */ 155810015Speter 155910015Speter/* 156010015Speter * The interrupt handler polls ALL ports on ALL adapters each time 156110015Speter * it is called. 156210015Speter */ 156310015Speter 156412496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 156534832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 156610015Speter 156756505Spetervoid 156856498Spetersi_intr(void *arg) 156910015Speter{ 157056498Speter struct si_softc *sc; 157156498Speter struct si_port *pp; 157210015Speter volatile struct si_channel *ccbp; 157356498Speter struct tty *tp; 157410015Speter volatile caddr_t maddr; 157511872Sphk BYTE op, ip; 157612174Speter int x, card, port, n, i, isopen; 157710015Speter volatile BYTE *z; 157810015Speter BYTE c; 157910015Speter 158056498Speter sc = arg; 158156498Speter 158256498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); 158356498Speter if (in_intr) 158410708Speter return; 158510015Speter in_intr = 1; 158610015Speter 158710015Speter /* 158810015Speter * When we get an int we poll all the channels and do ALL pending 158910015Speter * work, not just the first one we find. This allows all cards to 159010015Speter * share the same vector. 159134832Speter * 159234832Speter * XXX - But if we're sharing the vector with something that's NOT 159334832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 159410015Speter */ 159556498Speter for (card = 0; card < si_numunits; card++) { 159656498Speter sc = devclass_get_softc(si_devclass, card); 159756498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 159810015Speter continue; 159912174Speter 160012174Speter /* 160112174Speter * First, clear the interrupt 160212174Speter */ 160310015Speter switch(sc->sc_type) { 160434832Speter case SIHOST: 160510015Speter maddr = sc->sc_maddr; 160610015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 160710015Speter /* flag nothing pending */ 160810015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 160910015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 161010015Speter break; 161110015Speter case SIHOST2: 161210015Speter maddr = sc->sc_maddr; 161310015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 161410015Speter *(maddr+SIPLIRQCLR) = 0x00; 161510015Speter *(maddr+SIPLIRQCLR) = 0x10; 161610015Speter break; 161733395Speter case SIPCI: 161833395Speter maddr = sc->sc_maddr; 161933395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 162033395Speter *(maddr+SIPCIINTCL) = 0x0; 162133395Speter break; 162234832Speter case SIJETPCI: /* fall through to JETISA case */ 162333395Speter case SIJETISA: 162433395Speter maddr = sc->sc_maddr; 162533395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 162633395Speter *(maddr+SIJETINTCL) = 0x0; 162733395Speter break; 162810015Speter case SIEISA: 162910015Speter maddr = sc->sc_maddr; 163010015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 163156498Speter (void)inb(sc->sc_iobase + 3); 163210015Speter break; 163310015Speter case SIEMPTY: 163410015Speter default: 163510015Speter continue; 163610015Speter } 163710015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 163810015Speter 163912174Speter /* 164012174Speter * check each port 164112174Speter */ 164250442Speter for (pp = sc->sc_ports, port = 0; port < sc->sc_nport; 164334832Speter pp++, port++) { 164410015Speter ccbp = pp->sp_ccb; 164510015Speter tp = pp->sp_tty; 164610015Speter 164710015Speter /* 164810015Speter * See if a command has completed ? 164910015Speter */ 165010015Speter if (ccbp->hi_stat != pp->sp_pend) { 165110015Speter DPRINT((pp, DBG_INTR, 165234735Speter "si_intr hi_stat = 0x%x, pend = %d\n", 165310015Speter ccbp->hi_stat, pp->sp_pend)); 165410015Speter switch(pp->sp_pend) { 165510015Speter case LOPEN: 165610015Speter case MPEND: 165710015Speter case MOPEN: 165810015Speter case CONFIG: 165916575Speter case SBREAK: 166016575Speter case EBREAK: 166110015Speter pp->sp_pend = ccbp->hi_stat; 166210015Speter /* sleeping in si_command */ 166310015Speter wakeup(&pp->sp_state); 166410015Speter break; 166510015Speter default: 166610015Speter pp->sp_pend = ccbp->hi_stat; 166710015Speter } 166834832Speter } 166910015Speter 167010015Speter /* 167110015Speter * Continue on if it's closed 167210015Speter */ 167310015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 167410015Speter continue; 167510015Speter } 167610015Speter 167710015Speter /* 167810015Speter * Do modem state change if not a local device 167910015Speter */ 168010015Speter si_modem_state(pp, tp, ccbp->hi_ip); 168110015Speter 168210015Speter /* 168334832Speter * Check to see if we should 'receive' characters. 168412174Speter */ 168512174Speter if (tp->t_state & TS_CONNECTED && 168612174Speter tp->t_state & TS_ISOPEN) 168712174Speter isopen = 1; 168812174Speter else 168912174Speter isopen = 0; 169012174Speter 169112174Speter /* 169216575Speter * Do input break processing 169310015Speter */ 169410015Speter if (ccbp->hi_state & ST_BREAK) { 169512174Speter if (isopen) { 169612174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 169710015Speter } 169810015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 169910015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 170010015Speter } 170110015Speter 170210015Speter /* 170312174Speter * Do RX stuff - if not open then dump any characters. 170412174Speter * XXX: This is VERY messy and needs to be cleaned up. 170512174Speter * 170612174Speter * XXX: can we leave data in the host adapter buffer 170712174Speter * when the clists are full? That may be dangerous 170812174Speter * if the user cannot get an interrupt signal through. 170910015Speter */ 171010015Speter 171112174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 171212174Speter 171312174Speter if (!isopen) { 171410015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 171512174Speter goto end_rx; 171612174Speter } 171710015Speter 171812174Speter /* 171915640Speter * If the tty input buffers are blocked, stop emptying 172015640Speter * the incoming buffers and let the auto flow control 172115640Speter * assert.. 172215640Speter */ 172315640Speter if (tp->t_state & TS_TBLOCK) { 172415640Speter goto end_rx; 172515640Speter } 172615640Speter 172715640Speter /* 172812174Speter * Process read characters if not skipped above 172912174Speter */ 173015640Speter op = ccbp->hi_rxopos; 173115640Speter ip = ccbp->hi_rxipos; 173215640Speter c = ip - op; 173312174Speter if (c == 0) { 173412174Speter goto end_rx; 173512174Speter } 173610015Speter 173712174Speter n = c & 0xff; 173815640Speter if (n > 250) 173915640Speter n = 250; 174012174Speter 174112174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 174210015Speter n, op, ip)); 174310015Speter 174412174Speter /* 174512174Speter * Suck characters out of host card buffer into the 174612174Speter * "input staging buffer" - so that we dont leave the 174712174Speter * host card in limbo while we're possibly echoing 174812174Speter * characters and possibly flushing input inside the 174912174Speter * ldisc l_rint() routine. 175012174Speter */ 175112496Speter if (n <= SI_BUFFERSIZE - op) { 175210015Speter 175312174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 175412174Speter z = ccbp->hi_rxbuf + op; 175550442Speter si_vbcopy(z, si_rxbuf, n); 175610015Speter 175712174Speter op += n; 175812174Speter } else { 175912496Speter x = SI_BUFFERSIZE - op; 176010015Speter 176112174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 176212174Speter z = ccbp->hi_rxbuf + op; 176350442Speter si_vbcopy(z, si_rxbuf, x); 176410015Speter 176534832Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 176634832Speter n - x)); 176712174Speter z = ccbp->hi_rxbuf; 176850442Speter si_vbcopy(z, si_rxbuf + x, n - x); 176910015Speter 177012174Speter op += n; 177112174Speter } 177210015Speter 177312174Speter /* clear collected characters from buffer */ 177412174Speter ccbp->hi_rxopos = op; 177512174Speter 177612174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 177710015Speter n, op, ip)); 177810015Speter 177912174Speter /* 178012174Speter * at this point... 178112174Speter * n = number of chars placed in si_rxbuf 178212174Speter */ 178310015Speter 178412174Speter /* 178512174Speter * Avoid the grotesquely inefficient lineswitch 178612174Speter * routine (ttyinput) in "raw" mode. It usually 178712174Speter * takes about 450 instructions (that's without 178812174Speter * canonical processing or echo!). slinput is 178912174Speter * reasonably fast (usually 40 instructions 179012174Speter * plus call overhead). 179112174Speter */ 179212174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 179310015Speter 179412174Speter /* block if the driver supports it */ 179550442Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER && 179650442Speter (tp->t_cflag & CRTS_IFLOW || 179750442Speter tp->t_iflag & IXOFF) && 179850442Speter !(tp->t_state & TS_TBLOCK)) 179912174Speter ttyblock(tp); 180010015Speter 180112174Speter tk_nin += n; 180212174Speter tk_rawcc += n; 180312174Speter tp->t_rawcc += n; 180412174Speter 180512174Speter pp->sp_delta_overflows += 180612174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 180712174Speter 180812174Speter ttwakeup(tp); 180950442Speter if (tp->t_state & TS_TTSTOP && 181050442Speter (tp->t_iflag & IXANY || 181150442Speter tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 181212174Speter tp->t_state &= ~TS_TTSTOP; 181312174Speter tp->t_lflag &= ~FLUSHO; 181412174Speter si_start(tp); 181512174Speter } 181612174Speter } else { 181712174Speter /* 181812174Speter * It'd be nice to not have to go through the 181912174Speter * function call overhead for each char here. 182012174Speter * It'd be nice to block input it, saving a 182112174Speter * loop here and the call/return overhead. 182212174Speter */ 182312174Speter for(x = 0; x < n; x++) { 182412174Speter i = si_rxbuf[x]; 182512174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 182612174Speter == -1) { 182712174Speter pp->sp_delta_overflows++; 182810015Speter } 182912174Speter } 183012174Speter } 183112174Speter goto more_rx; /* try for more until RXbuf is empty */ 183210015Speter 183312174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 183410015Speter 183510015Speter /* 183610015Speter * Do TX stuff 183710015Speter */ 183810015Speter (*linesw[tp->t_line].l_start)(tp); 183910015Speter 184010015Speter } /* end of for (all ports on this controller) */ 184110015Speter } /* end of for (all controllers) */ 184210015Speter 184311609Speter in_intr = 0; 184456498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); 184510015Speter} 184610015Speter 184710015Speter/* 184810015Speter * Nudge the transmitter... 184912174Speter * 185012174Speter * XXX: I inherited some funny code here. It implies the host card only 185112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 185212174Speter * not interrupt when it's actually hits empty. In some cases, we have 185312174Speter * processes waiting for complete drain, and we need to simulate an interrupt 185412174Speter * about when we think the buffer is going to be empty (and retry if not). 185512174Speter * I really am not certain about this... I *need* the hardware manuals. 185610015Speter */ 185710015Speterstatic void 185856498Spetersi_start(struct tty *tp) 185910015Speter{ 186010015Speter struct si_port *pp; 186110015Speter volatile struct si_channel *ccbp; 186256498Speter struct clist *qp; 186310015Speter BYTE ipos; 186410015Speter int nchar; 186510015Speter int oldspl, count, n, amount, buffer_full; 186610015Speter 186710015Speter oldspl = spltty(); 186810015Speter 186910015Speter qp = &tp->t_outq; 187010015Speter pp = TP2PP(tp); 187110015Speter 187210015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 187310015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 187410015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 187510015Speter 187610015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 187710015Speter goto out; 187810015Speter 187910015Speter buffer_full = 0; 188010015Speter ccbp = pp->sp_ccb; 188110015Speter 188210015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 188310015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 188410015Speter 188510015Speter while ((nchar = qp->c_cc) > 0) { 188610015Speter if ((BYTE)count >= 255) { 188710015Speter buffer_full++; 188810015Speter break; 188910015Speter } 189010015Speter amount = min(nchar, (255 - (BYTE)count)); 189110015Speter ipos = (unsigned int)ccbp->hi_txipos; 189234832Speter n = q_to_b(&tp->t_outq, si_txbuf, amount); 189310015Speter /* will it fit in one lump? */ 189434832Speter if ((SI_BUFFERSIZE - ipos) >= n) { 189550442Speter si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); 189610015Speter } else { 189750442Speter si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], 189834832Speter SI_BUFFERSIZE - ipos); 189950442Speter si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos), 190050442Speter &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos)); 190110015Speter } 190210015Speter ccbp->hi_txipos += n; 190310015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 190410015Speter } 190510015Speter 190610015Speter if (count != 0 && nchar == 0) { 190710015Speter tp->t_state |= TS_BUSY; 190810015Speter } else { 190910015Speter tp->t_state &= ~TS_BUSY; 191010015Speter } 191110015Speter 191210015Speter /* wakeup time? */ 191310015Speter ttwwakeup(tp); 191410015Speter 191510015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 191610015Speter (BYTE)count, nchar, tp->t_state)); 191710015Speter 191834735Speter if (tp->t_state & TS_BUSY) 191910015Speter { 192010015Speter int time; 192110015Speter 192234735Speter time = ttspeedtab(tp->t_ospeed, chartimes); 192334735Speter 192434735Speter if (time > 0) { 192534735Speter if (time < nchar) 192634735Speter time = nchar / time; 192734735Speter else 192834735Speter time = 2; 192910015Speter } else { 193034735Speter DPRINT((pp, DBG_START, 193134735Speter "bad char time value! %d\n", time)); 193234735Speter time = hz/10; 193310015Speter } 193410015Speter 193510015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 193629677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 193710015Speter } else { 193810015Speter pp->sp_state |= SS_LSTART; 193910015Speter } 194010015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 194129677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 194210015Speter } 194310015Speter 194410015Speterout: 194510015Speter splx(oldspl); 194610015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 194710015Speter} 194810015Speter 194910015Speter/* 195010015Speter * Note: called at splsoftclock from the timeout code 195110015Speter * This has to deal with two things... cause wakeups while waiting for 195210015Speter * tty drains on last process exit, and call l_start at about the right 195310015Speter * time for protocols like ppp. 195410015Speter */ 195510015Speterstatic void 195625047Sbdesi_lstart(void *arg) 195710015Speter{ 195856498Speter struct si_port *pp = arg; 195956498Speter struct tty *tp; 196010015Speter int oldspl; 196110015Speter 196210015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 196310015Speter pp, pp->sp_state)); 196410015Speter 196510015Speter oldspl = spltty(); 196610015Speter 196710015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 196810015Speter splx(oldspl); 196910015Speter return; 197010015Speter } 197110015Speter pp->sp_state &= ~SS_LSTART; 197210015Speter pp->sp_state |= SS_INLSTART; 197310015Speter 197410015Speter tp = pp->sp_tty; 197510015Speter 197610015Speter /* deal with the process exit case */ 197710015Speter ttwwakeup(tp); 197810015Speter 197912174Speter /* nudge protocols - eg: ppp */ 198010015Speter (*linesw[tp->t_line].l_start)(tp); 198110015Speter 198210015Speter pp->sp_state &= ~SS_INLSTART; 198310015Speter splx(oldspl); 198410015Speter} 198510015Speter 198610015Speter/* 198710015Speter * Stop output on a line. called at spltty(); 198810015Speter */ 1989105215Sphkstatic void 199056498Spetersi_stop(struct tty *tp, int rw) 199110015Speter{ 199210015Speter volatile struct si_channel *ccbp; 199310015Speter struct si_port *pp; 199410015Speter 199510015Speter pp = TP2PP(tp); 199610015Speter ccbp = pp->sp_ccb; 199710015Speter 199851654Sphk DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw)); 199910015Speter 200010015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 200110015Speter if (rw & FWRITE) { 200210015Speter /* what level are we meant to be flushing anyway? */ 200310015Speter if (tp->t_state & TS_BUSY) { 200410015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 200510015Speter tp->t_state &= ~TS_BUSY; 200610015Speter ttwwakeup(tp); /* Bruce???? */ 200710015Speter } 200810015Speter } 200912174Speter#if 1 /* XXX: this doesn't work right yet.. */ 201012174Speter /* XXX: this may have been failing because we used to call l_rint() 201112174Speter * while we were looping based on these two counters. Now, we collect 201212174Speter * the data and then loop stuffing it into l_rint(), making this 201312174Speter * useless. Should we cause this to blow away the staging buffer? 201412174Speter */ 201510015Speter if (rw & FREAD) { 201610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 201710015Speter } 201810015Speter#endif 201910015Speter} 202010015Speter 202110015Speter/* 202234832Speter * Issue a command to the host card CPU. 202310015Speter */ 202410015Speter 202510015Speterstatic void 202656498Spetersi_command(struct si_port *pp, int cmd, int waitflag) 202710015Speter{ 202810015Speter int oldspl; 202910015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 203010015Speter int x; 203110015Speter 203210015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 203310015Speter pp, cmd, waitflag, ccbp->hi_stat)); 203410015Speter 203510015Speter oldspl = spltty(); /* Keep others out */ 203610015Speter 203710015Speter /* wait until it's finished what it was doing.. */ 203816575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 203916575Speter * is turned off. */ 204010015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 204110015Speter x != IDLE_CLOSE && 204216575Speter x != IDLE_BREAK && 204310015Speter x != cmd) { 204410015Speter if (in_intr) { /* Prevent sleep in intr */ 204510015Speter DPRINT((pp, DBG_PARAM, 204610015Speter "cmd intr collision - completing %d\trequested %d\n", 204710015Speter x, cmd)); 204810015Speter splx(oldspl); 204910015Speter return; 205010015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 205110015Speter "sicmd1", 1)) { 205210015Speter splx(oldspl); 205310015Speter return; 205410015Speter } 205510015Speter } 205616575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 205710015Speter 205810015Speter /* if there was a pending command, cause a state-change wakeup */ 205916575Speter switch(pp->sp_pend) { 206016575Speter case LOPEN: 206116575Speter case MPEND: 206216575Speter case MOPEN: 206316575Speter case CONFIG: 206416575Speter case SBREAK: 206516575Speter case EBREAK: 206616575Speter wakeup(&pp->sp_state); 206716575Speter break; 206816575Speter default: 206916575Speter break; 207010015Speter } 207110015Speter 207210015Speter pp->sp_pend = cmd; /* New command pending */ 207310015Speter ccbp->hi_stat = cmd; /* Post it */ 207410015Speter 207510015Speter if (waitflag) { 207610015Speter if (in_intr) { /* If in interrupt handler */ 207710015Speter DPRINT((pp, DBG_PARAM, 207810015Speter "attempt to sleep in si_intr - cmd req %d\n", 207910015Speter cmd)); 208010015Speter splx(oldspl); 208110015Speter return; 208216575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 208316575Speter ccbp->hi_stat != IDLE_BREAK) { 208410015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 208510015Speter "sicmd2", 0)) 208610015Speter break; 208710015Speter } 208810015Speter } 208910015Speter splx(oldspl); 209010015Speter} 209110015Speter 209210015Speterstatic void 209356498Spetersi_disc_optim(struct tty *tp, struct termios *t, struct si_port *pp) 209410015Speter{ 209510015Speter /* 209610015Speter * XXX can skip a lot more cases if Smarts. Maybe 209710015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 209810015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 209910015Speter */ 210050442Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) && 210150442Speter (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && 210250442Speter (!(t->c_iflag & PARMRK) || 210350442Speter (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && 210450442Speter !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && 210550442Speter linesw[tp->t_line].l_rint == ttyinput) 210610015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 210710015Speter else 210810015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 210933322Sphk pp->sp_hotchar = linesw[tp->t_line].l_hotchar; 211050442Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 211110161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 211210161Speter pp->sp_hotchar)); 211310015Speter} 211410015Speter 211510015Speter 211610015Speter#ifdef SI_DEBUG 211713353Speter 211856505Spetervoid 211913353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 212010015Speter{ 212113353Speter va_list ap; 212213630Sphk 212310015Speter if ((pp == NULL && (si_debug&flags)) || 212410015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 212534832Speter if (pp != NULL) 212634832Speter printf("%ci%d(%d): ", 's', 212746679Sphk (int)SI_CARD(minor(pp->sp_tty->t_dev)), 212846679Sphk (int)SI_PORT(minor(pp->sp_tty->t_dev))); 212913630Sphk va_start(ap, fmt); 213013630Sphk vprintf(fmt, ap); 213113353Speter va_end(ap); 213210015Speter } 213310015Speter} 213410015Speter 213510015Speterstatic char * 213656498Spetersi_mctl2str(enum si_mctl cmd) 213710015Speter{ 213810015Speter switch (cmd) { 213934832Speter case GET: 214034832Speter return("GET"); 214134832Speter case SET: 214234832Speter return("SET"); 214334832Speter case BIS: 214434832Speter return("BIS"); 214534832Speter case BIC: 214634832Speter return("BIC"); 214710015Speter } 214810015Speter return("BAD"); 214910015Speter} 215012502Sjulian 215112624Speter#endif /* DEBUG */ 215212502Sjulian 215334832Speterstatic char * 215456498Spetersi_modulename(int host_type, int uart_type) 215534832Speter{ 215634832Speter switch (host_type) { 215734832Speter /* Z280 based cards */ 215850442Speter case SIEISA: 215950442Speter case SIHOST2: 216034832Speter case SIHOST: 216134832Speter case SIPCI: 216234832Speter switch (uart_type) { 216334832Speter case 0: 216434832Speter return(" (XIO)"); 216534832Speter case 1: 216634832Speter return(" (SI)"); 216734832Speter } 216834832Speter break; 216934832Speter /* T225 based hosts */ 217034832Speter case SIJETPCI: 217134832Speter case SIJETISA: 217234832Speter switch (uart_type) { 217334832Speter case 0: 217434832Speter return(" (SI)"); 217534832Speter case 40: 217634832Speter return(" (XIO)"); 217736856Sphk case 72: 217836856Sphk return(" (SXDC)"); 217934832Speter } 218034832Speter break; 218134832Speter } 218234832Speter return(""); 218334832Speter} 2184