si.c revision 12731
110015Speter/* 212496Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 310015Speter * 410015Speter * Copyright (C) 1990, 1992 Specialix International, 510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 610015Speter * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> 710015Speter * 810015Speter * Originally derived from: SunOS 4.x version 910015Speter * Ported from BSDI version to FreeBSD by Peter Wemm. 1010015Speter * 1110015Speter * Redistribution and use in source and binary forms, with or without 1210015Speter * modification, are permitted provided that the following conditions 1310015Speter * are met: 1410015Speter * 1. Redistributions of source code must retain the above copyright 1510015Speter * notices, this list of conditions and the following disclaimer. 1610015Speter * 2. Redistributions in binary form must reproduce the above copyright 1710015Speter * notices, this list of conditions and the following disclaimer in the 1810015Speter * documentation and/or other materials provided with the distribution. 1910015Speter * 3. All advertising materials mentioning features or use of this software 2010015Speter * must display the following acknowledgement: 2110015Speter * This product includes software developed by Andy Rutter of 2210015Speter * Advanced Methods and Tools Ltd. based on original information 2310015Speter * from Specialix International. 2410015Speter * 4. Neither the name of Advanced Methods and Tools, nor Specialix 2510015Speter * International may be used to endorse or promote products derived from 2610015Speter * this software without specific prior written permission. 2710015Speter * 2810015Speter * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 2910015Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 3010015Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 3110015Speter * NO EVENT SHALL THE AUTHORS BE LIABLE. 3210015Speter * 3312731Sbde * $Id: si.c,v 1.25 1995/12/10 13:39:12 phk Exp $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3710015Speterstatic char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 3810015Speter si_copyright2[] = "@(#) (C) Andy Rutter 1993", 3910015Speter si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 4010015Speter#endif /* not lint */ 4110015Speter 4210015Speter#include <sys/param.h> 4310015Speter#include <sys/systm.h> 4410015Speter#include <sys/ioctl.h> 4510015Speter#include <sys/tty.h> 4610015Speter#include <sys/ttydefaults.h> 4710015Speter#include <sys/proc.h> 4810015Speter#include <sys/conf.h> 4910015Speter#include <sys/file.h> 5010015Speter#include <sys/uio.h> 5110015Speter#include <sys/dkstat.h> 5210015Speter#include <sys/kernel.h> 5310015Speter#include <sys/syslog.h> 5410015Speter#include <sys/malloc.h> 5510015Speter#include <sys/devconf.h> 5612675Sjulian#ifdef DEVFS 5712675Sjulian#include <sys/devfsext.h> 5812675Sjulian#endif /*DEVFS*/ 5910015Speter 6010015Speter#include <machine/clock.h> 6110015Speter 6212659Sbde#include <vm/vm.h> 6312662Sdg#include <vm/vm_param.h> 6412662Sdg#include <vm/pmap.h> 6512659Sbde 6610015Speter#include <i386/isa/icu.h> 6710015Speter#include <i386/isa/isa.h> 6810015Speter#include <i386/isa/isa_device.h> 6910015Speter 7010015Speter#include <i386/isa/sireg.h> 7110015Speter#include <machine/si.h> 7210015Speter 7310015Speter#include "si.h" 7410015Speter 7510015Speter/* 7610015Speter * This device driver is designed to interface the Specialix International 7712496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 7810015Speter * 7910015Speter * The controller is interfaced to the host via dual port ram 8010015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 8110015Speter */ 8210015Speter 8310015Speter#define POLL /* turn on poller to generate buffer empty interrupt */ 8412174Speter#undef FASTPOLL /* turn on 100Hz poller, (XXX: NOTYET!) */ 8510047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8612496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8710015Speter 8810015Speterenum si_mctl { GET, SET, BIS, BIC }; 8910015Speter 9012675Sjulianstatic const char devchar[] = "ABCDEFGHIJK"; 9112675Sjulianstatic const char portchar[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 9212502Sjulian 9312502Sjulian 9410015Speterstatic void si_command __P((struct si_port *, int, int)); 9510015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 9610015Speterstatic void si_write_enable __P((struct si_port *, int)); 9710015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9810015Speterstatic void si_start __P((struct tty *)); 9910015Speterstatic void si_lstart __P((struct si_port *)); 10010015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 10110015Speter struct si_port *pp)); 10210015Speterstatic void sihardclose __P((struct si_port *pp)); 10310015Speterstatic void sidtrwakeup __P((void *chan)); 10410015Speter 10512724Sphkstatic int siparam __P((struct tty *, struct termios *)); 10610015Speter 10712724Sphkstatic void si_registerdev __P((struct isa_device *id)); 10812724Sphkstatic int siprobe __P((struct isa_device *id)); 10912724Sphkstatic int siattach __P((struct isa_device *id)); 11010708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 11110708Speter 11212675Sjulianstruct isa_driver sidriver = 11312675Sjulian { siprobe, siattach, "si" }; 11412675Sjulian 11512675Sjulian 11612675Sjulianstatic d_open_t siopen; 11712675Sjulianstatic d_close_t siclose; 11812675Sjulianstatic d_read_t siread; 11912675Sjulianstatic d_write_t siwrite; 12012675Sjulianstatic d_ioctl_t siioctl; 12112675Sjulianstatic d_stop_t sistop; 12212731Sbdestatic d_devtotty_t sidevtotty; 12312675Sjulian 12412675Sjulian#define CDEV_MAJOR 68 12512678Sphkstatic struct cdevsw si_cdevsw = 12612675Sjulian { siopen, siclose, siread, siwrite, /*68*/ 12712675Sjulian siioctl, sistop, nxreset, sidevtotty,/* si */ 12812675Sjulian ttselect, nxmmap, NULL, "si", NULL, -1 }; 12912675Sjulian 13012675Sjulian 13112174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 13212174Speter/* XXX: should be varargs, I know.. but where's vprintf()? */ 13312174Speterstatic void si_dprintf __P((/* struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */)); 13410708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 13510708Speter#define DPRINT(x) si_dprintf x 13610708Speter#else 13710708Speter#define DPRINT(x) /* void */ 13810708Speter#endif 13910708Speter 14010962Speterstatic int si_Nports; 14110962Speterstatic int si_Nmodules; 14210962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 14310015Speter 14410962Speterstatic struct tty *si_tty; 14510962Speter 14612174Speter/* where the firmware lives; defined in si_code.c */ 14710015Speterextern int si_dsize; 14810015Speterextern unsigned char si_download[]; 14910015Speter 15010044Speterstruct si_softc { 15110044Speter int sc_type; /* adapter type */ 15210044Speter char *sc_typename; /* adapter type string */ 15310044Speter 15410044Speter struct si_port *sc_ports; /* port structures for this card */ 15510044Speter 15610044Speter caddr_t sc_paddr; /* physical addr of iomem */ 15710044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 15810044Speter int sc_nport; /* # ports on this card */ 15910044Speter int sc_irq; /* copy of attach irq */ 16010044Speter int sc_eisa_iobase; /* EISA io port address */ 16110044Speter int sc_eisa_irqbits; 16210044Speter struct kern_devconf sc_kdc; 16312675Sjulian#ifdef DEVFS 16412675Sjulian struct { 16512675Sjulian void *ttyd; 16612675Sjulian void *ttyl; 16712675Sjulian void *ttyi; 16812675Sjulian void *cuaa; 16912675Sjulian void *cual; 17012675Sjulian void *cuai; 17112675Sjulian } devfs_token[32]; /* what is the max per card? */ 17212675Sjulian#endif 17310044Speter}; 17412724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 17510044Speter 17612174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 17710015Speter# define B2000 2000 17810015Speter#endif 17910015Speterstatic struct speedtab bdrates[] = { 18010015Speter B75, CLK75, /* 0x0 */ 18110015Speter B110, CLK110, /* 0x1 */ 18210015Speter B150, CLK150, /* 0x3 */ 18310015Speter B300, CLK300, /* 0x4 */ 18410015Speter B600, CLK600, /* 0x5 */ 18510015Speter B1200, CLK1200, /* 0x6 */ 18610015Speter B2000, CLK2000, /* 0x7 */ 18710015Speter B2400, CLK2400, /* 0x8 */ 18810015Speter B4800, CLK4800, /* 0x9 */ 18910015Speter B9600, CLK9600, /* 0xb */ 19010015Speter B19200, CLK19200, /* 0xc */ 19110015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 19210015Speter B57600, CLK57600, /* 0xd */ 19310015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 19410015Speter -1, -1 19510015Speter}; 19610015Speter 19710015Speter 19810015Speter/* populated with approx character/sec rates - translated at card 19910015Speter * initialisation time to chars per tick of the clock */ 20010015Speterstatic int done_chartimes = 0; 20110015Speterstatic struct speedtab chartimes[] = { 20210015Speter B75, 8, 20310015Speter B110, 11, 20410015Speter B150, 15, 20510015Speter B300, 30, 20610015Speter B600, 60, 20710015Speter B1200, 120, 20810015Speter B2000, 200, 20910015Speter B2400, 240, 21010015Speter B4800, 480, 21110015Speter B9600, 960, 21210015Speter B19200, 1920, 21310015Speter B38400, 3840, 21410015Speter B57600, 5760, 21510015Speter B115200, 11520, 21610015Speter -1, -1 21710015Speter}; 21810015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 21910015Speter 22010047Speterstatic int si_default_rate = TTYDEF_SPEED; 22110047Speterstatic int si_default_iflag = 0; 22210047Speterstatic int si_default_oflag = 0; 22310047Speterstatic int si_default_lflag = 0; 22410047Speter#ifdef SI_DEF_HWFLOW 22510047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 22610047Speter#else 22710047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 22810047Speter#endif 22910047Speter 23010015Speter#ifdef POLL 23110015Speter#define POLL_INTERVAL (hz/2) 23210015Speterstatic int init_finished = 0; 23312174Speterstatic int fastpoll = 0; 23410015Speterstatic void si_poll __P((void *)); 23510015Speter#endif 23610015Speter 23710015Speter/* 23810015Speter * Array of adapter types and the corresponding RAM size. The order of 23910015Speter * entries here MUST match the ordinal of the adapter type. 24010015Speter */ 24110015Speterstatic char *si_type[] = { 24210015Speter "EMPTY", 24310015Speter "SIHOST", 24410015Speter "SI2", /* MCA */ 24510015Speter "SIHOST2", 24610015Speter "SIEISA", 24710015Speter}; 24810015Speter 24910015Speter 25010015Speterstatic struct kern_devconf si_kdc[NSI] = { { 25110015Speter 0, 0, 0, /* filled in by dev_attach */ 25210015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 25310015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 25410015Speter &kdc_isa0, /* parent */ 25510015Speter 0, /* parent data */ 25610015Speter DC_UNCONFIGURED, /* state */ 25710015Speter "Specialix SI/XIO Host adapter", 25810015Speter DC_CLS_SERIAL, /* class */ 25910015Speter} }; 26010015Speter 26112724Sphkstatic void 26210015Spetersi_registerdev(id) 26310015Speter struct isa_device *id; 26410015Speter{ 26510015Speter if (id->id_unit != 0) { 26610015Speter si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 26710015Speter } 26810015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 26910015Speter si_kdc[id->id_unit].kdc_isa = id; 27012174Speter si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 27110015Speter dev_attach(&si_kdc[id->id_unit]); 27210015Speter} 27310015Speter 27410015Speter/* Look for a valid board at the given mem addr */ 27512724Sphkstatic int 27610015Spetersiprobe(id) 27710015Speter struct isa_device *id; 27810015Speter{ 27910015Speter struct si_softc *sc; 28010015Speter int type; 28110015Speter u_int i, ramsize; 28210015Speter volatile BYTE was, *ux; 28310015Speter volatile unsigned char *maddr; 28410015Speter unsigned char *paddr; 28510015Speter 28610015Speter si_registerdev(id); 28710015Speter 28810015Speter maddr = id->id_maddr; /* virtual address... */ 28910015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 29010015Speter 29112496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 29212496Speter id->id_unit, id->id_maddr, paddr)); 29310015Speter 29410015Speter /* 29510015Speter * this is a lie, but it's easier than trying to handle caching 29610015Speter * and ram conflicts in the >1M and <16M region. 29710015Speter */ 29810015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 29910015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 30012174Speter printf("si%d: iomem (%lx) out of range\n", 30112174Speter id->id_unit, (long)paddr); 30210015Speter return(0); 30310015Speter } 30410015Speter 30510015Speter if (id->id_unit >= NSI) { 30610015Speter /* THIS IS IMPOSSIBLE */ 30710015Speter return(0); 30810015Speter } 30910015Speter 31010015Speter if (((u_int)paddr & 0x7fff) != 0) { 31110015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 31210015Speter "si%d: iomem (%x) not on 32k boundary\n", 31310015Speter id->id_unit, paddr)); 31410015Speter return(0); 31510015Speter } 31610015Speter 31710015Speter 31810015Speter for (i=0; i < NSI; i++) { 31910015Speter if ((sc = &si_softc[i]) == NULL) 32010015Speter continue; 32110015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 32210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 32310015Speter "si%d: iomem (%x) already configured to si%d\n", 32410015Speter id->id_unit, sc->sc_paddr, i)); 32510015Speter return(0); 32610015Speter } 32710015Speter } 32810015Speter 32910015Speter#if NEISA > 0 33010015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 33110015Speter int irq, port; 33210015Speter unsigned long base; 33310015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 33410015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 33510015Speter 33610015Speter port = id->id_iobase; 33710015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 33810015Speter irq = ((inb(port+2) >> 4) & 0xf); 33910015Speter 34010015Speter id->id_irq = eisa_irqs[irq]; 34110015Speter 34210015Speter DPRINT((0, DBG_AUTOBOOT, 34312496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 34410015Speter id->id_unit, base, irq, id->id_irq, port)); 34510015Speter 34610015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 34710015Speter goto bad_irq; 34810015Speter 34910015Speter id->id_iobase &= 0xf000; 35010015Speter id->id_iosize = 0x0fff; 35110015Speter 35210015Speter type = EISA; 35310015Speter outb(p+2, (BYTE)irq << 4); 35410015Speter 35510015Speter sc->sc_eisa_iobase = p; 35610015Speter sc->sc_eisa_irqbits = irq << 4; 35710015Speter ramsize = SIEISA_RAMSIZE; 35810015Speter goto got_card; 35910015Speter } 36010015Speter#endif 36110015Speter 36210015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 36310015Speter *maddr = 0x17; 36410015Speter if (*maddr != 0x17) { 36510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 36610015Speter "si%d: 0x17 check fail at phys 0x%x\n", 36710015Speter id->id_unit, paddr)); 36810015Speterfail: 36910015Speter return(0); 37010015Speter } 37110015Speter /* 37210015Speter * OK, now to see if whatever responded is really an SI card. 37310015Speter * Try for a MK II first (SIHOST2) 37410015Speter */ 37510015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 37610015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 37710015Speter goto try_mk1; 37810015Speter 37910015Speter /* It must be an SIHOST2 */ 38010015Speter *(maddr + SIPLRESET) = 0; 38110015Speter *(maddr + SIPLIRQCLR) = 0; 38210015Speter *(maddr + SIPLIRQSET) = 0x10; 38310015Speter type = SIHOST2; 38410015Speter ramsize = SIHOST2_RAMSIZE; 38510015Speter goto got_card; 38610015Speter 38710015Speter /* 38810015Speter * Its not a MK II, so try for a MK I (SIHOST) 38910015Speter */ 39010015Spetertry_mk1: 39110015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 39210015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 39310015Speter *(maddr+SIRAM) = 0x17; 39410015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 39510015Speter goto fail; 39610015Speter *(maddr+0x7ff8) = 0x17; 39710015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 39810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 39910015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 40010015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 40110015Speter goto fail; 40210015Speter } 40310015Speter 40410015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 40510015Speter type = SIHOST; 40610015Speter ramsize = SIHOST_RAMSIZE; 40710015Speter 40810015Spetergot_card: 40912496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 41012496Speter id->id_unit, type)); 41110015Speter /* Try the acid test */ 41210015Speter ux = (BYTE *)(maddr + SIRAM); 41310015Speter for (i=0; i<ramsize; i++, ux++) 41410015Speter *ux = (BYTE)(i&0xff); 41510015Speter ux = (BYTE *)(maddr + SIRAM); 41610015Speter for (i=0; i<ramsize; i++, ux++) { 41710015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 41810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 41912174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 42010015Speter id->id_unit, paddr+i, was, i&0xff)); 42110015Speter goto fail; 42210015Speter } 42310015Speter } 42410015Speter 42510015Speter /* clear out the RAM */ 42610015Speter ux = (BYTE *)(maddr + SIRAM); 42710015Speter for (i=0; i<ramsize; i++) 42810015Speter *ux++ = 0; 42910015Speter ux = (BYTE *)(maddr + SIRAM); 43010015Speter for (i=0; i<ramsize; i++) { 43110015Speter if ((was = *ux++) != 0) { 43210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 43312174Speter "si%d: clear fail at phys 0x%x, was %x\n", 43410015Speter id->id_unit, paddr+i, was)); 43510015Speter goto fail; 43610015Speter } 43710015Speter } 43810015Speter 43910015Speter /* 44010015Speter * Success, we've found a valid board, now fill in 44110015Speter * the adapter structure. 44210015Speter */ 44310015Speter switch (type) { 44410015Speter case SIHOST2: 44510015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 44610015Speterbad_irq: 44710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 44810015Speter "si%d: bad IRQ value - %d\n", 44910015Speter id->id_unit, id->id_irq)); 45010015Speter return(0); 45110015Speter } 45210015Speter id->id_msize = SIHOST2_MEMSIZE; 45310015Speter break; 45410015Speter case SIHOST: 45510015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 45610015Speter goto bad_irq; 45710015Speter } 45810015Speter id->id_msize = SIHOST_MEMSIZE; 45910015Speter break; 46010015Speter case SIEISA: 46110015Speter id->id_msize = SIEISA_MEMSIZE; 46210015Speter break; 46310015Speter case SI2: /* MCA */ 46410015Speter default: 46510015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 46610015Speter return(0); 46710015Speter } 46810015Speter si_softc[id->id_unit].sc_type = type; 46910015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 47010015Speter return(-1); /* -1 == found */ 47110015Speter} 47210015Speter 47310015Speter/* 47410015Speter * Attach the device. Initialize the card. 47510015Speter */ 47612724Sphkstatic int 47710015Spetersiattach(id) 47810015Speter struct isa_device *id; 47910015Speter{ 48010015Speter int unit = id->id_unit; 48110015Speter struct si_softc *sc = &si_softc[unit]; 48210015Speter struct si_port *pp; 48310015Speter volatile struct si_channel *ccbp; 48410015Speter volatile struct si_reg *regp; 48510015Speter volatile caddr_t maddr; 48610015Speter struct si_module *modp; 48710015Speter struct tty *tp; 48810015Speter struct speedtab *spt; 48910015Speter int nmodule, nport, x, y; 49012174Speter int uart_type; 49112675Sjulian char name[32]; 49210015Speter 49312496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 49410015Speter 49510015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 49610015Speter sc->sc_maddr = id->id_maddr; 49710015Speter sc->sc_irq = id->id_irq; 49810015Speter 49910015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 50010015Speter 50110015Speter maddr = sc->sc_maddr; 50210015Speter 50310015Speter /* 50410015Speter * OK, now lets download the firmware and try and boot the CPU.. 50510015Speter */ 50610015Speter 50712496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 50812496Speter id->id_unit, si_dsize)); 50910015Speter bcopy(si_download, maddr, si_dsize); 51010015Speter 51110015Speter switch (sc->sc_type) { 51210015Speter case SIEISA: 51310015Speter#if NEISA > 0 51410015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 51510015Speter *(maddr+0x42) = 1; 51610015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 51710015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 51810015Speter break; 51910015Speter#endif /* fall-through if not EISA */ 52010015Speter case SI2: 52112174Speter /* 52212174Speter * must get around to converting the code for 52312174Speter * these one day, if FreeBSD ever supports it. 52412174Speter */ 52510015Speter return 0; 52610015Speter case SIHOST: 52710015Speter *(maddr+SIRESET_CL) = 0; 52810015Speter *(maddr+SIINTCL_CL) = 0; 52910015Speter break; 53010015Speter case SIHOST2: 53110015Speter *(maddr+SIPLRESET) = 0x10; 53210015Speter switch (sc->sc_irq) { 53310015Speter case IRQ11: 53410015Speter *(maddr+SIPLIRQ11) = 0x10; 53510015Speter break; 53610015Speter case IRQ12: 53710015Speter *(maddr+SIPLIRQ12) = 0x10; 53810015Speter break; 53910015Speter case IRQ15: 54010015Speter *(maddr+SIPLIRQ15) = 0x10; 54110015Speter break; 54210015Speter } 54310015Speter *(maddr+SIPLIRQCLR) = 0x10; 54410015Speter break; 54510015Speter } 54610015Speter 54710015Speter DELAY(1000000); /* wait around for a second */ 54810015Speter 54910015Speter regp = (struct si_reg *)maddr; 55010015Speter y = 0; 55110015Speter /* wait max of 5 sec for init OK */ 55210015Speter while (regp->initstat == 0 && y++ < 10) { 55310015Speter DELAY(500000); 55410015Speter } 55510015Speter switch (regp->initstat) { 55610015Speter case 0: 55710015Speter printf("si%d: startup timeout - aborting\n", unit); 55812174Speter sc->sc_type = SIEMPTY; 55910015Speter return 0; 56010015Speter case 1: 56112174Speter /* set throttle to 125 intr per second */ 56210015Speter regp->int_count = 25000; 56310015Speter /* rx intr max of 25 timer per second */ 56410015Speter regp->rx_int_count = 4; 56510015Speter regp->int_pending = 0; /* no intr pending */ 56610015Speter regp->int_scounter = 0; /* reset counter */ 56710015Speter break; 56810015Speter case 0xff: 56910015Speter /* 57010015Speter * No modules found, so give up on this one. 57110015Speter */ 57210015Speter printf("si%d: %s - no ports found\n", unit, 57310015Speter si_type[sc->sc_type]); 57410015Speter return 0; 57510015Speter default: 57610015Speter printf("si%d: Z280 version error - initstat %x\n", 57710015Speter unit, regp->initstat); 57810015Speter return 0; 57910015Speter } 58010015Speter 58110015Speter /* 58210015Speter * First time around the ports just count them in order 58310015Speter * to allocate some memory. 58410015Speter */ 58510015Speter nport = 0; 58610015Speter modp = (struct si_module *)(maddr + 0x80); 58710015Speter for (;;) { 58812174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 58910015Speter switch (modp->sm_type & (~MMASK)) { 59010015Speter case M232: 59110015Speter case M422: 59210015Speter DPRINT((0, DBG_DOWNLOAD, 59312174Speter "si%d: Found 232/422 module, %d ports\n", 59410015Speter unit, (int)(modp->sm_type & MMASK))); 59510015Speter 59610015Speter /* this is a firmware issue */ 59710015Speter if (si_Nports == SI_MAXPORTPERCARD) { 59810015Speter printf("si%d: extra ports ignored\n", unit); 59910015Speter continue; 60010015Speter } 60110015Speter 60210015Speter x = modp->sm_type & MMASK; 60310015Speter nport += x; 60410015Speter si_Nports += x; 60510015Speter si_Nmodules++; 60610015Speter break; 60710015Speter default: 60810015Speter printf("si%d: unknown module type %d\n", 60910015Speter unit, modp->sm_type); 61010015Speter break; 61110015Speter } 61210015Speter if (modp->sm_next == 0) 61310015Speter break; 61410015Speter modp = (struct si_module *) 61510015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 61610015Speter } 61710015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 61810015Speter M_DEVBUF, M_NOWAIT); 61910015Speter if (sc->sc_ports == 0) { 62010015Spetermem_fail: 62110015Speter printf("si%d: fail to malloc memory for port structs\n", 62210015Speter unit); 62310015Speter return 0; 62410015Speter } 62510015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 62610015Speter sc->sc_nport = nport; 62710015Speter 62810015Speter /* 62910015Speter * allocate tty structures for ports 63010015Speter */ 63110015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 63210015Speter if (tp == 0) 63310015Speter goto mem_fail; 63410015Speter bzero(tp, sizeof(*tp) * nport); 63510962Speter si_tty = tp; 63610015Speter 63710015Speter /* mark the device state as attached */ 63810015Speter si_kdc[unit].kdc_state = DC_BUSY; 63910015Speter 64010015Speter /* 64110015Speter * Scan round the ports again, this time initialising. 64210015Speter */ 64310015Speter pp = sc->sc_ports; 64410015Speter nmodule = 0; 64510015Speter modp = (struct si_module *)(maddr + 0x80); 64612174Speter uart_type = 0; 64710015Speter for (;;) { 64810015Speter switch (modp->sm_type & (~MMASK)) { 64910015Speter case M232: 65010015Speter case M422: 65110015Speter nmodule++; 65210015Speter nport = (modp->sm_type & MMASK); 65310015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 65412174Speter if (uart_type == 0) 65512174Speter uart_type = ccbp->type; 65610015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 65710015Speter pp->sp_ccb = ccbp; /* save the address */ 65810015Speter pp->sp_tty = tp++; 65910015Speter pp->sp_pend = IDLE_CLOSE; 66010015Speter pp->sp_state = 0; /* internal flag */ 66110015Speter pp->sp_dtr_wait = 3 * hz; 66210047Speter pp->sp_iin.c_iflag = si_default_iflag; 66310047Speter pp->sp_iin.c_oflag = si_default_oflag; 66410047Speter pp->sp_iin.c_cflag = si_default_cflag; 66510047Speter pp->sp_iin.c_lflag = si_default_lflag; 66610015Speter termioschars(&pp->sp_iin); 66710015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 66810047Speter si_default_rate; 66910015Speter pp->sp_iout = pp->sp_iin; 67010015Speter } 67110015Speter break; 67210015Speter default: 67310015Speter break; 67410015Speter } 67510015Speter if (modp->sm_next == 0) { 67612174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 67710015Speter unit, 67810015Speter sc->sc_typename, 67910015Speter sc->sc_nport, 68012174Speter nmodule, 68112174Speter uart_type); 68210015Speter break; 68310015Speter } 68410015Speter modp = (struct si_module *) 68510015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 68610015Speter } 68710015Speter if (done_chartimes == 0) { 68810015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 68910015Speter if ((spt->sp_code /= hz) == 0) 69010015Speter spt->sp_code = 1; 69110015Speter } 69210015Speter done_chartimes = 1; 69310015Speter } 69412502Sjulian 69512675Sjulian#ifdef DEVFS 69612675Sjulian/* path name devsw minor type uid gid perm*/ 69712675Sjulian for ( x = 0; x < nport; x++ ) { 69812675Sjulian sprintf(name,"tty%c%c",devchar[unit],portchar[x + 1]); 69912675Sjulian sc->devfs_token[x].ttyd = devfs_add_devsw( 70012675Sjulian "/", name, &si_cdevsw, unit, 70112675Sjulian DV_CHR, 0, 0, 0600); 70212675Sjulian sprintf(name,"ttyi%c%c",devchar[unit],portchar[x + 1]); 70312675Sjulian sc->devfs_token[x].ttyi = devfs_add_devsw( 70412675Sjulian "/", name, &si_cdevsw, unit + 32, 70512675Sjulian DV_CHR, 0, 0, 0600); 70612675Sjulian sprintf(name,"ttyl%c%c",devchar[unit],portchar[x + 1]); 70712675Sjulian sc->devfs_token[x].ttyl = devfs_add_devsw( 70812675Sjulian "/", name, &si_cdevsw, unit + 64, 70912675Sjulian DV_CHR, 0, 0, 0600); 71012675Sjulian sprintf(name,"cua%c%c",devchar[unit],portchar[x + 1]); 71112675Sjulian sc->devfs_token[x].cuaa = devfs_add_devsw( 71212675Sjulian "/", name, &si_cdevsw, unit + 128, 71312675Sjulian DV_CHR, 0, 0, 0600); 71412675Sjulian sprintf(name,"cuai%c%c",devchar[unit],portchar[x + 1]); 71512675Sjulian sc->devfs_token[x].cuai = devfs_add_devsw( 71612675Sjulian "/", name, &si_cdevsw, unit + 160, 71712675Sjulian DV_CHR, 0, 0, 0600); 71812675Sjulian sprintf(name,"cual%c%c",devchar[unit],portchar[x + 1]); 71912675Sjulian sc->devfs_token[x].cual = devfs_add_devsw( 72012675Sjulian "/", name, &si_cdevsw, unit + 192, 72112675Sjulian DV_CHR, 0, 0, 0600); 72212675Sjulian } 72312675Sjulian#endif 72410015Speter return (1); 72510015Speter} 72610015Speter 72712675Sjulianstatic int 72810015Spetersiopen(dev, flag, mode, p) 72910015Speter dev_t dev; 73010015Speter int flag, mode; 73110015Speter struct proc *p; 73210015Speter{ 73310015Speter int oldspl, error; 73410015Speter int card, port; 73510015Speter register struct si_softc *sc; 73610015Speter register struct tty *tp; 73710015Speter volatile struct si_channel *ccbp; 73810015Speter struct si_port *pp; 73910015Speter int mynor = minor(dev); 74010015Speter 74110015Speter /* quickly let in /dev/si_control */ 74210015Speter if (IS_CONTROLDEV(mynor)) { 74310015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 74410015Speter return(error); 74510015Speter return(0); 74610015Speter } 74710015Speter 74810015Speter card = SI_CARD(mynor); 74910015Speter if (card >= NSI) 75010015Speter return (ENXIO); 75110015Speter sc = &si_softc[card]; 75210015Speter 75312174Speter if (sc->sc_type == SIEMPTY) { 75412174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 75510015Speter card, sc->sc_typename)); 75610015Speter return(ENXIO); 75710015Speter } 75810015Speter 75910015Speter port = SI_PORT(mynor); 76010015Speter if (port >= sc->sc_nport) { 76112174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 76210015Speter card, sc->sc_nport)); 76310015Speter return(ENXIO); 76410015Speter } 76510015Speter 76610015Speter#ifdef POLL 76710015Speter /* 76810015Speter * We've now got a device, so start the poller. 76910015Speter */ 77010015Speter if (init_finished == 0) { 77110015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 77210015Speter init_finished = 1; 77310015Speter } 77410015Speter#endif 77510015Speter 77610015Speter /* initial/lock device */ 77710015Speter if (IS_STATE(mynor)) { 77810015Speter return(0); 77910015Speter } 78010015Speter 78110015Speter pp = sc->sc_ports + port; 78210015Speter tp = pp->sp_tty; /* the "real" tty */ 78310015Speter ccbp = pp->sp_ccb; /* Find control block */ 78410015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 78510015Speter dev, flag, mode, p)); 78610015Speter 78710015Speter oldspl = spltty(); /* Keep others out */ 78810015Speter error = 0; 78910015Speter 79010015Speteropen_top: 79110015Speter while (pp->sp_state & SS_DTR_OFF) { 79210015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 79310015Speter if (error != 0) 79410015Speter goto out; 79510015Speter } 79610015Speter 79710015Speter if (tp->t_state & TS_ISOPEN) { 79810015Speter /* 79910015Speter * The device is open, so everything has been initialised. 80010015Speter * handle conflicts. 80110015Speter */ 80210015Speter if (IS_CALLOUT(mynor)) { 80310015Speter if (!pp->sp_active_out) { 80410015Speter error = EBUSY; 80510015Speter goto out; 80610015Speter } 80710015Speter } else { 80810015Speter if (pp->sp_active_out) { 80910015Speter if (flag & O_NONBLOCK) { 81010015Speter error = EBUSY; 81110015Speter goto out; 81210015Speter } 81310015Speter error = tsleep(&pp->sp_active_out, 81410015Speter TTIPRI|PCATCH, "sibi", 0); 81510015Speter if (error != 0) 81610015Speter goto out; 81710015Speter goto open_top; 81810015Speter } 81910015Speter } 82010015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 82110015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 82210015Speter "already open and EXCLUSIVE set\n")); 82310015Speter error = EBUSY; 82410015Speter goto out; 82510015Speter } 82610015Speter } else { 82710015Speter /* 82810015Speter * The device isn't open, so there are no conflicts. 82910015Speter * Initialize it. Avoid sleep... :-) 83010015Speter */ 83110015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 83210015Speter tp->t_oproc = si_start; 83310015Speter tp->t_param = siparam; 83410015Speter tp->t_dev = dev; 83510015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 83610015Speter ? pp->sp_iout : pp->sp_iin; 83710015Speter 83810015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 83910015Speter 84010015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 84110015Speter 84210015Speter error = siparam(tp, &tp->t_termios); 84310015Speter 84410015Speter --pp->sp_wopeners; 84510015Speter if (error != 0) 84610015Speter goto out; 84710015Speter /* XXX: we should goto_top if siparam slept */ 84810015Speter 84910015Speter ttsetwater(tp); 85010015Speter 85110015Speter /* set initial DCD state */ 85210015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 85310015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 85410015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 85510015Speter } 85610015Speter } 85710015Speter 85810015Speter /* whoops! we beat the close! */ 85910015Speter if (pp->sp_state & SS_CLOSING) { 86010015Speter /* try and stop it from proceeding to bash the hardware */ 86110015Speter pp->sp_state &= ~SS_CLOSING; 86210015Speter } 86310015Speter 86410015Speter /* 86510015Speter * Wait for DCD if necessary 86610015Speter */ 86710015Speter if (!(tp->t_state & TS_CARR_ON) 86810015Speter && !IS_CALLOUT(mynor) 86910015Speter && !(tp->t_cflag & CLOCAL) 87010015Speter && !(flag & O_NONBLOCK)) { 87110015Speter ++pp->sp_wopeners; 87210015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 87310015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 87410015Speter --pp->sp_wopeners; 87510015Speter if (error != 0) 87610015Speter goto out; 87710015Speter goto open_top; 87810015Speter } 87910015Speter 88010015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 88110015Speter si_disc_optim(tp, &tp->t_termios, pp); 88210015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 88310015Speter pp->sp_active_out = TRUE; 88410015Speter 88510015Speter pp->sp_state |= SS_OPEN; /* made it! */ 88610015Speter 88710015Speterout: 88810015Speter splx(oldspl); 88910015Speter 89010015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 89110015Speter 89210015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 89310015Speter sihardclose(pp); 89410015Speter 89510015Speter return(error); 89610015Speter} 89710015Speter 89812675Sjulianstatic int 89910015Spetersiclose(dev, flag, mode, p) 90010015Speter dev_t dev; 90110015Speter int flag, mode; 90210015Speter struct proc *p; 90310015Speter{ 90410015Speter register struct si_port *pp; 90510015Speter register struct tty *tp; 90610015Speter int oldspl; 90710015Speter int error = 0; 90810015Speter int mynor = minor(dev); 90910015Speter 91010015Speter if (IS_SPECIAL(mynor)) 91110015Speter return(0); 91210015Speter 91310015Speter oldspl = spltty(); 91410015Speter 91510015Speter pp = MINOR2PP(mynor); 91610015Speter tp = pp->sp_tty; 91710015Speter 91810015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 91910015Speter dev, flag, mode, p, pp->sp_state)); 92010015Speter 92110015Speter /* did we sleep and loose a race? */ 92210015Speter if (pp->sp_state & SS_CLOSING) { 92310015Speter /* error = ESOMETING? */ 92410015Speter goto out; 92510015Speter } 92610015Speter 92710015Speter /* begin race detection.. */ 92810015Speter pp->sp_state |= SS_CLOSING; 92910015Speter 93010015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 93110015Speter 93210015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 93310015Speter (*linesw[tp->t_line].l_close)(tp, flag); 93410015Speter 93510015Speter si_write_enable(pp, 1); 93610015Speter 93710015Speter /* did we sleep and somebody started another open? */ 93810015Speter if (!(pp->sp_state & SS_CLOSING)) { 93910015Speter /* error = ESOMETING? */ 94010015Speter goto out; 94110015Speter } 94210015Speter /* ok. we are now still on the right track.. nuke the hardware */ 94310015Speter 94410015Speter if (pp->sp_state & SS_LSTART) { 94510015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 94610015Speter pp->sp_state &= ~SS_LSTART; 94710015Speter } 94810015Speter 94910015Speter sistop(tp, FREAD | FWRITE); 95010015Speter 95110015Speter sihardclose(pp); 95210015Speter ttyclose(tp); 95310015Speter pp->sp_state &= ~SS_OPEN; 95410015Speter 95510015Speterout: 95610015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 95710015Speter splx(oldspl); 95810015Speter return(error); 95910015Speter} 96010015Speter 96110015Speterstatic void 96210015Spetersihardclose(pp) 96310015Speter struct si_port *pp; 96410015Speter{ 96510015Speter int oldspl; 96610015Speter struct tty *tp; 96710015Speter volatile struct si_channel *ccbp; 96810015Speter 96910015Speter oldspl = spltty(); 97010015Speter 97110015Speter tp = pp->sp_tty; 97210015Speter ccbp = pp->sp_ccb; /* Find control block */ 97310015Speter if (tp->t_cflag & HUPCL 97410015Speter || !pp->sp_active_out 97510015Speter && !(ccbp->hi_ip & IP_DCD) 97610015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 97710015Speter || !(tp->t_state & TS_ISOPEN)) { 97810015Speter 97910015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 98010015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 98110015Speter 98210015Speter if (pp->sp_dtr_wait != 0) { 98310015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 98410015Speter pp->sp_state |= SS_DTR_OFF; 98510015Speter } 98610015Speter 98710015Speter } 98810015Speter pp->sp_active_out = FALSE; 98910015Speter wakeup((caddr_t)&pp->sp_active_out); 99010015Speter wakeup(TSA_CARR_ON(tp)); 99110015Speter 99210015Speter splx(oldspl); 99310015Speter} 99410015Speter 99510015Speter 99610015Speter/* 99710015Speter * called at splsoftclock()... 99810015Speter */ 99910015Speterstatic void 100010015Spetersidtrwakeup(chan) 100110015Speter void *chan; 100210015Speter{ 100310015Speter struct si_port *pp; 100410015Speter int oldspl; 100510015Speter 100610015Speter oldspl = spltty(); 100710015Speter 100810015Speter pp = (struct si_port *)chan; 100910015Speter pp->sp_state &= ~SS_DTR_OFF; 101010015Speter wakeup(&pp->sp_dtr_wait); 101110015Speter 101210015Speter splx(oldspl); 101310015Speter} 101410015Speter 101510015Speter/* 101610015Speter * User level stuff - read and write 101710015Speter */ 101812675Sjulianstatic int 101910015Spetersiread(dev, uio, flag) 102010015Speter register dev_t dev; 102110015Speter struct uio *uio; 102210015Speter int flag; 102310015Speter{ 102410015Speter register struct tty *tp; 102510015Speter int mynor = minor(dev); 102610015Speter 102710015Speter if (IS_SPECIAL(mynor)) { 102810015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 102910015Speter return(ENODEV); 103010015Speter } 103110015Speter tp = MINOR2TP(mynor); 103210015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 103310015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 103410015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 103510015Speter} 103610015Speter 103710015Speter 103812675Sjulianstatic int 103910015Spetersiwrite(dev, uio, flag) 104010015Speter dev_t dev; 104110015Speter struct uio *uio; 104210015Speter int flag; 104310015Speter{ 104410015Speter register struct si_port *pp; 104510015Speter register struct tty *tp; 104610015Speter int error = 0; 104710015Speter int mynor = minor(dev); 104810015Speter int oldspl; 104910015Speter 105010015Speter if (IS_SPECIAL(mynor)) { 105110015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 105210015Speter return(ENODEV); 105310015Speter } 105410015Speter pp = MINOR2PP(mynor); 105510015Speter tp = pp->sp_tty; 105610015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 105710015Speter 105810015Speter oldspl = spltty(); 105910015Speter /* 106010015Speter * If writes are currently blocked, wait on the "real" tty 106110015Speter */ 106210015Speter while (pp->sp_state & SS_BLOCKWRITE) { 106310015Speter pp->sp_state |= SS_WAITWRITE; 106410015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 106510015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 106610015Speter "siwrite", 0)) 106710015Speter goto out; 106810015Speter } 106910015Speter 107010015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 107110015Speterout: 107210015Speter splx(oldspl); 107310015Speter return (error); 107410015Speter} 107510015Speter 107610015Speter 107712675Sjulianstatic struct tty * 107810015Spetersidevtotty(dev_t dev) 107910015Speter{ 108010015Speter struct si_port *pp; 108110015Speter int mynor = minor(dev); 108210015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 108310015Speter 108410015Speter if (IS_SPECIAL(mynor)) 108510015Speter return(NULL); 108610015Speter if (SI_PORT(mynor) >= sc->sc_nport) 108710015Speter return(NULL); 108810015Speter pp = MINOR2PP(mynor); 108910015Speter return (pp->sp_tty); 109010015Speter} 109110015Speter 109212675Sjulianstatic int 109310015Spetersiioctl(dev, cmd, data, flag, p) 109410015Speter dev_t dev; 109510015Speter int cmd; 109610015Speter caddr_t data; 109710015Speter int flag; 109810015Speter struct proc *p; 109910015Speter{ 110010015Speter struct si_port *pp; 110110015Speter register struct tty *tp; 110210015Speter int error; 110310015Speter int mynor = minor(dev); 110410015Speter int oldspl; 110510015Speter int blocked = 0; 110610015Speter#if defined(COMPAT_43) 110710015Speter int oldcmd; 110810015Speter struct termios term; 110910015Speter#endif 111010015Speter 111110015Speter if (IS_SI_IOCTL(cmd)) 111210015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 111310015Speter 111410015Speter pp = MINOR2PP(mynor); 111510015Speter tp = pp->sp_tty; 111610015Speter 111710015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 111810015Speter dev, cmd, data, flag)); 111910015Speter if (IS_STATE(mynor)) { 112010015Speter struct termios *ct; 112110015Speter 112210015Speter switch (mynor & SI_STATE_MASK) { 112310015Speter case SI_INIT_STATE_MASK: 112410015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 112510015Speter break; 112610015Speter case SI_LOCK_STATE_MASK: 112710015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 112810015Speter break; 112910015Speter default: 113010015Speter return (ENODEV); 113110015Speter } 113210015Speter switch (cmd) { 113310015Speter case TIOCSETA: 113410015Speter error = suser(p->p_ucred, &p->p_acflag); 113510015Speter if (error != 0) 113610015Speter return (error); 113710015Speter *ct = *(struct termios *)data; 113810015Speter return (0); 113910015Speter case TIOCGETA: 114010015Speter *(struct termios *)data = *ct; 114110015Speter return (0); 114210015Speter case TIOCGETD: 114310015Speter *(int *)data = TTYDISC; 114410015Speter return (0); 114510015Speter case TIOCGWINSZ: 114610015Speter bzero(data, sizeof(struct winsize)); 114710015Speter return (0); 114810015Speter default: 114910015Speter return (ENOTTY); 115010015Speter } 115110015Speter } 115210015Speter /* 115310015Speter * Do the old-style ioctl compat routines... 115410015Speter */ 115510015Speter#if defined(COMPAT_43) 115610015Speter term = tp->t_termios; 115710015Speter oldcmd = cmd; 115810015Speter error = ttsetcompat(tp, &cmd, data, &term); 115910015Speter if (error != 0) 116010015Speter return (error); 116110015Speter if (cmd != oldcmd) 116210015Speter data = (caddr_t)&term; 116310015Speter#endif 116410015Speter /* 116510015Speter * Do the initial / lock state business 116610015Speter */ 116710015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 116810015Speter int cc; 116910015Speter struct termios *dt = (struct termios *)data; 117010015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 117110015Speter ? &pp->sp_lout : &pp->sp_lin; 117210015Speter 117310015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 117410015Speter | (dt->c_iflag & ~lt->c_iflag); 117510015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 117610015Speter | (dt->c_oflag & ~lt->c_oflag); 117710015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 117810015Speter | (dt->c_cflag & ~lt->c_cflag); 117910015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 118010015Speter | (dt->c_lflag & ~lt->c_lflag); 118110015Speter for (cc = 0; cc < NCCS; ++cc) 118210015Speter if (lt->c_cc[cc] != 0) 118310015Speter dt->c_cc[cc] = tp->t_cc[cc]; 118410015Speter if (lt->c_ispeed != 0) 118510015Speter dt->c_ispeed = tp->t_ispeed; 118610015Speter if (lt->c_ospeed != 0) 118710015Speter dt->c_ospeed = tp->t_ospeed; 118810015Speter } 118910015Speter 119010015Speter /* 119110015Speter * Block user-level writes to give the ttywait() 119210015Speter * a chance to completely drain for commands 119310015Speter * that require the port to be in a quiescent state. 119410015Speter */ 119510015Speter switch (cmd) { 119610015Speter case TIOCSETAW: case TIOCSETAF: 119710015Speter case TIOCDRAIN: case TIOCSETP: 119810015Speter blocked++; /* block writes for ttywait() and siparam() */ 119910015Speter si_write_enable(pp, 0); 120010015Speter } 120110015Speter 120210015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 120310015Speter if (error >= 0) 120410015Speter goto out; 120510015Speter 120610015Speter oldspl = spltty(); 120710015Speter 120810015Speter error = ttioctl(tp, cmd, data, flag); 120910015Speter si_disc_optim(tp, &tp->t_termios, pp); 121010015Speter if (error >= 0) 121110015Speter goto outspl; 121210015Speter 121310015Speter switch (cmd) { 121410015Speter case TIOCSBRK: 121510015Speter si_command(pp, SBREAK, SI_NOWAIT); 121610015Speter break; 121710015Speter case TIOCCBRK: 121810015Speter si_command(pp, EBREAK, SI_NOWAIT); 121910015Speter break; 122010015Speter case TIOCSDTR: 122110015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 122210015Speter break; 122310015Speter case TIOCCDTR: 122410015Speter (void) si_modem(pp, SET, 0); 122510015Speter break; 122610015Speter case TIOCMSET: 122710015Speter (void) si_modem(pp, SET, *(int *)data); 122810015Speter break; 122910015Speter case TIOCMBIS: 123010015Speter (void) si_modem(pp, BIS, *(int *)data); 123110015Speter break; 123210015Speter case TIOCMBIC: 123310015Speter (void) si_modem(pp, BIC, *(int *)data); 123410015Speter break; 123510015Speter case TIOCMGET: 123610015Speter *(int *)data = si_modem(pp, GET, 0); 123710015Speter break; 123810015Speter case TIOCMSDTRWAIT: 123910015Speter /* must be root since the wait applies to following logins */ 124010015Speter error = suser(p->p_ucred, &p->p_acflag); 124110015Speter if (error != 0) { 124210015Speter goto outspl; 124310015Speter } 124410015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 124510015Speter break; 124610015Speter case TIOCMGDTRWAIT: 124710015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 124810015Speter break; 124910015Speter 125010015Speter default: 125110015Speter error = ENOTTY; 125210015Speter } 125310015Speter error = 0; 125410015Speteroutspl: 125510015Speter splx(oldspl); 125610015Speterout: 125710015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 125810015Speter if (blocked) 125910015Speter si_write_enable(pp, 1); 126010015Speter return(error); 126110015Speter} 126210015Speter 126310015Speter/* 126410015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 126510015Speter */ 126610015Speterstatic int 126710015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 126810015Speter{ 126910015Speter struct si_softc *xsc; 127010015Speter register struct si_port *xpp; 127110015Speter volatile struct si_reg *regp; 127210015Speter struct si_tcsi *dp; 127310044Speter struct si_pstat *sps; 127411872Sphk int *ip, error = 0; 127510015Speter int oldspl; 127610015Speter int card, port; 127710015Speter int mynor = minor(dev); 127810015Speter 127910015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 128010015Speter dev, cmd, data, flag)); 128110015Speter 128210044Speter#if 1 128310044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 128410044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 128510044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 128610044Speter#endif 128710044Speter 128810015Speter if (!IS_CONTROLDEV(mynor)) { 128910015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 129010015Speter return(ENODEV); 129110015Speter } 129210015Speter 129310015Speter oldspl = spltty(); /* better safe than sorry */ 129410015Speter 129510015Speter ip = (int *)data; 129610015Speter 129710015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 129810015Speter 129910015Speter switch (cmd) { 130010015Speter case TCSIPORTS: 130110015Speter *ip = si_Nports; 130210015Speter goto out; 130310015Speter case TCSIMODULES: 130410015Speter *ip = si_Nmodules; 130510015Speter goto out; 130610015Speter case TCSISDBG_ALL: 130710015Speter SUCHECK; 130810015Speter si_debug = *ip; 130910015Speter goto out; 131010015Speter case TCSIGDBG_ALL: 131110015Speter *ip = si_debug; 131210015Speter goto out; 131310015Speter default: 131410015Speter /* 131510015Speter * Check that a controller for this port exists 131610015Speter */ 131710044Speter 131810044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 131910044Speter 132010015Speter dp = (struct si_tcsi *)data; 132110044Speter sps = (struct si_pstat *)data; 132210015Speter card = dp->tc_card; 132310015Speter xsc = &si_softc[card]; /* check.. */ 132412174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 132510015Speter error = ENOENT; 132610015Speter goto out; 132710015Speter } 132810015Speter /* 132910015Speter * And check that a port exists 133010015Speter */ 133110015Speter port = dp->tc_port; 133210015Speter if (port < 0 || port >= xsc->sc_nport) { 133310015Speter error = ENOENT; 133410015Speter goto out; 133510015Speter } 133610015Speter xpp = xsc->sc_ports + port; 133710015Speter regp = (struct si_reg *)xsc->sc_maddr; 133810015Speter } 133910015Speter 134010015Speter switch (cmd) { 134110015Speter case TCSIDEBUG: 134210015Speter#ifdef SI_DEBUG 134310015Speter SUCHECK; 134410015Speter if (xpp->sp_debug) 134510015Speter xpp->sp_debug = 0; 134610015Speter else { 134710015Speter xpp->sp_debug = DBG_ALL; 134810015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 134910015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 135010015Speter } 135110015Speter break; 135210015Speter#else 135310015Speter error = ENODEV; 135410015Speter goto out; 135510015Speter#endif 135610015Speter case TCSISDBG_LEVEL: 135710015Speter case TCSIGDBG_LEVEL: 135810015Speter#ifdef SI_DEBUG 135910015Speter if (cmd == TCSIGDBG_LEVEL) { 136010015Speter dp->tc_dbglvl = xpp->sp_debug; 136110015Speter } else { 136210015Speter SUCHECK; 136310015Speter xpp->sp_debug = dp->tc_dbglvl; 136410015Speter } 136510015Speter break; 136610015Speter#else 136710015Speter error = ENODEV; 136810015Speter goto out; 136910015Speter#endif 137010015Speter case TCSIGRXIT: 137110015Speter dp->tc_int = regp->rx_int_count; 137210015Speter break; 137310015Speter case TCSIRXIT: 137410015Speter SUCHECK; 137510015Speter regp->rx_int_count = dp->tc_int; 137610015Speter break; 137710015Speter case TCSIGIT: 137810015Speter dp->tc_int = regp->int_count; 137910015Speter break; 138010015Speter case TCSIIT: 138110015Speter SUCHECK; 138210015Speter regp->int_count = dp->tc_int; 138310015Speter break; 138410044Speter case TCSISTATE: 138510044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 138610015Speter break; 138710044Speter /* these next three use a different structure */ 138810044Speter case TCSI_PORT: 138910015Speter SUCHECK; 139010044Speter sps->tc_siport = *xpp; 139110015Speter break; 139210044Speter case TCSI_CCB: 139310044Speter SUCHECK; 139410044Speter sps->tc_ccb = *xpp->sp_ccb; 139510015Speter break; 139610044Speter case TCSI_TTY: 139710044Speter SUCHECK; 139810044Speter sps->tc_tty = *xpp->sp_tty; 139910015Speter break; 140010015Speter default: 140110015Speter error = EINVAL; 140210015Speter goto out; 140310015Speter } 140410015Speterout: 140510015Speter splx(oldspl); 140610015Speter return(error); /* success */ 140710015Speter} 140810015Speter 140910015Speter/* 141010015Speter * siparam() : Configure line params 141110015Speter * called at spltty(); 141210015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 141310015Speter * caller must arrange this if it's important.. 141410015Speter */ 141512724Sphkstatic int 141610015Spetersiparam(tp, t) 141710015Speter register struct tty *tp; 141810015Speter register struct termios *t; 141910015Speter{ 142010015Speter register struct si_port *pp = TP2PP(tp); 142110015Speter volatile struct si_channel *ccbp; 142210015Speter int oldspl, cflag, iflag, oflag, lflag; 142310015Speter int error = 0; /* shutup gcc */ 142410015Speter int ispeed = 0; /* shutup gcc */ 142510015Speter int ospeed = 0; /* shutup gcc */ 142610161Speter BYTE val; 142710015Speter 142810015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 142910015Speter cflag = t->c_cflag; 143010015Speter iflag = t->c_iflag; 143110015Speter oflag = t->c_oflag; 143210015Speter lflag = t->c_lflag; 143310044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 143410044Speter oflag, cflag, iflag, lflag)); 143510015Speter 143610015Speter 143710015Speter /* if not hung up.. */ 143810015Speter if (t->c_ospeed != 0) { 143910015Speter /* translate baud rate to firmware values */ 144010015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 144110015Speter ispeed = t->c_ispeed ? 144210015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 144310015Speter 144410015Speter /* enforce legit baud rate */ 144510015Speter if (ospeed < 0 || ispeed < 0) 144610015Speter return (EINVAL); 144710015Speter } 144810015Speter 144910015Speter 145010015Speter oldspl = spltty(); 145110015Speter 145210015Speter ccbp = pp->sp_ccb; 145310015Speter 145410161Speter /* ========== set hi_break ========== */ 145510161Speter val = 0; 145610161Speter if (iflag & IGNBRK) /* Breaks */ 145710161Speter val |= BR_IGN; 145810161Speter if (iflag & BRKINT) /* Interrupt on break? */ 145910161Speter val |= BR_INT; 146010161Speter if (iflag & PARMRK) /* Parity mark? */ 146110161Speter val |= BR_PARMRK; 146210161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 146310161Speter val |= BR_PARIGN; 146410161Speter ccbp->hi_break = val; 146510161Speter 146610161Speter /* ========== set hi_csr ========== */ 146710015Speter /* if not hung up.. */ 146810015Speter if (t->c_ospeed != 0) { 146910015Speter /* Set I/O speeds */ 147010161Speter val = (ispeed << 4) | ospeed; 147110015Speter } 147210161Speter ccbp->hi_csr = val; 147310015Speter 147410161Speter /* ========== set hi_mr2 ========== */ 147510161Speter val = 0; 147610015Speter if (cflag & CSTOPB) /* Stop bits */ 147710161Speter val |= MR2_2_STOP; 147810015Speter else 147910161Speter val |= MR2_1_STOP; 148010161Speter /* 148110161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 148210161Speter * a DCE, hence the reverse sense of RTS and CTS 148310161Speter */ 148410161Speter /* Output Flow - RTS must be raised before data can be sent */ 148510161Speter if (cflag & CCTS_OFLOW) 148610161Speter val |= MR2_RTSCONT; 148710161Speter 148810161Speter ccbp->hi_mr1 = val; 148910161Speter 149010161Speter /* ========== set hi_mr1 ========== */ 149110161Speter val = 0; 149210015Speter if (!(cflag & PARENB)) /* Parity */ 149310161Speter val |= MR1_NONE; 149410015Speter else 149510161Speter val |= MR1_WITH; 149610015Speter if (cflag & PARODD) 149710161Speter val |= MR1_ODD; 149810015Speter 149910015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 150010161Speter val |= MR1_8_BITS; 150110015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 150210161Speter val |= MR1_7_BITS; 150310015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 150410161Speter val |= MR1_6_BITS; 150510015Speter } else { /* Must be 5 */ 150610161Speter val |= MR1_5_BITS; 150710015Speter } 150810161Speter /* 150910161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 151010161Speter * a DCE, hence the reverse sense of RTS and CTS 151110161Speter */ 151210161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 151310161Speter if (cflag & CRTS_IFLOW) 151410161Speter val |= MR1_CTSCONT; 151510015Speter 151610161Speter ccbp->hi_mr1 = val; 151710161Speter 151810161Speter /* ========== set hi_mask ========== */ 151910161Speter val = 0xff; 152010161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 152110161Speter val &= 0xFF; 152210161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 152310161Speter val &= 0x7F; 152410161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 152510161Speter val &= 0x3F; 152610161Speter } else { /* Must be 5 */ 152710161Speter val &= 0x1F; 152810161Speter } 152910015Speter if (iflag & ISTRIP) 153010161Speter val &= 0x7F; 153110015Speter 153210161Speter ccbp->hi_mask = val; 153310161Speter 153410161Speter /* ========== set hi_prtcl ========== */ 153510161Speter val = 0; 153610015Speter /* Monitor DCD etc. if a modem */ 153710015Speter if (!(cflag & CLOCAL)) 153810161Speter val |= SP_DCEN; 153910161Speter if (iflag & IXANY) 154010161Speter val |= SP_TANY; 154110161Speter if (iflag & IXON) 154210161Speter val |= SP_TXEN; 154310161Speter if (iflag & IXOFF) 154410161Speter val |= SP_RXEN; 154510161Speter if (iflag & INPCK) 154610161Speter val |= SP_PAEN; 154710015Speter 154810161Speter ccbp->hi_prtcl = val; 154910161Speter 155010161Speter 155110161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 155210161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 155310015Speter ccbp->hi_txon = t->c_cc[VSTART]; 155410015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 155510015Speter 155610015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 155710015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 155810015Speter 155910161Speter /* ========== send settings to the card ========== */ 156010015Speter /* potential sleep here */ 156110015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 156210015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 156310015Speter else 156410015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 156510015Speter 156610161Speter /* ========== set DTR etc ========== */ 156710015Speter /* Hangup if ospeed == 0 */ 156810015Speter if (t->c_ospeed == 0) { 156910015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 157010015Speter } else { 157110015Speter /* 157210015Speter * If the previous speed was 0, may need to re-enable 157310015Speter * the modem signals 157410015Speter */ 157510015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 157610015Speter } 157710015Speter 157810044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 157910044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 158010015Speter 158110015Speter splx(oldspl); 158210015Speter return(error); 158310015Speter} 158410015Speter 158510015Speter/* 158610015Speter * Enable or Disable the writes to this channel... 158710015Speter * "state" -> enabled = 1; disabled = 0; 158810015Speter */ 158910015Speterstatic void 159010015Spetersi_write_enable(pp, state) 159110015Speter register struct si_port *pp; 159210015Speter int state; 159310015Speter{ 159410015Speter int oldspl; 159510015Speter 159610015Speter oldspl = spltty(); 159710015Speter 159810015Speter if (state) { 159910015Speter pp->sp_state &= ~SS_BLOCKWRITE; 160010015Speter if (pp->sp_state & SS_WAITWRITE) { 160110015Speter pp->sp_state &= ~SS_WAITWRITE; 160210015Speter /* thunder away! */ 160310015Speter wakeup((caddr_t)pp); 160410015Speter } 160510015Speter } else { 160610015Speter pp->sp_state |= SS_BLOCKWRITE; 160710015Speter } 160810015Speter 160910015Speter splx(oldspl); 161010015Speter} 161110015Speter 161210015Speter/* 161310015Speter * Set/Get state of modem control lines. 161410015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 161510015Speter * TIOCM_DTR DSR 161610015Speter * TIOCM_RTS CTS 161710015Speter */ 161810015Speterstatic int 161910015Spetersi_modem(pp, cmd, bits) 162010015Speter struct si_port *pp; 162110015Speter enum si_mctl cmd; 162210015Speter int bits; 162310015Speter{ 162410015Speter volatile struct si_channel *ccbp; 162510015Speter int x; 162610015Speter 162710015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 162810015Speter ccbp = pp->sp_ccb; /* Find channel address */ 162910015Speter switch (cmd) { 163010015Speter case GET: 163110015Speter x = ccbp->hi_ip; 163210015Speter bits = TIOCM_LE; 163310015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 163410015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 163510015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 163610015Speter if (x & IP_RI) bits |= TIOCM_RI; 163710015Speter return(bits); 163810015Speter case SET: 163910015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 164010015Speter /* fall through */ 164110015Speter case BIS: 164210015Speter x = 0; 164310015Speter if (bits & TIOCM_DTR) 164410015Speter x |= OP_DSR; 164510015Speter if (bits & TIOCM_RTS) 164610015Speter x |= OP_CTS; 164710015Speter ccbp->hi_op |= x; 164810015Speter break; 164910015Speter case BIC: 165010015Speter if (bits & TIOCM_DTR) 165110015Speter ccbp->hi_op &= ~OP_DSR; 165210015Speter if (bits & TIOCM_RTS) 165310015Speter ccbp->hi_op &= ~OP_CTS; 165410015Speter } 165510015Speter return 0; 165610015Speter} 165710015Speter 165810015Speter/* 165910015Speter * Handle change of modem state 166010015Speter */ 166110015Speterstatic void 166210015Spetersi_modem_state(pp, tp, hi_ip) 166310015Speter register struct si_port *pp; 166410015Speter register struct tty *tp; 166510015Speter register int hi_ip; 166610015Speter{ 166710015Speter /* if a modem dev */ 166810015Speter if (hi_ip & IP_DCD) { 166910015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 167010015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 167110015Speter tp->t_line)); 167210015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 167310015Speter } 167410015Speter } else { 167510015Speter if (pp->sp_last_hi_ip & IP_DCD) { 167610015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 167710015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 167810015Speter (void) si_modem(pp, SET, 0); 167910015Speter } 168010015Speter } 168110015Speter pp->sp_last_hi_ip = hi_ip; 168210015Speter 168310015Speter} 168410015Speter 168510015Speter/* 168610015Speter * Poller to catch missed interrupts. 168712174Speter * 168812496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 168912496Speter * better response. We could really use a "periodic" version timeout(). :-) 169010015Speter */ 169110015Speter#ifdef POLL 169210708Speterstatic void 169310015Spetersi_poll(void *nothing) 169410015Speter{ 169510015Speter register struct si_softc *sc; 169610015Speter register int i; 169710015Speter volatile struct si_reg *regp; 169812174Speter register struct si_port *pp; 169912174Speter int lost, oldspl, port; 170010015Speter 170110015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 170211609Speter oldspl = spltty(); 170310015Speter if (in_intr) 170410015Speter goto out; 170510015Speter lost = 0; 170610015Speter for (i=0; i<NSI; i++) { 170710015Speter sc = &si_softc[i]; 170812174Speter if (sc->sc_type == SIEMPTY) 170910015Speter continue; 171010015Speter regp = (struct si_reg *)sc->sc_maddr; 171110015Speter /* 171210015Speter * See if there has been a pending interrupt for 2 seconds 171310015Speter * or so. The test <int_scounter >= 200) won't correspond 171410015Speter * to 2 seconds if int_count gets changed. 171510015Speter */ 171610015Speter if (regp->int_pending != 0) { 171710015Speter if (regp->int_scounter >= 200 && 171810015Speter regp->initstat == 1) { 171912174Speter printf("si%d: lost intr\n", i); 172010015Speter lost++; 172110015Speter } 172210015Speter } else { 172310015Speter regp->int_scounter = 0; 172410015Speter } 172510015Speter 172612174Speter /* 172712174Speter * gripe about no input flow control.. 172812174Speter */ 172912174Speter pp = sc->sc_ports; 173012174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 173112174Speter if (pp->sp_delta_overflows > 0) { 173212174Speter printf("si%d: %d tty level buffer overflows\n", 173312174Speter i, pp->sp_delta_overflows); 173412174Speter pp->sp_delta_overflows = 0; 173512174Speter } 173612174Speter } 173710015Speter } 173810015Speter if (lost) 173910015Speter siintr(-1); /* call intr with fake vector */ 174011609Speterout: 174110015Speter splx(oldspl); 174210015Speter 174310015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 174410015Speter} 174510015Speter#endif /* ifdef POLL */ 174610015Speter 174710015Speter/* 174810015Speter * The interrupt handler polls ALL ports on ALL adapters each time 174910015Speter * it is called. 175010015Speter */ 175110015Speter 175212496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 175310015Speter 175410708Spetervoid 175511609Spetersiintr(int unit) 175610015Speter{ 175710015Speter register struct si_softc *sc; 175810015Speter 175910015Speter register struct si_port *pp; 176010015Speter volatile struct si_channel *ccbp; 176110015Speter register struct tty *tp; 176210015Speter volatile caddr_t maddr; 176311872Sphk BYTE op, ip; 176412174Speter int x, card, port, n, i, isopen; 176510015Speter volatile BYTE *z; 176610015Speter BYTE c; 176710015Speter 176811609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 176911609Speter if (in_intr) { 177011609Speter if (unit < 0) /* should never happen */ 177110708Speter return; 177212174Speter printf("si%d: Warning interrupt handler re-entered\n", 177311609Speter unit); 177410708Speter return; 177510015Speter } 177610015Speter in_intr = 1; 177710015Speter 177810015Speter /* 177910015Speter * When we get an int we poll all the channels and do ALL pending 178010015Speter * work, not just the first one we find. This allows all cards to 178110015Speter * share the same vector. 178210015Speter */ 178310015Speter for (card=0; card < NSI; card++) { 178410015Speter sc = &si_softc[card]; 178512174Speter if (sc->sc_type == SIEMPTY) 178610015Speter continue; 178712174Speter 178812174Speter /* 178912174Speter * First, clear the interrupt 179012174Speter */ 179110015Speter switch(sc->sc_type) { 179210015Speter case SIHOST : 179310015Speter maddr = sc->sc_maddr; 179410015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 179510015Speter /* flag nothing pending */ 179610015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 179710015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 179810015Speter break; 179910015Speter case SIHOST2: 180010015Speter maddr = sc->sc_maddr; 180110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180210015Speter *(maddr+SIPLIRQCLR) = 0x00; 180310015Speter *(maddr+SIPLIRQCLR) = 0x10; 180410015Speter break; 180510015Speter case SIEISA: 180610015Speter#if NEISA > 0 180710015Speter maddr = sc->sc_maddr; 180810015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180910015Speter (void)inb(sc->sc_eisa_iobase+3); 181010015Speter break; 181110015Speter#endif /* fall through if not EISA kernel */ 181210015Speter case SIEMPTY: 181310015Speter default: 181410015Speter continue; 181510015Speter } 181610015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 181710015Speter 181812174Speter /* 181912174Speter * check each port 182012174Speter */ 182112174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 182210015Speter ccbp = pp->sp_ccb; 182310015Speter tp = pp->sp_tty; 182410015Speter 182512174Speter 182610015Speter /* 182710015Speter * See if a command has completed ? 182810015Speter */ 182910015Speter if (ccbp->hi_stat != pp->sp_pend) { 183010015Speter DPRINT((pp, DBG_INTR, 183110015Speter "siintr hi_stat = 0x%x, pend = %d\n", 183210015Speter ccbp->hi_stat, pp->sp_pend)); 183310015Speter switch(pp->sp_pend) { 183410015Speter case LOPEN: 183510015Speter case MPEND: 183610015Speter case MOPEN: 183710015Speter case CONFIG: 183810015Speter pp->sp_pend = ccbp->hi_stat; 183910015Speter /* sleeping in si_command */ 184010015Speter wakeup(&pp->sp_state); 184110015Speter break; 184210015Speter default: 184310015Speter pp->sp_pend = ccbp->hi_stat; 184410015Speter } 184510015Speter } 184610015Speter 184710015Speter /* 184810015Speter * Continue on if it's closed 184910015Speter */ 185010015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 185110015Speter continue; 185210015Speter } 185310015Speter 185410015Speter /* 185510015Speter * Do modem state change if not a local device 185610015Speter */ 185710015Speter si_modem_state(pp, tp, ccbp->hi_ip); 185810015Speter 185910015Speter /* 186012174Speter * Check to see if there's we should 'receive' 186112174Speter * characters. 186212174Speter */ 186312174Speter if (tp->t_state & TS_CONNECTED && 186412174Speter tp->t_state & TS_ISOPEN) 186512174Speter isopen = 1; 186612174Speter else 186712174Speter isopen = 0; 186812174Speter 186912174Speter /* 187010015Speter * Do break processing 187110015Speter */ 187210015Speter if (ccbp->hi_state & ST_BREAK) { 187312174Speter if (isopen) { 187412174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 187510015Speter } 187610015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 187710015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 187810015Speter } 187910015Speter 188010015Speter /* 188112174Speter * Do RX stuff - if not open then dump any characters. 188212174Speter * XXX: This is VERY messy and needs to be cleaned up. 188312174Speter * 188412174Speter * XXX: can we leave data in the host adapter buffer 188512174Speter * when the clists are full? That may be dangerous 188612174Speter * if the user cannot get an interrupt signal through. 188710015Speter */ 188810015Speter 188912174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 189012174Speter 189112174Speter if (!isopen) { 189210015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 189312174Speter goto end_rx; 189412174Speter } 189510015Speter 189612174Speter /* 189712174Speter * Process read characters if not skipped above 189812174Speter */ 189912174Speter c = ccbp->hi_rxipos - ccbp->hi_rxopos; 190012174Speter if (c == 0) { 190112174Speter goto end_rx; 190212174Speter } 190310015Speter 190412174Speter op = ccbp->hi_rxopos; 190512174Speter ip = ccbp->hi_rxipos; 190612174Speter n = c & 0xff; 190712174Speter 190812174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 190910015Speter n, op, ip)); 191010015Speter 191112174Speter /* 191212174Speter * Suck characters out of host card buffer into the 191312174Speter * "input staging buffer" - so that we dont leave the 191412174Speter * host card in limbo while we're possibly echoing 191512174Speter * characters and possibly flushing input inside the 191612174Speter * ldisc l_rint() routine. 191712174Speter */ 191812496Speter if (n <= SI_BUFFERSIZE - op) { 191910015Speter 192012174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 192112174Speter z = ccbp->hi_rxbuf + op; 192212174Speter bcopy((caddr_t)z, si_rxbuf, n); 192310015Speter 192412174Speter op += n; 192512174Speter } else { 192612496Speter x = SI_BUFFERSIZE - op; 192710015Speter 192812174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 192912174Speter z = ccbp->hi_rxbuf + op; 193012174Speter bcopy((caddr_t)z, si_rxbuf, x); 193110015Speter 193212174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 193312174Speter z = ccbp->hi_rxbuf; 193412174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 193510015Speter 193612174Speter op += n; 193712174Speter } 193810015Speter 193912174Speter /* clear collected characters from buffer */ 194012174Speter ccbp->hi_rxopos = op; 194112174Speter 194212174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 194310015Speter n, op, ip)); 194410015Speter 194512174Speter /* 194612174Speter * at this point... 194712174Speter * n = number of chars placed in si_rxbuf 194812174Speter */ 194910015Speter 195012174Speter /* 195112174Speter * Avoid the grotesquely inefficient lineswitch 195212174Speter * routine (ttyinput) in "raw" mode. It usually 195312174Speter * takes about 450 instructions (that's without 195412174Speter * canonical processing or echo!). slinput is 195512174Speter * reasonably fast (usually 40 instructions 195612174Speter * plus call overhead). 195712174Speter */ 195812174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 195910015Speter 196012174Speter /* block if the driver supports it */ 196112174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 196212174Speter && (tp->t_cflag & CRTS_IFLOW 196312174Speter || tp->t_iflag & IXOFF) 196412174Speter && !(tp->t_state & TS_TBLOCK)) 196512174Speter ttyblock(tp); 196610015Speter 196712174Speter tk_nin += n; 196812174Speter tk_rawcc += n; 196912174Speter tp->t_rawcc += n; 197012174Speter 197112174Speter pp->sp_delta_overflows += 197212174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 197312174Speter 197412174Speter ttwakeup(tp); 197512174Speter if (tp->t_state & TS_TTSTOP 197612174Speter && (tp->t_iflag & IXANY 197712174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 197812174Speter tp->t_state &= ~TS_TTSTOP; 197912174Speter tp->t_lflag &= ~FLUSHO; 198012174Speter si_start(tp); 198112174Speter } 198212174Speter } else { 198312174Speter /* 198412174Speter * It'd be nice to not have to go through the 198512174Speter * function call overhead for each char here. 198612174Speter * It'd be nice to block input it, saving a 198712174Speter * loop here and the call/return overhead. 198812174Speter */ 198912174Speter for(x = 0; x < n; x++) { 199012174Speter i = si_rxbuf[x]; 199112174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 199212174Speter == -1) { 199312174Speter pp->sp_delta_overflows++; 199410015Speter } 199512174Speter /* 199612174Speter * doesn't seem to be much point doing 199712174Speter * this here.. this driver has no 199812174Speter * softtty processing! ?? 199912174Speter */ 200012174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 200112174Speter setsofttty(); 200212174Speter } 200312174Speter } 200412174Speter } 200512174Speter goto more_rx; /* try for more until RXbuf is empty */ 200610015Speter 200712174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 200810015Speter 200910015Speter /* 201010015Speter * Do TX stuff 201110015Speter */ 201210015Speter (*linesw[tp->t_line].l_start)(tp); 201310015Speter 201410015Speter } /* end of for (all ports on this controller) */ 201510015Speter } /* end of for (all controllers) */ 201610015Speter 201711609Speter in_intr = 0; 201811609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 201910015Speter} 202010015Speter 202110015Speter/* 202210015Speter * Nudge the transmitter... 202312174Speter * 202412174Speter * XXX: I inherited some funny code here. It implies the host card only 202512174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 202612174Speter * not interrupt when it's actually hits empty. In some cases, we have 202712174Speter * processes waiting for complete drain, and we need to simulate an interrupt 202812174Speter * about when we think the buffer is going to be empty (and retry if not). 202912174Speter * I really am not certain about this... I *need* the hardware manuals. 203010015Speter */ 203110015Speterstatic void 203210015Spetersi_start(tp) 203310015Speter register struct tty *tp; 203410015Speter{ 203510015Speter struct si_port *pp; 203610015Speter volatile struct si_channel *ccbp; 203710015Speter register struct clist *qp; 203810015Speter register char *dptr; 203910015Speter BYTE ipos; 204010015Speter int nchar; 204110015Speter int oldspl, count, n, amount, buffer_full; 204210015Speter int do_exitproc; 204310015Speter 204410015Speter oldspl = spltty(); 204510015Speter 204610015Speter qp = &tp->t_outq; 204710015Speter pp = TP2PP(tp); 204810015Speter 204910015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 205010015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 205110015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 205210015Speter 205310015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 205410015Speter goto out; 205510015Speter 205610015Speter do_exitproc = 0; 205710015Speter buffer_full = 0; 205810015Speter ccbp = pp->sp_ccb; 205910015Speter 206010015Speter /* 206110015Speter * Handle the case where ttywait() is called on process exit 206210015Speter * this may be BSDI specific, I dont know... 206310015Speter */ 206410015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 206510015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 206610015Speter do_exitproc++; 206710015Speter } 206810015Speter 206910015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 207010015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 207110015Speter 207210015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 207310015Speter 207410015Speter while ((nchar = qp->c_cc) > 0) { 207510015Speter if ((BYTE)count >= 255) { 207610015Speter buffer_full++; 207710015Speter break; 207810015Speter } 207910015Speter amount = min(nchar, (255 - (BYTE)count)); 208010015Speter ipos = (unsigned int)ccbp->hi_txipos; 208110015Speter /* will it fit in one lump? */ 208212496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 208310015Speter n = q_to_b(&tp->t_outq, 208410015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 208510015Speter } else { 208610015Speter n = q_to_b(&tp->t_outq, 208710015Speter (char *)&ccbp->hi_txbuf[ipos], 208812496Speter SI_BUFFERSIZE-ipos); 208912496Speter if (n == SI_BUFFERSIZE-ipos) { 209010015Speter n += q_to_b(&tp->t_outq, 209110015Speter (char *)&ccbp->hi_txbuf[0], 209212496Speter amount - (SI_BUFFERSIZE-ipos)); 209310015Speter } 209410015Speter } 209510015Speter ccbp->hi_txipos += n; 209610015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 209710015Speter } 209810015Speter 209910015Speter if (count != 0 && nchar == 0) { 210010015Speter tp->t_state |= TS_BUSY; 210110015Speter } else { 210210015Speter tp->t_state &= ~TS_BUSY; 210310015Speter } 210410015Speter 210510015Speter /* wakeup time? */ 210610015Speter ttwwakeup(tp); 210710015Speter 210810015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 210910015Speter (BYTE)count, nchar, tp->t_state)); 211010015Speter 211110015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 211210015Speter { 211310015Speter int time; 211410015Speter 211510015Speter if (do_exitproc != 0) { 211610015Speter time = hz / 10; 211710015Speter } else { 211810015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 211910015Speter 212010015Speter if (time > 0) { 212110015Speter if (time < nchar) 212210015Speter time = nchar / time; 212310015Speter else 212410015Speter time = 2; 212510015Speter } else { 212612174Speter printf("si%d: bad char time value!!\n", 212712174Speter (int)SI_CARD(tp->t_dev)); 212810015Speter goto out; 212910015Speter } 213010015Speter } 213110015Speter 213210015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 213310015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 213410015Speter } else { 213510015Speter pp->sp_state |= SS_LSTART; 213610015Speter } 213710015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 213810015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 213910015Speter } 214010015Speter 214110015Speterout: 214210015Speter splx(oldspl); 214310015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 214410015Speter} 214510015Speter 214610015Speter/* 214710015Speter * Note: called at splsoftclock from the timeout code 214810015Speter * This has to deal with two things... cause wakeups while waiting for 214910015Speter * tty drains on last process exit, and call l_start at about the right 215010015Speter * time for protocols like ppp. 215110015Speter */ 215210015Speterstatic void 215310015Spetersi_lstart(pp) 215410015Speter register struct si_port *pp; 215510015Speter{ 215610015Speter register struct tty *tp; 215710015Speter int oldspl; 215810015Speter 215910015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 216010015Speter pp, pp->sp_state)); 216110015Speter 216210015Speter oldspl = spltty(); 216310015Speter 216410015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 216510015Speter splx(oldspl); 216610015Speter return; 216710015Speter } 216810015Speter pp->sp_state &= ~SS_LSTART; 216910015Speter pp->sp_state |= SS_INLSTART; 217010015Speter 217110015Speter tp = pp->sp_tty; 217210015Speter 217310015Speter /* deal with the process exit case */ 217410015Speter ttwwakeup(tp); 217510015Speter 217612174Speter /* nudge protocols - eg: ppp */ 217710015Speter (*linesw[tp->t_line].l_start)(tp); 217810015Speter 217910015Speter pp->sp_state &= ~SS_INLSTART; 218010015Speter splx(oldspl); 218110015Speter} 218210015Speter 218310015Speter/* 218410015Speter * Stop output on a line. called at spltty(); 218510015Speter */ 218610015Spetervoid 218710015Spetersistop(tp, rw) 218810015Speter register struct tty *tp; 218910015Speter int rw; 219010015Speter{ 219110015Speter volatile struct si_channel *ccbp; 219210015Speter struct si_port *pp; 219310015Speter 219410015Speter pp = TP2PP(tp); 219510015Speter ccbp = pp->sp_ccb; 219610015Speter 219710015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 219810015Speter 219910015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 220010015Speter if (rw & FWRITE) { 220110015Speter /* what level are we meant to be flushing anyway? */ 220210015Speter if (tp->t_state & TS_BUSY) { 220310015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 220410015Speter tp->t_state &= ~TS_BUSY; 220510015Speter ttwwakeup(tp); /* Bruce???? */ 220610015Speter } 220710015Speter } 220812174Speter#if 1 /* XXX: this doesn't work right yet.. */ 220912174Speter /* XXX: this may have been failing because we used to call l_rint() 221012174Speter * while we were looping based on these two counters. Now, we collect 221112174Speter * the data and then loop stuffing it into l_rint(), making this 221212174Speter * useless. Should we cause this to blow away the staging buffer? 221312174Speter */ 221410015Speter if (rw & FREAD) { 221510015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 221610015Speter } 221710015Speter#endif 221810015Speter} 221910015Speter 222010015Speter/* 222110015Speter * Issue a command to the Z280 host card CPU. 222210015Speter */ 222310015Speter 222410015Speterstatic void 222510015Spetersi_command(pp, cmd, waitflag) 222610015Speter struct si_port *pp; /* port control block (local) */ 222710015Speter int cmd; 222810015Speter int waitflag; 222910015Speter{ 223010015Speter int oldspl; 223110015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 223210015Speter int x; 223310015Speter 223410015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 223510015Speter pp, cmd, waitflag, ccbp->hi_stat)); 223610015Speter 223710015Speter oldspl = spltty(); /* Keep others out */ 223810015Speter 223910015Speter /* wait until it's finished what it was doing.. */ 224010015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 224110015Speter x != IDLE_CLOSE && 224210015Speter x != cmd) { 224310015Speter if (in_intr) { /* Prevent sleep in intr */ 224410015Speter DPRINT((pp, DBG_PARAM, 224510015Speter "cmd intr collision - completing %d\trequested %d\n", 224610015Speter x, cmd)); 224710015Speter splx(oldspl); 224810015Speter return; 224910015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 225010015Speter "sicmd1", 1)) { 225110015Speter splx(oldspl); 225210015Speter return; 225310015Speter } 225410015Speter } 225510015Speter /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 225610015Speter 225710015Speter /* if there was a pending command, cause a state-change wakeup */ 225810015Speter if (pp->sp_pend != IDLE_OPEN) { 225910015Speter switch(pp->sp_pend) { 226010015Speter case LOPEN: 226110015Speter case MPEND: 226210015Speter case MOPEN: 226310015Speter case CONFIG: 226410015Speter wakeup(&pp->sp_state); 226510015Speter break; 226610015Speter default: 226710015Speter break; 226810015Speter } 226910015Speter } 227010015Speter 227110015Speter pp->sp_pend = cmd; /* New command pending */ 227210015Speter ccbp->hi_stat = cmd; /* Post it */ 227310015Speter 227410015Speter if (waitflag) { 227510015Speter if (in_intr) { /* If in interrupt handler */ 227610015Speter DPRINT((pp, DBG_PARAM, 227710015Speter "attempt to sleep in si_intr - cmd req %d\n", 227810015Speter cmd)); 227910015Speter splx(oldspl); 228010015Speter return; 228110015Speter } else while(ccbp->hi_stat != IDLE_OPEN) { 228210015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 228310015Speter "sicmd2", 0)) 228410015Speter break; 228510015Speter } 228610015Speter } 228710015Speter splx(oldspl); 228810015Speter} 228910015Speter 229010015Speterstatic void 229110015Spetersi_disc_optim(tp, t, pp) 229210015Speter struct tty *tp; 229310015Speter struct termios *t; 229410015Speter struct si_port *pp; 229510015Speter{ 229610015Speter /* 229710015Speter * XXX can skip a lot more cases if Smarts. Maybe 229810015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 229910015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 230010015Speter */ 230110015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 230210015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 230310015Speter && (!(t->c_iflag & PARMRK) 230410015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 230510015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 230610015Speter && linesw[tp->t_line].l_rint == ttyinput) 230710015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 230810015Speter else 230910015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 231010161Speter 231110015Speter /* 231210015Speter * Prepare to reduce input latency for packet 231310015Speter * discplines with a end of packet character. 231410015Speter */ 231510015Speter if (tp->t_line == SLIPDISC) 231610015Speter pp->sp_hotchar = 0xc0; 231710015Speter else if (tp->t_line == PPPDISC) 231810015Speter pp->sp_hotchar = 0x7e; 231910015Speter else 232010015Speter pp->sp_hotchar = 0; 232110161Speter 232210161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 232310161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 232410161Speter pp->sp_hotchar)); 232510015Speter} 232610015Speter 232710015Speter 232810015Speter#ifdef SI_DEBUG 232910015Speterstatic void 233010015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6) 233110015Speter struct si_port *pp; 233210015Speter int flags; 233310015Speter char *str; 233410015Speter int a1, a2, a3, a4, a5, a6; 233510015Speter{ 233610015Speter if ((pp == NULL && (si_debug&flags)) || 233710015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 233810015Speter if (pp != NULL) 233912496Speter printf("%ci%d(%d): ", 's', 234012174Speter (int)SI_CARD(pp->sp_tty->t_dev), 234112174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 234210015Speter printf(str, a1, a2, a3, a4, a5, a6); 234310015Speter } 234410015Speter} 234510015Speter 234610015Speterstatic char * 234710015Spetersi_mctl2str(cmd) 234810015Speter enum si_mctl cmd; 234910015Speter{ 235010015Speter switch (cmd) { 235110015Speter case GET: return("GET"); 235210015Speter case SET: return("SET"); 235310015Speter case BIS: return("BIS"); 235410015Speter case BIC: return("BIC"); 235510015Speter } 235610015Speter return("BAD"); 235710015Speter} 235812502Sjulian 235912624Speter#endif /* DEBUG */ 236012502Sjulian 236112624Speter 236212502Sjulian 236312502Sjulianstatic si_devsw_installed = 0; 236412502Sjulian 236512517Sjulianstatic void si_drvinit(void *unused) 236612502Sjulian{ 236712517Sjulian dev_t dev; 236812517Sjulian 236912502Sjulian if( ! si_devsw_installed ) { 237012675Sjulian dev = makedev(CDEV_MAJOR, 0); 237112675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 237212502Sjulian si_devsw_installed = 1; 237312517Sjulian } 237412502Sjulian} 237512517Sjulian 237612517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 237712517Sjulian 2378