si.c revision 151383
1218822Sdim/*- 2218822Sdim * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 333965Sjdp * 4218822Sdim * Copyright (C) 1990, 1992, 1998 Specialix International, 5218822Sdim * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 638889Sjdp * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au> 738889Sjdp * 838889Sjdp * Originally derived from: SunOS 4.x version 933965Sjdp * Ported from BSDI version to FreeBSD by Peter Wemm. 1033965Sjdp * 1138889Sjdp * Redistribution and use in source and binary forms, with or without 1238889Sjdp * modification, are permitted provided that the following conditions 1338889Sjdp * are met: 1433965Sjdp * 1. Redistributions of source code must retain the above copyright 15218822Sdim * notices, this list of conditions and the following disclaimer. 1638889Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1738889Sjdp * notices, this list of conditions and the following disclaimer in the 1838889Sjdp * documentation and/or other materials provided with the distribution. 1933965Sjdp * 3. All advertising materials mentioning features or use of this software 2038889Sjdp * must display the following acknowledgement: 2138889Sjdp * This product includes software developed by Andy Rutter of 2238889Sjdp * Advanced Methods and Tools Ltd. based on original information 2338889Sjdp * from Specialix International. 24218822Sdim * 4. Neither the name of Advanced Methods and Tools, nor Specialix 2538889Sjdp * International may be used to endorse or promote products derived from 26218822Sdim * this software without specific prior written permission. 27218822Sdim * 28218822Sdim * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 29218822Sdim * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30218822Sdim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 3138889Sjdp * NO EVENT SHALL THE AUTHORS BE LIABLE. 3238889Sjdp * 3338889Sjdp */ 3438889Sjdp 3538889Sjdp#include <sys/cdefs.h> 3638889Sjdp__FBSDID("$FreeBSD: head/sys/dev/si/si.c 151383 2005-10-16 20:22:56Z phk $"); 3738889Sjdp 3838889Sjdp#ifndef lint 3938889Sjdpstatic const char si_copyright1[] = "@(#) Copyright (C) Specialix International, 1990,1992,1998", 40218822Sdim si_copyright2[] = "@(#) Copyright (C) Andy Rutter 1993", 41218822Sdim si_copyright3[] = "@(#) Copyright (C) Peter Wemm 2000"; 42218822Sdim#endif /* not lint */ 43218822Sdim 44218822Sdim#include "opt_compat.h" 45218822Sdim#include "opt_debug_si.h" 46218822Sdim#include "opt_tty.h" 47218822Sdim 48218822Sdim#include <sys/param.h> 49218822Sdim#include <sys/systm.h> 50218822Sdim#include <sys/serial.h> 51218822Sdim#include <sys/tty.h> 52218822Sdim#include <sys/conf.h> 53218822Sdim#include <sys/fcntl.h> 54218822Sdim#include <sys/kernel.h> 55218822Sdim#include <sys/malloc.h> 56218822Sdim#include <sys/sysctl.h> 57218822Sdim#include <sys/bus.h> 58218822Sdim#include <machine/bus.h> 59218822Sdim#include <sys/rman.h> 60218822Sdim#include <machine/resource.h> 61218822Sdim 62218822Sdim 63218822Sdim#include <vm/vm.h> 64218822Sdim#include <vm/pmap.h> 65218822Sdim 66218822Sdim#include <machine/stdarg.h> 67218822Sdim 68218822Sdim#include <dev/si/sireg.h> 69218822Sdim#include <dev/si/sivar.h> 70218822Sdim#include <dev/si/si.h> 71218822Sdim 72218822Sdim/* 73218822Sdim * This device driver is designed to interface the Specialix International 74218822Sdim * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 75218822Sdim * EISA or PCI bus machine. 76218822Sdim * 77218822Sdim * The controller is interfaced to the host via dual port RAM 78218822Sdim * and an interrupt. 79218822Sdim * 80218822Sdim * The code for the Host 1 (very old ISA cards) has not been tested. 81218822Sdim */ 82218822Sdim 83218822Sdim#define POLL /* turn on poller to scan for lost interrupts */ 84218822Sdim#define REALPOLL /* on each poll, scan for work regardless */ 85218822Sdim#define POLLHZ (hz/10) /* 10 times per second */ 86218822Sdim#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 87218822Sdim#define INT_COUNT 25000 /* max of 125 ints per second */ 88218822Sdim#define JET_INT_COUNT 100 /* max of 100 ints per second */ 89218822Sdim#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 90218822Sdim 91218822Sdimstatic void si_command(struct si_port *, int, int); 92218822Sdimstatic int si_Sioctl(struct cdev *, u_long, caddr_t, int, struct thread *); 93218822Sdimstatic void si_start(struct tty *); 94218822Sdimstatic void si_stop(struct tty *, int); 95218822Sdimstatic timeout_t si_lstart; 96218822Sdim 97218822Sdimstatic t_break_t sibreak; 98218822Sdimstatic t_close_t siclose; 99218822Sdimstatic t_modem_t simodem; 100218822Sdimstatic t_open_t siopen; 101218822Sdim 102218822Sdimstatic int siparam(struct tty *, struct termios *); 103218822Sdim 104218822Sdimstatic void si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip); 105218822Sdimstatic char * si_modulename(int host_type, int uart_type); 106218822Sdim 107218822Sdimstatic struct cdevsw si_Scdevsw = { 108218822Sdim .d_version = D_VERSION, 109218822Sdim .d_ioctl = si_Sioctl, 110218822Sdim .d_name = "si", 111218822Sdim .d_flags = D_TTY | D_NEEDGIANT, 112218822Sdim}; 113218822Sdim 114218822Sdimstatic int si_Nports; 115218822Sdimstatic int si_Nmodules; 116218822Sdimstatic int si_debug = 0; /* data, not bss, so it's patchable */ 117218822Sdim 118218822SdimSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 119218822SdimTUNABLE_INT("machdep.si_debug", &si_debug); 120218822Sdim 121218822Sdimstatic int si_numunits; 122218822Sdim 123218822Sdimdevclass_t si_devclass; 124218822Sdim 125218822Sdim#ifndef B2000 /* not standard, but the hardware knows it. */ 126218822Sdim# define B2000 2000 127218822Sdim#endif 128218822Sdimstatic struct speedtab bdrates[] = { 129218822Sdim { B75, CLK75, }, /* 0x0 */ 130218822Sdim { B110, CLK110, }, /* 0x1 */ 131218822Sdim { B150, CLK150, }, /* 0x3 */ 132218822Sdim { B300, CLK300, }, /* 0x4 */ 133218822Sdim { B600, CLK600, }, /* 0x5 */ 134218822Sdim { B1200, CLK1200, }, /* 0x6 */ 135218822Sdim { B2000, CLK2000, }, /* 0x7 */ 136218822Sdim { B2400, CLK2400, }, /* 0x8 */ 137218822Sdim { B4800, CLK4800, }, /* 0x9 */ 138218822Sdim { B9600, CLK9600, }, /* 0xb */ 139218822Sdim { B19200, CLK19200, }, /* 0xc */ 140218822Sdim { B38400, CLK38400, }, /* 0x2 (out of order!) */ 141218822Sdim { B57600, CLK57600, }, /* 0xd */ 142218822Sdim { B115200, CLK110, }, /* 0x1 (dupe!, 110 baud on "si") */ 143218822Sdim { -1, -1 }, 144218822Sdim}; 145218822Sdim 146218822Sdim 147218822Sdim/* populated with approx character/sec rates - translated at card 148218822Sdim * initialisation time to chars per tick of the clock */ 149218822Sdimstatic int done_chartimes = 0; 150218822Sdimstatic struct speedtab chartimes[] = { 151218822Sdim { B75, 8, }, 152218822Sdim { B110, 11, }, 153218822Sdim { B150, 15, }, 154218822Sdim { B300, 30, }, 155218822Sdim { B600, 60, }, 156218822Sdim { B1200, 120, }, 157218822Sdim { B2000, 200, }, 158218822Sdim { B2400, 240, }, 159218822Sdim { B4800, 480, }, 160218822Sdim { B9600, 960, }, 161218822Sdim { B19200, 1920, }, 162218822Sdim { B38400, 3840, }, 163218822Sdim { B57600, 5760, }, 164218822Sdim { B115200, 11520, }, 165218822Sdim { -1, -1 }, 166218822Sdim}; 167218822Sdimstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 168218822Sdim 169218822Sdim#ifdef POLL 170218822Sdimstatic int si_pollrate; /* in addition to irq */ 171218822Sdimstatic int si_realpoll = 0; /* poll HW on timer */ 172218822Sdim 173218822SdimSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 174218822SdimSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 175218822Sdim 176218822Sdimstatic int init_finished = 0; 177218822Sdimstatic void si_poll(void *); 178218822Sdim#endif 179218822Sdim 180218822Sdim/* 181218822Sdim * Array of adapter types and the corresponding RAM size. The order of 182218822Sdim * entries here MUST match the ordinal of the adapter type. 183218822Sdim */ 184218822Sdimstatic const char *si_type[] = { 185218822Sdim "EMPTY", 186218822Sdim "SIHOST", 187218822Sdim "SIMCA", /* FreeBSD does not support Microchannel */ 188218822Sdim "SIHOST2", 189218822Sdim "SIEISA", 190218822Sdim "SIPCI", 191218822Sdim "SXPCI", 192218822Sdim "SXISA", 193218822Sdim}; 194218822Sdim 195218822Sdim/* 196218822Sdim * We have to make an 8 bit version of bcopy, since some cards can't 197218822Sdim * deal with 32 bit I/O 198218822Sdim */ 199218822Sdimstatic void __inline 200218822Sdimsi_bcopy(const void *src, void *dst, size_t len) 201218822Sdim{ 202218822Sdim u_char *d; 203218822Sdim const u_char *s; 204218822Sdim 205218822Sdim d = dst; 206218822Sdim s = src; 207218822Sdim while (len--) 208218822Sdim *d++ = *s++; 209218822Sdim} 210218822Sdimstatic void __inline 211218822Sdimsi_vbcopy(const volatile void *src, void *dst, size_t len) 212218822Sdim{ 213218822Sdim u_char *d; 21438889Sjdp const volatile u_char *s; 215218822Sdim 216218822Sdim d = dst; 217218822Sdim s = src; 218218822Sdim while (len--) 21938889Sjdp *d++ = *s++; 22060484Sobrien} 221218822Sdimstatic void __inline 22260484Sobriensi_bcopyv(const void *src, volatile void *dst, size_t len) 22338889Sjdp{ 22438889Sjdp volatile u_char *d; 225218822Sdim const u_char *s; 22638889Sjdp 22760484Sobrien d = dst; 22860484Sobrien s = src; 22933965Sjdp while (len--) 230218822Sdim *d++ = *s++; 231218822Sdim} 232218822Sdim 233218822Sdim/* 234218822Sdim * Attach the device. Initialize the card. 235218822Sdim */ 23660484Sobrienint 237218822Sdimsiattach(device_t dev) 23860484Sobrien{ 239218822Sdim int unit; 24038889Sjdp struct si_softc *sc; 241218822Sdim struct si_port *pp; 242218822Sdim struct tty *tp; 243218822Sdim volatile struct si_channel *ccbp; 244218822Sdim volatile struct si_reg *regp; 245218822Sdim volatile caddr_t maddr; 246104834Sobrien struct si_module *modp; 247104834Sobrien struct speedtab *spt; 24838889Sjdp int nmodule, nport, x, y; 249218822Sdim int uart_type; 250218822Sdim 251218822Sdim sc = device_get_softc(dev); 252218822Sdim unit = device_get_unit(dev); 253218822Sdim 25460484Sobrien sc->sc_typename = si_type[sc->sc_type]; 255218822Sdim if (si_numunits < unit + 1) 25638889Sjdp si_numunits = unit + 1; 257218822Sdim 258218822Sdim DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", unit)); 259218822Sdim 260218822Sdim#ifdef POLL 261218822Sdim if (si_pollrate == 0) { 26260484Sobrien si_pollrate = POLLHZ; /* in addition to irq */ 263218822Sdim#ifdef REALPOLL 264218822Sdim si_realpoll = 1; /* scan always */ 265218822Sdim#endif 266218822Sdim } 267218822Sdim#endif 268218822Sdim 269218822Sdim DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 270218822Sdim sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 271218822Sdim 272218822Sdim sc->sc_ports = NULL; /* mark as uninitialised */ 27338889Sjdp 27438889Sjdp maddr = sc->sc_maddr; 275218822Sdim 276218822Sdim /* Stop the CPU first so it won't stomp around while we load */ 27738889Sjdp 278218822Sdim switch (sc->sc_type) { 279218822Sdim case SIEISA: 28038889Sjdp outb(sc->sc_iobase + 2, sc->sc_irq << 4); 28160484Sobrien break; 28260484Sobrien case SIPCI: 283218822Sdim *(maddr+SIPCIRESET) = 0; 28438889Sjdp break; 285218822Sdim case SIJETPCI: /* fall through to JET ISA */ 286218822Sdim case SIJETISA: 28777298Sobrien *(maddr+SIJETCONFIG) = 0; 28877298Sobrien break; 28938889Sjdp case SIHOST2: 290218822Sdim *(maddr+SIPLRESET) = 0; 291218822Sdim break; 292218822Sdim case SIHOST: 293218822Sdim *(maddr+SIRESET) = 0; 294218822Sdim break; 295218822Sdim default: /* this should never happen */ 29660484Sobrien printf("si%d: unsupported configuration\n", unit); 29738889Sjdp return EINVAL; 298218822Sdim break; 299218822Sdim } 300218822Sdim 30177298Sobrien /* OK, now lets download the download code */ 30260484Sobrien 30338889Sjdp if (SI_ISJET(sc->sc_type)) { 304218822Sdim DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 305218822Sdim unit, si3_t225_dsize)); 306218822Sdim si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 307218822Sdim si3_t225_dsize); 308218822Sdim DPRINT((0, DBG_DOWNLOAD, 309218822Sdim "si%d: jet_bootstrap: nbytes %d -> %x\n", 310218822Sdim unit, si3_t225_bsize, si3_t225_bootloadaddr)); 311218822Sdim si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 312218822Sdim si3_t225_bsize); 313218822Sdim } else { 314218822Sdim DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 315218822Sdim unit, si2_z280_dsize)); 316218822Sdim si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 317218822Sdim si2_z280_dsize); 318218822Sdim } 319218822Sdim 320218822Sdim /* Now start the CPU */ 321218822Sdim 322218822Sdim switch (sc->sc_type) { 323218822Sdim case SIEISA: 324218822Sdim /* modify the download code to tell it that it's on an EISA */ 325218822Sdim *(maddr + 0x42) = 1; 326218822Sdim outb(sc->sc_iobase + 2, (sc->sc_irq << 4) | 4); 327218822Sdim (void)inb(sc->sc_iobase + 3); /* reset interrupt */ 328218822Sdim break; 329218822Sdim case SIPCI: 330218822Sdim /* modify the download code to tell it that it's on a PCI */ 331218822Sdim *(maddr+0x42) = 1; 332218822Sdim *(maddr+SIPCIRESET) = 1; 333218822Sdim *(maddr+SIPCIINTCL) = 0; 334218822Sdim break; 335218822Sdim case SIJETPCI: 336218822Sdim *(maddr+SIJETRESET) = 0; 337218822Sdim *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 338218822Sdim break; 339218822Sdim case SIJETISA: 340218822Sdim *(maddr+SIJETRESET) = 0; 341218822Sdim switch (sc->sc_irq) { 342218822Sdim case 9: 343218822Sdim *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 344218822Sdim break; 345218822Sdim case 10: 346218822Sdim *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 347218822Sdim break; 348218822Sdim case 11: 349218822Sdim *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 350218822Sdim break; 351218822Sdim case 12: 352218822Sdim *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 353218822Sdim break; 354218822Sdim case 15: 35538889Sjdp *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 356218822Sdim break; 35789857Sobrien } 35838889Sjdp break; 35938889Sjdp case SIHOST: 36077298Sobrien *(maddr+SIRESET_CL) = 0; 36177298Sobrien *(maddr+SIINTCL_CL) = 0; 36233965Sjdp break; 36360484Sobrien case SIHOST2: 36460484Sobrien *(maddr+SIPLRESET) = 0x10; 36533965Sjdp switch (sc->sc_irq) { 36633965Sjdp case 11: 36760484Sobrien *(maddr+SIPLIRQ11) = 0x10; 36860484Sobrien break; 36960484Sobrien case 12: 37060484Sobrien *(maddr+SIPLIRQ12) = 0x10; 37160484Sobrien break; 37233965Sjdp case 15: 37360484Sobrien *(maddr+SIPLIRQ15) = 0x10; 37460484Sobrien break; 37560484Sobrien } 37633965Sjdp *(maddr+SIPLIRQCLR) = 0x10; 37733965Sjdp break; 37833965Sjdp default: /* this should _REALLY_ never happen */ 37960484Sobrien printf("si%d: Uh, it was supported a second ago...\n", unit); 38060484Sobrien return EINVAL; 38160484Sobrien } 38260484Sobrien 38360484Sobrien DELAY(1000000); /* wait around for a second */ 384218822Sdim 38560484Sobrien regp = (struct si_reg *)maddr; 386218822Sdim y = 0; 387218822Sdim /* wait max of 5 sec for init OK */ 38833965Sjdp while (regp->initstat == 0 && y++ < 10) { 389104834Sobrien DELAY(500000); 390218822Sdim } 39133965Sjdp switch (regp->initstat) { 39233965Sjdp case 0: 39360484Sobrien printf("si%d: startup timeout - aborting\n", unit); 39460484Sobrien sc->sc_type = SIEMPTY; 395104834Sobrien return EINVAL; 396104834Sobrien case 1: 397104834Sobrien if (SI_ISJET(sc->sc_type)) { 398218822Sdim /* set throttle to 100 times per second */ 399218822Sdim regp->int_count = JET_INT_COUNT; 400104834Sobrien /* rx_intr_count is a NOP in Jet */ 40133965Sjdp } else { 402104834Sobrien /* set throttle to 125 times per second */ 403218822Sdim regp->int_count = INT_COUNT; 404104834Sobrien /* rx intr max of 25 times per second */ 405218822Sdim regp->rx_int_count = RXINT_COUNT; 406218822Sdim } 40733965Sjdp regp->int_pending = 0; /* no intr pending */ 408218822Sdim regp->int_scounter = 0; /* reset counter */ 409104834Sobrien break; 410218822Sdim case 0xff: 411218822Sdim /* 412218822Sdim * No modules found, so give up on this one. 413104834Sobrien */ 414104834Sobrien printf("si%d: %s - no ports found\n", unit, 415104834Sobrien si_type[sc->sc_type]); 416104834Sobrien return 0; 417218822Sdim default: 418104834Sobrien printf("si%d: download code version error - initstat %x\n", 419104834Sobrien unit, regp->initstat); 420218822Sdim return EINVAL; 421218822Sdim } 42233965Sjdp 42377298Sobrien /* 424130561Sobrien * First time around the ports just count them in order 425218822Sdim * to allocate some memory. 42633965Sjdp */ 42738889Sjdp nport = 0; 42838889Sjdp modp = (struct si_module *)(maddr + 0x80); 42933965Sjdp for (;;) { 43033965Sjdp DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 43138889Sjdp switch (modp->sm_type) { 43238889Sjdp case TA4: 43338889Sjdp DPRINT((0, DBG_DOWNLOAD, 43438889Sjdp "si%d: Found old TA4 module, 4 ports\n", 43560484Sobrien unit)); 436218822Sdim x = 4; 437218822Sdim break; 43877298Sobrien case TA8: 43977298Sobrien DPRINT((0, DBG_DOWNLOAD, 44077298Sobrien "si%d: Found old TA8 module, 8 ports\n", 44177298Sobrien unit)); 44277298Sobrien x = 8; 44377298Sobrien break; 44477298Sobrien case TA4_ASIC: 44577298Sobrien DPRINT((0, DBG_DOWNLOAD, 44677298Sobrien "si%d: Found ASIC TA4 module, 4 ports\n", 44777298Sobrien unit)); 44877298Sobrien x = 4; 44977298Sobrien break; 45077298Sobrien case TA8_ASIC: 45177298Sobrien DPRINT((0, DBG_DOWNLOAD, 45233965Sjdp "si%d: Found ASIC TA8 module, 8 ports\n", 45360484Sobrien unit)); 454218822Sdim x = 8; 455218822Sdim break; 456218822Sdim case MTA: 457218822Sdim DPRINT((0, DBG_DOWNLOAD, 458218822Sdim "si%d: Found CD1400 module, 8 ports\n", 459218822Sdim unit)); 460218822Sdim x = 8; 461218822Sdim break; 462218822Sdim case SXDC: 463218822Sdim DPRINT((0, DBG_DOWNLOAD, 464218822Sdim "si%d: Found SXDC module, 8 ports\n", 465218822Sdim unit)); 466218822Sdim x = 8; 467218822Sdim break; 468218822Sdim default: 469218822Sdim printf("si%d: unknown module type %d\n", 470218822Sdim unit, modp->sm_type); 471218822Sdim goto try_next; 472218822Sdim } 473218822Sdim 474218822Sdim /* this was limited in firmware and is also a driver issue */ 475218822Sdim if ((nport + x) > SI_MAXPORTPERCARD) { 476218822Sdim printf("si%d: extra ports ignored\n", unit); 47738889Sjdp goto try_next; 47860484Sobrien } 47938889Sjdp 480218822Sdim nport += x; 481218822Sdim si_Nports += x; 48260484Sobrien si_Nmodules++; 483218822Sdim 484218822Sdimtry_next: 485218822Sdim if (modp->sm_next == 0) 486130561Sobrien break; 487104834Sobrien modp = (struct si_module *) 488104834Sobrien (maddr + (unsigned)(modp->sm_next & 0x7fff)); 489104834Sobrien } 490218822Sdim sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 491104834Sobrien M_DEVBUF, M_NOWAIT | M_ZERO); 492104834Sobrien if (sc->sc_ports == 0) { 493104834Sobrien printf("si%d: fail to malloc memory for port structs\n", 494218822Sdim unit); 495218822Sdim return EINVAL; 49638889Sjdp } 49768765Sobrien sc->sc_nport = nport; 498218822Sdim 49938889Sjdp /* 50038889Sjdp * Scan round the ports again, this time initialising. 50138889Sjdp */ 502218822Sdim pp = sc->sc_ports; 50377298Sobrien nmodule = 0; 50433965Sjdp modp = (struct si_module *)(maddr + 0x80); 505218822Sdim uart_type = 1000; /* arbitary, > uchar_max */ 506218822Sdim for (;;) { 507218822Sdim switch (modp->sm_type) { 50860484Sobrien case TA4: 509218822Sdim nport = 4; 51068765Sobrien break; 511218822Sdim case TA8: 51289857Sobrien nport = 8; 513218822Sdim break; 514218822Sdim case TA4_ASIC: 51533965Sjdp nport = 4; 516218822Sdim break; 51760484Sobrien case TA8_ASIC: 51889857Sobrien nport = 8; 519218822Sdim break; 520218822Sdim case MTA: 52160484Sobrien nport = 8; 52277298Sobrien break; 523218822Sdim case SXDC: 524218822Sdim nport = 8; 52538889Sjdp break; 52638889Sjdp default: 527218822Sdim goto try_next2; 528218822Sdim } 529218822Sdim nmodule++; 530218822Sdim ccbp = (struct si_channel *)((char *)modp + 0x100); 531218822Sdim if (uart_type == 1000) 532218822Sdim uart_type = ccbp->type; 533218822Sdim else if (uart_type != ccbp->type) 534218822Sdim printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 535218822Sdim unit, nmodule, 536218822Sdim ccbp->type, si_modulename(sc->sc_type, ccbp->type), 537218822Sdim uart_type, si_modulename(sc->sc_type, uart_type)); 538218822Sdim 539218822Sdim for (x = 0; x < nport; x++, pp++, ccbp++) { 540218822Sdim pp->sp_ccb = ccbp; /* save the address */ 541218822Sdim pp->sp_pend = IDLE_CLOSE; 542218822Sdim pp->sp_state = 0; /* internal flag */ 543218822Sdim#ifdef SI_DEBUG 544218822Sdim sprintf(pp->sp_name, "si%r%r", unit, x); 545218822Sdim#endif 546218822Sdim tp = pp->sp_tty = ttyalloc(); 547218822Sdim tp->t_sc = pp; 548218822Sdim tp->t_break = sibreak; 549218822Sdim tp->t_close = siclose; 550218822Sdim tp->t_modem = simodem; 551218822Sdim tp->t_open = siopen; 552218822Sdim tp->t_oproc = si_start; 55338889Sjdp tp->t_param = siparam; 554218822Sdim tp->t_stop = si_stop; 555218822Sdim ttycreate(tp, TS_CALLOUT, "A%r%r", unit, x); 55638889Sjdp } 557218822Sdimtry_next2: 55838889Sjdp if (modp->sm_next == 0) { 559218822Sdim printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 560218822Sdim unit, 56138889Sjdp sc->sc_typename, 562218822Sdim sc->sc_nport, 56360484Sobrien nmodule, 564218822Sdim uart_type, 565218822Sdim si_modulename(sc->sc_type, uart_type)); 56660484Sobrien break; 567218822Sdim } 568218822Sdim modp = (struct si_module *) 569218822Sdim (maddr + (unsigned)(modp->sm_next & 0x7fff)); 570218822Sdim } 571218822Sdim if (done_chartimes == 0) { 57238889Sjdp for (spt = chartimes ; spt->sp_speed != -1; spt++) { 573218822Sdim if ((spt->sp_code /= hz) == 0) 574218822Sdim spt->sp_code = 1; 57538889Sjdp } 57638889Sjdp done_chartimes = 1; 577218822Sdim } 578218822Sdim 579218822Sdim make_dev(&si_Scdevsw, 0, 0, 0, 0600, "si_control"); 58038889Sjdp return (0); 58138889Sjdp} 582218822Sdim 58338889Sjdpstatic int 584218822Sdimsiopen(struct tty *tp, struct cdev *dev) 585218822Sdim{ 586218822Sdim 587218822Sdim#ifdef POLL 588218822Sdim /* 589218822Sdim * We've now got a device, so start the poller. 590218822Sdim */ 59138889Sjdp if (init_finished == 0) { 59238889Sjdp timeout(si_poll, (caddr_t)0L, si_pollrate); 59338889Sjdp init_finished = 1; 59438889Sjdp } 59560484Sobrien#endif 596218822Sdim return(0); 597218822Sdim} 598218822Sdim 599218822Sdimstatic void 60038889Sjdpsiclose(struct tty *tp) 60138889Sjdp{ 602218822Sdim struct si_port *pp; 603218822Sdim 604218822Sdim pp = tp->t_sc; 605218822Sdim (void) si_command(pp, FCLOSE, SI_NOWAIT); 606218822Sdim} 607218822Sdim 60838889Sjdpstatic void 60938889Sjdpsibreak(struct tty *tp, int sig) 610218822Sdim{ 611218822Sdim struct si_port *pp; 612218822Sdim 613218822Sdim pp = tp->t_sc; 614218822Sdim if (sig) 615218822Sdim si_command(pp, SBREAK, SI_WAIT); 616218822Sdim else 617218822Sdim si_command(pp, EBREAK, SI_WAIT); 618218822Sdim} 619218822Sdim 620218822Sdim 621218822Sdim/* 622218822Sdim * Handle the Specialix ioctls on the control dev. 623218822Sdim */ 624218822Sdimstatic int 625218822Sdimsi_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 626218822Sdim{ 627218822Sdim struct si_softc *xsc; 628218822Sdim struct si_port *xpp; 629218822Sdim volatile struct si_reg *regp; 630218822Sdim struct si_tcsi *dp; 631218822Sdim struct si_pstat *sps; 632218822Sdim int *ip, error = 0; 633218822Sdim int oldspl; 634218822Sdim int card, port; 635218822Sdim 636218822Sdim DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n", 637218822Sdim devtoname(dev), cmd, data, flag)); 638218822Sdim 639218822Sdim#if 1 640218822Sdim DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 641218822Sdim DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 642218822Sdim DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 643218822Sdim#endif 644218822Sdim 645218822Sdim oldspl = spltty(); /* better safe than sorry */ 646218822Sdim 647218822Sdim ip = (int *)data; 648218822Sdim 649218822Sdim#define SUCHECK if ((error = suser(td))) goto out 650218822Sdim 651218822Sdim switch (cmd) { 652218822Sdim case TCSIPORTS: 653218822Sdim *ip = si_Nports; 654218822Sdim goto out; 655218822Sdim case TCSIMODULES: 656218822Sdim *ip = si_Nmodules; 657218822Sdim goto out; 658218822Sdim case TCSISDBG_ALL: 659218822Sdim SUCHECK; 660218822Sdim si_debug = *ip; 661218822Sdim goto out; 662218822Sdim case TCSIGDBG_ALL: 663218822Sdim *ip = si_debug; 664218822Sdim goto out; 665218822Sdim default: 666218822Sdim /* 667218822Sdim * Check that a controller for this port exists 668218822Sdim */ 669218822Sdim 670218822Sdim /* may also be a struct si_pstat, a superset of si_tcsi */ 671218822Sdim 67238889Sjdp dp = (struct si_tcsi *)data; 673218822Sdim sps = (struct si_pstat *)data; 674218822Sdim card = dp->tc_card; 67538889Sjdp xsc = devclass_get_softc(si_devclass, card); /* check.. */ 676218822Sdim if (xsc == NULL || xsc->sc_type == SIEMPTY) { 677218822Sdim error = ENOENT; 67838889Sjdp goto out; 67938889Sjdp } 68038889Sjdp /* 68138889Sjdp * And check that a port exists 68277298Sobrien */ 683218822Sdim port = dp->tc_port; 68477298Sobrien if (port < 0 || port >= xsc->sc_nport) { 68538889Sjdp error = ENOENT; 686218822Sdim goto out; 68738889Sjdp } 688218822Sdim xpp = xsc->sc_ports + port; 689218822Sdim regp = (struct si_reg *)xsc->sc_maddr; 69038889Sjdp } 691218822Sdim 692218822Sdim switch (cmd) { 69338889Sjdp case TCSIDEBUG: 69438889Sjdp#ifdef SI_DEBUG 69538889Sjdp SUCHECK; 69638889Sjdp if (xpp->sp_debug) 69738889Sjdp xpp->sp_debug = 0; 69838889Sjdp else { 69938889Sjdp xpp->sp_debug = DBG_ALL; 70038889Sjdp DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 701218822Sdim (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 702218822Sdim } 70338889Sjdp break; 70460484Sobrien#else 70560484Sobrien error = ENODEV; 70660484Sobrien goto out; 70760484Sobrien#endif 70860484Sobrien case TCSISDBG_LEVEL: 70960484Sobrien case TCSIGDBG_LEVEL: 710218822Sdim#ifdef SI_DEBUG 711218822Sdim if (cmd == TCSIGDBG_LEVEL) { 712218822Sdim dp->tc_dbglvl = xpp->sp_debug; 713218822Sdim } else { 714218822Sdim SUCHECK; 715218822Sdim xpp->sp_debug = dp->tc_dbglvl; 716218822Sdim } 717218822Sdim break; 71860484Sobrien#else 71960484Sobrien error = ENODEV; 72060484Sobrien goto out; 72160484Sobrien#endif 72260484Sobrien case TCSIGRXIT: 72360484Sobrien dp->tc_int = regp->rx_int_count; 72460484Sobrien break; 72560484Sobrien case TCSIRXIT: 72660484Sobrien SUCHECK; 72760484Sobrien regp->rx_int_count = dp->tc_int; 72860484Sobrien break; 729218822Sdim case TCSIGIT: 73060484Sobrien dp->tc_int = regp->int_count; 73160484Sobrien break; 73260484Sobrien case TCSIIT: 73360484Sobrien SUCHECK; 73460484Sobrien regp->int_count = dp->tc_int; 73560484Sobrien break; 73660484Sobrien case TCSISTATE: 737218822Sdim dp->tc_int = xpp->sp_ccb->hi_ip; 738218822Sdim break; 739218822Sdim /* these next three use a different structure */ 740218822Sdim case TCSI_PORT: 741218822Sdim SUCHECK; 742218822Sdim si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 743218822Sdim break; 74460484Sobrien case TCSI_CCB: 745218822Sdim SUCHECK; 746218822Sdim si_vbcopy(xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 747218822Sdim break; 748218822Sdim case TCSI_TTY: 749218822Sdim SUCHECK; 750218822Sdim si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 751218822Sdim break; 752218822Sdim default: 75360484Sobrien error = EINVAL; 754218822Sdim goto out; 75560484Sobrien } 75660484Sobrienout: 75760484Sobrien splx(oldspl); 75860484Sobrien return(error); /* success */ 75960484Sobrien} 76060484Sobrien 76160484Sobrien/* 76260484Sobrien * siparam() : Configure line params 76360484Sobrien * called at spltty(); 764218822Sdim * this may sleep, does not flush, nor wait for drain, nor block writes 76560484Sobrien * caller must arrange this if it's important.. 76660484Sobrien */ 76760484Sobrienstatic int 76860484Sobriensiparam(struct tty *tp, struct termios *t) 76960484Sobrien{ 770218822Sdim struct si_port *pp = tp->t_sc; 771218822Sdim volatile struct si_channel *ccbp; 772218822Sdim int oldspl, cflag, iflag, oflag, lflag; 773218822Sdim int error = 0; /* shutup gcc */ 77460484Sobrien int ispeed = 0; /* shutup gcc */ 775218822Sdim int ospeed = 0; /* shutup gcc */ 776218822Sdim BYTE val; 777218822Sdim 778218822Sdim DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 779218822Sdim cflag = t->c_cflag; 780218822Sdim iflag = t->c_iflag; 781218822Sdim oflag = t->c_oflag; 782218822Sdim lflag = t->c_lflag; 78338889Sjdp DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 78438889Sjdp oflag, cflag, iflag, lflag)); 785218822Sdim 786218822Sdim /* XXX - if Jet host and SXDC module, use extended baud rates */ 78738889Sjdp 78838889Sjdp /* if not hung up.. */ 789218822Sdim if (t->c_ospeed != 0) { 790218822Sdim /* translate baud rate to firmware values */ 791218822Sdim ospeed = ttspeedtab(t->c_ospeed, bdrates); 792218822Sdim ispeed = t->c_ispeed ? 793218822Sdim ttspeedtab(t->c_ispeed, bdrates) : ospeed; 794218822Sdim 795218822Sdim /* enforce legit baud rate */ 79660484Sobrien if (ospeed < 0 || ispeed < 0) 797218822Sdim return (EINVAL); 798218822Sdim } 799218822Sdim 800218822Sdim oldspl = spltty(); 80160484Sobrien 802218822Sdim ccbp = pp->sp_ccb; 803218822Sdim 804218822Sdim /* ========== set hi_break ========== */ 805218822Sdim val = 0; 806218822Sdim if (iflag & IGNBRK) /* Breaks */ 80738889Sjdp val |= BR_IGN; 808218822Sdim if (iflag & BRKINT) /* Interrupt on break? */ 809218822Sdim val |= BR_INT; 810218822Sdim if (iflag & PARMRK) /* Parity mark? */ 811218822Sdim val |= BR_PARMRK; 812218822Sdim if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 813218822Sdim val |= BR_PARIGN; 814218822Sdim ccbp->hi_break = val; 815218822Sdim 816218822Sdim /* ========== set hi_csr ========== */ 817218822Sdim /* if not hung up.. */ 818218822Sdim if (t->c_ospeed != 0) { 819218822Sdim /* Set I/O speeds */ 820218822Sdim val = (ispeed << 4) | ospeed; 821218822Sdim } 822218822Sdim ccbp->hi_csr = val; 823218822Sdim 824218822Sdim /* ========== set hi_mr2 ========== */ 825218822Sdim val = 0; 826218822Sdim if (cflag & CSTOPB) /* Stop bits */ 82738889Sjdp val |= MR2_2_STOP; 828218822Sdim else 829218822Sdim val |= MR2_1_STOP; 830218822Sdim /* 831218822Sdim * Enable H/W RTS/CTS handshaking. The default TA/MTA is 83238889Sjdp * a DCE, hence the reverse sense of RTS and CTS 83338889Sjdp */ 834218822Sdim /* Output Flow - RTS must be raised before data can be sent */ 83538889Sjdp if (cflag & CCTS_OFLOW) 83638889Sjdp val |= MR2_RTSCONT; 837218822Sdim 838218822Sdim ccbp->hi_mr2 = val; 839218822Sdim 840218822Sdim /* ========== set hi_mr1 ========== */ 841218822Sdim val = 0; 842218822Sdim if (!(cflag & PARENB)) /* Parity */ 843218822Sdim val |= MR1_NONE; 844218822Sdim else 845218822Sdim val |= MR1_WITH; 846218822Sdim if (cflag & PARODD) 847218822Sdim val |= MR1_ODD; 848218822Sdim 849218822Sdim if ((cflag & CS8) == CS8) { /* 8 data bits? */ 850218822Sdim val |= MR1_8_BITS; 851218822Sdim } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 85260484Sobrien val |= MR1_7_BITS; 853218822Sdim } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 854218822Sdim val |= MR1_6_BITS; 855218822Sdim } else { /* Must be 5 */ 856218822Sdim val |= MR1_5_BITS; 857218822Sdim } 858218822Sdim /* 859218822Sdim * Enable H/W RTS/CTS handshaking. The default TA/MTA is 86060484Sobrien * a DCE, hence the reverse sense of RTS and CTS 86160484Sobrien */ 86260484Sobrien /* Input Flow - CTS is raised when port is ready to receive data */ 863218822Sdim if (cflag & CRTS_IFLOW) 864218822Sdim val |= MR1_CTSCONT; 865218822Sdim 866218822Sdim ccbp->hi_mr1 = val; 867218822Sdim 868218822Sdim /* ========== set hi_mask ========== */ 869218822Sdim val = 0xff; 87060484Sobrien if ((cflag & CS8) == CS8) { /* 8 data bits? */ 87160484Sobrien val &= 0xFF; 872218822Sdim } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 87338889Sjdp val &= 0x7F; 87460484Sobrien } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 87560484Sobrien val &= 0x3F; 87638889Sjdp } else { /* Must be 5 */ 877218822Sdim val &= 0x1F; 878218822Sdim } 879218822Sdim if (iflag & ISTRIP) 880218822Sdim val &= 0x7F; 88138889Sjdp 88238889Sjdp ccbp->hi_mask = val; 88338889Sjdp 88438889Sjdp /* ========== set hi_prtcl ========== */ 88538889Sjdp val = SP_DCEN; /* Monitor DCD always, or TIOCMGET misses it */ 88638889Sjdp if (iflag & IXANY) 88738889Sjdp val |= SP_TANY; 888218822Sdim if (iflag & IXON) 88960484Sobrien val |= SP_TXEN; 89038889Sjdp if (iflag & IXOFF) 89138889Sjdp val |= SP_RXEN; 892218822Sdim if (iflag & INPCK) 893218822Sdim val |= SP_PAEN; 894218822Sdim 895218822Sdim ccbp->hi_prtcl = val; 896218822Sdim 897218822Sdim 898218822Sdim /* ========== set hi_{rx|tx}{on|off} ========== */ 899218822Sdim /* XXX: the card TOTALLY shields us from the flow control... */ 900218822Sdim ccbp->hi_txon = t->c_cc[VSTART]; 901218822Sdim ccbp->hi_txoff = t->c_cc[VSTOP]; 902218822Sdim 903218822Sdim ccbp->hi_rxon = t->c_cc[VSTART]; 904218822Sdim ccbp->hi_rxoff = t->c_cc[VSTOP]; 905218822Sdim 906218822Sdim /* ========== send settings to the card ========== */ 90738889Sjdp /* potential sleep here */ 908218822Sdim if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 909218822Sdim si_command(pp, LOPEN, SI_WAIT); /* open it */ 91038889Sjdp else 911218822Sdim si_command(pp, CONFIG, SI_WAIT); /* change params */ 912218822Sdim 913218822Sdim /* ========== set DTR etc ========== */ 914218822Sdim /* Hangup if ospeed == 0 */ 915218822Sdim if (t->c_ospeed == 0) { 916218822Sdim (void) simodem(tp, 0, SER_DTR | SER_RTS); 91760484Sobrien } else { 918218822Sdim /* 91960484Sobrien * If the previous speed was 0, may need to re-enable 920218822Sdim * the modem signals 92138889Sjdp */ 922218822Sdim (void) simodem(tp, SER_DTR | SER_RTS, 0); 92360484Sobrien } 924218822Sdim 92560484Sobrien DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 926218822Sdim ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 927218822Sdim 928218822Sdim splx(oldspl); 929218822Sdim return(error); 930218822Sdim} 931218822Sdim 932218822Sdim/* 933218822Sdim * Set/Get state of modem control lines. 934218822Sdim * Due to DCE-like behaviour of the adapter, some signals need translation: 935218822Sdim * TIOCM_DTR DSR 936218822Sdim * TIOCM_RTS CTS 937218822Sdim */ 93860484Sobrienstatic int 939218822Sdimsimodem(struct tty *tp, int sigon, int sigoff) 940218822Sdim{ 941218822Sdim struct si_port *pp; 942218822Sdim volatile struct si_channel *ccbp; 94338889Sjdp int x; 944218822Sdim 94538889Sjdp pp = tp->t_sc; 946218822Sdim DPRINT((pp, DBG_ENTRY|DBG_MODEM, "simodem(%x,%x)\n", sigon, sigoff)); 947218822Sdim ccbp = pp->sp_ccb; /* Find channel address */ 948218822Sdim if (sigon == 0 && sigoff == 0) { 949218822Sdim x = ccbp->hi_ip; 950218822Sdim /* 951218822Sdim * XXX: not sure this is correct, should it be CTS&DSR ? 952218822Sdim * XXX: or do we (just) miss CTS & DSR ? 953218822Sdim */ 954218822Sdim if (x & IP_DCD) sigon |= SER_DCD; 955218822Sdim if (x & IP_DTR) sigon |= SER_DTR; 956218822Sdim if (x & IP_RTS) sigon |= SER_RTS; 957218822Sdim if (x & IP_RI) sigon |= SER_RI; 958218822Sdim return (sigon); 959218822Sdim } 960218822Sdim 961218822Sdim x = ccbp->hi_op; 962218822Sdim if (sigon & SER_DTR) 963218822Sdim x |= OP_DSR; 964218822Sdim if (sigoff & SER_DTR) 965218822Sdim x &= ~OP_DSR; 966218822Sdim if (sigon & SER_RTS) 967218822Sdim x |= OP_CTS; 968218822Sdim if (sigoff & SER_RTS) 969218822Sdim x &= ~OP_CTS; 970218822Sdim ccbp->hi_op = x; 971218822Sdim return 0; 972218822Sdim} 973218822Sdim 974218822Sdim/* 975218822Sdim * Handle change of modem state 976218822Sdim */ 977218822Sdimstatic void 978218822Sdimsi_modem_state(struct si_port *pp, struct tty *tp, int hi_ip) 979218822Sdim{ 980218822Sdim /* if a modem dev */ 981218822Sdim if (hi_ip & IP_DCD) { 982218822Sdim if (!(pp->sp_last_hi_ip & IP_DCD)) { 983218822Sdim DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 984218822Sdim tp->t_line)); 985218822Sdim (void)ttyld_modem(tp, 1); 986218822Sdim } 987218822Sdim } else { 988218822Sdim if (pp->sp_last_hi_ip & IP_DCD) { 989218822Sdim DPRINT((pp, DBG_INTR, "modem carr off\n")); 990218822Sdim if (ttyld_modem(tp, 0)) 991218822Sdim (void) simodem(tp, 0, SER_DTR | SER_RTS); 992218822Sdim } 993218822Sdim } 994218822Sdim pp->sp_last_hi_ip = hi_ip; 995218822Sdim 996218822Sdim} 997218822Sdim 998218822Sdim/* 999218822Sdim * Poller to catch missed interrupts. 1000218822Sdim * 1001218822Sdim * Note that the SYSV Specialix drivers poll at 100 times per second to get 1002218822Sdim * better response. We could really use a "periodic" version timeout(). :-) 1003218822Sdim */ 1004218822Sdim#ifdef POLL 1005218822Sdimstatic void 100660484Sobriensi_poll(void *nothing) 1007130561Sobrien{ 100860484Sobrien struct si_softc *sc; 100938889Sjdp int i; 101038889Sjdp volatile struct si_reg *regp; 101138889Sjdp struct si_port *pp; 101238889Sjdp int lost, oldspl, port; 101338889Sjdp 101438889Sjdp DPRINT((0, DBG_POLL, "si_poll()\n")); 101538889Sjdp oldspl = spltty(); 101689857Sobrien if (in_intr) 101789857Sobrien goto out; 101889857Sobrien lost = 0; 101938889Sjdp for (i = 0; i < si_numunits; i++) { 102038889Sjdp sc = devclass_get_softc(si_devclass, i); 102138889Sjdp if (sc == NULL || sc->sc_type == SIEMPTY) 102238889Sjdp continue; 102338889Sjdp regp = (struct si_reg *)sc->sc_maddr; 102438889Sjdp 102577298Sobrien /* 102677298Sobrien * See if there has been a pending interrupt for 2 seconds 102777298Sobrien * or so. The test (int_scounter >= 200) won't correspond 102860484Sobrien * to 2 seconds if int_count gets changed. 102938889Sjdp */ 103038889Sjdp if (regp->int_pending != 0) { 103138889Sjdp if (regp->int_scounter >= 200 && 103238889Sjdp regp->initstat == 1) { 103338889Sjdp printf("si%d: lost intr\n", i); 103438889Sjdp lost++; 103538889Sjdp } 103638889Sjdp } else { 103738889Sjdp regp->int_scounter = 0; 103838889Sjdp } 103938889Sjdp 104038889Sjdp /* 104138889Sjdp * gripe about no input flow control.. 104238889Sjdp */ 104338889Sjdp pp = sc->sc_ports; 104438889Sjdp for (port = 0; port < sc->sc_nport; pp++, port++) { 104538889Sjdp if (pp->sp_delta_overflows > 0) { 1046218822Sdim printf("si%d: %d tty level buffer overflows\n", 104738889Sjdp i, pp->sp_delta_overflows); 104838889Sjdp pp->sp_delta_overflows = 0; 104938889Sjdp } 105038889Sjdp } 105138889Sjdp } 105238889Sjdp if (lost || si_realpoll) 105338889Sjdp si_intr(NULL); /* call intr with fake vector */ 105438889Sjdpout: 1055218822Sdim splx(oldspl); 105633965Sjdp 1057218822Sdim timeout(si_poll, (caddr_t)0L, si_pollrate); 105833965Sjdp} 1059218822Sdim#endif /* ifdef POLL */ 106033965Sjdp 1061218822Sdim/* 106233965Sjdp * The interrupt handler polls ALL ports on ALL adapters each time 106333965Sjdp * it is called. 1064218822Sdim */ 106533965Sjdp 1066218822Sdimstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 106733965Sjdpstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 1068218822Sdim 106933965Sjdpvoid 107033965Sjdpsi_intr(void *arg) 1071218822Sdim{ 1072218822Sdim struct si_softc *sc; 1073218822Sdim struct si_port *pp; 1074218822Sdim volatile struct si_channel *ccbp; 1075218822Sdim struct tty *tp; 1076218822Sdim volatile caddr_t maddr; 1077218822Sdim BYTE op, ip; 107860484Sobrien int x, card, port, n, i, isopen; 107960484Sobrien volatile BYTE *z; 108060484Sobrien BYTE c; 108160484Sobrien 108260484Sobrien sc = arg; 1083218822Sdim 108460484Sobrien DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); 108560484Sobrien if (in_intr) 1086218822Sdim return; 1087218822Sdim in_intr = 1; 1088218822Sdim 1089218822Sdim /* 1090218822Sdim * When we get an int we poll all the channels and do ALL pending 1091218822Sdim * work, not just the first one we find. This allows all cards to 1092218822Sdim * share the same vector. 1093218822Sdim * 1094218822Sdim * XXX - But if we're sharing the vector with something that's NOT 1095218822Sdim * a SI/XIO/SX card, we may be making more work for ourselves. 1096218822Sdim */ 1097218822Sdim for (card = 0; card < si_numunits; card++) { 1098218822Sdim sc = devclass_get_softc(si_devclass, card); 1099218822Sdim if (sc == NULL || sc->sc_type == SIEMPTY) 1100218822Sdim continue; 1101218822Sdim 1102218822Sdim /* 1103218822Sdim * First, clear the interrupt 1104218822Sdim */ 1105218822Sdim switch(sc->sc_type) { 1106218822Sdim case SIHOST: 1107218822Sdim maddr = sc->sc_maddr; 1108218822Sdim ((volatile struct si_reg *)maddr)->int_pending = 0; 1109218822Sdim /* flag nothing pending */ 111038889Sjdp *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 111133965Sjdp *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 1112218822Sdim break; 111360484Sobrien case SIHOST2: 111460484Sobrien maddr = sc->sc_maddr; 111533965Sjdp ((volatile struct si_reg *)maddr)->int_pending = 0; 111633965Sjdp *(maddr+SIPLIRQCLR) = 0x00; 111733965Sjdp *(maddr+SIPLIRQCLR) = 0x10; 111838889Sjdp break; 111938889Sjdp case SIPCI: 112033965Sjdp maddr = sc->sc_maddr; 112189857Sobrien ((volatile struct si_reg *)maddr)->int_pending = 0; 1122218822Sdim *(maddr+SIPCIINTCL) = 0x0; 112333965Sjdp break; 112433965Sjdp case SIJETPCI: /* fall through to JETISA case */ 112560484Sobrien case SIJETISA: 112660484Sobrien maddr = sc->sc_maddr; 112760484Sobrien ((volatile struct si_reg *)maddr)->int_pending = 0; 112860484Sobrien *(maddr+SIJETINTCL) = 0x0; 112977298Sobrien break; 113077298Sobrien case SIEISA: 113177298Sobrien maddr = sc->sc_maddr; 113277298Sobrien ((volatile struct si_reg *)maddr)->int_pending = 0; 113377298Sobrien (void)inb(sc->sc_iobase + 3); 113477298Sobrien break; 113577298Sobrien case SIEMPTY: 113633965Sjdp default: 113760484Sobrien continue; 113860484Sobrien } 113960484Sobrien ((volatile struct si_reg *)maddr)->int_scounter = 0; 114060484Sobrien 114160484Sobrien /* 114233965Sjdp * check each port 114333965Sjdp */ 114438889Sjdp for (pp = sc->sc_ports, port = 0; port < sc->sc_nport; 114533965Sjdp pp++, port++) { 114633965Sjdp ccbp = pp->sp_ccb; 114733965Sjdp tp = pp->sp_tty; 114838889Sjdp 114994536Sobrien /* 115094536Sobrien * See if a command has completed ? 115133965Sjdp */ 115260484Sobrien if (ccbp->hi_stat != pp->sp_pend) { 115333965Sjdp DPRINT((pp, DBG_INTR, 115460484Sobrien "si_intr hi_stat = 0x%x, pend = %d\n", 115533965Sjdp ccbp->hi_stat, pp->sp_pend)); 115633965Sjdp switch(pp->sp_pend) { 115760484Sobrien case LOPEN: 115833965Sjdp case MPEND: 115960484Sobrien case MOPEN: 116033965Sjdp case CONFIG: 116133965Sjdp case SBREAK: 116260484Sobrien case EBREAK: 116338889Sjdp pp->sp_pend = ccbp->hi_stat; 116460484Sobrien /* sleeping in si_command */ 116538889Sjdp wakeup(&pp->sp_state); 116633965Sjdp break; 116738889Sjdp default: 116838889Sjdp pp->sp_pend = ccbp->hi_stat; 116933965Sjdp } 117033965Sjdp } 117138889Sjdp 117233965Sjdp /* 117360484Sobrien * Continue on if it's closed 1174218822Sdim */ 1175218822Sdim if (ccbp->hi_stat == IDLE_CLOSE) { 1176218822Sdim continue; 1177218822Sdim } 117838889Sjdp 117933965Sjdp /* 1180104834Sobrien * Do modem state change if not a local device 118138889Sjdp */ 118238889Sjdp si_modem_state(pp, tp, ccbp->hi_ip); 118338889Sjdp 118438889Sjdp /* 1185130561Sobrien * Check to see if we should 'receive' characters. 1186104834Sobrien */ 1187104834Sobrien if (tp->t_state & TS_CONNECTED && 1188104834Sobrien tp->t_state & TS_ISOPEN) 118938889Sjdp isopen = 1; 119033965Sjdp else 119133965Sjdp isopen = 0; 119233965Sjdp 119333965Sjdp /* 119433965Sjdp * Do input break processing 119533965Sjdp */ 119633965Sjdp if (ccbp->hi_state & ST_BREAK) { 119733965Sjdp if (isopen) { 1198218822Sdim ttyld_rint(tp, TTY_BI); 1199218822Sdim } 1200218822Sdim ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 1201218822Sdim DPRINT((pp, DBG_INTR, "si_intr break\n")); 1202218822Sdim } 1203218822Sdim 1204218822Sdim /* 1205218822Sdim * Do RX stuff - if not open then dump any characters. 1206218822Sdim * XXX: This is VERY messy and needs to be cleaned up. 1207218822Sdim * 1208104834Sobrien * XXX: can we leave data in the host adapter buffer 1209218822Sdim * when the clists are full? That may be dangerous 1210218822Sdim * if the user cannot get an interrupt signal through. 1211218822Sdim */ 1212218822Sdim 1213218822Sdim more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 1214218822Sdim 1215218822Sdim if (!isopen) { 1216218822Sdim ccbp->hi_rxopos = ccbp->hi_rxipos; 1217218822Sdim goto end_rx; 1218218822Sdim } 1219218822Sdim 1220218822Sdim /* 1221218822Sdim * If the tty input buffers are blocked, stop emptying 1222218822Sdim * the incoming buffers and let the auto flow control 1223218822Sdim * assert.. 1224218822Sdim */ 1225218822Sdim if (tp->t_state & TS_TBLOCK) { 1226218822Sdim goto end_rx; 1227218822Sdim } 1228218822Sdim 1229218822Sdim /* 1230218822Sdim * Process read characters if not skipped above 1231218822Sdim */ 1232218822Sdim op = ccbp->hi_rxopos; 1233218822Sdim ip = ccbp->hi_rxipos; 1234218822Sdim c = ip - op; 1235218822Sdim if (c == 0) { 1236218822Sdim goto end_rx; 1237218822Sdim } 1238218822Sdim 1239218822Sdim n = c & 0xff; 1240218822Sdim if (n > 250) 1241218822Sdim n = 250; 1242218822Sdim 1243218822Sdim DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1244218822Sdim n, op, ip)); 1245218822Sdim 1246218822Sdim /* 1247218822Sdim * Suck characters out of host card buffer into the 1248218822Sdim * "input staging buffer" - so that we dont leave the 1249218822Sdim * host card in limbo while we're possibly echoing 1250218822Sdim * characters and possibly flushing input inside the 1251218822Sdim * ldisc l_rint() routine. 1252218822Sdim */ 1253218822Sdim if (n <= SI_BUFFERSIZE - op) { 1254218822Sdim 1255218822Sdim DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 1256218822Sdim z = ccbp->hi_rxbuf + op; 1257218822Sdim si_vbcopy(z, si_rxbuf, n); 1258218822Sdim 1259218822Sdim op += n; 1260218822Sdim } else { 1261218822Sdim x = SI_BUFFERSIZE - op; 1262218822Sdim 1263218822Sdim DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 1264218822Sdim z = ccbp->hi_rxbuf + op; 1265218822Sdim si_vbcopy(z, si_rxbuf, x); 1266218822Sdim 1267218822Sdim DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 1268218822Sdim n - x)); 1269218822Sdim z = ccbp->hi_rxbuf; 1270218822Sdim si_vbcopy(z, si_rxbuf + x, n - x); 127133965Sjdp 127233965Sjdp op += n; 127333965Sjdp } 127433965Sjdp 1275218822Sdim /* clear collected characters from buffer */ 1276218822Sdim ccbp->hi_rxopos = op; 1277218822Sdim 1278218822Sdim DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1279218822Sdim n, op, ip)); 1280218822Sdim 1281218822Sdim /* 1282218822Sdim * at this point... 1283218822Sdim * n = number of chars placed in si_rxbuf 1284104834Sobrien */ 1285218822Sdim 1286218822Sdim /* 1287218822Sdim * Avoid the grotesquely inefficient lineswitch 1288218822Sdim * routine (ttyinput) in "raw" mode. It usually 128933965Sjdp * takes about 450 instructions (that's without 129033965Sjdp * canonical processing or echo!). slinput is 1291218822Sdim * reasonably fast (usually 40 instructions 1292218822Sdim * plus call overhead). 1293218822Sdim */ 1294218822Sdim if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1295218822Sdim 1296218822Sdim /* block if the driver supports it */ 1297218822Sdim if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER && 1298218822Sdim (tp->t_cflag & CRTS_IFLOW || 1299218822Sdim tp->t_iflag & IXOFF) && 1300218822Sdim !(tp->t_state & TS_TBLOCK)) 1301218822Sdim ttyblock(tp); 1302218822Sdim 1303218822Sdim tk_nin += n; 1304130561Sobrien tk_rawcc += n; 1305218822Sdim tp->t_rawcc += n; 1306218822Sdim 1307218822Sdim pp->sp_delta_overflows += 1308218822Sdim b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 130989857Sobrien 1310218822Sdim ttwakeup(tp); 1311218822Sdim if (tp->t_state & TS_TTSTOP && 1312218822Sdim (tp->t_iflag & IXANY || 1313218822Sdim tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 1314218822Sdim tp->t_state &= ~TS_TTSTOP; 1315218822Sdim tp->t_lflag &= ~FLUSHO; 1316218822Sdim si_start(tp); 1317218822Sdim } 1318104834Sobrien } else { 1319218822Sdim /* 1320218822Sdim * It'd be nice to not have to go through the 1321218822Sdim * function call overhead for each char here. 1322218822Sdim * It'd be nice to block input it, saving a 1323218822Sdim * loop here and the call/return overhead. 1324218822Sdim */ 1325218822Sdim for(x = 0; x < n; x++) { 1326218822Sdim i = si_rxbuf[x]; 1327218822Sdim if (ttyld_rint(tp, i) 1328218822Sdim == -1) { 1329218822Sdim pp->sp_delta_overflows++; 1330218822Sdim } 1331218822Sdim } 1332130561Sobrien } 1333130561Sobrien goto more_rx; /* try for more until RXbuf is empty */ 1334218822Sdim 1335218822Sdim end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 1336218822Sdim 1337218822Sdim /* 1338218822Sdim * Do TX stuff 1339218822Sdim */ 1340218822Sdim ttyld_start(tp); 1341218822Sdim 1342218822Sdim } /* end of for (all ports on this controller) */ 1343218822Sdim } /* end of for (all controllers) */ 1344218822Sdim 1345218822Sdim in_intr = 0; 1346218822Sdim DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); 1347218822Sdim} 1348218822Sdim 1349218822Sdim/* 1350218822Sdim * Nudge the transmitter... 1351218822Sdim * 1352218822Sdim * XXX: I inherited some funny code here. It implies the host card only 1353218822Sdim * interrupts when the transmit buffer reaches the low-water-mark, and does 1354218822Sdim * not interrupt when it's actually hits empty. In some cases, we have 1355218822Sdim * processes waiting for complete drain, and we need to simulate an interrupt 1356218822Sdim * about when we think the buffer is going to be empty (and retry if not). 1357218822Sdim * I really am not certain about this... I *need* the hardware manuals. 1358218822Sdim */ 1359218822Sdimstatic void 1360218822Sdimsi_start(struct tty *tp) 1361218822Sdim{ 1362218822Sdim struct si_port *pp; 1363218822Sdim volatile struct si_channel *ccbp; 1364218822Sdim struct clist *qp; 1365218822Sdim BYTE ipos; 1366218822Sdim int nchar; 1367218822Sdim int oldspl, count, n, amount, buffer_full; 1368218822Sdim 1369218822Sdim oldspl = spltty(); 1370218822Sdim 1371218822Sdim qp = &tp->t_outq; 1372218822Sdim pp = tp->t_sc; 1373218822Sdim 1374218822Sdim DPRINT((pp, DBG_ENTRY|DBG_START, 1375218822Sdim "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 1376218822Sdim tp, tp->t_state, pp->sp_state, qp->c_cc)); 1377218822Sdim 1378218822Sdim if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 1379218822Sdim goto out; 1380218822Sdim 1381218822Sdim buffer_full = 0; 1382218822Sdim ccbp = pp->sp_ccb; 1383218822Sdim 1384218822Sdim count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 1385218822Sdim DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 1386218822Sdim 1387218822Sdim while ((nchar = qp->c_cc) > 0) { 1388218822Sdim if ((BYTE)count >= 255) { 1389218822Sdim buffer_full++; 1390218822Sdim break; 1391218822Sdim } 1392218822Sdim amount = min(nchar, (255 - (BYTE)count)); 1393218822Sdim ipos = (unsigned int)ccbp->hi_txipos; 1394218822Sdim n = q_to_b(&tp->t_outq, si_txbuf, amount); 1395218822Sdim /* will it fit in one lump? */ 1396218822Sdim if ((SI_BUFFERSIZE - ipos) >= n) { 1397218822Sdim si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); 1398218822Sdim } else { 1399218822Sdim si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], 1400218822Sdim SI_BUFFERSIZE - ipos); 1401218822Sdim si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos), 1402218822Sdim &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos)); 1403218822Sdim } 1404218822Sdim ccbp->hi_txipos += n; 1405104834Sobrien count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 1406104834Sobrien } 1407218822Sdim 1408218822Sdim if (count != 0 && nchar == 0) { 1409218822Sdim tp->t_state |= TS_BUSY; 1410218822Sdim } else { 1411218822Sdim tp->t_state &= ~TS_BUSY; 1412218822Sdim } 1413218822Sdim 1414218822Sdim /* wakeup time? */ 1415218822Sdim ttwwakeup(tp); 1416218822Sdim 1417218822Sdim DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 1418218822Sdim (BYTE)count, nchar, tp->t_state)); 141994536Sobrien 1420218822Sdim if (tp->t_state & TS_BUSY) 142133965Sjdp { 142233965Sjdp int time; 1423218822Sdim 1424218822Sdim time = ttspeedtab(tp->t_ospeed, chartimes); 1425218822Sdim 1426218822Sdim if (time > 0) { 1427218822Sdim if (time < nchar) 142838889Sjdp time = nchar / time; 1429218822Sdim else 1430218822Sdim time = 2; 1431218822Sdim } else { 1432218822Sdim DPRINT((pp, DBG_START, 1433218822Sdim "bad char time value! %d\n", time)); 143489857Sobrien time = hz/10; 1435218822Sdim } 1436218822Sdim 1437218822Sdim if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 1438218822Sdim untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 1439218822Sdim } else { 1440218822Sdim pp->sp_state |= SS_LSTART; 1441218822Sdim } 1442218822Sdim DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 1443218822Sdim pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 144433965Sjdp } 144538889Sjdp 144638889Sjdpout: 144738889Sjdp splx(oldspl); 1448 DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 1449} 1450 1451/* 1452 * Note: called at splsoftclock from the timeout code 1453 * This has to deal with two things... cause wakeups while waiting for 1454 * tty drains on last process exit, and call l_start at about the right 1455 * time for protocols like ppp. 1456 */ 1457static void 1458si_lstart(void *arg) 1459{ 1460 struct si_port *pp = arg; 1461 struct tty *tp; 1462 int oldspl; 1463 1464 DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 1465 pp, pp->sp_state)); 1466 1467 oldspl = spltty(); 1468 tp = pp->sp_tty; 1469 1470 if ((tp->t_state & TS_ISOPEN) == 0 || 1471 (pp->sp_state & SS_LSTART) == 0) { 1472 splx(oldspl); 1473 return; 1474 } 1475 pp->sp_state &= ~SS_LSTART; 1476 pp->sp_state |= SS_INLSTART; 1477 1478 1479 /* deal with the process exit case */ 1480 ttwwakeup(tp); 1481 1482 /* nudge protocols - eg: ppp */ 1483 ttyld_start(tp); 1484 1485 pp->sp_state &= ~SS_INLSTART; 1486 splx(oldspl); 1487} 1488 1489/* 1490 * Stop output on a line. called at spltty(); 1491 */ 1492static void 1493si_stop(struct tty *tp, int rw) 1494{ 1495 volatile struct si_channel *ccbp; 1496 struct si_port *pp; 1497 1498 pp = tp->t_sc; 1499 ccbp = pp->sp_ccb; 1500 1501 DPRINT((pp, DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw)); 1502 1503 /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 1504 if (rw & FWRITE) { 1505 /* what level are we meant to be flushing anyway? */ 1506 if (tp->t_state & TS_BUSY) { 1507 si_command(pp, WFLUSH, SI_NOWAIT); 1508 tp->t_state &= ~TS_BUSY; 1509 ttwwakeup(tp); /* Bruce???? */ 1510 } 1511 } 1512#if 1 /* XXX: this doesn't work right yet.. */ 1513 /* XXX: this may have been failing because we used to call l_rint() 1514 * while we were looping based on these two counters. Now, we collect 1515 * the data and then loop stuffing it into l_rint(), making this 1516 * useless. Should we cause this to blow away the staging buffer? 1517 */ 1518 if (rw & FREAD) { 1519 ccbp->hi_rxopos = ccbp->hi_rxipos; 1520 } 1521#endif 1522} 1523 1524/* 1525 * Issue a command to the host card CPU. 1526 */ 1527 1528static void 1529si_command(struct si_port *pp, int cmd, int waitflag) 1530{ 1531 int oldspl; 1532 volatile struct si_channel *ccbp = pp->sp_ccb; 1533 int x; 1534 1535 DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 1536 pp, cmd, waitflag, ccbp->hi_stat)); 1537 1538 oldspl = spltty(); /* Keep others out */ 1539 1540 /* wait until it's finished what it was doing.. */ 1541 /* XXX: sits in IDLE_BREAK until something disturbs it or break 1542 * is turned off. */ 1543 while((x = ccbp->hi_stat) != IDLE_OPEN && 1544 x != IDLE_CLOSE && 1545 x != IDLE_BREAK && 1546 x != cmd) { 1547 if (in_intr) { /* Prevent sleep in intr */ 1548 DPRINT((pp, DBG_PARAM, 1549 "cmd intr collision - completing %d\trequested %d\n", 1550 x, cmd)); 1551 splx(oldspl); 1552 return; 1553 } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 1554 "sicmd1", 1)) { 1555 splx(oldspl); 1556 return; 1557 } 1558 } 1559 /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 1560 1561 /* if there was a pending command, cause a state-change wakeup */ 1562 switch(pp->sp_pend) { 1563 case LOPEN: 1564 case MPEND: 1565 case MOPEN: 1566 case CONFIG: 1567 case SBREAK: 1568 case EBREAK: 1569 wakeup(&pp->sp_state); 1570 break; 1571 default: 1572 break; 1573 } 1574 1575 pp->sp_pend = cmd; /* New command pending */ 1576 ccbp->hi_stat = cmd; /* Post it */ 1577 1578 if (waitflag) { 1579 if (in_intr) { /* If in interrupt handler */ 1580 DPRINT((pp, DBG_PARAM, 1581 "attempt to sleep in si_intr - cmd req %d\n", 1582 cmd)); 1583 splx(oldspl); 1584 return; 1585 } else while(ccbp->hi_stat != IDLE_OPEN && 1586 ccbp->hi_stat != IDLE_BREAK) { 1587 if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 1588 "sicmd2", 0)) 1589 break; 1590 } 1591 } 1592 splx(oldspl); 1593} 1594 1595 1596#ifdef SI_DEBUG 1597 1598void 1599si_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 1600{ 1601 va_list ap; 1602 1603 if ((pp == NULL && (si_debug&flags)) || 1604 (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 1605 if (pp != NULL) 1606 printf("%s: ", pp->sp_name); 1607 va_start(ap, fmt); 1608 vprintf(fmt, ap); 1609 va_end(ap); 1610 } 1611} 1612 1613#endif /* DEBUG */ 1614 1615static char * 1616si_modulename(int host_type, int uart_type) 1617{ 1618 switch (host_type) { 1619 /* Z280 based cards */ 1620 case SIEISA: 1621 case SIHOST2: 1622 case SIHOST: 1623 case SIPCI: 1624 switch (uart_type) { 1625 case 0: 1626 return(" (XIO)"); 1627 case 1: 1628 return(" (SI)"); 1629 } 1630 break; 1631 /* T225 based hosts */ 1632 case SIJETPCI: 1633 case SIJETISA: 1634 switch (uart_type) { 1635 case 0: 1636 return(" (SI)"); 1637 case 40: 1638 return(" (XIO)"); 1639 case 72: 1640 return(" (SXDC)"); 1641 } 1642 break; 1643 } 1644 return(""); 1645} 1646