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