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