si.c revision 16839
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 * 3316839Speter * $Id: si.c,v 1.46 1996/06/21 21:35:01 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> 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> 5515683Speter#include <sys/sysctl.h> 5610015Speter#include <sys/devconf.h> 5712675Sjulian#ifdef DEVFS 5812675Sjulian#include <sys/devfsext.h> 5912675Sjulian#endif /*DEVFS*/ 6010015Speter 6110015Speter#include <machine/clock.h> 6210015Speter 6312659Sbde#include <vm/vm.h> 6412662Sdg#include <vm/vm_param.h> 6512662Sdg#include <vm/pmap.h> 6612659Sbde 6710015Speter#include <i386/isa/icu.h> 6810015Speter#include <i386/isa/isa.h> 6910015Speter#include <i386/isa/isa_device.h> 7010015Speter 7110015Speter#include <i386/isa/sireg.h> 7210015Speter#include <machine/si.h> 7313353Speter#include <machine/stdarg.h> 7410015Speter 7510015Speter#include "si.h" 7610015Speter 7710015Speter/* 7810015Speter * This device driver is designed to interface the Specialix International 7912496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 8010015Speter * 8110015Speter * The controller is interfaced to the host via dual port ram 8210015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 8310015Speter */ 8410015Speter 8510015Speter#define POLL /* turn on poller to generate buffer empty interrupt */ 8610047Speter#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 8712496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8815639Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 8915639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 9010015Speter 9110015Speterenum si_mctl { GET, SET, BIS, BIC }; 9210015Speter 9310015Speterstatic void si_command __P((struct si_port *, int, int)); 9410015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 9510015Speterstatic void si_write_enable __P((struct si_port *, int)); 9610015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 9710015Speterstatic void si_start __P((struct tty *)); 9810015Speterstatic void si_lstart __P((struct si_port *)); 9910015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 10010015Speter struct si_port *pp)); 10110015Speterstatic void sihardclose __P((struct si_port *pp)); 10210015Speterstatic void sidtrwakeup __P((void *chan)); 10310015Speter 10412724Sphkstatic int siparam __P((struct tty *, struct termios *)); 10510015Speter 10612724Sphkstatic void si_registerdev __P((struct isa_device *id)); 10712724Sphkstatic int siprobe __P((struct isa_device *id)); 10812724Sphkstatic int siattach __P((struct isa_device *id)); 10910708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 11010708Speter 11112675Sjulianstruct isa_driver sidriver = 11212675Sjulian { siprobe, siattach, "si" }; 11312675Sjulian 11412675Sjulian 11512675Sjulianstatic d_open_t siopen; 11612675Sjulianstatic d_close_t siclose; 11712675Sjulianstatic d_read_t siread; 11812675Sjulianstatic d_write_t siwrite; 11912675Sjulianstatic d_ioctl_t siioctl; 12012675Sjulianstatic d_stop_t sistop; 12112731Sbdestatic d_devtotty_t sidevtotty; 12212675Sjulian 12312675Sjulian#define CDEV_MAJOR 68 12412678Sphkstatic struct cdevsw si_cdevsw = 12512675Sjulian { siopen, siclose, siread, siwrite, /*68*/ 12612743Sbde siioctl, sistop, noreset, sidevtotty,/* si */ 12712742Sbde ttselect, nommap, NULL, "si", NULL, -1 }; 12812675Sjulian 12912675Sjulian 13012174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 13113353Speter 13213353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 13313353Speter ...)); 13410708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 13513353Speter 13610708Speter#define DPRINT(x) si_dprintf x 13713353Speter 13810708Speter#else 13910708Speter#define DPRINT(x) /* void */ 14010708Speter#endif 14110708Speter 14210962Speterstatic int si_Nports; 14310962Speterstatic int si_Nmodules; 14410962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 14510015Speter 14610962Speterstatic struct tty *si_tty; 14710962Speter 14812174Speter/* where the firmware lives; defined in si_code.c */ 14910015Speterextern int si_dsize; 15010015Speterextern unsigned char si_download[]; 15110015Speter 15210044Speterstruct si_softc { 15310044Speter int sc_type; /* adapter type */ 15410044Speter char *sc_typename; /* adapter type string */ 15510044Speter 15610044Speter struct si_port *sc_ports; /* port structures for this card */ 15710044Speter 15810044Speter caddr_t sc_paddr; /* physical addr of iomem */ 15910044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 16010044Speter int sc_nport; /* # ports on this card */ 16110044Speter int sc_irq; /* copy of attach irq */ 16210044Speter int sc_eisa_iobase; /* EISA io port address */ 16310044Speter int sc_eisa_irqbits; 16410044Speter struct kern_devconf sc_kdc; 16512675Sjulian#ifdef DEVFS 16612675Sjulian struct { 16712675Sjulian void *ttyd; 16812826Speter void *cuaa; 16912675Sjulian void *ttyl; 17012675Sjulian void *ttyi; 17112675Sjulian } devfs_token[32]; /* what is the max per card? */ 17213165Speter void *control_token; 17312675Sjulian#endif 17410044Speter}; 17512724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 17610044Speter 17712174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 17810015Speter# define B2000 2000 17910015Speter#endif 18010015Speterstatic struct speedtab bdrates[] = { 18110015Speter B75, CLK75, /* 0x0 */ 18210015Speter B110, CLK110, /* 0x1 */ 18310015Speter B150, CLK150, /* 0x3 */ 18410015Speter B300, CLK300, /* 0x4 */ 18510015Speter B600, CLK600, /* 0x5 */ 18610015Speter B1200, CLK1200, /* 0x6 */ 18710015Speter B2000, CLK2000, /* 0x7 */ 18810015Speter B2400, CLK2400, /* 0x8 */ 18910015Speter B4800, CLK4800, /* 0x9 */ 19010015Speter B9600, CLK9600, /* 0xb */ 19110015Speter B19200, CLK19200, /* 0xc */ 19210015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 19310015Speter B57600, CLK57600, /* 0xd */ 19410015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 19510015Speter -1, -1 19610015Speter}; 19710015Speter 19810015Speter 19910015Speter/* populated with approx character/sec rates - translated at card 20010015Speter * initialisation time to chars per tick of the clock */ 20110015Speterstatic int done_chartimes = 0; 20210015Speterstatic struct speedtab chartimes[] = { 20310015Speter B75, 8, 20410015Speter B110, 11, 20510015Speter B150, 15, 20610015Speter B300, 30, 20710015Speter B600, 60, 20810015Speter B1200, 120, 20910015Speter B2000, 200, 21010015Speter B2400, 240, 21110015Speter B4800, 480, 21210015Speter B9600, 960, 21310015Speter B19200, 1920, 21410015Speter B38400, 3840, 21510015Speter B57600, 5760, 21610015Speter B115200, 11520, 21710015Speter -1, -1 21810015Speter}; 21910015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 22010015Speter 22110047Speterstatic int si_default_rate = TTYDEF_SPEED; 22210047Speterstatic int si_default_iflag = 0; 22310047Speterstatic int si_default_oflag = 0; 22410047Speterstatic int si_default_lflag = 0; 22510047Speter#ifdef SI_DEF_HWFLOW 22610047Speterstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 22710047Speter#else 22810047Speterstatic int si_default_cflag = TTYDEF_CFLAG; 22910047Speter#endif 23010047Speter 23110015Speter#ifdef POLL 23215683Speterstatic int si_pollrate; /* in addition to irq */ 23315639Speter 23416403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 23515639Speter 23610015Speterstatic int init_finished = 0; 23710015Speterstatic void si_poll __P((void *)); 23810015Speter#endif 23910015Speter 24010015Speter/* 24110015Speter * Array of adapter types and the corresponding RAM size. The order of 24210015Speter * entries here MUST match the ordinal of the adapter type. 24310015Speter */ 24410015Speterstatic char *si_type[] = { 24510015Speter "EMPTY", 24610015Speter "SIHOST", 24710015Speter "SI2", /* MCA */ 24810015Speter "SIHOST2", 24910015Speter "SIEISA", 25010015Speter}; 25110015Speter 25210015Speter 25310015Speterstatic struct kern_devconf si_kdc[NSI] = { { 25410015Speter 0, 0, 0, /* filled in by dev_attach */ 25510015Speter "si", 0, { MDDT_ISA, 0, "tty" }, 25610015Speter isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 25710015Speter &kdc_isa0, /* parent */ 25810015Speter 0, /* parent data */ 25910015Speter DC_UNCONFIGURED, /* state */ 26010015Speter "Specialix SI/XIO Host adapter", 26110015Speter DC_CLS_SERIAL, /* class */ 26210015Speter} }; 26310015Speter 26412724Sphkstatic void 26510015Spetersi_registerdev(id) 26610015Speter struct isa_device *id; 26710015Speter{ 26810015Speter if (id->id_unit != 0) { 26916214Speter bcopy(&si_kdc[0], &si_kdc[id->id_unit], sizeof(si_kdc[0])); 27010015Speter } 27110015Speter si_kdc[id->id_unit].kdc_unit = id->id_unit; 27210015Speter si_kdc[id->id_unit].kdc_isa = id; 27312174Speter si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 27410015Speter dev_attach(&si_kdc[id->id_unit]); 27510015Speter} 27610015Speter 27710015Speter/* Look for a valid board at the given mem addr */ 27812724Sphkstatic int 27910015Spetersiprobe(id) 28010015Speter struct isa_device *id; 28110015Speter{ 28210015Speter struct si_softc *sc; 28310015Speter int type; 28410015Speter u_int i, ramsize; 28510015Speter volatile BYTE was, *ux; 28610015Speter volatile unsigned char *maddr; 28710015Speter unsigned char *paddr; 28810015Speter 28910015Speter si_registerdev(id); 29010015Speter 29115683Speter si_pollrate = (hz / 10); /* 10 per second */ 29215683Speter 29310015Speter maddr = id->id_maddr; /* virtual address... */ 29410015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 29510015Speter 29612496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 29712496Speter id->id_unit, id->id_maddr, paddr)); 29810015Speter 29910015Speter /* 30010015Speter * this is a lie, but it's easier than trying to handle caching 30110015Speter * and ram conflicts in the >1M and <16M region. 30210015Speter */ 30310015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 30410015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 30512174Speter printf("si%d: iomem (%lx) out of range\n", 30612174Speter id->id_unit, (long)paddr); 30710015Speter return(0); 30810015Speter } 30910015Speter 31010015Speter if (id->id_unit >= NSI) { 31110015Speter /* THIS IS IMPOSSIBLE */ 31210015Speter return(0); 31310015Speter } 31410015Speter 31510015Speter if (((u_int)paddr & 0x7fff) != 0) { 31610015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 31710015Speter "si%d: iomem (%x) not on 32k boundary\n", 31810015Speter id->id_unit, paddr)); 31910015Speter return(0); 32010015Speter } 32110015Speter 32210015Speter 32310015Speter for (i=0; i < NSI; i++) { 32410015Speter if ((sc = &si_softc[i]) == NULL) 32510015Speter continue; 32610015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 32710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 32810015Speter "si%d: iomem (%x) already configured to si%d\n", 32910015Speter id->id_unit, sc->sc_paddr, i)); 33010015Speter return(0); 33110015Speter } 33210015Speter } 33310015Speter 33410015Speter#if NEISA > 0 33510015Speter if (id->id_iobase > 0x0fff) { /* EISA card */ 33610015Speter int irq, port; 33710015Speter unsigned long base; 33810015Speter int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 33910015Speter IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 34010015Speter 34110015Speter port = id->id_iobase; 34210015Speter base = (inb(port+1) << 24) | (inb(port) << 16); 34310015Speter irq = ((inb(port+2) >> 4) & 0xf); 34410015Speter 34510015Speter id->id_irq = eisa_irqs[irq]; 34610015Speter 34710015Speter DPRINT((0, DBG_AUTOBOOT, 34812496Speter "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 34910015Speter id->id_unit, base, irq, id->id_irq, port)); 35010015Speter 35110015Speter if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 35210015Speter goto bad_irq; 35310015Speter 35410015Speter id->id_iobase &= 0xf000; 35510015Speter id->id_iosize = 0x0fff; 35610015Speter 35710015Speter type = EISA; 35810015Speter outb(p+2, (BYTE)irq << 4); 35910015Speter 36010015Speter sc->sc_eisa_iobase = p; 36110015Speter sc->sc_eisa_irqbits = irq << 4; 36210015Speter ramsize = SIEISA_RAMSIZE; 36310015Speter goto got_card; 36410015Speter } 36510015Speter#endif 36610015Speter 36710015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 36810015Speter *maddr = 0x17; 36910015Speter if (*maddr != 0x17) { 37010015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 37110015Speter "si%d: 0x17 check fail at phys 0x%x\n", 37210015Speter id->id_unit, paddr)); 37310015Speterfail: 37410015Speter return(0); 37510015Speter } 37610015Speter /* 37710015Speter * OK, now to see if whatever responded is really an SI card. 37810015Speter * Try for a MK II first (SIHOST2) 37910015Speter */ 38010015Speter for (i=SIPLSIG; i<SIPLSIG+8; i++) 38110015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 38210015Speter goto try_mk1; 38310015Speter 38410015Speter /* It must be an SIHOST2 */ 38510015Speter *(maddr + SIPLRESET) = 0; 38610015Speter *(maddr + SIPLIRQCLR) = 0; 38710015Speter *(maddr + SIPLIRQSET) = 0x10; 38810015Speter type = SIHOST2; 38910015Speter ramsize = SIHOST2_RAMSIZE; 39010015Speter goto got_card; 39110015Speter 39210015Speter /* 39310015Speter * Its not a MK II, so try for a MK I (SIHOST) 39410015Speter */ 39510015Spetertry_mk1: 39610015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 39710015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 39810015Speter *(maddr+SIRAM) = 0x17; 39910015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 40010015Speter goto fail; 40110015Speter *(maddr+0x7ff8) = 0x17; 40210015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 40310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 40410015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 40510015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 40610015Speter goto fail; 40710015Speter } 40810015Speter 40910015Speter /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 41010015Speter type = SIHOST; 41110015Speter ramsize = SIHOST_RAMSIZE; 41210015Speter 41310015Spetergot_card: 41412496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 41512496Speter id->id_unit, type)); 41610015Speter /* Try the acid test */ 41710015Speter ux = (BYTE *)(maddr + SIRAM); 41810015Speter for (i=0; i<ramsize; i++, ux++) 41910015Speter *ux = (BYTE)(i&0xff); 42010015Speter ux = (BYTE *)(maddr + SIRAM); 42110015Speter for (i=0; i<ramsize; i++, ux++) { 42210015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 42310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 42412174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 42510015Speter id->id_unit, paddr+i, was, i&0xff)); 42610015Speter goto fail; 42710015Speter } 42810015Speter } 42910015Speter 43010015Speter /* clear out the RAM */ 43110015Speter ux = (BYTE *)(maddr + SIRAM); 43210015Speter for (i=0; i<ramsize; i++) 43310015Speter *ux++ = 0; 43410015Speter ux = (BYTE *)(maddr + SIRAM); 43510015Speter for (i=0; i<ramsize; i++) { 43610015Speter if ((was = *ux++) != 0) { 43710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 43812174Speter "si%d: clear fail at phys 0x%x, was %x\n", 43910015Speter id->id_unit, paddr+i, was)); 44010015Speter goto fail; 44110015Speter } 44210015Speter } 44310015Speter 44410015Speter /* 44510015Speter * Success, we've found a valid board, now fill in 44610015Speter * the adapter structure. 44710015Speter */ 44810015Speter switch (type) { 44910015Speter case SIHOST2: 45010015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 45110015Speterbad_irq: 45210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 45310015Speter "si%d: bad IRQ value - %d\n", 45410015Speter id->id_unit, id->id_irq)); 45510015Speter return(0); 45610015Speter } 45710015Speter id->id_msize = SIHOST2_MEMSIZE; 45810015Speter break; 45910015Speter case SIHOST: 46010015Speter if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 46110015Speter goto bad_irq; 46210015Speter } 46310015Speter id->id_msize = SIHOST_MEMSIZE; 46410015Speter break; 46510015Speter case SIEISA: 46610015Speter id->id_msize = SIEISA_MEMSIZE; 46710015Speter break; 46810015Speter case SI2: /* MCA */ 46910015Speter default: 47010015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 47110015Speter return(0); 47210015Speter } 47310015Speter si_softc[id->id_unit].sc_type = type; 47410015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 47510015Speter return(-1); /* -1 == found */ 47610015Speter} 47710015Speter 47810015Speter/* 47910015Speter * Attach the device. Initialize the card. 48010015Speter */ 48112724Sphkstatic int 48210015Spetersiattach(id) 48310015Speter struct isa_device *id; 48410015Speter{ 48510015Speter int unit = id->id_unit; 48610015Speter struct si_softc *sc = &si_softc[unit]; 48710015Speter struct si_port *pp; 48810015Speter volatile struct si_channel *ccbp; 48910015Speter volatile struct si_reg *regp; 49010015Speter volatile caddr_t maddr; 49110015Speter struct si_module *modp; 49210015Speter struct tty *tp; 49310015Speter struct speedtab *spt; 49410015Speter int nmodule, nport, x, y; 49512174Speter int uart_type; 49610015Speter 49712496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 49810015Speter 49910015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 50010015Speter sc->sc_maddr = id->id_maddr; 50110015Speter sc->sc_irq = id->id_irq; 50210015Speter 50310015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 50410015Speter 50510015Speter maddr = sc->sc_maddr; 50610015Speter 50710015Speter /* 50810015Speter * OK, now lets download the firmware and try and boot the CPU.. 50910015Speter */ 51010015Speter 51112496Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 51212496Speter id->id_unit, si_dsize)); 51310015Speter bcopy(si_download, maddr, si_dsize); 51410015Speter 51510015Speter switch (sc->sc_type) { 51610015Speter case SIEISA: 51710015Speter#if NEISA > 0 51810015Speter /* modify the Z280 firmware to tell it that it's on an EISA */ 51910015Speter *(maddr+0x42) = 1; 52010015Speter outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 52110015Speter (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 52210015Speter break; 52310015Speter#endif /* fall-through if not EISA */ 52410015Speter case SI2: 52512174Speter /* 52612174Speter * must get around to converting the code for 52712174Speter * these one day, if FreeBSD ever supports it. 52812174Speter */ 52910015Speter return 0; 53010015Speter case SIHOST: 53110015Speter *(maddr+SIRESET_CL) = 0; 53210015Speter *(maddr+SIINTCL_CL) = 0; 53310015Speter break; 53410015Speter case SIHOST2: 53510015Speter *(maddr+SIPLRESET) = 0x10; 53610015Speter switch (sc->sc_irq) { 53710015Speter case IRQ11: 53810015Speter *(maddr+SIPLIRQ11) = 0x10; 53910015Speter break; 54010015Speter case IRQ12: 54110015Speter *(maddr+SIPLIRQ12) = 0x10; 54210015Speter break; 54310015Speter case IRQ15: 54410015Speter *(maddr+SIPLIRQ15) = 0x10; 54510015Speter break; 54610015Speter } 54710015Speter *(maddr+SIPLIRQCLR) = 0x10; 54810015Speter break; 54910015Speter } 55010015Speter 55110015Speter DELAY(1000000); /* wait around for a second */ 55210015Speter 55310015Speter regp = (struct si_reg *)maddr; 55410015Speter y = 0; 55510015Speter /* wait max of 5 sec for init OK */ 55610015Speter while (regp->initstat == 0 && y++ < 10) { 55710015Speter DELAY(500000); 55810015Speter } 55910015Speter switch (regp->initstat) { 56010015Speter case 0: 56110015Speter printf("si%d: startup timeout - aborting\n", unit); 56212174Speter sc->sc_type = SIEMPTY; 56310015Speter return 0; 56410015Speter case 1: 56512174Speter /* set throttle to 125 intr per second */ 56615639Speter regp->int_count = INT_COUNT; 56710015Speter /* rx intr max of 25 timer per second */ 56815639Speter regp->rx_int_count = RXINT_COUNT; 56910015Speter regp->int_pending = 0; /* no intr pending */ 57010015Speter regp->int_scounter = 0; /* reset counter */ 57110015Speter break; 57210015Speter case 0xff: 57310015Speter /* 57410015Speter * No modules found, so give up on this one. 57510015Speter */ 57610015Speter printf("si%d: %s - no ports found\n", unit, 57710015Speter si_type[sc->sc_type]); 57810015Speter return 0; 57910015Speter default: 58010015Speter printf("si%d: Z280 version error - initstat %x\n", 58110015Speter unit, regp->initstat); 58210015Speter return 0; 58310015Speter } 58410015Speter 58510015Speter /* 58610015Speter * First time around the ports just count them in order 58710015Speter * to allocate some memory. 58810015Speter */ 58910015Speter nport = 0; 59010015Speter modp = (struct si_module *)(maddr + 0x80); 59110015Speter for (;;) { 59212174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 59310015Speter switch (modp->sm_type & (~MMASK)) { 59410015Speter case M232: 59510015Speter case M422: 59610015Speter DPRINT((0, DBG_DOWNLOAD, 59712174Speter "si%d: Found 232/422 module, %d ports\n", 59810015Speter unit, (int)(modp->sm_type & MMASK))); 59910015Speter 60010015Speter /* this is a firmware issue */ 60110015Speter if (si_Nports == SI_MAXPORTPERCARD) { 60210015Speter printf("si%d: extra ports ignored\n", unit); 60310015Speter continue; 60410015Speter } 60510015Speter 60610015Speter x = modp->sm_type & MMASK; 60710015Speter nport += x; 60810015Speter si_Nports += x; 60910015Speter si_Nmodules++; 61010015Speter break; 61110015Speter default: 61210015Speter printf("si%d: unknown module type %d\n", 61310015Speter unit, modp->sm_type); 61410015Speter break; 61510015Speter } 61610015Speter if (modp->sm_next == 0) 61710015Speter break; 61810015Speter modp = (struct si_module *) 61910015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 62010015Speter } 62110015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 62210015Speter M_DEVBUF, M_NOWAIT); 62310015Speter if (sc->sc_ports == 0) { 62410015Spetermem_fail: 62510015Speter printf("si%d: fail to malloc memory for port structs\n", 62610015Speter unit); 62710015Speter return 0; 62810015Speter } 62910015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 63010015Speter sc->sc_nport = nport; 63110015Speter 63210015Speter /* 63310015Speter * allocate tty structures for ports 63410015Speter */ 63510015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 63610015Speter if (tp == 0) 63710015Speter goto mem_fail; 63810015Speter bzero(tp, sizeof(*tp) * nport); 63910962Speter si_tty = tp; 64010015Speter 64110015Speter /* mark the device state as attached */ 64210015Speter si_kdc[unit].kdc_state = DC_BUSY; 64310015Speter 64410015Speter /* 64510015Speter * Scan round the ports again, this time initialising. 64610015Speter */ 64710015Speter pp = sc->sc_ports; 64810015Speter nmodule = 0; 64910015Speter modp = (struct si_module *)(maddr + 0x80); 65012174Speter uart_type = 0; 65110015Speter for (;;) { 65210015Speter switch (modp->sm_type & (~MMASK)) { 65310015Speter case M232: 65410015Speter case M422: 65510015Speter nmodule++; 65610015Speter nport = (modp->sm_type & MMASK); 65710015Speter ccbp = (struct si_channel *)((char *)modp+0x100); 65812174Speter if (uart_type == 0) 65912174Speter uart_type = ccbp->type; 66010015Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 66110015Speter pp->sp_ccb = ccbp; /* save the address */ 66210015Speter pp->sp_tty = tp++; 66310015Speter pp->sp_pend = IDLE_CLOSE; 66410015Speter pp->sp_state = 0; /* internal flag */ 66510015Speter pp->sp_dtr_wait = 3 * hz; 66610047Speter pp->sp_iin.c_iflag = si_default_iflag; 66710047Speter pp->sp_iin.c_oflag = si_default_oflag; 66810047Speter pp->sp_iin.c_cflag = si_default_cflag; 66910047Speter pp->sp_iin.c_lflag = si_default_lflag; 67010015Speter termioschars(&pp->sp_iin); 67110015Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 67210047Speter si_default_rate; 67310015Speter pp->sp_iout = pp->sp_iin; 67410015Speter } 67510015Speter break; 67610015Speter default: 67710015Speter break; 67810015Speter } 67910015Speter if (modp->sm_next == 0) { 68012174Speter printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 68110015Speter unit, 68210015Speter sc->sc_typename, 68310015Speter sc->sc_nport, 68412174Speter nmodule, 68512174Speter uart_type); 68610015Speter break; 68710015Speter } 68810015Speter modp = (struct si_module *) 68910015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 69010015Speter } 69110015Speter if (done_chartimes == 0) { 69210015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 69310015Speter if ((spt->sp_code /= hz) == 0) 69410015Speter spt->sp_code = 1; 69510015Speter } 69610015Speter done_chartimes = 1; 69710015Speter } 69812502Sjulian 69912675Sjulian#ifdef DEVFS 70012675Sjulian/* path name devsw minor type uid gid perm*/ 70113169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 70213165Speter y = x + 1; /* For sync with the manuals that start at 1 */ 70313630Sphk sc->devfs_token[x].ttyd = devfs_add_devswf( 70413630Sphk &si_cdevsw, x, 70513630Sphk DV_CHR, 0, 0, 0600, "ttyA%02d", y); 70613630Sphk sc->devfs_token[x].cuaa = devfs_add_devswf( 70713630Sphk &si_cdevsw, x + 128, 70813630Sphk DV_CHR, 0, 0, 0600, "cuaA%02d", y); 70913630Sphk sc->devfs_token[x].ttyi = devfs_add_devswf( 71013630Sphk &si_cdevsw, x + 0x10000, 71113630Sphk DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 71213630Sphk sc->devfs_token[x].ttyl = devfs_add_devswf( 71313630Sphk &si_cdevsw, x + 0x20000, 71413630Sphk DV_CHR, 0, 0, 0600, "ttylA%02d", y); 71512675Sjulian } 71614873Sscrappy sc->control_token = 71714873Sscrappy devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 71814873Sscrappy "si_control"); 71912675Sjulian#endif 72010015Speter return (1); 72110015Speter} 72210015Speter 72312675Sjulianstatic int 72410015Spetersiopen(dev, flag, mode, p) 72510015Speter dev_t dev; 72610015Speter int flag, mode; 72710015Speter struct proc *p; 72810015Speter{ 72910015Speter int oldspl, error; 73010015Speter int card, port; 73110015Speter register struct si_softc *sc; 73210015Speter register struct tty *tp; 73310015Speter volatile struct si_channel *ccbp; 73410015Speter struct si_port *pp; 73510015Speter int mynor = minor(dev); 73610015Speter 73710015Speter /* quickly let in /dev/si_control */ 73810015Speter if (IS_CONTROLDEV(mynor)) { 73910015Speter if (error = suser(p->p_ucred, &p->p_acflag)) 74010015Speter return(error); 74110015Speter return(0); 74210015Speter } 74310015Speter 74410015Speter card = SI_CARD(mynor); 74510015Speter if (card >= NSI) 74610015Speter return (ENXIO); 74710015Speter sc = &si_softc[card]; 74810015Speter 74912174Speter if (sc->sc_type == SIEMPTY) { 75012174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 75110015Speter card, sc->sc_typename)); 75210015Speter return(ENXIO); 75310015Speter } 75410015Speter 75510015Speter port = SI_PORT(mynor); 75610015Speter if (port >= sc->sc_nport) { 75712174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 75810015Speter card, sc->sc_nport)); 75910015Speter return(ENXIO); 76010015Speter } 76110015Speter 76210015Speter#ifdef POLL 76310015Speter /* 76410015Speter * We've now got a device, so start the poller. 76510015Speter */ 76610015Speter if (init_finished == 0) { 76715639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 76810015Speter init_finished = 1; 76910015Speter } 77010015Speter#endif 77110015Speter 77210015Speter /* initial/lock device */ 77310015Speter if (IS_STATE(mynor)) { 77410015Speter return(0); 77510015Speter } 77610015Speter 77710015Speter pp = sc->sc_ports + port; 77810015Speter tp = pp->sp_tty; /* the "real" tty */ 77910015Speter ccbp = pp->sp_ccb; /* Find control block */ 78010015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 78110015Speter dev, flag, mode, p)); 78210015Speter 78310015Speter oldspl = spltty(); /* Keep others out */ 78410015Speter error = 0; 78510015Speter 78610015Speteropen_top: 78710015Speter while (pp->sp_state & SS_DTR_OFF) { 78810015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 78910015Speter if (error != 0) 79010015Speter goto out; 79110015Speter } 79210015Speter 79310015Speter if (tp->t_state & TS_ISOPEN) { 79410015Speter /* 79510015Speter * The device is open, so everything has been initialised. 79610015Speter * handle conflicts. 79710015Speter */ 79810015Speter if (IS_CALLOUT(mynor)) { 79910015Speter if (!pp->sp_active_out) { 80010015Speter error = EBUSY; 80110015Speter goto out; 80210015Speter } 80310015Speter } else { 80410015Speter if (pp->sp_active_out) { 80510015Speter if (flag & O_NONBLOCK) { 80610015Speter error = EBUSY; 80710015Speter goto out; 80810015Speter } 80910015Speter error = tsleep(&pp->sp_active_out, 81010015Speter TTIPRI|PCATCH, "sibi", 0); 81110015Speter if (error != 0) 81210015Speter goto out; 81310015Speter goto open_top; 81410015Speter } 81510015Speter } 81610015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 81710015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 81810015Speter "already open and EXCLUSIVE set\n")); 81910015Speter error = EBUSY; 82010015Speter goto out; 82110015Speter } 82210015Speter } else { 82310015Speter /* 82410015Speter * The device isn't open, so there are no conflicts. 82510015Speter * Initialize it. Avoid sleep... :-) 82610015Speter */ 82710015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 82810015Speter tp->t_oproc = si_start; 82910015Speter tp->t_param = siparam; 83010015Speter tp->t_dev = dev; 83110015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 83210015Speter ? pp->sp_iout : pp->sp_iin; 83310015Speter 83410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 83510015Speter 83610015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 83710015Speter 83810015Speter error = siparam(tp, &tp->t_termios); 83910015Speter 84010015Speter --pp->sp_wopeners; 84110015Speter if (error != 0) 84210015Speter goto out; 84310015Speter /* XXX: we should goto_top if siparam slept */ 84410015Speter 84510015Speter ttsetwater(tp); 84610015Speter 84710015Speter /* set initial DCD state */ 84810015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 84910015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 85010015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 85110015Speter } 85210015Speter } 85310015Speter 85410015Speter /* whoops! we beat the close! */ 85510015Speter if (pp->sp_state & SS_CLOSING) { 85610015Speter /* try and stop it from proceeding to bash the hardware */ 85710015Speter pp->sp_state &= ~SS_CLOSING; 85810015Speter } 85910015Speter 86010015Speter /* 86110015Speter * Wait for DCD if necessary 86210015Speter */ 86310015Speter if (!(tp->t_state & TS_CARR_ON) 86410015Speter && !IS_CALLOUT(mynor) 86510015Speter && !(tp->t_cflag & CLOCAL) 86610015Speter && !(flag & O_NONBLOCK)) { 86710015Speter ++pp->sp_wopeners; 86810015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 86910015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 87010015Speter --pp->sp_wopeners; 87110015Speter if (error != 0) 87210015Speter goto out; 87310015Speter goto open_top; 87410015Speter } 87510015Speter 87610015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 87710015Speter si_disc_optim(tp, &tp->t_termios, pp); 87810015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 87910015Speter pp->sp_active_out = TRUE; 88010015Speter 88110015Speter pp->sp_state |= SS_OPEN; /* made it! */ 88210015Speter 88310015Speterout: 88410015Speter splx(oldspl); 88510015Speter 88610015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 88710015Speter 88810015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 88910015Speter sihardclose(pp); 89010015Speter 89110015Speter return(error); 89210015Speter} 89310015Speter 89412675Sjulianstatic int 89510015Spetersiclose(dev, flag, mode, p) 89610015Speter dev_t dev; 89710015Speter int flag, mode; 89810015Speter struct proc *p; 89910015Speter{ 90010015Speter register struct si_port *pp; 90110015Speter register struct tty *tp; 90210015Speter int oldspl; 90310015Speter int error = 0; 90410015Speter int mynor = minor(dev); 90510015Speter 90610015Speter if (IS_SPECIAL(mynor)) 90710015Speter return(0); 90810015Speter 90910015Speter oldspl = spltty(); 91010015Speter 91110015Speter pp = MINOR2PP(mynor); 91210015Speter tp = pp->sp_tty; 91310015Speter 91410015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 91510015Speter dev, flag, mode, p, pp->sp_state)); 91610015Speter 91710015Speter /* did we sleep and loose a race? */ 91810015Speter if (pp->sp_state & SS_CLOSING) { 91910015Speter /* error = ESOMETING? */ 92010015Speter goto out; 92110015Speter } 92210015Speter 92310015Speter /* begin race detection.. */ 92410015Speter pp->sp_state |= SS_CLOSING; 92510015Speter 92610015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 92710015Speter 92810015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 92910015Speter (*linesw[tp->t_line].l_close)(tp, flag); 93010015Speter 93110015Speter si_write_enable(pp, 1); 93210015Speter 93310015Speter /* did we sleep and somebody started another open? */ 93410015Speter if (!(pp->sp_state & SS_CLOSING)) { 93510015Speter /* error = ESOMETING? */ 93610015Speter goto out; 93710015Speter } 93810015Speter /* ok. we are now still on the right track.. nuke the hardware */ 93910015Speter 94010015Speter if (pp->sp_state & SS_LSTART) { 94110015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 94210015Speter pp->sp_state &= ~SS_LSTART; 94310015Speter } 94410015Speter 94510015Speter sistop(tp, FREAD | FWRITE); 94610015Speter 94710015Speter sihardclose(pp); 94810015Speter ttyclose(tp); 94910015Speter pp->sp_state &= ~SS_OPEN; 95010015Speter 95110015Speterout: 95210015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 95310015Speter splx(oldspl); 95410015Speter return(error); 95510015Speter} 95610015Speter 95710015Speterstatic void 95810015Spetersihardclose(pp) 95910015Speter struct si_port *pp; 96010015Speter{ 96110015Speter int oldspl; 96210015Speter struct tty *tp; 96310015Speter volatile struct si_channel *ccbp; 96410015Speter 96510015Speter oldspl = spltty(); 96610015Speter 96710015Speter tp = pp->sp_tty; 96810015Speter ccbp = pp->sp_ccb; /* Find control block */ 96910015Speter if (tp->t_cflag & HUPCL 97010015Speter || !pp->sp_active_out 97110015Speter && !(ccbp->hi_ip & IP_DCD) 97210015Speter && !(pp->sp_iin.c_cflag && CLOCAL) 97310015Speter || !(tp->t_state & TS_ISOPEN)) { 97410015Speter 97510015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 97610015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 97710015Speter 97810015Speter if (pp->sp_dtr_wait != 0) { 97910015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 98010015Speter pp->sp_state |= SS_DTR_OFF; 98110015Speter } 98210015Speter 98310015Speter } 98410015Speter pp->sp_active_out = FALSE; 98510015Speter wakeup((caddr_t)&pp->sp_active_out); 98610015Speter wakeup(TSA_CARR_ON(tp)); 98710015Speter 98810015Speter splx(oldspl); 98910015Speter} 99010015Speter 99110015Speter 99210015Speter/* 99310015Speter * called at splsoftclock()... 99410015Speter */ 99510015Speterstatic void 99610015Spetersidtrwakeup(chan) 99710015Speter void *chan; 99810015Speter{ 99910015Speter struct si_port *pp; 100010015Speter int oldspl; 100110015Speter 100210015Speter oldspl = spltty(); 100310015Speter 100410015Speter pp = (struct si_port *)chan; 100510015Speter pp->sp_state &= ~SS_DTR_OFF; 100610015Speter wakeup(&pp->sp_dtr_wait); 100710015Speter 100810015Speter splx(oldspl); 100910015Speter} 101010015Speter 101110015Speter/* 101210015Speter * User level stuff - read and write 101310015Speter */ 101412675Sjulianstatic int 101510015Spetersiread(dev, uio, flag) 101610015Speter register dev_t dev; 101710015Speter struct uio *uio; 101810015Speter int flag; 101910015Speter{ 102010015Speter register struct tty *tp; 102110015Speter int mynor = minor(dev); 102210015Speter 102310015Speter if (IS_SPECIAL(mynor)) { 102410015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 102510015Speter return(ENODEV); 102610015Speter } 102710015Speter tp = MINOR2TP(mynor); 102810015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 102910015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 103010015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 103110015Speter} 103210015Speter 103310015Speter 103412675Sjulianstatic int 103510015Spetersiwrite(dev, uio, flag) 103610015Speter dev_t dev; 103710015Speter struct uio *uio; 103810015Speter int flag; 103910015Speter{ 104010015Speter register struct si_port *pp; 104110015Speter register struct tty *tp; 104210015Speter int error = 0; 104310015Speter int mynor = minor(dev); 104410015Speter int oldspl; 104510015Speter 104610015Speter if (IS_SPECIAL(mynor)) { 104710015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 104810015Speter return(ENODEV); 104910015Speter } 105010015Speter pp = MINOR2PP(mynor); 105110015Speter tp = pp->sp_tty; 105210015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 105310015Speter 105410015Speter oldspl = spltty(); 105510015Speter /* 105610015Speter * If writes are currently blocked, wait on the "real" tty 105710015Speter */ 105810015Speter while (pp->sp_state & SS_BLOCKWRITE) { 105910015Speter pp->sp_state |= SS_WAITWRITE; 106010015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 106110015Speter if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 106210015Speter "siwrite", 0)) 106310015Speter goto out; 106410015Speter } 106510015Speter 106610015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 106710015Speterout: 106810015Speter splx(oldspl); 106910015Speter return (error); 107010015Speter} 107110015Speter 107210015Speter 107312675Sjulianstatic struct tty * 107410015Spetersidevtotty(dev_t dev) 107510015Speter{ 107610015Speter struct si_port *pp; 107710015Speter int mynor = minor(dev); 107810015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 107910015Speter 108010015Speter if (IS_SPECIAL(mynor)) 108110015Speter return(NULL); 108210015Speter if (SI_PORT(mynor) >= sc->sc_nport) 108310015Speter return(NULL); 108410015Speter pp = MINOR2PP(mynor); 108510015Speter return (pp->sp_tty); 108610015Speter} 108710015Speter 108812675Sjulianstatic int 108910015Spetersiioctl(dev, cmd, data, flag, p) 109010015Speter dev_t dev; 109110015Speter int cmd; 109210015Speter caddr_t data; 109310015Speter int flag; 109410015Speter struct proc *p; 109510015Speter{ 109610015Speter struct si_port *pp; 109710015Speter register struct tty *tp; 109810015Speter int error; 109910015Speter int mynor = minor(dev); 110010015Speter int oldspl; 110110015Speter int blocked = 0; 110210015Speter#if defined(COMPAT_43) 110310015Speter int oldcmd; 110410015Speter struct termios term; 110510015Speter#endif 110610015Speter 110710015Speter if (IS_SI_IOCTL(cmd)) 110810015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 110910015Speter 111010015Speter pp = MINOR2PP(mynor); 111110015Speter tp = pp->sp_tty; 111210015Speter 111310015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 111410015Speter dev, cmd, data, flag)); 111510015Speter if (IS_STATE(mynor)) { 111610015Speter struct termios *ct; 111710015Speter 111810015Speter switch (mynor & SI_STATE_MASK) { 111910015Speter case SI_INIT_STATE_MASK: 112010015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 112110015Speter break; 112210015Speter case SI_LOCK_STATE_MASK: 112316839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 112410015Speter break; 112510015Speter default: 112610015Speter return (ENODEV); 112710015Speter } 112810015Speter switch (cmd) { 112910015Speter case TIOCSETA: 113010015Speter error = suser(p->p_ucred, &p->p_acflag); 113110015Speter if (error != 0) 113210015Speter return (error); 113310015Speter *ct = *(struct termios *)data; 113410015Speter return (0); 113510015Speter case TIOCGETA: 113610015Speter *(struct termios *)data = *ct; 113710015Speter return (0); 113810015Speter case TIOCGETD: 113910015Speter *(int *)data = TTYDISC; 114010015Speter return (0); 114110015Speter case TIOCGWINSZ: 114210015Speter bzero(data, sizeof(struct winsize)); 114310015Speter return (0); 114410015Speter default: 114510015Speter return (ENOTTY); 114610015Speter } 114710015Speter } 114810015Speter /* 114910015Speter * Do the old-style ioctl compat routines... 115010015Speter */ 115110015Speter#if defined(COMPAT_43) 115210015Speter term = tp->t_termios; 115310015Speter oldcmd = cmd; 115410015Speter error = ttsetcompat(tp, &cmd, data, &term); 115510015Speter if (error != 0) 115610015Speter return (error); 115710015Speter if (cmd != oldcmd) 115810015Speter data = (caddr_t)&term; 115910015Speter#endif 116010015Speter /* 116110015Speter * Do the initial / lock state business 116210015Speter */ 116310015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 116410015Speter int cc; 116510015Speter struct termios *dt = (struct termios *)data; 116610015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 116710015Speter ? &pp->sp_lout : &pp->sp_lin; 116810015Speter 116910015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 117010015Speter | (dt->c_iflag & ~lt->c_iflag); 117110015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 117210015Speter | (dt->c_oflag & ~lt->c_oflag); 117310015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 117410015Speter | (dt->c_cflag & ~lt->c_cflag); 117510015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 117610015Speter | (dt->c_lflag & ~lt->c_lflag); 117710015Speter for (cc = 0; cc < NCCS; ++cc) 117810015Speter if (lt->c_cc[cc] != 0) 117910015Speter dt->c_cc[cc] = tp->t_cc[cc]; 118010015Speter if (lt->c_ispeed != 0) 118110015Speter dt->c_ispeed = tp->t_ispeed; 118210015Speter if (lt->c_ospeed != 0) 118310015Speter dt->c_ospeed = tp->t_ospeed; 118410015Speter } 118510015Speter 118610015Speter /* 118710015Speter * Block user-level writes to give the ttywait() 118810015Speter * a chance to completely drain for commands 118910015Speter * that require the port to be in a quiescent state. 119010015Speter */ 119110015Speter switch (cmd) { 119210015Speter case TIOCSETAW: case TIOCSETAF: 119310015Speter case TIOCDRAIN: case TIOCSETP: 119410015Speter blocked++; /* block writes for ttywait() and siparam() */ 119510015Speter si_write_enable(pp, 0); 119610015Speter } 119710015Speter 119810015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 119910015Speter if (error >= 0) 120010015Speter goto out; 120110015Speter 120210015Speter oldspl = spltty(); 120310015Speter 120410015Speter error = ttioctl(tp, cmd, data, flag); 120510015Speter si_disc_optim(tp, &tp->t_termios, pp); 120610015Speter if (error >= 0) 120710015Speter goto outspl; 120810015Speter 120910015Speter switch (cmd) { 121010015Speter case TIOCSBRK: 121116575Speter si_command(pp, SBREAK, SI_WAIT); 121210015Speter break; 121310015Speter case TIOCCBRK: 121416575Speter si_command(pp, EBREAK, SI_WAIT); 121510015Speter break; 121610015Speter case TIOCSDTR: 121710015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 121810015Speter break; 121910015Speter case TIOCCDTR: 122010015Speter (void) si_modem(pp, SET, 0); 122110015Speter break; 122210015Speter case TIOCMSET: 122310015Speter (void) si_modem(pp, SET, *(int *)data); 122410015Speter break; 122510015Speter case TIOCMBIS: 122610015Speter (void) si_modem(pp, BIS, *(int *)data); 122710015Speter break; 122810015Speter case TIOCMBIC: 122910015Speter (void) si_modem(pp, BIC, *(int *)data); 123010015Speter break; 123110015Speter case TIOCMGET: 123210015Speter *(int *)data = si_modem(pp, GET, 0); 123310015Speter break; 123410015Speter case TIOCMSDTRWAIT: 123510015Speter /* must be root since the wait applies to following logins */ 123610015Speter error = suser(p->p_ucred, &p->p_acflag); 123710015Speter if (error != 0) { 123810015Speter goto outspl; 123910015Speter } 124010015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 124110015Speter break; 124210015Speter case TIOCMGDTRWAIT: 124310015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 124410015Speter break; 124510015Speter 124610015Speter default: 124710015Speter error = ENOTTY; 124810015Speter } 124910015Speter error = 0; 125010015Speteroutspl: 125110015Speter splx(oldspl); 125210015Speterout: 125310015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 125410015Speter if (blocked) 125510015Speter si_write_enable(pp, 1); 125610015Speter return(error); 125710015Speter} 125810015Speter 125910015Speter/* 126010015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 126110015Speter */ 126210015Speterstatic int 126310015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 126410015Speter{ 126510015Speter struct si_softc *xsc; 126610015Speter register struct si_port *xpp; 126710015Speter volatile struct si_reg *regp; 126810015Speter struct si_tcsi *dp; 126910044Speter struct si_pstat *sps; 127011872Sphk int *ip, error = 0; 127110015Speter int oldspl; 127210015Speter int card, port; 127310015Speter int mynor = minor(dev); 127410015Speter 127510015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 127610015Speter dev, cmd, data, flag)); 127710015Speter 127810044Speter#if 1 127910044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 128010044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 128110044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 128210044Speter#endif 128310044Speter 128410015Speter if (!IS_CONTROLDEV(mynor)) { 128510015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 128610015Speter return(ENODEV); 128710015Speter } 128810015Speter 128910015Speter oldspl = spltty(); /* better safe than sorry */ 129010015Speter 129110015Speter ip = (int *)data; 129210015Speter 129310015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 129410015Speter 129510015Speter switch (cmd) { 129610015Speter case TCSIPORTS: 129710015Speter *ip = si_Nports; 129810015Speter goto out; 129910015Speter case TCSIMODULES: 130010015Speter *ip = si_Nmodules; 130110015Speter goto out; 130210015Speter case TCSISDBG_ALL: 130310015Speter SUCHECK; 130410015Speter si_debug = *ip; 130510015Speter goto out; 130610015Speter case TCSIGDBG_ALL: 130710015Speter *ip = si_debug; 130810015Speter goto out; 130910015Speter default: 131010015Speter /* 131110015Speter * Check that a controller for this port exists 131210015Speter */ 131310044Speter 131410044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 131510044Speter 131610015Speter dp = (struct si_tcsi *)data; 131710044Speter sps = (struct si_pstat *)data; 131810015Speter card = dp->tc_card; 131910015Speter xsc = &si_softc[card]; /* check.. */ 132012174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 132110015Speter error = ENOENT; 132210015Speter goto out; 132310015Speter } 132410015Speter /* 132510015Speter * And check that a port exists 132610015Speter */ 132710015Speter port = dp->tc_port; 132810015Speter if (port < 0 || port >= xsc->sc_nport) { 132910015Speter error = ENOENT; 133010015Speter goto out; 133110015Speter } 133210015Speter xpp = xsc->sc_ports + port; 133310015Speter regp = (struct si_reg *)xsc->sc_maddr; 133410015Speter } 133510015Speter 133610015Speter switch (cmd) { 133710015Speter case TCSIDEBUG: 133810015Speter#ifdef SI_DEBUG 133910015Speter SUCHECK; 134010015Speter if (xpp->sp_debug) 134110015Speter xpp->sp_debug = 0; 134210015Speter else { 134310015Speter xpp->sp_debug = DBG_ALL; 134410015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 134510015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 134610015Speter } 134710015Speter break; 134810015Speter#else 134910015Speter error = ENODEV; 135010015Speter goto out; 135110015Speter#endif 135210015Speter case TCSISDBG_LEVEL: 135310015Speter case TCSIGDBG_LEVEL: 135410015Speter#ifdef SI_DEBUG 135510015Speter if (cmd == TCSIGDBG_LEVEL) { 135610015Speter dp->tc_dbglvl = xpp->sp_debug; 135710015Speter } else { 135810015Speter SUCHECK; 135910015Speter xpp->sp_debug = dp->tc_dbglvl; 136010015Speter } 136110015Speter break; 136210015Speter#else 136310015Speter error = ENODEV; 136410015Speter goto out; 136510015Speter#endif 136610015Speter case TCSIGRXIT: 136710015Speter dp->tc_int = regp->rx_int_count; 136810015Speter break; 136910015Speter case TCSIRXIT: 137010015Speter SUCHECK; 137110015Speter regp->rx_int_count = dp->tc_int; 137210015Speter break; 137310015Speter case TCSIGIT: 137410015Speter dp->tc_int = regp->int_count; 137510015Speter break; 137610015Speter case TCSIIT: 137710015Speter SUCHECK; 137810015Speter regp->int_count = dp->tc_int; 137910015Speter break; 138010044Speter case TCSISTATE: 138110044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 138210015Speter break; 138310044Speter /* these next three use a different structure */ 138410044Speter case TCSI_PORT: 138510015Speter SUCHECK; 138616444Speter bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 138710015Speter break; 138810044Speter case TCSI_CCB: 138910044Speter SUCHECK; 139016444Speter bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 139110015Speter break; 139210044Speter case TCSI_TTY: 139310044Speter SUCHECK; 139416444Speter bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 139510015Speter break; 139610015Speter default: 139710015Speter error = EINVAL; 139810015Speter goto out; 139910015Speter } 140010015Speterout: 140110015Speter splx(oldspl); 140210015Speter return(error); /* success */ 140310015Speter} 140410015Speter 140510015Speter/* 140610015Speter * siparam() : Configure line params 140710015Speter * called at spltty(); 140810015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 140910015Speter * caller must arrange this if it's important.. 141010015Speter */ 141112724Sphkstatic int 141210015Spetersiparam(tp, t) 141310015Speter register struct tty *tp; 141410015Speter register struct termios *t; 141510015Speter{ 141610015Speter register struct si_port *pp = TP2PP(tp); 141710015Speter volatile struct si_channel *ccbp; 141810015Speter int oldspl, cflag, iflag, oflag, lflag; 141910015Speter int error = 0; /* shutup gcc */ 142010015Speter int ispeed = 0; /* shutup gcc */ 142110015Speter int ospeed = 0; /* shutup gcc */ 142210161Speter BYTE val; 142310015Speter 142410015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 142510015Speter cflag = t->c_cflag; 142610015Speter iflag = t->c_iflag; 142710015Speter oflag = t->c_oflag; 142810015Speter lflag = t->c_lflag; 142910044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 143010044Speter oflag, cflag, iflag, lflag)); 143110015Speter 143210015Speter 143310015Speter /* if not hung up.. */ 143410015Speter if (t->c_ospeed != 0) { 143510015Speter /* translate baud rate to firmware values */ 143610015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 143710015Speter ispeed = t->c_ispeed ? 143810015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 143910015Speter 144010015Speter /* enforce legit baud rate */ 144110015Speter if (ospeed < 0 || ispeed < 0) 144210015Speter return (EINVAL); 144310015Speter } 144410015Speter 144510015Speter 144610015Speter oldspl = spltty(); 144710015Speter 144810015Speter ccbp = pp->sp_ccb; 144910015Speter 145010161Speter /* ========== set hi_break ========== */ 145110161Speter val = 0; 145210161Speter if (iflag & IGNBRK) /* Breaks */ 145310161Speter val |= BR_IGN; 145410161Speter if (iflag & BRKINT) /* Interrupt on break? */ 145510161Speter val |= BR_INT; 145610161Speter if (iflag & PARMRK) /* Parity mark? */ 145710161Speter val |= BR_PARMRK; 145810161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 145910161Speter val |= BR_PARIGN; 146010161Speter ccbp->hi_break = val; 146110161Speter 146210161Speter /* ========== set hi_csr ========== */ 146310015Speter /* if not hung up.. */ 146410015Speter if (t->c_ospeed != 0) { 146510015Speter /* Set I/O speeds */ 146610161Speter val = (ispeed << 4) | ospeed; 146710015Speter } 146810161Speter ccbp->hi_csr = val; 146910015Speter 147010161Speter /* ========== set hi_mr2 ========== */ 147110161Speter val = 0; 147210015Speter if (cflag & CSTOPB) /* Stop bits */ 147310161Speter val |= MR2_2_STOP; 147410015Speter else 147510161Speter val |= MR2_1_STOP; 147610161Speter /* 147710161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 147810161Speter * a DCE, hence the reverse sense of RTS and CTS 147910161Speter */ 148010161Speter /* Output Flow - RTS must be raised before data can be sent */ 148110161Speter if (cflag & CCTS_OFLOW) 148210161Speter val |= MR2_RTSCONT; 148310161Speter 148416575Speter ccbp->hi_mr2 = val; 148510161Speter 148610161Speter /* ========== set hi_mr1 ========== */ 148710161Speter val = 0; 148810015Speter if (!(cflag & PARENB)) /* Parity */ 148910161Speter val |= MR1_NONE; 149010015Speter else 149110161Speter val |= MR1_WITH; 149210015Speter if (cflag & PARODD) 149310161Speter val |= MR1_ODD; 149410015Speter 149510015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 149610161Speter val |= MR1_8_BITS; 149710015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 149810161Speter val |= MR1_7_BITS; 149910015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 150010161Speter val |= MR1_6_BITS; 150110015Speter } else { /* Must be 5 */ 150210161Speter val |= MR1_5_BITS; 150310015Speter } 150410161Speter /* 150510161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 150610161Speter * a DCE, hence the reverse sense of RTS and CTS 150710161Speter */ 150810161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 150910161Speter if (cflag & CRTS_IFLOW) 151010161Speter val |= MR1_CTSCONT; 151110015Speter 151210161Speter ccbp->hi_mr1 = val; 151310161Speter 151410161Speter /* ========== set hi_mask ========== */ 151510161Speter val = 0xff; 151610161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 151710161Speter val &= 0xFF; 151810161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 151910161Speter val &= 0x7F; 152010161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 152110161Speter val &= 0x3F; 152210161Speter } else { /* Must be 5 */ 152310161Speter val &= 0x1F; 152410161Speter } 152510015Speter if (iflag & ISTRIP) 152610161Speter val &= 0x7F; 152710015Speter 152810161Speter ccbp->hi_mask = val; 152910161Speter 153010161Speter /* ========== set hi_prtcl ========== */ 153110161Speter val = 0; 153210015Speter /* Monitor DCD etc. if a modem */ 153310015Speter if (!(cflag & CLOCAL)) 153410161Speter val |= SP_DCEN; 153510161Speter if (iflag & IXANY) 153610161Speter val |= SP_TANY; 153710161Speter if (iflag & IXON) 153810161Speter val |= SP_TXEN; 153910161Speter if (iflag & IXOFF) 154010161Speter val |= SP_RXEN; 154110161Speter if (iflag & INPCK) 154210161Speter val |= SP_PAEN; 154310015Speter 154410161Speter ccbp->hi_prtcl = val; 154510161Speter 154610161Speter 154710161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 154810161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 154910015Speter ccbp->hi_txon = t->c_cc[VSTART]; 155010015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 155110015Speter 155210015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 155310015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 155410015Speter 155510161Speter /* ========== send settings to the card ========== */ 155610015Speter /* potential sleep here */ 155710015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 155810015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 155910015Speter else 156010015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 156110015Speter 156210161Speter /* ========== set DTR etc ========== */ 156310015Speter /* Hangup if ospeed == 0 */ 156410015Speter if (t->c_ospeed == 0) { 156510015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 156610015Speter } else { 156710015Speter /* 156810015Speter * If the previous speed was 0, may need to re-enable 156910015Speter * the modem signals 157010015Speter */ 157110015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 157210015Speter } 157310015Speter 157410044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 157510044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 157610015Speter 157710015Speter splx(oldspl); 157810015Speter return(error); 157910015Speter} 158010015Speter 158110015Speter/* 158210015Speter * Enable or Disable the writes to this channel... 158310015Speter * "state" -> enabled = 1; disabled = 0; 158410015Speter */ 158510015Speterstatic void 158610015Spetersi_write_enable(pp, state) 158710015Speter register struct si_port *pp; 158810015Speter int state; 158910015Speter{ 159010015Speter int oldspl; 159110015Speter 159210015Speter oldspl = spltty(); 159310015Speter 159410015Speter if (state) { 159510015Speter pp->sp_state &= ~SS_BLOCKWRITE; 159610015Speter if (pp->sp_state & SS_WAITWRITE) { 159710015Speter pp->sp_state &= ~SS_WAITWRITE; 159810015Speter /* thunder away! */ 159910015Speter wakeup((caddr_t)pp); 160010015Speter } 160110015Speter } else { 160210015Speter pp->sp_state |= SS_BLOCKWRITE; 160310015Speter } 160410015Speter 160510015Speter splx(oldspl); 160610015Speter} 160710015Speter 160810015Speter/* 160910015Speter * Set/Get state of modem control lines. 161010015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 161110015Speter * TIOCM_DTR DSR 161210015Speter * TIOCM_RTS CTS 161310015Speter */ 161410015Speterstatic int 161510015Spetersi_modem(pp, cmd, bits) 161610015Speter struct si_port *pp; 161710015Speter enum si_mctl cmd; 161810015Speter int bits; 161910015Speter{ 162010015Speter volatile struct si_channel *ccbp; 162110015Speter int x; 162210015Speter 162310015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 162410015Speter ccbp = pp->sp_ccb; /* Find channel address */ 162510015Speter switch (cmd) { 162610015Speter case GET: 162710015Speter x = ccbp->hi_ip; 162810015Speter bits = TIOCM_LE; 162910015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 163010015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 163110015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 163210015Speter if (x & IP_RI) bits |= TIOCM_RI; 163310015Speter return(bits); 163410015Speter case SET: 163510015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 163610015Speter /* fall through */ 163710015Speter case BIS: 163810015Speter x = 0; 163910015Speter if (bits & TIOCM_DTR) 164010015Speter x |= OP_DSR; 164110015Speter if (bits & TIOCM_RTS) 164210015Speter x |= OP_CTS; 164310015Speter ccbp->hi_op |= x; 164410015Speter break; 164510015Speter case BIC: 164610015Speter if (bits & TIOCM_DTR) 164710015Speter ccbp->hi_op &= ~OP_DSR; 164810015Speter if (bits & TIOCM_RTS) 164910015Speter ccbp->hi_op &= ~OP_CTS; 165010015Speter } 165110015Speter return 0; 165210015Speter} 165310015Speter 165410015Speter/* 165510015Speter * Handle change of modem state 165610015Speter */ 165710015Speterstatic void 165810015Spetersi_modem_state(pp, tp, hi_ip) 165910015Speter register struct si_port *pp; 166010015Speter register struct tty *tp; 166110015Speter register int hi_ip; 166210015Speter{ 166310015Speter /* if a modem dev */ 166410015Speter if (hi_ip & IP_DCD) { 166510015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 166610015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 166710015Speter tp->t_line)); 166810015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 166910015Speter } 167010015Speter } else { 167110015Speter if (pp->sp_last_hi_ip & IP_DCD) { 167210015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 167310015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 167410015Speter (void) si_modem(pp, SET, 0); 167510015Speter } 167610015Speter } 167710015Speter pp->sp_last_hi_ip = hi_ip; 167810015Speter 167910015Speter} 168010015Speter 168110015Speter/* 168210015Speter * Poller to catch missed interrupts. 168312174Speter * 168412496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 168512496Speter * better response. We could really use a "periodic" version timeout(). :-) 168610015Speter */ 168710015Speter#ifdef POLL 168810708Speterstatic void 168910015Spetersi_poll(void *nothing) 169010015Speter{ 169110015Speter register struct si_softc *sc; 169210015Speter register int i; 169310015Speter volatile struct si_reg *regp; 169412174Speter register struct si_port *pp; 169512174Speter int lost, oldspl, port; 169610015Speter 169710015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 169811609Speter oldspl = spltty(); 169910015Speter if (in_intr) 170010015Speter goto out; 170110015Speter lost = 0; 170210015Speter for (i=0; i<NSI; i++) { 170310015Speter sc = &si_softc[i]; 170412174Speter if (sc->sc_type == SIEMPTY) 170510015Speter continue; 170610015Speter regp = (struct si_reg *)sc->sc_maddr; 170710015Speter /* 170810015Speter * See if there has been a pending interrupt for 2 seconds 170910015Speter * or so. The test <int_scounter >= 200) won't correspond 171010015Speter * to 2 seconds if int_count gets changed. 171110015Speter */ 171210015Speter if (regp->int_pending != 0) { 171310015Speter if (regp->int_scounter >= 200 && 171410015Speter regp->initstat == 1) { 171512174Speter printf("si%d: lost intr\n", i); 171610015Speter lost++; 171710015Speter } 171810015Speter } else { 171910015Speter regp->int_scounter = 0; 172010015Speter } 172110015Speter 172212174Speter /* 172312174Speter * gripe about no input flow control.. 172412174Speter */ 172512174Speter pp = sc->sc_ports; 172612174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 172712174Speter if (pp->sp_delta_overflows > 0) { 172812174Speter printf("si%d: %d tty level buffer overflows\n", 172912174Speter i, pp->sp_delta_overflows); 173012174Speter pp->sp_delta_overflows = 0; 173112174Speter } 173212174Speter } 173310015Speter } 173410015Speter if (lost) 173510015Speter siintr(-1); /* call intr with fake vector */ 173611609Speterout: 173710015Speter splx(oldspl); 173810015Speter 173915639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 174010015Speter} 174110015Speter#endif /* ifdef POLL */ 174210015Speter 174310015Speter/* 174410015Speter * The interrupt handler polls ALL ports on ALL adapters each time 174510015Speter * it is called. 174610015Speter */ 174710015Speter 174812496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 174910015Speter 175010708Spetervoid 175111609Spetersiintr(int unit) 175210015Speter{ 175310015Speter register struct si_softc *sc; 175410015Speter 175510015Speter register struct si_port *pp; 175610015Speter volatile struct si_channel *ccbp; 175710015Speter register struct tty *tp; 175810015Speter volatile caddr_t maddr; 175911872Sphk BYTE op, ip; 176012174Speter int x, card, port, n, i, isopen; 176110015Speter volatile BYTE *z; 176210015Speter BYTE c; 176310015Speter 176411609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 176511609Speter if (in_intr) { 176611609Speter if (unit < 0) /* should never happen */ 176710708Speter return; 176812174Speter printf("si%d: Warning interrupt handler re-entered\n", 176911609Speter unit); 177010708Speter return; 177110015Speter } 177210015Speter in_intr = 1; 177310015Speter 177410015Speter /* 177510015Speter * When we get an int we poll all the channels and do ALL pending 177610015Speter * work, not just the first one we find. This allows all cards to 177710015Speter * share the same vector. 177810015Speter */ 177910015Speter for (card=0; card < NSI; card++) { 178010015Speter sc = &si_softc[card]; 178112174Speter if (sc->sc_type == SIEMPTY) 178210015Speter continue; 178312174Speter 178412174Speter /* 178512174Speter * First, clear the interrupt 178612174Speter */ 178710015Speter switch(sc->sc_type) { 178810015Speter case SIHOST : 178910015Speter maddr = sc->sc_maddr; 179010015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 179110015Speter /* flag nothing pending */ 179210015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 179310015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 179410015Speter break; 179510015Speter case SIHOST2: 179610015Speter maddr = sc->sc_maddr; 179710015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 179810015Speter *(maddr+SIPLIRQCLR) = 0x00; 179910015Speter *(maddr+SIPLIRQCLR) = 0x10; 180010015Speter break; 180110015Speter case SIEISA: 180210015Speter#if NEISA > 0 180310015Speter maddr = sc->sc_maddr; 180410015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180510015Speter (void)inb(sc->sc_eisa_iobase+3); 180610015Speter break; 180710015Speter#endif /* fall through if not EISA kernel */ 180810015Speter case SIEMPTY: 180910015Speter default: 181010015Speter continue; 181110015Speter } 181210015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 181310015Speter 181412174Speter /* 181512174Speter * check each port 181612174Speter */ 181712174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 181810015Speter ccbp = pp->sp_ccb; 181910015Speter tp = pp->sp_tty; 182010015Speter 182112174Speter 182210015Speter /* 182310015Speter * See if a command has completed ? 182410015Speter */ 182510015Speter if (ccbp->hi_stat != pp->sp_pend) { 182610015Speter DPRINT((pp, DBG_INTR, 182710015Speter "siintr hi_stat = 0x%x, pend = %d\n", 182810015Speter ccbp->hi_stat, pp->sp_pend)); 182910015Speter switch(pp->sp_pend) { 183010015Speter case LOPEN: 183110015Speter case MPEND: 183210015Speter case MOPEN: 183310015Speter case CONFIG: 183416575Speter case SBREAK: 183516575Speter case EBREAK: 183610015Speter pp->sp_pend = ccbp->hi_stat; 183710015Speter /* sleeping in si_command */ 183810015Speter wakeup(&pp->sp_state); 183910015Speter break; 184010015Speter default: 184110015Speter pp->sp_pend = ccbp->hi_stat; 184210015Speter } 184310015Speter } 184410015Speter 184510015Speter /* 184610015Speter * Continue on if it's closed 184710015Speter */ 184810015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 184910015Speter continue; 185010015Speter } 185110015Speter 185210015Speter /* 185310015Speter * Do modem state change if not a local device 185410015Speter */ 185510015Speter si_modem_state(pp, tp, ccbp->hi_ip); 185610015Speter 185710015Speter /* 185812174Speter * Check to see if there's we should 'receive' 185912174Speter * characters. 186012174Speter */ 186112174Speter if (tp->t_state & TS_CONNECTED && 186212174Speter tp->t_state & TS_ISOPEN) 186312174Speter isopen = 1; 186412174Speter else 186512174Speter isopen = 0; 186612174Speter 186712174Speter /* 186816575Speter * Do input break processing 186910015Speter */ 187010015Speter if (ccbp->hi_state & ST_BREAK) { 187112174Speter if (isopen) { 187212174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 187310015Speter } 187410015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 187510015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 187610015Speter } 187710015Speter 187810015Speter /* 187912174Speter * Do RX stuff - if not open then dump any characters. 188012174Speter * XXX: This is VERY messy and needs to be cleaned up. 188112174Speter * 188212174Speter * XXX: can we leave data in the host adapter buffer 188312174Speter * when the clists are full? That may be dangerous 188412174Speter * if the user cannot get an interrupt signal through. 188510015Speter */ 188610015Speter 188712174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 188812174Speter 188912174Speter if (!isopen) { 189010015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 189112174Speter goto end_rx; 189212174Speter } 189310015Speter 189412174Speter /* 189515640Speter * If the tty input buffers are blocked, stop emptying 189615640Speter * the incoming buffers and let the auto flow control 189715640Speter * assert.. 189815640Speter */ 189915640Speter if (tp->t_state & TS_TBLOCK) { 190015640Speter goto end_rx; 190115640Speter } 190215640Speter 190315640Speter /* 190412174Speter * Process read characters if not skipped above 190512174Speter */ 190615640Speter op = ccbp->hi_rxopos; 190715640Speter ip = ccbp->hi_rxipos; 190815640Speter c = ip - op; 190912174Speter if (c == 0) { 191012174Speter goto end_rx; 191112174Speter } 191210015Speter 191312174Speter n = c & 0xff; 191415640Speter if (n > 250) 191515640Speter n = 250; 191612174Speter 191712174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 191810015Speter n, op, ip)); 191910015Speter 192012174Speter /* 192112174Speter * Suck characters out of host card buffer into the 192212174Speter * "input staging buffer" - so that we dont leave the 192312174Speter * host card in limbo while we're possibly echoing 192412174Speter * characters and possibly flushing input inside the 192512174Speter * ldisc l_rint() routine. 192612174Speter */ 192712496Speter if (n <= SI_BUFFERSIZE - op) { 192810015Speter 192912174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 193012174Speter z = ccbp->hi_rxbuf + op; 193112174Speter bcopy((caddr_t)z, si_rxbuf, n); 193210015Speter 193312174Speter op += n; 193412174Speter } else { 193512496Speter x = SI_BUFFERSIZE - op; 193610015Speter 193712174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 193812174Speter z = ccbp->hi_rxbuf + op; 193912174Speter bcopy((caddr_t)z, si_rxbuf, x); 194010015Speter 194112174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 194212174Speter z = ccbp->hi_rxbuf; 194312174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 194410015Speter 194512174Speter op += n; 194612174Speter } 194710015Speter 194812174Speter /* clear collected characters from buffer */ 194912174Speter ccbp->hi_rxopos = op; 195012174Speter 195112174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 195210015Speter n, op, ip)); 195310015Speter 195412174Speter /* 195512174Speter * at this point... 195612174Speter * n = number of chars placed in si_rxbuf 195712174Speter */ 195810015Speter 195912174Speter /* 196012174Speter * Avoid the grotesquely inefficient lineswitch 196112174Speter * routine (ttyinput) in "raw" mode. It usually 196212174Speter * takes about 450 instructions (that's without 196312174Speter * canonical processing or echo!). slinput is 196412174Speter * reasonably fast (usually 40 instructions 196512174Speter * plus call overhead). 196612174Speter */ 196712174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 196810015Speter 196912174Speter /* block if the driver supports it */ 197012174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 197112174Speter && (tp->t_cflag & CRTS_IFLOW 197212174Speter || tp->t_iflag & IXOFF) 197312174Speter && !(tp->t_state & TS_TBLOCK)) 197412174Speter ttyblock(tp); 197510015Speter 197612174Speter tk_nin += n; 197712174Speter tk_rawcc += n; 197812174Speter tp->t_rawcc += n; 197912174Speter 198012174Speter pp->sp_delta_overflows += 198112174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 198212174Speter 198312174Speter ttwakeup(tp); 198412174Speter if (tp->t_state & TS_TTSTOP 198512174Speter && (tp->t_iflag & IXANY 198612174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 198712174Speter tp->t_state &= ~TS_TTSTOP; 198812174Speter tp->t_lflag &= ~FLUSHO; 198912174Speter si_start(tp); 199012174Speter } 199112174Speter } else { 199212174Speter /* 199312174Speter * It'd be nice to not have to go through the 199412174Speter * function call overhead for each char here. 199512174Speter * It'd be nice to block input it, saving a 199612174Speter * loop here and the call/return overhead. 199712174Speter */ 199812174Speter for(x = 0; x < n; x++) { 199912174Speter i = si_rxbuf[x]; 200012174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 200112174Speter == -1) { 200212174Speter pp->sp_delta_overflows++; 200310015Speter } 200412174Speter /* 200512174Speter * doesn't seem to be much point doing 200612174Speter * this here.. this driver has no 200712174Speter * softtty processing! ?? 200812174Speter */ 200912174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 201012174Speter setsofttty(); 201112174Speter } 201212174Speter } 201312174Speter } 201412174Speter goto more_rx; /* try for more until RXbuf is empty */ 201510015Speter 201612174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 201710015Speter 201810015Speter /* 201910015Speter * Do TX stuff 202010015Speter */ 202110015Speter (*linesw[tp->t_line].l_start)(tp); 202210015Speter 202310015Speter } /* end of for (all ports on this controller) */ 202410015Speter } /* end of for (all controllers) */ 202510015Speter 202611609Speter in_intr = 0; 202711609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 202810015Speter} 202910015Speter 203010015Speter/* 203110015Speter * Nudge the transmitter... 203212174Speter * 203312174Speter * XXX: I inherited some funny code here. It implies the host card only 203412174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 203512174Speter * not interrupt when it's actually hits empty. In some cases, we have 203612174Speter * processes waiting for complete drain, and we need to simulate an interrupt 203712174Speter * about when we think the buffer is going to be empty (and retry if not). 203812174Speter * I really am not certain about this... I *need* the hardware manuals. 203910015Speter */ 204010015Speterstatic void 204110015Spetersi_start(tp) 204210015Speter register struct tty *tp; 204310015Speter{ 204410015Speter struct si_port *pp; 204510015Speter volatile struct si_channel *ccbp; 204610015Speter register struct clist *qp; 204710015Speter register char *dptr; 204810015Speter BYTE ipos; 204910015Speter int nchar; 205010015Speter int oldspl, count, n, amount, buffer_full; 205110015Speter int do_exitproc; 205210015Speter 205310015Speter oldspl = spltty(); 205410015Speter 205510015Speter qp = &tp->t_outq; 205610015Speter pp = TP2PP(tp); 205710015Speter 205810015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 205910015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 206010015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 206110015Speter 206210015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 206310015Speter goto out; 206410015Speter 206510015Speter do_exitproc = 0; 206610015Speter buffer_full = 0; 206710015Speter ccbp = pp->sp_ccb; 206810015Speter 206910015Speter /* 207010015Speter * Handle the case where ttywait() is called on process exit 207110015Speter * this may be BSDI specific, I dont know... 207210015Speter */ 207310015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 207410015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 207510015Speter do_exitproc++; 207610015Speter } 207710015Speter 207810015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 207910015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 208010015Speter 208110015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 208210015Speter 208310015Speter while ((nchar = qp->c_cc) > 0) { 208410015Speter if ((BYTE)count >= 255) { 208510015Speter buffer_full++; 208610015Speter break; 208710015Speter } 208810015Speter amount = min(nchar, (255 - (BYTE)count)); 208910015Speter ipos = (unsigned int)ccbp->hi_txipos; 209010015Speter /* will it fit in one lump? */ 209112496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 209210015Speter n = q_to_b(&tp->t_outq, 209310015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 209410015Speter } else { 209510015Speter n = q_to_b(&tp->t_outq, 209610015Speter (char *)&ccbp->hi_txbuf[ipos], 209712496Speter SI_BUFFERSIZE-ipos); 209812496Speter if (n == SI_BUFFERSIZE-ipos) { 209910015Speter n += q_to_b(&tp->t_outq, 210010015Speter (char *)&ccbp->hi_txbuf[0], 210112496Speter amount - (SI_BUFFERSIZE-ipos)); 210210015Speter } 210310015Speter } 210410015Speter ccbp->hi_txipos += n; 210510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 210610015Speter } 210710015Speter 210810015Speter if (count != 0 && nchar == 0) { 210910015Speter tp->t_state |= TS_BUSY; 211010015Speter } else { 211110015Speter tp->t_state &= ~TS_BUSY; 211210015Speter } 211310015Speter 211410015Speter /* wakeup time? */ 211510015Speter ttwwakeup(tp); 211610015Speter 211710015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 211810015Speter (BYTE)count, nchar, tp->t_state)); 211910015Speter 212010015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 212110015Speter { 212210015Speter int time; 212310015Speter 212410015Speter if (do_exitproc != 0) { 212510015Speter time = hz / 10; 212610015Speter } else { 212710015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 212810015Speter 212910015Speter if (time > 0) { 213010015Speter if (time < nchar) 213110015Speter time = nchar / time; 213210015Speter else 213310015Speter time = 2; 213410015Speter } else { 213516024Speter DPRINT((pp, DBG_START, 213616024Speter "bad char time value! %d\n", time)); 213716024Speter time = hz/10; 213810015Speter } 213910015Speter } 214010015Speter 214110015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 214210015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 214310015Speter } else { 214410015Speter pp->sp_state |= SS_LSTART; 214510015Speter } 214610015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 214710015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 214810015Speter } 214910015Speter 215010015Speterout: 215110015Speter splx(oldspl); 215210015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 215310015Speter} 215410015Speter 215510015Speter/* 215610015Speter * Note: called at splsoftclock from the timeout code 215710015Speter * This has to deal with two things... cause wakeups while waiting for 215810015Speter * tty drains on last process exit, and call l_start at about the right 215910015Speter * time for protocols like ppp. 216010015Speter */ 216110015Speterstatic void 216210015Spetersi_lstart(pp) 216310015Speter register struct si_port *pp; 216410015Speter{ 216510015Speter register struct tty *tp; 216610015Speter int oldspl; 216710015Speter 216810015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 216910015Speter pp, pp->sp_state)); 217010015Speter 217110015Speter oldspl = spltty(); 217210015Speter 217310015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 217410015Speter splx(oldspl); 217510015Speter return; 217610015Speter } 217710015Speter pp->sp_state &= ~SS_LSTART; 217810015Speter pp->sp_state |= SS_INLSTART; 217910015Speter 218010015Speter tp = pp->sp_tty; 218110015Speter 218210015Speter /* deal with the process exit case */ 218310015Speter ttwwakeup(tp); 218410015Speter 218512174Speter /* nudge protocols - eg: ppp */ 218610015Speter (*linesw[tp->t_line].l_start)(tp); 218710015Speter 218810015Speter pp->sp_state &= ~SS_INLSTART; 218910015Speter splx(oldspl); 219010015Speter} 219110015Speter 219210015Speter/* 219310015Speter * Stop output on a line. called at spltty(); 219410015Speter */ 219510015Spetervoid 219610015Spetersistop(tp, rw) 219710015Speter register struct tty *tp; 219810015Speter int rw; 219910015Speter{ 220010015Speter volatile struct si_channel *ccbp; 220110015Speter struct si_port *pp; 220210015Speter 220310015Speter pp = TP2PP(tp); 220410015Speter ccbp = pp->sp_ccb; 220510015Speter 220610015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 220710015Speter 220810015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 220910015Speter if (rw & FWRITE) { 221010015Speter /* what level are we meant to be flushing anyway? */ 221110015Speter if (tp->t_state & TS_BUSY) { 221210015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 221310015Speter tp->t_state &= ~TS_BUSY; 221410015Speter ttwwakeup(tp); /* Bruce???? */ 221510015Speter } 221610015Speter } 221712174Speter#if 1 /* XXX: this doesn't work right yet.. */ 221812174Speter /* XXX: this may have been failing because we used to call l_rint() 221912174Speter * while we were looping based on these two counters. Now, we collect 222012174Speter * the data and then loop stuffing it into l_rint(), making this 222112174Speter * useless. Should we cause this to blow away the staging buffer? 222212174Speter */ 222310015Speter if (rw & FREAD) { 222410015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 222510015Speter } 222610015Speter#endif 222710015Speter} 222810015Speter 222910015Speter/* 223010015Speter * Issue a command to the Z280 host card CPU. 223110015Speter */ 223210015Speter 223310015Speterstatic void 223410015Spetersi_command(pp, cmd, waitflag) 223510015Speter struct si_port *pp; /* port control block (local) */ 223610015Speter int cmd; 223710015Speter int waitflag; 223810015Speter{ 223910015Speter int oldspl; 224010015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 224110015Speter int x; 224210015Speter 224310015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 224410015Speter pp, cmd, waitflag, ccbp->hi_stat)); 224510015Speter 224610015Speter oldspl = spltty(); /* Keep others out */ 224710015Speter 224810015Speter /* wait until it's finished what it was doing.. */ 224916575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 225016575Speter * is turned off. */ 225110015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 225210015Speter x != IDLE_CLOSE && 225316575Speter x != IDLE_BREAK && 225410015Speter x != cmd) { 225510015Speter if (in_intr) { /* Prevent sleep in intr */ 225610015Speter DPRINT((pp, DBG_PARAM, 225710015Speter "cmd intr collision - completing %d\trequested %d\n", 225810015Speter x, cmd)); 225910015Speter splx(oldspl); 226010015Speter return; 226110015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 226210015Speter "sicmd1", 1)) { 226310015Speter splx(oldspl); 226410015Speter return; 226510015Speter } 226610015Speter } 226716575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 226810015Speter 226910015Speter /* if there was a pending command, cause a state-change wakeup */ 227016575Speter switch(pp->sp_pend) { 227116575Speter case LOPEN: 227216575Speter case MPEND: 227316575Speter case MOPEN: 227416575Speter case CONFIG: 227516575Speter case SBREAK: 227616575Speter case EBREAK: 227716575Speter wakeup(&pp->sp_state); 227816575Speter break; 227916575Speter default: 228016575Speter break; 228110015Speter } 228210015Speter 228310015Speter pp->sp_pend = cmd; /* New command pending */ 228410015Speter ccbp->hi_stat = cmd; /* Post it */ 228510015Speter 228610015Speter if (waitflag) { 228710015Speter if (in_intr) { /* If in interrupt handler */ 228810015Speter DPRINT((pp, DBG_PARAM, 228910015Speter "attempt to sleep in si_intr - cmd req %d\n", 229010015Speter cmd)); 229110015Speter splx(oldspl); 229210015Speter return; 229316575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 229416575Speter ccbp->hi_stat != IDLE_BREAK) { 229510015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 229610015Speter "sicmd2", 0)) 229710015Speter break; 229810015Speter } 229910015Speter } 230010015Speter splx(oldspl); 230110015Speter} 230210015Speter 230310015Speterstatic void 230410015Spetersi_disc_optim(tp, t, pp) 230510015Speter struct tty *tp; 230610015Speter struct termios *t; 230710015Speter struct si_port *pp; 230810015Speter{ 230910015Speter /* 231010015Speter * XXX can skip a lot more cases if Smarts. Maybe 231110015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 231210015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 231310015Speter */ 231410015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 231510015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 231610015Speter && (!(t->c_iflag & PARMRK) 231710015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 231810015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 231910015Speter && linesw[tp->t_line].l_rint == ttyinput) 232010015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 232110015Speter else 232210015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 232310161Speter 232410015Speter /* 232510015Speter * Prepare to reduce input latency for packet 232610015Speter * discplines with a end of packet character. 232710015Speter */ 232810015Speter if (tp->t_line == SLIPDISC) 232910015Speter pp->sp_hotchar = 0xc0; 233010015Speter else if (tp->t_line == PPPDISC) 233110015Speter pp->sp_hotchar = 0x7e; 233210015Speter else 233310015Speter pp->sp_hotchar = 0; 233410161Speter 233510161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 233610161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 233710161Speter pp->sp_hotchar)); 233810015Speter} 233910015Speter 234010015Speter 234110015Speter#ifdef SI_DEBUG 234213353Speter 234310015Speterstatic void 234413353Speter#ifdef __STDC__ 234513353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 234613353Speter#else 234713353Spetersi_dprintf(pp, flags, fmt, va_alist) 234810015Speter struct si_port *pp; 234910015Speter int flags; 235013353Speter char *fmt; 235113353Speter#endif 235210015Speter{ 235313353Speter va_list ap; 235413630Sphk 235510015Speter if ((pp == NULL && (si_debug&flags)) || 235610015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 235710015Speter if (pp != NULL) 235812496Speter printf("%ci%d(%d): ", 's', 235912174Speter (int)SI_CARD(pp->sp_tty->t_dev), 236012174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 236113630Sphk va_start(ap, fmt); 236213630Sphk vprintf(fmt, ap); 236313353Speter va_end(ap); 236410015Speter } 236510015Speter} 236610015Speter 236710015Speterstatic char * 236810015Spetersi_mctl2str(cmd) 236910015Speter enum si_mctl cmd; 237010015Speter{ 237110015Speter switch (cmd) { 237210015Speter case GET: return("GET"); 237310015Speter case SET: return("SET"); 237410015Speter case BIS: return("BIS"); 237510015Speter case BIC: return("BIC"); 237610015Speter } 237710015Speter return("BAD"); 237810015Speter} 237912502Sjulian 238012624Speter#endif /* DEBUG */ 238112502Sjulian 238212624Speter 238312502Sjulian 238412502Sjulianstatic si_devsw_installed = 0; 238512502Sjulian 238612517Sjulianstatic void si_drvinit(void *unused) 238712502Sjulian{ 238812517Sjulian dev_t dev; 238912517Sjulian 239012502Sjulian if( ! si_devsw_installed ) { 239112675Sjulian dev = makedev(CDEV_MAJOR, 0); 239212675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 239312502Sjulian si_devsw_installed = 1; 239412517Sjulian } 239512502Sjulian} 239612517Sjulian 239712517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 239812517Sjulian 2399