si.c revision 12826
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 * 3312826Speter * $Id: si.c,v 1.28 1995/12/10 20:54:35 bde 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*/ 12712743Sbde siioctl, sistop, noreset, sidevtotty,/* si */ 12812742Sbde ttselect, nommap, 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; 16612826Speter void *cuaa; 16712675Sjulian void *ttyl; 16812675Sjulian void *ttyi; 16912675Sjulian } devfs_token[32]; /* what is the max per card? */ 17012675Sjulian#endif 17110044Speter}; 17212724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 17310044Speter 17412174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 17510015Speter# define B2000 2000 17610015Speter#endif 17710015Speterstatic struct speedtab bdrates[] = { 17810015Speter B75, CLK75, /* 0x0 */ 17910015Speter B110, CLK110, /* 0x1 */ 18010015Speter B150, CLK150, /* 0x3 */ 18110015Speter B300, CLK300, /* 0x4 */ 18210015Speter B600, CLK600, /* 0x5 */ 18310015Speter B1200, CLK1200, /* 0x6 */ 18410015Speter B2000, CLK2000, /* 0x7 */ 18510015Speter B2400, CLK2400, /* 0x8 */ 18610015Speter B4800, CLK4800, /* 0x9 */ 18710015Speter B9600, CLK9600, /* 0xb */ 18810015Speter B19200, CLK19200, /* 0xc */ 18910015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 19010015Speter B57600, CLK57600, /* 0xd */ 19110015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 19210015Speter -1, -1 19310015Speter}; 19410015Speter 19510015Speter 19610015Speter/* populated with approx character/sec rates - translated at card 19710015Speter * initialisation time to chars per tick of the clock */ 19810015Speterstatic int done_chartimes = 0; 19910015Speterstatic struct speedtab chartimes[] = { 20010015Speter B75, 8, 20110015Speter B110, 11, 20210015Speter B150, 15, 20310015Speter B300, 30, 20410015Speter B600, 60, 20510015Speter B1200, 120, 20610015Speter B2000, 200, 20710015Speter B2400, 240, 20810015Speter B4800, 480, 20910015Speter B9600, 960, 21010015Speter B19200, 1920, 21110015Speter B38400, 3840, 21210015Speter B57600, 5760, 21310015Speter B115200, 11520, 21410015Speter -1, -1 21510015Speter}; 21610015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 21710015Speter 21810047Speterstatic int si_default_rate = TTYDEF_SPEED; 21910047Speterstatic int si_default_iflag = 0; 22010047Speterstatic int si_default_oflag = 0; 22110047Speterstatic int si_default_lflag = 0; 22210047Speter#ifdef SI_DEF_HWFLOW 22310047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 22410047Speter#else 22510047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 22610047Speter#endif 22710047Speter 22810015Speter#ifdef POLL 22910015Speter#define POLL_INTERVAL (hz/2) 23010015Speterstatic int init_finished = 0; 23112174Speterstatic int fastpoll = 0; 23210015Speterstatic void si_poll __P((void *)); 23310015Speter#endif 23410015Speter 23510015Speter/* 23610015Speter * Array of adapter types and the corresponding RAM size. The order of 23710015Speter * entries here MUST match the ordinal of the adapter type. 23810015Speter */ 23910015Speterstatic char *si_type[] = { 24010015Speter "EMPTY", 24110015Speter "SIHOST", 24210015Speter "SI2", /* MCA */ 24310015Speter "SIHOST2", 24410015Speter "SIEISA", 24510015Speter}; 24610015Speter 24710015Speter 24810015Speterstatic struct kern_devconf si_kdc[NSI] = { { 24910015Speter 0, 0, 0, /* filled in by dev_attach */ 25010015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 25110015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 25210015Speter &kdc_isa0, /* parent */ 25310015Speter 0, /* parent data */ 25410015Speter DC_UNCONFIGURED, /* state */ 25510015Speter "Specialix SI/XIO Host adapter", 25610015Speter DC_CLS_SERIAL, /* class */ 25710015Speter} }; 25810015Speter 25912724Sphkstatic void 26010015Spetersi_registerdev(id) 26110015Speter struct isa_device *id; 26210015Speter{ 26310015Speter if (id->id_unit != 0) { 26410015Speter si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 26510015Speter } 26610015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 26710015Speter si_kdc[id->id_unit].kdc_isa = id; 26812174Speter si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 26910015Speter dev_attach(&si_kdc[id->id_unit]); 27010015Speter} 27110015Speter 27210015Speter/* Look for a valid board at the given mem addr */ 27312724Sphkstatic int 27410015Spetersiprobe(id) 27510015Speter struct isa_device *id; 27610015Speter{ 27710015Speter struct si_softc *sc; 27810015Speter int type; 27910015Speter u_int i, ramsize; 28010015Speter volatile BYTE was, *ux; 28110015Speter volatile unsigned char *maddr; 28210015Speter unsigned char *paddr; 28310015Speter 28410015Speter si_registerdev(id); 28510015Speter 28610015Speter maddr = id->id_maddr; /* virtual address... */ 28710015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 28810015Speter 28912496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 29012496Speter id->id_unit, id->id_maddr, paddr)); 29110015Speter 29210015Speter /* 29310015Speter * this is a lie, but it's easier than trying to handle caching 29410015Speter * and ram conflicts in the >1M and <16M region. 29510015Speter */ 29610015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 29710015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 29812174Speter printf("si%d: iomem (%lx) out of range\n", 29912174Speter id->id_unit, (long)paddr); 30010015Speter return(0); 30110015Speter } 30210015Speter 30310015Speter if (id->id_unit >= NSI) { 30410015Speter /* THIS IS IMPOSSIBLE */ 30510015Speter return(0); 30610015Speter } 30710015Speter 30810015Speter if (((u_int)paddr & 0x7fff) != 0) { 30910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 31010015Speter "si%d: iomem (%x) not on 32k boundary\n", 31110015Speter id->id_unit, paddr)); 31210015Speter return(0); 31310015Speter } 31410015Speter 31510015Speter 31610015Speter for (i=0; i < NSI; i++) { 31710015Speter if ((sc = &si_softc[i]) == NULL) 31810015Speter continue; 31910015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 32010015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 32110015Speter "si%d: iomem (%x) already configured to si%d\n", 32210015Speter id->id_unit, sc->sc_paddr, i)); 32310015Speter return(0); 32410015Speter } 32510015Speter } 32610015Speter 32710015Speter#if NEISA > 0 32810015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 32910015Speter int irq, port; 33010015Speter unsigned long base; 33110015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 33210015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 33310015Speter 33410015Speter port = id->id_iobase; 33510015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 33610015Speter irq = ((inb(port+2) >> 4) & 0xf); 33710015Speter 33810015Speter id->id_irq = eisa_irqs[irq]; 33910015Speter 34010015Speter DPRINT((0, DBG_AUTOBOOT, 34112496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 34210015Speter id->id_unit, base, irq, id->id_irq, port)); 34310015Speter 34410015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 34510015Speter goto bad_irq; 34610015Speter 34710015Speter id->id_iobase &= 0xf000; 34810015Speter id->id_iosize = 0x0fff; 34910015Speter 35010015Speter type = EISA; 35110015Speter outb(p+2, (BYTE)irq << 4); 35210015Speter 35310015Speter sc->sc_eisa_iobase = p; 35410015Speter sc->sc_eisa_irqbits = irq << 4; 35510015Speter ramsize = SIEISA_RAMSIZE; 35610015Speter goto got_card; 35710015Speter } 35810015Speter#endif 35910015Speter 36010015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 36110015Speter *maddr = 0x17; 36210015Speter if (*maddr != 0x17) { 36310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 36410015Speter "si%d: 0x17 check fail at phys 0x%x\n", 36510015Speter id->id_unit, paddr)); 36610015Speterfail: 36710015Speter return(0); 36810015Speter } 36910015Speter /* 37010015Speter * OK, now to see if whatever responded is really an SI card. 37110015Speter * Try for a MK II first (SIHOST2) 37210015Speter */ 37310015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 37410015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 37510015Speter goto try_mk1; 37610015Speter 37710015Speter /* It must be an SIHOST2 */ 37810015Speter *(maddr + SIPLRESET) = 0; 37910015Speter *(maddr + SIPLIRQCLR) = 0; 38010015Speter *(maddr + SIPLIRQSET) = 0x10; 38110015Speter type = SIHOST2; 38210015Speter ramsize = SIHOST2_RAMSIZE; 38310015Speter goto got_card; 38410015Speter 38510015Speter /* 38610015Speter * Its not a MK II, so try for a MK I (SIHOST) 38710015Speter */ 38810015Spetertry_mk1: 38910015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 39010015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 39110015Speter *(maddr+SIRAM) = 0x17; 39210015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 39310015Speter goto fail; 39410015Speter *(maddr+0x7ff8) = 0x17; 39510015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 39610015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 39710015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 39810015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 39910015Speter goto fail; 40010015Speter } 40110015Speter 40210015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 40310015Speter type = SIHOST; 40410015Speter ramsize = SIHOST_RAMSIZE; 40510015Speter 40610015Spetergot_card: 40712496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 40812496Speter id->id_unit, type)); 40910015Speter /* Try the acid test */ 41010015Speter ux = (BYTE *)(maddr + SIRAM); 41110015Speter for (i=0; i<ramsize; i++, ux++) 41210015Speter *ux = (BYTE)(i&0xff); 41310015Speter ux = (BYTE *)(maddr + SIRAM); 41410015Speter for (i=0; i<ramsize; i++, ux++) { 41510015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 41610015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 41712174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 41810015Speter id->id_unit, paddr+i, was, i&0xff)); 41910015Speter goto fail; 42010015Speter } 42110015Speter } 42210015Speter 42310015Speter /* clear out the RAM */ 42410015Speter ux = (BYTE *)(maddr + SIRAM); 42510015Speter for (i=0; i<ramsize; i++) 42610015Speter *ux++ = 0; 42710015Speter ux = (BYTE *)(maddr + SIRAM); 42810015Speter for (i=0; i<ramsize; i++) { 42910015Speter if ((was = *ux++) != 0) { 43010015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 43112174Speter "si%d: clear fail at phys 0x%x, was %x\n", 43210015Speter id->id_unit, paddr+i, was)); 43310015Speter goto fail; 43410015Speter } 43510015Speter } 43610015Speter 43710015Speter /* 43810015Speter * Success, we've found a valid board, now fill in 43910015Speter * the adapter structure. 44010015Speter */ 44110015Speter switch (type) { 44210015Speter case SIHOST2: 44310015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 44410015Speterbad_irq: 44510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 44610015Speter "si%d: bad IRQ value - %d\n", 44710015Speter id->id_unit, id->id_irq)); 44810015Speter return(0); 44910015Speter } 45010015Speter id->id_msize = SIHOST2_MEMSIZE; 45110015Speter break; 45210015Speter case SIHOST: 45310015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 45410015Speter goto bad_irq; 45510015Speter } 45610015Speter id->id_msize = SIHOST_MEMSIZE; 45710015Speter break; 45810015Speter case SIEISA: 45910015Speter id->id_msize = SIEISA_MEMSIZE; 46010015Speter break; 46110015Speter case SI2: /* MCA */ 46210015Speter default: 46310015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 46410015Speter return(0); 46510015Speter } 46610015Speter si_softc[id->id_unit].sc_type = type; 46710015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 46810015Speter return(-1); /* -1 == found */ 46910015Speter} 47010015Speter 47110015Speter/* 47210015Speter * Attach the device. Initialize the card. 47310015Speter */ 47412724Sphkstatic int 47510015Spetersiattach(id) 47610015Speter struct isa_device *id; 47710015Speter{ 47810015Speter int unit = id->id_unit; 47910015Speter struct si_softc *sc = &si_softc[unit]; 48010015Speter struct si_port *pp; 48110015Speter volatile struct si_channel *ccbp; 48210015Speter volatile struct si_reg *regp; 48310015Speter volatile caddr_t maddr; 48410015Speter struct si_module *modp; 48510015Speter struct tty *tp; 48610015Speter struct speedtab *spt; 48710015Speter int nmodule, nport, x, y; 48812174Speter int uart_type; 48912675Sjulian char name[32]; 49010015Speter 49112496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 49210015Speter 49310015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 49410015Speter sc->sc_maddr = id->id_maddr; 49510015Speter sc->sc_irq = id->id_irq; 49610015Speter 49710015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 49810015Speter 49910015Speter maddr = sc->sc_maddr; 50010015Speter 50110015Speter /* 50210015Speter * OK, now lets download the firmware and try and boot the CPU.. 50310015Speter */ 50410015Speter 50512496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 50612496Speter id->id_unit, si_dsize)); 50710015Speter bcopy(si_download, maddr, si_dsize); 50810015Speter 50910015Speter switch (sc->sc_type) { 51010015Speter case SIEISA: 51110015Speter#if NEISA > 0 51210015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 51310015Speter *(maddr+0x42) = 1; 51410015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 51510015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 51610015Speter break; 51710015Speter#endif /* fall-through if not EISA */ 51810015Speter case SI2: 51912174Speter /* 52012174Speter * must get around to converting the code for 52112174Speter * these one day, if FreeBSD ever supports it. 52212174Speter */ 52310015Speter return 0; 52410015Speter case SIHOST: 52510015Speter *(maddr+SIRESET_CL) = 0; 52610015Speter *(maddr+SIINTCL_CL) = 0; 52710015Speter break; 52810015Speter case SIHOST2: 52910015Speter *(maddr+SIPLRESET) = 0x10; 53010015Speter switch (sc->sc_irq) { 53110015Speter case IRQ11: 53210015Speter *(maddr+SIPLIRQ11) = 0x10; 53310015Speter break; 53410015Speter case IRQ12: 53510015Speter *(maddr+SIPLIRQ12) = 0x10; 53610015Speter break; 53710015Speter case IRQ15: 53810015Speter *(maddr+SIPLIRQ15) = 0x10; 53910015Speter break; 54010015Speter } 54110015Speter *(maddr+SIPLIRQCLR) = 0x10; 54210015Speter break; 54310015Speter } 54410015Speter 54510015Speter DELAY(1000000); /* wait around for a second */ 54610015Speter 54710015Speter regp = (struct si_reg *)maddr; 54810015Speter y = 0; 54910015Speter /* wait max of 5 sec for init OK */ 55010015Speter while (regp->initstat == 0 && y++ < 10) { 55110015Speter DELAY(500000); 55210015Speter } 55310015Speter switch (regp->initstat) { 55410015Speter case 0: 55510015Speter printf("si%d: startup timeout - aborting\n", unit); 55612174Speter sc->sc_type = SIEMPTY; 55710015Speter return 0; 55810015Speter case 1: 55912174Speter /* set throttle to 125 intr per second */ 56010015Speter regp->int_count = 25000; 56110015Speter /* rx intr max of 25 timer per second */ 56210015Speter regp->rx_int_count = 4; 56310015Speter regp->int_pending = 0; /* no intr pending */ 56410015Speter regp->int_scounter = 0; /* reset counter */ 56510015Speter break; 56610015Speter case 0xff: 56710015Speter /* 56810015Speter * No modules found, so give up on this one. 56910015Speter */ 57010015Speter printf("si%d: %s - no ports found\n", unit, 57110015Speter si_type[sc->sc_type]); 57210015Speter return 0; 57310015Speter default: 57410015Speter printf("si%d: Z280 version error - initstat %x\n", 57510015Speter unit, regp->initstat); 57610015Speter return 0; 57710015Speter } 57810015Speter 57910015Speter /* 58010015Speter * First time around the ports just count them in order 58110015Speter * to allocate some memory. 58210015Speter */ 58310015Speter nport = 0; 58410015Speter modp = (struct si_module *)(maddr + 0x80); 58510015Speter for (;;) { 58612174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 58710015Speter switch (modp->sm_type & (~MMASK)) { 58810015Speter case M232: 58910015Speter case M422: 59010015Speter DPRINT((0, DBG_DOWNLOAD, 59112174Speter "si%d: Found 232/422 module, %d ports\n", 59210015Speter unit, (int)(modp->sm_type & MMASK))); 59310015Speter 59410015Speter /* this is a firmware issue */ 59510015Speter if (si_Nports == SI_MAXPORTPERCARD) { 59610015Speter printf("si%d: extra ports ignored\n", unit); 59710015Speter continue; 59810015Speter } 59910015Speter 60010015Speter x = modp->sm_type & MMASK; 60110015Speter nport += x; 60210015Speter si_Nports += x; 60310015Speter si_Nmodules++; 60410015Speter break; 60510015Speter default: 60610015Speter printf("si%d: unknown module type %d\n", 60710015Speter unit, modp->sm_type); 60810015Speter break; 60910015Speter } 61010015Speter if (modp->sm_next == 0) 61110015Speter break; 61210015Speter modp = (struct si_module *) 61310015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 61410015Speter } 61510015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 61610015Speter M_DEVBUF, M_NOWAIT); 61710015Speter if (sc->sc_ports == 0) { 61810015Spetermem_fail: 61910015Speter printf("si%d: fail to malloc memory for port structs\n", 62010015Speter unit); 62110015Speter return 0; 62210015Speter } 62310015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 62410015Speter sc->sc_nport = nport; 62510015Speter 62610015Speter /* 62710015Speter * allocate tty structures for ports 62810015Speter */ 62910015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 63010015Speter if (tp == 0) 63110015Speter goto mem_fail; 63210015Speter bzero(tp, sizeof(*tp) * nport); 63310962Speter si_tty = tp; 63410015Speter 63510015Speter /* mark the device state as attached */ 63610015Speter si_kdc[unit].kdc_state = DC_BUSY; 63710015Speter 63810015Speter /* 63910015Speter * Scan round the ports again, this time initialising. 64010015Speter */ 64110015Speter pp = sc->sc_ports; 64210015Speter nmodule = 0; 64310015Speter modp = (struct si_module *)(maddr + 0x80); 64412174Speter uart_type = 0; 64510015Speter for (;;) { 64610015Speter switch (modp->sm_type & (~MMASK)) { 64710015Speter case M232: 64810015Speter case M422: 64910015Speter nmodule++; 65010015Speter nport = (modp->sm_type & MMASK); 65110015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 65212174Speter if (uart_type == 0) 65312174Speter uart_type = ccbp->type; 65410015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 65510015Speter pp->sp_ccb = ccbp; /* save the address */ 65610015Speter pp->sp_tty = tp++; 65710015Speter pp->sp_pend = IDLE_CLOSE; 65810015Speter pp->sp_state = 0; /* internal flag */ 65910015Speter pp->sp_dtr_wait = 3 * hz; 66010047Speter pp->sp_iin.c_iflag = si_default_iflag; 66110047Speter pp->sp_iin.c_oflag = si_default_oflag; 66210047Speter pp->sp_iin.c_cflag = si_default_cflag; 66310047Speter pp->sp_iin.c_lflag = si_default_lflag; 66410015Speter termioschars(&pp->sp_iin); 66510015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 66610047Speter si_default_rate; 66710015Speter pp->sp_iout = pp->sp_iin; 66810015Speter } 66910015Speter break; 67010015Speter default: 67110015Speter break; 67210015Speter } 67310015Speter if (modp->sm_next == 0) { 67412174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 67510015Speter unit, 67610015Speter sc->sc_typename, 67710015Speter sc->sc_nport, 67812174Speter nmodule, 67912174Speter uart_type); 68010015Speter break; 68110015Speter } 68210015Speter modp = (struct si_module *) 68310015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 68410015Speter } 68510015Speter if (done_chartimes == 0) { 68610015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 68710015Speter if ((spt->sp_code /= hz) == 0) 68810015Speter spt->sp_code = 1; 68910015Speter } 69010015Speter done_chartimes = 1; 69110015Speter } 69212502Sjulian 69312675Sjulian#ifdef DEVFS 69412675Sjulian/* path name devsw minor type uid gid perm*/ 69512675Sjulian for ( x = 0; x < nport; x++ ) { 69612826Speter sprintf(name,"ttyA%02d", x + 1); 69712675Sjulian sc->devfs_token[x].ttyd = devfs_add_devsw( 69812675Sjulian "/", name, &si_cdevsw, unit, 69912675Sjulian DV_CHR, 0, 0, 0600); 70012826Speter sprintf(name,"cuaA%02d", x + 1); 70112675Sjulian sc->devfs_token[x].cuaa = devfs_add_devsw( 70212675Sjulian "/", name, &si_cdevsw, unit + 128, 70312675Sjulian DV_CHR, 0, 0, 0600); 70412826Speter sprintf(name,"ttyiA%02d", x + 1); 70512826Speter sc->devfs_token[x].ttyi = devfs_add_devsw( 70612826Speter "/", name, &si_cdevsw, unit + 0x10000, 70712675Sjulian DV_CHR, 0, 0, 0600); 70812826Speter sprintf(name,"ttylA%02d", x + 1); 70912826Speter sc->devfs_token[x].ttyl = devfs_add_devsw( 71012826Speter "/", name, &si_cdevsw, unit + 0x20000, 71112675Sjulian DV_CHR, 0, 0, 0600); 71212675Sjulian } 71312826Speter /* XXX: no global yet */ 71412675Sjulian#endif 71510015Speter return (1); 71610015Speter} 71710015Speter 71812675Sjulianstatic int 71910015Spetersiopen(dev, flag, mode, p) 72010015Speter dev_t dev; 72110015Speter int flag, mode; 72210015Speter struct proc *p; 72310015Speter{ 72410015Speter int oldspl, error; 72510015Speter int card, port; 72610015Speter register struct si_softc *sc; 72710015Speter register struct tty *tp; 72810015Speter volatile struct si_channel *ccbp; 72910015Speter struct si_port *pp; 73010015Speter int mynor = minor(dev); 73110015Speter 73210015Speter /* quickly let in /dev/si_control */ 73310015Speter if (IS_CONTROLDEV(mynor)) { 73410015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 73510015Speter return(error); 73610015Speter return(0); 73710015Speter } 73810015Speter 73910015Speter card = SI_CARD(mynor); 74010015Speter if (card >= NSI) 74110015Speter return (ENXIO); 74210015Speter sc = &si_softc[card]; 74310015Speter 74412174Speter if (sc->sc_type == SIEMPTY) { 74512174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 74610015Speter card, sc->sc_typename)); 74710015Speter return(ENXIO); 74810015Speter } 74910015Speter 75010015Speter port = SI_PORT(mynor); 75110015Speter if (port >= sc->sc_nport) { 75212174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 75310015Speter card, sc->sc_nport)); 75410015Speter return(ENXIO); 75510015Speter } 75610015Speter 75710015Speter#ifdef POLL 75810015Speter /* 75910015Speter * We've now got a device, so start the poller. 76010015Speter */ 76110015Speter if (init_finished == 0) { 76210015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 76310015Speter init_finished = 1; 76410015Speter } 76510015Speter#endif 76610015Speter 76710015Speter /* initial/lock device */ 76810015Speter if (IS_STATE(mynor)) { 76910015Speter return(0); 77010015Speter } 77110015Speter 77210015Speter pp = sc->sc_ports + port; 77310015Speter tp = pp->sp_tty; /* the "real" tty */ 77410015Speter ccbp = pp->sp_ccb; /* Find control block */ 77510015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 77610015Speter dev, flag, mode, p)); 77710015Speter 77810015Speter oldspl = spltty(); /* Keep others out */ 77910015Speter error = 0; 78010015Speter 78110015Speteropen_top: 78210015Speter while (pp->sp_state & SS_DTR_OFF) { 78310015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 78410015Speter if (error != 0) 78510015Speter goto out; 78610015Speter } 78710015Speter 78810015Speter if (tp->t_state & TS_ISOPEN) { 78910015Speter /* 79010015Speter * The device is open, so everything has been initialised. 79110015Speter * handle conflicts. 79210015Speter */ 79310015Speter if (IS_CALLOUT(mynor)) { 79410015Speter if (!pp->sp_active_out) { 79510015Speter error = EBUSY; 79610015Speter goto out; 79710015Speter } 79810015Speter } else { 79910015Speter if (pp->sp_active_out) { 80010015Speter if (flag & O_NONBLOCK) { 80110015Speter error = EBUSY; 80210015Speter goto out; 80310015Speter } 80410015Speter error = tsleep(&pp->sp_active_out, 80510015Speter TTIPRI|PCATCH, "sibi", 0); 80610015Speter if (error != 0) 80710015Speter goto out; 80810015Speter goto open_top; 80910015Speter } 81010015Speter } 81110015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 81210015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 81310015Speter "already open and EXCLUSIVE set\n")); 81410015Speter error = EBUSY; 81510015Speter goto out; 81610015Speter } 81710015Speter } else { 81810015Speter /* 81910015Speter * The device isn't open, so there are no conflicts. 82010015Speter * Initialize it. Avoid sleep... :-) 82110015Speter */ 82210015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 82310015Speter tp->t_oproc = si_start; 82410015Speter tp->t_param = siparam; 82510015Speter tp->t_dev = dev; 82610015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 82710015Speter ? pp->sp_iout : pp->sp_iin; 82810015Speter 82910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 83010015Speter 83110015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 83210015Speter 83310015Speter error = siparam(tp, &tp->t_termios); 83410015Speter 83510015Speter --pp->sp_wopeners; 83610015Speter if (error != 0) 83710015Speter goto out; 83810015Speter /* XXX: we should goto_top if siparam slept */ 83910015Speter 84010015Speter ttsetwater(tp); 84110015Speter 84210015Speter /* set initial DCD state */ 84310015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 84410015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 84510015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 84610015Speter } 84710015Speter } 84810015Speter 84910015Speter /* whoops! we beat the close! */ 85010015Speter if (pp->sp_state & SS_CLOSING) { 85110015Speter /* try and stop it from proceeding to bash the hardware */ 85210015Speter pp->sp_state &= ~SS_CLOSING; 85310015Speter } 85410015Speter 85510015Speter /* 85610015Speter * Wait for DCD if necessary 85710015Speter */ 85810015Speter if (!(tp->t_state & TS_CARR_ON) 85910015Speter && !IS_CALLOUT(mynor) 86010015Speter && !(tp->t_cflag & CLOCAL) 86110015Speter && !(flag & O_NONBLOCK)) { 86210015Speter ++pp->sp_wopeners; 86310015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 86410015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 86510015Speter --pp->sp_wopeners; 86610015Speter if (error != 0) 86710015Speter goto out; 86810015Speter goto open_top; 86910015Speter } 87010015Speter 87110015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 87210015Speter si_disc_optim(tp, &tp->t_termios, pp); 87310015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 87410015Speter pp->sp_active_out = TRUE; 87510015Speter 87610015Speter pp->sp_state |= SS_OPEN; /* made it! */ 87710015Speter 87810015Speterout: 87910015Speter splx(oldspl); 88010015Speter 88110015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 88210015Speter 88310015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 88410015Speter sihardclose(pp); 88510015Speter 88610015Speter return(error); 88710015Speter} 88810015Speter 88912675Sjulianstatic int 89010015Spetersiclose(dev, flag, mode, p) 89110015Speter dev_t dev; 89210015Speter int flag, mode; 89310015Speter struct proc *p; 89410015Speter{ 89510015Speter register struct si_port *pp; 89610015Speter register struct tty *tp; 89710015Speter int oldspl; 89810015Speter int error = 0; 89910015Speter int mynor = minor(dev); 90010015Speter 90110015Speter if (IS_SPECIAL(mynor)) 90210015Speter return(0); 90310015Speter 90410015Speter oldspl = spltty(); 90510015Speter 90610015Speter pp = MINOR2PP(mynor); 90710015Speter tp = pp->sp_tty; 90810015Speter 90910015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 91010015Speter dev, flag, mode, p, pp->sp_state)); 91110015Speter 91210015Speter /* did we sleep and loose a race? */ 91310015Speter if (pp->sp_state & SS_CLOSING) { 91410015Speter /* error = ESOMETING? */ 91510015Speter goto out; 91610015Speter } 91710015Speter 91810015Speter /* begin race detection.. */ 91910015Speter pp->sp_state |= SS_CLOSING; 92010015Speter 92110015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 92210015Speter 92310015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 92410015Speter (*linesw[tp->t_line].l_close)(tp, flag); 92510015Speter 92610015Speter si_write_enable(pp, 1); 92710015Speter 92810015Speter /* did we sleep and somebody started another open? */ 92910015Speter if (!(pp->sp_state & SS_CLOSING)) { 93010015Speter /* error = ESOMETING? */ 93110015Speter goto out; 93210015Speter } 93310015Speter /* ok. we are now still on the right track.. nuke the hardware */ 93410015Speter 93510015Speter if (pp->sp_state & SS_LSTART) { 93610015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 93710015Speter pp->sp_state &= ~SS_LSTART; 93810015Speter } 93910015Speter 94010015Speter sistop(tp, FREAD | FWRITE); 94110015Speter 94210015Speter sihardclose(pp); 94310015Speter ttyclose(tp); 94410015Speter pp->sp_state &= ~SS_OPEN; 94510015Speter 94610015Speterout: 94710015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 94810015Speter splx(oldspl); 94910015Speter return(error); 95010015Speter} 95110015Speter 95210015Speterstatic void 95310015Spetersihardclose(pp) 95410015Speter struct si_port *pp; 95510015Speter{ 95610015Speter int oldspl; 95710015Speter struct tty *tp; 95810015Speter volatile struct si_channel *ccbp; 95910015Speter 96010015Speter oldspl = spltty(); 96110015Speter 96210015Speter tp = pp->sp_tty; 96310015Speter ccbp = pp->sp_ccb; /* Find control block */ 96410015Speter if (tp->t_cflag & HUPCL 96510015Speter || !pp->sp_active_out 96610015Speter && !(ccbp->hi_ip & IP_DCD) 96710015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 96810015Speter || !(tp->t_state & TS_ISOPEN)) { 96910015Speter 97010015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 97110015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 97210015Speter 97310015Speter if (pp->sp_dtr_wait != 0) { 97410015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 97510015Speter pp->sp_state |= SS_DTR_OFF; 97610015Speter } 97710015Speter 97810015Speter } 97910015Speter pp->sp_active_out = FALSE; 98010015Speter wakeup((caddr_t)&pp->sp_active_out); 98110015Speter wakeup(TSA_CARR_ON(tp)); 98210015Speter 98310015Speter splx(oldspl); 98410015Speter} 98510015Speter 98610015Speter 98710015Speter/* 98810015Speter * called at splsoftclock()... 98910015Speter */ 99010015Speterstatic void 99110015Spetersidtrwakeup(chan) 99210015Speter void *chan; 99310015Speter{ 99410015Speter struct si_port *pp; 99510015Speter int oldspl; 99610015Speter 99710015Speter oldspl = spltty(); 99810015Speter 99910015Speter pp = (struct si_port *)chan; 100010015Speter pp->sp_state &= ~SS_DTR_OFF; 100110015Speter wakeup(&pp->sp_dtr_wait); 100210015Speter 100310015Speter splx(oldspl); 100410015Speter} 100510015Speter 100610015Speter/* 100710015Speter * User level stuff - read and write 100810015Speter */ 100912675Sjulianstatic int 101010015Spetersiread(dev, uio, flag) 101110015Speter register dev_t dev; 101210015Speter struct uio *uio; 101310015Speter int flag; 101410015Speter{ 101510015Speter register struct tty *tp; 101610015Speter int mynor = minor(dev); 101710015Speter 101810015Speter if (IS_SPECIAL(mynor)) { 101910015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 102010015Speter return(ENODEV); 102110015Speter } 102210015Speter tp = MINOR2TP(mynor); 102310015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 102410015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 102510015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 102610015Speter} 102710015Speter 102810015Speter 102912675Sjulianstatic int 103010015Spetersiwrite(dev, uio, flag) 103110015Speter dev_t dev; 103210015Speter struct uio *uio; 103310015Speter int flag; 103410015Speter{ 103510015Speter register struct si_port *pp; 103610015Speter register struct tty *tp; 103710015Speter int error = 0; 103810015Speter int mynor = minor(dev); 103910015Speter int oldspl; 104010015Speter 104110015Speter if (IS_SPECIAL(mynor)) { 104210015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 104310015Speter return(ENODEV); 104410015Speter } 104510015Speter pp = MINOR2PP(mynor); 104610015Speter tp = pp->sp_tty; 104710015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 104810015Speter 104910015Speter oldspl = spltty(); 105010015Speter /* 105110015Speter * If writes are currently blocked, wait on the "real" tty 105210015Speter */ 105310015Speter while (pp->sp_state & SS_BLOCKWRITE) { 105410015Speter pp->sp_state |= SS_WAITWRITE; 105510015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 105610015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 105710015Speter "siwrite", 0)) 105810015Speter goto out; 105910015Speter } 106010015Speter 106110015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 106210015Speterout: 106310015Speter splx(oldspl); 106410015Speter return (error); 106510015Speter} 106610015Speter 106710015Speter 106812675Sjulianstatic struct tty * 106910015Spetersidevtotty(dev_t dev) 107010015Speter{ 107110015Speter struct si_port *pp; 107210015Speter int mynor = minor(dev); 107310015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 107410015Speter 107510015Speter if (IS_SPECIAL(mynor)) 107610015Speter return(NULL); 107710015Speter if (SI_PORT(mynor) >= sc->sc_nport) 107810015Speter return(NULL); 107910015Speter pp = MINOR2PP(mynor); 108010015Speter return (pp->sp_tty); 108110015Speter} 108210015Speter 108312675Sjulianstatic int 108410015Spetersiioctl(dev, cmd, data, flag, p) 108510015Speter dev_t dev; 108610015Speter int cmd; 108710015Speter caddr_t data; 108810015Speter int flag; 108910015Speter struct proc *p; 109010015Speter{ 109110015Speter struct si_port *pp; 109210015Speter register struct tty *tp; 109310015Speter int error; 109410015Speter int mynor = minor(dev); 109510015Speter int oldspl; 109610015Speter int blocked = 0; 109710015Speter#if defined(COMPAT_43) 109810015Speter int oldcmd; 109910015Speter struct termios term; 110010015Speter#endif 110110015Speter 110210015Speter if (IS_SI_IOCTL(cmd)) 110310015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 110410015Speter 110510015Speter pp = MINOR2PP(mynor); 110610015Speter tp = pp->sp_tty; 110710015Speter 110810015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 110910015Speter dev, cmd, data, flag)); 111010015Speter if (IS_STATE(mynor)) { 111110015Speter struct termios *ct; 111210015Speter 111310015Speter switch (mynor & SI_STATE_MASK) { 111410015Speter case SI_INIT_STATE_MASK: 111510015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 111610015Speter break; 111710015Speter case SI_LOCK_STATE_MASK: 111810015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 111910015Speter break; 112010015Speter default: 112110015Speter return (ENODEV); 112210015Speter } 112310015Speter switch (cmd) { 112410015Speter case TIOCSETA: 112510015Speter error = suser(p->p_ucred, &p->p_acflag); 112610015Speter if (error != 0) 112710015Speter return (error); 112810015Speter *ct = *(struct termios *)data; 112910015Speter return (0); 113010015Speter case TIOCGETA: 113110015Speter *(struct termios *)data = *ct; 113210015Speter return (0); 113310015Speter case TIOCGETD: 113410015Speter *(int *)data = TTYDISC; 113510015Speter return (0); 113610015Speter case TIOCGWINSZ: 113710015Speter bzero(data, sizeof(struct winsize)); 113810015Speter return (0); 113910015Speter default: 114010015Speter return (ENOTTY); 114110015Speter } 114210015Speter } 114310015Speter /* 114410015Speter * Do the old-style ioctl compat routines... 114510015Speter */ 114610015Speter#if defined(COMPAT_43) 114710015Speter term = tp->t_termios; 114810015Speter oldcmd = cmd; 114910015Speter error = ttsetcompat(tp, &cmd, data, &term); 115010015Speter if (error != 0) 115110015Speter return (error); 115210015Speter if (cmd != oldcmd) 115310015Speter data = (caddr_t)&term; 115410015Speter#endif 115510015Speter /* 115610015Speter * Do the initial / lock state business 115710015Speter */ 115810015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 115910015Speter int cc; 116010015Speter struct termios *dt = (struct termios *)data; 116110015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 116210015Speter ? &pp->sp_lout : &pp->sp_lin; 116310015Speter 116410015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 116510015Speter | (dt->c_iflag & ~lt->c_iflag); 116610015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 116710015Speter | (dt->c_oflag & ~lt->c_oflag); 116810015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 116910015Speter | (dt->c_cflag & ~lt->c_cflag); 117010015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 117110015Speter | (dt->c_lflag & ~lt->c_lflag); 117210015Speter for (cc = 0; cc < NCCS; ++cc) 117310015Speter if (lt->c_cc[cc] != 0) 117410015Speter dt->c_cc[cc] = tp->t_cc[cc]; 117510015Speter if (lt->c_ispeed != 0) 117610015Speter dt->c_ispeed = tp->t_ispeed; 117710015Speter if (lt->c_ospeed != 0) 117810015Speter dt->c_ospeed = tp->t_ospeed; 117910015Speter } 118010015Speter 118110015Speter /* 118210015Speter * Block user-level writes to give the ttywait() 118310015Speter * a chance to completely drain for commands 118410015Speter * that require the port to be in a quiescent state. 118510015Speter */ 118610015Speter switch (cmd) { 118710015Speter case TIOCSETAW: case TIOCSETAF: 118810015Speter case TIOCDRAIN: case TIOCSETP: 118910015Speter blocked++; /* block writes for ttywait() and siparam() */ 119010015Speter si_write_enable(pp, 0); 119110015Speter } 119210015Speter 119310015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 119410015Speter if (error >= 0) 119510015Speter goto out; 119610015Speter 119710015Speter oldspl = spltty(); 119810015Speter 119910015Speter error = ttioctl(tp, cmd, data, flag); 120010015Speter si_disc_optim(tp, &tp->t_termios, pp); 120110015Speter if (error >= 0) 120210015Speter goto outspl; 120310015Speter 120410015Speter switch (cmd) { 120510015Speter case TIOCSBRK: 120610015Speter si_command(pp, SBREAK, SI_NOWAIT); 120710015Speter break; 120810015Speter case TIOCCBRK: 120910015Speter si_command(pp, EBREAK, SI_NOWAIT); 121010015Speter break; 121110015Speter case TIOCSDTR: 121210015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 121310015Speter break; 121410015Speter case TIOCCDTR: 121510015Speter (void) si_modem(pp, SET, 0); 121610015Speter break; 121710015Speter case TIOCMSET: 121810015Speter (void) si_modem(pp, SET, *(int *)data); 121910015Speter break; 122010015Speter case TIOCMBIS: 122110015Speter (void) si_modem(pp, BIS, *(int *)data); 122210015Speter break; 122310015Speter case TIOCMBIC: 122410015Speter (void) si_modem(pp, BIC, *(int *)data); 122510015Speter break; 122610015Speter case TIOCMGET: 122710015Speter *(int *)data = si_modem(pp, GET, 0); 122810015Speter break; 122910015Speter case TIOCMSDTRWAIT: 123010015Speter /* must be root since the wait applies to following logins */ 123110015Speter error = suser(p->p_ucred, &p->p_acflag); 123210015Speter if (error != 0) { 123310015Speter goto outspl; 123410015Speter } 123510015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 123610015Speter break; 123710015Speter case TIOCMGDTRWAIT: 123810015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 123910015Speter break; 124010015Speter 124110015Speter default: 124210015Speter error = ENOTTY; 124310015Speter } 124410015Speter error = 0; 124510015Speteroutspl: 124610015Speter splx(oldspl); 124710015Speterout: 124810015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 124910015Speter if (blocked) 125010015Speter si_write_enable(pp, 1); 125110015Speter return(error); 125210015Speter} 125310015Speter 125410015Speter/* 125510015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 125610015Speter */ 125710015Speterstatic int 125810015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 125910015Speter{ 126010015Speter struct si_softc *xsc; 126110015Speter register struct si_port *xpp; 126210015Speter volatile struct si_reg *regp; 126310015Speter struct si_tcsi *dp; 126410044Speter struct si_pstat *sps; 126511872Sphk int *ip, error = 0; 126610015Speter int oldspl; 126710015Speter int card, port; 126810015Speter int mynor = minor(dev); 126910015Speter 127010015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 127110015Speter dev, cmd, data, flag)); 127210015Speter 127310044Speter#if 1 127410044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 127510044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 127610044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 127710044Speter#endif 127810044Speter 127910015Speter if (!IS_CONTROLDEV(mynor)) { 128010015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 128110015Speter return(ENODEV); 128210015Speter } 128310015Speter 128410015Speter oldspl = spltty(); /* better safe than sorry */ 128510015Speter 128610015Speter ip = (int *)data; 128710015Speter 128810015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 128910015Speter 129010015Speter switch (cmd) { 129110015Speter case TCSIPORTS: 129210015Speter *ip = si_Nports; 129310015Speter goto out; 129410015Speter case TCSIMODULES: 129510015Speter *ip = si_Nmodules; 129610015Speter goto out; 129710015Speter case TCSISDBG_ALL: 129810015Speter SUCHECK; 129910015Speter si_debug = *ip; 130010015Speter goto out; 130110015Speter case TCSIGDBG_ALL: 130210015Speter *ip = si_debug; 130310015Speter goto out; 130410015Speter default: 130510015Speter /* 130610015Speter * Check that a controller for this port exists 130710015Speter */ 130810044Speter 130910044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 131010044Speter 131110015Speter dp = (struct si_tcsi *)data; 131210044Speter sps = (struct si_pstat *)data; 131310015Speter card = dp->tc_card; 131410015Speter xsc = &si_softc[card]; /* check.. */ 131512174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 131610015Speter error = ENOENT; 131710015Speter goto out; 131810015Speter } 131910015Speter /* 132010015Speter * And check that a port exists 132110015Speter */ 132210015Speter port = dp->tc_port; 132310015Speter if (port < 0 || port >= xsc->sc_nport) { 132410015Speter error = ENOENT; 132510015Speter goto out; 132610015Speter } 132710015Speter xpp = xsc->sc_ports + port; 132810015Speter regp = (struct si_reg *)xsc->sc_maddr; 132910015Speter } 133010015Speter 133110015Speter switch (cmd) { 133210015Speter case TCSIDEBUG: 133310015Speter#ifdef SI_DEBUG 133410015Speter SUCHECK; 133510015Speter if (xpp->sp_debug) 133610015Speter xpp->sp_debug = 0; 133710015Speter else { 133810015Speter xpp->sp_debug = DBG_ALL; 133910015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 134010015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 134110015Speter } 134210015Speter break; 134310015Speter#else 134410015Speter error = ENODEV; 134510015Speter goto out; 134610015Speter#endif 134710015Speter case TCSISDBG_LEVEL: 134810015Speter case TCSIGDBG_LEVEL: 134910015Speter#ifdef SI_DEBUG 135010015Speter if (cmd == TCSIGDBG_LEVEL) { 135110015Speter dp->tc_dbglvl = xpp->sp_debug; 135210015Speter } else { 135310015Speter SUCHECK; 135410015Speter xpp->sp_debug = dp->tc_dbglvl; 135510015Speter } 135610015Speter break; 135710015Speter#else 135810015Speter error = ENODEV; 135910015Speter goto out; 136010015Speter#endif 136110015Speter case TCSIGRXIT: 136210015Speter dp->tc_int = regp->rx_int_count; 136310015Speter break; 136410015Speter case TCSIRXIT: 136510015Speter SUCHECK; 136610015Speter regp->rx_int_count = dp->tc_int; 136710015Speter break; 136810015Speter case TCSIGIT: 136910015Speter dp->tc_int = regp->int_count; 137010015Speter break; 137110015Speter case TCSIIT: 137210015Speter SUCHECK; 137310015Speter regp->int_count = dp->tc_int; 137410015Speter break; 137510044Speter case TCSISTATE: 137610044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 137710015Speter break; 137810044Speter /* these next three use a different structure */ 137910044Speter case TCSI_PORT: 138010015Speter SUCHECK; 138110044Speter sps->tc_siport = *xpp; 138210015Speter break; 138310044Speter case TCSI_CCB: 138410044Speter SUCHECK; 138510044Speter sps->tc_ccb = *xpp->sp_ccb; 138610015Speter break; 138710044Speter case TCSI_TTY: 138810044Speter SUCHECK; 138910044Speter sps->tc_tty = *xpp->sp_tty; 139010015Speter break; 139110015Speter default: 139210015Speter error = EINVAL; 139310015Speter goto out; 139410015Speter } 139510015Speterout: 139610015Speter splx(oldspl); 139710015Speter return(error); /* success */ 139810015Speter} 139910015Speter 140010015Speter/* 140110015Speter * siparam() : Configure line params 140210015Speter * called at spltty(); 140310015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 140410015Speter * caller must arrange this if it's important.. 140510015Speter */ 140612724Sphkstatic int 140710015Spetersiparam(tp, t) 140810015Speter register struct tty *tp; 140910015Speter register struct termios *t; 141010015Speter{ 141110015Speter register struct si_port *pp = TP2PP(tp); 141210015Speter volatile struct si_channel *ccbp; 141310015Speter int oldspl, cflag, iflag, oflag, lflag; 141410015Speter int error = 0; /* shutup gcc */ 141510015Speter int ispeed = 0; /* shutup gcc */ 141610015Speter int ospeed = 0; /* shutup gcc */ 141710161Speter BYTE val; 141810015Speter 141910015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 142010015Speter cflag = t->c_cflag; 142110015Speter iflag = t->c_iflag; 142210015Speter oflag = t->c_oflag; 142310015Speter lflag = t->c_lflag; 142410044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 142510044Speter oflag, cflag, iflag, lflag)); 142610015Speter 142710015Speter 142810015Speter /* if not hung up.. */ 142910015Speter if (t->c_ospeed != 0) { 143010015Speter /* translate baud rate to firmware values */ 143110015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 143210015Speter ispeed = t->c_ispeed ? 143310015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 143410015Speter 143510015Speter /* enforce legit baud rate */ 143610015Speter if (ospeed < 0 || ispeed < 0) 143710015Speter return (EINVAL); 143810015Speter } 143910015Speter 144010015Speter 144110015Speter oldspl = spltty(); 144210015Speter 144310015Speter ccbp = pp->sp_ccb; 144410015Speter 144510161Speter /* ========== set hi_break ========== */ 144610161Speter val = 0; 144710161Speter if (iflag & IGNBRK) /* Breaks */ 144810161Speter val |= BR_IGN; 144910161Speter if (iflag & BRKINT) /* Interrupt on break? */ 145010161Speter val |= BR_INT; 145110161Speter if (iflag & PARMRK) /* Parity mark? */ 145210161Speter val |= BR_PARMRK; 145310161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 145410161Speter val |= BR_PARIGN; 145510161Speter ccbp->hi_break = val; 145610161Speter 145710161Speter /* ========== set hi_csr ========== */ 145810015Speter /* if not hung up.. */ 145910015Speter if (t->c_ospeed != 0) { 146010015Speter /* Set I/O speeds */ 146110161Speter val = (ispeed << 4) | ospeed; 146210015Speter } 146310161Speter ccbp->hi_csr = val; 146410015Speter 146510161Speter /* ========== set hi_mr2 ========== */ 146610161Speter val = 0; 146710015Speter if (cflag & CSTOPB) /* Stop bits */ 146810161Speter val |= MR2_2_STOP; 146910015Speter else 147010161Speter val |= MR2_1_STOP; 147110161Speter /* 147210161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 147310161Speter * a DCE, hence the reverse sense of RTS and CTS 147410161Speter */ 147510161Speter /* Output Flow - RTS must be raised before data can be sent */ 147610161Speter if (cflag & CCTS_OFLOW) 147710161Speter val |= MR2_RTSCONT; 147810161Speter 147910161Speter ccbp->hi_mr1 = val; 148010161Speter 148110161Speter /* ========== set hi_mr1 ========== */ 148210161Speter val = 0; 148310015Speter if (!(cflag & PARENB)) /* Parity */ 148410161Speter val |= MR1_NONE; 148510015Speter else 148610161Speter val |= MR1_WITH; 148710015Speter if (cflag & PARODD) 148810161Speter val |= MR1_ODD; 148910015Speter 149010015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 149110161Speter val |= MR1_8_BITS; 149210015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 149310161Speter val |= MR1_7_BITS; 149410015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 149510161Speter val |= MR1_6_BITS; 149610015Speter } else { /* Must be 5 */ 149710161Speter val |= MR1_5_BITS; 149810015Speter } 149910161Speter /* 150010161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 150110161Speter * a DCE, hence the reverse sense of RTS and CTS 150210161Speter */ 150310161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 150410161Speter if (cflag & CRTS_IFLOW) 150510161Speter val |= MR1_CTSCONT; 150610015Speter 150710161Speter ccbp->hi_mr1 = val; 150810161Speter 150910161Speter /* ========== set hi_mask ========== */ 151010161Speter val = 0xff; 151110161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 151210161Speter val &= 0xFF; 151310161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 151410161Speter val &= 0x7F; 151510161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 151610161Speter val &= 0x3F; 151710161Speter } else { /* Must be 5 */ 151810161Speter val &= 0x1F; 151910161Speter } 152010015Speter if (iflag & ISTRIP) 152110161Speter val &= 0x7F; 152210015Speter 152310161Speter ccbp->hi_mask = val; 152410161Speter 152510161Speter /* ========== set hi_prtcl ========== */ 152610161Speter val = 0; 152710015Speter /* Monitor DCD etc. if a modem */ 152810015Speter if (!(cflag & CLOCAL)) 152910161Speter val |= SP_DCEN; 153010161Speter if (iflag & IXANY) 153110161Speter val |= SP_TANY; 153210161Speter if (iflag & IXON) 153310161Speter val |= SP_TXEN; 153410161Speter if (iflag & IXOFF) 153510161Speter val |= SP_RXEN; 153610161Speter if (iflag & INPCK) 153710161Speter val |= SP_PAEN; 153810015Speter 153910161Speter ccbp->hi_prtcl = val; 154010161Speter 154110161Speter 154210161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 154310161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 154410015Speter ccbp->hi_txon = t->c_cc[VSTART]; 154510015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 154610015Speter 154710015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 154810015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 154910015Speter 155010161Speter /* ========== send settings to the card ========== */ 155110015Speter /* potential sleep here */ 155210015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 155310015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 155410015Speter else 155510015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 155610015Speter 155710161Speter /* ========== set DTR etc ========== */ 155810015Speter /* Hangup if ospeed == 0 */ 155910015Speter if (t->c_ospeed == 0) { 156010015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 156110015Speter } else { 156210015Speter /* 156310015Speter * If the previous speed was 0, may need to re-enable 156410015Speter * the modem signals 156510015Speter */ 156610015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 156710015Speter } 156810015Speter 156910044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 157010044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 157110015Speter 157210015Speter splx(oldspl); 157310015Speter return(error); 157410015Speter} 157510015Speter 157610015Speter/* 157710015Speter * Enable or Disable the writes to this channel... 157810015Speter * "state" -> enabled = 1; disabled = 0; 157910015Speter */ 158010015Speterstatic void 158110015Spetersi_write_enable(pp, state) 158210015Speter register struct si_port *pp; 158310015Speter int state; 158410015Speter{ 158510015Speter int oldspl; 158610015Speter 158710015Speter oldspl = spltty(); 158810015Speter 158910015Speter if (state) { 159010015Speter pp->sp_state &= ~SS_BLOCKWRITE; 159110015Speter if (pp->sp_state & SS_WAITWRITE) { 159210015Speter pp->sp_state &= ~SS_WAITWRITE; 159310015Speter /* thunder away! */ 159410015Speter wakeup((caddr_t)pp); 159510015Speter } 159610015Speter } else { 159710015Speter pp->sp_state |= SS_BLOCKWRITE; 159810015Speter } 159910015Speter 160010015Speter splx(oldspl); 160110015Speter} 160210015Speter 160310015Speter/* 160410015Speter * Set/Get state of modem control lines. 160510015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 160610015Speter * TIOCM_DTR DSR 160710015Speter * TIOCM_RTS CTS 160810015Speter */ 160910015Speterstatic int 161010015Spetersi_modem(pp, cmd, bits) 161110015Speter struct si_port *pp; 161210015Speter enum si_mctl cmd; 161310015Speter int bits; 161410015Speter{ 161510015Speter volatile struct si_channel *ccbp; 161610015Speter int x; 161710015Speter 161810015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 161910015Speter ccbp = pp->sp_ccb; /* Find channel address */ 162010015Speter switch (cmd) { 162110015Speter case GET: 162210015Speter x = ccbp->hi_ip; 162310015Speter bits = TIOCM_LE; 162410015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 162510015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 162610015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 162710015Speter if (x & IP_RI) bits |= TIOCM_RI; 162810015Speter return(bits); 162910015Speter case SET: 163010015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 163110015Speter /* fall through */ 163210015Speter case BIS: 163310015Speter x = 0; 163410015Speter if (bits & TIOCM_DTR) 163510015Speter x |= OP_DSR; 163610015Speter if (bits & TIOCM_RTS) 163710015Speter x |= OP_CTS; 163810015Speter ccbp->hi_op |= x; 163910015Speter break; 164010015Speter case BIC: 164110015Speter if (bits & TIOCM_DTR) 164210015Speter ccbp->hi_op &= ~OP_DSR; 164310015Speter if (bits & TIOCM_RTS) 164410015Speter ccbp->hi_op &= ~OP_CTS; 164510015Speter } 164610015Speter return 0; 164710015Speter} 164810015Speter 164910015Speter/* 165010015Speter * Handle change of modem state 165110015Speter */ 165210015Speterstatic void 165310015Spetersi_modem_state(pp, tp, hi_ip) 165410015Speter register struct si_port *pp; 165510015Speter register struct tty *tp; 165610015Speter register int hi_ip; 165710015Speter{ 165810015Speter /* if a modem dev */ 165910015Speter if (hi_ip & IP_DCD) { 166010015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 166110015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 166210015Speter tp->t_line)); 166310015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 166410015Speter } 166510015Speter } else { 166610015Speter if (pp->sp_last_hi_ip & IP_DCD) { 166710015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 166810015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 166910015Speter (void) si_modem(pp, SET, 0); 167010015Speter } 167110015Speter } 167210015Speter pp->sp_last_hi_ip = hi_ip; 167310015Speter 167410015Speter} 167510015Speter 167610015Speter/* 167710015Speter * Poller to catch missed interrupts. 167812174Speter * 167912496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 168012496Speter * better response. We could really use a "periodic" version timeout(). :-) 168110015Speter */ 168210015Speter#ifdef POLL 168310708Speterstatic void 168410015Spetersi_poll(void *nothing) 168510015Speter{ 168610015Speter register struct si_softc *sc; 168710015Speter register int i; 168810015Speter volatile struct si_reg *regp; 168912174Speter register struct si_port *pp; 169012174Speter int lost, oldspl, port; 169110015Speter 169210015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 169311609Speter oldspl = spltty(); 169410015Speter if (in_intr) 169510015Speter goto out; 169610015Speter lost = 0; 169710015Speter for (i=0; i<NSI; i++) { 169810015Speter sc = &si_softc[i]; 169912174Speter if (sc->sc_type == SIEMPTY) 170010015Speter continue; 170110015Speter regp = (struct si_reg *)sc->sc_maddr; 170210015Speter /* 170310015Speter * See if there has been a pending interrupt for 2 seconds 170410015Speter * or so. The test <int_scounter >= 200) won't correspond 170510015Speter * to 2 seconds if int_count gets changed. 170610015Speter */ 170710015Speter if (regp->int_pending != 0) { 170810015Speter if (regp->int_scounter >= 200 && 170910015Speter regp->initstat == 1) { 171012174Speter printf("si%d: lost intr\n", i); 171110015Speter lost++; 171210015Speter } 171310015Speter } else { 171410015Speter regp->int_scounter = 0; 171510015Speter } 171610015Speter 171712174Speter /* 171812174Speter * gripe about no input flow control.. 171912174Speter */ 172012174Speter pp = sc->sc_ports; 172112174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 172212174Speter if (pp->sp_delta_overflows > 0) { 172312174Speter printf("si%d: %d tty level buffer overflows\n", 172412174Speter i, pp->sp_delta_overflows); 172512174Speter pp->sp_delta_overflows = 0; 172612174Speter } 172712174Speter } 172810015Speter } 172910015Speter if (lost) 173010015Speter siintr(-1); /* call intr with fake vector */ 173111609Speterout: 173210015Speter splx(oldspl); 173310015Speter 173410015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 173510015Speter} 173610015Speter#endif /* ifdef POLL */ 173710015Speter 173810015Speter/* 173910015Speter * The interrupt handler polls ALL ports on ALL adapters each time 174010015Speter * it is called. 174110015Speter */ 174210015Speter 174312496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 174410015Speter 174510708Spetervoid 174611609Spetersiintr(int unit) 174710015Speter{ 174810015Speter register struct si_softc *sc; 174910015Speter 175010015Speter register struct si_port *pp; 175110015Speter volatile struct si_channel *ccbp; 175210015Speter register struct tty *tp; 175310015Speter volatile caddr_t maddr; 175411872Sphk BYTE op, ip; 175512174Speter int x, card, port, n, i, isopen; 175610015Speter volatile BYTE *z; 175710015Speter BYTE c; 175810015Speter 175911609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 176011609Speter if (in_intr) { 176111609Speter if (unit < 0) /* should never happen */ 176210708Speter return; 176312174Speter printf("si%d: Warning interrupt handler re-entered\n", 176411609Speter unit); 176510708Speter return; 176610015Speter } 176710015Speter in_intr = 1; 176810015Speter 176910015Speter /* 177010015Speter * When we get an int we poll all the channels and do ALL pending 177110015Speter * work, not just the first one we find. This allows all cards to 177210015Speter * share the same vector. 177310015Speter */ 177410015Speter for (card=0; card < NSI; card++) { 177510015Speter sc = &si_softc[card]; 177612174Speter if (sc->sc_type == SIEMPTY) 177710015Speter continue; 177812174Speter 177912174Speter /* 178012174Speter * First, clear the interrupt 178112174Speter */ 178210015Speter switch(sc->sc_type) { 178310015Speter case SIHOST : 178410015Speter maddr = sc->sc_maddr; 178510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 178610015Speter /* flag nothing pending */ 178710015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 178810015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 178910015Speter break; 179010015Speter case SIHOST2: 179110015Speter maddr = sc->sc_maddr; 179210015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 179310015Speter *(maddr+SIPLIRQCLR) = 0x00; 179410015Speter *(maddr+SIPLIRQCLR) = 0x10; 179510015Speter break; 179610015Speter case SIEISA: 179710015Speter#if NEISA > 0 179810015Speter maddr = sc->sc_maddr; 179910015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180010015Speter (void)inb(sc->sc_eisa_iobase+3); 180110015Speter break; 180210015Speter#endif /* fall through if not EISA kernel */ 180310015Speter case SIEMPTY: 180410015Speter default: 180510015Speter continue; 180610015Speter } 180710015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 180810015Speter 180912174Speter /* 181012174Speter * check each port 181112174Speter */ 181212174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 181310015Speter ccbp = pp->sp_ccb; 181410015Speter tp = pp->sp_tty; 181510015Speter 181612174Speter 181710015Speter /* 181810015Speter * See if a command has completed ? 181910015Speter */ 182010015Speter if (ccbp->hi_stat != pp->sp_pend) { 182110015Speter DPRINT((pp, DBG_INTR, 182210015Speter "siintr hi_stat = 0x%x, pend = %d\n", 182310015Speter ccbp->hi_stat, pp->sp_pend)); 182410015Speter switch(pp->sp_pend) { 182510015Speter case LOPEN: 182610015Speter case MPEND: 182710015Speter case MOPEN: 182810015Speter case CONFIG: 182910015Speter pp->sp_pend = ccbp->hi_stat; 183010015Speter /* sleeping in si_command */ 183110015Speter wakeup(&pp->sp_state); 183210015Speter break; 183310015Speter default: 183410015Speter pp->sp_pend = ccbp->hi_stat; 183510015Speter } 183610015Speter } 183710015Speter 183810015Speter /* 183910015Speter * Continue on if it's closed 184010015Speter */ 184110015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 184210015Speter continue; 184310015Speter } 184410015Speter 184510015Speter /* 184610015Speter * Do modem state change if not a local device 184710015Speter */ 184810015Speter si_modem_state(pp, tp, ccbp->hi_ip); 184910015Speter 185010015Speter /* 185112174Speter * Check to see if there's we should 'receive' 185212174Speter * characters. 185312174Speter */ 185412174Speter if (tp->t_state & TS_CONNECTED && 185512174Speter tp->t_state & TS_ISOPEN) 185612174Speter isopen = 1; 185712174Speter else 185812174Speter isopen = 0; 185912174Speter 186012174Speter /* 186110015Speter * Do break processing 186210015Speter */ 186310015Speter if (ccbp->hi_state & ST_BREAK) { 186412174Speter if (isopen) { 186512174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 186610015Speter } 186710015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 186810015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 186910015Speter } 187010015Speter 187110015Speter /* 187212174Speter * Do RX stuff - if not open then dump any characters. 187312174Speter * XXX: This is VERY messy and needs to be cleaned up. 187412174Speter * 187512174Speter * XXX: can we leave data in the host adapter buffer 187612174Speter * when the clists are full? That may be dangerous 187712174Speter * if the user cannot get an interrupt signal through. 187810015Speter */ 187910015Speter 188012174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 188112174Speter 188212174Speter if (!isopen) { 188310015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 188412174Speter goto end_rx; 188512174Speter } 188610015Speter 188712174Speter /* 188812174Speter * Process read characters if not skipped above 188912174Speter */ 189012174Speter c = ccbp->hi_rxipos - ccbp->hi_rxopos; 189112174Speter if (c == 0) { 189212174Speter goto end_rx; 189312174Speter } 189410015Speter 189512174Speter op = ccbp->hi_rxopos; 189612174Speter ip = ccbp->hi_rxipos; 189712174Speter n = c & 0xff; 189812174Speter 189912174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 190010015Speter n, op, ip)); 190110015Speter 190212174Speter /* 190312174Speter * Suck characters out of host card buffer into the 190412174Speter * "input staging buffer" - so that we dont leave the 190512174Speter * host card in limbo while we're possibly echoing 190612174Speter * characters and possibly flushing input inside the 190712174Speter * ldisc l_rint() routine. 190812174Speter */ 190912496Speter if (n <= SI_BUFFERSIZE - op) { 191010015Speter 191112174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 191212174Speter z = ccbp->hi_rxbuf + op; 191312174Speter bcopy((caddr_t)z, si_rxbuf, n); 191410015Speter 191512174Speter op += n; 191612174Speter } else { 191712496Speter x = SI_BUFFERSIZE - op; 191810015Speter 191912174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 192012174Speter z = ccbp->hi_rxbuf + op; 192112174Speter bcopy((caddr_t)z, si_rxbuf, x); 192210015Speter 192312174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 192412174Speter z = ccbp->hi_rxbuf; 192512174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 192610015Speter 192712174Speter op += n; 192812174Speter } 192910015Speter 193012174Speter /* clear collected characters from buffer */ 193112174Speter ccbp->hi_rxopos = op; 193212174Speter 193312174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 193410015Speter n, op, ip)); 193510015Speter 193612174Speter /* 193712174Speter * at this point... 193812174Speter * n = number of chars placed in si_rxbuf 193912174Speter */ 194010015Speter 194112174Speter /* 194212174Speter * Avoid the grotesquely inefficient lineswitch 194312174Speter * routine (ttyinput) in "raw" mode. It usually 194412174Speter * takes about 450 instructions (that's without 194512174Speter * canonical processing or echo!). slinput is 194612174Speter * reasonably fast (usually 40 instructions 194712174Speter * plus call overhead). 194812174Speter */ 194912174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 195010015Speter 195112174Speter /* block if the driver supports it */ 195212174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 195312174Speter && (tp->t_cflag & CRTS_IFLOW 195412174Speter || tp->t_iflag & IXOFF) 195512174Speter && !(tp->t_state & TS_TBLOCK)) 195612174Speter ttyblock(tp); 195710015Speter 195812174Speter tk_nin += n; 195912174Speter tk_rawcc += n; 196012174Speter tp->t_rawcc += n; 196112174Speter 196212174Speter pp->sp_delta_overflows += 196312174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 196412174Speter 196512174Speter ttwakeup(tp); 196612174Speter if (tp->t_state & TS_TTSTOP 196712174Speter && (tp->t_iflag & IXANY 196812174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 196912174Speter tp->t_state &= ~TS_TTSTOP; 197012174Speter tp->t_lflag &= ~FLUSHO; 197112174Speter si_start(tp); 197212174Speter } 197312174Speter } else { 197412174Speter /* 197512174Speter * It'd be nice to not have to go through the 197612174Speter * function call overhead for each char here. 197712174Speter * It'd be nice to block input it, saving a 197812174Speter * loop here and the call/return overhead. 197912174Speter */ 198012174Speter for(x = 0; x < n; x++) { 198112174Speter i = si_rxbuf[x]; 198212174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 198312174Speter == -1) { 198412174Speter pp->sp_delta_overflows++; 198510015Speter } 198612174Speter /* 198712174Speter * doesn't seem to be much point doing 198812174Speter * this here.. this driver has no 198912174Speter * softtty processing! ?? 199012174Speter */ 199112174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 199212174Speter setsofttty(); 199312174Speter } 199412174Speter } 199512174Speter } 199612174Speter goto more_rx; /* try for more until RXbuf is empty */ 199710015Speter 199812174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 199910015Speter 200010015Speter /* 200110015Speter * Do TX stuff 200210015Speter */ 200310015Speter (*linesw[tp->t_line].l_start)(tp); 200410015Speter 200510015Speter } /* end of for (all ports on this controller) */ 200610015Speter } /* end of for (all controllers) */ 200710015Speter 200811609Speter in_intr = 0; 200911609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 201010015Speter} 201110015Speter 201210015Speter/* 201310015Speter * Nudge the transmitter... 201412174Speter * 201512174Speter * XXX: I inherited some funny code here. It implies the host card only 201612174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 201712174Speter * not interrupt when it's actually hits empty. In some cases, we have 201812174Speter * processes waiting for complete drain, and we need to simulate an interrupt 201912174Speter * about when we think the buffer is going to be empty (and retry if not). 202012174Speter * I really am not certain about this... I *need* the hardware manuals. 202110015Speter */ 202210015Speterstatic void 202310015Spetersi_start(tp) 202410015Speter register struct tty *tp; 202510015Speter{ 202610015Speter struct si_port *pp; 202710015Speter volatile struct si_channel *ccbp; 202810015Speter register struct clist *qp; 202910015Speter register char *dptr; 203010015Speter BYTE ipos; 203110015Speter int nchar; 203210015Speter int oldspl, count, n, amount, buffer_full; 203310015Speter int do_exitproc; 203410015Speter 203510015Speter oldspl = spltty(); 203610015Speter 203710015Speter qp = &tp->t_outq; 203810015Speter pp = TP2PP(tp); 203910015Speter 204010015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 204110015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 204210015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 204310015Speter 204410015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 204510015Speter goto out; 204610015Speter 204710015Speter do_exitproc = 0; 204810015Speter buffer_full = 0; 204910015Speter ccbp = pp->sp_ccb; 205010015Speter 205110015Speter /* 205210015Speter * Handle the case where ttywait() is called on process exit 205310015Speter * this may be BSDI specific, I dont know... 205410015Speter */ 205510015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 205610015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 205710015Speter do_exitproc++; 205810015Speter } 205910015Speter 206010015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 206110015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 206210015Speter 206310015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 206410015Speter 206510015Speter while ((nchar = qp->c_cc) > 0) { 206610015Speter if ((BYTE)count >= 255) { 206710015Speter buffer_full++; 206810015Speter break; 206910015Speter } 207010015Speter amount = min(nchar, (255 - (BYTE)count)); 207110015Speter ipos = (unsigned int)ccbp->hi_txipos; 207210015Speter /* will it fit in one lump? */ 207312496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 207410015Speter n = q_to_b(&tp->t_outq, 207510015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 207610015Speter } else { 207710015Speter n = q_to_b(&tp->t_outq, 207810015Speter (char *)&ccbp->hi_txbuf[ipos], 207912496Speter SI_BUFFERSIZE-ipos); 208012496Speter if (n == SI_BUFFERSIZE-ipos) { 208110015Speter n += q_to_b(&tp->t_outq, 208210015Speter (char *)&ccbp->hi_txbuf[0], 208312496Speter amount - (SI_BUFFERSIZE-ipos)); 208410015Speter } 208510015Speter } 208610015Speter ccbp->hi_txipos += n; 208710015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 208810015Speter } 208910015Speter 209010015Speter if (count != 0 && nchar == 0) { 209110015Speter tp->t_state |= TS_BUSY; 209210015Speter } else { 209310015Speter tp->t_state &= ~TS_BUSY; 209410015Speter } 209510015Speter 209610015Speter /* wakeup time? */ 209710015Speter ttwwakeup(tp); 209810015Speter 209910015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 210010015Speter (BYTE)count, nchar, tp->t_state)); 210110015Speter 210210015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 210310015Speter { 210410015Speter int time; 210510015Speter 210610015Speter if (do_exitproc != 0) { 210710015Speter time = hz / 10; 210810015Speter } else { 210910015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 211010015Speter 211110015Speter if (time > 0) { 211210015Speter if (time < nchar) 211310015Speter time = nchar / time; 211410015Speter else 211510015Speter time = 2; 211610015Speter } else { 211712174Speter printf("si%d: bad char time value!!\n", 211812174Speter (int)SI_CARD(tp->t_dev)); 211910015Speter goto out; 212010015Speter } 212110015Speter } 212210015Speter 212310015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 212410015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 212510015Speter } else { 212610015Speter pp->sp_state |= SS_LSTART; 212710015Speter } 212810015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 212910015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 213010015Speter } 213110015Speter 213210015Speterout: 213310015Speter splx(oldspl); 213410015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 213510015Speter} 213610015Speter 213710015Speter/* 213810015Speter * Note: called at splsoftclock from the timeout code 213910015Speter * This has to deal with two things... cause wakeups while waiting for 214010015Speter * tty drains on last process exit, and call l_start at about the right 214110015Speter * time for protocols like ppp. 214210015Speter */ 214310015Speterstatic void 214410015Spetersi_lstart(pp) 214510015Speter register struct si_port *pp; 214610015Speter{ 214710015Speter register struct tty *tp; 214810015Speter int oldspl; 214910015Speter 215010015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 215110015Speter pp, pp->sp_state)); 215210015Speter 215310015Speter oldspl = spltty(); 215410015Speter 215510015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 215610015Speter splx(oldspl); 215710015Speter return; 215810015Speter } 215910015Speter pp->sp_state &= ~SS_LSTART; 216010015Speter pp->sp_state |= SS_INLSTART; 216110015Speter 216210015Speter tp = pp->sp_tty; 216310015Speter 216410015Speter /* deal with the process exit case */ 216510015Speter ttwwakeup(tp); 216610015Speter 216712174Speter /* nudge protocols - eg: ppp */ 216810015Speter (*linesw[tp->t_line].l_start)(tp); 216910015Speter 217010015Speter pp->sp_state &= ~SS_INLSTART; 217110015Speter splx(oldspl); 217210015Speter} 217310015Speter 217410015Speter/* 217510015Speter * Stop output on a line. called at spltty(); 217610015Speter */ 217710015Spetervoid 217810015Spetersistop(tp, rw) 217910015Speter register struct tty *tp; 218010015Speter int rw; 218110015Speter{ 218210015Speter volatile struct si_channel *ccbp; 218310015Speter struct si_port *pp; 218410015Speter 218510015Speter pp = TP2PP(tp); 218610015Speter ccbp = pp->sp_ccb; 218710015Speter 218810015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 218910015Speter 219010015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 219110015Speter if (rw & FWRITE) { 219210015Speter /* what level are we meant to be flushing anyway? */ 219310015Speter if (tp->t_state & TS_BUSY) { 219410015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 219510015Speter tp->t_state &= ~TS_BUSY; 219610015Speter ttwwakeup(tp); /* Bruce???? */ 219710015Speter } 219810015Speter } 219912174Speter#if 1 /* XXX: this doesn't work right yet.. */ 220012174Speter /* XXX: this may have been failing because we used to call l_rint() 220112174Speter * while we were looping based on these two counters. Now, we collect 220212174Speter * the data and then loop stuffing it into l_rint(), making this 220312174Speter * useless. Should we cause this to blow away the staging buffer? 220412174Speter */ 220510015Speter if (rw & FREAD) { 220610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 220710015Speter } 220810015Speter#endif 220910015Speter} 221010015Speter 221110015Speter/* 221210015Speter * Issue a command to the Z280 host card CPU. 221310015Speter */ 221410015Speter 221510015Speterstatic void 221610015Spetersi_command(pp, cmd, waitflag) 221710015Speter struct si_port *pp; /* port control block (local) */ 221810015Speter int cmd; 221910015Speter int waitflag; 222010015Speter{ 222110015Speter int oldspl; 222210015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 222310015Speter int x; 222410015Speter 222510015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 222610015Speter pp, cmd, waitflag, ccbp->hi_stat)); 222710015Speter 222810015Speter oldspl = spltty(); /* Keep others out */ 222910015Speter 223010015Speter /* wait until it's finished what it was doing.. */ 223110015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 223210015Speter x != IDLE_CLOSE && 223310015Speter x != cmd) { 223410015Speter if (in_intr) { /* Prevent sleep in intr */ 223510015Speter DPRINT((pp, DBG_PARAM, 223610015Speter "cmd intr collision - completing %d\trequested %d\n", 223710015Speter x, cmd)); 223810015Speter splx(oldspl); 223910015Speter return; 224010015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 224110015Speter "sicmd1", 1)) { 224210015Speter splx(oldspl); 224310015Speter return; 224410015Speter } 224510015Speter } 224610015Speter /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 224710015Speter 224810015Speter /* if there was a pending command, cause a state-change wakeup */ 224910015Speter if (pp->sp_pend != IDLE_OPEN) { 225010015Speter switch(pp->sp_pend) { 225110015Speter case LOPEN: 225210015Speter case MPEND: 225310015Speter case MOPEN: 225410015Speter case CONFIG: 225510015Speter wakeup(&pp->sp_state); 225610015Speter break; 225710015Speter default: 225810015Speter break; 225910015Speter } 226010015Speter } 226110015Speter 226210015Speter pp->sp_pend = cmd; /* New command pending */ 226310015Speter ccbp->hi_stat = cmd; /* Post it */ 226410015Speter 226510015Speter if (waitflag) { 226610015Speter if (in_intr) { /* If in interrupt handler */ 226710015Speter DPRINT((pp, DBG_PARAM, 226810015Speter "attempt to sleep in si_intr - cmd req %d\n", 226910015Speter cmd)); 227010015Speter splx(oldspl); 227110015Speter return; 227210015Speter } else while(ccbp->hi_stat != IDLE_OPEN) { 227310015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 227410015Speter "sicmd2", 0)) 227510015Speter break; 227610015Speter } 227710015Speter } 227810015Speter splx(oldspl); 227910015Speter} 228010015Speter 228110015Speterstatic void 228210015Spetersi_disc_optim(tp, t, pp) 228310015Speter struct tty *tp; 228410015Speter struct termios *t; 228510015Speter struct si_port *pp; 228610015Speter{ 228710015Speter /* 228810015Speter * XXX can skip a lot more cases if Smarts. Maybe 228910015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 229010015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 229110015Speter */ 229210015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 229310015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 229410015Speter && (!(t->c_iflag & PARMRK) 229510015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 229610015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 229710015Speter && linesw[tp->t_line].l_rint == ttyinput) 229810015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 229910015Speter else 230010015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 230110161Speter 230210015Speter /* 230310015Speter * Prepare to reduce input latency for packet 230410015Speter * discplines with a end of packet character. 230510015Speter */ 230610015Speter if (tp->t_line == SLIPDISC) 230710015Speter pp->sp_hotchar = 0xc0; 230810015Speter else if (tp->t_line == PPPDISC) 230910015Speter pp->sp_hotchar = 0x7e; 231010015Speter else 231110015Speter pp->sp_hotchar = 0; 231210161Speter 231310161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 231410161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 231510161Speter pp->sp_hotchar)); 231610015Speter} 231710015Speter 231810015Speter 231910015Speter#ifdef SI_DEBUG 232010015Speterstatic void 232110015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6) 232210015Speter struct si_port *pp; 232310015Speter int flags; 232410015Speter char *str; 232510015Speter int a1, a2, a3, a4, a5, a6; 232610015Speter{ 232710015Speter if ((pp == NULL && (si_debug&flags)) || 232810015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 232910015Speter if (pp != NULL) 233012496Speter printf("%ci%d(%d): ", 's', 233112174Speter (int)SI_CARD(pp->sp_tty->t_dev), 233212174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 233310015Speter printf(str, a1, a2, a3, a4, a5, a6); 233410015Speter } 233510015Speter} 233610015Speter 233710015Speterstatic char * 233810015Spetersi_mctl2str(cmd) 233910015Speter enum si_mctl cmd; 234010015Speter{ 234110015Speter switch (cmd) { 234210015Speter case GET: return("GET"); 234310015Speter case SET: return("SET"); 234410015Speter case BIS: return("BIS"); 234510015Speter case BIC: return("BIC"); 234610015Speter } 234710015Speter return("BAD"); 234810015Speter} 234912502Sjulian 235012624Speter#endif /* DEBUG */ 235112502Sjulian 235212624Speter 235312502Sjulian 235412502Sjulianstatic si_devsw_installed = 0; 235512502Sjulian 235612517Sjulianstatic void si_drvinit(void *unused) 235712502Sjulian{ 235812517Sjulian dev_t dev; 235912517Sjulian 236012502Sjulian if( ! si_devsw_installed ) { 236112675Sjulian dev = makedev(CDEV_MAJOR, 0); 236212675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 236312502Sjulian si_devsw_installed = 1; 236412517Sjulian } 236512502Sjulian} 236612517Sjulian 236712517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 236812517Sjulian 2369