si.c revision 12502
110015Speter/* 212496Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 310015Speter * 410015Speter * Copyright (C) 1990, 1992 Specialix International, 510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 610015Speter * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> 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 * 3312502Sjulian * $Id: si.c,v 1.16 1995/11/28 07:29:29 bde Exp $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3710015Speterstatic char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 3810015Speter si_copyright2[] = "@(#) (C) Andy Rutter 1993", 3910015Speter si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 4010015Speter#endif /* not lint */ 4110015Speter 4210015Speter#include <sys/param.h> 4310015Speter#include <sys/systm.h> 4410015Speter#include <sys/ioctl.h> 4510015Speter#include <sys/tty.h> 4610015Speter#include <sys/ttydefaults.h> 4710015Speter#include <sys/proc.h> 4810015Speter#include <sys/user.h> 4910015Speter#include <sys/conf.h> 5010015Speter#include <sys/file.h> 5110015Speter#include <sys/uio.h> 5210015Speter#include <sys/dkstat.h> 5310015Speter#include <sys/kernel.h> 5410015Speter#include <sys/syslog.h> 5510015Speter#include <sys/malloc.h> 5610015Speter#include <sys/devconf.h> 5710015Speter 5810015Speter#include <machine/clock.h> 5910015Speter 6010015Speter#include <i386/isa/icu.h> 6110015Speter#include <i386/isa/isa.h> 6210015Speter#include <i386/isa/isa_device.h> 6310015Speter 6410015Speter#include <i386/isa/sireg.h> 6510015Speter#include <machine/si.h> 6610015Speter 6710015Speter#include "si.h" 6810015Speter 6910015Speter/* 7010015Speter * This device driver is designed to interface the Specialix International 7112496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 7210015Speter * 7310015Speter * The controller is interfaced to the host via dual port ram 7410015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 7510015Speter */ 7610015Speter 7710015Speter#define POLL /* turn on poller to generate buffer empty interrupt */ 7812174Speter#undef FASTPOLL /* turn on 100Hz poller, (XXX: NOTYET!) */ 7910047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8012496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8110015Speter 8210015Speterenum si_mctl { GET, SET, BIS, BIC }; 8310015Speter 8412502Sjulian#ifdef JREMOD 8512502Sjulian#define CDEV_MAJOR 68 8612502Sjulianstatic void si_devsw_install(); 8712502Sjulian#endif /*JREMOD*/ 8812502Sjulian 8912502Sjulian 9010015Speterstatic void si_command __P((struct si_port *, int, int)); 9110015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 9210015Speterstatic void si_write_enable __P((struct si_port *, int)); 9310015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9410015Speterstatic void si_start __P((struct tty *)); 9510015Speterstatic void si_lstart __P((struct si_port *)); 9610015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 9710015Speter struct si_port *pp)); 9810015Speterstatic void sihardclose __P((struct si_port *pp)); 9910015Speterstatic void sidtrwakeup __P((void *chan)); 10010015Speter 10110015Speterint siparam __P((struct tty *, struct termios *)); 10210015Speter 10310708Speterextern void si_registerdev __P((struct isa_device *id)); 10410708Speterextern int siprobe __P((struct isa_device *id)); 10510708Speterextern int siattach __P((struct isa_device *id)); 10610708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 10710708Speter 10812174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 10912174Speter/* XXX: should be varargs, I know.. but where's vprintf()? */ 11012174Speterstatic void si_dprintf __P((/* struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */)); 11110708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 11210708Speter#define DPRINT(x) si_dprintf x 11310708Speter#else 11410708Speter#define DPRINT(x) /* void */ 11510708Speter#endif 11610708Speter 11710962Speterstatic int si_Nports; 11810962Speterstatic int si_Nmodules; 11910962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 12010015Speter 12110962Speterstatic struct tty *si_tty; 12210962Speter 12312174Speter/* where the firmware lives; defined in si_code.c */ 12410015Speterextern int si_dsize; 12510015Speterextern unsigned char si_download[]; 12610015Speter 12710044Speterstruct si_softc { 12810044Speter int sc_type; /* adapter type */ 12910044Speter char *sc_typename; /* adapter type string */ 13010044Speter 13110044Speter struct si_port *sc_ports; /* port structures for this card */ 13210044Speter 13310044Speter caddr_t sc_paddr; /* physical addr of iomem */ 13410044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 13510044Speter int sc_nport; /* # ports on this card */ 13610044Speter int sc_irq; /* copy of attach irq */ 13710044Speter int sc_eisa_iobase; /* EISA io port address */ 13810044Speter int sc_eisa_irqbits; 13910044Speter struct kern_devconf sc_kdc; 14010044Speter}; 14110044Speterstruct si_softc si_softc[NSI]; /* up to 4 elements */ 14210044Speter 14312174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 14410015Speter# define B2000 2000 14510015Speter#endif 14610015Speterstatic struct speedtab bdrates[] = { 14710015Speter B75, CLK75, /* 0x0 */ 14810015Speter B110, CLK110, /* 0x1 */ 14910015Speter B150, CLK150, /* 0x3 */ 15010015Speter B300, CLK300, /* 0x4 */ 15110015Speter B600, CLK600, /* 0x5 */ 15210015Speter B1200, CLK1200, /* 0x6 */ 15310015Speter B2000, CLK2000, /* 0x7 */ 15410015Speter B2400, CLK2400, /* 0x8 */ 15510015Speter B4800, CLK4800, /* 0x9 */ 15610015Speter B9600, CLK9600, /* 0xb */ 15710015Speter B19200, CLK19200, /* 0xc */ 15810015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 15910015Speter B57600, CLK57600, /* 0xd */ 16010015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 16110015Speter -1, -1 16210015Speter}; 16310015Speter 16410015Speter 16510015Speter/* populated with approx character/sec rates - translated at card 16610015Speter * initialisation time to chars per tick of the clock */ 16710015Speterstatic int done_chartimes = 0; 16810015Speterstatic struct speedtab chartimes[] = { 16910015Speter B75, 8, 17010015Speter B110, 11, 17110015Speter B150, 15, 17210015Speter B300, 30, 17310015Speter B600, 60, 17410015Speter B1200, 120, 17510015Speter B2000, 200, 17610015Speter B2400, 240, 17710015Speter B4800, 480, 17810015Speter B9600, 960, 17910015Speter B19200, 1920, 18010015Speter B38400, 3840, 18110015Speter B57600, 5760, 18210015Speter B115200, 11520, 18310015Speter -1, -1 18410015Speter}; 18510015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 18610015Speter 18710047Speterstatic int si_default_rate = TTYDEF_SPEED; 18810047Speterstatic int si_default_iflag = 0; 18910047Speterstatic int si_default_oflag = 0; 19010047Speterstatic int si_default_lflag = 0; 19110047Speter#ifdef SI_DEF_HWFLOW 19210047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 19310047Speter#else 19410047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 19510047Speter#endif 19610047Speter 19710015Speter#ifdef POLL 19810015Speter#define POLL_INTERVAL (hz/2) 19910015Speterstatic int init_finished = 0; 20012174Speterstatic int fastpoll = 0; 20110015Speterstatic void si_poll __P((void *)); 20210015Speter#endif 20310015Speter 20410015Speter/* 20510015Speter * Array of adapter types and the corresponding RAM size. The order of 20610015Speter * entries here MUST match the ordinal of the adapter type. 20710015Speter */ 20810015Speterstatic char *si_type[] = { 20910015Speter "EMPTY", 21010015Speter "SIHOST", 21110015Speter "SI2", /* MCA */ 21210015Speter "SIHOST2", 21310015Speter "SIEISA", 21410015Speter}; 21510015Speter 21610015Speter 21710015Speterstatic struct kern_devconf si_kdc[NSI] = { { 21810015Speter 0, 0, 0, /* filled in by dev_attach */ 21910015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 22010015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 22110015Speter &kdc_isa0, /* parent */ 22210015Speter 0, /* parent data */ 22310015Speter DC_UNCONFIGURED, /* state */ 22410015Speter "Specialix SI/XIO Host adapter", 22510015Speter DC_CLS_SERIAL, /* class */ 22610015Speter} }; 22710015Speter 22810015Spetervoid 22910015Spetersi_registerdev(id) 23010015Speter struct isa_device *id; 23110015Speter{ 23210015Speter if (id->id_unit != 0) { 23310015Speter si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 23410015Speter } 23510015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 23610015Speter si_kdc[id->id_unit].kdc_isa = id; 23712174Speter si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 23810015Speter dev_attach(&si_kdc[id->id_unit]); 23910015Speter} 24010015Speter 24110015Speter/* Look for a valid board at the given mem addr */ 24210015Speterint 24310015Spetersiprobe(id) 24410015Speter struct isa_device *id; 24510015Speter{ 24610015Speter struct si_softc *sc; 24710015Speter int type; 24810015Speter u_int i, ramsize; 24910015Speter volatile BYTE was, *ux; 25010015Speter volatile unsigned char *maddr; 25110015Speter unsigned char *paddr; 25210015Speter 25310015Speter si_registerdev(id); 25410015Speter 25510015Speter maddr = id->id_maddr; /* virtual address... */ 25610015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 25710015Speter 25812496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 25912496Speter id->id_unit, id->id_maddr, paddr)); 26010015Speter 26110015Speter /* 26210015Speter * this is a lie, but it's easier than trying to handle caching 26310015Speter * and ram conflicts in the >1M and <16M region. 26410015Speter */ 26510015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 26610015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 26712174Speter printf("si%d: iomem (%lx) out of range\n", 26812174Speter id->id_unit, (long)paddr); 26910015Speter return(0); 27010015Speter } 27110015Speter 27210015Speter if (id->id_unit >= NSI) { 27310015Speter /* THIS IS IMPOSSIBLE */ 27410015Speter return(0); 27510015Speter } 27610015Speter 27710015Speter if (((u_int)paddr & 0x7fff) != 0) { 27810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 27910015Speter "si%d: iomem (%x) not on 32k boundary\n", 28010015Speter id->id_unit, paddr)); 28110015Speter return(0); 28210015Speter } 28310015Speter 28410015Speter 28510015Speter for (i=0; i < NSI; i++) { 28610015Speter if ((sc = &si_softc[i]) == NULL) 28710015Speter continue; 28810015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 28910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 29010015Speter "si%d: iomem (%x) already configured to si%d\n", 29110015Speter id->id_unit, sc->sc_paddr, i)); 29210015Speter return(0); 29310015Speter } 29410015Speter } 29510015Speter 29610015Speter#if NEISA > 0 29710015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 29810015Speter int irq, port; 29910015Speter unsigned long base; 30010015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 30110015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 30210015Speter 30310015Speter port = id->id_iobase; 30410015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 30510015Speter irq = ((inb(port+2) >> 4) & 0xf); 30610015Speter 30710015Speter id->id_irq = eisa_irqs[irq]; 30810015Speter 30910015Speter DPRINT((0, DBG_AUTOBOOT, 31012496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 31110015Speter id->id_unit, base, irq, id->id_irq, port)); 31210015Speter 31310015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 31410015Speter goto bad_irq; 31510015Speter 31610015Speter id->id_iobase &= 0xf000; 31710015Speter id->id_iosize = 0x0fff; 31810015Speter 31910015Speter type = EISA; 32010015Speter outb(p+2, (BYTE)irq << 4); 32110015Speter 32210015Speter sc->sc_eisa_iobase = p; 32310015Speter sc->sc_eisa_irqbits = irq << 4; 32410015Speter ramsize = SIEISA_RAMSIZE; 32510015Speter goto got_card; 32610015Speter } 32710015Speter#endif 32810015Speter 32910015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 33010015Speter *maddr = 0x17; 33110015Speter if (*maddr != 0x17) { 33210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 33310015Speter "si%d: 0x17 check fail at phys 0x%x\n", 33410015Speter id->id_unit, paddr)); 33510015Speterfail: 33610015Speter return(0); 33710015Speter } 33810015Speter /* 33910015Speter * OK, now to see if whatever responded is really an SI card. 34010015Speter * Try for a MK II first (SIHOST2) 34110015Speter */ 34210015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 34310015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 34410015Speter goto try_mk1; 34510015Speter 34610015Speter /* It must be an SIHOST2 */ 34710015Speter *(maddr + SIPLRESET) = 0; 34810015Speter *(maddr + SIPLIRQCLR) = 0; 34910015Speter *(maddr + SIPLIRQSET) = 0x10; 35010015Speter type = SIHOST2; 35110015Speter ramsize = SIHOST2_RAMSIZE; 35210015Speter goto got_card; 35310015Speter 35410015Speter /* 35510015Speter * Its not a MK II, so try for a MK I (SIHOST) 35610015Speter */ 35710015Spetertry_mk1: 35810015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 35910015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 36010015Speter *(maddr+SIRAM) = 0x17; 36110015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 36210015Speter goto fail; 36310015Speter *(maddr+0x7ff8) = 0x17; 36410015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 36510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 36610015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 36710015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 36810015Speter goto fail; 36910015Speter } 37010015Speter 37110015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 37210015Speter type = SIHOST; 37310015Speter ramsize = SIHOST_RAMSIZE; 37410015Speter 37510015Spetergot_card: 37612496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 37712496Speter id->id_unit, type)); 37810015Speter /* Try the acid test */ 37910015Speter ux = (BYTE *)(maddr + SIRAM); 38010015Speter for (i=0; i<ramsize; i++, ux++) 38110015Speter *ux = (BYTE)(i&0xff); 38210015Speter ux = (BYTE *)(maddr + SIRAM); 38310015Speter for (i=0; i<ramsize; i++, ux++) { 38410015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 38510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 38612174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 38710015Speter id->id_unit, paddr+i, was, i&0xff)); 38810015Speter goto fail; 38910015Speter } 39010015Speter } 39110015Speter 39210015Speter /* clear out the RAM */ 39310015Speter ux = (BYTE *)(maddr + SIRAM); 39410015Speter for (i=0; i<ramsize; i++) 39510015Speter *ux++ = 0; 39610015Speter ux = (BYTE *)(maddr + SIRAM); 39710015Speter for (i=0; i<ramsize; i++) { 39810015Speter if ((was = *ux++) != 0) { 39910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 40012174Speter "si%d: clear fail at phys 0x%x, was %x\n", 40110015Speter id->id_unit, paddr+i, was)); 40210015Speter goto fail; 40310015Speter } 40410015Speter } 40510015Speter 40610015Speter /* 40710015Speter * Success, we've found a valid board, now fill in 40810015Speter * the adapter structure. 40910015Speter */ 41010015Speter switch (type) { 41110015Speter case SIHOST2: 41210015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 41310015Speterbad_irq: 41410015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 41510015Speter "si%d: bad IRQ value - %d\n", 41610015Speter id->id_unit, id->id_irq)); 41710015Speter return(0); 41810015Speter } 41910015Speter id->id_msize = SIHOST2_MEMSIZE; 42010015Speter break; 42110015Speter case SIHOST: 42210015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 42310015Speter goto bad_irq; 42410015Speter } 42510015Speter id->id_msize = SIHOST_MEMSIZE; 42610015Speter break; 42710015Speter case SIEISA: 42810015Speter id->id_msize = SIEISA_MEMSIZE; 42910015Speter break; 43010015Speter case SI2: /* MCA */ 43110015Speter default: 43210015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 43310015Speter return(0); 43410015Speter } 43510015Speter si_softc[id->id_unit].sc_type = type; 43610015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 43710015Speter return(-1); /* -1 == found */ 43810015Speter} 43910015Speter 44010015Speter/* 44110015Speter * Attach the device. Initialize the card. 44210015Speter */ 44310015Speterint 44410015Spetersiattach(id) 44510015Speter struct isa_device *id; 44610015Speter{ 44710015Speter int unit = id->id_unit; 44810015Speter struct si_softc *sc = &si_softc[unit]; 44910015Speter struct si_port *pp; 45010015Speter volatile struct si_channel *ccbp; 45110015Speter volatile struct si_reg *regp; 45210015Speter volatile caddr_t maddr; 45310015Speter struct si_module *modp; 45410015Speter struct tty *tp; 45510015Speter struct speedtab *spt; 45610015Speter int nmodule, nport, x, y; 45712174Speter int uart_type; 45810015Speter 45912496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 46010015Speter 46110015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 46210015Speter sc->sc_maddr = id->id_maddr; 46310015Speter sc->sc_irq = id->id_irq; 46410015Speter 46510015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 46610015Speter 46710015Speter maddr = sc->sc_maddr; 46810015Speter 46910015Speter /* 47010015Speter * OK, now lets download the firmware and try and boot the CPU.. 47110015Speter */ 47210015Speter 47312496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 47412496Speter id->id_unit, si_dsize)); 47510015Speter bcopy(si_download, maddr, si_dsize); 47610015Speter 47710015Speter switch (sc->sc_type) { 47810015Speter case SIEISA: 47910015Speter#if NEISA > 0 48010015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 48110015Speter *(maddr+0x42) = 1; 48210015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 48310015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 48410015Speter break; 48510015Speter#endif /* fall-through if not EISA */ 48610015Speter case SI2: 48712174Speter /* 48812174Speter * must get around to converting the code for 48912174Speter * these one day, if FreeBSD ever supports it. 49012174Speter */ 49110015Speter return 0; 49210015Speter case SIHOST: 49310015Speter *(maddr+SIRESET_CL) = 0; 49410015Speter *(maddr+SIINTCL_CL) = 0; 49510015Speter break; 49610015Speter case SIHOST2: 49710015Speter *(maddr+SIPLRESET) = 0x10; 49810015Speter switch (sc->sc_irq) { 49910015Speter case IRQ11: 50010015Speter *(maddr+SIPLIRQ11) = 0x10; 50110015Speter break; 50210015Speter case IRQ12: 50310015Speter *(maddr+SIPLIRQ12) = 0x10; 50410015Speter break; 50510015Speter case IRQ15: 50610015Speter *(maddr+SIPLIRQ15) = 0x10; 50710015Speter break; 50810015Speter } 50910015Speter *(maddr+SIPLIRQCLR) = 0x10; 51010015Speter break; 51110015Speter } 51210015Speter 51310015Speter DELAY(1000000); /* wait around for a second */ 51410015Speter 51510015Speter regp = (struct si_reg *)maddr; 51610015Speter y = 0; 51710015Speter /* wait max of 5 sec for init OK */ 51810015Speter while (regp->initstat == 0 && y++ < 10) { 51910015Speter DELAY(500000); 52010015Speter } 52110015Speter switch (regp->initstat) { 52210015Speter case 0: 52310015Speter printf("si%d: startup timeout - aborting\n", unit); 52412174Speter sc->sc_type = SIEMPTY; 52510015Speter return 0; 52610015Speter case 1: 52712174Speter /* set throttle to 125 intr per second */ 52810015Speter regp->int_count = 25000; 52910015Speter /* rx intr max of 25 timer per second */ 53010015Speter regp->rx_int_count = 4; 53110015Speter regp->int_pending = 0; /* no intr pending */ 53210015Speter regp->int_scounter = 0; /* reset counter */ 53310015Speter break; 53410015Speter case 0xff: 53510015Speter /* 53610015Speter * No modules found, so give up on this one. 53710015Speter */ 53810015Speter printf("si%d: %s - no ports found\n", unit, 53910015Speter si_type[sc->sc_type]); 54010015Speter return 0; 54110015Speter default: 54210015Speter printf("si%d: Z280 version error - initstat %x\n", 54310015Speter unit, regp->initstat); 54410015Speter return 0; 54510015Speter } 54610015Speter 54710015Speter /* 54810015Speter * First time around the ports just count them in order 54910015Speter * to allocate some memory. 55010015Speter */ 55110015Speter nport = 0; 55210015Speter modp = (struct si_module *)(maddr + 0x80); 55310015Speter for (;;) { 55412174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 55510015Speter switch (modp->sm_type & (~MMASK)) { 55610015Speter case M232: 55710015Speter case M422: 55810015Speter DPRINT((0, DBG_DOWNLOAD, 55912174Speter "si%d: Found 232/422 module, %d ports\n", 56010015Speter unit, (int)(modp->sm_type & MMASK))); 56110015Speter 56210015Speter /* this is a firmware issue */ 56310015Speter if (si_Nports == SI_MAXPORTPERCARD) { 56410015Speter printf("si%d: extra ports ignored\n", unit); 56510015Speter continue; 56610015Speter } 56710015Speter 56810015Speter x = modp->sm_type & MMASK; 56910015Speter nport += x; 57010015Speter si_Nports += x; 57110015Speter si_Nmodules++; 57210015Speter break; 57310015Speter default: 57410015Speter printf("si%d: unknown module type %d\n", 57510015Speter unit, modp->sm_type); 57610015Speter break; 57710015Speter } 57810015Speter if (modp->sm_next == 0) 57910015Speter break; 58010015Speter modp = (struct si_module *) 58110015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 58210015Speter } 58310015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 58410015Speter M_DEVBUF, M_NOWAIT); 58510015Speter if (sc->sc_ports == 0) { 58610015Spetermem_fail: 58710015Speter printf("si%d: fail to malloc memory for port structs\n", 58810015Speter unit); 58910015Speter return 0; 59010015Speter } 59110015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 59210015Speter sc->sc_nport = nport; 59310015Speter 59410015Speter /* 59510015Speter * allocate tty structures for ports 59610015Speter */ 59710015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 59810015Speter if (tp == 0) 59910015Speter goto mem_fail; 60010015Speter bzero(tp, sizeof(*tp) * nport); 60110962Speter si_tty = tp; 60210015Speter 60310015Speter /* mark the device state as attached */ 60410015Speter si_kdc[unit].kdc_state = DC_BUSY; 60510015Speter 60610015Speter /* 60710015Speter * Scan round the ports again, this time initialising. 60810015Speter */ 60910015Speter pp = sc->sc_ports; 61010015Speter nmodule = 0; 61110015Speter modp = (struct si_module *)(maddr + 0x80); 61212174Speter uart_type = 0; 61310015Speter for (;;) { 61410015Speter switch (modp->sm_type & (~MMASK)) { 61510015Speter case M232: 61610015Speter case M422: 61710015Speter nmodule++; 61810015Speter nport = (modp->sm_type & MMASK); 61910015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 62012174Speter if (uart_type == 0) 62112174Speter uart_type = ccbp->type; 62210015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 62310015Speter pp->sp_ccb = ccbp; /* save the address */ 62410015Speter pp->sp_tty = tp++; 62510015Speter pp->sp_pend = IDLE_CLOSE; 62610015Speter pp->sp_state = 0; /* internal flag */ 62710015Speter pp->sp_dtr_wait = 3 * hz; 62810047Speter pp->sp_iin.c_iflag = si_default_iflag; 62910047Speter pp->sp_iin.c_oflag = si_default_oflag; 63010047Speter pp->sp_iin.c_cflag = si_default_cflag; 63110047Speter pp->sp_iin.c_lflag = si_default_lflag; 63210015Speter termioschars(&pp->sp_iin); 63310015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 63410047Speter si_default_rate; 63510015Speter pp->sp_iout = pp->sp_iin; 63610015Speter } 63710015Speter break; 63810015Speter default: 63910015Speter break; 64010015Speter } 64110015Speter if (modp->sm_next == 0) { 64212174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 64310015Speter unit, 64410015Speter sc->sc_typename, 64510015Speter sc->sc_nport, 64612174Speter nmodule, 64712174Speter uart_type); 64810015Speter break; 64910015Speter } 65010015Speter modp = (struct si_module *) 65110015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 65210015Speter } 65310015Speter if (done_chartimes == 0) { 65410015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 65510015Speter if ((spt->sp_code /= hz) == 0) 65610015Speter spt->sp_code = 1; 65710015Speter } 65810015Speter done_chartimes = 1; 65910015Speter } 66012502Sjulian#ifdef JREMOD 66112502Sjulian si_devsw_install(); 66212502Sjulian#endif /*JREMOD*/ 66312502Sjulian 66410015Speter return (1); 66510015Speter} 66610015Speter 66710015Speterstruct isa_driver sidriver = 66810015Speter { siprobe, siattach, "si" }; 66910015Speter 67010015Speter 67110015Speterint 67210015Spetersiopen(dev, flag, mode, p) 67310015Speter dev_t dev; 67410015Speter int flag, mode; 67510015Speter struct proc *p; 67610015Speter{ 67710015Speter int oldspl, error; 67810015Speter int card, port; 67910015Speter register struct si_softc *sc; 68010015Speter register struct tty *tp; 68110015Speter volatile struct si_channel *ccbp; 68210015Speter struct si_port *pp; 68310015Speter int mynor = minor(dev); 68410015Speter 68510015Speter /* quickly let in /dev/si_control */ 68610015Speter if (IS_CONTROLDEV(mynor)) { 68710015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 68810015Speter return(error); 68910015Speter return(0); 69010015Speter } 69110015Speter 69210015Speter card = SI_CARD(mynor); 69310015Speter if (card >= NSI) 69410015Speter return (ENXIO); 69510015Speter sc = &si_softc[card]; 69610015Speter 69712174Speter if (sc->sc_type == SIEMPTY) { 69812174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 69910015Speter card, sc->sc_typename)); 70010015Speter return(ENXIO); 70110015Speter } 70210015Speter 70310015Speter port = SI_PORT(mynor); 70410015Speter if (port >= sc->sc_nport) { 70512174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 70610015Speter card, sc->sc_nport)); 70710015Speter return(ENXIO); 70810015Speter } 70910015Speter 71010015Speter#ifdef POLL 71110015Speter /* 71210015Speter * We've now got a device, so start the poller. 71310015Speter */ 71410015Speter if (init_finished == 0) { 71510015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 71610015Speter init_finished = 1; 71710015Speter } 71810015Speter#endif 71910015Speter 72010015Speter /* initial/lock device */ 72110015Speter if (IS_STATE(mynor)) { 72210015Speter return(0); 72310015Speter } 72410015Speter 72510015Speter pp = sc->sc_ports + port; 72610015Speter tp = pp->sp_tty; /* the "real" tty */ 72710015Speter ccbp = pp->sp_ccb; /* Find control block */ 72810015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 72910015Speter dev, flag, mode, p)); 73010015Speter 73110015Speter oldspl = spltty(); /* Keep others out */ 73210015Speter error = 0; 73310015Speter 73410015Speteropen_top: 73510015Speter while (pp->sp_state & SS_DTR_OFF) { 73610015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 73710015Speter if (error != 0) 73810015Speter goto out; 73910015Speter } 74010015Speter 74110015Speter if (tp->t_state & TS_ISOPEN) { 74210015Speter /* 74310015Speter * The device is open, so everything has been initialised. 74410015Speter * handle conflicts. 74510015Speter */ 74610015Speter if (IS_CALLOUT(mynor)) { 74710015Speter if (!pp->sp_active_out) { 74810015Speter error = EBUSY; 74910015Speter goto out; 75010015Speter } 75110015Speter } else { 75210015Speter if (pp->sp_active_out) { 75310015Speter if (flag & O_NONBLOCK) { 75410015Speter error = EBUSY; 75510015Speter goto out; 75610015Speter } 75710015Speter error = tsleep(&pp->sp_active_out, 75810015Speter TTIPRI|PCATCH, "sibi", 0); 75910015Speter if (error != 0) 76010015Speter goto out; 76110015Speter goto open_top; 76210015Speter } 76310015Speter } 76410015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 76510015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 76610015Speter "already open and EXCLUSIVE set\n")); 76710015Speter error = EBUSY; 76810015Speter goto out; 76910015Speter } 77010015Speter } else { 77110015Speter /* 77210015Speter * The device isn't open, so there are no conflicts. 77310015Speter * Initialize it. Avoid sleep... :-) 77410015Speter */ 77510015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 77610015Speter tp->t_oproc = si_start; 77710015Speter tp->t_param = siparam; 77810015Speter tp->t_dev = dev; 77910015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 78010015Speter ? pp->sp_iout : pp->sp_iin; 78110015Speter 78210015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 78310015Speter 78410015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 78510015Speter 78610015Speter error = siparam(tp, &tp->t_termios); 78710015Speter 78810015Speter --pp->sp_wopeners; 78910015Speter if (error != 0) 79010015Speter goto out; 79110015Speter /* XXX: we should goto_top if siparam slept */ 79210015Speter 79310015Speter ttsetwater(tp); 79410015Speter 79510015Speter /* set initial DCD state */ 79610015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 79710015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 79810015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 79910015Speter } 80010015Speter } 80110015Speter 80210015Speter /* whoops! we beat the close! */ 80310015Speter if (pp->sp_state & SS_CLOSING) { 80410015Speter /* try and stop it from proceeding to bash the hardware */ 80510015Speter pp->sp_state &= ~SS_CLOSING; 80610015Speter } 80710015Speter 80810015Speter /* 80910015Speter * Wait for DCD if necessary 81010015Speter */ 81110015Speter if (!(tp->t_state & TS_CARR_ON) 81210015Speter && !IS_CALLOUT(mynor) 81310015Speter && !(tp->t_cflag & CLOCAL) 81410015Speter && !(flag & O_NONBLOCK)) { 81510015Speter ++pp->sp_wopeners; 81610015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 81710015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 81810015Speter --pp->sp_wopeners; 81910015Speter if (error != 0) 82010015Speter goto out; 82110015Speter goto open_top; 82210015Speter } 82310015Speter 82410015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 82510015Speter si_disc_optim(tp, &tp->t_termios, pp); 82610015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 82710015Speter pp->sp_active_out = TRUE; 82810015Speter 82910015Speter pp->sp_state |= SS_OPEN; /* made it! */ 83010015Speter 83110015Speterout: 83210015Speter splx(oldspl); 83310015Speter 83410015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 83510015Speter 83610015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 83710015Speter sihardclose(pp); 83810015Speter 83910015Speter return(error); 84010015Speter} 84110015Speter 84210015Speterint 84310015Spetersiclose(dev, flag, mode, p) 84410015Speter dev_t dev; 84510015Speter int flag, mode; 84610015Speter struct proc *p; 84710015Speter{ 84810015Speter register struct si_port *pp; 84910015Speter register struct tty *tp; 85010015Speter int oldspl; 85110015Speter int error = 0; 85210015Speter int mynor = minor(dev); 85310015Speter 85410015Speter if (IS_SPECIAL(mynor)) 85510015Speter return(0); 85610015Speter 85710015Speter oldspl = spltty(); 85810015Speter 85910015Speter pp = MINOR2PP(mynor); 86010015Speter tp = pp->sp_tty; 86110015Speter 86210015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 86310015Speter dev, flag, mode, p, pp->sp_state)); 86410015Speter 86510015Speter /* did we sleep and loose a race? */ 86610015Speter if (pp->sp_state & SS_CLOSING) { 86710015Speter /* error = ESOMETING? */ 86810015Speter goto out; 86910015Speter } 87010015Speter 87110015Speter /* begin race detection.. */ 87210015Speter pp->sp_state |= SS_CLOSING; 87310015Speter 87410015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 87510015Speter 87610015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 87710015Speter (*linesw[tp->t_line].l_close)(tp, flag); 87810015Speter 87910015Speter si_write_enable(pp, 1); 88010015Speter 88110015Speter /* did we sleep and somebody started another open? */ 88210015Speter if (!(pp->sp_state & SS_CLOSING)) { 88310015Speter /* error = ESOMETING? */ 88410015Speter goto out; 88510015Speter } 88610015Speter /* ok. we are now still on the right track.. nuke the hardware */ 88710015Speter 88810015Speter if (pp->sp_state & SS_LSTART) { 88910015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 89010015Speter pp->sp_state &= ~SS_LSTART; 89110015Speter } 89210015Speter 89310015Speter sistop(tp, FREAD | FWRITE); 89410015Speter 89510015Speter sihardclose(pp); 89610015Speter ttyclose(tp); 89710015Speter pp->sp_state &= ~SS_OPEN; 89810015Speter 89910015Speterout: 90010015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 90110015Speter splx(oldspl); 90210015Speter return(error); 90310015Speter} 90410015Speter 90510015Speterstatic void 90610015Spetersihardclose(pp) 90710015Speter struct si_port *pp; 90810015Speter{ 90910015Speter int oldspl; 91010015Speter struct tty *tp; 91110015Speter volatile struct si_channel *ccbp; 91210015Speter 91310015Speter oldspl = spltty(); 91410015Speter 91510015Speter tp = pp->sp_tty; 91610015Speter ccbp = pp->sp_ccb; /* Find control block */ 91710015Speter if (tp->t_cflag & HUPCL 91810015Speter || !pp->sp_active_out 91910015Speter && !(ccbp->hi_ip & IP_DCD) 92010015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 92110015Speter || !(tp->t_state & TS_ISOPEN)) { 92210015Speter 92310015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 92410015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 92510015Speter 92610015Speter if (pp->sp_dtr_wait != 0) { 92710015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 92810015Speter pp->sp_state |= SS_DTR_OFF; 92910015Speter } 93010015Speter 93110015Speter } 93210015Speter pp->sp_active_out = FALSE; 93310015Speter wakeup((caddr_t)&pp->sp_active_out); 93410015Speter wakeup(TSA_CARR_ON(tp)); 93510015Speter 93610015Speter splx(oldspl); 93710015Speter} 93810015Speter 93910015Speter 94010015Speter/* 94110015Speter * called at splsoftclock()... 94210015Speter */ 94310015Speterstatic void 94410015Spetersidtrwakeup(chan) 94510015Speter void *chan; 94610015Speter{ 94710015Speter struct si_port *pp; 94810015Speter int oldspl; 94910015Speter 95010015Speter oldspl = spltty(); 95110015Speter 95210015Speter pp = (struct si_port *)chan; 95310015Speter pp->sp_state &= ~SS_DTR_OFF; 95410015Speter wakeup(&pp->sp_dtr_wait); 95510015Speter 95610015Speter splx(oldspl); 95710015Speter} 95810015Speter 95910015Speter/* 96010015Speter * User level stuff - read and write 96110015Speter */ 96210015Speterint 96310015Spetersiread(dev, uio, flag) 96410015Speter register dev_t dev; 96510015Speter struct uio *uio; 96610015Speter int flag; 96710015Speter{ 96810015Speter register struct tty *tp; 96910015Speter int mynor = minor(dev); 97010015Speter 97110015Speter if (IS_SPECIAL(mynor)) { 97210015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 97310015Speter return(ENODEV); 97410015Speter } 97510015Speter tp = MINOR2TP(mynor); 97610015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 97710015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 97810015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 97910015Speter} 98010015Speter 98110015Speter 98210015Speterint 98310015Spetersiwrite(dev, uio, flag) 98410015Speter dev_t dev; 98510015Speter struct uio *uio; 98610015Speter int flag; 98710015Speter{ 98810015Speter register struct si_port *pp; 98910015Speter register struct tty *tp; 99010015Speter int error = 0; 99110015Speter int mynor = minor(dev); 99210015Speter int oldspl; 99310015Speter 99410015Speter if (IS_SPECIAL(mynor)) { 99510015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 99610015Speter return(ENODEV); 99710015Speter } 99810015Speter pp = MINOR2PP(mynor); 99910015Speter tp = pp->sp_tty; 100010015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 100110015Speter 100210015Speter oldspl = spltty(); 100310015Speter /* 100410015Speter * If writes are currently blocked, wait on the "real" tty 100510015Speter */ 100610015Speter while (pp->sp_state & SS_BLOCKWRITE) { 100710015Speter pp->sp_state |= SS_WAITWRITE; 100810015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 100910015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 101010015Speter "siwrite", 0)) 101110015Speter goto out; 101210015Speter } 101310015Speter 101410015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 101510015Speterout: 101610015Speter splx(oldspl); 101710015Speter return (error); 101810015Speter} 101910015Speter 102010015Speter 102110015Speterstruct tty * 102210015Spetersidevtotty(dev_t dev) 102310015Speter{ 102410015Speter struct si_port *pp; 102510015Speter int mynor = minor(dev); 102610015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 102710015Speter 102810015Speter if (IS_SPECIAL(mynor)) 102910015Speter return(NULL); 103010015Speter if (SI_PORT(mynor) >= sc->sc_nport) 103110015Speter return(NULL); 103210015Speter pp = MINOR2PP(mynor); 103310015Speter return (pp->sp_tty); 103410015Speter} 103510015Speter 103610015Speterint 103710015Spetersiioctl(dev, cmd, data, flag, p) 103810015Speter dev_t dev; 103910015Speter int cmd; 104010015Speter caddr_t data; 104110015Speter int flag; 104210015Speter struct proc *p; 104310015Speter{ 104410015Speter struct si_port *pp; 104510015Speter register struct tty *tp; 104610015Speter int error; 104710015Speter int mynor = minor(dev); 104810015Speter int oldspl; 104910015Speter int blocked = 0; 105010015Speter#if defined(COMPAT_43) 105110015Speter int oldcmd; 105210015Speter struct termios term; 105310015Speter#endif 105410015Speter 105510015Speter if (IS_SI_IOCTL(cmd)) 105610015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 105710015Speter 105810015Speter pp = MINOR2PP(mynor); 105910015Speter tp = pp->sp_tty; 106010015Speter 106110015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 106210015Speter dev, cmd, data, flag)); 106310015Speter if (IS_STATE(mynor)) { 106410015Speter struct termios *ct; 106510015Speter 106610015Speter switch (mynor & SI_STATE_MASK) { 106710015Speter case SI_INIT_STATE_MASK: 106810015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 106910015Speter break; 107010015Speter case SI_LOCK_STATE_MASK: 107110015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 107210015Speter break; 107310015Speter default: 107410015Speter return (ENODEV); 107510015Speter } 107610015Speter switch (cmd) { 107710015Speter case TIOCSETA: 107810015Speter error = suser(p->p_ucred, &p->p_acflag); 107910015Speter if (error != 0) 108010015Speter return (error); 108110015Speter *ct = *(struct termios *)data; 108210015Speter return (0); 108310015Speter case TIOCGETA: 108410015Speter *(struct termios *)data = *ct; 108510015Speter return (0); 108610015Speter case TIOCGETD: 108710015Speter *(int *)data = TTYDISC; 108810015Speter return (0); 108910015Speter case TIOCGWINSZ: 109010015Speter bzero(data, sizeof(struct winsize)); 109110015Speter return (0); 109210015Speter default: 109310015Speter return (ENOTTY); 109410015Speter } 109510015Speter } 109610015Speter /* 109710015Speter * Do the old-style ioctl compat routines... 109810015Speter */ 109910015Speter#if defined(COMPAT_43) 110010015Speter term = tp->t_termios; 110110015Speter oldcmd = cmd; 110210015Speter error = ttsetcompat(tp, &cmd, data, &term); 110310015Speter if (error != 0) 110410015Speter return (error); 110510015Speter if (cmd != oldcmd) 110610015Speter data = (caddr_t)&term; 110710015Speter#endif 110810015Speter /* 110910015Speter * Do the initial / lock state business 111010015Speter */ 111110015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 111210015Speter int cc; 111310015Speter struct termios *dt = (struct termios *)data; 111410015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 111510015Speter ? &pp->sp_lout : &pp->sp_lin; 111610015Speter 111710015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 111810015Speter | (dt->c_iflag & ~lt->c_iflag); 111910015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 112010015Speter | (dt->c_oflag & ~lt->c_oflag); 112110015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 112210015Speter | (dt->c_cflag & ~lt->c_cflag); 112310015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 112410015Speter | (dt->c_lflag & ~lt->c_lflag); 112510015Speter for (cc = 0; cc < NCCS; ++cc) 112610015Speter if (lt->c_cc[cc] != 0) 112710015Speter dt->c_cc[cc] = tp->t_cc[cc]; 112810015Speter if (lt->c_ispeed != 0) 112910015Speter dt->c_ispeed = tp->t_ispeed; 113010015Speter if (lt->c_ospeed != 0) 113110015Speter dt->c_ospeed = tp->t_ospeed; 113210015Speter } 113310015Speter 113410015Speter /* 113510015Speter * Block user-level writes to give the ttywait() 113610015Speter * a chance to completely drain for commands 113710015Speter * that require the port to be in a quiescent state. 113810015Speter */ 113910015Speter switch (cmd) { 114010015Speter case TIOCSETAW: case TIOCSETAF: 114110015Speter case TIOCDRAIN: case TIOCSETP: 114210015Speter blocked++; /* block writes for ttywait() and siparam() */ 114310015Speter si_write_enable(pp, 0); 114410015Speter } 114510015Speter 114610015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 114710015Speter if (error >= 0) 114810015Speter goto out; 114910015Speter 115010015Speter oldspl = spltty(); 115110015Speter 115210015Speter error = ttioctl(tp, cmd, data, flag); 115310015Speter si_disc_optim(tp, &tp->t_termios, pp); 115410015Speter if (error >= 0) 115510015Speter goto outspl; 115610015Speter 115710015Speter switch (cmd) { 115810015Speter case TIOCSBRK: 115910015Speter si_command(pp, SBREAK, SI_NOWAIT); 116010015Speter break; 116110015Speter case TIOCCBRK: 116210015Speter si_command(pp, EBREAK, SI_NOWAIT); 116310015Speter break; 116410015Speter case TIOCSDTR: 116510015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 116610015Speter break; 116710015Speter case TIOCCDTR: 116810015Speter (void) si_modem(pp, SET, 0); 116910015Speter break; 117010015Speter case TIOCMSET: 117110015Speter (void) si_modem(pp, SET, *(int *)data); 117210015Speter break; 117310015Speter case TIOCMBIS: 117410015Speter (void) si_modem(pp, BIS, *(int *)data); 117510015Speter break; 117610015Speter case TIOCMBIC: 117710015Speter (void) si_modem(pp, BIC, *(int *)data); 117810015Speter break; 117910015Speter case TIOCMGET: 118010015Speter *(int *)data = si_modem(pp, GET, 0); 118110015Speter break; 118210015Speter case TIOCMSDTRWAIT: 118310015Speter /* must be root since the wait applies to following logins */ 118410015Speter error = suser(p->p_ucred, &p->p_acflag); 118510015Speter if (error != 0) { 118610015Speter goto outspl; 118710015Speter } 118810015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 118910015Speter break; 119010015Speter case TIOCMGDTRWAIT: 119110015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 119210015Speter break; 119310015Speter 119410015Speter default: 119510015Speter error = ENOTTY; 119610015Speter } 119710015Speter error = 0; 119810015Speteroutspl: 119910015Speter splx(oldspl); 120010015Speterout: 120110015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 120210015Speter if (blocked) 120310015Speter si_write_enable(pp, 1); 120410015Speter return(error); 120510015Speter} 120610015Speter 120710015Speter/* 120810015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 120910015Speter */ 121010015Speterstatic int 121110015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 121210015Speter{ 121310015Speter struct si_softc *xsc; 121410015Speter register struct si_port *xpp; 121510015Speter volatile struct si_reg *regp; 121610015Speter struct si_tcsi *dp; 121710044Speter struct si_pstat *sps; 121811872Sphk int *ip, error = 0; 121910015Speter int oldspl; 122010015Speter int card, port; 122110015Speter int mynor = minor(dev); 122210015Speter 122310015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 122410015Speter dev, cmd, data, flag)); 122510015Speter 122610044Speter#if 1 122710044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 122810044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 122910044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 123010044Speter#endif 123110044Speter 123210015Speter if (!IS_CONTROLDEV(mynor)) { 123310015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 123410015Speter return(ENODEV); 123510015Speter } 123610015Speter 123710015Speter oldspl = spltty(); /* better safe than sorry */ 123810015Speter 123910015Speter ip = (int *)data; 124010015Speter 124110015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 124210015Speter 124310015Speter switch (cmd) { 124410015Speter case TCSIPORTS: 124510015Speter *ip = si_Nports; 124610015Speter goto out; 124710015Speter case TCSIMODULES: 124810015Speter *ip = si_Nmodules; 124910015Speter goto out; 125010015Speter case TCSISDBG_ALL: 125110015Speter SUCHECK; 125210015Speter si_debug = *ip; 125310015Speter goto out; 125410015Speter case TCSIGDBG_ALL: 125510015Speter *ip = si_debug; 125610015Speter goto out; 125710015Speter default: 125810015Speter /* 125910015Speter * Check that a controller for this port exists 126010015Speter */ 126110044Speter 126210044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 126310044Speter 126410015Speter dp = (struct si_tcsi *)data; 126510044Speter sps = (struct si_pstat *)data; 126610015Speter card = dp->tc_card; 126710015Speter xsc = &si_softc[card]; /* check.. */ 126812174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 126910015Speter error = ENOENT; 127010015Speter goto out; 127110015Speter } 127210015Speter /* 127310015Speter * And check that a port exists 127410015Speter */ 127510015Speter port = dp->tc_port; 127610015Speter if (port < 0 || port >= xsc->sc_nport) { 127710015Speter error = ENOENT; 127810015Speter goto out; 127910015Speter } 128010015Speter xpp = xsc->sc_ports + port; 128110015Speter regp = (struct si_reg *)xsc->sc_maddr; 128210015Speter } 128310015Speter 128410015Speter switch (cmd) { 128510015Speter case TCSIDEBUG: 128610015Speter#ifdef SI_DEBUG 128710015Speter SUCHECK; 128810015Speter if (xpp->sp_debug) 128910015Speter xpp->sp_debug = 0; 129010015Speter else { 129110015Speter xpp->sp_debug = DBG_ALL; 129210015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 129310015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 129410015Speter } 129510015Speter break; 129610015Speter#else 129710015Speter error = ENODEV; 129810015Speter goto out; 129910015Speter#endif 130010015Speter case TCSISDBG_LEVEL: 130110015Speter case TCSIGDBG_LEVEL: 130210015Speter#ifdef SI_DEBUG 130310015Speter if (cmd == TCSIGDBG_LEVEL) { 130410015Speter dp->tc_dbglvl = xpp->sp_debug; 130510015Speter } else { 130610015Speter SUCHECK; 130710015Speter xpp->sp_debug = dp->tc_dbglvl; 130810015Speter } 130910015Speter break; 131010015Speter#else 131110015Speter error = ENODEV; 131210015Speter goto out; 131310015Speter#endif 131410015Speter case TCSIGRXIT: 131510015Speter dp->tc_int = regp->rx_int_count; 131610015Speter break; 131710015Speter case TCSIRXIT: 131810015Speter SUCHECK; 131910015Speter regp->rx_int_count = dp->tc_int; 132010015Speter break; 132110015Speter case TCSIGIT: 132210015Speter dp->tc_int = regp->int_count; 132310015Speter break; 132410015Speter case TCSIIT: 132510015Speter SUCHECK; 132610015Speter regp->int_count = dp->tc_int; 132710015Speter break; 132810044Speter case TCSISTATE: 132910044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 133010015Speter break; 133110044Speter /* these next three use a different structure */ 133210044Speter case TCSI_PORT: 133310015Speter SUCHECK; 133410044Speter sps->tc_siport = *xpp; 133510015Speter break; 133610044Speter case TCSI_CCB: 133710044Speter SUCHECK; 133810044Speter sps->tc_ccb = *xpp->sp_ccb; 133910015Speter break; 134010044Speter case TCSI_TTY: 134110044Speter SUCHECK; 134210044Speter sps->tc_tty = *xpp->sp_tty; 134310015Speter break; 134410015Speter default: 134510015Speter error = EINVAL; 134610015Speter goto out; 134710015Speter } 134810015Speterout: 134910015Speter splx(oldspl); 135010015Speter return(error); /* success */ 135110015Speter} 135210015Speter 135310015Speter/* 135410015Speter * siparam() : Configure line params 135510015Speter * called at spltty(); 135610015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 135710015Speter * caller must arrange this if it's important.. 135810015Speter */ 135910015Speterint 136010015Spetersiparam(tp, t) 136110015Speter register struct tty *tp; 136210015Speter register struct termios *t; 136310015Speter{ 136410015Speter register struct si_port *pp = TP2PP(tp); 136510015Speter volatile struct si_channel *ccbp; 136610015Speter int oldspl, cflag, iflag, oflag, lflag; 136710015Speter int error = 0; /* shutup gcc */ 136810015Speter int ispeed = 0; /* shutup gcc */ 136910015Speter int ospeed = 0; /* shutup gcc */ 137010161Speter BYTE val; 137110015Speter 137210015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 137310015Speter cflag = t->c_cflag; 137410015Speter iflag = t->c_iflag; 137510015Speter oflag = t->c_oflag; 137610015Speter lflag = t->c_lflag; 137710044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 137810044Speter oflag, cflag, iflag, lflag)); 137910015Speter 138010015Speter 138110015Speter /* if not hung up.. */ 138210015Speter if (t->c_ospeed != 0) { 138310015Speter /* translate baud rate to firmware values */ 138410015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 138510015Speter ispeed = t->c_ispeed ? 138610015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 138710015Speter 138810015Speter /* enforce legit baud rate */ 138910015Speter if (ospeed < 0 || ispeed < 0) 139010015Speter return (EINVAL); 139110015Speter } 139210015Speter 139310015Speter 139410015Speter oldspl = spltty(); 139510015Speter 139610015Speter ccbp = pp->sp_ccb; 139710015Speter 139810161Speter /* ========== set hi_break ========== */ 139910161Speter val = 0; 140010161Speter if (iflag & IGNBRK) /* Breaks */ 140110161Speter val |= BR_IGN; 140210161Speter if (iflag & BRKINT) /* Interrupt on break? */ 140310161Speter val |= BR_INT; 140410161Speter if (iflag & PARMRK) /* Parity mark? */ 140510161Speter val |= BR_PARMRK; 140610161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 140710161Speter val |= BR_PARIGN; 140810161Speter ccbp->hi_break = val; 140910161Speter 141010161Speter /* ========== set hi_csr ========== */ 141110015Speter /* if not hung up.. */ 141210015Speter if (t->c_ospeed != 0) { 141310015Speter /* Set I/O speeds */ 141410161Speter val = (ispeed << 4) | ospeed; 141510015Speter } 141610161Speter ccbp->hi_csr = val; 141710015Speter 141810161Speter /* ========== set hi_mr2 ========== */ 141910161Speter val = 0; 142010015Speter if (cflag & CSTOPB) /* Stop bits */ 142110161Speter val |= MR2_2_STOP; 142210015Speter else 142310161Speter val |= MR2_1_STOP; 142410161Speter /* 142510161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 142610161Speter * a DCE, hence the reverse sense of RTS and CTS 142710161Speter */ 142810161Speter /* Output Flow - RTS must be raised before data can be sent */ 142910161Speter if (cflag & CCTS_OFLOW) 143010161Speter val |= MR2_RTSCONT; 143110161Speter 143210161Speter ccbp->hi_mr1 = val; 143310161Speter 143410161Speter /* ========== set hi_mr1 ========== */ 143510161Speter val = 0; 143610015Speter if (!(cflag & PARENB)) /* Parity */ 143710161Speter val |= MR1_NONE; 143810015Speter else 143910161Speter val |= MR1_WITH; 144010015Speter if (cflag & PARODD) 144110161Speter val |= MR1_ODD; 144210015Speter 144310015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 144410161Speter val |= MR1_8_BITS; 144510015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 144610161Speter val |= MR1_7_BITS; 144710015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 144810161Speter val |= MR1_6_BITS; 144910015Speter } else { /* Must be 5 */ 145010161Speter val |= MR1_5_BITS; 145110015Speter } 145210161Speter /* 145310161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 145410161Speter * a DCE, hence the reverse sense of RTS and CTS 145510161Speter */ 145610161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 145710161Speter if (cflag & CRTS_IFLOW) 145810161Speter val |= MR1_CTSCONT; 145910015Speter 146010161Speter ccbp->hi_mr1 = val; 146110161Speter 146210161Speter /* ========== set hi_mask ========== */ 146310161Speter val = 0xff; 146410161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 146510161Speter val &= 0xFF; 146610161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 146710161Speter val &= 0x7F; 146810161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 146910161Speter val &= 0x3F; 147010161Speter } else { /* Must be 5 */ 147110161Speter val &= 0x1F; 147210161Speter } 147310015Speter if (iflag & ISTRIP) 147410161Speter val &= 0x7F; 147510015Speter 147610161Speter ccbp->hi_mask = val; 147710161Speter 147810161Speter /* ========== set hi_prtcl ========== */ 147910161Speter val = 0; 148010015Speter /* Monitor DCD etc. if a modem */ 148110015Speter if (!(cflag & CLOCAL)) 148210161Speter val |= SP_DCEN; 148310161Speter if (iflag & IXANY) 148410161Speter val |= SP_TANY; 148510161Speter if (iflag & IXON) 148610161Speter val |= SP_TXEN; 148710161Speter if (iflag & IXOFF) 148810161Speter val |= SP_RXEN; 148910161Speter if (iflag & INPCK) 149010161Speter val |= SP_PAEN; 149110015Speter 149210161Speter ccbp->hi_prtcl = val; 149310161Speter 149410161Speter 149510161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 149610161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 149710015Speter ccbp->hi_txon = t->c_cc[VSTART]; 149810015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 149910015Speter 150010015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 150110015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 150210015Speter 150310161Speter /* ========== send settings to the card ========== */ 150410015Speter /* potential sleep here */ 150510015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 150610015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 150710015Speter else 150810015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 150910015Speter 151010161Speter /* ========== set DTR etc ========== */ 151110015Speter /* Hangup if ospeed == 0 */ 151210015Speter if (t->c_ospeed == 0) { 151310015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 151410015Speter } else { 151510015Speter /* 151610015Speter * If the previous speed was 0, may need to re-enable 151710015Speter * the modem signals 151810015Speter */ 151910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 152010015Speter } 152110015Speter 152210044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 152310044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 152410015Speter 152510015Speter splx(oldspl); 152610015Speter return(error); 152710015Speter} 152810015Speter 152910015Speter/* 153010015Speter * Enable or Disable the writes to this channel... 153110015Speter * "state" -> enabled = 1; disabled = 0; 153210015Speter */ 153310015Speterstatic void 153410015Spetersi_write_enable(pp, state) 153510015Speter register struct si_port *pp; 153610015Speter int state; 153710015Speter{ 153810015Speter int oldspl; 153910015Speter 154010015Speter oldspl = spltty(); 154110015Speter 154210015Speter if (state) { 154310015Speter pp->sp_state &= ~SS_BLOCKWRITE; 154410015Speter if (pp->sp_state & SS_WAITWRITE) { 154510015Speter pp->sp_state &= ~SS_WAITWRITE; 154610015Speter /* thunder away! */ 154710015Speter wakeup((caddr_t)pp); 154810015Speter } 154910015Speter } else { 155010015Speter pp->sp_state |= SS_BLOCKWRITE; 155110015Speter } 155210015Speter 155310015Speter splx(oldspl); 155410015Speter} 155510015Speter 155610015Speter/* 155710015Speter * Set/Get state of modem control lines. 155810015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 155910015Speter * TIOCM_DTR DSR 156010015Speter * TIOCM_RTS CTS 156110015Speter */ 156210015Speterstatic int 156310015Spetersi_modem(pp, cmd, bits) 156410015Speter struct si_port *pp; 156510015Speter enum si_mctl cmd; 156610015Speter int bits; 156710015Speter{ 156810015Speter volatile struct si_channel *ccbp; 156910015Speter int x; 157010015Speter 157110015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 157210015Speter ccbp = pp->sp_ccb; /* Find channel address */ 157310015Speter switch (cmd) { 157410015Speter case GET: 157510015Speter x = ccbp->hi_ip; 157610015Speter bits = TIOCM_LE; 157710015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 157810015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 157910015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 158010015Speter if (x & IP_RI) bits |= TIOCM_RI; 158110015Speter return(bits); 158210015Speter case SET: 158310015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 158410015Speter /* fall through */ 158510015Speter case BIS: 158610015Speter x = 0; 158710015Speter if (bits & TIOCM_DTR) 158810015Speter x |= OP_DSR; 158910015Speter if (bits & TIOCM_RTS) 159010015Speter x |= OP_CTS; 159110015Speter ccbp->hi_op |= x; 159210015Speter break; 159310015Speter case BIC: 159410015Speter if (bits & TIOCM_DTR) 159510015Speter ccbp->hi_op &= ~OP_DSR; 159610015Speter if (bits & TIOCM_RTS) 159710015Speter ccbp->hi_op &= ~OP_CTS; 159810015Speter } 159910015Speter return 0; 160010015Speter} 160110015Speter 160210015Speter/* 160310015Speter * Handle change of modem state 160410015Speter */ 160510015Speterstatic void 160610015Spetersi_modem_state(pp, tp, hi_ip) 160710015Speter register struct si_port *pp; 160810015Speter register struct tty *tp; 160910015Speter register int hi_ip; 161010015Speter{ 161110015Speter /* if a modem dev */ 161210015Speter if (hi_ip & IP_DCD) { 161310015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 161410015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 161510015Speter tp->t_line)); 161610015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 161710015Speter } 161810015Speter } else { 161910015Speter if (pp->sp_last_hi_ip & IP_DCD) { 162010015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 162110015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 162210015Speter (void) si_modem(pp, SET, 0); 162310015Speter } 162410015Speter } 162510015Speter pp->sp_last_hi_ip = hi_ip; 162610015Speter 162710015Speter} 162810015Speter 162910015Speter/* 163010015Speter * Poller to catch missed interrupts. 163112174Speter * 163212496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 163312496Speter * better response. We could really use a "periodic" version timeout(). :-) 163410015Speter */ 163510015Speter#ifdef POLL 163610708Speterstatic void 163710015Spetersi_poll(void *nothing) 163810015Speter{ 163910015Speter register struct si_softc *sc; 164010015Speter register int i; 164110015Speter volatile struct si_reg *regp; 164212174Speter register struct si_port *pp; 164312174Speter int lost, oldspl, port; 164410015Speter 164510015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 164611609Speter oldspl = spltty(); 164710015Speter if (in_intr) 164810015Speter goto out; 164910015Speter lost = 0; 165010015Speter for (i=0; i<NSI; i++) { 165110015Speter sc = &si_softc[i]; 165212174Speter if (sc->sc_type == SIEMPTY) 165310015Speter continue; 165410015Speter regp = (struct si_reg *)sc->sc_maddr; 165510015Speter /* 165610015Speter * See if there has been a pending interrupt for 2 seconds 165710015Speter * or so. The test <int_scounter >= 200) won't correspond 165810015Speter * to 2 seconds if int_count gets changed. 165910015Speter */ 166010015Speter if (regp->int_pending != 0) { 166110015Speter if (regp->int_scounter >= 200 && 166210015Speter regp->initstat == 1) { 166312174Speter printf("si%d: lost intr\n", i); 166410015Speter lost++; 166510015Speter } 166610015Speter } else { 166710015Speter regp->int_scounter = 0; 166810015Speter } 166910015Speter 167012174Speter /* 167112174Speter * gripe about no input flow control.. 167212174Speter */ 167312174Speter pp = sc->sc_ports; 167412174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 167512174Speter if (pp->sp_delta_overflows > 0) { 167612174Speter printf("si%d: %d tty level buffer overflows\n", 167712174Speter i, pp->sp_delta_overflows); 167812174Speter pp->sp_delta_overflows = 0; 167912174Speter } 168012174Speter } 168110015Speter } 168210015Speter if (lost) 168310015Speter siintr(-1); /* call intr with fake vector */ 168411609Speterout: 168510015Speter splx(oldspl); 168610015Speter 168710015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 168810015Speter} 168910015Speter#endif /* ifdef POLL */ 169010015Speter 169110015Speter/* 169210015Speter * The interrupt handler polls ALL ports on ALL adapters each time 169310015Speter * it is called. 169410015Speter */ 169510015Speter 169612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 169710015Speter 169810708Spetervoid 169911609Spetersiintr(int unit) 170010015Speter{ 170110015Speter register struct si_softc *sc; 170210015Speter 170310015Speter register struct si_port *pp; 170410015Speter volatile struct si_channel *ccbp; 170510015Speter register struct tty *tp; 170610015Speter volatile caddr_t maddr; 170711872Sphk BYTE op, ip; 170812174Speter int x, card, port, n, i, isopen; 170910015Speter volatile BYTE *z; 171010015Speter BYTE c; 171110015Speter 171211609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 171311609Speter if (in_intr) { 171411609Speter if (unit < 0) /* should never happen */ 171510708Speter return; 171612174Speter printf("si%d: Warning interrupt handler re-entered\n", 171711609Speter unit); 171810708Speter return; 171910015Speter } 172010015Speter in_intr = 1; 172110015Speter 172210015Speter /* 172310015Speter * When we get an int we poll all the channels and do ALL pending 172410015Speter * work, not just the first one we find. This allows all cards to 172510015Speter * share the same vector. 172610015Speter */ 172710015Speter for (card=0; card < NSI; card++) { 172810015Speter sc = &si_softc[card]; 172912174Speter if (sc->sc_type == SIEMPTY) 173010015Speter continue; 173112174Speter 173212174Speter /* 173312174Speter * First, clear the interrupt 173412174Speter */ 173510015Speter switch(sc->sc_type) { 173610015Speter case SIHOST : 173710015Speter maddr = sc->sc_maddr; 173810015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 173910015Speter /* flag nothing pending */ 174010015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 174110015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 174210015Speter break; 174310015Speter case SIHOST2: 174410015Speter maddr = sc->sc_maddr; 174510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 174610015Speter *(maddr+SIPLIRQCLR) = 0x00; 174710015Speter *(maddr+SIPLIRQCLR) = 0x10; 174810015Speter break; 174910015Speter case SIEISA: 175010015Speter#if NEISA > 0 175110015Speter maddr = sc->sc_maddr; 175210015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 175310015Speter (void)inb(sc->sc_eisa_iobase+3); 175410015Speter break; 175510015Speter#endif /* fall through if not EISA kernel */ 175610015Speter case SIEMPTY: 175710015Speter default: 175810015Speter continue; 175910015Speter } 176010015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 176110015Speter 176212174Speter /* 176312174Speter * check each port 176412174Speter */ 176512174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 176610015Speter ccbp = pp->sp_ccb; 176710015Speter tp = pp->sp_tty; 176810015Speter 176912174Speter 177010015Speter /* 177110015Speter * See if a command has completed ? 177210015Speter */ 177310015Speter if (ccbp->hi_stat != pp->sp_pend) { 177410015Speter DPRINT((pp, DBG_INTR, 177510015Speter "siintr hi_stat = 0x%x, pend = %d\n", 177610015Speter ccbp->hi_stat, pp->sp_pend)); 177710015Speter switch(pp->sp_pend) { 177810015Speter case LOPEN: 177910015Speter case MPEND: 178010015Speter case MOPEN: 178110015Speter case CONFIG: 178210015Speter pp->sp_pend = ccbp->hi_stat; 178310015Speter /* sleeping in si_command */ 178410015Speter wakeup(&pp->sp_state); 178510015Speter break; 178610015Speter default: 178710015Speter pp->sp_pend = ccbp->hi_stat; 178810015Speter } 178910015Speter } 179010015Speter 179110015Speter /* 179210015Speter * Continue on if it's closed 179310015Speter */ 179410015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 179510015Speter continue; 179610015Speter } 179710015Speter 179810015Speter /* 179910015Speter * Do modem state change if not a local device 180010015Speter */ 180110015Speter si_modem_state(pp, tp, ccbp->hi_ip); 180210015Speter 180310015Speter /* 180412174Speter * Check to see if there's we should 'receive' 180512174Speter * characters. 180612174Speter */ 180712174Speter if (tp->t_state & TS_CONNECTED && 180812174Speter tp->t_state & TS_ISOPEN) 180912174Speter isopen = 1; 181012174Speter else 181112174Speter isopen = 0; 181212174Speter 181312174Speter /* 181410015Speter * Do break processing 181510015Speter */ 181610015Speter if (ccbp->hi_state & ST_BREAK) { 181712174Speter if (isopen) { 181812174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 181910015Speter } 182010015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 182110015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 182210015Speter } 182310015Speter 182410015Speter /* 182512174Speter * Do RX stuff - if not open then dump any characters. 182612174Speter * XXX: This is VERY messy and needs to be cleaned up. 182712174Speter * 182812174Speter * XXX: can we leave data in the host adapter buffer 182912174Speter * when the clists are full? That may be dangerous 183012174Speter * if the user cannot get an interrupt signal through. 183110015Speter */ 183210015Speter 183312174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 183412174Speter 183512174Speter if (!isopen) { 183610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 183712174Speter goto end_rx; 183812174Speter } 183910015Speter 184012174Speter /* 184112174Speter * Process read characters if not skipped above 184212174Speter */ 184312174Speter c = ccbp->hi_rxipos - ccbp->hi_rxopos; 184412174Speter if (c == 0) { 184512174Speter goto end_rx; 184612174Speter } 184710015Speter 184812174Speter op = ccbp->hi_rxopos; 184912174Speter ip = ccbp->hi_rxipos; 185012174Speter n = c & 0xff; 185112174Speter 185212174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 185310015Speter n, op, ip)); 185410015Speter 185512174Speter /* 185612174Speter * Suck characters out of host card buffer into the 185712174Speter * "input staging buffer" - so that we dont leave the 185812174Speter * host card in limbo while we're possibly echoing 185912174Speter * characters and possibly flushing input inside the 186012174Speter * ldisc l_rint() routine. 186112174Speter */ 186212496Speter if (n <= SI_BUFFERSIZE - op) { 186310015Speter 186412174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 186512174Speter z = ccbp->hi_rxbuf + op; 186612174Speter bcopy((caddr_t)z, si_rxbuf, n); 186710015Speter 186812174Speter op += n; 186912174Speter } else { 187012496Speter x = SI_BUFFERSIZE - op; 187110015Speter 187212174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 187312174Speter z = ccbp->hi_rxbuf + op; 187412174Speter bcopy((caddr_t)z, si_rxbuf, x); 187510015Speter 187612174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 187712174Speter z = ccbp->hi_rxbuf; 187812174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 187910015Speter 188012174Speter op += n; 188112174Speter } 188210015Speter 188312174Speter /* clear collected characters from buffer */ 188412174Speter ccbp->hi_rxopos = op; 188512174Speter 188612174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 188710015Speter n, op, ip)); 188810015Speter 188912174Speter /* 189012174Speter * at this point... 189112174Speter * n = number of chars placed in si_rxbuf 189212174Speter */ 189310015Speter 189412174Speter /* 189512174Speter * Avoid the grotesquely inefficient lineswitch 189612174Speter * routine (ttyinput) in "raw" mode. It usually 189712174Speter * takes about 450 instructions (that's without 189812174Speter * canonical processing or echo!). slinput is 189912174Speter * reasonably fast (usually 40 instructions 190012174Speter * plus call overhead). 190112174Speter */ 190212174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 190310015Speter 190412174Speter /* block if the driver supports it */ 190512174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 190612174Speter && (tp->t_cflag & CRTS_IFLOW 190712174Speter || tp->t_iflag & IXOFF) 190812174Speter && !(tp->t_state & TS_TBLOCK)) 190912174Speter ttyblock(tp); 191010015Speter 191112174Speter tk_nin += n; 191212174Speter tk_rawcc += n; 191312174Speter tp->t_rawcc += n; 191412174Speter 191512174Speter pp->sp_delta_overflows += 191612174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 191712174Speter 191812174Speter ttwakeup(tp); 191912174Speter if (tp->t_state & TS_TTSTOP 192012174Speter && (tp->t_iflag & IXANY 192112174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 192212174Speter tp->t_state &= ~TS_TTSTOP; 192312174Speter tp->t_lflag &= ~FLUSHO; 192412174Speter si_start(tp); 192512174Speter } 192612174Speter } else { 192712174Speter /* 192812174Speter * It'd be nice to not have to go through the 192912174Speter * function call overhead for each char here. 193012174Speter * It'd be nice to block input it, saving a 193112174Speter * loop here and the call/return overhead. 193212174Speter */ 193312174Speter for(x = 0; x < n; x++) { 193412174Speter i = si_rxbuf[x]; 193512174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 193612174Speter == -1) { 193712174Speter pp->sp_delta_overflows++; 193810015Speter } 193912174Speter /* 194012174Speter * doesn't seem to be much point doing 194112174Speter * this here.. this driver has no 194212174Speter * softtty processing! ?? 194312174Speter */ 194412174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 194512174Speter setsofttty(); 194612174Speter } 194712174Speter } 194812174Speter } 194912174Speter goto more_rx; /* try for more until RXbuf is empty */ 195010015Speter 195112174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 195210015Speter 195310015Speter /* 195410015Speter * Do TX stuff 195510015Speter */ 195610015Speter (*linesw[tp->t_line].l_start)(tp); 195710015Speter 195810015Speter } /* end of for (all ports on this controller) */ 195910015Speter } /* end of for (all controllers) */ 196010015Speter 196111609Speter in_intr = 0; 196211609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 196310015Speter} 196410015Speter 196510015Speter/* 196610015Speter * Nudge the transmitter... 196712174Speter * 196812174Speter * XXX: I inherited some funny code here. It implies the host card only 196912174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 197012174Speter * not interrupt when it's actually hits empty. In some cases, we have 197112174Speter * processes waiting for complete drain, and we need to simulate an interrupt 197212174Speter * about when we think the buffer is going to be empty (and retry if not). 197312174Speter * I really am not certain about this... I *need* the hardware manuals. 197410015Speter */ 197510015Speterstatic void 197610015Spetersi_start(tp) 197710015Speter register struct tty *tp; 197810015Speter{ 197910015Speter struct si_port *pp; 198010015Speter volatile struct si_channel *ccbp; 198110015Speter register struct clist *qp; 198210015Speter register char *dptr; 198310015Speter BYTE ipos; 198410015Speter int nchar; 198510015Speter int oldspl, count, n, amount, buffer_full; 198610015Speter int do_exitproc; 198710015Speter 198810015Speter oldspl = spltty(); 198910015Speter 199010015Speter qp = &tp->t_outq; 199110015Speter pp = TP2PP(tp); 199210015Speter 199310015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 199410015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 199510015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 199610015Speter 199710015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 199810015Speter goto out; 199910015Speter 200010015Speter do_exitproc = 0; 200110015Speter buffer_full = 0; 200210015Speter ccbp = pp->sp_ccb; 200310015Speter 200410015Speter /* 200510015Speter * Handle the case where ttywait() is called on process exit 200610015Speter * this may be BSDI specific, I dont know... 200710015Speter */ 200810015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 200910015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 201010015Speter do_exitproc++; 201110015Speter } 201210015Speter 201310015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 201410015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 201510015Speter 201610015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 201710015Speter 201810015Speter while ((nchar = qp->c_cc) > 0) { 201910015Speter if ((BYTE)count >= 255) { 202010015Speter buffer_full++; 202110015Speter break; 202210015Speter } 202310015Speter amount = min(nchar, (255 - (BYTE)count)); 202410015Speter ipos = (unsigned int)ccbp->hi_txipos; 202510015Speter /* will it fit in one lump? */ 202612496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 202710015Speter n = q_to_b(&tp->t_outq, 202810015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 202910015Speter } else { 203010015Speter n = q_to_b(&tp->t_outq, 203110015Speter (char *)&ccbp->hi_txbuf[ipos], 203212496Speter SI_BUFFERSIZE-ipos); 203312496Speter if (n == SI_BUFFERSIZE-ipos) { 203410015Speter n += q_to_b(&tp->t_outq, 203510015Speter (char *)&ccbp->hi_txbuf[0], 203612496Speter amount - (SI_BUFFERSIZE-ipos)); 203710015Speter } 203810015Speter } 203910015Speter ccbp->hi_txipos += n; 204010015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 204110015Speter } 204210015Speter 204310015Speter if (count != 0 && nchar == 0) { 204410015Speter tp->t_state |= TS_BUSY; 204510015Speter } else { 204610015Speter tp->t_state &= ~TS_BUSY; 204710015Speter } 204810015Speter 204910015Speter /* wakeup time? */ 205010015Speter ttwwakeup(tp); 205110015Speter 205210015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 205310015Speter (BYTE)count, nchar, tp->t_state)); 205410015Speter 205510015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 205610015Speter { 205710015Speter int time; 205810015Speter 205910015Speter if (do_exitproc != 0) { 206010015Speter time = hz / 10; 206110015Speter } else { 206210015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 206310015Speter 206410015Speter if (time > 0) { 206510015Speter if (time < nchar) 206610015Speter time = nchar / time; 206710015Speter else 206810015Speter time = 2; 206910015Speter } else { 207012174Speter printf("si%d: bad char time value!!\n", 207112174Speter (int)SI_CARD(tp->t_dev)); 207210015Speter goto out; 207310015Speter } 207410015Speter } 207510015Speter 207610015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 207710015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 207810015Speter } else { 207910015Speter pp->sp_state |= SS_LSTART; 208010015Speter } 208110015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 208210015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 208310015Speter } 208410015Speter 208510015Speterout: 208610015Speter splx(oldspl); 208710015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 208810015Speter} 208910015Speter 209010015Speter/* 209110015Speter * Note: called at splsoftclock from the timeout code 209210015Speter * This has to deal with two things... cause wakeups while waiting for 209310015Speter * tty drains on last process exit, and call l_start at about the right 209410015Speter * time for protocols like ppp. 209510015Speter */ 209610015Speterstatic void 209710015Spetersi_lstart(pp) 209810015Speter register struct si_port *pp; 209910015Speter{ 210010015Speter register struct tty *tp; 210110015Speter int oldspl; 210210015Speter 210310015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 210410015Speter pp, pp->sp_state)); 210510015Speter 210610015Speter oldspl = spltty(); 210710015Speter 210810015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 210910015Speter splx(oldspl); 211010015Speter return; 211110015Speter } 211210015Speter pp->sp_state &= ~SS_LSTART; 211310015Speter pp->sp_state |= SS_INLSTART; 211410015Speter 211510015Speter tp = pp->sp_tty; 211610015Speter 211710015Speter /* deal with the process exit case */ 211810015Speter ttwwakeup(tp); 211910015Speter 212012174Speter /* nudge protocols - eg: ppp */ 212110015Speter (*linesw[tp->t_line].l_start)(tp); 212210015Speter 212310015Speter pp->sp_state &= ~SS_INLSTART; 212410015Speter splx(oldspl); 212510015Speter} 212610015Speter 212710015Speter/* 212810015Speter * Stop output on a line. called at spltty(); 212910015Speter */ 213010015Spetervoid 213110015Spetersistop(tp, rw) 213210015Speter register struct tty *tp; 213310015Speter int rw; 213410015Speter{ 213510015Speter volatile struct si_channel *ccbp; 213610015Speter struct si_port *pp; 213710015Speter 213810015Speter pp = TP2PP(tp); 213910015Speter ccbp = pp->sp_ccb; 214010015Speter 214110015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 214210015Speter 214310015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 214410015Speter if (rw & FWRITE) { 214510015Speter /* what level are we meant to be flushing anyway? */ 214610015Speter if (tp->t_state & TS_BUSY) { 214710015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 214810015Speter tp->t_state &= ~TS_BUSY; 214910015Speter ttwwakeup(tp); /* Bruce???? */ 215010015Speter } 215110015Speter } 215212174Speter#if 1 /* XXX: this doesn't work right yet.. */ 215312174Speter /* XXX: this may have been failing because we used to call l_rint() 215412174Speter * while we were looping based on these two counters. Now, we collect 215512174Speter * the data and then loop stuffing it into l_rint(), making this 215612174Speter * useless. Should we cause this to blow away the staging buffer? 215712174Speter */ 215810015Speter if (rw & FREAD) { 215910015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 216010015Speter } 216110015Speter#endif 216210015Speter} 216310015Speter 216410015Speter/* 216510015Speter * Issue a command to the Z280 host card CPU. 216610015Speter */ 216710015Speter 216810015Speterstatic void 216910015Spetersi_command(pp, cmd, waitflag) 217010015Speter struct si_port *pp; /* port control block (local) */ 217110015Speter int cmd; 217210015Speter int waitflag; 217310015Speter{ 217410015Speter int oldspl; 217510015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 217610015Speter int x; 217710015Speter 217810015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 217910015Speter pp, cmd, waitflag, ccbp->hi_stat)); 218010015Speter 218110015Speter oldspl = spltty(); /* Keep others out */ 218210015Speter 218310015Speter /* wait until it's finished what it was doing.. */ 218410015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 218510015Speter x != IDLE_CLOSE && 218610015Speter x != cmd) { 218710015Speter if (in_intr) { /* Prevent sleep in intr */ 218810015Speter DPRINT((pp, DBG_PARAM, 218910015Speter "cmd intr collision - completing %d\trequested %d\n", 219010015Speter x, cmd)); 219110015Speter splx(oldspl); 219210015Speter return; 219310015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 219410015Speter "sicmd1", 1)) { 219510015Speter splx(oldspl); 219610015Speter return; 219710015Speter } 219810015Speter } 219910015Speter /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 220010015Speter 220110015Speter /* if there was a pending command, cause a state-change wakeup */ 220210015Speter if (pp->sp_pend != IDLE_OPEN) { 220310015Speter switch(pp->sp_pend) { 220410015Speter case LOPEN: 220510015Speter case MPEND: 220610015Speter case MOPEN: 220710015Speter case CONFIG: 220810015Speter wakeup(&pp->sp_state); 220910015Speter break; 221010015Speter default: 221110015Speter break; 221210015Speter } 221310015Speter } 221410015Speter 221510015Speter pp->sp_pend = cmd; /* New command pending */ 221610015Speter ccbp->hi_stat = cmd; /* Post it */ 221710015Speter 221810015Speter if (waitflag) { 221910015Speter if (in_intr) { /* If in interrupt handler */ 222010015Speter DPRINT((pp, DBG_PARAM, 222110015Speter "attempt to sleep in si_intr - cmd req %d\n", 222210015Speter cmd)); 222310015Speter splx(oldspl); 222410015Speter return; 222510015Speter } else while(ccbp->hi_stat != IDLE_OPEN) { 222610015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 222710015Speter "sicmd2", 0)) 222810015Speter break; 222910015Speter } 223010015Speter } 223110015Speter splx(oldspl); 223210015Speter} 223310015Speter 223410015Speterstatic void 223510015Spetersi_disc_optim(tp, t, pp) 223610015Speter struct tty *tp; 223710015Speter struct termios *t; 223810015Speter struct si_port *pp; 223910015Speter{ 224010015Speter /* 224110015Speter * XXX can skip a lot more cases if Smarts. Maybe 224210015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 224310015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 224410015Speter */ 224510015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 224610015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 224710015Speter && (!(t->c_iflag & PARMRK) 224810015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 224910015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 225010015Speter && linesw[tp->t_line].l_rint == ttyinput) 225110015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 225210015Speter else 225310015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 225410161Speter 225510015Speter /* 225610015Speter * Prepare to reduce input latency for packet 225710015Speter * discplines with a end of packet character. 225810015Speter */ 225910015Speter if (tp->t_line == SLIPDISC) 226010015Speter pp->sp_hotchar = 0xc0; 226110015Speter else if (tp->t_line == PPPDISC) 226210015Speter pp->sp_hotchar = 0x7e; 226310015Speter else 226410015Speter pp->sp_hotchar = 0; 226510161Speter 226610161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 226710161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 226810161Speter pp->sp_hotchar)); 226910015Speter} 227010015Speter 227110015Speter 227210015Speter#ifdef SI_DEBUG 227310015Speterstatic void 227410015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6) 227510015Speter struct si_port *pp; 227610015Speter int flags; 227710015Speter char *str; 227810015Speter int a1, a2, a3, a4, a5, a6; 227910015Speter{ 228010015Speter if ((pp == NULL && (si_debug&flags)) || 228110015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 228210015Speter if (pp != NULL) 228312496Speter printf("%ci%d(%d): ", 's', 228412174Speter (int)SI_CARD(pp->sp_tty->t_dev), 228512174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 228610015Speter printf(str, a1, a2, a3, a4, a5, a6); 228710015Speter } 228810015Speter} 228910015Speter 229010015Speterstatic char * 229110015Spetersi_mctl2str(cmd) 229210015Speter enum si_mctl cmd; 229310015Speter{ 229410015Speter switch (cmd) { 229510015Speter case GET: return("GET"); 229610015Speter case SET: return("SET"); 229710015Speter case BIS: return("BIS"); 229810015Speter case BIC: return("BIC"); 229910015Speter } 230010015Speter return("BAD"); 230110015Speter} 230212502Sjulian 230312502Sjulian 230412502Sjulian#ifdef JREMOD 230512502Sjulianstruct cdevsw si_cdevsw = 230612502Sjulian { siopen, siclose, siread, siwrite, /*68*/ 230712502Sjulian siioctl, sistop, nxreset, sidevtotty,/* si */ 230812502Sjulian ttselect, nxmmap, NULL }; 230912502Sjulian 231012502Sjulianstatic si_devsw_installed = 0; 231112502Sjulian 231212502Sjulianstatic void si_devsw_install() 231312502Sjulian{ 231412502Sjulian dev_t descript; 231512502Sjulian if( ! si_devsw_installed ) { 231612502Sjulian descript = makedev(CDEV_MAJOR,0); 231712502Sjulian cdevsw_add(&descript,&si_cdevsw,NULL); 231812502Sjulian#if defined(BDEV_MAJOR) 231912502Sjulian descript = makedev(BDEV_MAJOR,0); 232012502Sjulian bdevsw_add(&descript,&si_bdevsw,NULL); 232112502Sjulian#endif /*BDEV_MAJOR*/ 232212502Sjulian si_devsw_installed = 1; 232312502Sjulian } 232412502Sjulian} 232512502Sjulian#endif /* JREMOD */ 232610015Speter#endif 2327