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