si.c revision 11609
110015Speter/* 210015Speter * Device driver for Specialix range (SLXOS) 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 * 3311609Speter * $Id: si.c,v 1.9 1995/09/22 20:00:12 peter 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#define SI_DEBUG /* turn driver debugging on */ 4310015Speter 4410015Speter#include <sys/param.h> 4510015Speter#include <sys/systm.h> 4610015Speter#include <sys/ioctl.h> 4710015Speter#include <sys/tty.h> 4810015Speter#include <sys/ttydefaults.h> 4910015Speter#include <sys/proc.h> 5010015Speter#include <sys/user.h> 5110015Speter#include <sys/conf.h> 5210015Speter#include <sys/file.h> 5310015Speter#include <sys/uio.h> 5410015Speter#include <sys/dkstat.h> 5510015Speter#include <sys/kernel.h> 5610015Speter#include <sys/syslog.h> 5710015Speter#include <sys/device.h> 5810015Speter#include <sys/malloc.h> 5910015Speter#include <sys/devconf.h> 6010015Speter 6110015Speter#include <machine/clock.h> 6210015Speter 6310015Speter#include <i386/isa/icu.h> 6410015Speter#include <i386/isa/isa.h> 6510015Speter#include <i386/isa/isa_device.h> 6610015Speter 6710015Speter#include <i386/isa/sireg.h> 6810015Speter#include <machine/si.h> 6910015Speter 7010015Speter#include "si.h" 7110015Speter 7210015Speter/* 7310015Speter * This device driver is designed to interface the Specialix International 7410015Speter * range of serial multiplexor cards (SLXOS) to BSDI/386 on an ISA bus machine. 7510015Speter * 7610015Speter * The controller is interfaced to the host via dual port ram 7710015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 7810015Speter */ 7910015Speter 8010015Speter#define POLL /* turn on poller to generate buffer empty interrupt */ 8110047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8210015Speter#define SI_I_HIGH_WATER (TTYHOG - SLXOS_BUFFERSIZE) 8310015Speter 8410015Speterenum si_mctl { GET, SET, BIS, BIC }; 8510015Speter 8610015Speterstatic void si_command __P((struct si_port *, int, int)); 8710015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 8810015Speterstatic void si_write_enable __P((struct si_port *, int)); 8910015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9010015Speterstatic void si_start __P((struct tty *)); 9110015Speterstatic void si_lstart __P((struct si_port *)); 9210015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 9310015Speter struct si_port *pp)); 9410015Speterstatic void sihardclose __P((struct si_port *pp)); 9510015Speterstatic void sidtrwakeup __P((void *chan)); 9610015Speter 9710708Spetervoid sistop __P((struct tty *tp, int rw)); 9811609Spetervoid siintr __P((int unit)); 9910015Speterint siparam __P((struct tty *, struct termios *)); 10010015Speter 10110708Speterextern void si_registerdev __P((struct isa_device *id)); 10210708Speterextern int siprobe __P((struct isa_device *id)); 10310708Speterextern int siattach __P((struct isa_device *id)); 10410708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 10510708Speter 10610708Speter#ifdef SI_DEBUG 10710708Speterstatic void si_dprintf __P((/* XXX should be varargs struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */)); 10810708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 10910708Speter#define DPRINT(x) si_dprintf x 11010708Speter#else 11110708Speter#define DPRINT(x) /* void */ 11210708Speter#endif 11310708Speter 11410962Speterstatic int si_Nports; 11510962Speterstatic int si_Nmodules; 11610962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 11710015Speter 11810962Speterstatic struct tty *si_tty; 11910962Speter 12010015Speter/* where the firmware lives */ 12110015Speterextern int si_dsize; 12210015Speterextern unsigned char si_download[]; 12310015Speter 12410044Speterstruct si_softc { 12510044Speter int sc_type; /* adapter type */ 12610044Speter char *sc_typename; /* adapter type string */ 12710044Speter 12810044Speter struct si_port *sc_ports; /* port structures for this card */ 12910044Speter 13010044Speter caddr_t sc_paddr; /* physical addr of iomem */ 13110044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 13210044Speter int sc_nport; /* # ports on this card */ 13310044Speter int sc_irq; /* copy of attach irq */ 13410044Speter int sc_eisa_iobase; /* EISA io port address */ 13510044Speter int sc_eisa_irqbits; 13610044Speter struct kern_devconf sc_kdc; 13710044Speter}; 13810044Speterstruct si_softc si_softc[NSI]; /* up to 4 elements */ 13910044Speter 14010015Speter#ifndef B2000 /* not standard */ 14110015Speter# define B2000 2000 14210015Speter#endif 14310015Speterstatic struct speedtab bdrates[] = { 14410015Speter B75, CLK75, /* 0x0 */ 14510015Speter B110, CLK110, /* 0x1 */ 14610015Speter B150, CLK150, /* 0x3 */ 14710015Speter B300, CLK300, /* 0x4 */ 14810015Speter B600, CLK600, /* 0x5 */ 14910015Speter B1200, CLK1200, /* 0x6 */ 15010015Speter B2000, CLK2000, /* 0x7 */ 15110015Speter B2400, CLK2400, /* 0x8 */ 15210015Speter B4800, CLK4800, /* 0x9 */ 15310015Speter B9600, CLK9600, /* 0xb */ 15410015Speter B19200, CLK19200, /* 0xc */ 15510015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 15610015Speter B57600, CLK57600, /* 0xd */ 15710015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 15810015Speter -1, -1 15910015Speter}; 16010015Speter 16110015Speter 16210015Speter/* populated with approx character/sec rates - translated at card 16310015Speter * initialisation time to chars per tick of the clock */ 16410015Speterstatic int done_chartimes = 0; 16510015Speterstatic struct speedtab chartimes[] = { 16610015Speter B75, 8, 16710015Speter B110, 11, 16810015Speter B150, 15, 16910015Speter B300, 30, 17010015Speter B600, 60, 17110015Speter B1200, 120, 17210015Speter B2000, 200, 17310015Speter B2400, 240, 17410015Speter B4800, 480, 17510015Speter B9600, 960, 17610015Speter B19200, 1920, 17710015Speter B38400, 3840, 17810015Speter B57600, 5760, 17910015Speter B115200, 11520, 18010015Speter -1, -1 18110015Speter}; 18210015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 18310015Speter 18410047Speterstatic int si_default_rate = TTYDEF_SPEED; 18510047Speterstatic int si_default_iflag = 0; 18610047Speterstatic int si_default_oflag = 0; 18710047Speterstatic int si_default_lflag = 0; 18810047Speter#ifdef SI_DEF_HWFLOW 18910047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 19010047Speter#else 19110047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 19210047Speter#endif 19310047Speter 19410015Speter#ifdef POLL 19510015Speter#define POLL_INTERVAL (hz/2) 19610015Speterstatic int init_finished = 0; 19710015Speterstatic void si_poll __P((void *)); 19810015Speter#endif 19910015Speter 20010015Speter/* 20110015Speter * Array of adapter types and the corresponding RAM size. The order of 20210015Speter * entries here MUST match the ordinal of the adapter type. 20310015Speter */ 20410015Speterstatic char *si_type[] = { 20510015Speter "EMPTY", 20610015Speter "SIHOST", 20710015Speter "SI2", /* MCA */ 20810015Speter "SIHOST2", 20910015Speter "SIEISA", 21010015Speter}; 21110015Speter 21210015Speter 21310015Speterstatic struct kern_devconf si_kdc[NSI] = { { 21410015Speter 0, 0, 0, /* filled in by dev_attach */ 21510015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 21610015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 21710015Speter &kdc_isa0, /* parent */ 21810015Speter 0, /* parent data */ 21910015Speter DC_UNCONFIGURED, /* state */ 22010015Speter "Specialix SI/XIO Host adapter", 22110015Speter DC_CLS_SERIAL, /* class */ 22210015Speter} }; 22310015Speter 22410015Spetervoid 22510015Spetersi_registerdev(id) 22610015Speter struct isa_device *id; 22710015Speter{ 22810015Speter if (id->id_unit != 0) { 22910015Speter si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 23010015Speter } 23110015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 23210015Speter si_kdc[id->id_unit].kdc_isa = id; 23310015Speter dev_attach(&si_kdc[id->id_unit]); 23410015Speter} 23510015Speter 23610015Speter/* Look for a valid board at the given mem addr */ 23710015Speterint 23810015Spetersiprobe(id) 23910015Speter struct isa_device *id; 24010015Speter{ 24110015Speter struct si_softc *sc; 24210015Speter int type; 24310015Speter u_int i, ramsize; 24410015Speter volatile BYTE was, *ux; 24510015Speter volatile unsigned char *maddr; 24610015Speter unsigned char *paddr; 24710015Speter 24810015Speter si_registerdev(id); 24910015Speter 25010015Speter maddr = id->id_maddr; /* virtual address... */ 25110015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 25210015Speter 25310015Speter DPRINT((0, DBG_AUTOBOOT, "SLXOS probe at virtual=0x%x physical=0x%x\n", 25410015Speter id->id_maddr, paddr)); 25510015Speter 25610015Speter /* 25710015Speter * this is a lie, but it's easier than trying to handle caching 25810015Speter * and ram conflicts in the >1M and <16M region. 25910015Speter */ 26010015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 26110015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 26210015Speter printf("si%d: iomem (%x) out of range\n", 26310015Speter id->id_unit, paddr); 26410015Speter return(0); 26510015Speter } 26610015Speter 26710015Speter if (id->id_unit >= NSI) { 26810015Speter /* THIS IS IMPOSSIBLE */ 26910015Speter return(0); 27010015Speter } 27110015Speter 27210015Speter if (((u_int)paddr & 0x7fff) != 0) { 27310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 27410015Speter "si%d: iomem (%x) not on 32k boundary\n", 27510015Speter id->id_unit, paddr)); 27610015Speter return(0); 27710015Speter } 27810015Speter 27910015Speter 28010015Speter for (i=0; i < NSI; i++) { 28110015Speter if ((sc = &si_softc[i]) == NULL) 28210015Speter continue; 28310015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 28410015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 28510015Speter "si%d: iomem (%x) already configured to si%d\n", 28610015Speter id->id_unit, sc->sc_paddr, i)); 28710015Speter return(0); 28810015Speter } 28910015Speter } 29010015Speter 29110015Speter#if NEISA > 0 29210015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 29310015Speter int irq, port; 29410015Speter unsigned long base; 29510015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 29610015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 29710015Speter 29810015Speter port = id->id_iobase; 29910015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 30010015Speter irq = ((inb(port+2) >> 4) & 0xf); 30110015Speter 30210015Speter id->id_irq = eisa_irqs[irq]; 30310015Speter 30410015Speter DPRINT((0, DBG_AUTOBOOT, 30510015Speter "SLXOS: si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 30610015Speter id->id_unit, base, irq, id->id_irq, port)); 30710015Speter 30810015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 30910015Speter goto bad_irq; 31010015Speter 31110015Speter id->id_iobase &= 0xf000; 31210015Speter id->id_iosize = 0x0fff; 31310015Speter 31410015Speter type = EISA; 31510015Speter outb(p+2, (BYTE)irq << 4); 31610015Speter 31710015Speter sc->sc_eisa_iobase = p; 31810015Speter sc->sc_eisa_irqbits = irq << 4; 31910015Speter ramsize = SIEISA_RAMSIZE; 32010015Speter goto got_card; 32110015Speter } 32210015Speter#endif 32310015Speter 32410015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 32510015Speter *maddr = 0x17; 32610015Speter if (*maddr != 0x17) { 32710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 32810015Speter "si%d: 0x17 check fail at phys 0x%x\n", 32910015Speter id->id_unit, paddr)); 33010015Speterfail: 33110015Speter return(0); 33210015Speter } 33310015Speter /* 33410015Speter * OK, now to see if whatever responded is really an SI card. 33510015Speter * Try for a MK II first (SIHOST2) 33610015Speter */ 33710015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 33810015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 33910015Speter goto try_mk1; 34010015Speter 34110015Speter /* It must be an SIHOST2 */ 34210015Speter *(maddr + SIPLRESET) = 0; 34310015Speter *(maddr + SIPLIRQCLR) = 0; 34410015Speter *(maddr + SIPLIRQSET) = 0x10; 34510015Speter type = SIHOST2; 34610015Speter ramsize = SIHOST2_RAMSIZE; 34710015Speter goto got_card; 34810015Speter 34910015Speter /* 35010015Speter * Its not a MK II, so try for a MK I (SIHOST) 35110015Speter */ 35210015Spetertry_mk1: 35310015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 35410015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 35510015Speter *(maddr+SIRAM) = 0x17; 35610015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 35710015Speter goto fail; 35810015Speter *(maddr+0x7ff8) = 0x17; 35910015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 36010015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 36110015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 36210015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 36310015Speter goto fail; 36410015Speter } 36510015Speter 36610015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 36710015Speter type = SIHOST; 36810015Speter ramsize = SIHOST_RAMSIZE; 36910015Speter 37010015Spetergot_card: 37110015Speter DPRINT((0, DBG_AUTOBOOT, "SLXOS: found type %d card, try memory test\n", type)); 37210015Speter /* Try the acid test */ 37310015Speter ux = (BYTE *)(maddr + SIRAM); 37410015Speter for (i=0; i<ramsize; i++, ux++) 37510015Speter *ux = (BYTE)(i&0xff); 37610015Speter ux = (BYTE *)(maddr + SIRAM); 37710015Speter for (i=0; i<ramsize; i++, ux++) { 37810015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 37910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 38010015Speter "SLXOS si%d: match fail at phys 0x%x, was %x should be %x\n", 38110015Speter id->id_unit, paddr+i, was, i&0xff)); 38210015Speter goto fail; 38310015Speter } 38410015Speter } 38510015Speter 38610015Speter /* clear out the RAM */ 38710015Speter ux = (BYTE *)(maddr + SIRAM); 38810015Speter for (i=0; i<ramsize; i++) 38910015Speter *ux++ = 0; 39010015Speter ux = (BYTE *)(maddr + SIRAM); 39110015Speter for (i=0; i<ramsize; i++) { 39210015Speter if ((was = *ux++) != 0) { 39310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 39410015Speter "SLXOS si%d: clear fail at phys 0x%x, was %x\n", 39510015Speter id->id_unit, paddr+i, was)); 39610015Speter goto fail; 39710015Speter } 39810015Speter } 39910015Speter 40010015Speter /* 40110015Speter * Success, we've found a valid board, now fill in 40210015Speter * the adapter structure. 40310015Speter */ 40410015Speter switch (type) { 40510015Speter case SIHOST2: 40610015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 40710015Speterbad_irq: 40810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 40910015Speter "si%d: bad IRQ value - %d\n", 41010015Speter id->id_unit, id->id_irq)); 41110015Speter return(0); 41210015Speter } 41310015Speter id->id_msize = SIHOST2_MEMSIZE; 41410015Speter break; 41510015Speter case SIHOST: 41610015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 41710015Speter goto bad_irq; 41810015Speter } 41910015Speter id->id_msize = SIHOST_MEMSIZE; 42010015Speter break; 42110015Speter case SIEISA: 42210015Speter id->id_msize = SIEISA_MEMSIZE; 42310015Speter break; 42410015Speter case SI2: /* MCA */ 42510015Speter default: 42610015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 42710015Speter return(0); 42810015Speter } 42910015Speter si_softc[id->id_unit].sc_type = type; 43010015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 43110015Speter return(-1); /* -1 == found */ 43210015Speter} 43310015Speter 43410015Speter/* 43510015Speter * Attach the device. Initialize the card. 43610015Speter */ 43710015Speterint 43810015Spetersiattach(id) 43910015Speter struct isa_device *id; 44010015Speter{ 44110015Speter int unit = id->id_unit; 44210015Speter struct si_softc *sc = &si_softc[unit]; 44310015Speter struct si_port *pp; 44410015Speter volatile struct si_channel *ccbp; 44510015Speter volatile struct si_reg *regp; 44610015Speter volatile caddr_t maddr; 44710015Speter struct si_module *modp; 44810015Speter struct tty *tp; 44910015Speter struct speedtab *spt; 45010015Speter int nmodule, nport, x, y; 45110015Speter 45210015Speter DPRINT((0, DBG_AUTOBOOT, "SLXOS siattach\n")); 45310015Speter 45410015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 45510015Speter sc->sc_maddr = id->id_maddr; 45610015Speter sc->sc_irq = id->id_irq; 45710015Speter 45810015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 45910015Speter 46010015Speter maddr = sc->sc_maddr; 46110015Speter 46210015Speter /* 46310015Speter * OK, now lets download the firmware and try and boot the CPU.. 46410015Speter */ 46510015Speter 46610015Speter DPRINT((0, DBG_DOWNLOAD, "SLXOS si_download: nbytes %d\n", si_dsize)); 46710015Speter bcopy(si_download, maddr, si_dsize); 46810015Speter 46910015Speter switch (sc->sc_type) { 47010015Speter case SIEISA: 47110015Speter#if NEISA > 0 47210015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 47310015Speter *(maddr+0x42) = 1; 47410015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 47510015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 47610015Speter break; 47710015Speter#endif /* fall-through if not EISA */ 47810015Speter case SI2: 47910015Speter /* must get around to writing the code for 48010015Speter * these one day */ 48110015Speter return 0; 48210015Speter case SIHOST: 48310015Speter *(maddr+SIRESET_CL) = 0; 48410015Speter *(maddr+SIINTCL_CL) = 0; 48510015Speter break; 48610015Speter case SIHOST2: 48710015Speter *(maddr+SIPLRESET) = 0x10; 48810015Speter switch (sc->sc_irq) { 48910015Speter case IRQ11: 49010015Speter *(maddr+SIPLIRQ11) = 0x10; 49110015Speter break; 49210015Speter case IRQ12: 49310015Speter *(maddr+SIPLIRQ12) = 0x10; 49410015Speter break; 49510015Speter case IRQ15: 49610015Speter *(maddr+SIPLIRQ15) = 0x10; 49710015Speter break; 49810015Speter } 49910015Speter *(maddr+SIPLIRQCLR) = 0x10; 50010015Speter break; 50110015Speter } 50210015Speter 50310015Speter DELAY(1000000); /* wait around for a second */ 50410015Speter 50510015Speter regp = (struct si_reg *)maddr; 50610015Speter y = 0; 50710015Speter /* wait max of 5 sec for init OK */ 50810015Speter while (regp->initstat == 0 && y++ < 10) { 50910015Speter DELAY(500000); 51010015Speter } 51110015Speter switch (regp->initstat) { 51210015Speter case 0: 51310015Speter printf("si%d: startup timeout - aborting\n", unit); 51410015Speter sc->sc_type = NULL; 51510015Speter return 0; 51610015Speter case 1: 51710015Speter /* set throttle to 100 intr per second */ 51810015Speter regp->int_count = 25000; 51910015Speter /* rx intr max of 25 timer per second */ 52010015Speter regp->rx_int_count = 4; 52110015Speter regp->int_pending = 0; /* no intr pending */ 52210015Speter regp->int_scounter = 0; /* reset counter */ 52310015Speter break; 52410015Speter case 0xff: 52510015Speter /* 52610015Speter * No modules found, so give up on this one. 52710015Speter */ 52810015Speter printf("si%d: %s - no ports found\n", unit, 52910015Speter si_type[sc->sc_type]); 53010015Speter return 0; 53110015Speter default: 53210015Speter printf("si%d: Z280 version error - initstat %x\n", 53310015Speter unit, regp->initstat); 53410015Speter return 0; 53510015Speter } 53610015Speter 53710015Speter /* 53810015Speter * First time around the ports just count them in order 53910015Speter * to allocate some memory. 54010015Speter */ 54110015Speter nport = 0; 54210015Speter modp = (struct si_module *)(maddr + 0x80); 54310015Speter for (;;) { 54410015Speter DPRINT((0, DBG_DOWNLOAD, "SLXOS si%d: ccb addr 0x%x\n", unit, modp)); 54510015Speter switch (modp->sm_type & (~MMASK)) { 54610015Speter case M232: 54710015Speter case M422: 54810015Speter DPRINT((0, DBG_DOWNLOAD, 54910015Speter "SLXOS si%d: Found 232/422 module, %d ports\n", 55010015Speter unit, (int)(modp->sm_type & MMASK))); 55110015Speter 55210015Speter /* this is a firmware issue */ 55310015Speter if (si_Nports == SI_MAXPORTPERCARD) { 55410015Speter printf("si%d: extra ports ignored\n", unit); 55510015Speter continue; 55610015Speter } 55710015Speter 55810015Speter x = modp->sm_type & MMASK; 55910015Speter nport += x; 56010015Speter si_Nports += x; 56110015Speter si_Nmodules++; 56210015Speter break; 56310015Speter default: 56410015Speter printf("si%d: unknown module type %d\n", 56510015Speter unit, modp->sm_type); 56610015Speter break; 56710015Speter } 56810015Speter if (modp->sm_next == 0) 56910015Speter break; 57010015Speter modp = (struct si_module *) 57110015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 57210015Speter } 57310015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 57410015Speter M_DEVBUF, M_NOWAIT); 57510015Speter if (sc->sc_ports == 0) { 57610015Spetermem_fail: 57710015Speter printf("si%d: fail to malloc memory for port structs\n", 57810015Speter unit); 57910015Speter return 0; 58010015Speter } 58110015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 58210015Speter sc->sc_nport = nport; 58310015Speter 58410015Speter /* 58510015Speter * allocate tty structures for ports 58610015Speter */ 58710015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 58810015Speter if (tp == 0) 58910015Speter goto mem_fail; 59010015Speter bzero(tp, sizeof(*tp) * nport); 59110962Speter si_tty = tp; 59210015Speter 59310015Speter /* mark the device state as attached */ 59410015Speter si_kdc[unit].kdc_state = DC_BUSY; 59510015Speter 59610015Speter /* 59710015Speter * Scan round the ports again, this time initialising. 59810015Speter */ 59910015Speter pp = sc->sc_ports; 60010015Speter nmodule = 0; 60110015Speter modp = (struct si_module *)(maddr + 0x80); 60210015Speter for (;;) { 60310015Speter switch (modp->sm_type & (~MMASK)) { 60410015Speter case M232: 60510015Speter case M422: 60610015Speter nmodule++; 60710015Speter nport = (modp->sm_type & MMASK); 60810015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 60910015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 61010015Speter pp->sp_ccb = ccbp; /* save the address */ 61110015Speter pp->sp_tty = tp++; 61210015Speter pp->sp_pend = IDLE_CLOSE; 61310044Speter pp->sp_flags = 0; 61410015Speter pp->sp_state = 0; /* internal flag */ 61510015Speter pp->sp_dtr_wait = 3 * hz; 61610047Speter pp->sp_iin.c_iflag = si_default_iflag; 61710047Speter pp->sp_iin.c_oflag = si_default_oflag; 61810047Speter pp->sp_iin.c_cflag = si_default_cflag; 61910047Speter pp->sp_iin.c_lflag = si_default_lflag; 62010015Speter termioschars(&pp->sp_iin); 62110015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 62210047Speter si_default_rate; 62310015Speter pp->sp_iout = pp->sp_iin; 62410015Speter } 62510015Speter break; 62610015Speter default: 62710015Speter break; 62810015Speter } 62910015Speter if (modp->sm_next == 0) { 63010962Speter printf("si%d: card: %s, ports: %d, modules: %d\n", 63110015Speter unit, 63210015Speter sc->sc_typename, 63310015Speter sc->sc_nport, 63410015Speter nmodule); 63510015Speter break; 63610015Speter } 63710015Speter modp = (struct si_module *) 63810015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 63910015Speter } 64010015Speter if (done_chartimes == 0) { 64110015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 64210015Speter if ((spt->sp_code /= hz) == 0) 64310015Speter spt->sp_code = 1; 64410015Speter } 64510015Speter done_chartimes = 1; 64610015Speter } 64710015Speter return (1); 64810015Speter} 64910015Speter 65010015Speterstruct isa_driver sidriver = 65110015Speter { siprobe, siattach, "si" }; 65210015Speter 65310015Speter 65410015Speterint 65510015Spetersiopen(dev, flag, mode, p) 65610015Speter dev_t dev; 65710015Speter int flag, mode; 65810015Speter struct proc *p; 65910015Speter{ 66010015Speter int oldspl, error; 66110015Speter int card, port; 66210015Speter register struct si_softc *sc; 66310015Speter register struct tty *tp; 66410015Speter volatile struct si_channel *ccbp; 66510015Speter struct si_port *pp; 66610015Speter int mynor = minor(dev); 66710015Speter 66810015Speter /* quickly let in /dev/si_control */ 66910015Speter if (IS_CONTROLDEV(mynor)) { 67010015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 67110015Speter return(error); 67210015Speter return(0); 67310015Speter } 67410015Speter 67510015Speter card = SI_CARD(mynor); 67610015Speter if (card >= NSI) 67710015Speter return (ENXIO); 67810015Speter sc = &si_softc[card]; 67910015Speter 68010015Speter if (sc->sc_type == NULL) { 68110015Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: type %s??\n", 68210015Speter card, sc->sc_typename)); 68310015Speter return(ENXIO); 68410015Speter } 68510015Speter 68610015Speter port = SI_PORT(mynor); 68710015Speter if (port >= sc->sc_nport) { 68810015Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: nports %d\n", 68910015Speter card, sc->sc_nport)); 69010015Speter return(ENXIO); 69110015Speter } 69210015Speter 69310015Speter#ifdef POLL 69410015Speter /* 69510015Speter * We've now got a device, so start the poller. 69610015Speter */ 69710015Speter if (init_finished == 0) { 69810015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 69910015Speter init_finished = 1; 70010015Speter } 70110015Speter#endif 70210015Speter 70310015Speter /* initial/lock device */ 70410015Speter if (IS_STATE(mynor)) { 70510015Speter return(0); 70610015Speter } 70710015Speter 70810015Speter pp = sc->sc_ports + port; 70910015Speter tp = pp->sp_tty; /* the "real" tty */ 71010015Speter ccbp = pp->sp_ccb; /* Find control block */ 71110015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 71210015Speter dev, flag, mode, p)); 71310015Speter 71410015Speter oldspl = spltty(); /* Keep others out */ 71510015Speter error = 0; 71610015Speter 71710015Speteropen_top: 71810015Speter while (pp->sp_state & SS_DTR_OFF) { 71910015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 72010015Speter if (error != 0) 72110015Speter goto out; 72210015Speter } 72310015Speter 72410015Speter if (tp->t_state & TS_ISOPEN) { 72510015Speter /* 72610015Speter * The device is open, so everything has been initialised. 72710015Speter * handle conflicts. 72810015Speter */ 72910015Speter if (IS_CALLOUT(mynor)) { 73010015Speter if (!pp->sp_active_out) { 73110015Speter error = EBUSY; 73210015Speter goto out; 73310015Speter } 73410015Speter } else { 73510015Speter if (pp->sp_active_out) { 73610015Speter if (flag & O_NONBLOCK) { 73710015Speter error = EBUSY; 73810015Speter goto out; 73910015Speter } 74010015Speter error = tsleep(&pp->sp_active_out, 74110015Speter TTIPRI|PCATCH, "sibi", 0); 74210015Speter if (error != 0) 74310015Speter goto out; 74410015Speter goto open_top; 74510015Speter } 74610015Speter } 74710015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 74810015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 74910015Speter "already open and EXCLUSIVE set\n")); 75010015Speter error = EBUSY; 75110015Speter goto out; 75210015Speter } 75310015Speter } else { 75410015Speter /* 75510015Speter * The device isn't open, so there are no conflicts. 75610015Speter * Initialize it. Avoid sleep... :-) 75710015Speter */ 75810015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 75910015Speter tp->t_oproc = si_start; 76010015Speter tp->t_param = siparam; 76110015Speter tp->t_dev = dev; 76210015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 76310015Speter ? pp->sp_iout : pp->sp_iin; 76410015Speter 76510015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 76610015Speter 76710015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 76810015Speter 76910015Speter error = siparam(tp, &tp->t_termios); 77010015Speter 77110015Speter --pp->sp_wopeners; 77210015Speter if (error != 0) 77310015Speter goto out; 77410015Speter /* XXX: we should goto_top if siparam slept */ 77510015Speter 77610015Speter ttsetwater(tp); 77710015Speter 77810015Speter /* set initial DCD state */ 77910015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 78010015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 78110015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 78210015Speter } 78310015Speter } 78410015Speter 78510015Speter /* whoops! we beat the close! */ 78610015Speter if (pp->sp_state & SS_CLOSING) { 78710015Speter /* try and stop it from proceeding to bash the hardware */ 78810015Speter pp->sp_state &= ~SS_CLOSING; 78910015Speter } 79010015Speter 79110015Speter /* 79210015Speter * Wait for DCD if necessary 79310015Speter */ 79410015Speter if (!(tp->t_state & TS_CARR_ON) 79510015Speter && !IS_CALLOUT(mynor) 79610015Speter && !(tp->t_cflag & CLOCAL) 79710015Speter && !(flag & O_NONBLOCK)) { 79810015Speter ++pp->sp_wopeners; 79910015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 80010015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 80110015Speter --pp->sp_wopeners; 80210015Speter if (error != 0) 80310015Speter goto out; 80410015Speter goto open_top; 80510015Speter } 80610015Speter 80710015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 80810015Speter si_disc_optim(tp, &tp->t_termios, pp); 80910015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 81010015Speter pp->sp_active_out = TRUE; 81110015Speter 81210015Speter pp->sp_state |= SS_OPEN; /* made it! */ 81310015Speter 81410015Speterout: 81510015Speter splx(oldspl); 81610015Speter 81710015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 81810015Speter 81910015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 82010015Speter sihardclose(pp); 82110015Speter 82210015Speter return(error); 82310015Speter} 82410015Speter 82510015Speterint 82610015Spetersiclose(dev, flag, mode, p) 82710015Speter dev_t dev; 82810015Speter int flag, mode; 82910015Speter struct proc *p; 83010015Speter{ 83110015Speter register struct si_port *pp; 83210015Speter register struct tty *tp; 83310015Speter int oldspl; 83410015Speter int error = 0; 83510015Speter int mynor = minor(dev); 83610015Speter 83710015Speter if (IS_SPECIAL(mynor)) 83810015Speter return(0); 83910015Speter 84010015Speter oldspl = spltty(); 84110015Speter 84210015Speter pp = MINOR2PP(mynor); 84310015Speter tp = pp->sp_tty; 84410015Speter 84510015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 84610015Speter dev, flag, mode, p, pp->sp_state)); 84710015Speter 84810015Speter /* did we sleep and loose a race? */ 84910015Speter if (pp->sp_state & SS_CLOSING) { 85010015Speter /* error = ESOMETING? */ 85110015Speter goto out; 85210015Speter } 85310015Speter 85410015Speter /* begin race detection.. */ 85510015Speter pp->sp_state |= SS_CLOSING; 85610015Speter 85710015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 85810015Speter 85910015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 86010015Speter (*linesw[tp->t_line].l_close)(tp, flag); 86110015Speter 86210015Speter si_write_enable(pp, 1); 86310015Speter 86410015Speter /* did we sleep and somebody started another open? */ 86510015Speter if (!(pp->sp_state & SS_CLOSING)) { 86610015Speter /* error = ESOMETING? */ 86710015Speter goto out; 86810015Speter } 86910015Speter /* ok. we are now still on the right track.. nuke the hardware */ 87010015Speter 87110015Speter if (pp->sp_state & SS_LSTART) { 87210015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 87310015Speter pp->sp_state &= ~SS_LSTART; 87410015Speter } 87510015Speter 87610015Speter sistop(tp, FREAD | FWRITE); 87710015Speter 87810015Speter sihardclose(pp); 87910015Speter ttyclose(tp); 88010015Speter pp->sp_state &= ~SS_OPEN; 88110015Speter 88210015Speterout: 88310015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 88410015Speter splx(oldspl); 88510015Speter return(error); 88610015Speter} 88710015Speter 88810015Speterstatic void 88910015Spetersihardclose(pp) 89010015Speter struct si_port *pp; 89110015Speter{ 89210015Speter int oldspl; 89310015Speter struct tty *tp; 89410015Speter volatile struct si_channel *ccbp; 89510015Speter 89610015Speter oldspl = spltty(); 89710015Speter 89810015Speter tp = pp->sp_tty; 89910015Speter ccbp = pp->sp_ccb; /* Find control block */ 90010015Speter if (tp->t_cflag & HUPCL 90110015Speter || !pp->sp_active_out 90210015Speter && !(ccbp->hi_ip & IP_DCD) 90310015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 90410015Speter || !(tp->t_state & TS_ISOPEN)) { 90510015Speter 90610015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 90710015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 90810015Speter 90910015Speter if (pp->sp_dtr_wait != 0) { 91010015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 91110015Speter pp->sp_state |= SS_DTR_OFF; 91210015Speter } 91310015Speter 91410015Speter } 91510015Speter pp->sp_active_out = FALSE; 91610015Speter wakeup((caddr_t)&pp->sp_active_out); 91710015Speter wakeup(TSA_CARR_ON(tp)); 91810015Speter 91910015Speter splx(oldspl); 92010015Speter} 92110015Speter 92210015Speter 92310015Speter/* 92410015Speter * called at splsoftclock()... 92510015Speter */ 92610015Speterstatic void 92710015Spetersidtrwakeup(chan) 92810015Speter void *chan; 92910015Speter{ 93010015Speter struct si_port *pp; 93110015Speter int oldspl; 93210015Speter 93310015Speter oldspl = spltty(); 93410015Speter 93510015Speter pp = (struct si_port *)chan; 93610015Speter pp->sp_state &= ~SS_DTR_OFF; 93710015Speter wakeup(&pp->sp_dtr_wait); 93810015Speter 93910015Speter splx(oldspl); 94010015Speter} 94110015Speter 94210015Speter/* 94310015Speter * User level stuff - read and write 94410015Speter */ 94510015Speterint 94610015Spetersiread(dev, uio, flag) 94710015Speter register dev_t dev; 94810015Speter struct uio *uio; 94910015Speter int flag; 95010015Speter{ 95110015Speter register struct tty *tp; 95210015Speter int mynor = minor(dev); 95310015Speter 95410015Speter if (IS_SPECIAL(mynor)) { 95510015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 95610015Speter return(ENODEV); 95710015Speter } 95810015Speter tp = MINOR2TP(mynor); 95910015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 96010015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 96110015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 96210015Speter} 96310015Speter 96410015Speter 96510015Speterint 96610015Spetersiwrite(dev, uio, flag) 96710015Speter dev_t dev; 96810015Speter struct uio *uio; 96910015Speter int flag; 97010015Speter{ 97110015Speter register struct si_port *pp; 97210015Speter register struct tty *tp; 97310015Speter int error = 0; 97410015Speter int mynor = minor(dev); 97510015Speter int oldspl; 97610015Speter 97710015Speter if (IS_SPECIAL(mynor)) { 97810015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 97910015Speter return(ENODEV); 98010015Speter } 98110015Speter pp = MINOR2PP(mynor); 98210015Speter tp = pp->sp_tty; 98310015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 98410015Speter 98510015Speter oldspl = spltty(); 98610015Speter /* 98710015Speter * If writes are currently blocked, wait on the "real" tty 98810015Speter */ 98910015Speter while (pp->sp_state & SS_BLOCKWRITE) { 99010015Speter pp->sp_state |= SS_WAITWRITE; 99110015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 99210015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 99310015Speter "siwrite", 0)) 99410015Speter goto out; 99510015Speter } 99610015Speter 99710015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 99810015Speterout: 99910015Speter splx(oldspl); 100010015Speter return (error); 100110015Speter} 100210015Speter 100310015Speter 100410015Speterstruct tty * 100510015Spetersidevtotty(dev_t dev) 100610015Speter{ 100710015Speter struct si_port *pp; 100810015Speter int mynor = minor(dev); 100910015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 101010015Speter 101110015Speter if (IS_SPECIAL(mynor)) 101210015Speter return(NULL); 101310015Speter if (SI_PORT(mynor) >= sc->sc_nport) 101410015Speter return(NULL); 101510015Speter pp = MINOR2PP(mynor); 101610015Speter return (pp->sp_tty); 101710015Speter} 101810015Speter 101910015Speterint 102010015Spetersiioctl(dev, cmd, data, flag, p) 102110015Speter dev_t dev; 102210015Speter int cmd; 102310015Speter caddr_t data; 102410015Speter int flag; 102510015Speter struct proc *p; 102610015Speter{ 102710015Speter struct si_port *pp; 102810015Speter register struct tty *tp; 102910015Speter int error; 103010015Speter int mynor = minor(dev); 103110015Speter int oldspl; 103210015Speter int blocked = 0; 103310015Speter#if defined(COMPAT_43) 103410015Speter int oldcmd; 103510015Speter struct termios term; 103610015Speter#endif 103710015Speter 103810015Speter if (IS_SI_IOCTL(cmd)) 103910015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 104010015Speter 104110015Speter pp = MINOR2PP(mynor); 104210015Speter tp = pp->sp_tty; 104310015Speter 104410015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 104510015Speter dev, cmd, data, flag)); 104610015Speter if (IS_STATE(mynor)) { 104710015Speter struct termios *ct; 104810015Speter 104910015Speter switch (mynor & SI_STATE_MASK) { 105010015Speter case SI_INIT_STATE_MASK: 105110015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 105210015Speter break; 105310015Speter case SI_LOCK_STATE_MASK: 105410015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 105510015Speter break; 105610015Speter default: 105710015Speter return (ENODEV); 105810015Speter } 105910015Speter switch (cmd) { 106010015Speter case TIOCSETA: 106110015Speter error = suser(p->p_ucred, &p->p_acflag); 106210015Speter if (error != 0) 106310015Speter return (error); 106410015Speter *ct = *(struct termios *)data; 106510015Speter return (0); 106610015Speter case TIOCGETA: 106710015Speter *(struct termios *)data = *ct; 106810015Speter return (0); 106910015Speter case TIOCGETD: 107010015Speter *(int *)data = TTYDISC; 107110015Speter return (0); 107210015Speter case TIOCGWINSZ: 107310015Speter bzero(data, sizeof(struct winsize)); 107410015Speter return (0); 107510015Speter default: 107610015Speter return (ENOTTY); 107710015Speter } 107810015Speter } 107910015Speter /* 108010015Speter * Do the old-style ioctl compat routines... 108110015Speter */ 108210015Speter#if defined(COMPAT_43) 108310015Speter term = tp->t_termios; 108410015Speter oldcmd = cmd; 108510015Speter error = ttsetcompat(tp, &cmd, data, &term); 108610015Speter if (error != 0) 108710015Speter return (error); 108810015Speter if (cmd != oldcmd) 108910015Speter data = (caddr_t)&term; 109010015Speter#endif 109110015Speter /* 109210015Speter * Do the initial / lock state business 109310015Speter */ 109410015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 109510015Speter int cc; 109610015Speter struct termios *dt = (struct termios *)data; 109710015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 109810015Speter ? &pp->sp_lout : &pp->sp_lin; 109910015Speter 110010015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 110110015Speter | (dt->c_iflag & ~lt->c_iflag); 110210015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 110310015Speter | (dt->c_oflag & ~lt->c_oflag); 110410015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 110510015Speter | (dt->c_cflag & ~lt->c_cflag); 110610015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 110710015Speter | (dt->c_lflag & ~lt->c_lflag); 110810015Speter for (cc = 0; cc < NCCS; ++cc) 110910015Speter if (lt->c_cc[cc] != 0) 111010015Speter dt->c_cc[cc] = tp->t_cc[cc]; 111110015Speter if (lt->c_ispeed != 0) 111210015Speter dt->c_ispeed = tp->t_ispeed; 111310015Speter if (lt->c_ospeed != 0) 111410015Speter dt->c_ospeed = tp->t_ospeed; 111510015Speter } 111610015Speter 111710015Speter /* 111810015Speter * Block user-level writes to give the ttywait() 111910015Speter * a chance to completely drain for commands 112010015Speter * that require the port to be in a quiescent state. 112110015Speter */ 112210015Speter switch (cmd) { 112310015Speter case TIOCSETAW: case TIOCSETAF: 112410015Speter case TIOCDRAIN: case TIOCSETP: 112510015Speter blocked++; /* block writes for ttywait() and siparam() */ 112610015Speter si_write_enable(pp, 0); 112710015Speter } 112810015Speter 112910015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 113010015Speter if (error >= 0) 113110015Speter goto out; 113210015Speter 113310015Speter oldspl = spltty(); 113410015Speter 113510015Speter error = ttioctl(tp, cmd, data, flag); 113610015Speter si_disc_optim(tp, &tp->t_termios, pp); 113710015Speter if (error >= 0) 113810015Speter goto outspl; 113910015Speter 114010015Speter switch (cmd) { 114110015Speter case TIOCSBRK: 114210015Speter si_command(pp, SBREAK, SI_NOWAIT); 114310015Speter break; 114410015Speter case TIOCCBRK: 114510015Speter si_command(pp, EBREAK, SI_NOWAIT); 114610015Speter break; 114710015Speter case TIOCSDTR: 114810015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 114910015Speter break; 115010015Speter case TIOCCDTR: 115110015Speter (void) si_modem(pp, SET, 0); 115210015Speter break; 115310015Speter case TIOCMSET: 115410015Speter (void) si_modem(pp, SET, *(int *)data); 115510015Speter break; 115610015Speter case TIOCMBIS: 115710015Speter (void) si_modem(pp, BIS, *(int *)data); 115810015Speter break; 115910015Speter case TIOCMBIC: 116010015Speter (void) si_modem(pp, BIC, *(int *)data); 116110015Speter break; 116210015Speter case TIOCMGET: 116310015Speter *(int *)data = si_modem(pp, GET, 0); 116410015Speter break; 116510015Speter case TIOCMSDTRWAIT: 116610015Speter /* must be root since the wait applies to following logins */ 116710015Speter error = suser(p->p_ucred, &p->p_acflag); 116810015Speter if (error != 0) { 116910015Speter goto outspl; 117010015Speter } 117110015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 117210015Speter break; 117310015Speter case TIOCMGDTRWAIT: 117410015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 117510015Speter break; 117610015Speter 117710015Speter default: 117810015Speter error = ENOTTY; 117910015Speter } 118010015Speter error = 0; 118110015Speteroutspl: 118210015Speter splx(oldspl); 118310015Speterout: 118410015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 118510015Speter if (blocked) 118610015Speter si_write_enable(pp, 1); 118710015Speter return(error); 118810015Speter} 118910015Speter 119010015Speter/* 119110015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 119210015Speter */ 119310015Speterstatic int 119410015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 119510015Speter{ 119610015Speter struct si_softc *xsc; 119710015Speter register struct si_port *xpp; 119810015Speter volatile struct si_reg *regp; 119910015Speter struct si_tcsi *dp; 120010044Speter struct si_pstat *sps; 120110015Speter BYTE *bp; 120210015Speter int i, *ip, error = 0; 120310015Speter int oldspl; 120410015Speter int card, port; 120510015Speter unsigned short *usp; 120610015Speter int mynor = minor(dev); 120710015Speter 120810015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 120910015Speter dev, cmd, data, flag)); 121010015Speter 121110044Speter#if 1 121210044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 121310044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 121410044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 121510044Speter#endif 121610044Speter 121710015Speter if (!IS_CONTROLDEV(mynor)) { 121810015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 121910015Speter return(ENODEV); 122010015Speter } 122110015Speter 122210015Speter oldspl = spltty(); /* better safe than sorry */ 122310015Speter 122410015Speter ip = (int *)data; 122510015Speter 122610015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 122710015Speter 122810015Speter switch (cmd) { 122910015Speter case TCSIPORTS: 123010015Speter *ip = si_Nports; 123110015Speter goto out; 123210015Speter case TCSIMODULES: 123310015Speter *ip = si_Nmodules; 123410015Speter goto out; 123510015Speter case TCSISDBG_ALL: 123610015Speter SUCHECK; 123710015Speter si_debug = *ip; 123810015Speter goto out; 123910015Speter case TCSIGDBG_ALL: 124010015Speter *ip = si_debug; 124110015Speter goto out; 124210015Speter default: 124310015Speter /* 124410015Speter * Check that a controller for this port exists 124510015Speter */ 124610044Speter 124710044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 124810044Speter 124910015Speter dp = (struct si_tcsi *)data; 125010044Speter sps = (struct si_pstat *)data; 125110015Speter card = dp->tc_card; 125210015Speter xsc = &si_softc[card]; /* check.. */ 125310015Speter if (card < 0 || card >= NSI || xsc->sc_type == NULL) { 125410015Speter error = ENOENT; 125510015Speter goto out; 125610015Speter } 125710015Speter /* 125810015Speter * And check that a port exists 125910015Speter */ 126010015Speter port = dp->tc_port; 126110015Speter if (port < 0 || port >= xsc->sc_nport) { 126210015Speter error = ENOENT; 126310015Speter goto out; 126410015Speter } 126510015Speter xpp = xsc->sc_ports + port; 126610015Speter regp = (struct si_reg *)xsc->sc_maddr; 126710015Speter } 126810015Speter 126910015Speter switch (cmd) { 127010015Speter case TCSIDEBUG: 127110015Speter#ifdef SI_DEBUG 127210015Speter SUCHECK; 127310015Speter if (xpp->sp_debug) 127410015Speter xpp->sp_debug = 0; 127510015Speter else { 127610015Speter xpp->sp_debug = DBG_ALL; 127710015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 127810015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 127910015Speter } 128010015Speter break; 128110015Speter#else 128210015Speter error = ENODEV; 128310015Speter goto out; 128410015Speter#endif 128510015Speter case TCSISDBG_LEVEL: 128610015Speter case TCSIGDBG_LEVEL: 128710015Speter#ifdef SI_DEBUG 128810015Speter if (cmd == TCSIGDBG_LEVEL) { 128910015Speter dp->tc_dbglvl = xpp->sp_debug; 129010015Speter } else { 129110015Speter SUCHECK; 129210015Speter xpp->sp_debug = dp->tc_dbglvl; 129310015Speter } 129410015Speter break; 129510015Speter#else 129610015Speter error = ENODEV; 129710015Speter goto out; 129810015Speter#endif 129910015Speter case TCSIGRXIT: 130010015Speter dp->tc_int = regp->rx_int_count; 130110015Speter break; 130210015Speter case TCSIRXIT: 130310015Speter SUCHECK; 130410015Speter regp->rx_int_count = dp->tc_int; 130510015Speter break; 130610015Speter case TCSIGIT: 130710015Speter dp->tc_int = regp->int_count; 130810015Speter break; 130910015Speter case TCSIIT: 131010015Speter SUCHECK; 131110015Speter regp->int_count = dp->tc_int; 131210015Speter break; 131310044Speter case TCSISTATE: 131410044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 131510015Speter break; 131610044Speter /* these next three use a different structure */ 131710044Speter case TCSI_PORT: 131810015Speter SUCHECK; 131910044Speter sps->tc_siport = *xpp; 132010015Speter break; 132110044Speter case TCSI_CCB: 132210044Speter SUCHECK; 132310044Speter sps->tc_ccb = *xpp->sp_ccb; 132410015Speter break; 132510044Speter case TCSI_TTY: 132610044Speter SUCHECK; 132710044Speter sps->tc_tty = *xpp->sp_tty; 132810015Speter break; 132910015Speter default: 133010015Speter error = EINVAL; 133110015Speter goto out; 133210015Speter } 133310015Speterout: 133410015Speter splx(oldspl); 133510015Speter return(error); /* success */ 133610015Speter} 133710015Speter 133810015Speter/* 133910015Speter * siparam() : Configure line params 134010015Speter * called at spltty(); 134110015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 134210015Speter * caller must arrange this if it's important.. 134310015Speter */ 134410015Speterint 134510015Spetersiparam(tp, t) 134610015Speter register struct tty *tp; 134710015Speter register struct termios *t; 134810015Speter{ 134910015Speter register struct si_port *pp = TP2PP(tp); 135010015Speter volatile struct si_channel *ccbp; 135110015Speter int oldspl, cflag, iflag, oflag, lflag; 135210015Speter int error = 0; /* shutup gcc */ 135310015Speter int ispeed = 0; /* shutup gcc */ 135410015Speter int ospeed = 0; /* shutup gcc */ 135510161Speter BYTE val; 135610015Speter 135710015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 135810015Speter cflag = t->c_cflag; 135910015Speter iflag = t->c_iflag; 136010015Speter oflag = t->c_oflag; 136110015Speter lflag = t->c_lflag; 136210044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 136310044Speter oflag, cflag, iflag, lflag)); 136410015Speter 136510015Speter 136610015Speter /* if not hung up.. */ 136710015Speter if (t->c_ospeed != 0) { 136810015Speter /* translate baud rate to firmware values */ 136910015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 137010015Speter ispeed = t->c_ispeed ? 137110015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 137210015Speter 137310015Speter /* enforce legit baud rate */ 137410015Speter if (ospeed < 0 || ispeed < 0) 137510015Speter return (EINVAL); 137610015Speter } 137710015Speter 137810015Speter 137910015Speter oldspl = spltty(); 138010015Speter 138110015Speter ccbp = pp->sp_ccb; 138210015Speter 138310161Speter /* ========== set hi_break ========== */ 138410161Speter val = 0; 138510161Speter if (iflag & IGNBRK) /* Breaks */ 138610161Speter val |= BR_IGN; 138710161Speter if (iflag & BRKINT) /* Interrupt on break? */ 138810161Speter val |= BR_INT; 138910161Speter if (iflag & PARMRK) /* Parity mark? */ 139010161Speter val |= BR_PARMRK; 139110161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 139210161Speter val |= BR_PARIGN; 139310161Speter ccbp->hi_break = val; 139410161Speter 139510161Speter /* ========== set hi_csr ========== */ 139610015Speter /* if not hung up.. */ 139710015Speter if (t->c_ospeed != 0) { 139810015Speter /* Set I/O speeds */ 139910161Speter val = (ispeed << 4) | ospeed; 140010015Speter } 140110161Speter ccbp->hi_csr = val; 140210015Speter 140310161Speter /* ========== set hi_mr2 ========== */ 140410161Speter val = 0; 140510015Speter if (cflag & CSTOPB) /* Stop bits */ 140610161Speter val |= MR2_2_STOP; 140710015Speter else 140810161Speter val |= MR2_1_STOP; 140910161Speter /* 141010161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 141110161Speter * a DCE, hence the reverse sense of RTS and CTS 141210161Speter */ 141310161Speter /* Output Flow - RTS must be raised before data can be sent */ 141410161Speter if (cflag & CCTS_OFLOW) 141510161Speter val |= MR2_RTSCONT; 141610161Speter 141710161Speter ccbp->hi_mr1 = val; 141810161Speter 141910161Speter /* ========== set hi_mr1 ========== */ 142010161Speter val = 0; 142110015Speter if (!(cflag & PARENB)) /* Parity */ 142210161Speter val |= MR1_NONE; 142310015Speter else 142410161Speter val |= MR1_WITH; 142510015Speter if (cflag & PARODD) 142610161Speter val |= MR1_ODD; 142710015Speter 142810015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 142910161Speter val |= MR1_8_BITS; 143010015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 143110161Speter val |= MR1_7_BITS; 143210015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 143310161Speter val |= MR1_6_BITS; 143410015Speter } else { /* Must be 5 */ 143510161Speter val |= MR1_5_BITS; 143610015Speter } 143710161Speter /* 143810161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 143910161Speter * a DCE, hence the reverse sense of RTS and CTS 144010161Speter */ 144110161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 144210161Speter if (cflag & CRTS_IFLOW) 144310161Speter val |= MR1_CTSCONT; 144410015Speter 144510161Speter ccbp->hi_mr1 = val; 144610161Speter 144710161Speter /* ========== set hi_mask ========== */ 144810161Speter val = 0xff; 144910161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 145010161Speter val &= 0xFF; 145110161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 145210161Speter val &= 0x7F; 145310161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 145410161Speter val &= 0x3F; 145510161Speter } else { /* Must be 5 */ 145610161Speter val &= 0x1F; 145710161Speter } 145810015Speter if (iflag & ISTRIP) 145910161Speter val &= 0x7F; 146010015Speter 146110161Speter ccbp->hi_mask = val; 146210161Speter 146310161Speter /* ========== set hi_prtcl ========== */ 146410161Speter val = 0; 146510015Speter /* Monitor DCD etc. if a modem */ 146610015Speter if (!(cflag & CLOCAL)) 146710161Speter val |= SP_DCEN; 146810161Speter if (iflag & IXANY) 146910161Speter val |= SP_TANY; 147010161Speter if (iflag & IXON) 147110161Speter val |= SP_TXEN; 147210161Speter if (iflag & IXOFF) 147310161Speter val |= SP_RXEN; 147410161Speter if (iflag & INPCK) 147510161Speter val |= SP_PAEN; 147610015Speter 147710161Speter ccbp->hi_prtcl = val; 147810161Speter 147910161Speter 148010161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 148110161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 148210015Speter ccbp->hi_txon = t->c_cc[VSTART]; 148310015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 148410015Speter 148510015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 148610015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 148710015Speter 148810161Speter /* ========== send settings to the card ========== */ 148910015Speter /* potential sleep here */ 149010015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 149110015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 149210015Speter else 149310015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 149410015Speter 149510161Speter /* ========== set DTR etc ========== */ 149610015Speter /* Hangup if ospeed == 0 */ 149710015Speter if (t->c_ospeed == 0) { 149810015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 149910015Speter } else { 150010015Speter /* 150110015Speter * If the previous speed was 0, may need to re-enable 150210015Speter * the modem signals 150310015Speter */ 150410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 150510015Speter } 150610015Speter 150710044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 150810044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 150910015Speter 151010015Speter splx(oldspl); 151110015Speterout: 151210015Speter return(error); 151310015Speter} 151410015Speter 151510015Speter/* 151610015Speter * Enable or Disable the writes to this channel... 151710015Speter * "state" -> enabled = 1; disabled = 0; 151810015Speter */ 151910015Speterstatic void 152010015Spetersi_write_enable(pp, state) 152110015Speter register struct si_port *pp; 152210015Speter int state; 152310015Speter{ 152410015Speter int oldspl; 152510015Speter 152610015Speter oldspl = spltty(); 152710015Speter 152810015Speter if (state) { 152910015Speter pp->sp_state &= ~SS_BLOCKWRITE; 153010015Speter if (pp->sp_state & SS_WAITWRITE) { 153110015Speter pp->sp_state &= ~SS_WAITWRITE; 153210015Speter /* thunder away! */ 153310015Speter wakeup((caddr_t)pp); 153410015Speter } 153510015Speter } else { 153610015Speter pp->sp_state |= SS_BLOCKWRITE; 153710015Speter } 153810015Speter 153910015Speter splx(oldspl); 154010015Speter} 154110015Speter 154210015Speter/* 154310015Speter * Set/Get state of modem control lines. 154410015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 154510015Speter * TIOCM_DTR DSR 154610015Speter * TIOCM_RTS CTS 154710015Speter */ 154810015Speterstatic int 154910015Spetersi_modem(pp, cmd, bits) 155010015Speter struct si_port *pp; 155110015Speter enum si_mctl cmd; 155210015Speter int bits; 155310015Speter{ 155410015Speter volatile struct si_channel *ccbp; 155510015Speter int x; 155610015Speter 155710015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 155810015Speter ccbp = pp->sp_ccb; /* Find channel address */ 155910015Speter switch (cmd) { 156010015Speter case GET: 156110015Speter x = ccbp->hi_ip; 156210015Speter bits = TIOCM_LE; 156310015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 156410015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 156510015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 156610015Speter if (x & IP_RI) bits |= TIOCM_RI; 156710015Speter return(bits); 156810015Speter case SET: 156910015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 157010015Speter /* fall through */ 157110015Speter case BIS: 157210015Speter x = 0; 157310015Speter if (bits & TIOCM_DTR) 157410015Speter x |= OP_DSR; 157510015Speter if (bits & TIOCM_RTS) 157610015Speter x |= OP_CTS; 157710015Speter ccbp->hi_op |= x; 157810015Speter break; 157910015Speter case BIC: 158010015Speter if (bits & TIOCM_DTR) 158110015Speter ccbp->hi_op &= ~OP_DSR; 158210015Speter if (bits & TIOCM_RTS) 158310015Speter ccbp->hi_op &= ~OP_CTS; 158410015Speter } 158510015Speter return 0; 158610015Speter} 158710015Speter 158810015Speter/* 158910015Speter * Handle change of modem state 159010015Speter */ 159110015Speterstatic void 159210015Spetersi_modem_state(pp, tp, hi_ip) 159310015Speter register struct si_port *pp; 159410015Speter register struct tty *tp; 159510015Speter register int hi_ip; 159610015Speter{ 159710015Speter /* if a modem dev */ 159810015Speter if (hi_ip & IP_DCD) { 159910015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 160010015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 160110015Speter tp->t_line)); 160210015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 160310015Speter } 160410015Speter } else { 160510015Speter if (pp->sp_last_hi_ip & IP_DCD) { 160610015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 160710015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 160810015Speter (void) si_modem(pp, SET, 0); 160910015Speter } 161010015Speter } 161110015Speter pp->sp_last_hi_ip = hi_ip; 161210015Speter 161310015Speter} 161410015Speter 161510015Speter/* 161610015Speter * Poller to catch missed interrupts. 161710015Speter */ 161810015Speter#ifdef POLL 161910708Speterstatic void 162010015Spetersi_poll(void *nothing) 162110015Speter{ 162210015Speter register struct si_softc *sc; 162310015Speter register int i; 162410015Speter volatile struct si_reg *regp; 162510015Speter int lost, oldspl; 162610015Speter 162710015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 162811609Speter oldspl = spltty(); 162910015Speter if (in_intr) 163010015Speter goto out; 163110015Speter lost = 0; 163210015Speter for (i=0; i<NSI; i++) { 163310015Speter sc = &si_softc[i]; 163410015Speter if (sc->sc_type == NULL) 163510015Speter continue; 163610015Speter regp = (struct si_reg *)sc->sc_maddr; 163710015Speter /* 163810015Speter * See if there has been a pending interrupt for 2 seconds 163910015Speter * or so. The test <int_scounter >= 200) won't correspond 164010015Speter * to 2 seconds if int_count gets changed. 164110015Speter */ 164210015Speter if (regp->int_pending != 0) { 164310015Speter if (regp->int_scounter >= 200 && 164410015Speter regp->initstat == 1) { 164510015Speter printf("SLXOS si%d: lost intr\n", i); 164610015Speter lost++; 164710015Speter } 164810015Speter } else { 164910015Speter regp->int_scounter = 0; 165010015Speter } 165110015Speter 165210015Speter } 165310015Speter if (lost) 165410015Speter siintr(-1); /* call intr with fake vector */ 165511609Speterout: 165610015Speter splx(oldspl); 165710015Speter 165810015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 165910015Speter} 166010015Speter#endif /* ifdef POLL */ 166110015Speter 166210015Speter/* 166310015Speter * The interrupt handler polls ALL ports on ALL adapters each time 166410015Speter * it is called. 166510015Speter */ 166610015Speter 166710161Speterstatic BYTE rxbuf[SLXOS_BUFFERSIZE]; /* input staging area */ 166810015Speter 166910708Spetervoid 167011609Spetersiintr(int unit) 167110015Speter{ 167210015Speter register struct si_softc *sc; 167310015Speter 167410015Speter register struct si_port *pp; 167510015Speter volatile struct si_channel *ccbp; 167610015Speter register struct tty *tp; 167710015Speter volatile caddr_t maddr; 167810015Speter BYTE op, ip, cc; 167910161Speter int x, card, port, n, i; 168010015Speter volatile BYTE *z; 168110015Speter BYTE c; 168210015Speter 168311609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 168411609Speter if (in_intr) { 168511609Speter if (unit < 0) /* should never happen */ 168610708Speter return; 168710015Speter printf("SLXOS si%d: Warning interrupt handler re-entered\n", 168811609Speter unit); 168910708Speter return; 169010015Speter } 169110015Speter in_intr = 1; 169210015Speter 169310015Speter /* 169410015Speter * When we get an int we poll all the channels and do ALL pending 169510015Speter * work, not just the first one we find. This allows all cards to 169610015Speter * share the same vector. 169710015Speter */ 169810015Speter for (card=0; card < NSI; card++) { 169910015Speter sc = &si_softc[card]; 170010015Speter if (sc->sc_type == NULL) 170110015Speter continue; 170210015Speter switch(sc->sc_type) { 170310015Speter case SIHOST : 170410015Speter maddr = sc->sc_maddr; 170510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 170610015Speter /* flag nothing pending */ 170710015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 170810015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 170910015Speter break; 171010015Speter case SIHOST2: 171110015Speter maddr = sc->sc_maddr; 171210015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 171310015Speter *(maddr+SIPLIRQCLR) = 0x00; 171410015Speter *(maddr+SIPLIRQCLR) = 0x10; 171510015Speter break; 171610015Speter case SIEISA: 171710015Speter#if NEISA > 0 171810015Speter maddr = sc->sc_maddr; 171910015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 172010015Speter (void)inb(sc->sc_eisa_iobase+3); 172110015Speter break; 172210015Speter#endif /* fall through if not EISA kernel */ 172310015Speter case SIEMPTY: 172410015Speter default: 172510015Speter continue; 172610015Speter } 172710015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 172810015Speter 172910015Speter for (pp = sc->sc_ports, port=0; 173010015Speter port < sc->sc_nport; 173110015Speter pp++, port++) { 173210015Speter ccbp = pp->sp_ccb; 173310015Speter tp = pp->sp_tty; 173410015Speter 173510015Speter /* 173610015Speter * See if a command has completed ? 173710015Speter */ 173810015Speter if (ccbp->hi_stat != pp->sp_pend) { 173910015Speter DPRINT((pp, DBG_INTR, 174010015Speter "siintr hi_stat = 0x%x, pend = %d\n", 174110015Speter ccbp->hi_stat, pp->sp_pend)); 174210015Speter switch(pp->sp_pend) { 174310015Speter case LOPEN: 174410015Speter case MPEND: 174510015Speter case MOPEN: 174610015Speter case CONFIG: 174710015Speter pp->sp_pend = ccbp->hi_stat; 174810015Speter /* sleeping in si_command */ 174910015Speter wakeup(&pp->sp_state); 175010015Speter break; 175110015Speter default: 175210015Speter pp->sp_pend = ccbp->hi_stat; 175310015Speter } 175410015Speter } 175510015Speter 175610015Speter /* 175710015Speter * Continue on if it's closed 175810015Speter */ 175910015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 176010015Speter continue; 176110015Speter } 176210015Speter 176310015Speter /* 176410015Speter * Do modem state change if not a local device 176510015Speter */ 176610015Speter si_modem_state(pp, tp, ccbp->hi_ip); 176710015Speter 176810015Speter /* 176910015Speter * Do break processing 177010015Speter */ 177110015Speter if (ccbp->hi_state & ST_BREAK) { 177210672Speter if (tp->t_state & TS_CONNECTED && 177310672Speter tp->t_state & TS_ISOPEN) { 177410015Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 177510015Speter } 177610015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 177710015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 177810015Speter } 177910015Speter 178010015Speter /* 178110015Speter * Do RX stuff - if not open then 178210015Speter * dump any characters. 178310015Speter */ 178410015Speter 178510672Speter if ((tp->t_state & TS_CONNECTED) == 0 || 178610672Speter (tp->t_state & TS_ISOPEN) == 0) { 178710015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 178810015Speter } else { 178910015Speter while ((c = ccbp->hi_rxipos - ccbp->hi_rxopos) != 0) { 179010015Speter 179110015Speter op = ccbp->hi_rxopos; 179210015Speter ip = ccbp->hi_rxipos; 179310015Speter n = c & 0xff; 179410015Speter 179510015Speter DPRINT((pp, DBG_INTR, 179610015Speter "n = %d, op = %d, ip = %d\n", 179710015Speter n, op, ip)); 179810015Speter if (n <= SLXOS_BUFFERSIZE - op) { 179910015Speter 180010015Speter DPRINT((pp, DBG_INTR, 180110015Speter "\tsingle copy\n")); 180210015Speter z = ccbp->hi_rxbuf + op; 180310015Speter bcopy((caddr_t)z, rxbuf, n); 180410015Speter 180510015Speter op += n; 180610015Speter } else { 180710015Speter x = SLXOS_BUFFERSIZE - op; 180810015Speter 180910015Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 181010015Speter z = ccbp->hi_rxbuf + op; 181110015Speter bcopy((caddr_t)z, rxbuf, x); 181210015Speter 181310015Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 181410015Speter z = ccbp->hi_rxbuf; 181510015Speter bcopy((caddr_t)z, rxbuf+x, n-x); 181610015Speter 181710015Speter op += n; 181810015Speter } 181910015Speter 182010015Speter ccbp->hi_rxopos = op; 182110015Speter 182210015Speter DPRINT((pp, DBG_INTR, 182310015Speter "n = %d, op = %d, ip = %d\n", 182410015Speter n, op, ip)); 182510015Speter 182610015Speter /* 182710015Speter * at this point... 182810015Speter * n = number of chars placed in rxbuf 182910015Speter */ 183010015Speter /* 183110015Speter * Avoid the grotesquely inefficient lineswitch routine 183210015Speter * (ttyinput) in "raw" mode. It usually takes about 450 183310015Speter * instructions (that's without canonical processing or echo!). 183410015Speter * slinput is reasonably fast (usually 40 instructions plus 183510015Speter * call overhead). 183610015Speter */ 183710015Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 183810015Speter 183910015Speter /* block if the driver supports it */ 184010015Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 184110015Speter && (tp->t_cflag & CRTS_IFLOW 184210015Speter || tp->t_iflag & IXOFF) 184310015Speter && !(tp->t_state & TS_TBLOCK)) 184410015Speter ttyblock(tp); 184510015Speter 184610015Speter tk_nin += n; 184710015Speter tk_rawcc += n; 184810015Speter tp->t_rawcc += n; 184910015Speter 185010015Speter b_to_q((char *)rxbuf, n, &tp->t_rawq); 185110015Speter ttwakeup(tp); 185210015Speter if (tp->t_state & TS_TTSTOP 185310015Speter && (tp->t_iflag & IXANY 185410015Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 185510015Speter tp->t_state &= ~TS_TTSTOP; 185610015Speter tp->t_lflag &= ~FLUSHO; 185710015Speter si_start(tp); 185810015Speter } 185910015Speter } else { 186010015Speter for(x = 0; x < n; x++) { 186110161Speter i = rxbuf[x]; 186210161Speter (*linesw[tp->t_line].l_rint)(rxbuf[x], tp); 186310161Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 186410161Speter setsofttty(); 186510161Speter } 186610015Speter } 186710015Speter } 186810015Speter 186910015Speter } /* end of RX while */ 187010015Speter } /* end TS_CONNECTED */ 187110015Speter 187210015Speter /* 187310015Speter * Do TX stuff 187410015Speter */ 187510015Speter (*linesw[tp->t_line].l_start)(tp); 187610015Speter 187710015Speter } /* end of for (all ports on this controller) */ 187810015Speter } /* end of for (all controllers) */ 187910015Speter 188011609Speter in_intr = 0; 188111609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 188210015Speter} 188310015Speter 188410015Speter/* 188510015Speter * Nudge the transmitter... 188610015Speter */ 188710015Speterstatic void 188810015Spetersi_start(tp) 188910015Speter register struct tty *tp; 189010015Speter{ 189110015Speter struct si_port *pp; 189210015Speter volatile struct si_channel *ccbp; 189310015Speter register struct clist *qp; 189410015Speter register char *dptr; 189510015Speter BYTE ipos; 189610015Speter int nchar; 189710015Speter int oldspl, count, n, amount, buffer_full; 189810015Speter int do_exitproc; 189910015Speter 190010015Speter oldspl = spltty(); 190110015Speter 190210015Speter qp = &tp->t_outq; 190310015Speter pp = TP2PP(tp); 190410015Speter 190510015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 190610015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 190710015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 190810015Speter 190910015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 191010015Speter goto out; 191110015Speter 191210015Speter do_exitproc = 0; 191310015Speter buffer_full = 0; 191410015Speter ccbp = pp->sp_ccb; 191510015Speter 191610015Speter /* 191710015Speter * Handle the case where ttywait() is called on process exit 191810015Speter * this may be BSDI specific, I dont know... 191910015Speter */ 192010015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 192110015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 192210015Speter do_exitproc++; 192310015Speter } 192410015Speter 192510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 192610015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 192710015Speter 192810015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 192910015Speter 193010015Speter while ((nchar = qp->c_cc) > 0) { 193110015Speter if ((BYTE)count >= 255) { 193210015Speter buffer_full++; 193310015Speter break; 193410015Speter } 193510015Speter amount = min(nchar, (255 - (BYTE)count)); 193610015Speter ipos = (unsigned int)ccbp->hi_txipos; 193710015Speter /* will it fit in one lump? */ 193810015Speter if ((SLXOS_BUFFERSIZE - ipos) >= amount) { 193910015Speter n = q_to_b(&tp->t_outq, 194010015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 194110015Speter } else { 194210015Speter n = q_to_b(&tp->t_outq, 194310015Speter (char *)&ccbp->hi_txbuf[ipos], 194410015Speter SLXOS_BUFFERSIZE-ipos); 194510015Speter if (n == SLXOS_BUFFERSIZE-ipos) { 194610015Speter n += q_to_b(&tp->t_outq, 194710015Speter (char *)&ccbp->hi_txbuf[0], 194810015Speter amount - (SLXOS_BUFFERSIZE-ipos)); 194910015Speter } 195010015Speter } 195110015Speter ccbp->hi_txipos += n; 195210015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 195310015Speter } 195410015Speter 195510015Speter if (count != 0 && nchar == 0) { 195610015Speter tp->t_state |= TS_BUSY; 195710015Speter } else { 195810015Speter tp->t_state &= ~TS_BUSY; 195910015Speter } 196010015Speter 196110015Speter /* wakeup time? */ 196210015Speter ttwwakeup(tp); 196310015Speter 196410015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 196510015Speter (BYTE)count, nchar, tp->t_state)); 196610015Speter 196710015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 196810015Speter { 196910015Speter int time; 197010015Speter 197110015Speter if (do_exitproc != 0) { 197210015Speter time = hz / 10; 197310015Speter } else { 197410015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 197510015Speter 197610015Speter if (time > 0) { 197710015Speter if (time < nchar) 197810015Speter time = nchar / time; 197910015Speter else 198010015Speter time = 2; 198110015Speter } else { 198210015Speter printf("SLXOS si%d: bad char time value!!\n", 198310015Speter SI_CARD(tp->t_dev)); 198410015Speter goto out; 198510015Speter } 198610015Speter } 198710015Speter 198810015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 198910015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 199010015Speter } else { 199110015Speter pp->sp_state |= SS_LSTART; 199210015Speter } 199310015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 199410015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 199510015Speter } 199610015Speter 199710015Speterout: 199810015Speter splx(oldspl); 199910015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 200010015Speter} 200110015Speter 200210015Speter/* 200310015Speter * Note: called at splsoftclock from the timeout code 200410015Speter * This has to deal with two things... cause wakeups while waiting for 200510015Speter * tty drains on last process exit, and call l_start at about the right 200610015Speter * time for protocols like ppp. 200710015Speter */ 200810015Speterstatic void 200910015Spetersi_lstart(pp) 201010015Speter register struct si_port *pp; 201110015Speter{ 201210015Speter register struct tty *tp; 201310015Speter int oldspl; 201410015Speter 201510015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 201610015Speter pp, pp->sp_state)); 201710015Speter 201810015Speter oldspl = spltty(); 201910015Speter 202010015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 202110015Speter splx(oldspl); 202210015Speter return; 202310015Speter } 202410015Speter pp->sp_state &= ~SS_LSTART; 202510015Speter pp->sp_state |= SS_INLSTART; 202610015Speter 202710015Speter tp = pp->sp_tty; 202810015Speter 202910015Speter /* deal with the process exit case */ 203010015Speter ttwwakeup(tp); 203110015Speter 203210015Speter /* nudge protocols */ 203310015Speter (*linesw[tp->t_line].l_start)(tp); 203410015Speter 203510015Speter pp->sp_state &= ~SS_INLSTART; 203610015Speter splx(oldspl); 203710015Speter} 203810015Speter 203910015Speter/* 204010015Speter * Stop output on a line. called at spltty(); 204110015Speter */ 204210015Spetervoid 204310015Spetersistop(tp, rw) 204410015Speter register struct tty *tp; 204510015Speter int rw; 204610015Speter{ 204710015Speter volatile struct si_channel *ccbp; 204810015Speter struct si_port *pp; 204910015Speter 205010015Speter pp = TP2PP(tp); 205110015Speter ccbp = pp->sp_ccb; 205210015Speter 205310015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 205410015Speter 205510015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 205610015Speter if (rw & FWRITE) { 205710015Speter /* what level are we meant to be flushing anyway? */ 205810015Speter if (tp->t_state & TS_BUSY) { 205910015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 206010015Speter tp->t_state &= ~TS_BUSY; 206110015Speter ttwwakeup(tp); /* Bruce???? */ 206210015Speter } 206310015Speter } 206410015Speter#if 0 /* this doesn't work right yet.. */ 206510015Speter if (rw & FREAD) { 206610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 206710015Speter } 206810015Speter#endif 206910015Speter} 207010015Speter 207110015Speter/* 207210015Speter * Issue a command to the Z280 host card CPU. 207310015Speter */ 207410015Speter 207510015Speterstatic void 207610015Spetersi_command(pp, cmd, waitflag) 207710015Speter struct si_port *pp; /* port control block (local) */ 207810015Speter int cmd; 207910015Speter int waitflag; 208010015Speter{ 208110015Speter int oldspl; 208210015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 208310015Speter int x; 208410015Speter 208510015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 208610015Speter pp, cmd, waitflag, ccbp->hi_stat)); 208710015Speter 208810015Speter oldspl = spltty(); /* Keep others out */ 208910015Speter 209010015Speter /* wait until it's finished what it was doing.. */ 209110015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 209210015Speter x != IDLE_CLOSE && 209310015Speter x != cmd) { 209410015Speter if (in_intr) { /* Prevent sleep in intr */ 209510015Speter DPRINT((pp, DBG_PARAM, 209610015Speter "cmd intr collision - completing %d\trequested %d\n", 209710015Speter x, cmd)); 209810015Speter splx(oldspl); 209910015Speter return; 210010015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 210110015Speter "sicmd1", 1)) { 210210015Speter splx(oldspl); 210310015Speter return; 210410015Speter } 210510015Speter } 210610015Speter /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 210710015Speter 210810015Speter /* if there was a pending command, cause a state-change wakeup */ 210910015Speter if (pp->sp_pend != IDLE_OPEN) { 211010015Speter switch(pp->sp_pend) { 211110015Speter case LOPEN: 211210015Speter case MPEND: 211310015Speter case MOPEN: 211410015Speter case CONFIG: 211510015Speter wakeup(&pp->sp_state); 211610015Speter break; 211710015Speter default: 211810015Speter break; 211910015Speter } 212010015Speter } 212110015Speter 212210015Speter pp->sp_pend = cmd; /* New command pending */ 212310015Speter ccbp->hi_stat = cmd; /* Post it */ 212410015Speter 212510015Speter if (waitflag) { 212610015Speter if (in_intr) { /* If in interrupt handler */ 212710015Speter DPRINT((pp, DBG_PARAM, 212810015Speter "attempt to sleep in si_intr - cmd req %d\n", 212910015Speter cmd)); 213010015Speter splx(oldspl); 213110015Speter return; 213210015Speter } else while(ccbp->hi_stat != IDLE_OPEN) { 213310015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 213410015Speter "sicmd2", 0)) 213510015Speter break; 213610015Speter } 213710015Speter } 213810015Speter splx(oldspl); 213910015Speter} 214010015Speter 214110015Speterstatic void 214210015Spetersi_disc_optim(tp, t, pp) 214310015Speter struct tty *tp; 214410015Speter struct termios *t; 214510015Speter struct si_port *pp; 214610015Speter{ 214710015Speter /* 214810015Speter * XXX can skip a lot more cases if Smarts. Maybe 214910015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 215010015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 215110015Speter */ 215210015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 215310015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 215410015Speter && (!(t->c_iflag & PARMRK) 215510015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 215610015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 215710015Speter && linesw[tp->t_line].l_rint == ttyinput) 215810015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 215910015Speter else 216010015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 216110161Speter 216210015Speter /* 216310015Speter * Prepare to reduce input latency for packet 216410015Speter * discplines with a end of packet character. 216510015Speter */ 216610015Speter if (tp->t_line == SLIPDISC) 216710015Speter pp->sp_hotchar = 0xc0; 216810015Speter else if (tp->t_line == PPPDISC) 216910015Speter pp->sp_hotchar = 0x7e; 217010015Speter else 217110015Speter pp->sp_hotchar = 0; 217210161Speter 217310161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 217410161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 217510161Speter pp->sp_hotchar)); 217610015Speter} 217710015Speter 217810015Speter 217910015Speter#ifdef SI_DEBUG 218010015Speterstatic void 218110015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6) 218210015Speter struct si_port *pp; 218310015Speter int flags; 218410015Speter char *str; 218510015Speter int a1, a2, a3, a4, a5, a6; 218610015Speter{ 218710015Speter if ((pp == NULL && (si_debug&flags)) || 218810015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 218910015Speter if (pp != NULL) 219010015Speter printf("SLXOS %ci%d(%d): ", 's', 219110015Speter SI_CARD(pp->sp_tty->t_dev), 219210015Speter SI_PORT(pp->sp_tty->t_dev)); 219310015Speter printf(str, a1, a2, a3, a4, a5, a6); 219410015Speter } 219510015Speter} 219610015Speter 219710015Speterstatic char * 219810015Spetersi_mctl2str(cmd) 219910015Speter enum si_mctl cmd; 220010015Speter{ 220110015Speter switch (cmd) { 220210015Speter case GET: return("GET"); 220310015Speter case SET: return("SET"); 220410015Speter case BIS: return("BIS"); 220510015Speter case BIC: return("BIC"); 220610015Speter } 220710015Speter return("BAD"); 220810015Speter} 220910015Speter#endif 2210