1139749Simp/*- 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 * 3310015Speter */ 3410015Speter 35119419Sobrien#include <sys/cdefs.h> 36119419Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/si/si.c 320923 2017-07-12 22:16:54Z jhb $"); 37119419Sobrien 3810015Speter#ifndef lint 3934832Speterstatic const char si_copyright1[] = "@(#) Copyright (C) Specialix International, 1990,1992,1998", 4034832Speter si_copyright2[] = "@(#) Copyright (C) Andy Rutter 1993", 4156505Speter si_copyright3[] = "@(#) Copyright (C) Peter Wemm 2000"; 4210015Speter#endif /* not lint */ 4310015Speter 4431778Seivind#include "opt_compat.h" 4532929Seivind#include "opt_debug_si.h" 46166091Smarius#include "opt_eisa.h" 4731778Seivind 4810015Speter#include <sys/param.h> 4910015Speter#include <sys/systm.h> 50136058Sphk#include <sys/serial.h> 5110015Speter#include <sys/tty.h> 5210015Speter#include <sys/conf.h> 5324131Sbde#include <sys/fcntl.h> 5410015Speter#include <sys/kernel.h> 5510015Speter#include <sys/malloc.h> 56164033Srwatson#include <sys/priv.h> 5715683Speter#include <sys/sysctl.h> 5856498Speter#include <sys/bus.h> 5956498Speter#include <machine/bus.h> 6056498Speter#include <sys/rman.h> 6156498Speter#include <machine/resource.h> 6210015Speter 6310015Speter 6412659Sbde#include <vm/vm.h> 6512662Sdg#include <vm/pmap.h> 6612659Sbde 6713353Speter#include <machine/stdarg.h> 6810015Speter 6956498Speter#include <dev/si/sireg.h> 7056505Speter#include <dev/si/sivar.h> 7156498Speter#include <dev/si/si.h> 7256498Speter 7310015Speter/* 7410015Speter * This device driver is designed to interface the Specialix International 7534832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 7634832Speter * EISA or PCI bus machine. 7710015Speter * 7834832Speter * The controller is interfaced to the host via dual port RAM 7934832Speter * and an interrupt. 8033395Speter * 8134832Speter * The code for the Host 1 (very old ISA cards) has not been tested. 8210015Speter */ 8310015Speter 84182871Speter#undef POLL /* turn on poller to scan for lost interrupts */ 85179589Speter#if 0 8617547Speter#define REALPOLL /* on each poll, scan for work regardless */ 87179589Speter#endif 8817547Speter#define POLLHZ (hz/10) /* 10 times per second */ 8912496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 9034832Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 9134832Speter#define JET_INT_COUNT 100 /* max of 100 ints per second */ 9215639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 9310015Speter 9456498Speterstatic void si_command(struct si_port *, int, int); 95130585Sphkstatic int si_Sioctl(struct cdev *, u_long, caddr_t, int, struct thread *); 96182871Speter/* static void si_stop(struct tty *, int); */ 97182871Speter#if 0 9825047Sbdestatic timeout_t si_lstart; 99182871Speter#endif 10010015Speter 101182871Speterstatic tsw_outwakeup_t si_start; 102182871Speterstatic tsw_ioctl_t siioctl; 103182871Speterstatic tsw_close_t siclose; 104182871Speterstatic tsw_modem_t simodem; 105182871Speterstatic tsw_open_t siopen; 106182871Speterstatic tsw_param_t siparam; 10756505Speter 10856498Speterstatic void si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip); 10956498Speterstatic char * si_modulename(int host_type, int uart_type); 11010708Speter 111136058Sphkstatic struct cdevsw si_Scdevsw = { 112126080Sphk .d_version = D_VERSION, 113136058Sphk .d_ioctl = si_Sioctl, 114111815Sphk .d_name = "si", 115126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 11638485Sbde}; 11712675Sjulian 11810962Speterstatic int si_Nports; 11910962Speterstatic int si_Nmodules; 120182871Speterstatic int si_debug; 12110015Speter 12234832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 123100743SpeterTUNABLE_INT("machdep.si_debug", &si_debug); 12434832Speter 12556498Speterstatic int si_numunits; 12610044Speter 12756505Speterdevclass_t si_devclass; 12856498Speter 129182871Speterstruct si_speedtab { 130182871Speter int sp_speed; /* Speed. */ 131182871Speter int sp_code; /* Code. */ 132182871Speter}; 133182871Speter 13412174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 13510015Speter# define B2000 2000 13610015Speter#endif 137182871Speterstatic struct si_speedtab bdrates[] = { 13850442Speter { B75, CLK75, }, /* 0x0 */ 13950442Speter { B110, CLK110, }, /* 0x1 */ 14050442Speter { B150, CLK150, }, /* 0x3 */ 14150442Speter { B300, CLK300, }, /* 0x4 */ 14250442Speter { B600, CLK600, }, /* 0x5 */ 14350442Speter { B1200, CLK1200, }, /* 0x6 */ 14450442Speter { B2000, CLK2000, }, /* 0x7 */ 14550442Speter { B2400, CLK2400, }, /* 0x8 */ 14650442Speter { B4800, CLK4800, }, /* 0x9 */ 14750442Speter { B9600, CLK9600, }, /* 0xb */ 14850442Speter { B19200, CLK19200, }, /* 0xc */ 14950442Speter { B38400, CLK38400, }, /* 0x2 (out of order!) */ 15050442Speter { B57600, CLK57600, }, /* 0xd */ 15150442Speter { B115200, CLK110, }, /* 0x1 (dupe!, 110 baud on "si") */ 15250442Speter { -1, -1 }, 15310015Speter}; 15410015Speter 15510015Speter 15610015Speter#ifdef POLL 15715683Speterstatic int si_pollrate; /* in addition to irq */ 15856498Speterstatic int si_realpoll = 0; /* poll HW on timer */ 15915639Speter 16016403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 16117547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 16250442Speter 16310015Speterstatic int init_finished = 0; 16456498Speterstatic void si_poll(void *); 16510015Speter#endif 16610015Speter 16710015Speter/* 16810015Speter * Array of adapter types and the corresponding RAM size. The order of 16910015Speter * entries here MUST match the ordinal of the adapter type. 17010015Speter */ 171136058Sphkstatic const char *si_type[] = { 17210015Speter "EMPTY", 17310015Speter "SIHOST", 17434832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 17510015Speter "SIHOST2", 17610015Speter "SIEISA", 17733395Speter "SIPCI", 17833395Speter "SXPCI", 17933395Speter "SXISA", 18010015Speter}; 18110015Speter 182179589Speter#ifdef SI_DEBUG 183179589Speterstatic char * 184179589Spetersi_cmdname(int cmd) 185179589Speter{ 186179589Speter static char buf[32]; 187179589Speter 188179589Speter switch (cmd) { 189179589Speter case IDLE_OPEN: return("IDLE_OPEN"); 190179589Speter case LOPEN: return("LOPEN"); 191179589Speter case MOPEN: return("MOPEN"); 192179589Speter case MPEND: return("MPEND"); 193179589Speter case CONFIG: return("CONFIG"); 194179589Speter case CLOSE: return("CLOSE"); 195179589Speter case SBREAK: return("SBREAK"); 196179589Speter case EBREAK: return("EBREAK"); 197179589Speter case IDLE_CLOSE: return("IDLE_CLOSE"); 198179589Speter case IDLE_BREAK: return("IDLE_BREAK"); 199179589Speter case FCLOSE: return("FCLOSE"); 200179589Speter case RESUME: return("RESUME"); 201179589Speter case WFLUSH: return("WFLUSH"); 202179589Speter case RFLUSH: return("RFLUSH"); 203179589Speter default: 204179589Speter sprintf(buf, "?cmd:0x%x?", cmd); 205179589Speter return (buf); 206179589Speter } 207179589Speter} 208179589Speter#endif 209179589Speter 21056498Speter/* 21156498Speter * We have to make an 8 bit version of bcopy, since some cards can't 21256498Speter * deal with 32 bit I/O 21356498Speter */ 21456498Speterstatic void __inline 21556498Spetersi_bcopy(const void *src, void *dst, size_t len) 21656498Speter{ 217132771Skan u_char *d; 218132771Skan const u_char *s; 219132771Skan 220132771Skan d = dst; 221132771Skan s = src; 22256498Speter while (len--) 223132771Skan *d++ = *s++; 22456498Speter} 22556498Speterstatic void __inline 22656498Spetersi_vbcopy(const volatile void *src, void *dst, size_t len) 22756498Speter{ 228132771Skan u_char *d; 229132771Skan const volatile u_char *s; 230132771Skan 231132771Skan d = dst; 232132771Skan s = src; 23356498Speter while (len--) 234132771Skan *d++ = *s++; 23556498Speter} 23656498Speterstatic void __inline 23756498Spetersi_bcopyv(const void *src, volatile void *dst, size_t len) 23856498Speter{ 239132771Skan volatile u_char *d; 240132771Skan const u_char *s; 241132771Skan 242132771Skan d = dst; 243132771Skan s = src; 24456498Speter while (len--) 245132771Skan *d++ = *s++; 24656498Speter} 24756498Speter 248182871Speterstatic int 249182871Spetersi_speedtab(int speed, struct si_speedtab *table) 250182871Speter{ 251182871Speter for ( ; table->sp_speed != -1; table++) 252182871Speter if (table->sp_speed == speed) 253182871Speter return (table->sp_code); 254182871Speter return (-1); 255182871Speter} 256182871Speter 257182871Speter 258182871Speterstatic struct ttydevsw si_tty_class = { 259182871Speter .tsw_flags = TF_INITLOCK|TF_CALLOUT, 260182871Speter .tsw_open = siopen, 261182871Speter .tsw_close = siclose, 262182871Speter .tsw_outwakeup = si_start, 263182871Speter /* .tsw_stop = si_stop */ 264182871Speter .tsw_ioctl = siioctl, 265182871Speter .tsw_param = siparam, 266182871Speter .tsw_modem = simodem, 267182871Speter}; 268182871Speter 269182871Speter 27034832Speter/* 27110015Speter * Attach the device. Initialize the card. 27210015Speter */ 27356505Speterint 27456498Spetersiattach(device_t dev) 27510015Speter{ 27656498Speter int unit; 27756498Speter struct si_softc *sc; 27810015Speter struct si_port *pp; 279136058Sphk struct tty *tp; 28010015Speter volatile struct si_channel *ccbp; 28110015Speter volatile struct si_reg *regp; 28210015Speter volatile caddr_t maddr; 28310015Speter struct si_module *modp; 28410015Speter int nmodule, nport, x, y; 28512174Speter int uart_type; 28610015Speter 28756498Speter sc = device_get_softc(dev); 28856498Speter unit = device_get_unit(dev); 28910015Speter 29056505Speter sc->sc_typename = si_type[sc->sc_type]; 29156505Speter if (si_numunits < unit + 1) 29256505Speter si_numunits = unit + 1; 29356505Speter 29456498Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", unit)); 29510015Speter 29656498Speter#ifdef POLL 29756498Speter if (si_pollrate == 0) { 29856498Speter si_pollrate = POLLHZ; /* in addition to irq */ 29956498Speter#ifdef REALPOLL 30056498Speter si_realpoll = 1; /* scan always */ 30156498Speter#endif 30256498Speter } 30356498Speter#endif 30456498Speter 30533395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 30633395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 30733395Speter 30810015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 30910015Speter 31010015Speter maddr = sc->sc_maddr; 31110015Speter 31234832Speter /* Stop the CPU first so it won't stomp around while we load */ 31334832Speter 31434832Speter switch (sc->sc_type) { 315166091Smarius#ifdef DEV_EISA 31634832Speter case SIEISA: 31756498Speter outb(sc->sc_iobase + 2, sc->sc_irq << 4); 318166091Smarius#endif 31934832Speter break; 32034832Speter case SIPCI: 32134832Speter *(maddr+SIPCIRESET) = 0; 32234832Speter break; 32334832Speter case SIJETPCI: /* fall through to JET ISA */ 32434832Speter case SIJETISA: 32534832Speter *(maddr+SIJETCONFIG) = 0; 32634832Speter break; 32734832Speter case SIHOST2: 32834832Speter *(maddr+SIPLRESET) = 0; 32934832Speter break; 33034832Speter case SIHOST: 33134832Speter *(maddr+SIRESET) = 0; 33234832Speter break; 33334832Speter default: /* this should never happen */ 33434832Speter printf("si%d: unsupported configuration\n", unit); 33556498Speter return EINVAL; 33634832Speter break; 33734832Speter } 33834832Speter 33934832Speter /* OK, now lets download the download code */ 34034832Speter 34136956Ssteve if (SI_ISJET(sc->sc_type)) { 34233395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 34356498Speter unit, si3_t225_dsize)); 34434832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 34534832Speter si3_t225_dsize); 34634832Speter DPRINT((0, DBG_DOWNLOAD, 34734832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 34856498Speter unit, si3_t225_bsize, si3_t225_bootloadaddr)); 34934832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 35034832Speter si3_t225_bsize); 35134832Speter } else { 35233395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 35356498Speter unit, si2_z280_dsize)); 35434832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 35534832Speter si2_z280_dsize); 35633395Speter } 35710015Speter 35834832Speter /* Now start the CPU */ 35934832Speter 36010015Speter switch (sc->sc_type) { 361166091Smarius#ifdef DEV_EISA 36210015Speter case SIEISA: 36334832Speter /* modify the download code to tell it that it's on an EISA */ 36434832Speter *(maddr + 0x42) = 1; 36556498Speter outb(sc->sc_iobase + 2, (sc->sc_irq << 4) | 4); 36656498Speter (void)inb(sc->sc_iobase + 3); /* reset interrupt */ 36710015Speter break; 368166091Smarius#endif 36933395Speter case SIPCI: 37034832Speter /* modify the download code to tell it that it's on a PCI */ 37133395Speter *(maddr+0x42) = 1; 37233395Speter *(maddr+SIPCIRESET) = 1; 37333395Speter *(maddr+SIPCIINTCL) = 0; 37433395Speter break; 37533395Speter case SIJETPCI: 37633395Speter *(maddr+SIJETRESET) = 0; 37733395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 37833395Speter break; 37933395Speter case SIJETISA: 38033395Speter *(maddr+SIJETRESET) = 0; 38134832Speter switch (sc->sc_irq) { 38256498Speter case 9: 38334832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 38434832Speter break; 38556498Speter case 10: 38634832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 38734832Speter break; 38856498Speter case 11: 38934832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 39034832Speter break; 39156498Speter case 12: 39234832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 39334832Speter break; 39456498Speter case 15: 39534832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 39634832Speter break; 39734832Speter } 39833395Speter break; 39910015Speter case SIHOST: 40010015Speter *(maddr+SIRESET_CL) = 0; 40110015Speter *(maddr+SIINTCL_CL) = 0; 40210015Speter break; 40310015Speter case SIHOST2: 40410015Speter *(maddr+SIPLRESET) = 0x10; 40510015Speter switch (sc->sc_irq) { 40656498Speter case 11: 40710015Speter *(maddr+SIPLIRQ11) = 0x10; 40810015Speter break; 40956498Speter case 12: 41010015Speter *(maddr+SIPLIRQ12) = 0x10; 41110015Speter break; 41256498Speter case 15: 41310015Speter *(maddr+SIPLIRQ15) = 0x10; 41410015Speter break; 41510015Speter } 41610015Speter *(maddr+SIPLIRQCLR) = 0x10; 41710015Speter break; 41834832Speter default: /* this should _REALLY_ never happen */ 41934832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 42056498Speter return EINVAL; 42110015Speter } 42210015Speter 42310015Speter DELAY(1000000); /* wait around for a second */ 42410015Speter 42510015Speter regp = (struct si_reg *)maddr; 42610015Speter y = 0; 42710015Speter /* wait max of 5 sec for init OK */ 42810015Speter while (regp->initstat == 0 && y++ < 10) { 42910015Speter DELAY(500000); 43010015Speter } 43110015Speter switch (regp->initstat) { 43210015Speter case 0: 43310015Speter printf("si%d: startup timeout - aborting\n", unit); 43412174Speter sc->sc_type = SIEMPTY; 43556498Speter return EINVAL; 43610015Speter case 1: 43736956Ssteve if (SI_ISJET(sc->sc_type)) { 43834832Speter /* set throttle to 100 times per second */ 43934832Speter regp->int_count = JET_INT_COUNT; 44034832Speter /* rx_intr_count is a NOP in Jet */ 44134832Speter } else { 44234832Speter /* set throttle to 125 times per second */ 44334832Speter regp->int_count = INT_COUNT; 44434832Speter /* rx intr max of 25 times per second */ 44534832Speter regp->rx_int_count = RXINT_COUNT; 44634832Speter } 44710015Speter regp->int_pending = 0; /* no intr pending */ 44810015Speter regp->int_scounter = 0; /* reset counter */ 44910015Speter break; 45010015Speter case 0xff: 45110015Speter /* 45210015Speter * No modules found, so give up on this one. 45310015Speter */ 45410015Speter printf("si%d: %s - no ports found\n", unit, 45510015Speter si_type[sc->sc_type]); 45610015Speter return 0; 45710015Speter default: 45834832Speter printf("si%d: download code version error - initstat %x\n", 45910015Speter unit, regp->initstat); 46056498Speter return EINVAL; 46110015Speter } 46210015Speter 46310015Speter /* 46410015Speter * First time around the ports just count them in order 46510015Speter * to allocate some memory. 46610015Speter */ 46710015Speter nport = 0; 46810015Speter modp = (struct si_module *)(maddr + 0x80); 46910015Speter for (;;) { 47012174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 47134832Speter switch (modp->sm_type) { 47234832Speter case TA4: 47310015Speter DPRINT((0, DBG_DOWNLOAD, 47434832Speter "si%d: Found old TA4 module, 4 ports\n", 47534832Speter unit)); 47634832Speter x = 4; 47710015Speter break; 47834832Speter case TA8: 47934832Speter DPRINT((0, DBG_DOWNLOAD, 48034832Speter "si%d: Found old TA8 module, 8 ports\n", 48134832Speter unit)); 48234832Speter x = 8; 48334832Speter break; 48434832Speter case TA4_ASIC: 48534832Speter DPRINT((0, DBG_DOWNLOAD, 48634832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 48734832Speter unit)); 48834832Speter x = 4; 48934832Speter break; 49034832Speter case TA8_ASIC: 49134832Speter DPRINT((0, DBG_DOWNLOAD, 49234832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 49334832Speter unit)); 49434832Speter x = 8; 49534832Speter break; 49634832Speter case MTA: 49734832Speter DPRINT((0, DBG_DOWNLOAD, 49834832Speter "si%d: Found CD1400 module, 8 ports\n", 49934832Speter unit)); 50034832Speter x = 8; 50134832Speter break; 50234832Speter case SXDC: 50334832Speter DPRINT((0, DBG_DOWNLOAD, 50434832Speter "si%d: Found SXDC module, 8 ports\n", 50534832Speter unit)); 50634832Speter x = 8; 50734832Speter break; 50810015Speter default: 50910015Speter printf("si%d: unknown module type %d\n", 51010015Speter unit, modp->sm_type); 51134832Speter goto try_next; 51210015Speter } 51334832Speter 51434832Speter /* this was limited in firmware and is also a driver issue */ 51534832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 51634832Speter printf("si%d: extra ports ignored\n", unit); 51734832Speter goto try_next; 51834832Speter } 51934832Speter 52034832Speter nport += x; 52134832Speter si_Nports += x; 52234832Speter si_Nmodules++; 52334832Speter 52434832Spetertry_next: 52510015Speter if (modp->sm_next == 0) 52610015Speter break; 52710015Speter modp = (struct si_module *) 52810015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 52910015Speter } 53010015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 53169781Sdwmalone M_DEVBUF, M_NOWAIT | M_ZERO); 53210015Speter if (sc->sc_ports == 0) { 53310015Speter printf("si%d: fail to malloc memory for port structs\n", 53410015Speter unit); 53556498Speter return EINVAL; 53610015Speter } 53710015Speter sc->sc_nport = nport; 53810015Speter 53910015Speter /* 54010015Speter * Scan round the ports again, this time initialising. 54110015Speter */ 54210015Speter pp = sc->sc_ports; 54310015Speter nmodule = 0; 54410015Speter modp = (struct si_module *)(maddr + 0x80); 54534832Speter uart_type = 1000; /* arbitary, > uchar_max */ 54610015Speter for (;;) { 54734832Speter switch (modp->sm_type) { 54834832Speter case TA4: 54934832Speter nport = 4; 55010015Speter break; 55134832Speter case TA8: 55234832Speter nport = 8; 55334832Speter break; 55434832Speter case TA4_ASIC: 55534832Speter nport = 4; 55634832Speter break; 55734832Speter case TA8_ASIC: 55834832Speter nport = 8; 55934832Speter break; 56034832Speter case MTA: 56134832Speter nport = 8; 56234832Speter break; 56334832Speter case SXDC: 56434832Speter nport = 8; 56534832Speter break; 56610015Speter default: 56734832Speter goto try_next2; 56810015Speter } 56934832Speter nmodule++; 57034832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 57134832Speter if (uart_type == 1000) 57234832Speter uart_type = ccbp->type; 57334832Speter else if (uart_type != ccbp->type) 57434832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 57534832Speter unit, nmodule, 57634832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 57734832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 57834832Speter 57934832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 58034832Speter pp->sp_ccb = ccbp; /* save the address */ 58134832Speter pp->sp_pend = IDLE_CLOSE; 58234832Speter pp->sp_state = 0; /* internal flag */ 583136058Sphk#ifdef SI_DEBUG 584154081Sjhb sprintf(pp->sp_name, "si%r%r", unit, 585154081Sjhb (int)(pp - sc->sc_ports)); 586136058Sphk#endif 587193018Sed tp = pp->sp_tty = tty_alloc_mutex(&si_tty_class, pp, &Giant); 588182871Speter tty_makedev(tp, NULL, "A%r%r", unit, (int)(pp - sc->sc_ports)); 58934832Speter } 59034832Spetertry_next2: 59110015Speter if (modp->sm_next == 0) { 59234832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 59310015Speter unit, 59410015Speter sc->sc_typename, 59510015Speter sc->sc_nport, 59612174Speter nmodule, 59734832Speter uart_type, 59834832Speter si_modulename(sc->sc_type, uart_type)); 59910015Speter break; 60010015Speter } 60110015Speter modp = (struct si_module *) 60210015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 60310015Speter } 60412502Sjulian 605154081Sjhb if (unit == 0) 606154081Sjhb make_dev(&si_Scdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 607154081Sjhb "si_control"); 608320923Sjhb device_printf(dev, 609320923Sjhb "WARNING: This driver is deprecated and will be removed.\n"); 61056498Speter return (0); 61110015Speter} 61210015Speter 61312675Sjulianstatic int 614182871Spetersiopen(struct tty *tp) 61510015Speter{ 61610015Speter 617182871Speter DPRINT((0, DBG_ENTRY|DBG_OPEN, "siopen()\n")); 618179589Speter mtx_assert(&Giant, MA_OWNED); 61910015Speter#ifdef POLL 62010015Speter /* 62110015Speter * We've now got a device, so start the poller. 62210015Speter */ 62310015Speter if (init_finished == 0) { 62415639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 62510015Speter init_finished = 1; 62610015Speter } 62710015Speter#endif 628182871Speter DPRINT((0, DBG_EXIT|DBG_OPEN, "siopen() finished\n")); 629136058Sphk return(0); 63010015Speter} 63110015Speter 632136058Sphkstatic void 633136058Sphksiclose(struct tty *tp) 63410015Speter{ 63556498Speter struct si_port *pp; 63610015Speter 637182871Speter DPRINT((0, DBG_ENTRY|DBG_CLOSE, "siclose()\n")); 638179589Speter mtx_assert(&Giant, MA_OWNED); 639182871Speter pp = tty_softc(tp); 640179589Speter (void) si_command(pp, FCLOSE, SI_WAIT); 641182871Speter DPRINT((0, DBG_EXIT|DBG_CLOSE, "siclose() finished\n")); 64210015Speter} 64310015Speter 644182871Speterstatic int 645182871Spetersiioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 64610015Speter{ 64756498Speter struct si_port *pp; 64810015Speter 649182871Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "siioctl(0x%lx,0x%x)\n", cmd, data)); 650179589Speter mtx_assert(&Giant, MA_OWNED); 651182871Speter pp = tty_softc(tp); 652182871Speter switch (cmd) { 653182871Speter case TIOCSBRK: 65416575Speter si_command(pp, SBREAK, SI_WAIT); 655182871Speter return (0); 656182871Speter case TIOCCBRK: 65716575Speter si_command(pp, EBREAK, SI_WAIT); 658182871Speter return (0); 659182871Speter } 660182871Speter return (ENOIOCTL); /* Let the common tty ioctl handler do it */ 66110015Speter} 66210015Speter 66310015Speter/* 664136058Sphk * Handle the Specialix ioctls on the control dev. 66510015Speter */ 66610015Speterstatic int 667130585Sphksi_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 66810015Speter{ 66910015Speter struct si_softc *xsc; 67056498Speter struct si_port *xpp; 67110015Speter volatile struct si_reg *regp; 67210015Speter struct si_tcsi *dp; 67310044Speter struct si_pstat *sps; 67411872Sphk int *ip, error = 0; 67510015Speter int oldspl; 67610015Speter int card, port; 67710015Speter 678182871Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,0x%lx,0x%x)\n", 679182871Speter devtoname(dev), cmd, data)); 680179589Speter mtx_assert(&Giant, MA_OWNED); 68110015Speter 68210044Speter#if 1 68310044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 68410044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 68510044Speter#endif 68610044Speter 68710015Speter oldspl = spltty(); /* better safe than sorry */ 68810015Speter 68910015Speter ip = (int *)data; 69010015Speter 691164033Srwatson#define SUCHECK if ((error = priv_check(td, PRIV_DRIVER))) goto out 69210015Speter 69310015Speter switch (cmd) { 69410015Speter case TCSIPORTS: 69510015Speter *ip = si_Nports; 69610015Speter goto out; 69710015Speter case TCSIMODULES: 69810015Speter *ip = si_Nmodules; 69910015Speter goto out; 70010015Speter case TCSISDBG_ALL: 70110015Speter SUCHECK; 70210015Speter si_debug = *ip; 70310015Speter goto out; 70410015Speter case TCSIGDBG_ALL: 70510015Speter *ip = si_debug; 70610015Speter goto out; 70710015Speter default: 70810015Speter /* 70910015Speter * Check that a controller for this port exists 71010015Speter */ 71110044Speter 71210044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 71310044Speter 71410015Speter dp = (struct si_tcsi *)data; 71510044Speter sps = (struct si_pstat *)data; 71610015Speter card = dp->tc_card; 71756498Speter xsc = devclass_get_softc(si_devclass, card); /* check.. */ 71856498Speter if (xsc == NULL || xsc->sc_type == SIEMPTY) { 71910015Speter error = ENOENT; 72010015Speter goto out; 72110015Speter } 72210015Speter /* 72310015Speter * And check that a port exists 72410015Speter */ 72510015Speter port = dp->tc_port; 72610015Speter if (port < 0 || port >= xsc->sc_nport) { 72710015Speter error = ENOENT; 72810015Speter goto out; 72910015Speter } 73010015Speter xpp = xsc->sc_ports + port; 73110015Speter regp = (struct si_reg *)xsc->sc_maddr; 73210015Speter } 73310015Speter 73410015Speter switch (cmd) { 73510015Speter case TCSIDEBUG: 73610015Speter#ifdef SI_DEBUG 73710015Speter SUCHECK; 73810015Speter if (xpp->sp_debug) 73910015Speter xpp->sp_debug = 0; 74010015Speter else { 74110015Speter xpp->sp_debug = DBG_ALL; 74210015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 74310015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 74410015Speter } 74510015Speter break; 74610015Speter#else 74710015Speter error = ENODEV; 74810015Speter goto out; 74910015Speter#endif 75010015Speter case TCSISDBG_LEVEL: 75110015Speter case TCSIGDBG_LEVEL: 75210015Speter#ifdef SI_DEBUG 75310015Speter if (cmd == TCSIGDBG_LEVEL) { 75410015Speter dp->tc_dbglvl = xpp->sp_debug; 75510015Speter } else { 75610015Speter SUCHECK; 75710015Speter xpp->sp_debug = dp->tc_dbglvl; 75810015Speter } 75910015Speter break; 76010015Speter#else 76110015Speter error = ENODEV; 76210015Speter goto out; 76310015Speter#endif 76410015Speter case TCSIGRXIT: 76510015Speter dp->tc_int = regp->rx_int_count; 76610015Speter break; 76710015Speter case TCSIRXIT: 76810015Speter SUCHECK; 76910015Speter regp->rx_int_count = dp->tc_int; 77010015Speter break; 77110015Speter case TCSIGIT: 77210015Speter dp->tc_int = regp->int_count; 77310015Speter break; 77410015Speter case TCSIIT: 77510015Speter SUCHECK; 77610015Speter regp->int_count = dp->tc_int; 77710015Speter break; 77810044Speter case TCSISTATE: 77910044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 78010015Speter break; 78110044Speter /* these next three use a different structure */ 78210044Speter case TCSI_PORT: 78310015Speter SUCHECK; 78434832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 78510015Speter break; 78610044Speter case TCSI_CCB: 78710044Speter SUCHECK; 78850442Speter si_vbcopy(xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 78910015Speter break; 79010015Speter default: 79110015Speter error = EINVAL; 79210015Speter goto out; 79310015Speter } 79410015Speterout: 79510015Speter splx(oldspl); 79610015Speter return(error); /* success */ 79710015Speter} 79810015Speter 79910015Speter/* 80010015Speter * siparam() : Configure line params 80110015Speter * called at spltty(); 80210015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 80310015Speter * caller must arrange this if it's important.. 80410015Speter */ 80512724Sphkstatic int 80656498Spetersiparam(struct tty *tp, struct termios *t) 80710015Speter{ 808182871Speter struct si_port *pp = tty_softc(tp); 80910015Speter volatile struct si_channel *ccbp; 81010015Speter int oldspl, cflag, iflag, oflag, lflag; 81110015Speter int error = 0; /* shutup gcc */ 81210015Speter int ispeed = 0; /* shutup gcc */ 81310015Speter int ospeed = 0; /* shutup gcc */ 81410161Speter BYTE val; 81510015Speter 81610015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 817179589Speter mtx_assert(&Giant, MA_OWNED); 81810015Speter cflag = t->c_cflag; 81910015Speter iflag = t->c_iflag; 82010015Speter oflag = t->c_oflag; 82110015Speter lflag = t->c_lflag; 82210044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 82310044Speter oflag, cflag, iflag, lflag)); 82410015Speter 82534832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 82610015Speter 82710015Speter /* if not hung up.. */ 82810015Speter if (t->c_ospeed != 0) { 82910015Speter /* translate baud rate to firmware values */ 830182871Speter ospeed = si_speedtab(t->c_ospeed, bdrates); 83110015Speter ispeed = t->c_ispeed ? 832182871Speter si_speedtab(t->c_ispeed, bdrates) : ospeed; 83310015Speter /* enforce legit baud rate */ 83410015Speter if (ospeed < 0 || ispeed < 0) 83510015Speter return (EINVAL); 83610015Speter } 83710015Speter 83810015Speter oldspl = spltty(); 83910015Speter 84010015Speter ccbp = pp->sp_ccb; 84110015Speter 84210161Speter /* ========== set hi_break ========== */ 84310161Speter val = 0; 84410161Speter if (iflag & IGNBRK) /* Breaks */ 84510161Speter val |= BR_IGN; 84610161Speter if (iflag & BRKINT) /* Interrupt on break? */ 84710161Speter val |= BR_INT; 84810161Speter if (iflag & PARMRK) /* Parity mark? */ 84910161Speter val |= BR_PARMRK; 85010161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 85110161Speter val |= BR_PARIGN; 85210161Speter ccbp->hi_break = val; 85310161Speter 85410161Speter /* ========== set hi_csr ========== */ 85510015Speter /* if not hung up.. */ 85610015Speter if (t->c_ospeed != 0) { 85710015Speter /* Set I/O speeds */ 85810161Speter val = (ispeed << 4) | ospeed; 85910015Speter } 86010161Speter ccbp->hi_csr = val; 86110015Speter 86210161Speter /* ========== set hi_mr2 ========== */ 86310161Speter val = 0; 864182871Speter if (cflag & CSTOPB) /* Stop bits */ 86510161Speter val |= MR2_2_STOP; 86610015Speter else 86710161Speter val |= MR2_1_STOP; 868182871Speter 86910161Speter /* 87010161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 87110161Speter * a DCE, hence the reverse sense of RTS and CTS 87210161Speter */ 87310161Speter /* Output Flow - RTS must be raised before data can be sent */ 87410161Speter if (cflag & CCTS_OFLOW) 87510161Speter val |= MR2_RTSCONT; 87610161Speter 87716575Speter ccbp->hi_mr2 = val; 87810161Speter 87910161Speter /* ========== set hi_mr1 ========== */ 88010161Speter val = 0; 88110015Speter if (!(cflag & PARENB)) /* Parity */ 88210161Speter val |= MR1_NONE; 88310015Speter else 88410161Speter val |= MR1_WITH; 88510015Speter if (cflag & PARODD) 88610161Speter val |= MR1_ODD; 88710015Speter 888182871Speter if ((cflag & CS8) == CS8) /* 8 data bits? */ 88910161Speter val |= MR1_8_BITS; 890182871Speter else if ((cflag & CS7) == CS7) /* 7 data bits? */ 89110161Speter val |= MR1_7_BITS; 892182871Speter else if ((cflag & CS6) == CS6) /* 6 data bits? */ 89310161Speter val |= MR1_6_BITS; 894182871Speter else /* Must be 5 */ 89510161Speter val |= MR1_5_BITS; 896182871Speter 89710161Speter /* 89810161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 89910161Speter * a DCE, hence the reverse sense of RTS and CTS 90010161Speter */ 90110161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 90210161Speter if (cflag & CRTS_IFLOW) 90310161Speter val |= MR1_CTSCONT; 90410015Speter 90510161Speter ccbp->hi_mr1 = val; 90610161Speter 90710161Speter /* ========== set hi_mask ========== */ 90810161Speter val = 0xff; 90910161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 91010161Speter val &= 0xFF; 91110161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 91210161Speter val &= 0x7F; 91310161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 91410161Speter val &= 0x3F; 91510161Speter } else { /* Must be 5 */ 91610161Speter val &= 0x1F; 91710161Speter } 91810015Speter if (iflag & ISTRIP) 91910161Speter val &= 0x7F; 92010015Speter 92110161Speter ccbp->hi_mask = val; 92210161Speter 92310161Speter /* ========== set hi_prtcl ========== */ 92456592Speter val = SP_DCEN; /* Monitor DCD always, or TIOCMGET misses it */ 92510161Speter if (iflag & IXANY) 92610161Speter val |= SP_TANY; 92710161Speter if (iflag & IXON) 92810161Speter val |= SP_TXEN; 92910161Speter if (iflag & IXOFF) 93010161Speter val |= SP_RXEN; 93110161Speter if (iflag & INPCK) 93210161Speter val |= SP_PAEN; 93310015Speter 93410161Speter ccbp->hi_prtcl = val; 93510161Speter 93610161Speter 93710161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 93810161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 93910015Speter ccbp->hi_txon = t->c_cc[VSTART]; 94010015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 94110015Speter 94210015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 94310015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 94410015Speter 94510161Speter /* ========== send settings to the card ========== */ 94610015Speter /* potential sleep here */ 94710015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 94810015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 94910015Speter else 95010015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 95110015Speter 95210161Speter /* ========== set DTR etc ========== */ 95310015Speter /* Hangup if ospeed == 0 */ 95410015Speter if (t->c_ospeed == 0) { 955136058Sphk (void) simodem(tp, 0, SER_DTR | SER_RTS); 95610015Speter } else { 95710015Speter /* 95810015Speter * If the previous speed was 0, may need to re-enable 95934832Speter * the modem signals 96034832Speter */ 961136058Sphk (void) simodem(tp, SER_DTR | SER_RTS, 0); 96210015Speter } 96310015Speter 964182871Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x HI_CSR %x\n", 965182871Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break, ccbp->hi_csr)); 96610015Speter 96710015Speter splx(oldspl); 96810015Speter return(error); 96910015Speter} 97010015Speter 97110015Speter/* 97210015Speter * Set/Get state of modem control lines. 97310015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 97410015Speter * TIOCM_DTR DSR 97510015Speter * TIOCM_RTS CTS 97610015Speter */ 97710015Speterstatic int 978136058Sphksimodem(struct tty *tp, int sigon, int sigoff) 97910015Speter{ 980136058Sphk struct si_port *pp; 98110015Speter volatile struct si_channel *ccbp; 98210015Speter int x; 98310015Speter 984182871Speter pp = tty_softc(tp); 985136058Sphk DPRINT((pp, DBG_ENTRY|DBG_MODEM, "simodem(%x,%x)\n", sigon, sigoff)); 986179589Speter mtx_assert(&Giant, MA_OWNED); 98710015Speter ccbp = pp->sp_ccb; /* Find channel address */ 988136058Sphk if (sigon == 0 && sigoff == 0) { 98910015Speter x = ccbp->hi_ip; 990136058Sphk /* 991136058Sphk * XXX: not sure this is correct, should it be CTS&DSR ? 992136058Sphk * XXX: or do we (just) miss CTS & DSR ? 993136058Sphk */ 994136058Sphk if (x & IP_DCD) sigon |= SER_DCD; 995136058Sphk if (x & IP_DTR) sigon |= SER_DTR; 996136058Sphk if (x & IP_RTS) sigon |= SER_RTS; 997136058Sphk if (x & IP_RI) sigon |= SER_RI; 998136058Sphk return (sigon); 99910015Speter } 1000136058Sphk 1001136058Sphk x = ccbp->hi_op; 1002136058Sphk if (sigon & SER_DTR) 1003136058Sphk x |= OP_DSR; 1004136058Sphk if (sigoff & SER_DTR) 1005136058Sphk x &= ~OP_DSR; 1006136058Sphk if (sigon & SER_RTS) 1007136058Sphk x |= OP_CTS; 1008136058Sphk if (sigoff & SER_RTS) 1009136058Sphk x &= ~OP_CTS; 1010136058Sphk ccbp->hi_op = x; 101110015Speter return 0; 101210015Speter} 101310015Speter 101410015Speter/* 101510015Speter * Handle change of modem state 101610015Speter */ 101710015Speterstatic void 101856498Spetersi_modem_state(struct si_port *pp, struct tty *tp, int hi_ip) 101910015Speter{ 102010015Speter /* if a modem dev */ 1021179589Speter mtx_assert(&Giant, MA_OWNED); 102210015Speter if (hi_ip & IP_DCD) { 102350442Speter if (!(pp->sp_last_hi_ip & IP_DCD)) { 1024182871Speter DPRINT((pp, DBG_INTR, "modem carr on%d\n")); 1025182871Speter (void)ttydisc_modem(tp, 1); 102610015Speter } 102710015Speter } else { 102810015Speter if (pp->sp_last_hi_ip & IP_DCD) { 102910015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 1030182871Speter#if 0 /* XXX mpsafetty ttyld_modem used to tell us to shutdown the port or not */ 1031182871Speter if (ttydisc_modem(tp, 0)) 1032136058Sphk (void) simodem(tp, 0, SER_DTR | SER_RTS); 1033182871Speter#else 1034182871Speter ttydisc_modem(tp, 0); 1035182871Speter#endif 103610015Speter } 103710015Speter } 103810015Speter pp->sp_last_hi_ip = hi_ip; 103910015Speter 104010015Speter} 104110015Speter 104210015Speter/* 104310015Speter * Poller to catch missed interrupts. 104412174Speter * 104512496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 104612496Speter * better response. We could really use a "periodic" version timeout(). :-) 104710015Speter */ 104810015Speter#ifdef POLL 104910708Speterstatic void 105010015Spetersi_poll(void *nothing) 105110015Speter{ 105256498Speter struct si_softc *sc; 105356498Speter int i; 105410015Speter volatile struct si_reg *regp; 105556498Speter struct si_port *pp; 105612174Speter int lost, oldspl, port; 105710015Speter 105810015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 105911609Speter oldspl = spltty(); 1060179589Speter mtx_assert(&Giant, MA_OWNED); 106110015Speter lost = 0; 106256498Speter for (i = 0; i < si_numunits; i++) { 106356498Speter sc = devclass_get_softc(si_devclass, i); 106456498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 106510015Speter continue; 106610015Speter regp = (struct si_reg *)sc->sc_maddr; 106734832Speter 106810015Speter /* 106910015Speter * See if there has been a pending interrupt for 2 seconds 107033395Speter * or so. The test (int_scounter >= 200) won't correspond 107110015Speter * to 2 seconds if int_count gets changed. 107210015Speter */ 107310015Speter if (regp->int_pending != 0) { 107410015Speter if (regp->int_scounter >= 200 && 107510015Speter regp->initstat == 1) { 107612174Speter printf("si%d: lost intr\n", i); 107710015Speter lost++; 107810015Speter } 107910015Speter } else { 108010015Speter regp->int_scounter = 0; 108110015Speter } 108210015Speter 108312174Speter /* 108412174Speter * gripe about no input flow control.. 108512174Speter */ 108612174Speter pp = sc->sc_ports; 108712174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 108812174Speter if (pp->sp_delta_overflows > 0) { 108912174Speter printf("si%d: %d tty level buffer overflows\n", 109012174Speter i, pp->sp_delta_overflows); 109112174Speter pp->sp_delta_overflows = 0; 109212174Speter } 109312174Speter } 109410015Speter } 109517547Speter if (lost || si_realpoll) 109656498Speter si_intr(NULL); /* call intr with fake vector */ 109710015Speter splx(oldspl); 109810015Speter 109915639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 110010015Speter} 110110015Speter#endif /* ifdef POLL */ 110210015Speter 110310015Speter/* 110410015Speter * The interrupt handler polls ALL ports on ALL adapters each time 110510015Speter * it is called. 110610015Speter */ 110710015Speter 110812496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 110934832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 111010015Speter 111156505Spetervoid 111256498Spetersi_intr(void *arg) 111310015Speter{ 111456498Speter struct si_softc *sc; 111556498Speter struct si_port *pp; 111610015Speter volatile struct si_channel *ccbp; 111756498Speter struct tty *tp; 111810015Speter volatile caddr_t maddr; 111911872Sphk BYTE op, ip; 112012174Speter int x, card, port, n, i, isopen; 112110015Speter volatile BYTE *z; 112210015Speter BYTE c; 112310015Speter 112456498Speter sc = arg; 1125179589Speter mtx_assert(&Giant, MA_OWNED); 112656498Speter 112756498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); 112810015Speter 112910015Speter /* 113010015Speter * When we get an int we poll all the channels and do ALL pending 113110015Speter * work, not just the first one we find. This allows all cards to 113210015Speter * share the same vector. 113334832Speter * 113434832Speter * XXX - But if we're sharing the vector with something that's NOT 113534832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 113610015Speter */ 113756498Speter for (card = 0; card < si_numunits; card++) { 113856498Speter sc = devclass_get_softc(si_devclass, card); 113956498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 114010015Speter continue; 114112174Speter 114212174Speter /* 114312174Speter * First, clear the interrupt 114412174Speter */ 114510015Speter switch(sc->sc_type) { 114634832Speter case SIHOST: 114710015Speter maddr = sc->sc_maddr; 114810015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 114910015Speter /* flag nothing pending */ 115010015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 115110015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 115210015Speter break; 115310015Speter case SIHOST2: 115410015Speter maddr = sc->sc_maddr; 115510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 115610015Speter *(maddr+SIPLIRQCLR) = 0x00; 115710015Speter *(maddr+SIPLIRQCLR) = 0x10; 115810015Speter break; 115933395Speter case SIPCI: 116033395Speter maddr = sc->sc_maddr; 116133395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 116233395Speter *(maddr+SIPCIINTCL) = 0x0; 116333395Speter break; 116434832Speter case SIJETPCI: /* fall through to JETISA case */ 116533395Speter case SIJETISA: 116633395Speter maddr = sc->sc_maddr; 116733395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 116833395Speter *(maddr+SIJETINTCL) = 0x0; 116933395Speter break; 1170166091Smarius#ifdef DEV_EISA 117110015Speter case SIEISA: 117210015Speter maddr = sc->sc_maddr; 117310015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 117456498Speter (void)inb(sc->sc_iobase + 3); 117510015Speter break; 1176166091Smarius#endif 117710015Speter case SIEMPTY: 117810015Speter default: 117910015Speter continue; 118010015Speter } 118110015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 118210015Speter 118312174Speter /* 118412174Speter * check each port 118512174Speter */ 118650442Speter for (pp = sc->sc_ports, port = 0; port < sc->sc_nport; 118734832Speter pp++, port++) { 118810015Speter ccbp = pp->sp_ccb; 118910015Speter tp = pp->sp_tty; 1190182871Speter tty_lock(tp); 119110015Speter 119210015Speter /* 119310015Speter * See if a command has completed ? 119410015Speter */ 119510015Speter if (ccbp->hi_stat != pp->sp_pend) { 119610015Speter DPRINT((pp, DBG_INTR, 1197179589Speter "si_intr hi_stat = %s, pend = %s\n", 1198179589Speter si_cmdname(ccbp->hi_stat), 1199179589Speter si_cmdname(pp->sp_pend))); 120010015Speter switch(pp->sp_pend) { 120110015Speter case LOPEN: 120210015Speter case MPEND: 120310015Speter case MOPEN: 1204179589Speter case FCLOSE: 120510015Speter case CONFIG: 120616575Speter case SBREAK: 120716575Speter case EBREAK: 1208179589Speter /* sleeping in si_command */ 1209179589Speter DPRINT((pp, DBG_INTR, "do wakeup\n")); 121010015Speter wakeup(&pp->sp_state); 121110015Speter break; 121210015Speter } 1213179589Speter pp->sp_pend = ccbp->hi_stat; 121434832Speter } 121510015Speter 121610015Speter /* 121710015Speter * Continue on if it's closed 121810015Speter */ 1219182871Speter if (ccbp->hi_stat == IDLE_CLOSE) { 1220182871Speter tty_unlock(tp); 122110015Speter continue; 1222182871Speter } 122310015Speter 122410015Speter /* 122510015Speter * Do modem state change if not a local device 122610015Speter */ 122710015Speter si_modem_state(pp, tp, ccbp->hi_ip); 122810015Speter 122910015Speter /* 123034832Speter * Check to see if we should 'receive' characters. 123112174Speter */ 1232182871Speter isopen = tty_opened(tp); 123312174Speter 123412174Speter /* 123516575Speter * Do input break processing 123610015Speter */ 123710015Speter if (ccbp->hi_state & ST_BREAK) { 1238179589Speter if (isopen) 1239182871Speter ttydisc_rint(tp, 0, TRE_BREAK); 124010015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 124110015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 124210015Speter } 124310015Speter 124410015Speter /* 124512174Speter * Do RX stuff - if not open then dump any characters. 124612174Speter * XXX: This is VERY messy and needs to be cleaned up. 124712174Speter * 124812174Speter * XXX: can we leave data in the host adapter buffer 124912174Speter * when the clists are full? That may be dangerous 125012174Speter * if the user cannot get an interrupt signal through. 125110015Speter */ 125210015Speter 1253179589Speter more_rx: 125412174Speter 125512174Speter if (!isopen) { 1256182871Speter DPRINT((pp, DBG_INTR, "intr1: not open\n")); 125710015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 125812174Speter goto end_rx; 125912174Speter } 126010015Speter 1261182871Speter#if 0 /* XXXMPSAFETTY */ 126212174Speter /* 126315640Speter * If the tty input buffers are blocked, stop emptying 126415640Speter * the incoming buffers and let the auto flow control 126515640Speter * assert.. 126615640Speter */ 1267179589Speter if (tp->t_state & TS_TBLOCK) 126815640Speter goto end_rx; 1269182871Speter#endif 127015640Speter 127115640Speter /* 127212174Speter * Process read characters if not skipped above 127312174Speter */ 127415640Speter op = ccbp->hi_rxopos; 127515640Speter ip = ccbp->hi_rxipos; 127615640Speter c = ip - op; 1277179589Speter if (c == 0) 127812174Speter goto end_rx; 127910015Speter 128012174Speter n = c & 0xff; 128115640Speter if (n > 250) 128215640Speter n = 250; 128312174Speter 128412174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 128510015Speter n, op, ip)); 128610015Speter 128712174Speter /* 128812174Speter * Suck characters out of host card buffer into the 128912174Speter * "input staging buffer" - so that we dont leave the 129012174Speter * host card in limbo while we're possibly echoing 129112174Speter * characters and possibly flushing input inside the 129212174Speter * ldisc l_rint() routine. 129312174Speter */ 129412496Speter if (n <= SI_BUFFERSIZE - op) { 129510015Speter 129612174Speter z = ccbp->hi_rxbuf + op; 129750442Speter si_vbcopy(z, si_rxbuf, n); 129810015Speter 129912174Speter op += n; 130012174Speter } else { 130112496Speter x = SI_BUFFERSIZE - op; 130210015Speter 130312174Speter z = ccbp->hi_rxbuf + op; 130450442Speter si_vbcopy(z, si_rxbuf, x); 130510015Speter 130612174Speter z = ccbp->hi_rxbuf; 130750442Speter si_vbcopy(z, si_rxbuf + x, n - x); 130810015Speter 130912174Speter op += n; 131012174Speter } 131110015Speter 131212174Speter /* clear collected characters from buffer */ 131312174Speter ccbp->hi_rxopos = op; 131412174Speter 131512174Speter /* 131612174Speter * at this point... 131712174Speter * n = number of chars placed in si_rxbuf 131812174Speter */ 131910015Speter 1320182871Speter if (0 && ttydisc_can_bypass(tp)) { 132110015Speter 1322182871Speter i = ttydisc_rint_bypass(tp, (char *)si_rxbuf, n); 1323182871Speter if (i < n) 1324182871Speter pp->sp_delta_overflows += (n - i); 132510015Speter 132612174Speter } else { 132712174Speter /* 132812174Speter * It'd be nice to not have to go through the 132912174Speter * function call overhead for each char here. 133012174Speter * It'd be nice to block input it, saving a 133112174Speter * loop here and the call/return overhead. 133212174Speter */ 133312174Speter for(x = 0; x < n; x++) { 133412174Speter i = si_rxbuf[x]; 1335182871Speter if (ttydisc_rint(tp, i, 0) == -1) 133612174Speter pp->sp_delta_overflows++; 133712174Speter } 133812174Speter } 133912174Speter goto more_rx; /* try for more until RXbuf is empty */ 134010015Speter 1341179589Speter end_rx: 134210015Speter 1343182871Speter ttydisc_rint_done(tp); 1344182871Speter 134510015Speter /* 134610015Speter * Do TX stuff 134710015Speter */ 1348182871Speter si_start(tp); 1349182871Speter tty_unlock(tp); 135010015Speter 135110015Speter } /* end of for (all ports on this controller) */ 135210015Speter } /* end of for (all controllers) */ 135310015Speter 135456498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); 135510015Speter} 135610015Speter 135710015Speter/* 135810015Speter * Nudge the transmitter... 135912174Speter * 136012174Speter * XXX: I inherited some funny code here. It implies the host card only 136112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 136212174Speter * not interrupt when it's actually hits empty. In some cases, we have 136312174Speter * processes waiting for complete drain, and we need to simulate an interrupt 136412174Speter * about when we think the buffer is going to be empty (and retry if not). 136512174Speter * I really am not certain about this... I *need* the hardware manuals. 136610015Speter */ 136710015Speterstatic void 136856498Spetersi_start(struct tty *tp) 136910015Speter{ 137010015Speter struct si_port *pp; 137110015Speter volatile struct si_channel *ccbp; 1372182871Speter BYTE ipos, count; 1373182871Speter#if 0 137410015Speter int nchar; 1375182871Speter#endif 1376182871Speter int oldspl, n, amount; 137710015Speter 137810015Speter oldspl = spltty(); 1379179589Speter mtx_assert(&Giant, MA_OWNED); 138010015Speter 1381182871Speter pp = tty_softc(tp); 138210015Speter 138310015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 1384182871Speter "si_start(%x) sp_state %x\n", 1385182871Speter tp, pp->sp_state)); 138610015Speter 138710015Speter ccbp = pp->sp_ccb; 138810015Speter 1389182871Speter while ((count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos) < 255) { 1390182871Speter DPRINT((pp, DBG_START, "txbuf pend count %d\n", (BYTE)count)); 1391182871Speter ipos = (unsigned int)ccbp->hi_txipos; 1392182871Speter if ((int)ccbp->hi_txopos <= ipos) 1393182871Speter amount = SI_BUFFERSIZE - ipos; 1394182871Speter else 1395182871Speter amount = 255 - count; 1396182871Speter DPRINT((pp, DBG_START, "spaceleft amount %d\n", amount)); 1397182871Speter if (amount == 0) 139810015Speter break; 1399182871Speter n = ttydisc_getc(tp, si_txbuf, amount); 1400182871Speter DPRINT((pp, DBG_START, "getc n=%d\n", n)); 1401182871Speter if (n == 0) 1402182871Speter break; 1403182871Speter si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); 140410015Speter ccbp->hi_txipos += n; 140510015Speter } 140610015Speter 1407182871Speter#if 0 1408182871Speter /* 1409182871Speter * See if there are any characters still to come. If so, we can 1410182871Speter * depend on si_start being called again. 1411182871Speter * 1412182871Speter * XXX the manual is vague on this. It implies we get an interrupt 1413182871Speter * when the transmit queue reaches the 25% low water mark, but NOT 1414182871Speter * when it hits empty. 1415182871Speter */ 1416182871Speter nchar = ttyoutq_getsize(&tp->t_outq) - ttyoutq_bytesleft(&tp->t_outq); 1417182871Speter DPRINT((pp, DBG_START, "count %d, nchar %d\n", 1418182871Speter (BYTE)count, nchar)); 141910015Speter 1420182871Speter if (count != 0 && nchar == 0) { 142110015Speter int time; 142210015Speter 1423182871Speter /* XXX lame. Ticks per character. used to be a table. */ 1424182871Speter time = (tp->t_termios.c_ospeed + 9) / 10; 142534735Speter 142634735Speter if (time > 0) { 142734735Speter if (time < nchar) 142834735Speter time = nchar / time; 142934735Speter else 143034735Speter time = 2; 143110015Speter } else { 143234735Speter DPRINT((pp, DBG_START, 143334735Speter "bad char time value! %d\n", time)); 143434735Speter time = hz/10; 143510015Speter } 143610015Speter 1437179589Speter if ((pp->sp_state & SS_LSTART) != 0) 143829677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 143910015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 1440179589Speter pp->sp_state |= SS_LSTART; 144129677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 144210015Speter } 1443182871Speter#endif 144410015Speter 144510015Speter splx(oldspl); 144610015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 144710015Speter} 144810015Speter 1449182871Speter#if 0 145010015Speter/* 145110015Speter * This has to deal with two things... cause wakeups while waiting for 145210015Speter * tty drains on last process exit, and call l_start at about the right 145310015Speter * time for protocols like ppp. 145410015Speter */ 145510015Speterstatic void 145625047Sbdesi_lstart(void *arg) 145710015Speter{ 145856498Speter struct si_port *pp = arg; 145956498Speter struct tty *tp; 146010015Speter int oldspl; 146110015Speter 146210015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 146310015Speter pp, pp->sp_state)); 146410015Speter 146510015Speter oldspl = spltty(); 1466179589Speter mtx_assert(&Giant, MA_OWNED); 1467179589Speter pp->sp_state &= ~SS_LSTART; 1468136058Sphk tp = pp->sp_tty; 146910015Speter 1470182871Speter si_start(tp); 147110015Speter 147210015Speter splx(oldspl); 147310015Speter} 1474182871Speter#endif 147510015Speter 1476182871Speter#if 0 /* XXX mpsafetty */ 147710015Speter/* 147810015Speter * Stop output on a line. called at spltty(); 147910015Speter */ 1480105215Sphkstatic void 148156498Spetersi_stop(struct tty *tp, int rw) 148210015Speter{ 148310015Speter volatile struct si_channel *ccbp; 148410015Speter struct si_port *pp; 148510015Speter 1486179589Speter mtx_assert(&Giant, MA_OWNED); 1487182871Speter pp = tty_softc(tp); 148810015Speter ccbp = pp->sp_ccb; 148910015Speter 1490136058Sphk DPRINT((pp, DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw)); 149110015Speter 149210015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 149310015Speter if (rw & FWRITE) { 149410015Speter /* what level are we meant to be flushing anyway? */ 149510015Speter if (tp->t_state & TS_BUSY) { 1496136058Sphk si_command(pp, WFLUSH, SI_NOWAIT); 149710015Speter tp->t_state &= ~TS_BUSY; 149810015Speter ttwwakeup(tp); /* Bruce???? */ 149910015Speter } 150010015Speter } 150112174Speter#if 1 /* XXX: this doesn't work right yet.. */ 150212174Speter /* XXX: this may have been failing because we used to call l_rint() 150312174Speter * while we were looping based on these two counters. Now, we collect 150412174Speter * the data and then loop stuffing it into l_rint(), making this 150512174Speter * useless. Should we cause this to blow away the staging buffer? 150612174Speter */ 150710015Speter if (rw & FREAD) { 150810015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 150910015Speter } 151010015Speter#endif 151110015Speter} 1512182871Speter#endif 151310015Speter 151410015Speter/* 151534832Speter * Issue a command to the host card CPU. 1516182871Speter * 1517182871Speter * XXX This is all just so WRONG!. Ed says we're not supposed to sleep 1518182871Speter * here anyway. We sort of get away with it for now by using Giant. 1519182871Speter * Something better will have to be done. 1520182871Speter * Linux does a busy spin here waiting for the 8-bit cpu to notice the 1521182871Speter * posted command and respond to it. I'm not sure I like that either. 152210015Speter */ 152310015Speterstatic void 152456498Spetersi_command(struct si_port *pp, int cmd, int waitflag) 152510015Speter{ 152610015Speter int oldspl; 152710015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 152810015Speter int x; 1529182871Speter int err; 153010015Speter 1531179589Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%s,%d): hi_stat %s, sp_pend: %s\n", 1532179589Speter pp, si_cmdname(cmd), waitflag, si_cmdname(ccbp->hi_stat), 1533179589Speter si_cmdname(pp->sp_pend))); 153410015Speter 153510015Speter oldspl = spltty(); /* Keep others out */ 1536179589Speter mtx_assert(&Giant, MA_OWNED); 153710015Speter 153810015Speter /* wait until it's finished what it was doing.. */ 153916575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 154016575Speter * is turned off. */ 154110015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 154210015Speter x != IDLE_CLOSE && 154316575Speter x != IDLE_BREAK && 154410015Speter x != cmd) { 1545182871Speter DPRINT((pp, DBG_PARAM, "sicmd1 old cmd pending (going to tsleep): hi_stat (%s)\n", si_cmdname(ccbp->hi_stat))); 1546182871Speter err = tsleep(&pp->sp_state, (PSOCK+1)|PCATCH, "sicmd1", hz/4); 1547182871Speter if (err) { 1548179589Speter DPRINT((pp, DBG_PARAM, "sicmd1 timeout: hi_stat (%s)\n", 1549179589Speter si_cmdname(ccbp->hi_stat))); 1550179589Speter /* This is very very bad. The card has crashed. */ 1551179589Speter /* XXX the driver breaks at this point */ 1552182871Speter if (err == ETIMEDOUT) 1553188266Swkoszek DPRINT(("%s: tsleep1 timeout. hi_stat %s, sp_pend %s\n", pp->sp_name, si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 155410015Speter splx(oldspl); 155510015Speter return; 155610015Speter } 155710015Speter } 155816575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 1559182871Speter DPRINT((pp, DBG_PARAM, "sicmd1 now in: hi_stat (%s) sp_pend (%s)\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 156010015Speter 156110015Speter /* if there was a pending command, cause a state-change wakeup */ 156216575Speter switch(pp->sp_pend) { 156316575Speter case LOPEN: 156416575Speter case MPEND: 156516575Speter case MOPEN: 1566179589Speter case FCLOSE: 156716575Speter case CONFIG: 156816575Speter case SBREAK: 156916575Speter case EBREAK: 1570182871Speter DPRINT((pp, DBG_PARAM, "si_command: sp_pend %s, doing wakeup\n", si_cmdname(pp->sp_pend))); 157116575Speter wakeup(&pp->sp_state); 157216575Speter break; 157316575Speter default: 157416575Speter break; 157510015Speter } 157610015Speter 157710015Speter pp->sp_pend = cmd; /* New command pending */ 157810015Speter ccbp->hi_stat = cmd; /* Post it */ 1579182871Speter DPRINT((pp, DBG_PARAM, "sicmd now posted: hi_stat (%s) sp_pend (%s)\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 158010015Speter 158110015Speter if (waitflag) { 1582179589Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 1583179589Speter x != IDLE_CLOSE && 1584179589Speter x != IDLE_BREAK) { 1585182871Speter DPRINT((pp, DBG_PARAM, "sicmd2 now waiting: hi_stat (%s) sp_pend (%s) (going to tsleep)\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 1586182871Speter err = tsleep(&pp->sp_state, (PSOCK+1)|PCATCH, "sicmd2", hz); 1587182871Speter if (err) { 1588182871Speter DPRINT((pp, DBG_PARAM, "sicmd2 tsleep error: hi_stat (%s) sp_pend (%s)\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 1589182871Speter if (err == ETIMEDOUT) { 1590188266Swkoszek DPRINT(("%s: tsleep2 timeout. hi_stat %s, sp_pend %s\n", pp->sp_name, si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 1591182871Speter } 159210015Speter break; 1593182871Speter } 159410015Speter } 159510015Speter } 1596182871Speter DPRINT((pp, DBG_PARAM, "sicmd2 finished: hi_stat (%s) sp_pend (%s)\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); 159710015Speter splx(oldspl); 159810015Speter} 159910015Speter 160010015Speter 160110015Speter#ifdef SI_DEBUG 160213353Speter 160356505Spetervoid 160413353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 160510015Speter{ 160613353Speter va_list ap; 160713630Sphk 160810015Speter if ((pp == NULL && (si_debug&flags)) || 160910015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 161034832Speter if (pp != NULL) 1611136058Sphk printf("%s: ", pp->sp_name); 161213630Sphk va_start(ap, fmt); 161313630Sphk vprintf(fmt, ap); 161413353Speter va_end(ap); 161510015Speter } 161610015Speter} 161710015Speter 161812624Speter#endif /* DEBUG */ 161912502Sjulian 162034832Speterstatic char * 162156498Spetersi_modulename(int host_type, int uart_type) 162234832Speter{ 162334832Speter switch (host_type) { 162434832Speter /* Z280 based cards */ 1625166091Smarius#ifdef DEV_EISA 162650442Speter case SIEISA: 1627166091Smarius#endif 162850442Speter case SIHOST2: 162934832Speter case SIHOST: 163034832Speter case SIPCI: 163134832Speter switch (uart_type) { 163234832Speter case 0: 163334832Speter return(" (XIO)"); 163434832Speter case 1: 163534832Speter return(" (SI)"); 163634832Speter } 163734832Speter break; 163834832Speter /* T225 based hosts */ 163934832Speter case SIJETPCI: 164034832Speter case SIJETISA: 164134832Speter switch (uart_type) { 164234832Speter case 0: 164334832Speter return(" (SI)"); 164434832Speter case 40: 164534832Speter return(" (XIO)"); 164636856Sphk case 72: 164736856Sphk return(" (SXDC)"); 164834832Speter } 164934832Speter break; 165034832Speter } 165134832Speter return(""); 165234832Speter} 1653