si.c revision 17290
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 * 3317290Speter * $Id: si.c,v 1.47 1996/06/30 04:56:05 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, 106217290Speter "siwrite", tp->t_timeout)) { 106317290Speter if (error == ETIMEDOUT) 106417290Speter error = EIO; 106510015Speter goto out; 106617290Speter } 106710015Speter } 106810015Speter 106910015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 107010015Speterout: 107110015Speter splx(oldspl); 107210015Speter return (error); 107310015Speter} 107410015Speter 107510015Speter 107612675Sjulianstatic struct tty * 107710015Spetersidevtotty(dev_t dev) 107810015Speter{ 107910015Speter struct si_port *pp; 108010015Speter int mynor = minor(dev); 108110015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 108210015Speter 108310015Speter if (IS_SPECIAL(mynor)) 108410015Speter return(NULL); 108510015Speter if (SI_PORT(mynor) >= sc->sc_nport) 108610015Speter return(NULL); 108710015Speter pp = MINOR2PP(mynor); 108810015Speter return (pp->sp_tty); 108910015Speter} 109010015Speter 109112675Sjulianstatic int 109210015Spetersiioctl(dev, cmd, data, flag, p) 109310015Speter dev_t dev; 109410015Speter int cmd; 109510015Speter caddr_t data; 109610015Speter int flag; 109710015Speter struct proc *p; 109810015Speter{ 109910015Speter struct si_port *pp; 110010015Speter register struct tty *tp; 110110015Speter int error; 110210015Speter int mynor = minor(dev); 110310015Speter int oldspl; 110410015Speter int blocked = 0; 110510015Speter#if defined(COMPAT_43) 110610015Speter int oldcmd; 110710015Speter struct termios term; 110810015Speter#endif 110910015Speter 111010015Speter if (IS_SI_IOCTL(cmd)) 111110015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 111210015Speter 111310015Speter pp = MINOR2PP(mynor); 111410015Speter tp = pp->sp_tty; 111510015Speter 111610015Speter DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 111710015Speter dev, cmd, data, flag)); 111810015Speter if (IS_STATE(mynor)) { 111910015Speter struct termios *ct; 112010015Speter 112110015Speter switch (mynor & SI_STATE_MASK) { 112210015Speter case SI_INIT_STATE_MASK: 112310015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 112410015Speter break; 112510015Speter case SI_LOCK_STATE_MASK: 112616839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 112710015Speter break; 112810015Speter default: 112910015Speter return (ENODEV); 113010015Speter } 113110015Speter switch (cmd) { 113210015Speter case TIOCSETA: 113310015Speter error = suser(p->p_ucred, &p->p_acflag); 113410015Speter if (error != 0) 113510015Speter return (error); 113610015Speter *ct = *(struct termios *)data; 113710015Speter return (0); 113810015Speter case TIOCGETA: 113910015Speter *(struct termios *)data = *ct; 114010015Speter return (0); 114110015Speter case TIOCGETD: 114210015Speter *(int *)data = TTYDISC; 114310015Speter return (0); 114410015Speter case TIOCGWINSZ: 114510015Speter bzero(data, sizeof(struct winsize)); 114610015Speter return (0); 114710015Speter default: 114810015Speter return (ENOTTY); 114910015Speter } 115010015Speter } 115110015Speter /* 115210015Speter * Do the old-style ioctl compat routines... 115310015Speter */ 115410015Speter#if defined(COMPAT_43) 115510015Speter term = tp->t_termios; 115610015Speter oldcmd = cmd; 115710015Speter error = ttsetcompat(tp, &cmd, data, &term); 115810015Speter if (error != 0) 115910015Speter return (error); 116010015Speter if (cmd != oldcmd) 116110015Speter data = (caddr_t)&term; 116210015Speter#endif 116310015Speter /* 116410015Speter * Do the initial / lock state business 116510015Speter */ 116610015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 116710015Speter int cc; 116810015Speter struct termios *dt = (struct termios *)data; 116910015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 117010015Speter ? &pp->sp_lout : &pp->sp_lin; 117110015Speter 117210015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 117310015Speter | (dt->c_iflag & ~lt->c_iflag); 117410015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 117510015Speter | (dt->c_oflag & ~lt->c_oflag); 117610015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 117710015Speter | (dt->c_cflag & ~lt->c_cflag); 117810015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 117910015Speter | (dt->c_lflag & ~lt->c_lflag); 118010015Speter for (cc = 0; cc < NCCS; ++cc) 118110015Speter if (lt->c_cc[cc] != 0) 118210015Speter dt->c_cc[cc] = tp->t_cc[cc]; 118310015Speter if (lt->c_ispeed != 0) 118410015Speter dt->c_ispeed = tp->t_ispeed; 118510015Speter if (lt->c_ospeed != 0) 118610015Speter dt->c_ospeed = tp->t_ospeed; 118710015Speter } 118810015Speter 118910015Speter /* 119010015Speter * Block user-level writes to give the ttywait() 119110015Speter * a chance to completely drain for commands 119210015Speter * that require the port to be in a quiescent state. 119310015Speter */ 119410015Speter switch (cmd) { 119510015Speter case TIOCSETAW: case TIOCSETAF: 119610015Speter case TIOCDRAIN: case TIOCSETP: 119710015Speter blocked++; /* block writes for ttywait() and siparam() */ 119810015Speter si_write_enable(pp, 0); 119910015Speter } 120010015Speter 120110015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 120210015Speter if (error >= 0) 120310015Speter goto out; 120410015Speter 120510015Speter oldspl = spltty(); 120610015Speter 120710015Speter error = ttioctl(tp, cmd, data, flag); 120810015Speter si_disc_optim(tp, &tp->t_termios, pp); 120910015Speter if (error >= 0) 121010015Speter goto outspl; 121110015Speter 121210015Speter switch (cmd) { 121310015Speter case TIOCSBRK: 121416575Speter si_command(pp, SBREAK, SI_WAIT); 121510015Speter break; 121610015Speter case TIOCCBRK: 121716575Speter si_command(pp, EBREAK, SI_WAIT); 121810015Speter break; 121910015Speter case TIOCSDTR: 122010015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 122110015Speter break; 122210015Speter case TIOCCDTR: 122310015Speter (void) si_modem(pp, SET, 0); 122410015Speter break; 122510015Speter case TIOCMSET: 122610015Speter (void) si_modem(pp, SET, *(int *)data); 122710015Speter break; 122810015Speter case TIOCMBIS: 122910015Speter (void) si_modem(pp, BIS, *(int *)data); 123010015Speter break; 123110015Speter case TIOCMBIC: 123210015Speter (void) si_modem(pp, BIC, *(int *)data); 123310015Speter break; 123410015Speter case TIOCMGET: 123510015Speter *(int *)data = si_modem(pp, GET, 0); 123610015Speter break; 123710015Speter case TIOCMSDTRWAIT: 123810015Speter /* must be root since the wait applies to following logins */ 123910015Speter error = suser(p->p_ucred, &p->p_acflag); 124010015Speter if (error != 0) { 124110015Speter goto outspl; 124210015Speter } 124310015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 124410015Speter break; 124510015Speter case TIOCMGDTRWAIT: 124610015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 124710015Speter break; 124810015Speter 124910015Speter default: 125010015Speter error = ENOTTY; 125110015Speter } 125210015Speter error = 0; 125310015Speteroutspl: 125410015Speter splx(oldspl); 125510015Speterout: 125610015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 125710015Speter if (blocked) 125810015Speter si_write_enable(pp, 1); 125910015Speter return(error); 126010015Speter} 126110015Speter 126210015Speter/* 126310015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 126410015Speter */ 126510015Speterstatic int 126610015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 126710015Speter{ 126810015Speter struct si_softc *xsc; 126910015Speter register struct si_port *xpp; 127010015Speter volatile struct si_reg *regp; 127110015Speter struct si_tcsi *dp; 127210044Speter struct si_pstat *sps; 127311872Sphk int *ip, error = 0; 127410015Speter int oldspl; 127510015Speter int card, port; 127610015Speter int mynor = minor(dev); 127710015Speter 127810015Speter DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 127910015Speter dev, cmd, data, flag)); 128010015Speter 128110044Speter#if 1 128210044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 128310044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 128410044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 128510044Speter#endif 128610044Speter 128710015Speter if (!IS_CONTROLDEV(mynor)) { 128810015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 128910015Speter return(ENODEV); 129010015Speter } 129110015Speter 129210015Speter oldspl = spltty(); /* better safe than sorry */ 129310015Speter 129410015Speter ip = (int *)data; 129510015Speter 129610015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 129710015Speter 129810015Speter switch (cmd) { 129910015Speter case TCSIPORTS: 130010015Speter *ip = si_Nports; 130110015Speter goto out; 130210015Speter case TCSIMODULES: 130310015Speter *ip = si_Nmodules; 130410015Speter goto out; 130510015Speter case TCSISDBG_ALL: 130610015Speter SUCHECK; 130710015Speter si_debug = *ip; 130810015Speter goto out; 130910015Speter case TCSIGDBG_ALL: 131010015Speter *ip = si_debug; 131110015Speter goto out; 131210015Speter default: 131310015Speter /* 131410015Speter * Check that a controller for this port exists 131510015Speter */ 131610044Speter 131710044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 131810044Speter 131910015Speter dp = (struct si_tcsi *)data; 132010044Speter sps = (struct si_pstat *)data; 132110015Speter card = dp->tc_card; 132210015Speter xsc = &si_softc[card]; /* check.. */ 132312174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 132410015Speter error = ENOENT; 132510015Speter goto out; 132610015Speter } 132710015Speter /* 132810015Speter * And check that a port exists 132910015Speter */ 133010015Speter port = dp->tc_port; 133110015Speter if (port < 0 || port >= xsc->sc_nport) { 133210015Speter error = ENOENT; 133310015Speter goto out; 133410015Speter } 133510015Speter xpp = xsc->sc_ports + port; 133610015Speter regp = (struct si_reg *)xsc->sc_maddr; 133710015Speter } 133810015Speter 133910015Speter switch (cmd) { 134010015Speter case TCSIDEBUG: 134110015Speter#ifdef SI_DEBUG 134210015Speter SUCHECK; 134310015Speter if (xpp->sp_debug) 134410015Speter xpp->sp_debug = 0; 134510015Speter else { 134610015Speter xpp->sp_debug = DBG_ALL; 134710015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 134810015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 134910015Speter } 135010015Speter break; 135110015Speter#else 135210015Speter error = ENODEV; 135310015Speter goto out; 135410015Speter#endif 135510015Speter case TCSISDBG_LEVEL: 135610015Speter case TCSIGDBG_LEVEL: 135710015Speter#ifdef SI_DEBUG 135810015Speter if (cmd == TCSIGDBG_LEVEL) { 135910015Speter dp->tc_dbglvl = xpp->sp_debug; 136010015Speter } else { 136110015Speter SUCHECK; 136210015Speter xpp->sp_debug = dp->tc_dbglvl; 136310015Speter } 136410015Speter break; 136510015Speter#else 136610015Speter error = ENODEV; 136710015Speter goto out; 136810015Speter#endif 136910015Speter case TCSIGRXIT: 137010015Speter dp->tc_int = regp->rx_int_count; 137110015Speter break; 137210015Speter case TCSIRXIT: 137310015Speter SUCHECK; 137410015Speter regp->rx_int_count = dp->tc_int; 137510015Speter break; 137610015Speter case TCSIGIT: 137710015Speter dp->tc_int = regp->int_count; 137810015Speter break; 137910015Speter case TCSIIT: 138010015Speter SUCHECK; 138110015Speter regp->int_count = dp->tc_int; 138210015Speter break; 138310044Speter case TCSISTATE: 138410044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 138510015Speter break; 138610044Speter /* these next three use a different structure */ 138710044Speter case TCSI_PORT: 138810015Speter SUCHECK; 138916444Speter bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 139010015Speter break; 139110044Speter case TCSI_CCB: 139210044Speter SUCHECK; 139316444Speter bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 139410015Speter break; 139510044Speter case TCSI_TTY: 139610044Speter SUCHECK; 139716444Speter bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 139810015Speter break; 139910015Speter default: 140010015Speter error = EINVAL; 140110015Speter goto out; 140210015Speter } 140310015Speterout: 140410015Speter splx(oldspl); 140510015Speter return(error); /* success */ 140610015Speter} 140710015Speter 140810015Speter/* 140910015Speter * siparam() : Configure line params 141010015Speter * called at spltty(); 141110015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 141210015Speter * caller must arrange this if it's important.. 141310015Speter */ 141412724Sphkstatic int 141510015Spetersiparam(tp, t) 141610015Speter register struct tty *tp; 141710015Speter register struct termios *t; 141810015Speter{ 141910015Speter register struct si_port *pp = TP2PP(tp); 142010015Speter volatile struct si_channel *ccbp; 142110015Speter int oldspl, cflag, iflag, oflag, lflag; 142210015Speter int error = 0; /* shutup gcc */ 142310015Speter int ispeed = 0; /* shutup gcc */ 142410015Speter int ospeed = 0; /* shutup gcc */ 142510161Speter BYTE val; 142610015Speter 142710015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 142810015Speter cflag = t->c_cflag; 142910015Speter iflag = t->c_iflag; 143010015Speter oflag = t->c_oflag; 143110015Speter lflag = t->c_lflag; 143210044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 143310044Speter oflag, cflag, iflag, lflag)); 143410015Speter 143510015Speter 143610015Speter /* if not hung up.. */ 143710015Speter if (t->c_ospeed != 0) { 143810015Speter /* translate baud rate to firmware values */ 143910015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 144010015Speter ispeed = t->c_ispeed ? 144110015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 144210015Speter 144310015Speter /* enforce legit baud rate */ 144410015Speter if (ospeed < 0 || ispeed < 0) 144510015Speter return (EINVAL); 144610015Speter } 144710015Speter 144810015Speter 144910015Speter oldspl = spltty(); 145010015Speter 145110015Speter ccbp = pp->sp_ccb; 145210015Speter 145310161Speter /* ========== set hi_break ========== */ 145410161Speter val = 0; 145510161Speter if (iflag & IGNBRK) /* Breaks */ 145610161Speter val |= BR_IGN; 145710161Speter if (iflag & BRKINT) /* Interrupt on break? */ 145810161Speter val |= BR_INT; 145910161Speter if (iflag & PARMRK) /* Parity mark? */ 146010161Speter val |= BR_PARMRK; 146110161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 146210161Speter val |= BR_PARIGN; 146310161Speter ccbp->hi_break = val; 146410161Speter 146510161Speter /* ========== set hi_csr ========== */ 146610015Speter /* if not hung up.. */ 146710015Speter if (t->c_ospeed != 0) { 146810015Speter /* Set I/O speeds */ 146910161Speter val = (ispeed << 4) | ospeed; 147010015Speter } 147110161Speter ccbp->hi_csr = val; 147210015Speter 147310161Speter /* ========== set hi_mr2 ========== */ 147410161Speter val = 0; 147510015Speter if (cflag & CSTOPB) /* Stop bits */ 147610161Speter val |= MR2_2_STOP; 147710015Speter else 147810161Speter val |= MR2_1_STOP; 147910161Speter /* 148010161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 148110161Speter * a DCE, hence the reverse sense of RTS and CTS 148210161Speter */ 148310161Speter /* Output Flow - RTS must be raised before data can be sent */ 148410161Speter if (cflag & CCTS_OFLOW) 148510161Speter val |= MR2_RTSCONT; 148610161Speter 148716575Speter ccbp->hi_mr2 = val; 148810161Speter 148910161Speter /* ========== set hi_mr1 ========== */ 149010161Speter val = 0; 149110015Speter if (!(cflag & PARENB)) /* Parity */ 149210161Speter val |= MR1_NONE; 149310015Speter else 149410161Speter val |= MR1_WITH; 149510015Speter if (cflag & PARODD) 149610161Speter val |= MR1_ODD; 149710015Speter 149810015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 149910161Speter val |= MR1_8_BITS; 150010015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 150110161Speter val |= MR1_7_BITS; 150210015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 150310161Speter val |= MR1_6_BITS; 150410015Speter } else { /* Must be 5 */ 150510161Speter val |= MR1_5_BITS; 150610015Speter } 150710161Speter /* 150810161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 150910161Speter * a DCE, hence the reverse sense of RTS and CTS 151010161Speter */ 151110161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 151210161Speter if (cflag & CRTS_IFLOW) 151310161Speter val |= MR1_CTSCONT; 151410015Speter 151510161Speter ccbp->hi_mr1 = val; 151610161Speter 151710161Speter /* ========== set hi_mask ========== */ 151810161Speter val = 0xff; 151910161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 152010161Speter val &= 0xFF; 152110161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 152210161Speter val &= 0x7F; 152310161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 152410161Speter val &= 0x3F; 152510161Speter } else { /* Must be 5 */ 152610161Speter val &= 0x1F; 152710161Speter } 152810015Speter if (iflag & ISTRIP) 152910161Speter val &= 0x7F; 153010015Speter 153110161Speter ccbp->hi_mask = val; 153210161Speter 153310161Speter /* ========== set hi_prtcl ========== */ 153410161Speter val = 0; 153510015Speter /* Monitor DCD etc. if a modem */ 153610015Speter if (!(cflag & CLOCAL)) 153710161Speter val |= SP_DCEN; 153810161Speter if (iflag & IXANY) 153910161Speter val |= SP_TANY; 154010161Speter if (iflag & IXON) 154110161Speter val |= SP_TXEN; 154210161Speter if (iflag & IXOFF) 154310161Speter val |= SP_RXEN; 154410161Speter if (iflag & INPCK) 154510161Speter val |= SP_PAEN; 154610015Speter 154710161Speter ccbp->hi_prtcl = val; 154810161Speter 154910161Speter 155010161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 155110161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 155210015Speter ccbp->hi_txon = t->c_cc[VSTART]; 155310015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 155410015Speter 155510015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 155610015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 155710015Speter 155810161Speter /* ========== send settings to the card ========== */ 155910015Speter /* potential sleep here */ 156010015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 156110015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 156210015Speter else 156310015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 156410015Speter 156510161Speter /* ========== set DTR etc ========== */ 156610015Speter /* Hangup if ospeed == 0 */ 156710015Speter if (t->c_ospeed == 0) { 156810015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 156910015Speter } else { 157010015Speter /* 157110015Speter * If the previous speed was 0, may need to re-enable 157210015Speter * the modem signals 157310015Speter */ 157410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 157510015Speter } 157610015Speter 157710044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 157810044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 157910015Speter 158010015Speter splx(oldspl); 158110015Speter return(error); 158210015Speter} 158310015Speter 158410015Speter/* 158510015Speter * Enable or Disable the writes to this channel... 158610015Speter * "state" -> enabled = 1; disabled = 0; 158710015Speter */ 158810015Speterstatic void 158910015Spetersi_write_enable(pp, state) 159010015Speter register struct si_port *pp; 159110015Speter int state; 159210015Speter{ 159310015Speter int oldspl; 159410015Speter 159510015Speter oldspl = spltty(); 159610015Speter 159710015Speter if (state) { 159810015Speter pp->sp_state &= ~SS_BLOCKWRITE; 159910015Speter if (pp->sp_state & SS_WAITWRITE) { 160010015Speter pp->sp_state &= ~SS_WAITWRITE; 160110015Speter /* thunder away! */ 160210015Speter wakeup((caddr_t)pp); 160310015Speter } 160410015Speter } else { 160510015Speter pp->sp_state |= SS_BLOCKWRITE; 160610015Speter } 160710015Speter 160810015Speter splx(oldspl); 160910015Speter} 161010015Speter 161110015Speter/* 161210015Speter * Set/Get state of modem control lines. 161310015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 161410015Speter * TIOCM_DTR DSR 161510015Speter * TIOCM_RTS CTS 161610015Speter */ 161710015Speterstatic int 161810015Spetersi_modem(pp, cmd, bits) 161910015Speter struct si_port *pp; 162010015Speter enum si_mctl cmd; 162110015Speter int bits; 162210015Speter{ 162310015Speter volatile struct si_channel *ccbp; 162410015Speter int x; 162510015Speter 162610015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 162710015Speter ccbp = pp->sp_ccb; /* Find channel address */ 162810015Speter switch (cmd) { 162910015Speter case GET: 163010015Speter x = ccbp->hi_ip; 163110015Speter bits = TIOCM_LE; 163210015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 163310015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 163410015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 163510015Speter if (x & IP_RI) bits |= TIOCM_RI; 163610015Speter return(bits); 163710015Speter case SET: 163810015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 163910015Speter /* fall through */ 164010015Speter case BIS: 164110015Speter x = 0; 164210015Speter if (bits & TIOCM_DTR) 164310015Speter x |= OP_DSR; 164410015Speter if (bits & TIOCM_RTS) 164510015Speter x |= OP_CTS; 164610015Speter ccbp->hi_op |= x; 164710015Speter break; 164810015Speter case BIC: 164910015Speter if (bits & TIOCM_DTR) 165010015Speter ccbp->hi_op &= ~OP_DSR; 165110015Speter if (bits & TIOCM_RTS) 165210015Speter ccbp->hi_op &= ~OP_CTS; 165310015Speter } 165410015Speter return 0; 165510015Speter} 165610015Speter 165710015Speter/* 165810015Speter * Handle change of modem state 165910015Speter */ 166010015Speterstatic void 166110015Spetersi_modem_state(pp, tp, hi_ip) 166210015Speter register struct si_port *pp; 166310015Speter register struct tty *tp; 166410015Speter register int hi_ip; 166510015Speter{ 166610015Speter /* if a modem dev */ 166710015Speter if (hi_ip & IP_DCD) { 166810015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 166910015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 167010015Speter tp->t_line)); 167110015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 167210015Speter } 167310015Speter } else { 167410015Speter if (pp->sp_last_hi_ip & IP_DCD) { 167510015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 167610015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 167710015Speter (void) si_modem(pp, SET, 0); 167810015Speter } 167910015Speter } 168010015Speter pp->sp_last_hi_ip = hi_ip; 168110015Speter 168210015Speter} 168310015Speter 168410015Speter/* 168510015Speter * Poller to catch missed interrupts. 168612174Speter * 168712496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 168812496Speter * better response. We could really use a "periodic" version timeout(). :-) 168910015Speter */ 169010015Speter#ifdef POLL 169110708Speterstatic void 169210015Spetersi_poll(void *nothing) 169310015Speter{ 169410015Speter register struct si_softc *sc; 169510015Speter register int i; 169610015Speter volatile struct si_reg *regp; 169712174Speter register struct si_port *pp; 169812174Speter int lost, oldspl, port; 169910015Speter 170010015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 170111609Speter oldspl = spltty(); 170210015Speter if (in_intr) 170310015Speter goto out; 170410015Speter lost = 0; 170510015Speter for (i=0; i<NSI; i++) { 170610015Speter sc = &si_softc[i]; 170712174Speter if (sc->sc_type == SIEMPTY) 170810015Speter continue; 170910015Speter regp = (struct si_reg *)sc->sc_maddr; 171010015Speter /* 171110015Speter * See if there has been a pending interrupt for 2 seconds 171210015Speter * or so. The test <int_scounter >= 200) won't correspond 171310015Speter * to 2 seconds if int_count gets changed. 171410015Speter */ 171510015Speter if (regp->int_pending != 0) { 171610015Speter if (regp->int_scounter >= 200 && 171710015Speter regp->initstat == 1) { 171812174Speter printf("si%d: lost intr\n", i); 171910015Speter lost++; 172010015Speter } 172110015Speter } else { 172210015Speter regp->int_scounter = 0; 172310015Speter } 172410015Speter 172512174Speter /* 172612174Speter * gripe about no input flow control.. 172712174Speter */ 172812174Speter pp = sc->sc_ports; 172912174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 173012174Speter if (pp->sp_delta_overflows > 0) { 173112174Speter printf("si%d: %d tty level buffer overflows\n", 173212174Speter i, pp->sp_delta_overflows); 173312174Speter pp->sp_delta_overflows = 0; 173412174Speter } 173512174Speter } 173610015Speter } 173710015Speter if (lost) 173810015Speter siintr(-1); /* call intr with fake vector */ 173911609Speterout: 174010015Speter splx(oldspl); 174110015Speter 174215639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 174310015Speter} 174410015Speter#endif /* ifdef POLL */ 174510015Speter 174610015Speter/* 174710015Speter * The interrupt handler polls ALL ports on ALL adapters each time 174810015Speter * it is called. 174910015Speter */ 175010015Speter 175112496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 175210015Speter 175310708Spetervoid 175411609Spetersiintr(int unit) 175510015Speter{ 175610015Speter register struct si_softc *sc; 175710015Speter 175810015Speter register struct si_port *pp; 175910015Speter volatile struct si_channel *ccbp; 176010015Speter register struct tty *tp; 176110015Speter volatile caddr_t maddr; 176211872Sphk BYTE op, ip; 176312174Speter int x, card, port, n, i, isopen; 176410015Speter volatile BYTE *z; 176510015Speter BYTE c; 176610015Speter 176711609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 176811609Speter if (in_intr) { 176911609Speter if (unit < 0) /* should never happen */ 177010708Speter return; 177112174Speter printf("si%d: Warning interrupt handler re-entered\n", 177211609Speter unit); 177310708Speter return; 177410015Speter } 177510015Speter in_intr = 1; 177610015Speter 177710015Speter /* 177810015Speter * When we get an int we poll all the channels and do ALL pending 177910015Speter * work, not just the first one we find. This allows all cards to 178010015Speter * share the same vector. 178110015Speter */ 178210015Speter for (card=0; card < NSI; card++) { 178310015Speter sc = &si_softc[card]; 178412174Speter if (sc->sc_type == SIEMPTY) 178510015Speter continue; 178612174Speter 178712174Speter /* 178812174Speter * First, clear the interrupt 178912174Speter */ 179010015Speter switch(sc->sc_type) { 179110015Speter case SIHOST : 179210015Speter maddr = sc->sc_maddr; 179310015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 179410015Speter /* flag nothing pending */ 179510015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 179610015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 179710015Speter break; 179810015Speter case SIHOST2: 179910015Speter maddr = sc->sc_maddr; 180010015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180110015Speter *(maddr+SIPLIRQCLR) = 0x00; 180210015Speter *(maddr+SIPLIRQCLR) = 0x10; 180310015Speter break; 180410015Speter case SIEISA: 180510015Speter#if NEISA > 0 180610015Speter maddr = sc->sc_maddr; 180710015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 180810015Speter (void)inb(sc->sc_eisa_iobase+3); 180910015Speter break; 181010015Speter#endif /* fall through if not EISA kernel */ 181110015Speter case SIEMPTY: 181210015Speter default: 181310015Speter continue; 181410015Speter } 181510015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 181610015Speter 181712174Speter /* 181812174Speter * check each port 181912174Speter */ 182012174Speter for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 182110015Speter ccbp = pp->sp_ccb; 182210015Speter tp = pp->sp_tty; 182310015Speter 182412174Speter 182510015Speter /* 182610015Speter * See if a command has completed ? 182710015Speter */ 182810015Speter if (ccbp->hi_stat != pp->sp_pend) { 182910015Speter DPRINT((pp, DBG_INTR, 183010015Speter "siintr hi_stat = 0x%x, pend = %d\n", 183110015Speter ccbp->hi_stat, pp->sp_pend)); 183210015Speter switch(pp->sp_pend) { 183310015Speter case LOPEN: 183410015Speter case MPEND: 183510015Speter case MOPEN: 183610015Speter case CONFIG: 183716575Speter case SBREAK: 183816575Speter case EBREAK: 183910015Speter pp->sp_pend = ccbp->hi_stat; 184010015Speter /* sleeping in si_command */ 184110015Speter wakeup(&pp->sp_state); 184210015Speter break; 184310015Speter default: 184410015Speter pp->sp_pend = ccbp->hi_stat; 184510015Speter } 184610015Speter } 184710015Speter 184810015Speter /* 184910015Speter * Continue on if it's closed 185010015Speter */ 185110015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 185210015Speter continue; 185310015Speter } 185410015Speter 185510015Speter /* 185610015Speter * Do modem state change if not a local device 185710015Speter */ 185810015Speter si_modem_state(pp, tp, ccbp->hi_ip); 185910015Speter 186010015Speter /* 186112174Speter * Check to see if there's we should 'receive' 186212174Speter * characters. 186312174Speter */ 186412174Speter if (tp->t_state & TS_CONNECTED && 186512174Speter tp->t_state & TS_ISOPEN) 186612174Speter isopen = 1; 186712174Speter else 186812174Speter isopen = 0; 186912174Speter 187012174Speter /* 187116575Speter * Do input break processing 187210015Speter */ 187310015Speter if (ccbp->hi_state & ST_BREAK) { 187412174Speter if (isopen) { 187512174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 187610015Speter } 187710015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 187810015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 187910015Speter } 188010015Speter 188110015Speter /* 188212174Speter * Do RX stuff - if not open then dump any characters. 188312174Speter * XXX: This is VERY messy and needs to be cleaned up. 188412174Speter * 188512174Speter * XXX: can we leave data in the host adapter buffer 188612174Speter * when the clists are full? That may be dangerous 188712174Speter * if the user cannot get an interrupt signal through. 188810015Speter */ 188910015Speter 189012174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 189112174Speter 189212174Speter if (!isopen) { 189310015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 189412174Speter goto end_rx; 189512174Speter } 189610015Speter 189712174Speter /* 189815640Speter * If the tty input buffers are blocked, stop emptying 189915640Speter * the incoming buffers and let the auto flow control 190015640Speter * assert.. 190115640Speter */ 190215640Speter if (tp->t_state & TS_TBLOCK) { 190315640Speter goto end_rx; 190415640Speter } 190515640Speter 190615640Speter /* 190712174Speter * Process read characters if not skipped above 190812174Speter */ 190915640Speter op = ccbp->hi_rxopos; 191015640Speter ip = ccbp->hi_rxipos; 191115640Speter c = ip - op; 191212174Speter if (c == 0) { 191312174Speter goto end_rx; 191412174Speter } 191510015Speter 191612174Speter n = c & 0xff; 191715640Speter if (n > 250) 191815640Speter n = 250; 191912174Speter 192012174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 192110015Speter n, op, ip)); 192210015Speter 192312174Speter /* 192412174Speter * Suck characters out of host card buffer into the 192512174Speter * "input staging buffer" - so that we dont leave the 192612174Speter * host card in limbo while we're possibly echoing 192712174Speter * characters and possibly flushing input inside the 192812174Speter * ldisc l_rint() routine. 192912174Speter */ 193012496Speter if (n <= SI_BUFFERSIZE - op) { 193110015Speter 193212174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 193312174Speter z = ccbp->hi_rxbuf + op; 193412174Speter bcopy((caddr_t)z, si_rxbuf, n); 193510015Speter 193612174Speter op += n; 193712174Speter } else { 193812496Speter x = SI_BUFFERSIZE - op; 193910015Speter 194012174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 194112174Speter z = ccbp->hi_rxbuf + op; 194212174Speter bcopy((caddr_t)z, si_rxbuf, x); 194310015Speter 194412174Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 194512174Speter z = ccbp->hi_rxbuf; 194612174Speter bcopy((caddr_t)z, si_rxbuf+x, n-x); 194710015Speter 194812174Speter op += n; 194912174Speter } 195010015Speter 195112174Speter /* clear collected characters from buffer */ 195212174Speter ccbp->hi_rxopos = op; 195312174Speter 195412174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 195510015Speter n, op, ip)); 195610015Speter 195712174Speter /* 195812174Speter * at this point... 195912174Speter * n = number of chars placed in si_rxbuf 196012174Speter */ 196110015Speter 196212174Speter /* 196312174Speter * Avoid the grotesquely inefficient lineswitch 196412174Speter * routine (ttyinput) in "raw" mode. It usually 196512174Speter * takes about 450 instructions (that's without 196612174Speter * canonical processing or echo!). slinput is 196712174Speter * reasonably fast (usually 40 instructions 196812174Speter * plus call overhead). 196912174Speter */ 197012174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 197110015Speter 197212174Speter /* block if the driver supports it */ 197312174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 197412174Speter && (tp->t_cflag & CRTS_IFLOW 197512174Speter || tp->t_iflag & IXOFF) 197612174Speter && !(tp->t_state & TS_TBLOCK)) 197712174Speter ttyblock(tp); 197810015Speter 197912174Speter tk_nin += n; 198012174Speter tk_rawcc += n; 198112174Speter tp->t_rawcc += n; 198212174Speter 198312174Speter pp->sp_delta_overflows += 198412174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 198512174Speter 198612174Speter ttwakeup(tp); 198712174Speter if (tp->t_state & TS_TTSTOP 198812174Speter && (tp->t_iflag & IXANY 198912174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 199012174Speter tp->t_state &= ~TS_TTSTOP; 199112174Speter tp->t_lflag &= ~FLUSHO; 199212174Speter si_start(tp); 199312174Speter } 199412174Speter } else { 199512174Speter /* 199612174Speter * It'd be nice to not have to go through the 199712174Speter * function call overhead for each char here. 199812174Speter * It'd be nice to block input it, saving a 199912174Speter * loop here and the call/return overhead. 200012174Speter */ 200112174Speter for(x = 0; x < n; x++) { 200212174Speter i = si_rxbuf[x]; 200312174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 200412174Speter == -1) { 200512174Speter pp->sp_delta_overflows++; 200610015Speter } 200712174Speter /* 200812174Speter * doesn't seem to be much point doing 200912174Speter * this here.. this driver has no 201012174Speter * softtty processing! ?? 201112174Speter */ 201212174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 201312174Speter setsofttty(); 201412174Speter } 201512174Speter } 201612174Speter } 201712174Speter goto more_rx; /* try for more until RXbuf is empty */ 201810015Speter 201912174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 202010015Speter 202110015Speter /* 202210015Speter * Do TX stuff 202310015Speter */ 202410015Speter (*linesw[tp->t_line].l_start)(tp); 202510015Speter 202610015Speter } /* end of for (all ports on this controller) */ 202710015Speter } /* end of for (all controllers) */ 202810015Speter 202911609Speter in_intr = 0; 203011609Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 203110015Speter} 203210015Speter 203310015Speter/* 203410015Speter * Nudge the transmitter... 203512174Speter * 203612174Speter * XXX: I inherited some funny code here. It implies the host card only 203712174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 203812174Speter * not interrupt when it's actually hits empty. In some cases, we have 203912174Speter * processes waiting for complete drain, and we need to simulate an interrupt 204012174Speter * about when we think the buffer is going to be empty (and retry if not). 204112174Speter * I really am not certain about this... I *need* the hardware manuals. 204210015Speter */ 204310015Speterstatic void 204410015Spetersi_start(tp) 204510015Speter register struct tty *tp; 204610015Speter{ 204710015Speter struct si_port *pp; 204810015Speter volatile struct si_channel *ccbp; 204910015Speter register struct clist *qp; 205010015Speter register char *dptr; 205110015Speter BYTE ipos; 205210015Speter int nchar; 205310015Speter int oldspl, count, n, amount, buffer_full; 205410015Speter int do_exitproc; 205510015Speter 205610015Speter oldspl = spltty(); 205710015Speter 205810015Speter qp = &tp->t_outq; 205910015Speter pp = TP2PP(tp); 206010015Speter 206110015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 206210015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 206310015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 206410015Speter 206510015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 206610015Speter goto out; 206710015Speter 206810015Speter do_exitproc = 0; 206910015Speter buffer_full = 0; 207010015Speter ccbp = pp->sp_ccb; 207110015Speter 207210015Speter /* 207310015Speter * Handle the case where ttywait() is called on process exit 207410015Speter * this may be BSDI specific, I dont know... 207510015Speter */ 207610015Speter if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 207710015Speter (tp->t_session->s_leader->p_flag & P_WEXIT)) { 207810015Speter do_exitproc++; 207910015Speter } 208010015Speter 208110015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 208210015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 208310015Speter 208410015Speter dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 208510015Speter 208610015Speter while ((nchar = qp->c_cc) > 0) { 208710015Speter if ((BYTE)count >= 255) { 208810015Speter buffer_full++; 208910015Speter break; 209010015Speter } 209110015Speter amount = min(nchar, (255 - (BYTE)count)); 209210015Speter ipos = (unsigned int)ccbp->hi_txipos; 209310015Speter /* will it fit in one lump? */ 209412496Speter if ((SI_BUFFERSIZE - ipos) >= amount) { 209510015Speter n = q_to_b(&tp->t_outq, 209610015Speter (char *)&ccbp->hi_txbuf[ipos], amount); 209710015Speter } else { 209810015Speter n = q_to_b(&tp->t_outq, 209910015Speter (char *)&ccbp->hi_txbuf[ipos], 210012496Speter SI_BUFFERSIZE-ipos); 210112496Speter if (n == SI_BUFFERSIZE-ipos) { 210210015Speter n += q_to_b(&tp->t_outq, 210310015Speter (char *)&ccbp->hi_txbuf[0], 210412496Speter amount - (SI_BUFFERSIZE-ipos)); 210510015Speter } 210610015Speter } 210710015Speter ccbp->hi_txipos += n; 210810015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 210910015Speter } 211010015Speter 211110015Speter if (count != 0 && nchar == 0) { 211210015Speter tp->t_state |= TS_BUSY; 211310015Speter } else { 211410015Speter tp->t_state &= ~TS_BUSY; 211510015Speter } 211610015Speter 211710015Speter /* wakeup time? */ 211810015Speter ttwwakeup(tp); 211910015Speter 212010015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 212110015Speter (BYTE)count, nchar, tp->t_state)); 212210015Speter 212310015Speter if ((tp->t_state & TS_BUSY) || do_exitproc) 212410015Speter { 212510015Speter int time; 212610015Speter 212710015Speter if (do_exitproc != 0) { 212810015Speter time = hz / 10; 212910015Speter } else { 213010015Speter time = ttspeedtab(tp->t_ospeed, chartimes); 213110015Speter 213210015Speter if (time > 0) { 213310015Speter if (time < nchar) 213410015Speter time = nchar / time; 213510015Speter else 213610015Speter time = 2; 213710015Speter } else { 213816024Speter DPRINT((pp, DBG_START, 213916024Speter "bad char time value! %d\n", time)); 214016024Speter time = hz/10; 214110015Speter } 214210015Speter } 214310015Speter 214410015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 214510015Speter untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 214610015Speter } else { 214710015Speter pp->sp_state |= SS_LSTART; 214810015Speter } 214910015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 215010015Speter timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 215110015Speter } 215210015Speter 215310015Speterout: 215410015Speter splx(oldspl); 215510015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 215610015Speter} 215710015Speter 215810015Speter/* 215910015Speter * Note: called at splsoftclock from the timeout code 216010015Speter * This has to deal with two things... cause wakeups while waiting for 216110015Speter * tty drains on last process exit, and call l_start at about the right 216210015Speter * time for protocols like ppp. 216310015Speter */ 216410015Speterstatic void 216510015Spetersi_lstart(pp) 216610015Speter register struct si_port *pp; 216710015Speter{ 216810015Speter register struct tty *tp; 216910015Speter int oldspl; 217010015Speter 217110015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 217210015Speter pp, pp->sp_state)); 217310015Speter 217410015Speter oldspl = spltty(); 217510015Speter 217610015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 217710015Speter splx(oldspl); 217810015Speter return; 217910015Speter } 218010015Speter pp->sp_state &= ~SS_LSTART; 218110015Speter pp->sp_state |= SS_INLSTART; 218210015Speter 218310015Speter tp = pp->sp_tty; 218410015Speter 218510015Speter /* deal with the process exit case */ 218610015Speter ttwwakeup(tp); 218710015Speter 218812174Speter /* nudge protocols - eg: ppp */ 218910015Speter (*linesw[tp->t_line].l_start)(tp); 219010015Speter 219110015Speter pp->sp_state &= ~SS_INLSTART; 219210015Speter splx(oldspl); 219310015Speter} 219410015Speter 219510015Speter/* 219610015Speter * Stop output on a line. called at spltty(); 219710015Speter */ 219810015Spetervoid 219910015Spetersistop(tp, rw) 220010015Speter register struct tty *tp; 220110015Speter int rw; 220210015Speter{ 220310015Speter volatile struct si_channel *ccbp; 220410015Speter struct si_port *pp; 220510015Speter 220610015Speter pp = TP2PP(tp); 220710015Speter ccbp = pp->sp_ccb; 220810015Speter 220910015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 221010015Speter 221110015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 221210015Speter if (rw & FWRITE) { 221310015Speter /* what level are we meant to be flushing anyway? */ 221410015Speter if (tp->t_state & TS_BUSY) { 221510015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 221610015Speter tp->t_state &= ~TS_BUSY; 221710015Speter ttwwakeup(tp); /* Bruce???? */ 221810015Speter } 221910015Speter } 222012174Speter#if 1 /* XXX: this doesn't work right yet.. */ 222112174Speter /* XXX: this may have been failing because we used to call l_rint() 222212174Speter * while we were looping based on these two counters. Now, we collect 222312174Speter * the data and then loop stuffing it into l_rint(), making this 222412174Speter * useless. Should we cause this to blow away the staging buffer? 222512174Speter */ 222610015Speter if (rw & FREAD) { 222710015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 222810015Speter } 222910015Speter#endif 223010015Speter} 223110015Speter 223210015Speter/* 223310015Speter * Issue a command to the Z280 host card CPU. 223410015Speter */ 223510015Speter 223610015Speterstatic void 223710015Spetersi_command(pp, cmd, waitflag) 223810015Speter struct si_port *pp; /* port control block (local) */ 223910015Speter int cmd; 224010015Speter int waitflag; 224110015Speter{ 224210015Speter int oldspl; 224310015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 224410015Speter int x; 224510015Speter 224610015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 224710015Speter pp, cmd, waitflag, ccbp->hi_stat)); 224810015Speter 224910015Speter oldspl = spltty(); /* Keep others out */ 225010015Speter 225110015Speter /* wait until it's finished what it was doing.. */ 225216575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 225316575Speter * is turned off. */ 225410015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 225510015Speter x != IDLE_CLOSE && 225616575Speter x != IDLE_BREAK && 225710015Speter x != cmd) { 225810015Speter if (in_intr) { /* Prevent sleep in intr */ 225910015Speter DPRINT((pp, DBG_PARAM, 226010015Speter "cmd intr collision - completing %d\trequested %d\n", 226110015Speter x, cmd)); 226210015Speter splx(oldspl); 226310015Speter return; 226410015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 226510015Speter "sicmd1", 1)) { 226610015Speter splx(oldspl); 226710015Speter return; 226810015Speter } 226910015Speter } 227016575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 227110015Speter 227210015Speter /* if there was a pending command, cause a state-change wakeup */ 227316575Speter switch(pp->sp_pend) { 227416575Speter case LOPEN: 227516575Speter case MPEND: 227616575Speter case MOPEN: 227716575Speter case CONFIG: 227816575Speter case SBREAK: 227916575Speter case EBREAK: 228016575Speter wakeup(&pp->sp_state); 228116575Speter break; 228216575Speter default: 228316575Speter break; 228410015Speter } 228510015Speter 228610015Speter pp->sp_pend = cmd; /* New command pending */ 228710015Speter ccbp->hi_stat = cmd; /* Post it */ 228810015Speter 228910015Speter if (waitflag) { 229010015Speter if (in_intr) { /* If in interrupt handler */ 229110015Speter DPRINT((pp, DBG_PARAM, 229210015Speter "attempt to sleep in si_intr - cmd req %d\n", 229310015Speter cmd)); 229410015Speter splx(oldspl); 229510015Speter return; 229616575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 229716575Speter ccbp->hi_stat != IDLE_BREAK) { 229810015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 229910015Speter "sicmd2", 0)) 230010015Speter break; 230110015Speter } 230210015Speter } 230310015Speter splx(oldspl); 230410015Speter} 230510015Speter 230610015Speterstatic void 230710015Spetersi_disc_optim(tp, t, pp) 230810015Speter struct tty *tp; 230910015Speter struct termios *t; 231010015Speter struct si_port *pp; 231110015Speter{ 231210015Speter /* 231310015Speter * XXX can skip a lot more cases if Smarts. Maybe 231410015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 231510015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 231610015Speter */ 231710015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 231810015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 231910015Speter && (!(t->c_iflag & PARMRK) 232010015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 232110015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 232210015Speter && linesw[tp->t_line].l_rint == ttyinput) 232310015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 232410015Speter else 232510015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 232610161Speter 232710015Speter /* 232810015Speter * Prepare to reduce input latency for packet 232910015Speter * discplines with a end of packet character. 233010015Speter */ 233110015Speter if (tp->t_line == SLIPDISC) 233210015Speter pp->sp_hotchar = 0xc0; 233310015Speter else if (tp->t_line == PPPDISC) 233410015Speter pp->sp_hotchar = 0x7e; 233510015Speter else 233610015Speter pp->sp_hotchar = 0; 233710161Speter 233810161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 233910161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 234010161Speter pp->sp_hotchar)); 234110015Speter} 234210015Speter 234310015Speter 234410015Speter#ifdef SI_DEBUG 234513353Speter 234610015Speterstatic void 234713353Speter#ifdef __STDC__ 234813353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 234913353Speter#else 235013353Spetersi_dprintf(pp, flags, fmt, va_alist) 235110015Speter struct si_port *pp; 235210015Speter int flags; 235313353Speter char *fmt; 235413353Speter#endif 235510015Speter{ 235613353Speter va_list ap; 235713630Sphk 235810015Speter if ((pp == NULL && (si_debug&flags)) || 235910015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 236010015Speter if (pp != NULL) 236112496Speter printf("%ci%d(%d): ", 's', 236212174Speter (int)SI_CARD(pp->sp_tty->t_dev), 236312174Speter (int)SI_PORT(pp->sp_tty->t_dev)); 236413630Sphk va_start(ap, fmt); 236513630Sphk vprintf(fmt, ap); 236613353Speter va_end(ap); 236710015Speter } 236810015Speter} 236910015Speter 237010015Speterstatic char * 237110015Spetersi_mctl2str(cmd) 237210015Speter enum si_mctl cmd; 237310015Speter{ 237410015Speter switch (cmd) { 237510015Speter case GET: return("GET"); 237610015Speter case SET: return("SET"); 237710015Speter case BIS: return("BIS"); 237810015Speter case BIC: return("BIC"); 237910015Speter } 238010015Speter return("BAD"); 238110015Speter} 238212502Sjulian 238312624Speter#endif /* DEBUG */ 238412502Sjulian 238512624Speter 238612502Sjulian 238712502Sjulianstatic si_devsw_installed = 0; 238812502Sjulian 238912517Sjulianstatic void si_drvinit(void *unused) 239012502Sjulian{ 239112517Sjulian dev_t dev; 239212517Sjulian 239312502Sjulian if( ! si_devsw_installed ) { 239412675Sjulian dev = makedev(CDEV_MAJOR, 0); 239512675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 239612502Sjulian si_devsw_installed = 1; 239712517Sjulian } 239812502Sjulian} 239912517Sjulian 240012517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 240112517Sjulian 2402