si.c revision 29677
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 * 3329677Sgibbs * $Id: si.c,v 1.60 1997/09/14 03:19:18 peter Exp $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3716322Sgpalmerstatic const char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 3816322Sgpalmer si_copyright2[] = "@(#) (C) Andy Rutter 1993", 3916322Sgpalmer si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 4010015Speter#endif /* not lint */ 4110015Speter 4210015Speter#include <sys/param.h> 4310015Speter#include <sys/systm.h> 4424207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 4524207Sbde#include <sys/ioctl_compat.h> 4624207Sbde#endif 4710015Speter#include <sys/tty.h> 4810015Speter#include <sys/proc.h> 4910015Speter#include <sys/conf.h> 5024131Sbde#include <sys/fcntl.h> 5110015Speter#include <sys/dkstat.h> 5210015Speter#include <sys/kernel.h> 5310015Speter#include <sys/malloc.h> 5415683Speter#include <sys/sysctl.h> 5512675Sjulian#ifdef DEVFS 5612675Sjulian#include <sys/devfsext.h> 5712675Sjulian#endif /*DEVFS*/ 5810015Speter 5910015Speter#include <machine/clock.h> 6010015Speter 6112659Sbde#include <vm/vm.h> 6212662Sdg#include <vm/pmap.h> 6312659Sbde 6410015Speter#include <i386/isa/icu.h> 6510015Speter#include <i386/isa/isa.h> 6610015Speter#include <i386/isa/isa_device.h> 6710015Speter 6810015Speter#include <i386/isa/sireg.h> 6910015Speter#include <machine/si.h> 7013353Speter#include <machine/stdarg.h> 7110015Speter 7210015Speter#include "si.h" 7310015Speter 7410015Speter/* 7510015Speter * This device driver is designed to interface the Specialix International 7612496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 7710015Speter * 7810015Speter * The controller is interfaced to the host via dual port ram 7910015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 8010015Speter */ 8110015Speter 8217547Speter#define POLL /* turn on poller to scan for lost interrupts */ 8317547Speter#define REALPOLL /* on each poll, scan for work regardless */ 8417547Speter#define POLLHZ (hz/10) /* 10 times per second */ 8510047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8612496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8715639Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 8815639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 8910015Speter 9010015Speterenum si_mctl { GET, SET, BIS, BIC }; 9110015Speter 9210015Speterstatic void si_command __P((struct si_port *, int, int)); 9310015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 9410015Speterstatic void si_write_enable __P((struct si_port *, int)); 9510015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9610015Speterstatic void si_start __P((struct tty *)); 9725047Sbdestatic timeout_t si_lstart; 9810015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 9910015Speter struct si_port *pp)); 10010015Speterstatic void sihardclose __P((struct si_port *pp)); 10110015Speterstatic void sidtrwakeup __P((void *chan)); 10210015Speter 10312724Sphkstatic int siparam __P((struct tty *, struct termios *)); 10410015Speter 10512724Sphkstatic int siprobe __P((struct isa_device *id)); 10612724Sphkstatic int siattach __P((struct isa_device *id)); 10710708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 10810708Speter 10912675Sjulianstruct isa_driver sidriver = 11012675Sjulian { siprobe, siattach, "si" }; 11112675Sjulian 11212675Sjulian 11312675Sjulianstatic d_open_t siopen; 11412675Sjulianstatic d_close_t siclose; 11512675Sjulianstatic d_read_t siread; 11612675Sjulianstatic d_write_t siwrite; 11712675Sjulianstatic d_ioctl_t siioctl; 11812675Sjulianstatic d_stop_t sistop; 11912731Sbdestatic d_devtotty_t sidevtotty; 12012675Sjulian 12112675Sjulian#define CDEV_MAJOR 68 12212678Sphkstatic struct cdevsw si_cdevsw = 12312675Sjulian { siopen, siclose, siread, siwrite, /*68*/ 12412743Sbde siioctl, sistop, noreset, sidevtotty,/* si */ 12529368Speter ttpoll, nommap, NULL, "si", NULL, -1 }; 12612675Sjulian 12712675Sjulian 12812174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 12913353Speter 13013353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 13113353Speter ...)); 13210708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 13313353Speter 13410708Speter#define DPRINT(x) si_dprintf x 13513353Speter 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; 16212675Sjulian#ifdef DEVFS 16312675Sjulian struct { 16412675Sjulian void *ttyd; 16512826Speter void *cuaa; 16612675Sjulian void *ttyl; 16712675Sjulian void *ttyi; 16812675Sjulian } devfs_token[32]; /* what is the max per card? */ 16913165Speter void *control_token; 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 22915683Speterstatic int si_pollrate; /* in addition to irq */ 23017547Speterstatic int si_realpoll; /* poll HW on timer */ 23115639Speter 23216403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 23317547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 23415639Speter 23510015Speterstatic int init_finished = 0; 23610015Speterstatic void si_poll __P((void *)); 23710015Speter#endif 23810015Speter 23910015Speter/* 24010015Speter * Array of adapter types and the corresponding RAM size. The order of 24110015Speter * entries here MUST match the ordinal of the adapter type. 24210015Speter */ 24310015Speterstatic char *si_type[] = { 24410015Speter "EMPTY", 24510015Speter "SIHOST", 24610015Speter "SI2", /* MCA */ 24710015Speter "SIHOST2", 24810015Speter "SIEISA", 24910015Speter}; 25010015Speter 25110015Speter/* Look for a valid board at the given mem addr */ 25212724Sphkstatic int 25310015Spetersiprobe(id) 25410015Speter struct isa_device *id; 25510015Speter{ 25610015Speter struct si_softc *sc; 25710015Speter int type; 25810015Speter u_int i, ramsize; 25910015Speter volatile BYTE was, *ux; 26010015Speter volatile unsigned char *maddr; 26110015Speter unsigned char *paddr; 26210015Speter 26317547Speter si_pollrate = POLLHZ; /* default 10 per second */ 26417547Speter#ifdef REALPOLL 26517547Speter si_realpoll = 1; /* scan always */ 26617547Speter#endif 26715683Speter 26810015Speter maddr = id->id_maddr; /* virtual address... */ 26910015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 27010015Speter 27112496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 27212496Speter id->id_unit, id->id_maddr, paddr)); 27310015Speter 27410015Speter /* 27510015Speter * this is a lie, but it's easier than trying to handle caching 27610015Speter * and ram conflicts in the >1M and <16M region. 27710015Speter */ 27810015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 27910015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 28012174Speter printf("si%d: iomem (%lx) out of range\n", 28112174Speter id->id_unit, (long)paddr); 28210015Speter return(0); 28310015Speter } 28410015Speter 28510015Speter if (id->id_unit >= NSI) { 28610015Speter /* THIS IS IMPOSSIBLE */ 28710015Speter return(0); 28810015Speter } 28910015Speter 29010015Speter if (((u_int)paddr & 0x7fff) != 0) { 29110015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 29210015Speter "si%d: iomem (%x) not on 32k boundary\n", 29310015Speter id->id_unit, paddr)); 29410015Speter return(0); 29510015Speter } 29610015Speter 29710015Speter 29810015Speter for (i=0; i < NSI; i++) { 29910015Speter if ((sc = &si_softc[i]) == NULL) 30010015Speter continue; 30110015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 30210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 30310015Speter "si%d: iomem (%x) already configured to si%d\n", 30410015Speter id->id_unit, sc->sc_paddr, i)); 30510015Speter return(0); 30610015Speter } 30710015Speter } 30810015Speter 30910015Speter#if NEISA > 0 31010015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 31110015Speter int irq, port; 31210015Speter unsigned long base; 31310015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 31410015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 31510015Speter 31610015Speter port = id->id_iobase; 31710015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 31810015Speter irq = ((inb(port+2) >> 4) & 0xf); 31910015Speter 32010015Speter id->id_irq = eisa_irqs[irq]; 32110015Speter 32210015Speter DPRINT((0, DBG_AUTOBOOT, 32312496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 32410015Speter id->id_unit, base, irq, id->id_irq, port)); 32510015Speter 32610015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 32710015Speter goto bad_irq; 32810015Speter 32910015Speter id->id_iobase &= 0xf000; 33010015Speter id->id_iosize = 0x0fff; 33110015Speter 33210015Speter type = EISA; 33310015Speter outb(p+2, (BYTE)irq << 4); 33410015Speter 33510015Speter sc->sc_eisa_iobase = p; 33610015Speter sc->sc_eisa_irqbits = irq << 4; 33710015Speter ramsize = SIEISA_RAMSIZE; 33810015Speter goto got_card; 33910015Speter } 34010015Speter#endif 34110015Speter 34210015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 34310015Speter *maddr = 0x17; 34410015Speter if (*maddr != 0x17) { 34510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 34610015Speter "si%d: 0x17 check fail at phys 0x%x\n", 34710015Speter id->id_unit, paddr)); 34810015Speterfail: 34910015Speter return(0); 35010015Speter } 35110015Speter /* 35210015Speter * OK, now to see if whatever responded is really an SI card. 35310015Speter * Try for a MK II first (SIHOST2) 35410015Speter */ 35510015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 35610015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 35710015Speter goto try_mk1; 35810015Speter 35910015Speter /* It must be an SIHOST2 */ 36010015Speter *(maddr + SIPLRESET) = 0; 36110015Speter *(maddr + SIPLIRQCLR) = 0; 36210015Speter *(maddr + SIPLIRQSET) = 0x10; 36310015Speter type = SIHOST2; 36410015Speter ramsize = SIHOST2_RAMSIZE; 36510015Speter goto got_card; 36610015Speter 36710015Speter /* 36810015Speter * Its not a MK II, so try for a MK I (SIHOST) 36910015Speter */ 37010015Spetertry_mk1: 37110015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 37210015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 37310015Speter *(maddr+SIRAM) = 0x17; 37410015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 37510015Speter goto fail; 37610015Speter *(maddr+0x7ff8) = 0x17; 37710015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 37810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 37910015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 38010015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 38110015Speter goto fail; 38210015Speter } 38310015Speter 38410015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 38510015Speter type = SIHOST; 38610015Speter ramsize = SIHOST_RAMSIZE; 38710015Speter 38810015Spetergot_card: 38912496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 39012496Speter id->id_unit, type)); 39110015Speter /* Try the acid test */ 39218515Speter ux = maddr + SIRAM; 39310015Speter for (i=0; i<ramsize; i++, ux++) 39410015Speter *ux = (BYTE)(i&0xff); 39518515Speter ux = maddr + SIRAM; 39610015Speter for (i=0; i<ramsize; i++, ux++) { 39710015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 39810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 39912174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 40010015Speter id->id_unit, paddr+i, was, i&0xff)); 40110015Speter goto fail; 40210015Speter } 40310015Speter } 40410015Speter 40510015Speter /* clear out the RAM */ 40618515Speter ux = maddr + SIRAM; 40710015Speter for (i=0; i<ramsize; i++) 40810015Speter *ux++ = 0; 40918515Speter ux = maddr + SIRAM; 41010015Speter for (i=0; i<ramsize; i++) { 41110015Speter if ((was = *ux++) != 0) { 41210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 41312174Speter "si%d: clear fail at phys 0x%x, was %x\n", 41410015Speter id->id_unit, paddr+i, was)); 41510015Speter goto fail; 41610015Speter } 41710015Speter } 41810015Speter 41910015Speter /* 42010015Speter * Success, we've found a valid board, now fill in 42110015Speter * the adapter structure. 42210015Speter */ 42310015Speter switch (type) { 42410015Speter case SIHOST2: 42510015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 42610015Speterbad_irq: 42710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 42810015Speter "si%d: bad IRQ value - %d\n", 42910015Speter id->id_unit, id->id_irq)); 43010015Speter return(0); 43110015Speter } 43210015Speter id->id_msize = SIHOST2_MEMSIZE; 43310015Speter break; 43410015Speter case SIHOST: 43510015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 43610015Speter goto bad_irq; 43710015Speter } 43810015Speter id->id_msize = SIHOST_MEMSIZE; 43910015Speter break; 44010015Speter case SIEISA: 44110015Speter id->id_msize = SIEISA_MEMSIZE; 44210015Speter break; 44310015Speter case SI2: /* MCA */ 44410015Speter default: 44510015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 44610015Speter return(0); 44710015Speter } 44810015Speter si_softc[id->id_unit].sc_type = type; 44910015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 45010015Speter return(-1); /* -1 == found */ 45110015Speter} 45210015Speter 45310015Speter/* 45410015Speter * Attach the device. Initialize the card. 45510015Speter */ 45612724Sphkstatic int 45710015Spetersiattach(id) 45810015Speter struct isa_device *id; 45910015Speter{ 46010015Speter int unit = id->id_unit; 46110015Speter struct si_softc *sc = &si_softc[unit]; 46210015Speter struct si_port *pp; 46310015Speter volatile struct si_channel *ccbp; 46410015Speter volatile struct si_reg *regp; 46510015Speter volatile caddr_t maddr; 46610015Speter struct si_module *modp; 46710015Speter struct tty *tp; 46810015Speter struct speedtab *spt; 46910015Speter int nmodule, nport, x, y; 47012174Speter int uart_type; 47110015Speter 47212496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 47310015Speter 47410015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 47510015Speter sc->sc_maddr = id->id_maddr; 47610015Speter sc->sc_irq = id->id_irq; 47710015Speter 47810015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 47910015Speter 48010015Speter maddr = sc->sc_maddr; 48110015Speter 48210015Speter /* 48310015Speter * OK, now lets download the firmware and try and boot the CPU.. 48410015Speter */ 48510015Speter 48612496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 48712496Speter id->id_unit, si_dsize)); 48810015Speter bcopy(si_download, maddr, si_dsize); 48910015Speter 49010015Speter switch (sc->sc_type) { 49110015Speter case SIEISA: 49210015Speter#if NEISA > 0 49310015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 49410015Speter *(maddr+0x42) = 1; 49510015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 49610015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 49710015Speter break; 49810015Speter#endif /* fall-through if not EISA */ 49910015Speter case SI2: 50012174Speter /* 50112174Speter * must get around to converting the code for 50212174Speter * these one day, if FreeBSD ever supports it. 50312174Speter */ 50410015Speter return 0; 50510015Speter case SIHOST: 50610015Speter *(maddr+SIRESET_CL) = 0; 50710015Speter *(maddr+SIINTCL_CL) = 0; 50810015Speter break; 50910015Speter case SIHOST2: 51010015Speter *(maddr+SIPLRESET) = 0x10; 51110015Speter switch (sc->sc_irq) { 51210015Speter case IRQ11: 51310015Speter *(maddr+SIPLIRQ11) = 0x10; 51410015Speter break; 51510015Speter case IRQ12: 51610015Speter *(maddr+SIPLIRQ12) = 0x10; 51710015Speter break; 51810015Speter case IRQ15: 51910015Speter *(maddr+SIPLIRQ15) = 0x10; 52010015Speter break; 52110015Speter } 52210015Speter *(maddr+SIPLIRQCLR) = 0x10; 52310015Speter break; 52410015Speter } 52510015Speter 52610015Speter DELAY(1000000); /* wait around for a second */ 52710015Speter 52810015Speter regp = (struct si_reg *)maddr; 52910015Speter y = 0; 53010015Speter /* wait max of 5 sec for init OK */ 53110015Speter while (regp->initstat == 0 && y++ < 10) { 53210015Speter DELAY(500000); 53310015Speter } 53410015Speter switch (regp->initstat) { 53510015Speter case 0: 53610015Speter printf("si%d: startup timeout - aborting\n", unit); 53712174Speter sc->sc_type = SIEMPTY; 53810015Speter return 0; 53910015Speter case 1: 54012174Speter /* set throttle to 125 intr per second */ 54115639Speter regp->int_count = INT_COUNT; 54210015Speter /* rx intr max of 25 timer per second */ 54315639Speter regp->rx_int_count = RXINT_COUNT; 54410015Speter regp->int_pending = 0; /* no intr pending */ 54510015Speter regp->int_scounter = 0; /* reset counter */ 54610015Speter break; 54710015Speter case 0xff: 54810015Speter /* 54910015Speter * No modules found, so give up on this one. 55010015Speter */ 55110015Speter printf("si%d: %s - no ports found\n", unit, 55210015Speter si_type[sc->sc_type]); 55310015Speter return 0; 55410015Speter default: 55510015Speter printf("si%d: Z280 version error - initstat %x\n", 55610015Speter unit, regp->initstat); 55710015Speter return 0; 55810015Speter } 55910015Speter 56010015Speter /* 56110015Speter * First time around the ports just count them in order 56210015Speter * to allocate some memory. 56310015Speter */ 56410015Speter nport = 0; 56510015Speter modp = (struct si_module *)(maddr + 0x80); 56610015Speter for (;;) { 56712174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 56810015Speter switch (modp->sm_type & (~MMASK)) { 56910015Speter case M232: 57010015Speter case M422: 57110015Speter DPRINT((0, DBG_DOWNLOAD, 57212174Speter "si%d: Found 232/422 module, %d ports\n", 57310015Speter unit, (int)(modp->sm_type & MMASK))); 57410015Speter 57510015Speter /* this is a firmware issue */ 57610015Speter if (si_Nports == SI_MAXPORTPERCARD) { 57710015Speter printf("si%d: extra ports ignored\n", unit); 57810015Speter continue; 57910015Speter } 58010015Speter 58110015Speter x = modp->sm_type & MMASK; 58210015Speter nport += x; 58310015Speter si_Nports += x; 58410015Speter si_Nmodules++; 58510015Speter break; 58610015Speter default: 58710015Speter printf("si%d: unknown module type %d\n", 58810015Speter unit, modp->sm_type); 58910015Speter break; 59010015Speter } 59110015Speter if (modp->sm_next == 0) 59210015Speter break; 59310015Speter modp = (struct si_module *) 59410015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 59510015Speter } 59610015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 59710015Speter M_DEVBUF, M_NOWAIT); 59810015Speter if (sc->sc_ports == 0) { 59910015Spetermem_fail: 60010015Speter printf("si%d: fail to malloc memory for port structs\n", 60110015Speter unit); 60210015Speter return 0; 60310015Speter } 60410015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 60510015Speter sc->sc_nport = nport; 60610015Speter 60710015Speter /* 60810015Speter * allocate tty structures for ports 60910015Speter */ 61010015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 61110015Speter if (tp == 0) 61210015Speter goto mem_fail; 61310015Speter bzero(tp, sizeof(*tp) * nport); 61410962Speter si_tty = tp; 61510015Speter 61610015Speter /* 61710015Speter * Scan round the ports again, this time initialising. 61810015Speter */ 61910015Speter pp = sc->sc_ports; 62010015Speter nmodule = 0; 62110015Speter modp = (struct si_module *)(maddr + 0x80); 62212174Speter uart_type = 0; 62310015Speter for (;;) { 62410015Speter switch (modp->sm_type & (~MMASK)) { 62510015Speter case M232: 62610015Speter case M422: 62710015Speter nmodule++; 62810015Speter nport = (modp->sm_type & MMASK); 62910015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 63012174Speter if (uart_type == 0) 63112174Speter uart_type = ccbp->type; 63210015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 63310015Speter pp->sp_ccb = ccbp; /* save the address */ 63410015Speter pp->sp_tty = tp++; 63510015Speter pp->sp_pend = IDLE_CLOSE; 63610015Speter pp->sp_state = 0; /* internal flag */ 63710015Speter pp->sp_dtr_wait = 3 * hz; 63810047Speter pp->sp_iin.c_iflag = si_default_iflag; 63910047Speter pp->sp_iin.c_oflag = si_default_oflag; 64010047Speter pp->sp_iin.c_cflag = si_default_cflag; 64110047Speter pp->sp_iin.c_lflag = si_default_lflag; 64210015Speter termioschars(&pp->sp_iin); 64310015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 64410047Speter si_default_rate; 64510015Speter pp->sp_iout = pp->sp_iin; 64610015Speter } 64710015Speter break; 64810015Speter default: 64910015Speter break; 65010015Speter } 65110015Speter if (modp->sm_next == 0) { 65212174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 65310015Speter unit, 65410015Speter sc->sc_typename, 65510015Speter sc->sc_nport, 65612174Speter nmodule, 65712174Speter uart_type); 65810015Speter break; 65910015Speter } 66010015Speter modp = (struct si_module *) 66110015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 66210015Speter } 66310015Speter if (done_chartimes == 0) { 66410015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 66510015Speter if ((spt->sp_code /= hz) == 0) 66610015Speter spt->sp_code = 1; 66710015Speter } 66810015Speter done_chartimes = 1; 66910015Speter } 67012502Sjulian 67112675Sjulian#ifdef DEVFS 67212675Sjulian/* path name devsw minor type uid gid perm*/ 67313169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 67413165Speter y = x + 1; /* For sync with the manuals that start at 1 */ 67513630Sphk sc->devfs_token[x].ttyd = devfs_add_devswf( 67613630Sphk &si_cdevsw, x, 67713630Sphk DV_CHR, 0, 0, 0600, "ttyA%02d", y); 67813630Sphk sc->devfs_token[x].cuaa = devfs_add_devswf( 67913630Sphk &si_cdevsw, x + 128, 68013630Sphk DV_CHR, 0, 0, 0600, "cuaA%02d", y); 68113630Sphk sc->devfs_token[x].ttyi = devfs_add_devswf( 68213630Sphk &si_cdevsw, x + 0x10000, 68313630Sphk DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 68413630Sphk sc->devfs_token[x].ttyl = devfs_add_devswf( 68513630Sphk &si_cdevsw, x + 0x20000, 68613630Sphk DV_CHR, 0, 0, 0600, "ttylA%02d", y); 68712675Sjulian } 68814873Sscrappy sc->control_token = 68914873Sscrappy devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 69014873Sscrappy "si_control"); 69112675Sjulian#endif 69210015Speter return (1); 69310015Speter} 69410015Speter 69512675Sjulianstatic int 69610015Spetersiopen(dev, flag, mode, p) 69710015Speter dev_t dev; 69810015Speter int flag, mode; 69910015Speter struct proc *p; 70010015Speter{ 70110015Speter int oldspl, error; 70210015Speter int card, port; 70310015Speter register struct si_softc *sc; 70410015Speter register struct tty *tp; 70510015Speter volatile struct si_channel *ccbp; 70610015Speter struct si_port *pp; 70710015Speter int mynor = minor(dev); 70810015Speter 70910015Speter /* quickly let in /dev/si_control */ 71010015Speter if (IS_CONTROLDEV(mynor)) { 71118515Speter if ((error = suser(p->p_ucred, &p->p_acflag))) 71210015Speter return(error); 71310015Speter return(0); 71410015Speter } 71510015Speter 71610015Speter card = SI_CARD(mynor); 71710015Speter if (card >= NSI) 71810015Speter return (ENXIO); 71910015Speter sc = &si_softc[card]; 72010015Speter 72112174Speter if (sc->sc_type == SIEMPTY) { 72212174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 72310015Speter card, sc->sc_typename)); 72410015Speter return(ENXIO); 72510015Speter } 72610015Speter 72710015Speter port = SI_PORT(mynor); 72810015Speter if (port >= sc->sc_nport) { 72912174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 73010015Speter card, sc->sc_nport)); 73110015Speter return(ENXIO); 73210015Speter } 73310015Speter 73410015Speter#ifdef POLL 73510015Speter /* 73610015Speter * We've now got a device, so start the poller. 73710015Speter */ 73810015Speter if (init_finished == 0) { 73915639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 74010015Speter init_finished = 1; 74110015Speter } 74210015Speter#endif 74310015Speter 74410015Speter /* initial/lock device */ 74510015Speter if (IS_STATE(mynor)) { 74610015Speter return(0); 74710015Speter } 74810015Speter 74910015Speter pp = sc->sc_ports + port; 75010015Speter tp = pp->sp_tty; /* the "real" tty */ 75110015Speter ccbp = pp->sp_ccb; /* Find control block */ 75210015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 75310015Speter dev, flag, mode, p)); 75410015Speter 75510015Speter oldspl = spltty(); /* Keep others out */ 75610015Speter error = 0; 75710015Speter 75810015Speteropen_top: 75910015Speter while (pp->sp_state & SS_DTR_OFF) { 76010015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 76110015Speter if (error != 0) 76210015Speter goto out; 76310015Speter } 76410015Speter 76510015Speter if (tp->t_state & TS_ISOPEN) { 76610015Speter /* 76710015Speter * The device is open, so everything has been initialised. 76810015Speter * handle conflicts. 76910015Speter */ 77010015Speter if (IS_CALLOUT(mynor)) { 77110015Speter if (!pp->sp_active_out) { 77210015Speter error = EBUSY; 77310015Speter goto out; 77410015Speter } 77510015Speter } else { 77610015Speter if (pp->sp_active_out) { 77710015Speter if (flag & O_NONBLOCK) { 77810015Speter error = EBUSY; 77910015Speter goto out; 78010015Speter } 78110015Speter error = tsleep(&pp->sp_active_out, 78210015Speter TTIPRI|PCATCH, "sibi", 0); 78310015Speter if (error != 0) 78410015Speter goto out; 78510015Speter goto open_top; 78610015Speter } 78710015Speter } 78810015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 78910015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 79010015Speter "already open and EXCLUSIVE set\n")); 79110015Speter error = EBUSY; 79210015Speter goto out; 79310015Speter } 79410015Speter } else { 79510015Speter /* 79610015Speter * The device isn't open, so there are no conflicts. 79710015Speter * Initialize it. Avoid sleep... :-) 79810015Speter */ 79910015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 80010015Speter tp->t_oproc = si_start; 80110015Speter tp->t_param = siparam; 80210015Speter tp->t_dev = dev; 80310015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 80410015Speter ? pp->sp_iout : pp->sp_iin; 80510015Speter 80610015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 80710015Speter 80810015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 80910015Speter 81010015Speter error = siparam(tp, &tp->t_termios); 81110015Speter 81210015Speter --pp->sp_wopeners; 81310015Speter if (error != 0) 81410015Speter goto out; 81510015Speter /* XXX: we should goto_top if siparam slept */ 81610015Speter 81710015Speter ttsetwater(tp); 81810015Speter 81910015Speter /* set initial DCD state */ 82010015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 82110015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 82210015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 82310015Speter } 82410015Speter } 82510015Speter 82610015Speter /* whoops! we beat the close! */ 82710015Speter if (pp->sp_state & SS_CLOSING) { 82810015Speter /* try and stop it from proceeding to bash the hardware */ 82910015Speter pp->sp_state &= ~SS_CLOSING; 83010015Speter } 83110015Speter 83210015Speter /* 83310015Speter * Wait for DCD if necessary 83410015Speter */ 83510015Speter if (!(tp->t_state & TS_CARR_ON) 83610015Speter && !IS_CALLOUT(mynor) 83710015Speter && !(tp->t_cflag & CLOCAL) 83810015Speter && !(flag & O_NONBLOCK)) { 83910015Speter ++pp->sp_wopeners; 84010015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 84110015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 84210015Speter --pp->sp_wopeners; 84310015Speter if (error != 0) 84410015Speter goto out; 84510015Speter goto open_top; 84610015Speter } 84710015Speter 84810015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 84910015Speter si_disc_optim(tp, &tp->t_termios, pp); 85010015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 85110015Speter pp->sp_active_out = TRUE; 85210015Speter 85310015Speter pp->sp_state |= SS_OPEN; /* made it! */ 85410015Speter 85510015Speterout: 85610015Speter splx(oldspl); 85710015Speter 85810015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 85910015Speter 86010015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 86110015Speter sihardclose(pp); 86210015Speter 86310015Speter return(error); 86410015Speter} 86510015Speter 86612675Sjulianstatic int 86710015Spetersiclose(dev, flag, mode, p) 86810015Speter dev_t dev; 86910015Speter int flag, mode; 87010015Speter struct proc *p; 87110015Speter{ 87210015Speter register struct si_port *pp; 87310015Speter register struct tty *tp; 87410015Speter int oldspl; 87510015Speter int error = 0; 87610015Speter int mynor = minor(dev); 87710015Speter 87810015Speter if (IS_SPECIAL(mynor)) 87910015Speter return(0); 88010015Speter 88110015Speter oldspl = spltty(); 88210015Speter 88310015Speter pp = MINOR2PP(mynor); 88410015Speter tp = pp->sp_tty; 88510015Speter 88610015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 88710015Speter dev, flag, mode, p, pp->sp_state)); 88810015Speter 88910015Speter /* did we sleep and loose a race? */ 89010015Speter if (pp->sp_state & SS_CLOSING) { 89110015Speter /* error = ESOMETING? */ 89210015Speter goto out; 89310015Speter } 89410015Speter 89510015Speter /* begin race detection.. */ 89610015Speter pp->sp_state |= SS_CLOSING; 89710015Speter 89810015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 89910015Speter 90010015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 90110015Speter (*linesw[tp->t_line].l_close)(tp, flag); 90210015Speter 90310015Speter si_write_enable(pp, 1); 90410015Speter 90510015Speter /* did we sleep and somebody started another open? */ 90610015Speter if (!(pp->sp_state & SS_CLOSING)) { 90710015Speter /* error = ESOMETING? */ 90810015Speter goto out; 90910015Speter } 91010015Speter /* ok. we are now still on the right track.. nuke the hardware */ 91110015Speter 91210015Speter if (pp->sp_state & SS_LSTART) { 91329677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 91410015Speter pp->sp_state &= ~SS_LSTART; 91510015Speter } 91610015Speter 91710015Speter sistop(tp, FREAD | FWRITE); 91810015Speter 91910015Speter sihardclose(pp); 92010015Speter ttyclose(tp); 92110015Speter pp->sp_state &= ~SS_OPEN; 92210015Speter 92310015Speterout: 92410015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 92510015Speter splx(oldspl); 92610015Speter return(error); 92710015Speter} 92810015Speter 92910015Speterstatic void 93010015Spetersihardclose(pp) 93110015Speter struct si_port *pp; 93210015Speter{ 93310015Speter int oldspl; 93410015Speter struct tty *tp; 93510015Speter volatile struct si_channel *ccbp; 93610015Speter 93710015Speter oldspl = spltty(); 93810015Speter 93910015Speter tp = pp->sp_tty; 94010015Speter ccbp = pp->sp_ccb; /* Find control block */ 94110015Speter if (tp->t_cflag & HUPCL 94218515Speter || (!pp->sp_active_out 94318515Speter && !(ccbp->hi_ip & IP_DCD) 94418515Speter && !(pp->sp_iin.c_cflag && CLOCAL)) 94510015Speter || !(tp->t_state & TS_ISOPEN)) { 94610015Speter 94710015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 94810015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 94910015Speter 95010015Speter if (pp->sp_dtr_wait != 0) { 95110015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 95210015Speter pp->sp_state |= SS_DTR_OFF; 95310015Speter } 95410015Speter 95510015Speter } 95610015Speter pp->sp_active_out = FALSE; 95710015Speter wakeup((caddr_t)&pp->sp_active_out); 95810015Speter wakeup(TSA_CARR_ON(tp)); 95910015Speter 96010015Speter splx(oldspl); 96110015Speter} 96210015Speter 96310015Speter 96410015Speter/* 96510015Speter * called at splsoftclock()... 96610015Speter */ 96710015Speterstatic void 96810015Spetersidtrwakeup(chan) 96910015Speter void *chan; 97010015Speter{ 97110015Speter struct si_port *pp; 97210015Speter int oldspl; 97310015Speter 97410015Speter oldspl = spltty(); 97510015Speter 97610015Speter pp = (struct si_port *)chan; 97710015Speter pp->sp_state &= ~SS_DTR_OFF; 97810015Speter wakeup(&pp->sp_dtr_wait); 97910015Speter 98010015Speter splx(oldspl); 98110015Speter} 98210015Speter 98310015Speter/* 98410015Speter * User level stuff - read and write 98510015Speter */ 98612675Sjulianstatic int 98710015Spetersiread(dev, uio, flag) 98810015Speter register dev_t dev; 98910015Speter struct uio *uio; 99010015Speter int flag; 99110015Speter{ 99210015Speter register struct tty *tp; 99310015Speter int mynor = minor(dev); 99410015Speter 99510015Speter if (IS_SPECIAL(mynor)) { 99610015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 99710015Speter return(ENODEV); 99810015Speter } 99910015Speter tp = MINOR2TP(mynor); 100010015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 100110015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 100210015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 100310015Speter} 100410015Speter 100510015Speter 100612675Sjulianstatic int 100710015Spetersiwrite(dev, uio, flag) 100810015Speter dev_t dev; 100910015Speter struct uio *uio; 101010015Speter int flag; 101110015Speter{ 101210015Speter register struct si_port *pp; 101310015Speter register struct tty *tp; 101410015Speter int error = 0; 101510015Speter int mynor = minor(dev); 101610015Speter int oldspl; 101710015Speter 101810015Speter if (IS_SPECIAL(mynor)) { 101910015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 102010015Speter return(ENODEV); 102110015Speter } 102210015Speter pp = MINOR2PP(mynor); 102310015Speter tp = pp->sp_tty; 102410015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 102510015Speter 102610015Speter oldspl = spltty(); 102710015Speter /* 102810015Speter * If writes are currently blocked, wait on the "real" tty 102910015Speter */ 103010015Speter while (pp->sp_state & SS_BLOCKWRITE) { 103110015Speter pp->sp_state |= SS_WAITWRITE; 103210015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 103318515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 103418515Speter "siwrite", tp->t_timeout))) { 103517291Speter if (error == EWOULDBLOCK) 103617290Speter error = EIO; 103710015Speter goto out; 103817290Speter } 103910015Speter } 104010015Speter 104110015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 104210015Speterout: 104310015Speter splx(oldspl); 104410015Speter return (error); 104510015Speter} 104610015Speter 104710015Speter 104812675Sjulianstatic struct tty * 104910015Spetersidevtotty(dev_t dev) 105010015Speter{ 105110015Speter struct si_port *pp; 105210015Speter int mynor = minor(dev); 105310015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 105410015Speter 105510015Speter if (IS_SPECIAL(mynor)) 105610015Speter return(NULL); 105710015Speter if (SI_PORT(mynor) >= sc->sc_nport) 105810015Speter return(NULL); 105910015Speter pp = MINOR2PP(mynor); 106010015Speter return (pp->sp_tty); 106110015Speter} 106210015Speter 106312675Sjulianstatic int 106410015Spetersiioctl(dev, cmd, data, flag, p) 106510015Speter dev_t dev; 106610015Speter int cmd; 106710015Speter caddr_t data; 106810015Speter int flag; 106910015Speter struct proc *p; 107010015Speter{ 107110015Speter struct si_port *pp; 107210015Speter register struct tty *tp; 107310015Speter int error; 107410015Speter int mynor = minor(dev); 107510015Speter int oldspl; 107610015Speter int blocked = 0; 107710015Speter#if defined(COMPAT_43) 107810015Speter int oldcmd; 107910015Speter struct termios term; 108010015Speter#endif 108110015Speter 108210015Speter if (IS_SI_IOCTL(cmd)) 108310015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 108410015Speter 108510015Speter pp = MINOR2PP(mynor); 108610015Speter tp = pp->sp_tty; 108710015Speter 108810015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 108910015Speter dev, cmd, data, flag)); 109010015Speter if (IS_STATE(mynor)) { 109110015Speter struct termios *ct; 109210015Speter 109310015Speter switch (mynor & SI_STATE_MASK) { 109410015Speter case SI_INIT_STATE_MASK: 109510015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 109610015Speter break; 109710015Speter case SI_LOCK_STATE_MASK: 109816839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 109910015Speter break; 110010015Speter default: 110110015Speter return (ENODEV); 110210015Speter } 110310015Speter switch (cmd) { 110410015Speter case TIOCSETA: 110510015Speter error = suser(p->p_ucred, &p->p_acflag); 110610015Speter if (error != 0) 110710015Speter return (error); 110810015Speter *ct = *(struct termios *)data; 110910015Speter return (0); 111010015Speter case TIOCGETA: 111110015Speter *(struct termios *)data = *ct; 111210015Speter return (0); 111310015Speter case TIOCGETD: 111410015Speter *(int *)data = TTYDISC; 111510015Speter return (0); 111610015Speter case TIOCGWINSZ: 111710015Speter bzero(data, sizeof(struct winsize)); 111810015Speter return (0); 111910015Speter default: 112010015Speter return (ENOTTY); 112110015Speter } 112210015Speter } 112310015Speter /* 112410015Speter * Do the old-style ioctl compat routines... 112510015Speter */ 112610015Speter#if defined(COMPAT_43) 112710015Speter term = tp->t_termios; 112810015Speter oldcmd = cmd; 112910015Speter error = ttsetcompat(tp, &cmd, data, &term); 113010015Speter if (error != 0) 113110015Speter return (error); 113210015Speter if (cmd != oldcmd) 113310015Speter data = (caddr_t)&term; 113410015Speter#endif 113510015Speter /* 113610015Speter * Do the initial / lock state business 113710015Speter */ 113810015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 113910015Speter int cc; 114010015Speter struct termios *dt = (struct termios *)data; 114110015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 114210015Speter ? &pp->sp_lout : &pp->sp_lin; 114310015Speter 114410015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 114510015Speter | (dt->c_iflag & ~lt->c_iflag); 114610015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 114710015Speter | (dt->c_oflag & ~lt->c_oflag); 114810015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 114910015Speter | (dt->c_cflag & ~lt->c_cflag); 115010015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 115110015Speter | (dt->c_lflag & ~lt->c_lflag); 115210015Speter for (cc = 0; cc < NCCS; ++cc) 115310015Speter if (lt->c_cc[cc] != 0) 115410015Speter dt->c_cc[cc] = tp->t_cc[cc]; 115510015Speter if (lt->c_ispeed != 0) 115610015Speter dt->c_ispeed = tp->t_ispeed; 115710015Speter if (lt->c_ospeed != 0) 115810015Speter dt->c_ospeed = tp->t_ospeed; 115910015Speter } 116010015Speter 116110015Speter /* 116210015Speter * Block user-level writes to give the ttywait() 116310015Speter * a chance to completely drain for commands 116410015Speter * that require the port to be in a quiescent state. 116510015Speter */ 116610015Speter switch (cmd) { 116710015Speter case TIOCSETAW: case TIOCSETAF: 116817396Speter case TIOCDRAIN: 116917396Speter#ifdef COMPAT_43 117017396Speter case TIOCSETP: 117117396Speter#endif 117210015Speter blocked++; /* block writes for ttywait() and siparam() */ 117310015Speter si_write_enable(pp, 0); 117410015Speter } 117510015Speter 117610015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 117710015Speter if (error >= 0) 117810015Speter goto out; 117910015Speter 118010015Speter oldspl = spltty(); 118110015Speter 118210015Speter error = ttioctl(tp, cmd, data, flag); 118310015Speter si_disc_optim(tp, &tp->t_termios, pp); 118410015Speter if (error >= 0) 118510015Speter goto outspl; 118610015Speter 118710015Speter switch (cmd) { 118810015Speter case TIOCSBRK: 118916575Speter si_command(pp, SBREAK, SI_WAIT); 119010015Speter break; 119110015Speter case TIOCCBRK: 119216575Speter si_command(pp, EBREAK, SI_WAIT); 119310015Speter break; 119410015Speter case TIOCSDTR: 119510015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 119610015Speter break; 119710015Speter case TIOCCDTR: 119810015Speter (void) si_modem(pp, SET, 0); 119910015Speter break; 120010015Speter case TIOCMSET: 120110015Speter (void) si_modem(pp, SET, *(int *)data); 120210015Speter break; 120310015Speter case TIOCMBIS: 120410015Speter (void) si_modem(pp, BIS, *(int *)data); 120510015Speter break; 120610015Speter case TIOCMBIC: 120710015Speter (void) si_modem(pp, BIC, *(int *)data); 120810015Speter break; 120910015Speter case TIOCMGET: 121010015Speter *(int *)data = si_modem(pp, GET, 0); 121110015Speter break; 121210015Speter case TIOCMSDTRWAIT: 121310015Speter /* must be root since the wait applies to following logins */ 121410015Speter error = suser(p->p_ucred, &p->p_acflag); 121510015Speter if (error != 0) { 121610015Speter goto outspl; 121710015Speter } 121810015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 121910015Speter break; 122010015Speter case TIOCMGDTRWAIT: 122110015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 122210015Speter break; 122310015Speter 122410015Speter default: 122510015Speter error = ENOTTY; 122610015Speter } 122710015Speter error = 0; 122810015Speteroutspl: 122910015Speter splx(oldspl); 123010015Speterout: 123110015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 123210015Speter if (blocked) 123310015Speter si_write_enable(pp, 1); 123410015Speter return(error); 123510015Speter} 123610015Speter 123710015Speter/* 123810015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 123910015Speter */ 124010015Speterstatic int 124110015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 124210015Speter{ 124310015Speter struct si_softc *xsc; 124410015Speter register struct si_port *xpp; 124510015Speter volatile struct si_reg *regp; 124610015Speter struct si_tcsi *dp; 124710044Speter struct si_pstat *sps; 124811872Sphk int *ip, error = 0; 124910015Speter int oldspl; 125010015Speter int card, port; 125110015Speter int mynor = minor(dev); 125210015Speter 125310015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 125410015Speter dev, cmd, data, flag)); 125510015Speter 125610044Speter#if 1 125710044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 125810044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 125910044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 126010044Speter#endif 126110044Speter 126210015Speter if (!IS_CONTROLDEV(mynor)) { 126310015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 126410015Speter return(ENODEV); 126510015Speter } 126610015Speter 126710015Speter oldspl = spltty(); /* better safe than sorry */ 126810015Speter 126910015Speter ip = (int *)data; 127010015Speter 127118515Speter#define SUCHECK if ((error = suser(p->p_ucred, &p->p_acflag))) goto out 127210015Speter 127310015Speter switch (cmd) { 127410015Speter case TCSIPORTS: 127510015Speter *ip = si_Nports; 127610015Speter goto out; 127710015Speter case TCSIMODULES: 127810015Speter *ip = si_Nmodules; 127910015Speter goto out; 128010015Speter case TCSISDBG_ALL: 128110015Speter SUCHECK; 128210015Speter si_debug = *ip; 128310015Speter goto out; 128410015Speter case TCSIGDBG_ALL: 128510015Speter *ip = si_debug; 128610015Speter goto out; 128710015Speter default: 128810015Speter /* 128910015Speter * Check that a controller for this port exists 129010015Speter */ 129110044Speter 129210044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 129310044Speter 129410015Speter dp = (struct si_tcsi *)data; 129510044Speter sps = (struct si_pstat *)data; 129610015Speter card = dp->tc_card; 129710015Speter xsc = &si_softc[card]; /* check.. */ 129812174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 129910015Speter error = ENOENT; 130010015Speter goto out; 130110015Speter } 130210015Speter /* 130310015Speter * And check that a port exists 130410015Speter */ 130510015Speter port = dp->tc_port; 130610015Speter if (port < 0 || port >= xsc->sc_nport) { 130710015Speter error = ENOENT; 130810015Speter goto out; 130910015Speter } 131010015Speter xpp = xsc->sc_ports + port; 131110015Speter regp = (struct si_reg *)xsc->sc_maddr; 131210015Speter } 131310015Speter 131410015Speter switch (cmd) { 131510015Speter case TCSIDEBUG: 131610015Speter#ifdef SI_DEBUG 131710015Speter SUCHECK; 131810015Speter if (xpp->sp_debug) 131910015Speter xpp->sp_debug = 0; 132010015Speter else { 132110015Speter xpp->sp_debug = DBG_ALL; 132210015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 132310015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 132410015Speter } 132510015Speter break; 132610015Speter#else 132710015Speter error = ENODEV; 132810015Speter goto out; 132910015Speter#endif 133010015Speter case TCSISDBG_LEVEL: 133110015Speter case TCSIGDBG_LEVEL: 133210015Speter#ifdef SI_DEBUG 133310015Speter if (cmd == TCSIGDBG_LEVEL) { 133410015Speter dp->tc_dbglvl = xpp->sp_debug; 133510015Speter } else { 133610015Speter SUCHECK; 133710015Speter xpp->sp_debug = dp->tc_dbglvl; 133810015Speter } 133910015Speter break; 134010015Speter#else 134110015Speter error = ENODEV; 134210015Speter goto out; 134310015Speter#endif 134410015Speter case TCSIGRXIT: 134510015Speter dp->tc_int = regp->rx_int_count; 134610015Speter break; 134710015Speter case TCSIRXIT: 134810015Speter SUCHECK; 134910015Speter regp->rx_int_count = dp->tc_int; 135010015Speter break; 135110015Speter case TCSIGIT: 135210015Speter dp->tc_int = regp->int_count; 135310015Speter break; 135410015Speter case TCSIIT: 135510015Speter SUCHECK; 135610015Speter regp->int_count = dp->tc_int; 135710015Speter break; 135810044Speter case TCSISTATE: 135910044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 136010015Speter break; 136110044Speter /* these next three use a different structure */ 136210044Speter case TCSI_PORT: 136310015Speter SUCHECK; 136416444Speter bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 136510015Speter break; 136610044Speter case TCSI_CCB: 136710044Speter SUCHECK; 136816444Speter bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 136910015Speter break; 137010044Speter case TCSI_TTY: 137110044Speter SUCHECK; 137216444Speter bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 137310015Speter break; 137410015Speter default: 137510015Speter error = EINVAL; 137610015Speter goto out; 137710015Speter } 137810015Speterout: 137910015Speter splx(oldspl); 138010015Speter return(error); /* success */ 138110015Speter} 138210015Speter 138310015Speter/* 138410015Speter * siparam() : Configure line params 138510015Speter * called at spltty(); 138610015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 138710015Speter * caller must arrange this if it's important.. 138810015Speter */ 138912724Sphkstatic int 139010015Spetersiparam(tp, t) 139110015Speter register struct tty *tp; 139210015Speter register struct termios *t; 139310015Speter{ 139410015Speter register struct si_port *pp = TP2PP(tp); 139510015Speter volatile struct si_channel *ccbp; 139610015Speter int oldspl, cflag, iflag, oflag, lflag; 139710015Speter int error = 0; /* shutup gcc */ 139810015Speter int ispeed = 0; /* shutup gcc */ 139910015Speter int ospeed = 0; /* shutup gcc */ 140010161Speter BYTE val; 140110015Speter 140210015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 140310015Speter cflag = t->c_cflag; 140410015Speter iflag = t->c_iflag; 140510015Speter oflag = t->c_oflag; 140610015Speter lflag = t->c_lflag; 140710044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 140810044Speter oflag, cflag, iflag, lflag)); 140910015Speter 141010015Speter 141110015Speter /* if not hung up.. */ 141210015Speter if (t->c_ospeed != 0) { 141310015Speter /* translate baud rate to firmware values */ 141410015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 141510015Speter ispeed = t->c_ispeed ? 141610015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 141710015Speter 141810015Speter /* enforce legit baud rate */ 141910015Speter if (ospeed < 0 || ispeed < 0) 142010015Speter return (EINVAL); 142110015Speter } 142210015Speter 142310015Speter 142410015Speter oldspl = spltty(); 142510015Speter 142610015Speter ccbp = pp->sp_ccb; 142710015Speter 142810161Speter /* ========== set hi_break ========== */ 142910161Speter val = 0; 143010161Speter if (iflag & IGNBRK) /* Breaks */ 143110161Speter val |= BR_IGN; 143210161Speter if (iflag & BRKINT) /* Interrupt on break? */ 143310161Speter val |= BR_INT; 143410161Speter if (iflag & PARMRK) /* Parity mark? */ 143510161Speter val |= BR_PARMRK; 143610161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 143710161Speter val |= BR_PARIGN; 143810161Speter ccbp->hi_break = val; 143910161Speter 144010161Speter /* ========== set hi_csr ========== */ 144110015Speter /* if not hung up.. */ 144210015Speter if (t->c_ospeed != 0) { 144310015Speter /* Set I/O speeds */ 144410161Speter val = (ispeed << 4) | ospeed; 144510015Speter } 144610161Speter ccbp->hi_csr = val; 144710015Speter 144810161Speter /* ========== set hi_mr2 ========== */ 144910161Speter val = 0; 145010015Speter if (cflag & CSTOPB) /* Stop bits */ 145110161Speter val |= MR2_2_STOP; 145210015Speter else 145310161Speter val |= MR2_1_STOP; 145410161Speter /* 145510161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 145610161Speter * a DCE, hence the reverse sense of RTS and CTS 145710161Speter */ 145810161Speter /* Output Flow - RTS must be raised before data can be sent */ 145910161Speter if (cflag & CCTS_OFLOW) 146010161Speter val |= MR2_RTSCONT; 146110161Speter 146216575Speter ccbp->hi_mr2 = val; 146310161Speter 146410161Speter /* ========== set hi_mr1 ========== */ 146510161Speter val = 0; 146610015Speter if (!(cflag & PARENB)) /* Parity */ 146710161Speter val |= MR1_NONE; 146810015Speter else 146910161Speter val |= MR1_WITH; 147010015Speter if (cflag & PARODD) 147110161Speter val |= MR1_ODD; 147210015Speter 147310015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 147410161Speter val |= MR1_8_BITS; 147510015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 147610161Speter val |= MR1_7_BITS; 147710015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 147810161Speter val |= MR1_6_BITS; 147910015Speter } else { /* Must be 5 */ 148010161Speter val |= MR1_5_BITS; 148110015Speter } 148210161Speter /* 148310161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 148410161Speter * a DCE, hence the reverse sense of RTS and CTS 148510161Speter */ 148610161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 148710161Speter if (cflag & CRTS_IFLOW) 148810161Speter val |= MR1_CTSCONT; 148910015Speter 149010161Speter ccbp->hi_mr1 = val; 149110161Speter 149210161Speter /* ========== set hi_mask ========== */ 149310161Speter val = 0xff; 149410161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 149510161Speter val &= 0xFF; 149610161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 149710161Speter val &= 0x7F; 149810161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 149910161Speter val &= 0x3F; 150010161Speter } else { /* Must be 5 */ 150110161Speter val &= 0x1F; 150210161Speter } 150310015Speter if (iflag & ISTRIP) 150410161Speter val &= 0x7F; 150510015Speter 150610161Speter ccbp->hi_mask = val; 150710161Speter 150810161Speter /* ========== set hi_prtcl ========== */ 150910161Speter val = 0; 151010015Speter /* Monitor DCD etc. if a modem */ 151110015Speter if (!(cflag & CLOCAL)) 151210161Speter val |= SP_DCEN; 151310161Speter if (iflag & IXANY) 151410161Speter val |= SP_TANY; 151510161Speter if (iflag & IXON) 151610161Speter val |= SP_TXEN; 151710161Speter if (iflag & IXOFF) 151810161Speter val |= SP_RXEN; 151910161Speter if (iflag & INPCK) 152010161Speter val |= SP_PAEN; 152110015Speter 152210161Speter ccbp->hi_prtcl = val; 152310161Speter 152410161Speter 152510161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 152610161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 152710015Speter ccbp->hi_txon = t->c_cc[VSTART]; 152810015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 152910015Speter 153010015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 153110015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 153210015Speter 153310161Speter /* ========== send settings to the card ========== */ 153410015Speter /* potential sleep here */ 153510015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 153610015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 153710015Speter else 153810015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 153910015Speter 154010161Speter /* ========== set DTR etc ========== */ 154110015Speter /* Hangup if ospeed == 0 */ 154210015Speter if (t->c_ospeed == 0) { 154310015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 154410015Speter } else { 154510015Speter /* 154610015Speter * If the previous speed was 0, may need to re-enable 154710015Speter * the modem signals 154810015Speter */ 154910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 155010015Speter } 155110015Speter 155210044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 155310044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 155410015Speter 155510015Speter splx(oldspl); 155610015Speter return(error); 155710015Speter} 155810015Speter 155910015Speter/* 156010015Speter * Enable or Disable the writes to this channel... 156110015Speter * "state" -> enabled = 1; disabled = 0; 156210015Speter */ 156310015Speterstatic void 156410015Spetersi_write_enable(pp, state) 156510015Speter register struct si_port *pp; 156610015Speter int state; 156710015Speter{ 156810015Speter int oldspl; 156910015Speter 157010015Speter oldspl = spltty(); 157110015Speter 157210015Speter if (state) { 157310015Speter pp->sp_state &= ~SS_BLOCKWRITE; 157410015Speter if (pp->sp_state & SS_WAITWRITE) { 157510015Speter pp->sp_state &= ~SS_WAITWRITE; 157610015Speter /* thunder away! */ 157710015Speter wakeup((caddr_t)pp); 157810015Speter } 157910015Speter } else { 158010015Speter pp->sp_state |= SS_BLOCKWRITE; 158110015Speter } 158210015Speter 158310015Speter splx(oldspl); 158410015Speter} 158510015Speter 158610015Speter/* 158710015Speter * Set/Get state of modem control lines. 158810015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 158910015Speter * TIOCM_DTR DSR 159010015Speter * TIOCM_RTS CTS 159110015Speter */ 159210015Speterstatic int 159310015Spetersi_modem(pp, cmd, bits) 159410015Speter struct si_port *pp; 159510015Speter enum si_mctl cmd; 159610015Speter int bits; 159710015Speter{ 159810015Speter volatile struct si_channel *ccbp; 159910015Speter int x; 160010015Speter 160110015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 160210015Speter ccbp = pp->sp_ccb; /* Find channel address */ 160310015Speter switch (cmd) { 160410015Speter case GET: 160510015Speter x = ccbp->hi_ip; 160610015Speter bits = TIOCM_LE; 160710015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 160810015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 160910015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 161010015Speter if (x & IP_RI) bits |= TIOCM_RI; 161110015Speter return(bits); 161210015Speter case SET: 161310015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 161410015Speter /* fall through */ 161510015Speter case BIS: 161610015Speter x = 0; 161710015Speter if (bits & TIOCM_DTR) 161810015Speter x |= OP_DSR; 161910015Speter if (bits & TIOCM_RTS) 162010015Speter x |= OP_CTS; 162110015Speter ccbp->hi_op |= x; 162210015Speter break; 162310015Speter case BIC: 162410015Speter if (bits & TIOCM_DTR) 162510015Speter ccbp->hi_op &= ~OP_DSR; 162610015Speter if (bits & TIOCM_RTS) 162710015Speter ccbp->hi_op &= ~OP_CTS; 162810015Speter } 162910015Speter return 0; 163010015Speter} 163110015Speter 163210015Speter/* 163310015Speter * Handle change of modem state 163410015Speter */ 163510015Speterstatic void 163610015Spetersi_modem_state(pp, tp, hi_ip) 163710015Speter register struct si_port *pp; 163810015Speter register struct tty *tp; 163910015Speter register int hi_ip; 164010015Speter{ 164110015Speter /* if a modem dev */ 164210015Speter if (hi_ip & IP_DCD) { 164310015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 164410015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 164510015Speter tp->t_line)); 164610015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 164710015Speter } 164810015Speter } else { 164910015Speter if (pp->sp_last_hi_ip & IP_DCD) { 165010015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 165110015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 165210015Speter (void) si_modem(pp, SET, 0); 165310015Speter } 165410015Speter } 165510015Speter pp->sp_last_hi_ip = hi_ip; 165610015Speter 165710015Speter} 165810015Speter 165910015Speter/* 166010015Speter * Poller to catch missed interrupts. 166112174Speter * 166212496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 166312496Speter * better response. We could really use a "periodic" version timeout(). :-) 166410015Speter */ 166510015Speter#ifdef POLL 166610708Speterstatic void 166710015Spetersi_poll(void *nothing) 166810015Speter{ 166910015Speter register struct si_softc *sc; 167010015Speter register int i; 167110015Speter volatile struct si_reg *regp; 167212174Speter register struct si_port *pp; 167312174Speter int lost, oldspl, port; 167410015Speter 167510015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 167611609Speter oldspl = spltty(); 167710015Speter if (in_intr) 167810015Speter goto out; 167910015Speter lost = 0; 168010015Speter for (i=0; i<NSI; i++) { 168110015Speter sc = &si_softc[i]; 168212174Speter if (sc->sc_type == SIEMPTY) 168310015Speter continue; 168410015Speter regp = (struct si_reg *)sc->sc_maddr; 168510015Speter /* 168610015Speter * See if there has been a pending interrupt for 2 seconds 168710015Speter * or so. The test <int_scounter >= 200) won't correspond 168810015Speter * to 2 seconds if int_count gets changed. 168910015Speter */ 169010015Speter if (regp->int_pending != 0) { 169110015Speter if (regp->int_scounter >= 200 && 169210015Speter regp->initstat == 1) { 169312174Speter printf("si%d: lost intr\n", i); 169410015Speter lost++; 169510015Speter } 169610015Speter } else { 169710015Speter regp->int_scounter = 0; 169810015Speter } 169910015Speter 170012174Speter /* 170112174Speter * gripe about no input flow control.. 170212174Speter */ 170312174Speter pp = sc->sc_ports; 170412174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 170512174Speter if (pp->sp_delta_overflows > 0) { 170612174Speter printf("si%d: %d tty level buffer overflows\n", 170712174Speter i, pp->sp_delta_overflows); 170812174Speter pp->sp_delta_overflows = 0; 170912174Speter } 171012174Speter } 171110015Speter } 171217547Speter if (lost || si_realpoll) 171310015Speter siintr(-1); /* call intr with fake vector */ 171411609Speterout: 171510015Speter splx(oldspl); 171610015Speter 171715639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 171810015Speter} 171910015Speter#endif /* ifdef POLL */ 172010015Speter 172110015Speter/* 172210015Speter * The interrupt handler polls ALL ports on ALL adapters each time 172310015Speter * it is called. 172410015Speter */ 172510015Speter 172612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 172710015Speter 172810708Spetervoid 172911609Spetersiintr(int unit) 173010015Speter{ 173110015Speter register struct si_softc *sc; 173210015Speter 173310015Speter register struct si_port *pp; 173410015Speter volatile struct si_channel *ccbp; 173510015Speter register struct tty *tp; 173610015Speter volatile caddr_t maddr; 173711872Sphk BYTE op, ip; 173812174Speter int x, card, port, n, i, isopen; 173910015Speter volatile BYTE *z; 174010015Speter BYTE c; 174110015Speter 174211609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 174311609Speter if (in_intr) { 174411609Speter if (unit < 0) /* should never happen */ 174510708Speter return; 174612174Speter printf("si%d: Warning interrupt handler re-entered\n", 174711609Speter unit); 174810708Speter return; 174910015Speter } 175010015Speter in_intr = 1; 175110015Speter 175210015Speter /* 175310015Speter * When we get an int we poll all the channels and do ALL pending 175410015Speter * work, not just the first one we find. This allows all cards to 175510015Speter * share the same vector. 175610015Speter */ 175710015Speter for (card=0; card < NSI; card++) { 175810015Speter sc = &si_softc[card]; 175912174Speter if (sc->sc_type == SIEMPTY) 176010015Speter continue; 176112174Speter 176212174Speter /* 176312174Speter * First, clear the interrupt 176412174Speter */ 176510015Speter switch(sc->sc_type) { 176610015Speter case SIHOST : 176710015Speter maddr = sc->sc_maddr; 176810015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 176910015Speter /* flag nothing pending */ 177010015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 177110015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 177210015Speter break; 177310015Speter case SIHOST2: 177410015Speter maddr = sc->sc_maddr; 177510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 177610015Speter *(maddr+SIPLIRQCLR) = 0x00; 177710015Speter *(maddr+SIPLIRQCLR) = 0x10; 177810015Speter break; 177910015Speter case SIEISA: 178010015Speter#if NEISA > 0 178110015Speter maddr = sc->sc_maddr; 178210015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 178310015Speter (void)inb(sc->sc_eisa_iobase+3); 178410015Speter break; 178510015Speter#endif /* fall through if not EISA kernel */ 178610015Speter case SIEMPTY: 178710015Speter default: 178810015Speter continue; 178910015Speter } 179010015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 179110015Speter 179212174Speter /* 179312174Speter * check each port 179412174Speter */ 179512174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 179610015Speter ccbp = pp->sp_ccb; 179710015Speter tp = pp->sp_tty; 179810015Speter 179912174Speter 180010015Speter /* 180110015Speter * See if a command has completed ? 180210015Speter */ 180310015Speter if (ccbp->hi_stat != pp->sp_pend) { 180410015Speter DPRINT((pp, DBG_INTR, 180510015Speter "siintr hi_stat = 0x%x, pend = %d\n", 180610015Speter ccbp->hi_stat, pp->sp_pend)); 180710015Speter switch(pp->sp_pend) { 180810015Speter case LOPEN: 180910015Speter case MPEND: 181010015Speter case MOPEN: 181110015Speter case CONFIG: 181216575Speter case SBREAK: 181316575Speter case EBREAK: 181410015Speter pp->sp_pend = ccbp->hi_stat; 181510015Speter /* sleeping in si_command */ 181610015Speter wakeup(&pp->sp_state); 181710015Speter break; 181810015Speter default: 181910015Speter pp->sp_pend = ccbp->hi_stat; 182010015Speter } 182110015Speter } 182210015Speter 182310015Speter /* 182410015Speter * Continue on if it's closed 182510015Speter */ 182610015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 182710015Speter continue; 182810015Speter } 182910015Speter 183010015Speter /* 183110015Speter * Do modem state change if not a local device 183210015Speter */ 183310015Speter si_modem_state(pp, tp, ccbp->hi_ip); 183410015Speter 183510015Speter /* 183612174Speter * Check to see if there's we should 'receive' 183712174Speter * characters. 183812174Speter */ 183912174Speter if (tp->t_state & TS_CONNECTED && 184012174Speter tp->t_state & TS_ISOPEN) 184112174Speter isopen = 1; 184212174Speter else 184312174Speter isopen = 0; 184412174Speter 184512174Speter /* 184616575Speter * Do input break processing 184710015Speter */ 184810015Speter if (ccbp->hi_state & ST_BREAK) { 184912174Speter if (isopen) { 185012174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 185110015Speter } 185210015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 185310015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 185410015Speter } 185510015Speter 185610015Speter /* 185712174Speter * Do RX stuff - if not open then dump any characters. 185812174Speter * XXX: This is VERY messy and needs to be cleaned up. 185912174Speter * 186012174Speter * XXX: can we leave data in the host adapter buffer 186112174Speter * when the clists are full? That may be dangerous 186212174Speter * if the user cannot get an interrupt signal through. 186310015Speter */ 186410015Speter 186512174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 186612174Speter 186712174Speter if (!isopen) { 186810015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 186912174Speter goto end_rx; 187012174Speter } 187110015Speter 187212174Speter /* 187315640Speter * If the tty input buffers are blocked, stop emptying 187415640Speter * the incoming buffers and let the auto flow control 187515640Speter * assert.. 187615640Speter */ 187715640Speter if (tp->t_state & TS_TBLOCK) { 187815640Speter goto end_rx; 187915640Speter } 188015640Speter 188115640Speter /* 188212174Speter * Process read characters if not skipped above 188312174Speter */ 188415640Speter op = ccbp->hi_rxopos; 188515640Speter ip = ccbp->hi_rxipos; 188615640Speter c = ip - op; 188712174Speter if (c == 0) { 188812174Speter goto end_rx; 188912174Speter } 189010015Speter 189112174Speter n = c & 0xff; 189215640Speter if (n > 250) 189315640Speter n = 250; 189412174Speter 189512174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 189610015Speter n, op, ip)); 189710015Speter 189812174Speter /* 189912174Speter * Suck characters out of host card buffer into the 190012174Speter * "input staging buffer" - so that we dont leave the 190112174Speter * host card in limbo while we're possibly echoing 190212174Speter * characters and possibly flushing input inside the 190312174Speter * ldisc l_rint() routine. 190412174Speter */ 190512496Speter if (n <= SI_BUFFERSIZE - op) { 190610015Speter 190712174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 190812174Speter z = ccbp->hi_rxbuf + op; 190912174Speter bcopy((caddr_t)z, si_rxbuf, n); 191010015Speter 191112174Speter op += n; 191212174Speter } else { 191312496Speter x = SI_BUFFERSIZE - op; 191410015Speter 191512174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 191612174Speter z = ccbp->hi_rxbuf + op; 191712174Speter bcopy((caddr_t)z, si_rxbuf, x); 191810015Speter 191912174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 192012174Speter z = ccbp->hi_rxbuf; 192112174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 192210015Speter 192312174Speter op += n; 192412174Speter } 192510015Speter 192612174Speter /* clear collected characters from buffer */ 192712174Speter ccbp->hi_rxopos = op; 192812174Speter 192912174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 193010015Speter n, op, ip)); 193110015Speter 193212174Speter /* 193312174Speter * at this point... 193412174Speter * n = number of chars placed in si_rxbuf 193512174Speter */ 193610015Speter 193712174Speter /* 193812174Speter * Avoid the grotesquely inefficient lineswitch 193912174Speter * routine (ttyinput) in "raw" mode. It usually 194012174Speter * takes about 450 instructions (that's without 194112174Speter * canonical processing or echo!). slinput is 194212174Speter * reasonably fast (usually 40 instructions 194312174Speter * plus call overhead). 194412174Speter */ 194512174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 194610015Speter 194712174Speter /* block if the driver supports it */ 194812174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 194912174Speter && (tp->t_cflag & CRTS_IFLOW 195012174Speter || tp->t_iflag & IXOFF) 195112174Speter && !(tp->t_state & TS_TBLOCK)) 195212174Speter ttyblock(tp); 195310015Speter 195412174Speter tk_nin += n; 195512174Speter tk_rawcc += n; 195612174Speter tp->t_rawcc += n; 195712174Speter 195812174Speter pp->sp_delta_overflows += 195912174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 196012174Speter 196112174Speter ttwakeup(tp); 196212174Speter if (tp->t_state & TS_TTSTOP 196312174Speter && (tp->t_iflag & IXANY 196412174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 196512174Speter tp->t_state &= ~TS_TTSTOP; 196612174Speter tp->t_lflag &= ~FLUSHO; 196712174Speter si_start(tp); 196812174Speter } 196912174Speter } else { 197012174Speter /* 197112174Speter * It'd be nice to not have to go through the 197212174Speter * function call overhead for each char here. 197312174Speter * It'd be nice to block input it, saving a 197412174Speter * loop here and the call/return overhead. 197512174Speter */ 197612174Speter for(x = 0; x < n; x++) { 197712174Speter i = si_rxbuf[x]; 197812174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 197912174Speter == -1) { 198012174Speter pp->sp_delta_overflows++; 198110015Speter } 198212174Speter /* 198312174Speter * doesn't seem to be much point doing 198412174Speter * this here.. this driver has no 198512174Speter * softtty processing! ?? 198612174Speter */ 198712174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 198812174Speter setsofttty(); 198912174Speter } 199012174Speter } 199112174Speter } 199212174Speter goto more_rx; /* try for more until RXbuf is empty */ 199310015Speter 199412174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 199510015Speter 199610015Speter /* 199710015Speter * Do TX stuff 199810015Speter */ 199910015Speter (*linesw[tp->t_line].l_start)(tp); 200010015Speter 200110015Speter } /* end of for (all ports on this controller) */ 200210015Speter } /* end of for (all controllers) */ 200310015Speter 200411609Speter in_intr = 0; 200511609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 200610015Speter} 200710015Speter 200810015Speter/* 200910015Speter * Nudge the transmitter... 201012174Speter * 201112174Speter * XXX: I inherited some funny code here. It implies the host card only 201212174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 201312174Speter * not interrupt when it's actually hits empty. In some cases, we have 201412174Speter * processes waiting for complete drain, and we need to simulate an interrupt 201512174Speter * about when we think the buffer is going to be empty (and retry if not). 201612174Speter * I really am not certain about this... I *need* the hardware manuals. 201710015Speter */ 201810015Speterstatic void 201910015Spetersi_start(tp) 202010015Speter register struct tty *tp; 202110015Speter{ 202210015Speter struct si_port *pp; 202310015Speter volatile struct si_channel *ccbp; 202410015Speter register struct clist *qp; 202510015Speter BYTE ipos; 202610015Speter int nchar; 202710015Speter int oldspl, count, n, amount, buffer_full; 202810015Speter int do_exitproc; 202910015Speter 203010015Speter oldspl = spltty(); 203110015Speter 203210015Speter qp = &tp->t_outq; 203310015Speter pp = TP2PP(tp); 203410015Speter 203510015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 203610015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 203710015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 203810015Speter 203910015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 204010015Speter goto out; 204110015Speter 204210015Speter do_exitproc = 0; 204310015Speter buffer_full = 0; 204410015Speter ccbp = pp->sp_ccb; 204510015Speter 204610015Speter /* 204710015Speter * Handle the case where ttywait() is called on process exit 204810015Speter * this may be BSDI specific, I dont know... 204910015Speter */ 205010015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 205110015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 205210015Speter do_exitproc++; 205310015Speter } 205410015Speter 205510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 205610015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 205710015Speter 205810015Speter while ((nchar = qp->c_cc) > 0) { 205910015Speter if ((BYTE)count >= 255) { 206010015Speter buffer_full++; 206110015Speter break; 206210015Speter } 206310015Speter amount = min(nchar, (255 - (BYTE)count)); 206410015Speter ipos = (unsigned int)ccbp->hi_txipos; 206510015Speter /* will it fit in one lump? */ 206612496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 206710015Speter n = q_to_b(&tp->t_outq, 206810015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 206910015Speter } else { 207010015Speter n = q_to_b(&tp->t_outq, 207110015Speter (char *)&ccbp->hi_txbuf[ipos], 207212496Speter SI_BUFFERSIZE-ipos); 207312496Speter if (n == SI_BUFFERSIZE-ipos) { 207410015Speter n += q_to_b(&tp->t_outq, 207510015Speter (char *)&ccbp->hi_txbuf[0], 207612496Speter amount - (SI_BUFFERSIZE-ipos)); 207710015Speter } 207810015Speter } 207910015Speter ccbp->hi_txipos += n; 208010015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 208110015Speter } 208210015Speter 208310015Speter if (count != 0 && nchar == 0) { 208410015Speter tp->t_state |= TS_BUSY; 208510015Speter } else { 208610015Speter tp->t_state &= ~TS_BUSY; 208710015Speter } 208810015Speter 208910015Speter /* wakeup time? */ 209010015Speter ttwwakeup(tp); 209110015Speter 209210015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 209310015Speter (BYTE)count, nchar, tp->t_state)); 209410015Speter 209510015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 209610015Speter { 209710015Speter int time; 209810015Speter 209910015Speter if (do_exitproc != 0) { 210010015Speter time = hz / 10; 210110015Speter } else { 210210015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 210310015Speter 210410015Speter if (time > 0) { 210510015Speter if (time < nchar) 210610015Speter time = nchar / time; 210710015Speter else 210810015Speter time = 2; 210910015Speter } else { 211016024Speter DPRINT((pp, DBG_START, 211116024Speter "bad char time value! %d\n", time)); 211216024Speter time = hz/10; 211310015Speter } 211410015Speter } 211510015Speter 211610015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 211729677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 211810015Speter } else { 211910015Speter pp->sp_state |= SS_LSTART; 212010015Speter } 212110015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 212229677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 212310015Speter } 212410015Speter 212510015Speterout: 212610015Speter splx(oldspl); 212710015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 212810015Speter} 212910015Speter 213010015Speter/* 213110015Speter * Note: called at splsoftclock from the timeout code 213210015Speter * This has to deal with two things... cause wakeups while waiting for 213310015Speter * tty drains on last process exit, and call l_start at about the right 213410015Speter * time for protocols like ppp. 213510015Speter */ 213610015Speterstatic void 213725047Sbdesi_lstart(void *arg) 213810015Speter{ 213925047Sbde register struct si_port *pp = arg; 214010015Speter register struct tty *tp; 214110015Speter int oldspl; 214210015Speter 214310015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 214410015Speter pp, pp->sp_state)); 214510015Speter 214610015Speter oldspl = spltty(); 214710015Speter 214810015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 214910015Speter splx(oldspl); 215010015Speter return; 215110015Speter } 215210015Speter pp->sp_state &= ~SS_LSTART; 215310015Speter pp->sp_state |= SS_INLSTART; 215410015Speter 215510015Speter tp = pp->sp_tty; 215610015Speter 215710015Speter /* deal with the process exit case */ 215810015Speter ttwwakeup(tp); 215910015Speter 216012174Speter /* nudge protocols - eg: ppp */ 216110015Speter (*linesw[tp->t_line].l_start)(tp); 216210015Speter 216310015Speter pp->sp_state &= ~SS_INLSTART; 216410015Speter splx(oldspl); 216510015Speter} 216610015Speter 216710015Speter/* 216810015Speter * Stop output on a line. called at spltty(); 216910015Speter */ 217010015Spetervoid 217110015Spetersistop(tp, rw) 217210015Speter register struct tty *tp; 217310015Speter int rw; 217410015Speter{ 217510015Speter volatile struct si_channel *ccbp; 217610015Speter struct si_port *pp; 217710015Speter 217810015Speter pp = TP2PP(tp); 217910015Speter ccbp = pp->sp_ccb; 218010015Speter 218110015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 218210015Speter 218310015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 218410015Speter if (rw & FWRITE) { 218510015Speter /* what level are we meant to be flushing anyway? */ 218610015Speter if (tp->t_state & TS_BUSY) { 218710015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 218810015Speter tp->t_state &= ~TS_BUSY; 218910015Speter ttwwakeup(tp); /* Bruce???? */ 219010015Speter } 219110015Speter } 219212174Speter#if 1 /* XXX: this doesn't work right yet.. */ 219312174Speter /* XXX: this may have been failing because we used to call l_rint() 219412174Speter * while we were looping based on these two counters. Now, we collect 219512174Speter * the data and then loop stuffing it into l_rint(), making this 219612174Speter * useless. Should we cause this to blow away the staging buffer? 219712174Speter */ 219810015Speter if (rw & FREAD) { 219910015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 220010015Speter } 220110015Speter#endif 220210015Speter} 220310015Speter 220410015Speter/* 220510015Speter * Issue a command to the Z280 host card CPU. 220610015Speter */ 220710015Speter 220810015Speterstatic void 220910015Spetersi_command(pp, cmd, waitflag) 221010015Speter struct si_port *pp; /* port control block (local) */ 221110015Speter int cmd; 221210015Speter int waitflag; 221310015Speter{ 221410015Speter int oldspl; 221510015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 221610015Speter int x; 221710015Speter 221810015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 221910015Speter pp, cmd, waitflag, ccbp->hi_stat)); 222010015Speter 222110015Speter oldspl = spltty(); /* Keep others out */ 222210015Speter 222310015Speter /* wait until it's finished what it was doing.. */ 222416575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 222516575Speter * is turned off. */ 222610015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 222710015Speter x != IDLE_CLOSE && 222816575Speter x != IDLE_BREAK && 222910015Speter x != cmd) { 223010015Speter if (in_intr) { /* Prevent sleep in intr */ 223110015Speter DPRINT((pp, DBG_PARAM, 223210015Speter "cmd intr collision - completing %d\trequested %d\n", 223310015Speter x, cmd)); 223410015Speter splx(oldspl); 223510015Speter return; 223610015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 223710015Speter "sicmd1", 1)) { 223810015Speter splx(oldspl); 223910015Speter return; 224010015Speter } 224110015Speter } 224216575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 224310015Speter 224410015Speter /* if there was a pending command, cause a state-change wakeup */ 224516575Speter switch(pp->sp_pend) { 224616575Speter case LOPEN: 224716575Speter case MPEND: 224816575Speter case MOPEN: 224916575Speter case CONFIG: 225016575Speter case SBREAK: 225116575Speter case EBREAK: 225216575Speter wakeup(&pp->sp_state); 225316575Speter break; 225416575Speter default: 225516575Speter break; 225610015Speter } 225710015Speter 225810015Speter pp->sp_pend = cmd; /* New command pending */ 225910015Speter ccbp->hi_stat = cmd; /* Post it */ 226010015Speter 226110015Speter if (waitflag) { 226210015Speter if (in_intr) { /* If in interrupt handler */ 226310015Speter DPRINT((pp, DBG_PARAM, 226410015Speter "attempt to sleep in si_intr - cmd req %d\n", 226510015Speter cmd)); 226610015Speter splx(oldspl); 226710015Speter return; 226816575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 226916575Speter ccbp->hi_stat != IDLE_BREAK) { 227010015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 227110015Speter "sicmd2", 0)) 227210015Speter break; 227310015Speter } 227410015Speter } 227510015Speter splx(oldspl); 227610015Speter} 227710015Speter 227810015Speterstatic void 227910015Spetersi_disc_optim(tp, t, pp) 228010015Speter struct tty *tp; 228110015Speter struct termios *t; 228210015Speter struct si_port *pp; 228310015Speter{ 228410015Speter /* 228510015Speter * XXX can skip a lot more cases if Smarts. Maybe 228610015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 228710015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 228810015Speter */ 228910015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 229010015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 229110015Speter && (!(t->c_iflag & PARMRK) 229210015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 229310015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 229410015Speter && linesw[tp->t_line].l_rint == ttyinput) 229510015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 229610015Speter else 229710015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 229810161Speter 229910015Speter /* 230010015Speter * Prepare to reduce input latency for packet 230110015Speter * discplines with a end of packet character. 230210015Speter */ 230310015Speter if (tp->t_line == SLIPDISC) 230410015Speter pp->sp_hotchar = 0xc0; 230510015Speter else if (tp->t_line == PPPDISC) 230610015Speter pp->sp_hotchar = 0x7e; 230710015Speter else 230810015Speter pp->sp_hotchar = 0; 230910161Speter 231010161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 231110161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 231210161Speter pp->sp_hotchar)); 231310015Speter} 231410015Speter 231510015Speter 231610015Speter#ifdef SI_DEBUG 231713353Speter 231810015Speterstatic void 231913353Speter#ifdef __STDC__ 232013353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 232113353Speter#else 232213353Spetersi_dprintf(pp, flags, fmt, va_alist) 232310015Speter struct si_port *pp; 232410015Speter int flags; 232513353Speter char *fmt; 232613353Speter#endif 232710015Speter{ 232813353Speter va_list ap; 232913630Sphk 233010015Speter if ((pp == NULL && (si_debug&flags)) || 233110015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 233210015Speter if (pp != NULL) 233312496Speter printf("%ci%d(%d): ", 's', 233412174Speter (int)SI_CARD(pp->sp_tty->t_dev), 233512174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 233613630Sphk va_start(ap, fmt); 233713630Sphk vprintf(fmt, ap); 233813353Speter va_end(ap); 233910015Speter } 234010015Speter} 234110015Speter 234210015Speterstatic char * 234310015Spetersi_mctl2str(cmd) 234410015Speter enum si_mctl cmd; 234510015Speter{ 234610015Speter switch (cmd) { 234710015Speter case GET: return("GET"); 234810015Speter case SET: return("SET"); 234910015Speter case BIS: return("BIS"); 235010015Speter case BIC: return("BIC"); 235110015Speter } 235210015Speter return("BAD"); 235310015Speter} 235412502Sjulian 235512624Speter#endif /* DEBUG */ 235612502Sjulian 235712624Speter 235812502Sjulian 235912502Sjulianstatic si_devsw_installed = 0; 236012502Sjulian 236112517Sjulianstatic void si_drvinit(void *unused) 236212502Sjulian{ 236312517Sjulian dev_t dev; 236412517Sjulian 236512502Sjulian if( ! si_devsw_installed ) { 236612675Sjulian dev = makedev(CDEV_MAJOR, 0); 236712675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 236812502Sjulian si_devsw_installed = 1; 236912517Sjulian } 237012502Sjulian} 237112517Sjulian 237212517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 237312517Sjulian 2374