si.c revision 13353
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 * 3313169Speter * $Id: si.c,v 1.32 1996/01/02 09:20:29 peter Exp $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3710015Speterstatic char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 3810015Speter si_copyright2[] = "@(#) (C) Andy Rutter 1993", 3910015Speter si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 4010015Speter#endif /* not lint */ 4110015Speter 4210015Speter#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> 7213353Speter#include <machine/stdarg.h> 7310015Speter 7410015Speter#include "si.h" 7510015Speter 7610015Speter/* 7710015Speter * This device driver is designed to interface the Specialix International 7812496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 7910015Speter * 8010015Speter * The controller is interfaced to the host via dual port ram 8110015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 8210015Speter */ 8310015Speter 8410015Speter#define POLL /* turn on poller to generate buffer empty interrupt */ 8512174Speter#undef FASTPOLL /* turn on 100Hz poller, (XXX: NOTYET!) */ 8610047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8712496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8810015Speter 8910015Speterenum si_mctl { GET, SET, BIS, BIC }; 9010015Speter 9112675Sjulianstatic const char devchar[] = "ABCDEFGHIJK"; 9212675Sjulianstatic const char portchar[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 9312502Sjulian 9412502Sjulian 9510015Speterstatic void si_command __P((struct si_port *, int, int)); 9610015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 9710015Speterstatic void si_write_enable __P((struct si_port *, int)); 9810015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9910015Speterstatic void si_start __P((struct tty *)); 10010015Speterstatic void si_lstart __P((struct si_port *)); 10110015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 10210015Speter struct si_port *pp)); 10310015Speterstatic void sihardclose __P((struct si_port *pp)); 10410015Speterstatic void sidtrwakeup __P((void *chan)); 10510015Speter 10612724Sphkstatic int siparam __P((struct tty *, struct termios *)); 10710015Speter 10812724Sphkstatic void si_registerdev __P((struct isa_device *id)); 10912724Sphkstatic int siprobe __P((struct isa_device *id)); 11012724Sphkstatic int siattach __P((struct isa_device *id)); 11110708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 11210708Speter 11312675Sjulianstruct isa_driver sidriver = 11412675Sjulian { siprobe, siattach, "si" }; 11512675Sjulian 11612675Sjulian 11712675Sjulianstatic d_open_t siopen; 11812675Sjulianstatic d_close_t siclose; 11912675Sjulianstatic d_read_t siread; 12012675Sjulianstatic d_write_t siwrite; 12112675Sjulianstatic d_ioctl_t siioctl; 12212675Sjulianstatic d_stop_t sistop; 12312731Sbdestatic d_devtotty_t sidevtotty; 12412675Sjulian 12512675Sjulian#define CDEV_MAJOR 68 12612678Sphkstatic struct cdevsw si_cdevsw = 12712675Sjulian { siopen, siclose, siread, siwrite, /*68*/ 12812743Sbde siioctl, sistop, noreset, sidevtotty,/* si */ 12912742Sbde ttselect, nommap, NULL, "si", NULL, -1 }; 13012675Sjulian 13112675Sjulian 13212174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 13313353Speter 13413353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 13513353Speter ...)); 13610708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 13713353Speter 13810708Speter#define DPRINT(x) si_dprintf x 13913353Speter 14010708Speter#else 14110708Speter#define DPRINT(x) /* void */ 14210708Speter#endif 14310708Speter 14410962Speterstatic int si_Nports; 14510962Speterstatic int si_Nmodules; 14610962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 14710015Speter 14810962Speterstatic struct tty *si_tty; 14910962Speter 15012174Speter/* where the firmware lives; defined in si_code.c */ 15110015Speterextern int si_dsize; 15210015Speterextern unsigned char si_download[]; 15310015Speter 15412888Speter#ifdef DEVFS 15512888Speterstatic char chardev[] = "0123456789abcdef"; 15612888Speter#endif 15712888Speter 15810044Speterstruct si_softc { 15910044Speter int sc_type; /* adapter type */ 16010044Speter char *sc_typename; /* adapter type string */ 16110044Speter 16210044Speter struct si_port *sc_ports; /* port structures for this card */ 16310044Speter 16410044Speter caddr_t sc_paddr; /* physical addr of iomem */ 16510044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 16610044Speter int sc_nport; /* # ports on this card */ 16710044Speter int sc_irq; /* copy of attach irq */ 16810044Speter int sc_eisa_iobase; /* EISA io port address */ 16910044Speter int sc_eisa_irqbits; 17010044Speter struct kern_devconf sc_kdc; 17112675Sjulian#ifdef DEVFS 17212675Sjulian struct { 17312675Sjulian void *ttyd; 17412826Speter void *cuaa; 17512675Sjulian void *ttyl; 17612675Sjulian void *ttyi; 17712675Sjulian } devfs_token[32]; /* what is the max per card? */ 17813165Speter void *control_token; 17912675Sjulian#endif 18010044Speter}; 18112724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 18210044Speter 18312174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 18410015Speter# define B2000 2000 18510015Speter#endif 18610015Speterstatic struct speedtab bdrates[] = { 18710015Speter B75, CLK75, /* 0x0 */ 18810015Speter B110, CLK110, /* 0x1 */ 18910015Speter B150, CLK150, /* 0x3 */ 19010015Speter B300, CLK300, /* 0x4 */ 19110015Speter B600, CLK600, /* 0x5 */ 19210015Speter B1200, CLK1200, /* 0x6 */ 19310015Speter B2000, CLK2000, /* 0x7 */ 19410015Speter B2400, CLK2400, /* 0x8 */ 19510015Speter B4800, CLK4800, /* 0x9 */ 19610015Speter B9600, CLK9600, /* 0xb */ 19710015Speter B19200, CLK19200, /* 0xc */ 19810015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 19910015Speter B57600, CLK57600, /* 0xd */ 20010015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 20110015Speter -1, -1 20210015Speter}; 20310015Speter 20410015Speter 20510015Speter/* populated with approx character/sec rates - translated at card 20610015Speter * initialisation time to chars per tick of the clock */ 20710015Speterstatic int done_chartimes = 0; 20810015Speterstatic struct speedtab chartimes[] = { 20910015Speter B75, 8, 21010015Speter B110, 11, 21110015Speter B150, 15, 21210015Speter B300, 30, 21310015Speter B600, 60, 21410015Speter B1200, 120, 21510015Speter B2000, 200, 21610015Speter B2400, 240, 21710015Speter B4800, 480, 21810015Speter B9600, 960, 21910015Speter B19200, 1920, 22010015Speter B38400, 3840, 22110015Speter B57600, 5760, 22210015Speter B115200, 11520, 22310015Speter -1, -1 22410015Speter}; 22510015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 22610015Speter 22710047Speterstatic int si_default_rate = TTYDEF_SPEED; 22810047Speterstatic int si_default_iflag = 0; 22910047Speterstatic int si_default_oflag = 0; 23010047Speterstatic int si_default_lflag = 0; 23110047Speter#ifdef SI_DEF_HWFLOW 23210047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 23310047Speter#else 23410047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 23510047Speter#endif 23610047Speter 23710015Speter#ifdef POLL 23810015Speter#define POLL_INTERVAL (hz/2) 23910015Speterstatic int init_finished = 0; 24012174Speterstatic int fastpoll = 0; 24110015Speterstatic void si_poll __P((void *)); 24210015Speter#endif 24310015Speter 24410015Speter/* 24510015Speter * Array of adapter types and the corresponding RAM size. The order of 24610015Speter * entries here MUST match the ordinal of the adapter type. 24710015Speter */ 24810015Speterstatic char *si_type[] = { 24910015Speter "EMPTY", 25010015Speter "SIHOST", 25110015Speter "SI2", /* MCA */ 25210015Speter "SIHOST2", 25310015Speter "SIEISA", 25410015Speter}; 25510015Speter 25610015Speter 25710015Speterstatic struct kern_devconf si_kdc[NSI] = { { 25810015Speter 0, 0, 0, /* filled in by dev_attach */ 25910015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 26010015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 26110015Speter &kdc_isa0, /* parent */ 26210015Speter 0, /* parent data */ 26310015Speter DC_UNCONFIGURED, /* state */ 26410015Speter "Specialix SI/XIO Host adapter", 26510015Speter DC_CLS_SERIAL, /* class */ 26610015Speter} }; 26710015Speter 26812724Sphkstatic void 26910015Spetersi_registerdev(id) 27010015Speter struct isa_device *id; 27110015Speter{ 27210015Speter if (id->id_unit != 0) { 27310015Speter si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 27410015Speter } 27510015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 27610015Speter si_kdc[id->id_unit].kdc_isa = id; 27712174Speter si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 27810015Speter dev_attach(&si_kdc[id->id_unit]); 27910015Speter} 28010015Speter 28110015Speter/* Look for a valid board at the given mem addr */ 28212724Sphkstatic int 28310015Spetersiprobe(id) 28410015Speter struct isa_device *id; 28510015Speter{ 28610015Speter struct si_softc *sc; 28710015Speter int type; 28810015Speter u_int i, ramsize; 28910015Speter volatile BYTE was, *ux; 29010015Speter volatile unsigned char *maddr; 29110015Speter unsigned char *paddr; 29210015Speter 29310015Speter si_registerdev(id); 29410015Speter 29510015Speter maddr = id->id_maddr; /* virtual address... */ 29610015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 29710015Speter 29812496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 29912496Speter id->id_unit, id->id_maddr, paddr)); 30010015Speter 30110015Speter /* 30210015Speter * this is a lie, but it's easier than trying to handle caching 30310015Speter * and ram conflicts in the >1M and <16M region. 30410015Speter */ 30510015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 30610015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 30712174Speter printf("si%d: iomem (%lx) out of range\n", 30812174Speter id->id_unit, (long)paddr); 30910015Speter return(0); 31010015Speter } 31110015Speter 31210015Speter if (id->id_unit >= NSI) { 31310015Speter /* THIS IS IMPOSSIBLE */ 31410015Speter return(0); 31510015Speter } 31610015Speter 31710015Speter if (((u_int)paddr & 0x7fff) != 0) { 31810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 31910015Speter "si%d: iomem (%x) not on 32k boundary\n", 32010015Speter id->id_unit, paddr)); 32110015Speter return(0); 32210015Speter } 32310015Speter 32410015Speter 32510015Speter for (i=0; i < NSI; i++) { 32610015Speter if ((sc = &si_softc[i]) == NULL) 32710015Speter continue; 32810015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 32910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 33010015Speter "si%d: iomem (%x) already configured to si%d\n", 33110015Speter id->id_unit, sc->sc_paddr, i)); 33210015Speter return(0); 33310015Speter } 33410015Speter } 33510015Speter 33610015Speter#if NEISA > 0 33710015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 33810015Speter int irq, port; 33910015Speter unsigned long base; 34010015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 34110015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 34210015Speter 34310015Speter port = id->id_iobase; 34410015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 34510015Speter irq = ((inb(port+2) >> 4) & 0xf); 34610015Speter 34710015Speter id->id_irq = eisa_irqs[irq]; 34810015Speter 34910015Speter DPRINT((0, DBG_AUTOBOOT, 35012496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 35110015Speter id->id_unit, base, irq, id->id_irq, port)); 35210015Speter 35310015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 35410015Speter goto bad_irq; 35510015Speter 35610015Speter id->id_iobase &= 0xf000; 35710015Speter id->id_iosize = 0x0fff; 35810015Speter 35910015Speter type = EISA; 36010015Speter outb(p+2, (BYTE)irq << 4); 36110015Speter 36210015Speter sc->sc_eisa_iobase = p; 36310015Speter sc->sc_eisa_irqbits = irq << 4; 36410015Speter ramsize = SIEISA_RAMSIZE; 36510015Speter goto got_card; 36610015Speter } 36710015Speter#endif 36810015Speter 36910015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 37010015Speter *maddr = 0x17; 37110015Speter if (*maddr != 0x17) { 37210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 37310015Speter "si%d: 0x17 check fail at phys 0x%x\n", 37410015Speter id->id_unit, paddr)); 37510015Speterfail: 37610015Speter return(0); 37710015Speter } 37810015Speter /* 37910015Speter * OK, now to see if whatever responded is really an SI card. 38010015Speter * Try for a MK II first (SIHOST2) 38110015Speter */ 38210015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 38310015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 38410015Speter goto try_mk1; 38510015Speter 38610015Speter /* It must be an SIHOST2 */ 38710015Speter *(maddr + SIPLRESET) = 0; 38810015Speter *(maddr + SIPLIRQCLR) = 0; 38910015Speter *(maddr + SIPLIRQSET) = 0x10; 39010015Speter type = SIHOST2; 39110015Speter ramsize = SIHOST2_RAMSIZE; 39210015Speter goto got_card; 39310015Speter 39410015Speter /* 39510015Speter * Its not a MK II, so try for a MK I (SIHOST) 39610015Speter */ 39710015Spetertry_mk1: 39810015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 39910015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 40010015Speter *(maddr+SIRAM) = 0x17; 40110015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 40210015Speter goto fail; 40310015Speter *(maddr+0x7ff8) = 0x17; 40410015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 40510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 40610015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 40710015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 40810015Speter goto fail; 40910015Speter } 41010015Speter 41110015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 41210015Speter type = SIHOST; 41310015Speter ramsize = SIHOST_RAMSIZE; 41410015Speter 41510015Spetergot_card: 41612496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 41712496Speter id->id_unit, type)); 41810015Speter /* Try the acid test */ 41910015Speter ux = (BYTE *)(maddr + SIRAM); 42010015Speter for (i=0; i<ramsize; i++, ux++) 42110015Speter *ux = (BYTE)(i&0xff); 42210015Speter ux = (BYTE *)(maddr + SIRAM); 42310015Speter for (i=0; i<ramsize; i++, ux++) { 42410015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 42510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 42612174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 42710015Speter id->id_unit, paddr+i, was, i&0xff)); 42810015Speter goto fail; 42910015Speter } 43010015Speter } 43110015Speter 43210015Speter /* clear out the RAM */ 43310015Speter ux = (BYTE *)(maddr + SIRAM); 43410015Speter for (i=0; i<ramsize; i++) 43510015Speter *ux++ = 0; 43610015Speter ux = (BYTE *)(maddr + SIRAM); 43710015Speter for (i=0; i<ramsize; i++) { 43810015Speter if ((was = *ux++) != 0) { 43910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 44012174Speter "si%d: clear fail at phys 0x%x, was %x\n", 44110015Speter id->id_unit, paddr+i, was)); 44210015Speter goto fail; 44310015Speter } 44410015Speter } 44510015Speter 44610015Speter /* 44710015Speter * Success, we've found a valid board, now fill in 44810015Speter * the adapter structure. 44910015Speter */ 45010015Speter switch (type) { 45110015Speter case SIHOST2: 45210015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 45310015Speterbad_irq: 45410015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 45510015Speter "si%d: bad IRQ value - %d\n", 45610015Speter id->id_unit, id->id_irq)); 45710015Speter return(0); 45810015Speter } 45910015Speter id->id_msize = SIHOST2_MEMSIZE; 46010015Speter break; 46110015Speter case SIHOST: 46210015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 46310015Speter goto bad_irq; 46410015Speter } 46510015Speter id->id_msize = SIHOST_MEMSIZE; 46610015Speter break; 46710015Speter case SIEISA: 46810015Speter id->id_msize = SIEISA_MEMSIZE; 46910015Speter break; 47010015Speter case SI2: /* MCA */ 47110015Speter default: 47210015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 47310015Speter return(0); 47410015Speter } 47510015Speter si_softc[id->id_unit].sc_type = type; 47610015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 47710015Speter return(-1); /* -1 == found */ 47810015Speter} 47910015Speter 48010015Speter/* 48110015Speter * Attach the device. Initialize the card. 48210015Speter */ 48312724Sphkstatic int 48410015Spetersiattach(id) 48510015Speter struct isa_device *id; 48610015Speter{ 48710015Speter int unit = id->id_unit; 48810015Speter struct si_softc *sc = &si_softc[unit]; 48910015Speter struct si_port *pp; 49010015Speter volatile struct si_channel *ccbp; 49110015Speter volatile struct si_reg *regp; 49210015Speter volatile caddr_t maddr; 49310015Speter struct si_module *modp; 49410015Speter struct tty *tp; 49510015Speter struct speedtab *spt; 49610015Speter int nmodule, nport, x, y; 49712174Speter int uart_type; 49812888Speter#ifdef DEVFS 49912675Sjulian char name[32]; 50012888Speter#endif 50110015Speter 50212496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 50310015Speter 50410015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 50510015Speter sc->sc_maddr = id->id_maddr; 50610015Speter sc->sc_irq = id->id_irq; 50710015Speter 50810015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 50910015Speter 51010015Speter maddr = sc->sc_maddr; 51110015Speter 51210015Speter /* 51310015Speter * OK, now lets download the firmware and try and boot the CPU.. 51410015Speter */ 51510015Speter 51612496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 51712496Speter id->id_unit, si_dsize)); 51810015Speter bcopy(si_download, maddr, si_dsize); 51910015Speter 52010015Speter switch (sc->sc_type) { 52110015Speter case SIEISA: 52210015Speter#if NEISA > 0 52310015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 52410015Speter *(maddr+0x42) = 1; 52510015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 52610015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 52710015Speter break; 52810015Speter#endif /* fall-through if not EISA */ 52910015Speter case SI2: 53012174Speter /* 53112174Speter * must get around to converting the code for 53212174Speter * these one day, if FreeBSD ever supports it. 53312174Speter */ 53410015Speter return 0; 53510015Speter case SIHOST: 53610015Speter *(maddr+SIRESET_CL) = 0; 53710015Speter *(maddr+SIINTCL_CL) = 0; 53810015Speter break; 53910015Speter case SIHOST2: 54010015Speter *(maddr+SIPLRESET) = 0x10; 54110015Speter switch (sc->sc_irq) { 54210015Speter case IRQ11: 54310015Speter *(maddr+SIPLIRQ11) = 0x10; 54410015Speter break; 54510015Speter case IRQ12: 54610015Speter *(maddr+SIPLIRQ12) = 0x10; 54710015Speter break; 54810015Speter case IRQ15: 54910015Speter *(maddr+SIPLIRQ15) = 0x10; 55010015Speter break; 55110015Speter } 55210015Speter *(maddr+SIPLIRQCLR) = 0x10; 55310015Speter break; 55410015Speter } 55510015Speter 55610015Speter DELAY(1000000); /* wait around for a second */ 55710015Speter 55810015Speter regp = (struct si_reg *)maddr; 55910015Speter y = 0; 56010015Speter /* wait max of 5 sec for init OK */ 56110015Speter while (regp->initstat == 0 && y++ < 10) { 56210015Speter DELAY(500000); 56310015Speter } 56410015Speter switch (regp->initstat) { 56510015Speter case 0: 56610015Speter printf("si%d: startup timeout - aborting\n", unit); 56712174Speter sc->sc_type = SIEMPTY; 56810015Speter return 0; 56910015Speter case 1: 57012174Speter /* set throttle to 125 intr per second */ 57110015Speter regp->int_count = 25000; 57210015Speter /* rx intr max of 25 timer per second */ 57310015Speter regp->rx_int_count = 4; 57410015Speter regp->int_pending = 0; /* no intr pending */ 57510015Speter regp->int_scounter = 0; /* reset counter */ 57610015Speter break; 57710015Speter case 0xff: 57810015Speter /* 57910015Speter * No modules found, so give up on this one. 58010015Speter */ 58110015Speter printf("si%d: %s - no ports found\n", unit, 58210015Speter si_type[sc->sc_type]); 58310015Speter return 0; 58410015Speter default: 58510015Speter printf("si%d: Z280 version error - initstat %x\n", 58610015Speter unit, regp->initstat); 58710015Speter return 0; 58810015Speter } 58910015Speter 59010015Speter /* 59110015Speter * First time around the ports just count them in order 59210015Speter * to allocate some memory. 59310015Speter */ 59410015Speter nport = 0; 59510015Speter modp = (struct si_module *)(maddr + 0x80); 59610015Speter for (;;) { 59712174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 59810015Speter switch (modp->sm_type & (~MMASK)) { 59910015Speter case M232: 60010015Speter case M422: 60110015Speter DPRINT((0, DBG_DOWNLOAD, 60212174Speter "si%d: Found 232/422 module, %d ports\n", 60310015Speter unit, (int)(modp->sm_type & MMASK))); 60410015Speter 60510015Speter /* this is a firmware issue */ 60610015Speter if (si_Nports == SI_MAXPORTPERCARD) { 60710015Speter printf("si%d: extra ports ignored\n", unit); 60810015Speter continue; 60910015Speter } 61010015Speter 61110015Speter x = modp->sm_type & MMASK; 61210015Speter nport += x; 61310015Speter si_Nports += x; 61410015Speter si_Nmodules++; 61510015Speter break; 61610015Speter default: 61710015Speter printf("si%d: unknown module type %d\n", 61810015Speter unit, modp->sm_type); 61910015Speter break; 62010015Speter } 62110015Speter if (modp->sm_next == 0) 62210015Speter break; 62310015Speter modp = (struct si_module *) 62410015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 62510015Speter } 62610015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 62710015Speter M_DEVBUF, M_NOWAIT); 62810015Speter if (sc->sc_ports == 0) { 62910015Spetermem_fail: 63010015Speter printf("si%d: fail to malloc memory for port structs\n", 63110015Speter unit); 63210015Speter return 0; 63310015Speter } 63410015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 63510015Speter sc->sc_nport = nport; 63610015Speter 63710015Speter /* 63810015Speter * allocate tty structures for ports 63910015Speter */ 64010015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 64110015Speter if (tp == 0) 64210015Speter goto mem_fail; 64310015Speter bzero(tp, sizeof(*tp) * nport); 64410962Speter si_tty = tp; 64510015Speter 64610015Speter /* mark the device state as attached */ 64710015Speter si_kdc[unit].kdc_state = DC_BUSY; 64810015Speter 64910015Speter /* 65010015Speter * Scan round the ports again, this time initialising. 65110015Speter */ 65210015Speter pp = sc->sc_ports; 65310015Speter nmodule = 0; 65410015Speter modp = (struct si_module *)(maddr + 0x80); 65512174Speter uart_type = 0; 65610015Speter for (;;) { 65710015Speter switch (modp->sm_type & (~MMASK)) { 65810015Speter case M232: 65910015Speter case M422: 66010015Speter nmodule++; 66110015Speter nport = (modp->sm_type & MMASK); 66210015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 66312174Speter if (uart_type == 0) 66412174Speter uart_type = ccbp->type; 66510015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 66610015Speter pp->sp_ccb = ccbp; /* save the address */ 66710015Speter pp->sp_tty = tp++; 66810015Speter pp->sp_pend = IDLE_CLOSE; 66910015Speter pp->sp_state = 0; /* internal flag */ 67010015Speter pp->sp_dtr_wait = 3 * hz; 67110047Speter pp->sp_iin.c_iflag = si_default_iflag; 67210047Speter pp->sp_iin.c_oflag = si_default_oflag; 67310047Speter pp->sp_iin.c_cflag = si_default_cflag; 67410047Speter pp->sp_iin.c_lflag = si_default_lflag; 67510015Speter termioschars(&pp->sp_iin); 67610015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 67710047Speter si_default_rate; 67810015Speter pp->sp_iout = pp->sp_iin; 67910015Speter } 68010015Speter break; 68110015Speter default: 68210015Speter break; 68310015Speter } 68410015Speter if (modp->sm_next == 0) { 68512174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 68610015Speter unit, 68710015Speter sc->sc_typename, 68810015Speter sc->sc_nport, 68912174Speter nmodule, 69012174Speter uart_type); 69110015Speter break; 69210015Speter } 69310015Speter modp = (struct si_module *) 69410015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 69510015Speter } 69610015Speter if (done_chartimes == 0) { 69710015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 69810015Speter if ((spt->sp_code /= hz) == 0) 69910015Speter spt->sp_code = 1; 70010015Speter } 70110015Speter done_chartimes = 1; 70210015Speter } 70312502Sjulian 70412675Sjulian#ifdef DEVFS 70512675Sjulian/* path name devsw minor type uid gid perm*/ 70613169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 70713165Speter y = x + 1; /* For sync with the manuals that start at 1 */ 70813165Speter sprintf(name,"ttyA%c%c", chardev[y / 10], chardev[y % 10]); 70912675Sjulian sc->devfs_token[x].ttyd = devfs_add_devsw( 71012888Speter "/", name, &si_cdevsw, x, 71112675Sjulian DV_CHR, 0, 0, 0600); 71213165Speter sprintf(name,"cuaA%c%c", chardev[y / 10], chardev[y % 10]); 71312675Sjulian sc->devfs_token[x].cuaa = devfs_add_devsw( 71412888Speter "/", name, &si_cdevsw, x + 128, 71512675Sjulian DV_CHR, 0, 0, 0600); 71613165Speter sprintf(name,"ttyiA%c%c", chardev[y / 10], chardev[y % 10]); 71712826Speter sc->devfs_token[x].ttyi = devfs_add_devsw( 71812888Speter "/", name, &si_cdevsw, x + 0x10000, 71912675Sjulian DV_CHR, 0, 0, 0600); 72013165Speter sprintf(name,"ttylA%c%c", chardev[y / 10], chardev[y % 10]); 72112826Speter sc->devfs_token[x].ttyl = devfs_add_devsw( 72212888Speter "/", name, &si_cdevsw, x + 0x20000, 72312675Sjulian DV_CHR, 0, 0, 0600); 72412675Sjulian } 72513165Speter sc->control_token = devfs_add_devsw("/", "si_control", 72613165Speter &si_cdevsw, 0x40000, 72713165Speter DV_CHR, 0, 0, 0600); 72812675Sjulian#endif 72910015Speter return (1); 73010015Speter} 73110015Speter 73212675Sjulianstatic int 73310015Spetersiopen(dev, flag, mode, p) 73410015Speter dev_t dev; 73510015Speter int flag, mode; 73610015Speter struct proc *p; 73710015Speter{ 73810015Speter int oldspl, error; 73910015Speter int card, port; 74010015Speter register struct si_softc *sc; 74110015Speter register struct tty *tp; 74210015Speter volatile struct si_channel *ccbp; 74310015Speter struct si_port *pp; 74410015Speter int mynor = minor(dev); 74510015Speter 74610015Speter /* quickly let in /dev/si_control */ 74710015Speter if (IS_CONTROLDEV(mynor)) { 74810015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 74910015Speter return(error); 75010015Speter return(0); 75110015Speter } 75210015Speter 75310015Speter card = SI_CARD(mynor); 75410015Speter if (card >= NSI) 75510015Speter return (ENXIO); 75610015Speter sc = &si_softc[card]; 75710015Speter 75812174Speter if (sc->sc_type == SIEMPTY) { 75912174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 76010015Speter card, sc->sc_typename)); 76110015Speter return(ENXIO); 76210015Speter } 76310015Speter 76410015Speter port = SI_PORT(mynor); 76510015Speter if (port >= sc->sc_nport) { 76612174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 76710015Speter card, sc->sc_nport)); 76810015Speter return(ENXIO); 76910015Speter } 77010015Speter 77110015Speter#ifdef POLL 77210015Speter /* 77310015Speter * We've now got a device, so start the poller. 77410015Speter */ 77510015Speter if (init_finished == 0) { 77610015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 77710015Speter init_finished = 1; 77810015Speter } 77910015Speter#endif 78010015Speter 78110015Speter /* initial/lock device */ 78210015Speter if (IS_STATE(mynor)) { 78310015Speter return(0); 78410015Speter } 78510015Speter 78610015Speter pp = sc->sc_ports + port; 78710015Speter tp = pp->sp_tty; /* the "real" tty */ 78810015Speter ccbp = pp->sp_ccb; /* Find control block */ 78910015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 79010015Speter dev, flag, mode, p)); 79110015Speter 79210015Speter oldspl = spltty(); /* Keep others out */ 79310015Speter error = 0; 79410015Speter 79510015Speteropen_top: 79610015Speter while (pp->sp_state & SS_DTR_OFF) { 79710015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 79810015Speter if (error != 0) 79910015Speter goto out; 80010015Speter } 80110015Speter 80210015Speter if (tp->t_state & TS_ISOPEN) { 80310015Speter /* 80410015Speter * The device is open, so everything has been initialised. 80510015Speter * handle conflicts. 80610015Speter */ 80710015Speter if (IS_CALLOUT(mynor)) { 80810015Speter if (!pp->sp_active_out) { 80910015Speter error = EBUSY; 81010015Speter goto out; 81110015Speter } 81210015Speter } else { 81310015Speter if (pp->sp_active_out) { 81410015Speter if (flag & O_NONBLOCK) { 81510015Speter error = EBUSY; 81610015Speter goto out; 81710015Speter } 81810015Speter error = tsleep(&pp->sp_active_out, 81910015Speter TTIPRI|PCATCH, "sibi", 0); 82010015Speter if (error != 0) 82110015Speter goto out; 82210015Speter goto open_top; 82310015Speter } 82410015Speter } 82510015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 82610015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 82710015Speter "already open and EXCLUSIVE set\n")); 82810015Speter error = EBUSY; 82910015Speter goto out; 83010015Speter } 83110015Speter } else { 83210015Speter /* 83310015Speter * The device isn't open, so there are no conflicts. 83410015Speter * Initialize it. Avoid sleep... :-) 83510015Speter */ 83610015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 83710015Speter tp->t_oproc = si_start; 83810015Speter tp->t_param = siparam; 83910015Speter tp->t_dev = dev; 84010015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 84110015Speter ? pp->sp_iout : pp->sp_iin; 84210015Speter 84310015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 84410015Speter 84510015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 84610015Speter 84710015Speter error = siparam(tp, &tp->t_termios); 84810015Speter 84910015Speter --pp->sp_wopeners; 85010015Speter if (error != 0) 85110015Speter goto out; 85210015Speter /* XXX: we should goto_top if siparam slept */ 85310015Speter 85410015Speter ttsetwater(tp); 85510015Speter 85610015Speter /* set initial DCD state */ 85710015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 85810015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 85910015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 86010015Speter } 86110015Speter } 86210015Speter 86310015Speter /* whoops! we beat the close! */ 86410015Speter if (pp->sp_state & SS_CLOSING) { 86510015Speter /* try and stop it from proceeding to bash the hardware */ 86610015Speter pp->sp_state &= ~SS_CLOSING; 86710015Speter } 86810015Speter 86910015Speter /* 87010015Speter * Wait for DCD if necessary 87110015Speter */ 87210015Speter if (!(tp->t_state & TS_CARR_ON) 87310015Speter && !IS_CALLOUT(mynor) 87410015Speter && !(tp->t_cflag & CLOCAL) 87510015Speter && !(flag & O_NONBLOCK)) { 87610015Speter ++pp->sp_wopeners; 87710015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 87810015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 87910015Speter --pp->sp_wopeners; 88010015Speter if (error != 0) 88110015Speter goto out; 88210015Speter goto open_top; 88310015Speter } 88410015Speter 88510015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 88610015Speter si_disc_optim(tp, &tp->t_termios, pp); 88710015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 88810015Speter pp->sp_active_out = TRUE; 88910015Speter 89010015Speter pp->sp_state |= SS_OPEN; /* made it! */ 89110015Speter 89210015Speterout: 89310015Speter splx(oldspl); 89410015Speter 89510015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 89610015Speter 89710015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 89810015Speter sihardclose(pp); 89910015Speter 90010015Speter return(error); 90110015Speter} 90210015Speter 90312675Sjulianstatic int 90410015Spetersiclose(dev, flag, mode, p) 90510015Speter dev_t dev; 90610015Speter int flag, mode; 90710015Speter struct proc *p; 90810015Speter{ 90910015Speter register struct si_port *pp; 91010015Speter register struct tty *tp; 91110015Speter int oldspl; 91210015Speter int error = 0; 91310015Speter int mynor = minor(dev); 91410015Speter 91510015Speter if (IS_SPECIAL(mynor)) 91610015Speter return(0); 91710015Speter 91810015Speter oldspl = spltty(); 91910015Speter 92010015Speter pp = MINOR2PP(mynor); 92110015Speter tp = pp->sp_tty; 92210015Speter 92310015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 92410015Speter dev, flag, mode, p, pp->sp_state)); 92510015Speter 92610015Speter /* did we sleep and loose a race? */ 92710015Speter if (pp->sp_state & SS_CLOSING) { 92810015Speter /* error = ESOMETING? */ 92910015Speter goto out; 93010015Speter } 93110015Speter 93210015Speter /* begin race detection.. */ 93310015Speter pp->sp_state |= SS_CLOSING; 93410015Speter 93510015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 93610015Speter 93710015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 93810015Speter (*linesw[tp->t_line].l_close)(tp, flag); 93910015Speter 94010015Speter si_write_enable(pp, 1); 94110015Speter 94210015Speter /* did we sleep and somebody started another open? */ 94310015Speter if (!(pp->sp_state & SS_CLOSING)) { 94410015Speter /* error = ESOMETING? */ 94510015Speter goto out; 94610015Speter } 94710015Speter /* ok. we are now still on the right track.. nuke the hardware */ 94810015Speter 94910015Speter if (pp->sp_state & SS_LSTART) { 95010015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 95110015Speter pp->sp_state &= ~SS_LSTART; 95210015Speter } 95310015Speter 95410015Speter sistop(tp, FREAD | FWRITE); 95510015Speter 95610015Speter sihardclose(pp); 95710015Speter ttyclose(tp); 95810015Speter pp->sp_state &= ~SS_OPEN; 95910015Speter 96010015Speterout: 96110015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 96210015Speter splx(oldspl); 96310015Speter return(error); 96410015Speter} 96510015Speter 96610015Speterstatic void 96710015Spetersihardclose(pp) 96810015Speter struct si_port *pp; 96910015Speter{ 97010015Speter int oldspl; 97110015Speter struct tty *tp; 97210015Speter volatile struct si_channel *ccbp; 97310015Speter 97410015Speter oldspl = spltty(); 97510015Speter 97610015Speter tp = pp->sp_tty; 97710015Speter ccbp = pp->sp_ccb; /* Find control block */ 97810015Speter if (tp->t_cflag & HUPCL 97910015Speter || !pp->sp_active_out 98010015Speter && !(ccbp->hi_ip & IP_DCD) 98110015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 98210015Speter || !(tp->t_state & TS_ISOPEN)) { 98310015Speter 98410015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 98510015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 98610015Speter 98710015Speter if (pp->sp_dtr_wait != 0) { 98810015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 98910015Speter pp->sp_state |= SS_DTR_OFF; 99010015Speter } 99110015Speter 99210015Speter } 99310015Speter pp->sp_active_out = FALSE; 99410015Speter wakeup((caddr_t)&pp->sp_active_out); 99510015Speter wakeup(TSA_CARR_ON(tp)); 99610015Speter 99710015Speter splx(oldspl); 99810015Speter} 99910015Speter 100010015Speter 100110015Speter/* 100210015Speter * called at splsoftclock()... 100310015Speter */ 100410015Speterstatic void 100510015Spetersidtrwakeup(chan) 100610015Speter void *chan; 100710015Speter{ 100810015Speter struct si_port *pp; 100910015Speter int oldspl; 101010015Speter 101110015Speter oldspl = spltty(); 101210015Speter 101310015Speter pp = (struct si_port *)chan; 101410015Speter pp->sp_state &= ~SS_DTR_OFF; 101510015Speter wakeup(&pp->sp_dtr_wait); 101610015Speter 101710015Speter splx(oldspl); 101810015Speter} 101910015Speter 102010015Speter/* 102110015Speter * User level stuff - read and write 102210015Speter */ 102312675Sjulianstatic int 102410015Spetersiread(dev, uio, flag) 102510015Speter register dev_t dev; 102610015Speter struct uio *uio; 102710015Speter int flag; 102810015Speter{ 102910015Speter register struct tty *tp; 103010015Speter int mynor = minor(dev); 103110015Speter 103210015Speter if (IS_SPECIAL(mynor)) { 103310015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 103410015Speter return(ENODEV); 103510015Speter } 103610015Speter tp = MINOR2TP(mynor); 103710015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 103810015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 103910015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 104010015Speter} 104110015Speter 104210015Speter 104312675Sjulianstatic int 104410015Spetersiwrite(dev, uio, flag) 104510015Speter dev_t dev; 104610015Speter struct uio *uio; 104710015Speter int flag; 104810015Speter{ 104910015Speter register struct si_port *pp; 105010015Speter register struct tty *tp; 105110015Speter int error = 0; 105210015Speter int mynor = minor(dev); 105310015Speter int oldspl; 105410015Speter 105510015Speter if (IS_SPECIAL(mynor)) { 105610015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 105710015Speter return(ENODEV); 105810015Speter } 105910015Speter pp = MINOR2PP(mynor); 106010015Speter tp = pp->sp_tty; 106110015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 106210015Speter 106310015Speter oldspl = spltty(); 106410015Speter /* 106510015Speter * If writes are currently blocked, wait on the "real" tty 106610015Speter */ 106710015Speter while (pp->sp_state & SS_BLOCKWRITE) { 106810015Speter pp->sp_state |= SS_WAITWRITE; 106910015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 107010015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 107110015Speter "siwrite", 0)) 107210015Speter goto out; 107310015Speter } 107410015Speter 107510015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 107610015Speterout: 107710015Speter splx(oldspl); 107810015Speter return (error); 107910015Speter} 108010015Speter 108110015Speter 108212675Sjulianstatic struct tty * 108310015Spetersidevtotty(dev_t dev) 108410015Speter{ 108510015Speter struct si_port *pp; 108610015Speter int mynor = minor(dev); 108710015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 108810015Speter 108910015Speter if (IS_SPECIAL(mynor)) 109010015Speter return(NULL); 109110015Speter if (SI_PORT(mynor) >= sc->sc_nport) 109210015Speter return(NULL); 109310015Speter pp = MINOR2PP(mynor); 109410015Speter return (pp->sp_tty); 109510015Speter} 109610015Speter 109712675Sjulianstatic int 109810015Spetersiioctl(dev, cmd, data, flag, p) 109910015Speter dev_t dev; 110010015Speter int cmd; 110110015Speter caddr_t data; 110210015Speter int flag; 110310015Speter struct proc *p; 110410015Speter{ 110510015Speter struct si_port *pp; 110610015Speter register struct tty *tp; 110710015Speter int error; 110810015Speter int mynor = minor(dev); 110910015Speter int oldspl; 111010015Speter int blocked = 0; 111110015Speter#if defined(COMPAT_43) 111210015Speter int oldcmd; 111310015Speter struct termios term; 111410015Speter#endif 111510015Speter 111610015Speter if (IS_SI_IOCTL(cmd)) 111710015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 111810015Speter 111910015Speter pp = MINOR2PP(mynor); 112010015Speter tp = pp->sp_tty; 112110015Speter 112210015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 112310015Speter dev, cmd, data, flag)); 112410015Speter if (IS_STATE(mynor)) { 112510015Speter struct termios *ct; 112610015Speter 112710015Speter switch (mynor & SI_STATE_MASK) { 112810015Speter case SI_INIT_STATE_MASK: 112910015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 113010015Speter break; 113110015Speter case SI_LOCK_STATE_MASK: 113210015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 113310015Speter break; 113410015Speter default: 113510015Speter return (ENODEV); 113610015Speter } 113710015Speter switch (cmd) { 113810015Speter case TIOCSETA: 113910015Speter error = suser(p->p_ucred, &p->p_acflag); 114010015Speter if (error != 0) 114110015Speter return (error); 114210015Speter *ct = *(struct termios *)data; 114310015Speter return (0); 114410015Speter case TIOCGETA: 114510015Speter *(struct termios *)data = *ct; 114610015Speter return (0); 114710015Speter case TIOCGETD: 114810015Speter *(int *)data = TTYDISC; 114910015Speter return (0); 115010015Speter case TIOCGWINSZ: 115110015Speter bzero(data, sizeof(struct winsize)); 115210015Speter return (0); 115310015Speter default: 115410015Speter return (ENOTTY); 115510015Speter } 115610015Speter } 115710015Speter /* 115810015Speter * Do the old-style ioctl compat routines... 115910015Speter */ 116010015Speter#if defined(COMPAT_43) 116110015Speter term = tp->t_termios; 116210015Speter oldcmd = cmd; 116310015Speter error = ttsetcompat(tp, &cmd, data, &term); 116410015Speter if (error != 0) 116510015Speter return (error); 116610015Speter if (cmd != oldcmd) 116710015Speter data = (caddr_t)&term; 116810015Speter#endif 116910015Speter /* 117010015Speter * Do the initial / lock state business 117110015Speter */ 117210015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 117310015Speter int cc; 117410015Speter struct termios *dt = (struct termios *)data; 117510015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 117610015Speter ? &pp->sp_lout : &pp->sp_lin; 117710015Speter 117810015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 117910015Speter | (dt->c_iflag & ~lt->c_iflag); 118010015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 118110015Speter | (dt->c_oflag & ~lt->c_oflag); 118210015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 118310015Speter | (dt->c_cflag & ~lt->c_cflag); 118410015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 118510015Speter | (dt->c_lflag & ~lt->c_lflag); 118610015Speter for (cc = 0; cc < NCCS; ++cc) 118710015Speter if (lt->c_cc[cc] != 0) 118810015Speter dt->c_cc[cc] = tp->t_cc[cc]; 118910015Speter if (lt->c_ispeed != 0) 119010015Speter dt->c_ispeed = tp->t_ispeed; 119110015Speter if (lt->c_ospeed != 0) 119210015Speter dt->c_ospeed = tp->t_ospeed; 119310015Speter } 119410015Speter 119510015Speter /* 119610015Speter * Block user-level writes to give the ttywait() 119710015Speter * a chance to completely drain for commands 119810015Speter * that require the port to be in a quiescent state. 119910015Speter */ 120010015Speter switch (cmd) { 120110015Speter case TIOCSETAW: case TIOCSETAF: 120210015Speter case TIOCDRAIN: case TIOCSETP: 120310015Speter blocked++; /* block writes for ttywait() and siparam() */ 120410015Speter si_write_enable(pp, 0); 120510015Speter } 120610015Speter 120710015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 120810015Speter if (error >= 0) 120910015Speter goto out; 121010015Speter 121110015Speter oldspl = spltty(); 121210015Speter 121310015Speter error = ttioctl(tp, cmd, data, flag); 121410015Speter si_disc_optim(tp, &tp->t_termios, pp); 121510015Speter if (error >= 0) 121610015Speter goto outspl; 121710015Speter 121810015Speter switch (cmd) { 121910015Speter case TIOCSBRK: 122010015Speter si_command(pp, SBREAK, SI_NOWAIT); 122110015Speter break; 122210015Speter case TIOCCBRK: 122310015Speter si_command(pp, EBREAK, SI_NOWAIT); 122410015Speter break; 122510015Speter case TIOCSDTR: 122610015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 122710015Speter break; 122810015Speter case TIOCCDTR: 122910015Speter (void) si_modem(pp, SET, 0); 123010015Speter break; 123110015Speter case TIOCMSET: 123210015Speter (void) si_modem(pp, SET, *(int *)data); 123310015Speter break; 123410015Speter case TIOCMBIS: 123510015Speter (void) si_modem(pp, BIS, *(int *)data); 123610015Speter break; 123710015Speter case TIOCMBIC: 123810015Speter (void) si_modem(pp, BIC, *(int *)data); 123910015Speter break; 124010015Speter case TIOCMGET: 124110015Speter *(int *)data = si_modem(pp, GET, 0); 124210015Speter break; 124310015Speter case TIOCMSDTRWAIT: 124410015Speter /* must be root since the wait applies to following logins */ 124510015Speter error = suser(p->p_ucred, &p->p_acflag); 124610015Speter if (error != 0) { 124710015Speter goto outspl; 124810015Speter } 124910015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 125010015Speter break; 125110015Speter case TIOCMGDTRWAIT: 125210015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 125310015Speter break; 125410015Speter 125510015Speter default: 125610015Speter error = ENOTTY; 125710015Speter } 125810015Speter error = 0; 125910015Speteroutspl: 126010015Speter splx(oldspl); 126110015Speterout: 126210015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 126310015Speter if (blocked) 126410015Speter si_write_enable(pp, 1); 126510015Speter return(error); 126610015Speter} 126710015Speter 126810015Speter/* 126910015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 127010015Speter */ 127110015Speterstatic int 127210015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 127310015Speter{ 127410015Speter struct si_softc *xsc; 127510015Speter register struct si_port *xpp; 127610015Speter volatile struct si_reg *regp; 127710015Speter struct si_tcsi *dp; 127810044Speter struct si_pstat *sps; 127911872Sphk int *ip, error = 0; 128010015Speter int oldspl; 128110015Speter int card, port; 128210015Speter int mynor = minor(dev); 128310015Speter 128410015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 128510015Speter dev, cmd, data, flag)); 128610015Speter 128710044Speter#if 1 128810044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 128910044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 129010044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 129110044Speter#endif 129210044Speter 129310015Speter if (!IS_CONTROLDEV(mynor)) { 129410015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 129510015Speter return(ENODEV); 129610015Speter } 129710015Speter 129810015Speter oldspl = spltty(); /* better safe than sorry */ 129910015Speter 130010015Speter ip = (int *)data; 130110015Speter 130210015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 130310015Speter 130410015Speter switch (cmd) { 130510015Speter case TCSIPORTS: 130610015Speter *ip = si_Nports; 130710015Speter goto out; 130810015Speter case TCSIMODULES: 130910015Speter *ip = si_Nmodules; 131010015Speter goto out; 131110015Speter case TCSISDBG_ALL: 131210015Speter SUCHECK; 131310015Speter si_debug = *ip; 131410015Speter goto out; 131510015Speter case TCSIGDBG_ALL: 131610015Speter *ip = si_debug; 131710015Speter goto out; 131810015Speter default: 131910015Speter /* 132010015Speter * Check that a controller for this port exists 132110015Speter */ 132210044Speter 132310044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 132410044Speter 132510015Speter dp = (struct si_tcsi *)data; 132610044Speter sps = (struct si_pstat *)data; 132710015Speter card = dp->tc_card; 132810015Speter xsc = &si_softc[card]; /* check.. */ 132912174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 133010015Speter error = ENOENT; 133110015Speter goto out; 133210015Speter } 133310015Speter /* 133410015Speter * And check that a port exists 133510015Speter */ 133610015Speter port = dp->tc_port; 133710015Speter if (port < 0 || port >= xsc->sc_nport) { 133810015Speter error = ENOENT; 133910015Speter goto out; 134010015Speter } 134110015Speter xpp = xsc->sc_ports + port; 134210015Speter regp = (struct si_reg *)xsc->sc_maddr; 134310015Speter } 134410015Speter 134510015Speter switch (cmd) { 134610015Speter case TCSIDEBUG: 134710015Speter#ifdef SI_DEBUG 134810015Speter SUCHECK; 134910015Speter if (xpp->sp_debug) 135010015Speter xpp->sp_debug = 0; 135110015Speter else { 135210015Speter xpp->sp_debug = DBG_ALL; 135310015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 135410015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 135510015Speter } 135610015Speter break; 135710015Speter#else 135810015Speter error = ENODEV; 135910015Speter goto out; 136010015Speter#endif 136110015Speter case TCSISDBG_LEVEL: 136210015Speter case TCSIGDBG_LEVEL: 136310015Speter#ifdef SI_DEBUG 136410015Speter if (cmd == TCSIGDBG_LEVEL) { 136510015Speter dp->tc_dbglvl = xpp->sp_debug; 136610015Speter } else { 136710015Speter SUCHECK; 136810015Speter xpp->sp_debug = dp->tc_dbglvl; 136910015Speter } 137010015Speter break; 137110015Speter#else 137210015Speter error = ENODEV; 137310015Speter goto out; 137410015Speter#endif 137510015Speter case TCSIGRXIT: 137610015Speter dp->tc_int = regp->rx_int_count; 137710015Speter break; 137810015Speter case TCSIRXIT: 137910015Speter SUCHECK; 138010015Speter regp->rx_int_count = dp->tc_int; 138110015Speter break; 138210015Speter case TCSIGIT: 138310015Speter dp->tc_int = regp->int_count; 138410015Speter break; 138510015Speter case TCSIIT: 138610015Speter SUCHECK; 138710015Speter regp->int_count = dp->tc_int; 138810015Speter break; 138910044Speter case TCSISTATE: 139010044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 139110015Speter break; 139210044Speter /* these next three use a different structure */ 139310044Speter case TCSI_PORT: 139410015Speter SUCHECK; 139510044Speter sps->tc_siport = *xpp; 139610015Speter break; 139710044Speter case TCSI_CCB: 139810044Speter SUCHECK; 139910044Speter sps->tc_ccb = *xpp->sp_ccb; 140010015Speter break; 140110044Speter case TCSI_TTY: 140210044Speter SUCHECK; 140310044Speter sps->tc_tty = *xpp->sp_tty; 140410015Speter break; 140510015Speter default: 140610015Speter error = EINVAL; 140710015Speter goto out; 140810015Speter } 140910015Speterout: 141010015Speter splx(oldspl); 141110015Speter return(error); /* success */ 141210015Speter} 141310015Speter 141410015Speter/* 141510015Speter * siparam() : Configure line params 141610015Speter * called at spltty(); 141710015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 141810015Speter * caller must arrange this if it's important.. 141910015Speter */ 142012724Sphkstatic int 142110015Spetersiparam(tp, t) 142210015Speter register struct tty *tp; 142310015Speter register struct termios *t; 142410015Speter{ 142510015Speter register struct si_port *pp = TP2PP(tp); 142610015Speter volatile struct si_channel *ccbp; 142710015Speter int oldspl, cflag, iflag, oflag, lflag; 142810015Speter int error = 0; /* shutup gcc */ 142910015Speter int ispeed = 0; /* shutup gcc */ 143010015Speter int ospeed = 0; /* shutup gcc */ 143110161Speter BYTE val; 143210015Speter 143310015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 143410015Speter cflag = t->c_cflag; 143510015Speter iflag = t->c_iflag; 143610015Speter oflag = t->c_oflag; 143710015Speter lflag = t->c_lflag; 143810044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 143910044Speter oflag, cflag, iflag, lflag)); 144010015Speter 144110015Speter 144210015Speter /* if not hung up.. */ 144310015Speter if (t->c_ospeed != 0) { 144410015Speter /* translate baud rate to firmware values */ 144510015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 144610015Speter ispeed = t->c_ispeed ? 144710015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 144810015Speter 144910015Speter /* enforce legit baud rate */ 145010015Speter if (ospeed < 0 || ispeed < 0) 145110015Speter return (EINVAL); 145210015Speter } 145310015Speter 145410015Speter 145510015Speter oldspl = spltty(); 145610015Speter 145710015Speter ccbp = pp->sp_ccb; 145810015Speter 145910161Speter /* ========== set hi_break ========== */ 146010161Speter val = 0; 146110161Speter if (iflag & IGNBRK) /* Breaks */ 146210161Speter val |= BR_IGN; 146310161Speter if (iflag & BRKINT) /* Interrupt on break? */ 146410161Speter val |= BR_INT; 146510161Speter if (iflag & PARMRK) /* Parity mark? */ 146610161Speter val |= BR_PARMRK; 146710161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 146810161Speter val |= BR_PARIGN; 146910161Speter ccbp->hi_break = val; 147010161Speter 147110161Speter /* ========== set hi_csr ========== */ 147210015Speter /* if not hung up.. */ 147310015Speter if (t->c_ospeed != 0) { 147410015Speter /* Set I/O speeds */ 147510161Speter val = (ispeed << 4) | ospeed; 147610015Speter } 147710161Speter ccbp->hi_csr = val; 147810015Speter 147910161Speter /* ========== set hi_mr2 ========== */ 148010161Speter val = 0; 148110015Speter if (cflag & CSTOPB) /* Stop bits */ 148210161Speter val |= MR2_2_STOP; 148310015Speter else 148410161Speter val |= MR2_1_STOP; 148510161Speter /* 148610161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 148710161Speter * a DCE, hence the reverse sense of RTS and CTS 148810161Speter */ 148910161Speter /* Output Flow - RTS must be raised before data can be sent */ 149010161Speter if (cflag & CCTS_OFLOW) 149110161Speter val |= MR2_RTSCONT; 149210161Speter 149310161Speter ccbp->hi_mr1 = val; 149410161Speter 149510161Speter /* ========== set hi_mr1 ========== */ 149610161Speter val = 0; 149710015Speter if (!(cflag & PARENB)) /* Parity */ 149810161Speter val |= MR1_NONE; 149910015Speter else 150010161Speter val |= MR1_WITH; 150110015Speter if (cflag & PARODD) 150210161Speter val |= MR1_ODD; 150310015Speter 150410015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 150510161Speter val |= MR1_8_BITS; 150610015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 150710161Speter val |= MR1_7_BITS; 150810015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 150910161Speter val |= MR1_6_BITS; 151010015Speter } else { /* Must be 5 */ 151110161Speter val |= MR1_5_BITS; 151210015Speter } 151310161Speter /* 151410161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 151510161Speter * a DCE, hence the reverse sense of RTS and CTS 151610161Speter */ 151710161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 151810161Speter if (cflag & CRTS_IFLOW) 151910161Speter val |= MR1_CTSCONT; 152010015Speter 152110161Speter ccbp->hi_mr1 = val; 152210161Speter 152310161Speter /* ========== set hi_mask ========== */ 152410161Speter val = 0xff; 152510161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 152610161Speter val &= 0xFF; 152710161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 152810161Speter val &= 0x7F; 152910161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 153010161Speter val &= 0x3F; 153110161Speter } else { /* Must be 5 */ 153210161Speter val &= 0x1F; 153310161Speter } 153410015Speter if (iflag & ISTRIP) 153510161Speter val &= 0x7F; 153610015Speter 153710161Speter ccbp->hi_mask = val; 153810161Speter 153910161Speter /* ========== set hi_prtcl ========== */ 154010161Speter val = 0; 154110015Speter /* Monitor DCD etc. if a modem */ 154210015Speter if (!(cflag & CLOCAL)) 154310161Speter val |= SP_DCEN; 154410161Speter if (iflag & IXANY) 154510161Speter val |= SP_TANY; 154610161Speter if (iflag & IXON) 154710161Speter val |= SP_TXEN; 154810161Speter if (iflag & IXOFF) 154910161Speter val |= SP_RXEN; 155010161Speter if (iflag & INPCK) 155110161Speter val |= SP_PAEN; 155210015Speter 155310161Speter ccbp->hi_prtcl = val; 155410161Speter 155510161Speter 155610161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 155710161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 155810015Speter ccbp->hi_txon = t->c_cc[VSTART]; 155910015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 156010015Speter 156110015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 156210015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 156310015Speter 156410161Speter /* ========== send settings to the card ========== */ 156510015Speter /* potential sleep here */ 156610015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 156710015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 156810015Speter else 156910015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 157010015Speter 157110161Speter /* ========== set DTR etc ========== */ 157210015Speter /* Hangup if ospeed == 0 */ 157310015Speter if (t->c_ospeed == 0) { 157410015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 157510015Speter } else { 157610015Speter /* 157710015Speter * If the previous speed was 0, may need to re-enable 157810015Speter * the modem signals 157910015Speter */ 158010015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 158110015Speter } 158210015Speter 158310044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 158410044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 158510015Speter 158610015Speter splx(oldspl); 158710015Speter return(error); 158810015Speter} 158910015Speter 159010015Speter/* 159110015Speter * Enable or Disable the writes to this channel... 159210015Speter * "state" -> enabled = 1; disabled = 0; 159310015Speter */ 159410015Speterstatic void 159510015Spetersi_write_enable(pp, state) 159610015Speter register struct si_port *pp; 159710015Speter int state; 159810015Speter{ 159910015Speter int oldspl; 160010015Speter 160110015Speter oldspl = spltty(); 160210015Speter 160310015Speter if (state) { 160410015Speter pp->sp_state &= ~SS_BLOCKWRITE; 160510015Speter if (pp->sp_state & SS_WAITWRITE) { 160610015Speter pp->sp_state &= ~SS_WAITWRITE; 160710015Speter /* thunder away! */ 160810015Speter wakeup((caddr_t)pp); 160910015Speter } 161010015Speter } else { 161110015Speter pp->sp_state |= SS_BLOCKWRITE; 161210015Speter } 161310015Speter 161410015Speter splx(oldspl); 161510015Speter} 161610015Speter 161710015Speter/* 161810015Speter * Set/Get state of modem control lines. 161910015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 162010015Speter * TIOCM_DTR DSR 162110015Speter * TIOCM_RTS CTS 162210015Speter */ 162310015Speterstatic int 162410015Spetersi_modem(pp, cmd, bits) 162510015Speter struct si_port *pp; 162610015Speter enum si_mctl cmd; 162710015Speter int bits; 162810015Speter{ 162910015Speter volatile struct si_channel *ccbp; 163010015Speter int x; 163110015Speter 163210015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 163310015Speter ccbp = pp->sp_ccb; /* Find channel address */ 163410015Speter switch (cmd) { 163510015Speter case GET: 163610015Speter x = ccbp->hi_ip; 163710015Speter bits = TIOCM_LE; 163810015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 163910015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 164010015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 164110015Speter if (x & IP_RI) bits |= TIOCM_RI; 164210015Speter return(bits); 164310015Speter case SET: 164410015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 164510015Speter /* fall through */ 164610015Speter case BIS: 164710015Speter x = 0; 164810015Speter if (bits & TIOCM_DTR) 164910015Speter x |= OP_DSR; 165010015Speter if (bits & TIOCM_RTS) 165110015Speter x |= OP_CTS; 165210015Speter ccbp->hi_op |= x; 165310015Speter break; 165410015Speter case BIC: 165510015Speter if (bits & TIOCM_DTR) 165610015Speter ccbp->hi_op &= ~OP_DSR; 165710015Speter if (bits & TIOCM_RTS) 165810015Speter ccbp->hi_op &= ~OP_CTS; 165910015Speter } 166010015Speter return 0; 166110015Speter} 166210015Speter 166310015Speter/* 166410015Speter * Handle change of modem state 166510015Speter */ 166610015Speterstatic void 166710015Spetersi_modem_state(pp, tp, hi_ip) 166810015Speter register struct si_port *pp; 166910015Speter register struct tty *tp; 167010015Speter register int hi_ip; 167110015Speter{ 167210015Speter /* if a modem dev */ 167310015Speter if (hi_ip & IP_DCD) { 167410015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 167510015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 167610015Speter tp->t_line)); 167710015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 167810015Speter } 167910015Speter } else { 168010015Speter if (pp->sp_last_hi_ip & IP_DCD) { 168110015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 168210015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 168310015Speter (void) si_modem(pp, SET, 0); 168410015Speter } 168510015Speter } 168610015Speter pp->sp_last_hi_ip = hi_ip; 168710015Speter 168810015Speter} 168910015Speter 169010015Speter/* 169110015Speter * Poller to catch missed interrupts. 169212174Speter * 169312496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 169412496Speter * better response. We could really use a "periodic" version timeout(). :-) 169510015Speter */ 169610015Speter#ifdef POLL 169710708Speterstatic void 169810015Spetersi_poll(void *nothing) 169910015Speter{ 170010015Speter register struct si_softc *sc; 170110015Speter register int i; 170210015Speter volatile struct si_reg *regp; 170312174Speter register struct si_port *pp; 170412174Speter int lost, oldspl, port; 170510015Speter 170610015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 170711609Speter oldspl = spltty(); 170810015Speter if (in_intr) 170910015Speter goto out; 171010015Speter lost = 0; 171110015Speter for (i=0; i<NSI; i++) { 171210015Speter sc = &si_softc[i]; 171312174Speter if (sc->sc_type == SIEMPTY) 171410015Speter continue; 171510015Speter regp = (struct si_reg *)sc->sc_maddr; 171610015Speter /* 171710015Speter * See if there has been a pending interrupt for 2 seconds 171810015Speter * or so. The test <int_scounter >= 200) won't correspond 171910015Speter * to 2 seconds if int_count gets changed. 172010015Speter */ 172110015Speter if (regp->int_pending != 0) { 172210015Speter if (regp->int_scounter >= 200 && 172310015Speter regp->initstat == 1) { 172412174Speter printf("si%d: lost intr\n", i); 172510015Speter lost++; 172610015Speter } 172710015Speter } else { 172810015Speter regp->int_scounter = 0; 172910015Speter } 173010015Speter 173112174Speter /* 173212174Speter * gripe about no input flow control.. 173312174Speter */ 173412174Speter pp = sc->sc_ports; 173512174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 173612174Speter if (pp->sp_delta_overflows > 0) { 173712174Speter printf("si%d: %d tty level buffer overflows\n", 173812174Speter i, pp->sp_delta_overflows); 173912174Speter pp->sp_delta_overflows = 0; 174012174Speter } 174112174Speter } 174210015Speter } 174310015Speter if (lost) 174410015Speter siintr(-1); /* call intr with fake vector */ 174511609Speterout: 174610015Speter splx(oldspl); 174710015Speter 174810015Speter timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 174910015Speter} 175010015Speter#endif /* ifdef POLL */ 175110015Speter 175210015Speter/* 175310015Speter * The interrupt handler polls ALL ports on ALL adapters each time 175410015Speter * it is called. 175510015Speter */ 175610015Speter 175712496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 175810015Speter 175910708Spetervoid 176011609Spetersiintr(int unit) 176110015Speter{ 176210015Speter register struct si_softc *sc; 176310015Speter 176410015Speter register struct si_port *pp; 176510015Speter volatile struct si_channel *ccbp; 176610015Speter register struct tty *tp; 176710015Speter volatile caddr_t maddr; 176811872Sphk BYTE op, ip; 176912174Speter int x, card, port, n, i, isopen; 177010015Speter volatile BYTE *z; 177110015Speter BYTE c; 177210015Speter 177311609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 177411609Speter if (in_intr) { 177511609Speter if (unit < 0) /* should never happen */ 177610708Speter return; 177712174Speter printf("si%d: Warning interrupt handler re-entered\n", 177811609Speter unit); 177910708Speter return; 178010015Speter } 178110015Speter in_intr = 1; 178210015Speter 178310015Speter /* 178410015Speter * When we get an int we poll all the channels and do ALL pending 178510015Speter * work, not just the first one we find. This allows all cards to 178610015Speter * share the same vector. 178710015Speter */ 178810015Speter for (card=0; card < NSI; card++) { 178910015Speter sc = &si_softc[card]; 179012174Speter if (sc->sc_type == SIEMPTY) 179110015Speter continue; 179212174Speter 179312174Speter /* 179412174Speter * First, clear the interrupt 179512174Speter */ 179610015Speter switch(sc->sc_type) { 179710015Speter case SIHOST : 179810015Speter maddr = sc->sc_maddr; 179910015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180010015Speter /* flag nothing pending */ 180110015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 180210015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 180310015Speter break; 180410015Speter case SIHOST2: 180510015Speter maddr = sc->sc_maddr; 180610015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180710015Speter *(maddr+SIPLIRQCLR) = 0x00; 180810015Speter *(maddr+SIPLIRQCLR) = 0x10; 180910015Speter break; 181010015Speter case SIEISA: 181110015Speter#if NEISA > 0 181210015Speter maddr = sc->sc_maddr; 181310015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 181410015Speter (void)inb(sc->sc_eisa_iobase+3); 181510015Speter break; 181610015Speter#endif /* fall through if not EISA kernel */ 181710015Speter case SIEMPTY: 181810015Speter default: 181910015Speter continue; 182010015Speter } 182110015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 182210015Speter 182312174Speter /* 182412174Speter * check each port 182512174Speter */ 182612174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 182710015Speter ccbp = pp->sp_ccb; 182810015Speter tp = pp->sp_tty; 182910015Speter 183012174Speter 183110015Speter /* 183210015Speter * See if a command has completed ? 183310015Speter */ 183410015Speter if (ccbp->hi_stat != pp->sp_pend) { 183510015Speter DPRINT((pp, DBG_INTR, 183610015Speter "siintr hi_stat = 0x%x, pend = %d\n", 183710015Speter ccbp->hi_stat, pp->sp_pend)); 183810015Speter switch(pp->sp_pend) { 183910015Speter case LOPEN: 184010015Speter case MPEND: 184110015Speter case MOPEN: 184210015Speter case CONFIG: 184310015Speter pp->sp_pend = ccbp->hi_stat; 184410015Speter /* sleeping in si_command */ 184510015Speter wakeup(&pp->sp_state); 184610015Speter break; 184710015Speter default: 184810015Speter pp->sp_pend = ccbp->hi_stat; 184910015Speter } 185010015Speter } 185110015Speter 185210015Speter /* 185310015Speter * Continue on if it's closed 185410015Speter */ 185510015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 185610015Speter continue; 185710015Speter } 185810015Speter 185910015Speter /* 186010015Speter * Do modem state change if not a local device 186110015Speter */ 186210015Speter si_modem_state(pp, tp, ccbp->hi_ip); 186310015Speter 186410015Speter /* 186512174Speter * Check to see if there's we should 'receive' 186612174Speter * characters. 186712174Speter */ 186812174Speter if (tp->t_state & TS_CONNECTED && 186912174Speter tp->t_state & TS_ISOPEN) 187012174Speter isopen = 1; 187112174Speter else 187212174Speter isopen = 0; 187312174Speter 187412174Speter /* 187510015Speter * Do break processing 187610015Speter */ 187710015Speter if (ccbp->hi_state & ST_BREAK) { 187812174Speter if (isopen) { 187912174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 188010015Speter } 188110015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 188210015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 188310015Speter } 188410015Speter 188510015Speter /* 188612174Speter * Do RX stuff - if not open then dump any characters. 188712174Speter * XXX: This is VERY messy and needs to be cleaned up. 188812174Speter * 188912174Speter * XXX: can we leave data in the host adapter buffer 189012174Speter * when the clists are full? That may be dangerous 189112174Speter * if the user cannot get an interrupt signal through. 189210015Speter */ 189310015Speter 189412174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 189512174Speter 189612174Speter if (!isopen) { 189710015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 189812174Speter goto end_rx; 189912174Speter } 190010015Speter 190112174Speter /* 190212174Speter * Process read characters if not skipped above 190312174Speter */ 190412174Speter c = ccbp->hi_rxipos - ccbp->hi_rxopos; 190512174Speter if (c == 0) { 190612174Speter goto end_rx; 190712174Speter } 190810015Speter 190912174Speter op = ccbp->hi_rxopos; 191012174Speter ip = ccbp->hi_rxipos; 191112174Speter n = c & 0xff; 191212174Speter 191312174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 191410015Speter n, op, ip)); 191510015Speter 191612174Speter /* 191712174Speter * Suck characters out of host card buffer into the 191812174Speter * "input staging buffer" - so that we dont leave the 191912174Speter * host card in limbo while we're possibly echoing 192012174Speter * characters and possibly flushing input inside the 192112174Speter * ldisc l_rint() routine. 192212174Speter */ 192312496Speter if (n <= SI_BUFFERSIZE - op) { 192410015Speter 192512174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 192612174Speter z = ccbp->hi_rxbuf + op; 192712174Speter bcopy((caddr_t)z, si_rxbuf, n); 192810015Speter 192912174Speter op += n; 193012174Speter } else { 193112496Speter x = SI_BUFFERSIZE - op; 193210015Speter 193312174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 193412174Speter z = ccbp->hi_rxbuf + op; 193512174Speter bcopy((caddr_t)z, si_rxbuf, x); 193610015Speter 193712174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 193812174Speter z = ccbp->hi_rxbuf; 193912174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 194010015Speter 194112174Speter op += n; 194212174Speter } 194310015Speter 194412174Speter /* clear collected characters from buffer */ 194512174Speter ccbp->hi_rxopos = op; 194612174Speter 194712174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 194810015Speter n, op, ip)); 194910015Speter 195012174Speter /* 195112174Speter * at this point... 195212174Speter * n = number of chars placed in si_rxbuf 195312174Speter */ 195410015Speter 195512174Speter /* 195612174Speter * Avoid the grotesquely inefficient lineswitch 195712174Speter * routine (ttyinput) in "raw" mode. It usually 195812174Speter * takes about 450 instructions (that's without 195912174Speter * canonical processing or echo!). slinput is 196012174Speter * reasonably fast (usually 40 instructions 196112174Speter * plus call overhead). 196212174Speter */ 196312174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 196410015Speter 196512174Speter /* block if the driver supports it */ 196612174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 196712174Speter && (tp->t_cflag & CRTS_IFLOW 196812174Speter || tp->t_iflag & IXOFF) 196912174Speter && !(tp->t_state & TS_TBLOCK)) 197012174Speter ttyblock(tp); 197110015Speter 197212174Speter tk_nin += n; 197312174Speter tk_rawcc += n; 197412174Speter tp->t_rawcc += n; 197512174Speter 197612174Speter pp->sp_delta_overflows += 197712174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 197812174Speter 197912174Speter ttwakeup(tp); 198012174Speter if (tp->t_state & TS_TTSTOP 198112174Speter && (tp->t_iflag & IXANY 198212174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 198312174Speter tp->t_state &= ~TS_TTSTOP; 198412174Speter tp->t_lflag &= ~FLUSHO; 198512174Speter si_start(tp); 198612174Speter } 198712174Speter } else { 198812174Speter /* 198912174Speter * It'd be nice to not have to go through the 199012174Speter * function call overhead for each char here. 199112174Speter * It'd be nice to block input it, saving a 199212174Speter * loop here and the call/return overhead. 199312174Speter */ 199412174Speter for(x = 0; x < n; x++) { 199512174Speter i = si_rxbuf[x]; 199612174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 199712174Speter == -1) { 199812174Speter pp->sp_delta_overflows++; 199910015Speter } 200012174Speter /* 200112174Speter * doesn't seem to be much point doing 200212174Speter * this here.. this driver has no 200312174Speter * softtty processing! ?? 200412174Speter */ 200512174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 200612174Speter setsofttty(); 200712174Speter } 200812174Speter } 200912174Speter } 201012174Speter goto more_rx; /* try for more until RXbuf is empty */ 201110015Speter 201212174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 201310015Speter 201410015Speter /* 201510015Speter * Do TX stuff 201610015Speter */ 201710015Speter (*linesw[tp->t_line].l_start)(tp); 201810015Speter 201910015Speter } /* end of for (all ports on this controller) */ 202010015Speter } /* end of for (all controllers) */ 202110015Speter 202211609Speter in_intr = 0; 202311609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 202410015Speter} 202510015Speter 202610015Speter/* 202710015Speter * Nudge the transmitter... 202812174Speter * 202912174Speter * XXX: I inherited some funny code here. It implies the host card only 203012174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 203112174Speter * not interrupt when it's actually hits empty. In some cases, we have 203212174Speter * processes waiting for complete drain, and we need to simulate an interrupt 203312174Speter * about when we think the buffer is going to be empty (and retry if not). 203412174Speter * I really am not certain about this... I *need* the hardware manuals. 203510015Speter */ 203610015Speterstatic void 203710015Spetersi_start(tp) 203810015Speter register struct tty *tp; 203910015Speter{ 204010015Speter struct si_port *pp; 204110015Speter volatile struct si_channel *ccbp; 204210015Speter register struct clist *qp; 204310015Speter register char *dptr; 204410015Speter BYTE ipos; 204510015Speter int nchar; 204610015Speter int oldspl, count, n, amount, buffer_full; 204710015Speter int do_exitproc; 204810015Speter 204910015Speter oldspl = spltty(); 205010015Speter 205110015Speter qp = &tp->t_outq; 205210015Speter pp = TP2PP(tp); 205310015Speter 205410015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 205510015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 205610015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 205710015Speter 205810015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 205910015Speter goto out; 206010015Speter 206110015Speter do_exitproc = 0; 206210015Speter buffer_full = 0; 206310015Speter ccbp = pp->sp_ccb; 206410015Speter 206510015Speter /* 206610015Speter * Handle the case where ttywait() is called on process exit 206710015Speter * this may be BSDI specific, I dont know... 206810015Speter */ 206910015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 207010015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 207110015Speter do_exitproc++; 207210015Speter } 207310015Speter 207410015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 207510015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 207610015Speter 207710015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 207810015Speter 207910015Speter while ((nchar = qp->c_cc) > 0) { 208010015Speter if ((BYTE)count >= 255) { 208110015Speter buffer_full++; 208210015Speter break; 208310015Speter } 208410015Speter amount = min(nchar, (255 - (BYTE)count)); 208510015Speter ipos = (unsigned int)ccbp->hi_txipos; 208610015Speter /* will it fit in one lump? */ 208712496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 208810015Speter n = q_to_b(&tp->t_outq, 208910015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 209010015Speter } else { 209110015Speter n = q_to_b(&tp->t_outq, 209210015Speter (char *)&ccbp->hi_txbuf[ipos], 209312496Speter SI_BUFFERSIZE-ipos); 209412496Speter if (n == SI_BUFFERSIZE-ipos) { 209510015Speter n += q_to_b(&tp->t_outq, 209610015Speter (char *)&ccbp->hi_txbuf[0], 209712496Speter amount - (SI_BUFFERSIZE-ipos)); 209810015Speter } 209910015Speter } 210010015Speter ccbp->hi_txipos += n; 210110015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 210210015Speter } 210310015Speter 210410015Speter if (count != 0 && nchar == 0) { 210510015Speter tp->t_state |= TS_BUSY; 210610015Speter } else { 210710015Speter tp->t_state &= ~TS_BUSY; 210810015Speter } 210910015Speter 211010015Speter /* wakeup time? */ 211110015Speter ttwwakeup(tp); 211210015Speter 211310015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 211410015Speter (BYTE)count, nchar, tp->t_state)); 211510015Speter 211610015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 211710015Speter { 211810015Speter int time; 211910015Speter 212010015Speter if (do_exitproc != 0) { 212110015Speter time = hz / 10; 212210015Speter } else { 212310015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 212410015Speter 212510015Speter if (time > 0) { 212610015Speter if (time < nchar) 212710015Speter time = nchar / time; 212810015Speter else 212910015Speter time = 2; 213010015Speter } else { 213112174Speter printf("si%d: bad char time value!!\n", 213212174Speter (int)SI_CARD(tp->t_dev)); 213310015Speter goto out; 213410015Speter } 213510015Speter } 213610015Speter 213710015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 213810015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 213910015Speter } else { 214010015Speter pp->sp_state |= SS_LSTART; 214110015Speter } 214210015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 214310015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 214410015Speter } 214510015Speter 214610015Speterout: 214710015Speter splx(oldspl); 214810015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 214910015Speter} 215010015Speter 215110015Speter/* 215210015Speter * Note: called at splsoftclock from the timeout code 215310015Speter * This has to deal with two things... cause wakeups while waiting for 215410015Speter * tty drains on last process exit, and call l_start at about the right 215510015Speter * time for protocols like ppp. 215610015Speter */ 215710015Speterstatic void 215810015Spetersi_lstart(pp) 215910015Speter register struct si_port *pp; 216010015Speter{ 216110015Speter register struct tty *tp; 216210015Speter int oldspl; 216310015Speter 216410015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 216510015Speter pp, pp->sp_state)); 216610015Speter 216710015Speter oldspl = spltty(); 216810015Speter 216910015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 217010015Speter splx(oldspl); 217110015Speter return; 217210015Speter } 217310015Speter pp->sp_state &= ~SS_LSTART; 217410015Speter pp->sp_state |= SS_INLSTART; 217510015Speter 217610015Speter tp = pp->sp_tty; 217710015Speter 217810015Speter /* deal with the process exit case */ 217910015Speter ttwwakeup(tp); 218010015Speter 218112174Speter /* nudge protocols - eg: ppp */ 218210015Speter (*linesw[tp->t_line].l_start)(tp); 218310015Speter 218410015Speter pp->sp_state &= ~SS_INLSTART; 218510015Speter splx(oldspl); 218610015Speter} 218710015Speter 218810015Speter/* 218910015Speter * Stop output on a line. called at spltty(); 219010015Speter */ 219110015Spetervoid 219210015Spetersistop(tp, rw) 219310015Speter register struct tty *tp; 219410015Speter int rw; 219510015Speter{ 219610015Speter volatile struct si_channel *ccbp; 219710015Speter struct si_port *pp; 219810015Speter 219910015Speter pp = TP2PP(tp); 220010015Speter ccbp = pp->sp_ccb; 220110015Speter 220210015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 220310015Speter 220410015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 220510015Speter if (rw & FWRITE) { 220610015Speter /* what level are we meant to be flushing anyway? */ 220710015Speter if (tp->t_state & TS_BUSY) { 220810015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 220910015Speter tp->t_state &= ~TS_BUSY; 221010015Speter ttwwakeup(tp); /* Bruce???? */ 221110015Speter } 221210015Speter } 221312174Speter#if 1 /* XXX: this doesn't work right yet.. */ 221412174Speter /* XXX: this may have been failing because we used to call l_rint() 221512174Speter * while we were looping based on these two counters. Now, we collect 221612174Speter * the data and then loop stuffing it into l_rint(), making this 221712174Speter * useless. Should we cause this to blow away the staging buffer? 221812174Speter */ 221910015Speter if (rw & FREAD) { 222010015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 222110015Speter } 222210015Speter#endif 222310015Speter} 222410015Speter 222510015Speter/* 222610015Speter * Issue a command to the Z280 host card CPU. 222710015Speter */ 222810015Speter 222910015Speterstatic void 223010015Spetersi_command(pp, cmd, waitflag) 223110015Speter struct si_port *pp; /* port control block (local) */ 223210015Speter int cmd; 223310015Speter int waitflag; 223410015Speter{ 223510015Speter int oldspl; 223610015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 223710015Speter int x; 223810015Speter 223910015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 224010015Speter pp, cmd, waitflag, ccbp->hi_stat)); 224110015Speter 224210015Speter oldspl = spltty(); /* Keep others out */ 224310015Speter 224410015Speter /* wait until it's finished what it was doing.. */ 224510015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 224610015Speter x != IDLE_CLOSE && 224710015Speter x != cmd) { 224810015Speter if (in_intr) { /* Prevent sleep in intr */ 224910015Speter DPRINT((pp, DBG_PARAM, 225010015Speter "cmd intr collision - completing %d\trequested %d\n", 225110015Speter x, cmd)); 225210015Speter splx(oldspl); 225310015Speter return; 225410015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 225510015Speter "sicmd1", 1)) { 225610015Speter splx(oldspl); 225710015Speter return; 225810015Speter } 225910015Speter } 226010015Speter /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 226110015Speter 226210015Speter /* if there was a pending command, cause a state-change wakeup */ 226310015Speter if (pp->sp_pend != IDLE_OPEN) { 226410015Speter switch(pp->sp_pend) { 226510015Speter case LOPEN: 226610015Speter case MPEND: 226710015Speter case MOPEN: 226810015Speter case CONFIG: 226910015Speter wakeup(&pp->sp_state); 227010015Speter break; 227110015Speter default: 227210015Speter break; 227310015Speter } 227410015Speter } 227510015Speter 227610015Speter pp->sp_pend = cmd; /* New command pending */ 227710015Speter ccbp->hi_stat = cmd; /* Post it */ 227810015Speter 227910015Speter if (waitflag) { 228010015Speter if (in_intr) { /* If in interrupt handler */ 228110015Speter DPRINT((pp, DBG_PARAM, 228210015Speter "attempt to sleep in si_intr - cmd req %d\n", 228310015Speter cmd)); 228410015Speter splx(oldspl); 228510015Speter return; 228610015Speter } else while(ccbp->hi_stat != IDLE_OPEN) { 228710015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 228810015Speter "sicmd2", 0)) 228910015Speter break; 229010015Speter } 229110015Speter } 229210015Speter splx(oldspl); 229310015Speter} 229410015Speter 229510015Speterstatic void 229610015Spetersi_disc_optim(tp, t, pp) 229710015Speter struct tty *tp; 229810015Speter struct termios *t; 229910015Speter struct si_port *pp; 230010015Speter{ 230110015Speter /* 230210015Speter * XXX can skip a lot more cases if Smarts. Maybe 230310015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 230410015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 230510015Speter */ 230610015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 230710015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 230810015Speter && (!(t->c_iflag & PARMRK) 230910015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 231010015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 231110015Speter && linesw[tp->t_line].l_rint == ttyinput) 231210015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 231310015Speter else 231410015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 231510161Speter 231610015Speter /* 231710015Speter * Prepare to reduce input latency for packet 231810015Speter * discplines with a end of packet character. 231910015Speter */ 232010015Speter if (tp->t_line == SLIPDISC) 232110015Speter pp->sp_hotchar = 0xc0; 232210015Speter else if (tp->t_line == PPPDISC) 232310015Speter pp->sp_hotchar = 0x7e; 232410015Speter else 232510015Speter pp->sp_hotchar = 0; 232610161Speter 232710161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 232810161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 232910161Speter pp->sp_hotchar)); 233010015Speter} 233110015Speter 233210015Speter 233310015Speter#ifdef SI_DEBUG 233413353Speter 233510015Speterstatic void 233613353Speter#ifdef __STDC__ 233713353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 233813353Speter#else 233913353Spetersi_dprintf(pp, flags, fmt, va_alist) 234010015Speter struct si_port *pp; 234110015Speter int flags; 234213353Speter char *fmt; 234313353Speter#endif 234410015Speter{ 234513353Speter va_list ap; 234610015Speter if ((pp == NULL && (si_debug&flags)) || 234710015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 234813353Speter va_start(ap, fmt); 234910015Speter if (pp != NULL) 235012496Speter printf("%ci%d(%d): ", 's', 235112174Speter (int)SI_CARD(pp->sp_tty->t_dev), 235212174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 235313353Speter printf("%r", fmt, ap); 235413353Speter va_end(ap); 235510015Speter } 235610015Speter} 235710015Speter 235810015Speterstatic char * 235910015Spetersi_mctl2str(cmd) 236010015Speter enum si_mctl cmd; 236110015Speter{ 236210015Speter switch (cmd) { 236310015Speter case GET: return("GET"); 236410015Speter case SET: return("SET"); 236510015Speter case BIS: return("BIS"); 236610015Speter case BIC: return("BIC"); 236710015Speter } 236810015Speter return("BAD"); 236910015Speter} 237012502Sjulian 237112624Speter#endif /* DEBUG */ 237212502Sjulian 237312624Speter 237412502Sjulian 237512502Sjulianstatic si_devsw_installed = 0; 237612502Sjulian 237712517Sjulianstatic void si_drvinit(void *unused) 237812502Sjulian{ 237912517Sjulian dev_t dev; 238012517Sjulian 238112502Sjulian if( ! si_devsw_installed ) { 238212675Sjulian dev = makedev(CDEV_MAJOR, 0); 238312675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 238412502Sjulian si_devsw_installed = 1; 238512517Sjulian } 238612502Sjulian} 238712517Sjulian 238812517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 238912517Sjulian 2390