si.c revision 16024
1169586Smarcel/* 2179854Smarcel * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 3169586Smarcel * 4169586Smarcel * Copyright (C) 1990, 1992 Specialix International, 5169586Smarcel * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 6169586Smarcel * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> 7169586Smarcel * 8169586Smarcel * Originally derived from: SunOS 4.x version 9169586Smarcel * Ported from BSDI version to FreeBSD by Peter Wemm. 10169586Smarcel * 11169586Smarcel * Redistribution and use in source and binary forms, with or without 12169586Smarcel * modification, are permitted provided that the following conditions 13169586Smarcel * are met: 14169586Smarcel * 1. Redistributions of source code must retain the above copyright 15169586Smarcel * notices, this list of conditions and the following disclaimer. 16169586Smarcel * 2. Redistributions in binary form must reproduce the above copyright 17169586Smarcel * notices, this list of conditions and the following disclaimer in the 18169586Smarcel * documentation and/or other materials provided with the distribution. 19169586Smarcel * 3. All advertising materials mentioning features or use of this software 20169586Smarcel * must display the following acknowledgement: 21169586Smarcel * This product includes software developed by Andy Rutter of 22169586Smarcel * Advanced Methods and Tools Ltd. based on original information 23169586Smarcel * from Specialix International. 24169586Smarcel * 4. Neither the name of Advanced Methods and Tools, nor Specialix 25169586Smarcel * International may be used to endorse or promote products derived from 26169586Smarcel * this software without specific prior written permission. 27169586Smarcel * 28169586Smarcel * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 29169586Smarcel * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30185044Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 31208777Smarius * NO EVENT SHALL THE AUTHORS BE LIABLE. 32185044Smarcel * 33185044Smarcel * $Id: si.c,v 1.40 1996/05/08 04:48:25 peter Exp $ 34215570Sae */ 35185044Smarcel 36185044Smarcel#ifndef lint 37185044Smarcelstatic char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 38185044Smarcel si_copyright2[] = "@(#) (C) Andy Rutter 1993", 39185046Smarcel si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 40185044Smarcel#endif /* not lint */ 41215672Sae 42185044Smarcel#include <sys/param.h> 43169586Smarcel#include <sys/systm.h> 44169586Smarcel#include <sys/ioctl.h> 45209388Sae#include <sys/tty.h> 46209388Sae#include <sys/ttydefaults.h> 47169586Smarcel#include <sys/proc.h> 48169586Smarcel#include <sys/conf.h> 49185044Smarcel#include <sys/file.h> 50169586Smarcel#include <sys/uio.h> 51169586Smarcel#include <sys/dkstat.h> 52169586Smarcel#include <sys/kernel.h> 53169586Smarcel#include <sys/syslog.h> 54179550Smarcel#include <sys/malloc.h> 55173313Smarcel#include <sys/sysctl.h> 56173313Smarcel#include <sys/devconf.h> 57173313Smarcel#ifdef DEVFS 58173313Smarcel#include <sys/devfsext.h> 59169586Smarcel#endif /*DEVFS*/ 60173313Smarcel 61173313Smarcel#include <machine/clock.h> 62173313Smarcel 63209388Sae#include <vm/vm.h> 64209388Sae#include <vm/vm_param.h> 65215672Sae#include <vm/pmap.h> 66209388Sae 67212554Spjd#include <i386/isa/icu.h> 68212554Spjd#include <i386/isa/isa.h> 69179629Smarcel#include <i386/isa/isa_device.h> 70212554Spjd 71212554Spjd#include <i386/isa/sireg.h> 72212554Spjd#include <machine/si.h> 73212554Spjd#include <machine/stdarg.h> 74208777Smarius 75208777Smarius#include "si.h" 76208777Smarius 77208777Smarius/* 78209388Sae * This device driver is designed to interface the Specialix International 79208777Smarius * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 80208777Smarius * 81208777Smarius * The controller is interfaced to the host via dual port ram 82178180Smarcel * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 83208777Smarius */ 84185454Smarcel 85178180Smarcel#define POLL /* turn on poller to generate buffer empty interrupt */ 86219415Sae#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 87208777Smarius#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 88208777Smarius#define INT_COUNT 25000 /* max of 125 ints per second */ 89208777Smarius#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 90213097Sae 91215570Saeenum si_mctl { GET, SET, BIS, BIC }; 92215570Sae 93172837Smarcelstatic void si_command __P((struct si_port *, int, int)); 94173313Smarcelstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 95185454Smarcelstatic void si_write_enable __P((struct si_port *, int)); 96221363Saestatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 97212554Spjdstatic void si_start __P((struct tty *)); 98212554Spjdstatic void si_lstart __P((struct si_port *)); 99169586Smarcelstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 100212614Spjd struct si_port *pp)); 101212606Spjdstatic void sihardclose __P((struct si_port *pp)); 102212554Spjdstatic void sidtrwakeup __P((void *chan)); 103169586Smarcel 104222357Saestatic int siparam __P((struct tty *, struct termios *)); 105221363Sae 106169586Smarcelstatic void si_registerdev __P((struct isa_device *id)); 107215671Saestatic int siprobe __P((struct isa_device *id)); 108215671Saestatic int siattach __P((struct isa_device *id)); 109215570Saestatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 110178180Smarcel 111212606Spjdstruct isa_driver sidriver = 112212606Spjd { siprobe, siattach, "si" }; 113212614Spjd 114212554Spjd 115178180Smarcelstatic d_open_t siopen; 116222357Saestatic d_close_t siclose; 117178180Smarcelstatic d_read_t siread; 118212554Spjdstatic d_write_t siwrite; 119212554Spjdstatic d_ioctl_t siioctl; 120212554Spjdstatic d_stop_t sistop; 121185454Smarcelstatic d_devtotty_t sidevtotty; 122169586Smarcel 123212614Spjd#define CDEV_MAJOR 68 124212554Spjdstatic struct cdevsw si_cdevsw = 125169586Smarcel { siopen, siclose, siread, siwrite, /*68*/ 126212554Spjd siioctl, sistop, noreset, sidevtotty,/* si */ 127169586Smarcel ttselect, nommap, NULL, "si", NULL, -1 }; 128185454Smarcel 129212614Spjd 130212554Spjd#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 131169586Smarcel 132212554Spjdstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 133169586Smarcel ...)); 134214352Saestatic char *si_mctl2str __P((enum si_mctl cmd)); 135214352Sae 136212554Spjd#define DPRINT(x) si_dprintf x 137169586Smarcel 138213097Sae#else 139212554Spjd#define DPRINT(x) /* void */ 140185454Smarcel#endif 141212614Spjd 142212606Spjdstatic int si_Nports; 143212606Spjdstatic int si_Nmodules; 144212554Spjdstatic int si_debug = 0; /* data, not bss, so it's patchable */ 145169586Smarcel 146212554Spjdstatic struct tty *si_tty; 147169586Smarcel 148185454Smarcel/* where the firmware lives; defined in si_code.c */ 149179854Smarcelextern int si_dsize; 150251588Smarcelextern unsigned char si_download[]; 151212554Spjd 152179854Smarcelstruct si_softc { 153251588Smarcel int sc_type; /* adapter type */ 154179854Smarcel char *sc_typename; /* adapter type string */ 155179769Smarcel 156179769Smarcel struct si_port *sc_ports; /* port structures for this card */ 157179769Smarcel 158219415Sae caddr_t sc_paddr; /* physical addr of iomem */ 159179769Smarcel caddr_t sc_maddr; /* kvaddr of iomem */ 160222357Sae int sc_nport; /* # ports on this card */ 161179769Smarcel int sc_irq; /* copy of attach irq */ 162212554Spjd int sc_eisa_iobase; /* EISA io port address */ 163212554Spjd int sc_eisa_irqbits; 164212554Spjd struct kern_devconf sc_kdc; 165185454Smarcel#ifdef DEVFS 166179854Smarcel struct { 167251588Smarcel void *ttyd; 168212554Spjd void *cuaa; 169179854Smarcel void *ttyl; 170251588Smarcel void *ttyi; 171208777Smarius } devfs_token[32]; /* what is the max per card? */ 172207095Smarcel void *control_token; 173221363Sae#endif 174212554Spjd}; 175212614Spjdstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 176212554Spjd 177207095Smarcel#ifndef B2000 /* not standard, but the hardware knows it. */ 178222357Sae# define B2000 2000 179207095Smarcel#endif 180215570Saestatic struct speedtab bdrates[] = { 181215570Sae B75, CLK75, /* 0x0 */ 182215671Sae B110, CLK110, /* 0x1 */ 183215570Sae B150, CLK150, /* 0x3 */ 184215570Sae B300, CLK300, /* 0x4 */ 185215671Sae B600, CLK600, /* 0x5 */ 186215570Sae B1200, CLK1200, /* 0x6 */ 187214352Sae B2000, CLK2000, /* 0x7 */ 188214352Sae B2400, CLK2400, /* 0x8 */ 189214352Sae B4800, CLK4800, /* 0x9 */ 190214352Sae B9600, CLK9600, /* 0xb */ 191214352Sae B19200, CLK19200, /* 0xc */ 192169586Smarcel B38400, CLK38400, /* 0x2 (out of order!) */ 193169586Smarcel B57600, CLK57600, /* 0xd */ 194172837Smarcel B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 195172837Smarcel -1, -1 196172837Smarcel}; 197172837Smarcel 198172837Smarcel 199172837Smarcel/* populated with approx character/sec rates - translated at card 200172837Smarcel * initialisation time to chars per tick of the clock */ 201172837Smarcelstatic int done_chartimes = 0; 202172837Smarcelstatic struct speedtab chartimes[] = { 203172837Smarcel B75, 8, 204172837Smarcel B110, 11, 205172837Smarcel B150, 15, 206172837Smarcel B300, 30, 207172837Smarcel B600, 60, 208172837Smarcel B1200, 120, 209172837Smarcel B2000, 200, 210172837Smarcel B2400, 240, 211172837Smarcel B4800, 480, 212213662Sae B9600, 960, 213213662Sae B19200, 1920, 214172837Smarcel B38400, 3840, 215172837Smarcel B57600, 5760, 216172837Smarcel B115200, 11520, 217172837Smarcel -1, -1 218172837Smarcel}; 219172837Smarcelstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 220172837Smarcel 221172837Smarcelstatic int si_default_rate = TTYDEF_SPEED; 222172837Smarcelstatic int si_default_iflag = 0; 223172837Smarcelstatic int si_default_oflag = 0; 224172837Smarcelstatic int si_default_lflag = 0; 225172837Smarcel#ifdef SI_DEF_HWFLOW 226172837Smarcelstatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 227172837Smarcel#else 228172837Smarcelstatic int si_default_cflag = TTYDEF_CFLAG; 229172837Smarcel#endif 230172837Smarcel 231172837Smarcel#ifdef POLL 232172837Smarcelstatic int si_pollrate; /* in addition to irq */ 233172837Smarcel 234172837SmarcelSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RD, &si_pollrate, 0, ""); 235172837Smarcel 236172837Smarcelstatic int init_finished = 0; 237172837Smarcelstatic int fastpoll = 0; 238172837Smarcelstatic void si_poll __P((void *)); 239172837Smarcel#endif 240172837Smarcel 241172837Smarcel/* 242172837Smarcel * Array of adapter types and the corresponding RAM size. The order of 243172837Smarcel * entries here MUST match the ordinal of the adapter type. 244172837Smarcel */ 245172837Smarcelstatic char *si_type[] = { 246209388Sae "EMPTY", 247172837Smarcel "SIHOST", 248172837Smarcel "SI2", /* MCA */ 249188330Smarcel "SIHOST2", 250209388Sae "SIEISA", 251172837Smarcel}; 252172837Smarcel 253198478Slulf 254172837Smarcelstatic struct kern_devconf si_kdc[NSI] = { { 255188330Smarcel 0, 0, 0, /* filled in by dev_attach */ 256221952Sae "si", 0, { MDDT_ISA, 0, "tty" }, 257172837Smarcel isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 258172837Smarcel &kdc_isa0, /* parent */ 259172837Smarcel 0, /* parent data */ 260172837Smarcel DC_UNCONFIGURED, /* state */ 261188330Smarcel "Specialix SI/XIO Host adapter", 262172837Smarcel DC_CLS_SERIAL, /* class */ 263172837Smarcel} }; 264172837Smarcel 265172837Smarcelstatic void 266172837Smarcelsi_registerdev(id) 267172837Smarcel struct isa_device *id; 268172837Smarcel{ 269185046Smarcel if (id->id_unit != 0) { 270172837Smarcel si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 271185046Smarcel } 272172837Smarcel si_kdc[id->id_unit].kdc_unit = id->id_unit; 273185046Smarcel si_kdc[id->id_unit].kdc_isa = id; 274185046Smarcel si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 275172837Smarcel dev_attach(&si_kdc[id->id_unit]); 276172837Smarcel} 277172837Smarcel 278179854Smarcel/* Look for a valid board at the given mem addr */ 279179854Smarcelstatic int 280179854Smarcelsiprobe(id) 281184070Smarcel struct isa_device *id; 282184070Smarcel{ 283184070Smarcel struct si_softc *sc; 284179854Smarcel int type; 285184070Smarcel u_int i, ramsize; 286184070Smarcel volatile BYTE was, *ux; 287184070Smarcel volatile unsigned char *maddr; 288184070Smarcel unsigned char *paddr; 289184070Smarcel 290184070Smarcel si_registerdev(id); 291184070Smarcel 292184070Smarcel si_pollrate = (hz / 10); /* 10 per second */ 293184070Smarcel 294184070Smarcel maddr = id->id_maddr; /* virtual address... */ 295179854Smarcel paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 296179854Smarcel 297179854Smarcel DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 298222264Sae id->id_unit, id->id_maddr, paddr)); 299222263Sae 300221363Sae /* 301193673Smarcel * this is a lie, but it's easier than trying to handle caching 302207095Smarcel * and ram conflicts in the >1M and <16M region. 303207095Smarcel */ 304207095Smarcel if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 305207095Smarcel (caddr_t)paddr >= (caddr_t)IOM_END) { 306207095Smarcel printf("si%d: iomem (%lx) out of range\n", 307207095Smarcel id->id_unit, (long)paddr); 308209388Sae return(0); 309222630Sae } 310207095Smarcel 311225445Sae if (id->id_unit >= NSI) { 312207095Smarcel /* THIS IS IMPOSSIBLE */ 313212708Spjd return(0); 314212708Spjd } 315207095Smarcel 316207095Smarcel if (((u_int)paddr & 0x7fff) != 0) { 317207095Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 318207095Smarcel "si%d: iomem (%x) not on 32k boundary\n", 319207095Smarcel id->id_unit, paddr)); 320207095Smarcel return(0); 321207095Smarcel } 322207095Smarcel 323207095Smarcel 324207095Smarcel for (i=0; i < NSI; i++) { 325207095Smarcel if ((sc = &si_softc[i]) == NULL) 326212613Spjd continue; 327207095Smarcel if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 328207095Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 329207095Smarcel "si%d: iomem (%x) already configured to si%d\n", 330207095Smarcel id->id_unit, sc->sc_paddr, i)); 331207095Smarcel return(0); 332209388Sae } 333209388Sae } 334209388Sae 335207095Smarcel#if NEISA > 0 336221363Sae if (id->id_iobase > 0x0fff) { /* EISA card */ 337225445Sae int irq, port; 338221363Sae unsigned long base; 339225445Sae int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 340221363Sae IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 341221363Sae 342221363Sae port = id->id_iobase; 343221363Sae base = (inb(port+1) << 24) | (inb(port) << 16); 344221363Sae irq = ((inb(port+2) >> 4) & 0xf); 345222819Sae 346222630Sae id->id_irq = eisa_irqs[irq]; 347222631Sae 348222819Sae DPRINT((0, DBG_AUTOBOOT, 349221363Sae "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 350221363Sae id->id_unit, base, irq, id->id_irq, port)); 351221363Sae 352221363Sae if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 353221363Sae goto bad_irq; 354209388Sae 355209388Sae id->id_iobase &= 0xf000; 356209388Sae id->id_iosize = 0x0fff; 357209388Sae 358209388Sae type = EISA; 359209388Sae outb(p+2, (BYTE)irq << 4); 360209388Sae 361209388Sae sc->sc_eisa_iobase = p; 362225445Sae sc->sc_eisa_irqbits = irq << 4; 363221363Sae ramsize = SIEISA_RAMSIZE; 364209388Sae goto got_card; 365209388Sae } 366223356Sdelphij#endif 367209388Sae 368207095Smarcel /* Is there anything out there? (0x17 is just an arbitrary number) */ 369207095Smarcel *maddr = 0x17; 370207095Smarcel if (*maddr != 0x17) { 371207095Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 372207095Smarcel "si%d: 0x17 check fail at phys 0x%x\n", 373207095Smarcel id->id_unit, paddr)); 374207095Smarcelfail: 375207095Smarcel return(0); 376207095Smarcel } 377207095Smarcel /* 378207095Smarcel * OK, now to see if whatever responded is really an SI card. 379221952Sae * Try for a MK II first (SIHOST2) 380207095Smarcel */ 381222630Sae for (i=SIPLSIG; i<SIPLSIG+8; i++) 382222630Sae if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 383207095Smarcel goto try_mk1; 384225445Sae 385225445Sae /* It must be an SIHOST2 */ 386222630Sae *(maddr + SIPLRESET) = 0; 387222630Sae *(maddr + SIPLIRQCLR) = 0; 388222630Sae *(maddr + SIPLIRQSET) = 0x10; 389222630Sae type = SIHOST2; 390222630Sae ramsize = SIHOST2_RAMSIZE; 391222630Sae goto got_card; 392209388Sae 393222630Sae /* 394222630Sae * Its not a MK II, so try for a MK I (SIHOST) 395222630Sae */ 396222630Saetry_mk1: 397222630Sae *(maddr+SIRESET) = 0x0; /* reset the card */ 398222630Sae *(maddr+SIINTCL) = 0x0; /* clear int */ 399207095Smarcel *(maddr+SIRAM) = 0x17; 400221952Sae if (*(maddr+SIRAM) != (BYTE)0x17) 401209388Sae goto fail; 402209388Sae *(maddr+0x7ff8) = 0x17; 403207095Smarcel if (*(maddr+0x7ff8) != (BYTE)0x17) { 404207095Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 405222630Sae "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 406207095Smarcel id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 407207095Smarcel goto fail; 408209388Sae } 409209388Sae 410207095Smarcel /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 411209388Sae type = SIHOST; 412207095Smarcel ramsize = SIHOST_RAMSIZE; 413209388Sae 414209388Saegot_card: 415209388Sae DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 416209388Sae id->id_unit, type)); 417207095Smarcel /* Try the acid test */ 418207095Smarcel ux = (BYTE *)(maddr + SIRAM); 419207095Smarcel for (i=0; i<ramsize; i++, ux++) 420207095Smarcel *ux = (BYTE)(i&0xff); 421193673Smarcel ux = (BYTE *)(maddr + SIRAM); 422193673Smarcel for (i=0; i<ramsize; i++, ux++) { 423193673Smarcel if ((was = *ux) != (BYTE)(i&0xff)) { 424193673Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 425193673Smarcel "si%d: match fail at phys 0x%x, was %x should be %x\n", 426193673Smarcel id->id_unit, paddr+i, was, i&0xff)); 427221363Sae goto fail; 428221363Sae } 429221967Sae } 430209388Sae 431193673Smarcel /* clear out the RAM */ 432221363Sae ux = (BYTE *)(maddr + SIRAM); 433193673Smarcel for (i=0; i<ramsize; i++) 434193673Smarcel *ux++ = 0; 435207095Smarcel ux = (BYTE *)(maddr + SIRAM); 436207095Smarcel for (i=0; i<ramsize; i++) { 437193673Smarcel if ((was = *ux++) != 0) { 438193673Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 439193673Smarcel "si%d: clear fail at phys 0x%x, was %x\n", 440193673Smarcel id->id_unit, paddr+i, was)); 441193673Smarcel goto fail; 442193673Smarcel } 443196278Smarcel } 444196278Smarcel 445196278Smarcel /* 446196278Smarcel * Success, we've found a valid board, now fill in 447196278Smarcel * the adapter structure. 448196278Smarcel */ 449212613Spjd switch (type) { 450196278Smarcel case SIHOST2: 451196278Smarcel if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 452196278Smarcelbad_irq: 453196278Smarcel DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 454196278Smarcel "si%d: bad IRQ value - %d\n", 455209388Sae id->id_unit, id->id_irq)); 456209388Sae return(0); 457209388Sae } 458209388Sae id->id_msize = SIHOST2_MEMSIZE; 459221363Sae break; 460221363Sae case SIHOST: 461221363Sae if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 462221363Sae goto bad_irq; 463221363Sae } 464221363Sae id->id_msize = SIHOST_MEMSIZE; 465221363Sae break; 466221363Sae case SIEISA: 467221363Sae id->id_msize = SIEISA_MEMSIZE; 468221363Sae break; 469221363Sae case SI2: /* MCA */ 470221363Sae default: 471221363Sae printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 472221363Sae return(0); 473209388Sae } 474209388Sae si_softc[id->id_unit].sc_type = type; 475209388Sae si_softc[id->id_unit].sc_typename = si_type[type]; 476209388Sae return(-1); /* -1 == found */ 477209388Sae} 478209388Sae 479209388Sae/* 480209388Sae * Attach the device. Initialize the card. 481209388Sae */ 482209388Saestatic int 483209388Saesiattach(id) 484209388Sae struct isa_device *id; 485209388Sae{ 486209388Sae int unit = id->id_unit; 487209388Sae struct si_softc *sc = &si_softc[unit]; 488209388Sae struct si_port *pp; 489209388Sae volatile struct si_channel *ccbp; 490209388Sae volatile struct si_reg *regp; 491209388Sae volatile caddr_t maddr; 492221363Sae struct si_module *modp; 493209388Sae struct tty *tp; 494209388Sae struct speedtab *spt; 495222630Sae int nmodule, nport, x, y; 496222819Sae int uart_type; 497222819Sae#ifdef DEVFS 498222630Sae char name[32]; 499222630Sae#endif 500223356Sdelphij 501221967Sae DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 502223355Sae 503223355Sae sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 504221967Sae sc->sc_maddr = id->id_maddr; 505209388Sae sc->sc_irq = id->id_irq; 506209388Sae 507193673Smarcel sc->sc_ports = NULL; /* mark as uninitialised */ 508221967Sae 509221967Sae maddr = sc->sc_maddr; 510235033Sae 511235033Sae /* 512193673Smarcel * OK, now lets download the firmware and try and boot the CPU.. 513193673Smarcel */ 514221952Sae 515221967Sae DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 516221363Sae id->id_unit, si_dsize)); 517193673Smarcel bcopy(si_download, maddr, si_dsize); 518221363Sae 519193673Smarcel switch (sc->sc_type) { 520209388Sae case SIEISA: 521209388Sae#if NEISA > 0 522221363Sae /* modify the Z280 firmware to tell it that it's on an EISA */ 523193673Smarcel *(maddr+0x42) = 1; 524193673Smarcel outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 525193673Smarcel (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 526221363Sae break; 527221363Sae#endif /* fall-through if not EISA */ 528221363Sae case SI2: 529193673Smarcel /* 530193673Smarcel * must get around to converting the code for 531193673Smarcel * these one day, if FreeBSD ever supports it. 532221363Sae */ 533193673Smarcel return 0; 534193673Smarcel case SIHOST: 535193673Smarcel *(maddr+SIRESET_CL) = 0; 536193673Smarcel *(maddr+SIINTCL_CL) = 0; 537193673Smarcel break; 538193673Smarcel case SIHOST2: 539193673Smarcel *(maddr+SIPLRESET) = 0x10; 540221952Sae switch (sc->sc_irq) { 541235033Sae case IRQ11: 542235033Sae *(maddr+SIPLIRQ11) = 0x10; 543193673Smarcel break; 544221363Sae case IRQ12: 545193673Smarcel *(maddr+SIPLIRQ12) = 0x10; 546221363Sae break; 547193673Smarcel case IRQ15: 548209388Sae *(maddr+SIPLIRQ15) = 0x10; 549209388Sae break; 550221363Sae } 551193673Smarcel *(maddr+SIPLIRQCLR) = 0x10; 552193673Smarcel break; 553193673Smarcel } 554221363Sae 555221363Sae DELAY(1000000); /* wait around for a second */ 556221363Sae 557193673Smarcel regp = (struct si_reg *)maddr; 558193673Smarcel y = 0; 559193673Smarcel /* wait max of 5 sec for init OK */ 560221363Sae while (regp->initstat == 0 && y++ < 10) { 561193673Smarcel DELAY(500000); 562193673Smarcel } 563193673Smarcel switch (regp->initstat) { 564193673Smarcel case 0: 565193673Smarcel printf("si%d: startup timeout - aborting\n", unit); 566209388Sae sc->sc_type = SIEMPTY; 567209388Sae return 0; 568193673Smarcel case 1: 569209388Sae /* set throttle to 125 intr per second */ 570221967Sae regp->int_count = INT_COUNT; 571209388Sae /* rx intr max of 25 timer per second */ 572209388Sae regp->rx_int_count = RXINT_COUNT; 573209388Sae regp->int_pending = 0; /* no intr pending */ 574209388Sae regp->int_scounter = 0; /* reset counter */ 575209388Sae break; 576209388Sae case 0xff: 577193673Smarcel /* 578193673Smarcel * No modules found, so give up on this one. 579193673Smarcel */ 580172837Smarcel printf("si%d: %s - no ports found\n", unit, 581219415Sae si_type[sc->sc_type]); 582172837Smarcel return 0; 583172837Smarcel default: 584172837Smarcel printf("si%d: Z280 version error - initstat %x\n", 585209388Sae unit, regp->initstat); 586209388Sae return 0; 587219415Sae } 588172837Smarcel 589172837Smarcel /* 590172837Smarcel * First time around the ports just count them in order 591209388Sae * to allocate some memory. 592172837Smarcel */ 593209388Sae nport = 0; 594172837Smarcel modp = (struct si_module *)(maddr + 0x80); 595214352Sae for (;;) { 596214352Sae DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 597214352Sae switch (modp->sm_type & (~MMASK)) { 598219415Sae case M232: 599219415Sae case M422: 600219415Sae DPRINT((0, DBG_DOWNLOAD, 601219415Sae "si%d: Found 232/422 module, %d ports\n", 602219415Sae unit, (int)(modp->sm_type & MMASK))); 603219415Sae 604219415Sae /* this is a firmware issue */ 605219415Sae if (si_Nports == SI_MAXPORTPERCARD) { 606219415Sae printf("si%d: extra ports ignored\n", unit); 607172837Smarcel continue; 608172837Smarcel } 609214352Sae 610209388Sae x = modp->sm_type & MMASK; 611172837Smarcel nport += x; 612214352Sae si_Nports += x; 613214352Sae si_Nmodules++; 614172837Smarcel break; 615172837Smarcel default: 616188330Smarcel printf("si%d: unknown module type %d\n", 617221952Sae unit, modp->sm_type); 618188330Smarcel break; 619188330Smarcel } 620221952Sae if (modp->sm_next == 0) 621221952Sae break; 622221952Sae modp = (struct si_module *) 623172837Smarcel (maddr + (unsigned)(modp->sm_next & 0x7fff)); 624172837Smarcel } 625172837Smarcel sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 626209388Sae M_DEVBUF, M_NOWAIT); 627209388Sae if (sc->sc_ports == 0) { 628209388Saemem_fail: 629172837Smarcel printf("si%d: fail to malloc memory for port structs\n", 630172837Smarcel unit); 631219415Sae return 0; 632219415Sae } 633219415Sae bzero(sc->sc_ports, sizeof(struct si_port) * nport); 634219415Sae sc->sc_nport = nport; 635219415Sae 636219415Sae /* 637219415Sae * allocate tty structures for ports 638219415Sae */ 639219415Sae tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 640219415Sae if (tp == 0) 641219415Sae goto mem_fail; 642219415Sae bzero(tp, sizeof(*tp) * nport); 643188330Smarcel si_tty = tp; 644172837Smarcel 645172837Smarcel /* mark the device state as attached */ 646188330Smarcel si_kdc[unit].kdc_state = DC_BUSY; 647209388Sae 648209388Sae /* 649172837Smarcel * Scan round the ports again, this time initialising. 650188330Smarcel */ 651172837Smarcel pp = sc->sc_ports; 652172837Smarcel nmodule = 0; 653172837Smarcel modp = (struct si_module *)(maddr + 0x80); 654172837Smarcel uart_type = 0; 655179769Smarcel for (;;) { 656179769Smarcel switch (modp->sm_type & (~MMASK)) { 657179769Smarcel case M232: 658179769Smarcel case M422: 659215704Sbrucec nmodule++; 660179769Smarcel nport = (modp->sm_type & MMASK); 661179769Smarcel ccbp = (struct si_channel *)((char *)modp+0x100); 662179769Smarcel if (uart_type == 0) 663179769Smarcel uart_type = ccbp->type; 664179769Smarcel for (x = 0; x < nport; x++, pp++, ccbp++) { 665179769Smarcel pp->sp_ccb = ccbp; /* save the address */ 666179769Smarcel pp->sp_tty = tp++; 667179769Smarcel pp->sp_pend = IDLE_CLOSE; 668172837Smarcel pp->sp_state = 0; /* internal flag */ 669178180Smarcel pp->sp_dtr_wait = 3 * hz; 670172837Smarcel pp->sp_iin.c_iflag = si_default_iflag; 671172837Smarcel pp->sp_iin.c_oflag = si_default_oflag; 672172837Smarcel pp->sp_iin.c_cflag = si_default_cflag; 673172837Smarcel pp->sp_iin.c_lflag = si_default_lflag; 674179769Smarcel termioschars(&pp->sp_iin); 675219415Sae pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 676172837Smarcel si_default_rate; 677179769Smarcel pp->sp_iout = pp->sp_iin; 678179769Smarcel } 679179769Smarcel break; 680179769Smarcel default: 681179769Smarcel break; 682179769Smarcel } 683179769Smarcel if (modp->sm_next == 0) { 684179769Smarcel printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 685172837Smarcel unit, 686172837Smarcel sc->sc_typename, 687172837Smarcel sc->sc_nport, 688172837Smarcel nmodule, 689172837Smarcel uart_type); 690172837Smarcel break; 691172837Smarcel } 692172837Smarcel modp = (struct si_module *) 693172837Smarcel (maddr + (unsigned)(modp->sm_next & 0x7fff)); 694172837Smarcel } 695172837Smarcel if (done_chartimes == 0) { 696219415Sae for (spt = chartimes ; spt->sp_speed != -1; spt++) { 697172837Smarcel if ((spt->sp_code /= hz) == 0) 698172837Smarcel spt->sp_code = 1; 699172837Smarcel } 700172837Smarcel done_chartimes = 1; 701172837Smarcel } 702172837Smarcel 703219415Sae#ifdef DEVFS 704172837Smarcel/* path name devsw minor type uid gid perm*/ 705172837Smarcel for ( x = 0; x < sc->sc_nport; x++ ) { 706172837Smarcel y = x + 1; /* For sync with the manuals that start at 1 */ 707172837Smarcel sc->devfs_token[x].ttyd = devfs_add_devswf( 708172837Smarcel &si_cdevsw, x, 709219415Sae DV_CHR, 0, 0, 0600, "ttyA%02d", y); 710172837Smarcel sc->devfs_token[x].cuaa = devfs_add_devswf( 711172837Smarcel &si_cdevsw, x + 128, 712172837Smarcel DV_CHR, 0, 0, 0600, "cuaA%02d", y); 713172837Smarcel sc->devfs_token[x].ttyi = devfs_add_devswf( 714178180Smarcel &si_cdevsw, x + 0x10000, 715215570Sae DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 716215570Sae sc->devfs_token[x].ttyl = devfs_add_devswf( 717215570Sae &si_cdevsw, x + 0x20000, 718215570Sae DV_CHR, 0, 0, 0600, "ttylA%02d", y); 719215570Sae } 720215570Sae sc->control_token = 721215570Sae devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 722215570Sae "si_control"); 723215570Sae#endif 724229916Seadler return (1); 725215671Sae} 726215570Sae 727215570Saestatic int 728215570Saesiopen(dev, flag, mode, p) 729215570Sae dev_t dev; 730215570Sae int flag, mode; 731215570Sae struct proc *p; 732215570Sae{ 733215570Sae int oldspl, error; 734215570Sae int card, port; 735215570Sae register struct si_softc *sc; 736215570Sae register struct tty *tp; 737215570Sae volatile struct si_channel *ccbp; 738215570Sae struct si_port *pp; 739215570Sae int mynor = minor(dev); 740215570Sae 741215570Sae /* quickly let in /dev/si_control */ 742215570Sae if (IS_CONTROLDEV(mynor)) { 743215570Sae if (error = suser(p->p_ucred, &p->p_acflag)) 744215570Sae return(error); 745215570Sae return(0); 746215570Sae } 747215570Sae 748215570Sae card = SI_CARD(mynor); 749215570Sae if (card >= NSI) 750215570Sae return (ENXIO); 751215570Sae sc = &si_softc[card]; 752215570Sae 753215570Sae if (sc->sc_type == SIEMPTY) { 754215570Sae DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 755215570Sae card, sc->sc_typename)); 756215570Sae return(ENXIO); 757215570Sae } 758215570Sae 759215570Sae port = SI_PORT(mynor); 760215570Sae if (port >= sc->sc_nport) { 761215570Sae DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 762215570Sae card, sc->sc_nport)); 763215570Sae return(ENXIO); 764221952Sae } 765215570Sae 766215570Sae#ifdef POLL 767221952Sae /* 768221952Sae * We've now got a device, so start the poller. 769221952Sae */ 770215570Sae if (init_finished == 0) { 771215671Sae timeout(si_poll, (caddr_t)0L, si_pollrate); 772215570Sae init_finished = 1; 773215570Sae } 774215570Sae#endif 775215671Sae 776215671Sae /* initial/lock device */ 777215570Sae if (IS_STATE(mynor)) { 778215570Sae return(0); 779215570Sae } 780215570Sae 781215570Sae pp = sc->sc_ports + port; 782215570Sae tp = pp->sp_tty; /* the "real" tty */ 783215570Sae ccbp = pp->sp_ccb; /* Find control block */ 784215570Sae DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 785215570Sae dev, flag, mode, p)); 786215570Sae 787215570Sae oldspl = spltty(); /* Keep others out */ 788215570Sae error = 0; 789215570Sae 790215570Saeopen_top: 791215570Sae while (pp->sp_state & SS_DTR_OFF) { 792215570Sae error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 793215570Sae if (error != 0) 794215570Sae goto out; 795215570Sae } 796215672Sae 797215672Sae if (tp->t_state & TS_ISOPEN) { 798215672Sae /* 799215672Sae * The device is open, so everything has been initialised. 800215672Sae * handle conflicts. 801215672Sae */ 802215570Sae if (IS_CALLOUT(mynor)) { 803215570Sae if (!pp->sp_active_out) { 804215570Sae error = EBUSY; 805215570Sae goto out; 806215570Sae } 807215570Sae } else { 808215672Sae if (pp->sp_active_out) { 809215570Sae if (flag & O_NONBLOCK) { 810215570Sae error = EBUSY; 811215671Sae goto out; 812215570Sae } 813215570Sae error = tsleep(&pp->sp_active_out, 814215570Sae TTIPRI|PCATCH, "sibi", 0); 815215570Sae if (error != 0) 816215570Sae goto out; 817215570Sae goto open_top; 818215570Sae } 819215570Sae } 820215671Sae if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 821215570Sae DPRINT((pp, DBG_OPEN|DBG_FAIL, 822215570Sae "already open and EXCLUSIVE set\n")); 823215570Sae error = EBUSY; 824215570Sae goto out; 825215570Sae } 826215570Sae } else { 827215570Sae /* 828215570Sae * The device isn't open, so there are no conflicts. 829215570Sae * Initialize it. Avoid sleep... :-) 830215570Sae */ 831215570Sae DPRINT((pp, DBG_OPEN, "first open\n")); 832215672Sae tp->t_oproc = si_start; 833215672Sae tp->t_param = siparam; 834215672Sae tp->t_dev = dev; 835215672Sae tp->t_termios = mynor & SI_CALLOUT_MASK 836215672Sae ? pp->sp_iout : pp->sp_iin; 837215672Sae 838215672Sae (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 839215570Sae 840215570Sae ++pp->sp_wopeners; /* in case of sleep in siparam */ 841215570Sae 842215570Sae error = siparam(tp, &tp->t_termios); 843215570Sae 844215570Sae --pp->sp_wopeners; 845215570Sae if (error != 0) 846215570Sae goto out; 847215570Sae /* XXX: we should goto_top if siparam slept */ 848215570Sae 849215570Sae ttsetwater(tp); 850215570Sae 851215570Sae /* set initial DCD state */ 852215570Sae pp->sp_last_hi_ip = ccbp->hi_ip; 853215570Sae if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 854215570Sae (*linesw[tp->t_line].l_modem)(tp, 1); 855215570Sae } 856215570Sae } 857215570Sae 858215570Sae /* whoops! we beat the close! */ 859215570Sae if (pp->sp_state & SS_CLOSING) { 860215570Sae /* try and stop it from proceeding to bash the hardware */ 861215570Sae pp->sp_state &= ~SS_CLOSING; 862215570Sae } 863215570Sae 864215672Sae /* 865215672Sae * Wait for DCD if necessary 866215570Sae */ 867215570Sae if (!(tp->t_state & TS_CARR_ON) 868215570Sae && !IS_CALLOUT(mynor) 869215570Sae && !(tp->t_cflag & CLOCAL) 870215570Sae && !(flag & O_NONBLOCK)) { 871215570Sae ++pp->sp_wopeners; 872215570Sae DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 873215570Sae error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 874215570Sae --pp->sp_wopeners; 875215570Sae if (error != 0) 876215570Sae goto out; 877215570Sae goto open_top; 878215570Sae } 879215570Sae 880215671Sae error = (*linesw[tp->t_line].l_open)(dev, tp); 881215570Sae si_disc_optim(tp, &tp->t_termios, pp); 882215570Sae if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 883215671Sae pp->sp_active_out = TRUE; 884215671Sae 885215570Sae pp->sp_state |= SS_OPEN; /* made it! */ 886215570Sae 887215570Saeout: 888215570Sae splx(oldspl); 889215570Sae 890215570Sae DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 891215570Sae 892215671Sae if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 893215671Sae sihardclose(pp); 894215671Sae 895215570Sae return(error); 896215570Sae} 897215570Sae 898215570Saestatic int 899215570Saesiclose(dev, flag, mode, p) 900215570Sae dev_t dev; 901215570Sae int flag, mode; 902215570Sae struct proc *p; 903215570Sae{ 904215570Sae register struct si_port *pp; 905215570Sae register struct tty *tp; 906215570Sae int oldspl; 907215570Sae int error = 0; 908215570Sae int mynor = minor(dev); 909215570Sae 910215570Sae if (IS_SPECIAL(mynor)) 911215570Sae return(0); 912215570Sae 913215570Sae oldspl = spltty(); 914215570Sae 915215570Sae pp = MINOR2PP(mynor); 916215570Sae tp = pp->sp_tty; 917215570Sae 918215570Sae DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 919215570Sae dev, flag, mode, p, pp->sp_state)); 920215570Sae 921215570Sae /* did we sleep and loose a race? */ 922215570Sae if (pp->sp_state & SS_CLOSING) { 923215570Sae /* error = ESOMETING? */ 924215570Sae goto out; 925215570Sae } 926215570Sae 927215570Sae /* begin race detection.. */ 928215570Sae pp->sp_state |= SS_CLOSING; 929215570Sae 930215671Sae si_write_enable(pp, 0); /* block writes for ttywait() */ 931215570Sae 932223158Sae /* THIS MAY SLEEP IN TTYWAIT!!! */ 933215570Sae (*linesw[tp->t_line].l_close)(tp, flag); 934215570Sae 935215570Sae si_write_enable(pp, 1); 936215570Sae 937215570Sae /* did we sleep and somebody started another open? */ 938215570Sae if (!(pp->sp_state & SS_CLOSING)) { 939215570Sae /* error = ESOMETING? */ 940215570Sae goto out; 941215570Sae } 942215570Sae /* ok. we are now still on the right track.. nuke the hardware */ 943215570Sae 944215570Sae if (pp->sp_state & SS_LSTART) { 945215570Sae untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 946215570Sae pp->sp_state &= ~SS_LSTART; 947215570Sae } 948215570Sae 949215570Sae sistop(tp, FREAD | FWRITE); 950215570Sae 951215570Sae sihardclose(pp); 952215570Sae ttyclose(tp); 953215570Sae pp->sp_state &= ~SS_OPEN; 954215570Sae 955215570Saeout: 956215570Sae DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 957215570Sae splx(oldspl); 958215570Sae return(error); 959215570Sae} 960215570Sae 961215570Saestatic void 962215570Saesihardclose(pp) 963215570Sae struct si_port *pp; 964215570Sae{ 965215570Sae int oldspl; 966215570Sae struct tty *tp; 967215570Sae volatile struct si_channel *ccbp; 968215570Sae 969215570Sae oldspl = spltty(); 970215570Sae 971215570Sae tp = pp->sp_tty; 972215570Sae ccbp = pp->sp_ccb; /* Find control block */ 973215570Sae if (tp->t_cflag & HUPCL 974215570Sae || !pp->sp_active_out 975215672Sae && !(ccbp->hi_ip & IP_DCD) 976215672Sae && !(pp->sp_iin.c_cflag && CLOCAL) 977215570Sae || !(tp->t_state & TS_ISOPEN)) { 978215570Sae 979215570Sae (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 980215570Sae (void) si_command(pp, FCLOSE, SI_NOWAIT); 981215570Sae 982215570Sae if (pp->sp_dtr_wait != 0) { 983215570Sae timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 984215570Sae pp->sp_state |= SS_DTR_OFF; 985215570Sae } 986215570Sae 987215570Sae } 988215570Sae pp->sp_active_out = FALSE; 989215570Sae wakeup((caddr_t)&pp->sp_active_out); 990215570Sae wakeup(TSA_CARR_ON(tp)); 991215570Sae 992215570Sae splx(oldspl); 993215570Sae} 994215570Sae 995215570Sae 996215570Sae/* 997215570Sae * called at splsoftclock()... 998215570Sae */ 999215570Saestatic void 1000215570Saesidtrwakeup(chan) 1001215570Sae void *chan; 1002215570Sae{ 1003215570Sae struct si_port *pp; 1004215570Sae int oldspl; 1005215570Sae 1006215570Sae oldspl = spltty(); 1007215570Sae 1008215570Sae pp = (struct si_port *)chan; 1009215570Sae pp->sp_state &= ~SS_DTR_OFF; 1010215570Sae wakeup(&pp->sp_dtr_wait); 1011215570Sae 1012215570Sae splx(oldspl); 1013179629Smarcel} 1014179629Smarcel 1015178180Smarcel/* 1016178180Smarcel * User level stuff - read and write 1017178180Smarcel */ 1018179629Smarcelstatic int 1019178180Smarcelsiread(dev, uio, flag) 1020179629Smarcel register dev_t dev; 1021179629Smarcel struct uio *uio; 1022178180Smarcel int flag; 1023178180Smarcel{ 1024179629Smarcel register struct tty *tp; 1025179629Smarcel int mynor = minor(dev); 1026208777Smarius 1027179629Smarcel if (IS_SPECIAL(mynor)) { 1028179629Smarcel DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 1029178180Smarcel return(ENODEV); 1030179629Smarcel } 1031178180Smarcel tp = MINOR2TP(mynor); 1032178180Smarcel DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 1033178180Smarcel "siread(%x,%x,%x)\n", dev, uio, flag)); 1034179629Smarcel return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 1035179629Smarcel} 1036178180Smarcel 1037179629Smarcel 1038179629Smarcelstatic int 1039179629Smarcelsiwrite(dev, uio, flag) 1040178180Smarcel dev_t dev; 1041178180Smarcel struct uio *uio; 1042179629Smarcel int flag; 1043178180Smarcel{ 1044179629Smarcel register struct si_port *pp; 1045179629Smarcel register struct tty *tp; 1046208777Smarius int error = 0; 1047179629Smarcel int mynor = minor(dev); 1048179629Smarcel int oldspl; 1049179629Smarcel 1050179629Smarcel if (IS_SPECIAL(mynor)) { 1051185038Smarcel DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 1052185038Smarcel return(ENODEV); 1053208777Smarius } 1054179629Smarcel pp = MINOR2PP(mynor); 1055179629Smarcel tp = pp->sp_tty; 1056179629Smarcel DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 1057179629Smarcel 1058179629Smarcel oldspl = spltty(); 1059179629Smarcel /* 1060179629Smarcel * If writes are currently blocked, wait on the "real" tty 1061179629Smarcel */ 1062179629Smarcel while (pp->sp_state & SS_BLOCKWRITE) { 1063179629Smarcel pp->sp_state |= SS_WAITWRITE; 1064179629Smarcel DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 1065179629Smarcel if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 1066179629Smarcel "siwrite", 0)) 1067179629Smarcel goto out; 1068179629Smarcel } 1069179629Smarcel 1070179629Smarcel error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 1071179629Smarcelout: 1072185038Smarcel splx(oldspl); 1073185038Smarcel return (error); 1074185038Smarcel} 1075185038Smarcel 1076185038Smarcel 1077185038Smarcelstatic struct tty * 1078185038Smarcelsidevtotty(dev_t dev) 1079185038Smarcel{ 1080185038Smarcel struct si_port *pp; 1081185038Smarcel int mynor = minor(dev); 1082179629Smarcel struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 1083185038Smarcel 1084185038Smarcel if (IS_SPECIAL(mynor)) 1085185038Smarcel return(NULL); 1086185038Smarcel if (SI_PORT(mynor) >= sc->sc_nport) 1087179629Smarcel return(NULL); 1088179629Smarcel pp = MINOR2PP(mynor); 1089179629Smarcel return (pp->sp_tty); 1090208777Smarius} 1091179629Smarcel 1092208777Smariusstatic int 1093208777Smariussiioctl(dev, cmd, data, flag, p) 1094208777Smarius dev_t dev; 1095208777Smarius int cmd; 1096208777Smarius caddr_t data; 1097208777Smarius int flag; 1098208777Smarius struct proc *p; 1099208777Smarius{ 1100208777Smarius struct si_port *pp; 1101208777Smarius register struct tty *tp; 1102208777Smarius int error; 1103208777Smarius int mynor = minor(dev); 1104208777Smarius int oldspl; 1105208777Smarius int blocked = 0; 1106208777Smarius#if defined(COMPAT_43) 1107208777Smarius int oldcmd; 1108208777Smarius struct termios term; 1109208777Smarius#endif 1110208777Smarius 1111208777Smarius if (IS_SI_IOCTL(cmd)) 1112208777Smarius return(si_Sioctl(dev, cmd, data, flag, p)); 1113208777Smarius 1114208777Smarius pp = MINOR2PP(mynor); 1115208777Smarius tp = pp->sp_tty; 1116208777Smarius 1117208777Smarius DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 1118208777Smarius dev, cmd, data, flag)); 1119208777Smarius if (IS_STATE(mynor)) { 1120208777Smarius struct termios *ct; 1121208777Smarius 1122208777Smarius switch (mynor & SI_STATE_MASK) { 1123208777Smarius case SI_INIT_STATE_MASK: 1124208777Smarius ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 1125208777Smarius break; 1126208777Smarius case SI_LOCK_STATE_MASK: 1127208777Smarius ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 1128208777Smarius break; 1129208777Smarius default: 1130208777Smarius return (ENODEV); 1131208777Smarius } 1132208777Smarius switch (cmd) { 1133208777Smarius case TIOCSETA: 1134179629Smarcel error = suser(p->p_ucred, &p->p_acflag); 1135179629Smarcel if (error != 0) 1136179629Smarcel return (error); 1137185454Smarcel *ct = *(struct termios *)data; 1138179629Smarcel return (0); 1139208777Smarius case TIOCGETA: 1140208777Smarius *(struct termios *)data = *ct; 1141208777Smarius return (0); 1142179629Smarcel case TIOCGETD: 1143179629Smarcel *(int *)data = TTYDISC; 1144179629Smarcel return (0); 1145208777Smarius case TIOCGWINSZ: 1146179629Smarcel bzero(data, sizeof(struct winsize)); 1147212554Spjd return (0); 1148212554Spjd default: 1149208173Snwhitehorn return (ENOTTY); 1150179629Smarcel } 1151212554Spjd } 1152179629Smarcel /* 1153179629Smarcel * Do the old-style ioctl compat routines... 1154179629Smarcel */ 1155179629Smarcel#if defined(COMPAT_43) 1156179629Smarcel term = tp->t_termios; 1157179629Smarcel oldcmd = cmd; 1158179629Smarcel error = ttsetcompat(tp, &cmd, data, &term); 1159179629Smarcel if (error != 0) 1160208777Smarius return (error); 1161208777Smarius if (cmd != oldcmd) 1162208777Smarius data = (caddr_t)&term; 1163208777Smarius#endif 1164208777Smarius /* 1165208777Smarius * Do the initial / lock state business 1166208777Smarius */ 1167208777Smarius if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1168208777Smarius int cc; 1169208777Smarius struct termios *dt = (struct termios *)data; 1170208777Smarius struct termios *lt = mynor & SI_CALLOUT_MASK 1171216619Sae ? &pp->sp_lout : &pp->sp_lin; 1172216619Sae 1173212554Spjd dt->c_iflag = (tp->t_iflag & lt->c_iflag) 1174208777Smarius | (dt->c_iflag & ~lt->c_iflag); 1175208777Smarius dt->c_oflag = (tp->t_oflag & lt->c_oflag) 1176208777Smarius | (dt->c_oflag & ~lt->c_oflag); 1177208777Smarius dt->c_cflag = (tp->t_cflag & lt->c_cflag) 1178208777Smarius | (dt->c_cflag & ~lt->c_cflag); 1179208777Smarius dt->c_lflag = (tp->t_lflag & lt->c_lflag) 1180208777Smarius | (dt->c_lflag & ~lt->c_lflag); 1181208777Smarius for (cc = 0; cc < NCCS; ++cc) 1182208777Smarius if (lt->c_cc[cc] != 0) 1183208777Smarius dt->c_cc[cc] = tp->t_cc[cc]; 1184212554Spjd if (lt->c_ispeed != 0) 1185212554Spjd dt->c_ispeed = tp->t_ispeed; 1186208777Smarius if (lt->c_ospeed != 0) 1187179629Smarcel dt->c_ospeed = tp->t_ospeed; 1188212554Spjd } 1189179629Smarcel 1190179629Smarcel /* 1191179629Smarcel * Block user-level writes to give the ttywait() 1192179629Smarcel * a chance to completely drain for commands 1193179629Smarcel * that require the port to be in a quiescent state. 1194179629Smarcel */ 1195179629Smarcel switch (cmd) { 1196212554Spjd case TIOCSETAW: case TIOCSETAF: 1197179629Smarcel case TIOCDRAIN: case TIOCSETP: 1198179629Smarcel blocked++; /* block writes for ttywait() and siparam() */ 1199212708Spjd si_write_enable(pp, 0); 1200212708Spjd } 1201179629Smarcel 1202212554Spjd error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1203179629Smarcel if (error >= 0) 1204179629Smarcel goto out; 1205179629Smarcel 1206179629Smarcel oldspl = spltty(); 1207179629Smarcel 1208179629Smarcel error = ttioctl(tp, cmd, data, flag); 1209208777Smarius si_disc_optim(tp, &tp->t_termios, pp); 1210208777Smarius if (error >= 0) 1211208777Smarius goto outspl; 1212208777Smarius 1213223364Sae switch (cmd) { 1214223364Sae case TIOCSBRK: 1215223364Sae si_command(pp, SBREAK, SI_NOWAIT); 1216208777Smarius break; 1217223364Sae case TIOCCBRK: 1218208777Smarius si_command(pp, EBREAK, SI_NOWAIT); 1219179629Smarcel break; 1220179629Smarcel case TIOCSDTR: 1221179629Smarcel (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 1222185454Smarcel break; 1223185454Smarcel case TIOCCDTR: 1224208777Smarius (void) si_modem(pp, SET, 0); 1225208777Smarius break; 1226185454Smarcel case TIOCMSET: 1227185454Smarcel (void) si_modem(pp, SET, *(int *)data); 1228185454Smarcel break; 1229213097Sae case TIOCMBIS: 1230213097Sae (void) si_modem(pp, BIS, *(int *)data); 1231213097Sae break; 1232213097Sae case TIOCMBIC: 1233213097Sae (void) si_modem(pp, BIC, *(int *)data); 1234213097Sae break; 1235213097Sae case TIOCMGET: 1236213097Sae *(int *)data = si_modem(pp, GET, 0); 1237213097Sae break; 1238213097Sae case TIOCMSDTRWAIT: 1239213097Sae /* must be root since the wait applies to following logins */ 1240213097Sae error = suser(p->p_ucred, &p->p_acflag); 1241213097Sae if (error != 0) { 1242213097Sae goto outspl; 1243213097Sae } 1244213097Sae pp->sp_dtr_wait = *(int *)data * hz / 100; 1245213097Sae break; 1246213097Sae case TIOCMGDTRWAIT: 1247185454Smarcel *(int *)data = pp->sp_dtr_wait * 100 / hz; 1248185454Smarcel break; 1249185454Smarcel 1250185454Smarcel default: 1251185495Smarcel error = ENOTTY; 1252185454Smarcel } 1253212554Spjd error = 0; 1254212554Spjdoutspl: 1255212554Spjd splx(oldspl); 1256212554Spjdout: 1257193673Smarcel DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 1258193673Smarcel if (blocked) 1259193673Smarcel si_write_enable(pp, 1); 1260193673Smarcel return(error); 1261193673Smarcel} 1262193673Smarcel 1263193673Smarcel/* 1264193673Smarcel * Handle the Specialix ioctls. All MUST be called via the CONTROL device 1265185454Smarcel */ 1266185454Smarcelstatic int 1267185454Smarcelsi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 1268185454Smarcel{ 1269185454Smarcel struct si_softc *xsc; 1270185454Smarcel register struct si_port *xpp; 1271185495Smarcel volatile struct si_reg *regp; 1272185495Smarcel struct si_tcsi *dp; 1273179629Smarcel struct si_pstat *sps; 1274185454Smarcel int *ip, error = 0; 1275213097Sae int oldspl; 1276185495Smarcel int card, port; 1277185495Smarcel int mynor = minor(dev); 1278185495Smarcel 1279185495Smarcel DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 1280185495Smarcel dev, cmd, data, flag)); 1281179629Smarcel 1282#if 1 1283 DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 1284 DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 1285 DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 1286#endif 1287 1288 if (!IS_CONTROLDEV(mynor)) { 1289 DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 1290 return(ENODEV); 1291 } 1292 1293 oldspl = spltty(); /* better safe than sorry */ 1294 1295 ip = (int *)data; 1296 1297#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 1298 1299 switch (cmd) { 1300 case TCSIPORTS: 1301 *ip = si_Nports; 1302 goto out; 1303 case TCSIMODULES: 1304 *ip = si_Nmodules; 1305 goto out; 1306 case TCSISDBG_ALL: 1307 SUCHECK; 1308 si_debug = *ip; 1309 goto out; 1310 case TCSIGDBG_ALL: 1311 *ip = si_debug; 1312 goto out; 1313 default: 1314 /* 1315 * Check that a controller for this port exists 1316 */ 1317 1318 /* may also be a struct si_pstat, a superset of si_tcsi */ 1319 1320 dp = (struct si_tcsi *)data; 1321 sps = (struct si_pstat *)data; 1322 card = dp->tc_card; 1323 xsc = &si_softc[card]; /* check.. */ 1324 if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 1325 error = ENOENT; 1326 goto out; 1327 } 1328 /* 1329 * And check that a port exists 1330 */ 1331 port = dp->tc_port; 1332 if (port < 0 || port >= xsc->sc_nport) { 1333 error = ENOENT; 1334 goto out; 1335 } 1336 xpp = xsc->sc_ports + port; 1337 regp = (struct si_reg *)xsc->sc_maddr; 1338 } 1339 1340 switch (cmd) { 1341 case TCSIDEBUG: 1342#ifdef SI_DEBUG 1343 SUCHECK; 1344 if (xpp->sp_debug) 1345 xpp->sp_debug = 0; 1346 else { 1347 xpp->sp_debug = DBG_ALL; 1348 DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 1349 (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 1350 } 1351 break; 1352#else 1353 error = ENODEV; 1354 goto out; 1355#endif 1356 case TCSISDBG_LEVEL: 1357 case TCSIGDBG_LEVEL: 1358#ifdef SI_DEBUG 1359 if (cmd == TCSIGDBG_LEVEL) { 1360 dp->tc_dbglvl = xpp->sp_debug; 1361 } else { 1362 SUCHECK; 1363 xpp->sp_debug = dp->tc_dbglvl; 1364 } 1365 break; 1366#else 1367 error = ENODEV; 1368 goto out; 1369#endif 1370 case TCSIGRXIT: 1371 dp->tc_int = regp->rx_int_count; 1372 break; 1373 case TCSIRXIT: 1374 SUCHECK; 1375 regp->rx_int_count = dp->tc_int; 1376 break; 1377 case TCSIGIT: 1378 dp->tc_int = regp->int_count; 1379 break; 1380 case TCSIIT: 1381 SUCHECK; 1382 regp->int_count = dp->tc_int; 1383 break; 1384 case TCSISTATE: 1385 dp->tc_int = xpp->sp_ccb->hi_ip; 1386 break; 1387 /* these next three use a different structure */ 1388 case TCSI_PORT: 1389 SUCHECK; 1390 sps->tc_siport = *xpp; 1391 break; 1392 case TCSI_CCB: 1393 SUCHECK; 1394 sps->tc_ccb = *xpp->sp_ccb; 1395 break; 1396 case TCSI_TTY: 1397 SUCHECK; 1398 sps->tc_tty = *xpp->sp_tty; 1399 break; 1400 default: 1401 error = EINVAL; 1402 goto out; 1403 } 1404out: 1405 splx(oldspl); 1406 return(error); /* success */ 1407} 1408 1409/* 1410 * siparam() : Configure line params 1411 * called at spltty(); 1412 * this may sleep, does not flush, nor wait for drain, nor block writes 1413 * caller must arrange this if it's important.. 1414 */ 1415static int 1416siparam(tp, t) 1417 register struct tty *tp; 1418 register struct termios *t; 1419{ 1420 register struct si_port *pp = TP2PP(tp); 1421 volatile struct si_channel *ccbp; 1422 int oldspl, cflag, iflag, oflag, lflag; 1423 int error = 0; /* shutup gcc */ 1424 int ispeed = 0; /* shutup gcc */ 1425 int ospeed = 0; /* shutup gcc */ 1426 BYTE val; 1427 1428 DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 1429 cflag = t->c_cflag; 1430 iflag = t->c_iflag; 1431 oflag = t->c_oflag; 1432 lflag = t->c_lflag; 1433 DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 1434 oflag, cflag, iflag, lflag)); 1435 1436 1437 /* if not hung up.. */ 1438 if (t->c_ospeed != 0) { 1439 /* translate baud rate to firmware values */ 1440 ospeed = ttspeedtab(t->c_ospeed, bdrates); 1441 ispeed = t->c_ispeed ? 1442 ttspeedtab(t->c_ispeed, bdrates) : ospeed; 1443 1444 /* enforce legit baud rate */ 1445 if (ospeed < 0 || ispeed < 0) 1446 return (EINVAL); 1447 } 1448 1449 1450 oldspl = spltty(); 1451 1452 ccbp = pp->sp_ccb; 1453 1454 /* ========== set hi_break ========== */ 1455 val = 0; 1456 if (iflag & IGNBRK) /* Breaks */ 1457 val |= BR_IGN; 1458 if (iflag & BRKINT) /* Interrupt on break? */ 1459 val |= BR_INT; 1460 if (iflag & PARMRK) /* Parity mark? */ 1461 val |= BR_PARMRK; 1462 if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 1463 val |= BR_PARIGN; 1464 ccbp->hi_break = val; 1465 1466 /* ========== set hi_csr ========== */ 1467 /* if not hung up.. */ 1468 if (t->c_ospeed != 0) { 1469 /* Set I/O speeds */ 1470 val = (ispeed << 4) | ospeed; 1471 } 1472 ccbp->hi_csr = val; 1473 1474 /* ========== set hi_mr2 ========== */ 1475 val = 0; 1476 if (cflag & CSTOPB) /* Stop bits */ 1477 val |= MR2_2_STOP; 1478 else 1479 val |= MR2_1_STOP; 1480 /* 1481 * Enable H/W RTS/CTS handshaking. The default TA/MTA is 1482 * a DCE, hence the reverse sense of RTS and CTS 1483 */ 1484 /* Output Flow - RTS must be raised before data can be sent */ 1485 if (cflag & CCTS_OFLOW) 1486 val |= MR2_RTSCONT; 1487 1488 ccbp->hi_mr1 = val; 1489 1490 /* ========== set hi_mr1 ========== */ 1491 val = 0; 1492 if (!(cflag & PARENB)) /* Parity */ 1493 val |= MR1_NONE; 1494 else 1495 val |= MR1_WITH; 1496 if (cflag & PARODD) 1497 val |= MR1_ODD; 1498 1499 if ((cflag & CS8) == CS8) { /* 8 data bits? */ 1500 val |= MR1_8_BITS; 1501 } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 1502 val |= MR1_7_BITS; 1503 } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 1504 val |= MR1_6_BITS; 1505 } else { /* Must be 5 */ 1506 val |= MR1_5_BITS; 1507 } 1508 /* 1509 * Enable H/W RTS/CTS handshaking. The default TA/MTA is 1510 * a DCE, hence the reverse sense of RTS and CTS 1511 */ 1512 /* Input Flow - CTS is raised when port is ready to receive data */ 1513 if (cflag & CRTS_IFLOW) 1514 val |= MR1_CTSCONT; 1515 1516 ccbp->hi_mr1 = val; 1517 1518 /* ========== set hi_mask ========== */ 1519 val = 0xff; 1520 if ((cflag & CS8) == CS8) { /* 8 data bits? */ 1521 val &= 0xFF; 1522 } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 1523 val &= 0x7F; 1524 } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 1525 val &= 0x3F; 1526 } else { /* Must be 5 */ 1527 val &= 0x1F; 1528 } 1529 if (iflag & ISTRIP) 1530 val &= 0x7F; 1531 1532 ccbp->hi_mask = val; 1533 1534 /* ========== set hi_prtcl ========== */ 1535 val = 0; 1536 /* Monitor DCD etc. if a modem */ 1537 if (!(cflag & CLOCAL)) 1538 val |= SP_DCEN; 1539 if (iflag & IXANY) 1540 val |= SP_TANY; 1541 if (iflag & IXON) 1542 val |= SP_TXEN; 1543 if (iflag & IXOFF) 1544 val |= SP_RXEN; 1545 if (iflag & INPCK) 1546 val |= SP_PAEN; 1547 1548 ccbp->hi_prtcl = val; 1549 1550 1551 /* ========== set hi_{rx|tx}{on|off} ========== */ 1552 /* XXX: the card TOTALLY shields us from the flow control... */ 1553 ccbp->hi_txon = t->c_cc[VSTART]; 1554 ccbp->hi_txoff = t->c_cc[VSTOP]; 1555 1556 ccbp->hi_rxon = t->c_cc[VSTART]; 1557 ccbp->hi_rxoff = t->c_cc[VSTOP]; 1558 1559 /* ========== send settings to the card ========== */ 1560 /* potential sleep here */ 1561 if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 1562 si_command(pp, LOPEN, SI_WAIT); /* open it */ 1563 else 1564 si_command(pp, CONFIG, SI_WAIT); /* change params */ 1565 1566 /* ========== set DTR etc ========== */ 1567 /* Hangup if ospeed == 0 */ 1568 if (t->c_ospeed == 0) { 1569 (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 1570 } else { 1571 /* 1572 * If the previous speed was 0, may need to re-enable 1573 * the modem signals 1574 */ 1575 (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 1576 } 1577 1578 DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 1579 ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 1580 1581 splx(oldspl); 1582 return(error); 1583} 1584 1585/* 1586 * Enable or Disable the writes to this channel... 1587 * "state" -> enabled = 1; disabled = 0; 1588 */ 1589static void 1590si_write_enable(pp, state) 1591 register struct si_port *pp; 1592 int state; 1593{ 1594 int oldspl; 1595 1596 oldspl = spltty(); 1597 1598 if (state) { 1599 pp->sp_state &= ~SS_BLOCKWRITE; 1600 if (pp->sp_state & SS_WAITWRITE) { 1601 pp->sp_state &= ~SS_WAITWRITE; 1602 /* thunder away! */ 1603 wakeup((caddr_t)pp); 1604 } 1605 } else { 1606 pp->sp_state |= SS_BLOCKWRITE; 1607 } 1608 1609 splx(oldspl); 1610} 1611 1612/* 1613 * Set/Get state of modem control lines. 1614 * Due to DCE-like behaviour of the adapter, some signals need translation: 1615 * TIOCM_DTR DSR 1616 * TIOCM_RTS CTS 1617 */ 1618static int 1619si_modem(pp, cmd, bits) 1620 struct si_port *pp; 1621 enum si_mctl cmd; 1622 int bits; 1623{ 1624 volatile struct si_channel *ccbp; 1625 int x; 1626 1627 DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 1628 ccbp = pp->sp_ccb; /* Find channel address */ 1629 switch (cmd) { 1630 case GET: 1631 x = ccbp->hi_ip; 1632 bits = TIOCM_LE; 1633 if (x & IP_DCD) bits |= TIOCM_CAR; 1634 if (x & IP_DTR) bits |= TIOCM_DTR; 1635 if (x & IP_RTS) bits |= TIOCM_RTS; 1636 if (x & IP_RI) bits |= TIOCM_RI; 1637 return(bits); 1638 case SET: 1639 ccbp->hi_op &= ~(OP_DSR|OP_CTS); 1640 /* fall through */ 1641 case BIS: 1642 x = 0; 1643 if (bits & TIOCM_DTR) 1644 x |= OP_DSR; 1645 if (bits & TIOCM_RTS) 1646 x |= OP_CTS; 1647 ccbp->hi_op |= x; 1648 break; 1649 case BIC: 1650 if (bits & TIOCM_DTR) 1651 ccbp->hi_op &= ~OP_DSR; 1652 if (bits & TIOCM_RTS) 1653 ccbp->hi_op &= ~OP_CTS; 1654 } 1655 return 0; 1656} 1657 1658/* 1659 * Handle change of modem state 1660 */ 1661static void 1662si_modem_state(pp, tp, hi_ip) 1663 register struct si_port *pp; 1664 register struct tty *tp; 1665 register int hi_ip; 1666{ 1667 /* if a modem dev */ 1668 if (hi_ip & IP_DCD) { 1669 if ( !(pp->sp_last_hi_ip & IP_DCD)) { 1670 DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 1671 tp->t_line)); 1672 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 1673 } 1674 } else { 1675 if (pp->sp_last_hi_ip & IP_DCD) { 1676 DPRINT((pp, DBG_INTR, "modem carr off\n")); 1677 if ((*linesw[tp->t_line].l_modem)(tp, 0)) 1678 (void) si_modem(pp, SET, 0); 1679 } 1680 } 1681 pp->sp_last_hi_ip = hi_ip; 1682 1683} 1684 1685/* 1686 * Poller to catch missed interrupts. 1687 * 1688 * Note that the SYSV Specialix drivers poll at 100 times per second to get 1689 * better response. We could really use a "periodic" version timeout(). :-) 1690 */ 1691#ifdef POLL 1692static void 1693si_poll(void *nothing) 1694{ 1695 register struct si_softc *sc; 1696 register int i; 1697 volatile struct si_reg *regp; 1698 register struct si_port *pp; 1699 int lost, oldspl, port; 1700 1701 DPRINT((0, DBG_POLL, "si_poll()\n")); 1702 oldspl = spltty(); 1703 if (in_intr) 1704 goto out; 1705 lost = 0; 1706 for (i=0; i<NSI; i++) { 1707 sc = &si_softc[i]; 1708 if (sc->sc_type == SIEMPTY) 1709 continue; 1710 regp = (struct si_reg *)sc->sc_maddr; 1711 /* 1712 * See if there has been a pending interrupt for 2 seconds 1713 * or so. The test <int_scounter >= 200) won't correspond 1714 * to 2 seconds if int_count gets changed. 1715 */ 1716 if (regp->int_pending != 0) { 1717 if (regp->int_scounter >= 200 && 1718 regp->initstat == 1) { 1719 printf("si%d: lost intr\n", i); 1720 lost++; 1721 } 1722 } else { 1723 regp->int_scounter = 0; 1724 } 1725 1726 /* 1727 * gripe about no input flow control.. 1728 */ 1729 pp = sc->sc_ports; 1730 for (port = 0; port < sc->sc_nport; pp++, port++) { 1731 if (pp->sp_delta_overflows > 0) { 1732 printf("si%d: %d tty level buffer overflows\n", 1733 i, pp->sp_delta_overflows); 1734 pp->sp_delta_overflows = 0; 1735 } 1736 } 1737 } 1738 if (lost) 1739 siintr(-1); /* call intr with fake vector */ 1740out: 1741 splx(oldspl); 1742 1743 timeout(si_poll, (caddr_t)0L, si_pollrate); 1744} 1745#endif /* ifdef POLL */ 1746 1747/* 1748 * The interrupt handler polls ALL ports on ALL adapters each time 1749 * it is called. 1750 */ 1751 1752static BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 1753 1754void 1755siintr(int unit) 1756{ 1757 register struct si_softc *sc; 1758 1759 register struct si_port *pp; 1760 volatile struct si_channel *ccbp; 1761 register struct tty *tp; 1762 volatile caddr_t maddr; 1763 BYTE op, ip; 1764 int x, card, port, n, i, isopen; 1765 volatile BYTE *z; 1766 BYTE c; 1767 1768 DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 1769 if (in_intr) { 1770 if (unit < 0) /* should never happen */ 1771 return; 1772 printf("si%d: Warning interrupt handler re-entered\n", 1773 unit); 1774 return; 1775 } 1776 in_intr = 1; 1777 1778 /* 1779 * When we get an int we poll all the channels and do ALL pending 1780 * work, not just the first one we find. This allows all cards to 1781 * share the same vector. 1782 */ 1783 for (card=0; card < NSI; card++) { 1784 sc = &si_softc[card]; 1785 if (sc->sc_type == SIEMPTY) 1786 continue; 1787 1788 /* 1789 * First, clear the interrupt 1790 */ 1791 switch(sc->sc_type) { 1792 case SIHOST : 1793 maddr = sc->sc_maddr; 1794 ((volatile struct si_reg *)maddr)->int_pending = 0; 1795 /* flag nothing pending */ 1796 *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 1797 *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 1798 break; 1799 case SIHOST2: 1800 maddr = sc->sc_maddr; 1801 ((volatile struct si_reg *)maddr)->int_pending = 0; 1802 *(maddr+SIPLIRQCLR) = 0x00; 1803 *(maddr+SIPLIRQCLR) = 0x10; 1804 break; 1805 case SIEISA: 1806#if NEISA > 0 1807 maddr = sc->sc_maddr; 1808 ((volatile struct si_reg *)maddr)->int_pending = 0; 1809 (void)inb(sc->sc_eisa_iobase+3); 1810 break; 1811#endif /* fall through if not EISA kernel */ 1812 case SIEMPTY: 1813 default: 1814 continue; 1815 } 1816 ((volatile struct si_reg *)maddr)->int_scounter = 0; 1817 1818 /* 1819 * check each port 1820 */ 1821 for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 1822 ccbp = pp->sp_ccb; 1823 tp = pp->sp_tty; 1824 1825 1826 /* 1827 * See if a command has completed ? 1828 */ 1829 if (ccbp->hi_stat != pp->sp_pend) { 1830 DPRINT((pp, DBG_INTR, 1831 "siintr hi_stat = 0x%x, pend = %d\n", 1832 ccbp->hi_stat, pp->sp_pend)); 1833 switch(pp->sp_pend) { 1834 case LOPEN: 1835 case MPEND: 1836 case MOPEN: 1837 case CONFIG: 1838 pp->sp_pend = ccbp->hi_stat; 1839 /* sleeping in si_command */ 1840 wakeup(&pp->sp_state); 1841 break; 1842 default: 1843 pp->sp_pend = ccbp->hi_stat; 1844 } 1845 } 1846 1847 /* 1848 * Continue on if it's closed 1849 */ 1850 if (ccbp->hi_stat == IDLE_CLOSE) { 1851 continue; 1852 } 1853 1854 /* 1855 * Do modem state change if not a local device 1856 */ 1857 si_modem_state(pp, tp, ccbp->hi_ip); 1858 1859 /* 1860 * Check to see if there's we should 'receive' 1861 * characters. 1862 */ 1863 if (tp->t_state & TS_CONNECTED && 1864 tp->t_state & TS_ISOPEN) 1865 isopen = 1; 1866 else 1867 isopen = 0; 1868 1869 /* 1870 * Do break processing 1871 */ 1872 if (ccbp->hi_state & ST_BREAK) { 1873 if (isopen) { 1874 (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 1875 } 1876 ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 1877 DPRINT((pp, DBG_INTR, "si_intr break\n")); 1878 } 1879 1880 /* 1881 * Do RX stuff - if not open then dump any characters. 1882 * XXX: This is VERY messy and needs to be cleaned up. 1883 * 1884 * XXX: can we leave data in the host adapter buffer 1885 * when the clists are full? That may be dangerous 1886 * if the user cannot get an interrupt signal through. 1887 */ 1888 1889 more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 1890 1891 if (!isopen) { 1892 ccbp->hi_rxopos = ccbp->hi_rxipos; 1893 goto end_rx; 1894 } 1895 1896 /* 1897 * If the tty input buffers are blocked, stop emptying 1898 * the incoming buffers and let the auto flow control 1899 * assert.. 1900 */ 1901 if (tp->t_state & TS_TBLOCK) { 1902 goto end_rx; 1903 } 1904 1905 /* 1906 * Process read characters if not skipped above 1907 */ 1908 op = ccbp->hi_rxopos; 1909 ip = ccbp->hi_rxipos; 1910 c = ip - op; 1911 if (c == 0) { 1912 goto end_rx; 1913 } 1914 1915 n = c & 0xff; 1916 if (n > 250) 1917 n = 250; 1918 1919 DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1920 n, op, ip)); 1921 1922 /* 1923 * Suck characters out of host card buffer into the 1924 * "input staging buffer" - so that we dont leave the 1925 * host card in limbo while we're possibly echoing 1926 * characters and possibly flushing input inside the 1927 * ldisc l_rint() routine. 1928 */ 1929 if (n <= SI_BUFFERSIZE - op) { 1930 1931 DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 1932 z = ccbp->hi_rxbuf + op; 1933 bcopy((caddr_t)z, si_rxbuf, n); 1934 1935 op += n; 1936 } else { 1937 x = SI_BUFFERSIZE - op; 1938 1939 DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 1940 z = ccbp->hi_rxbuf + op; 1941 bcopy((caddr_t)z, si_rxbuf, x); 1942 1943 DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 1944 z = ccbp->hi_rxbuf; 1945 bcopy((caddr_t)z, si_rxbuf+x, n-x); 1946 1947 op += n; 1948 } 1949 1950 /* clear collected characters from buffer */ 1951 ccbp->hi_rxopos = op; 1952 1953 DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1954 n, op, ip)); 1955 1956 /* 1957 * at this point... 1958 * n = number of chars placed in si_rxbuf 1959 */ 1960 1961 /* 1962 * Avoid the grotesquely inefficient lineswitch 1963 * routine (ttyinput) in "raw" mode. It usually 1964 * takes about 450 instructions (that's without 1965 * canonical processing or echo!). slinput is 1966 * reasonably fast (usually 40 instructions 1967 * plus call overhead). 1968 */ 1969 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1970 1971 /* block if the driver supports it */ 1972 if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 1973 && (tp->t_cflag & CRTS_IFLOW 1974 || tp->t_iflag & IXOFF) 1975 && !(tp->t_state & TS_TBLOCK)) 1976 ttyblock(tp); 1977 1978 tk_nin += n; 1979 tk_rawcc += n; 1980 tp->t_rawcc += n; 1981 1982 pp->sp_delta_overflows += 1983 b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 1984 1985 ttwakeup(tp); 1986 if (tp->t_state & TS_TTSTOP 1987 && (tp->t_iflag & IXANY 1988 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 1989 tp->t_state &= ~TS_TTSTOP; 1990 tp->t_lflag &= ~FLUSHO; 1991 si_start(tp); 1992 } 1993 } else { 1994 /* 1995 * It'd be nice to not have to go through the 1996 * function call overhead for each char here. 1997 * It'd be nice to block input it, saving a 1998 * loop here and the call/return overhead. 1999 */ 2000 for(x = 0; x < n; x++) { 2001 i = si_rxbuf[x]; 2002 if ((*linesw[tp->t_line].l_rint)(i, tp) 2003 == -1) { 2004 pp->sp_delta_overflows++; 2005 } 2006 /* 2007 * doesn't seem to be much point doing 2008 * this here.. this driver has no 2009 * softtty processing! ?? 2010 */ 2011 if (pp->sp_hotchar && i == pp->sp_hotchar) { 2012 setsofttty(); 2013 } 2014 } 2015 } 2016 goto more_rx; /* try for more until RXbuf is empty */ 2017 2018 end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 2019 2020 /* 2021 * Do TX stuff 2022 */ 2023 (*linesw[tp->t_line].l_start)(tp); 2024 2025 } /* end of for (all ports on this controller) */ 2026 } /* end of for (all controllers) */ 2027 2028 in_intr = 0; 2029 DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 2030} 2031 2032/* 2033 * Nudge the transmitter... 2034 * 2035 * XXX: I inherited some funny code here. It implies the host card only 2036 * interrupts when the transmit buffer reaches the low-water-mark, and does 2037 * not interrupt when it's actually hits empty. In some cases, we have 2038 * processes waiting for complete drain, and we need to simulate an interrupt 2039 * about when we think the buffer is going to be empty (and retry if not). 2040 * I really am not certain about this... I *need* the hardware manuals. 2041 */ 2042static void 2043si_start(tp) 2044 register struct tty *tp; 2045{ 2046 struct si_port *pp; 2047 volatile struct si_channel *ccbp; 2048 register struct clist *qp; 2049 register char *dptr; 2050 BYTE ipos; 2051 int nchar; 2052 int oldspl, count, n, amount, buffer_full; 2053 int do_exitproc; 2054 2055 oldspl = spltty(); 2056 2057 qp = &tp->t_outq; 2058 pp = TP2PP(tp); 2059 2060 DPRINT((pp, DBG_ENTRY|DBG_START, 2061 "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 2062 tp, tp->t_state, pp->sp_state, qp->c_cc)); 2063 2064 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 2065 goto out; 2066 2067 do_exitproc = 0; 2068 buffer_full = 0; 2069 ccbp = pp->sp_ccb; 2070 2071 /* 2072 * Handle the case where ttywait() is called on process exit 2073 * this may be BSDI specific, I dont know... 2074 */ 2075 if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 2076 (tp->t_session->s_leader->p_flag & P_WEXIT)) { 2077 do_exitproc++; 2078 } 2079 2080 count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 2081 DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 2082 2083 dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 2084 2085 while ((nchar = qp->c_cc) > 0) { 2086 if ((BYTE)count >= 255) { 2087 buffer_full++; 2088 break; 2089 } 2090 amount = min(nchar, (255 - (BYTE)count)); 2091 ipos = (unsigned int)ccbp->hi_txipos; 2092 /* will it fit in one lump? */ 2093 if ((SI_BUFFERSIZE - ipos) >= amount) { 2094 n = q_to_b(&tp->t_outq, 2095 (char *)&ccbp->hi_txbuf[ipos], amount); 2096 } else { 2097 n = q_to_b(&tp->t_outq, 2098 (char *)&ccbp->hi_txbuf[ipos], 2099 SI_BUFFERSIZE-ipos); 2100 if (n == SI_BUFFERSIZE-ipos) { 2101 n += q_to_b(&tp->t_outq, 2102 (char *)&ccbp->hi_txbuf[0], 2103 amount - (SI_BUFFERSIZE-ipos)); 2104 } 2105 } 2106 ccbp->hi_txipos += n; 2107 count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 2108 } 2109 2110 if (count != 0 && nchar == 0) { 2111 tp->t_state |= TS_BUSY; 2112 } else { 2113 tp->t_state &= ~TS_BUSY; 2114 } 2115 2116 /* wakeup time? */ 2117 ttwwakeup(tp); 2118 2119 DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 2120 (BYTE)count, nchar, tp->t_state)); 2121 2122 if ((tp->t_state & TS_BUSY) || do_exitproc) 2123 { 2124 int time; 2125 2126 if (do_exitproc != 0) { 2127 time = hz / 10; 2128 } else { 2129 time = ttspeedtab(tp->t_ospeed, chartimes); 2130 2131 if (time > 0) { 2132 if (time < nchar) 2133 time = nchar / time; 2134 else 2135 time = 2; 2136 } else { 2137 DPRINT((pp, DBG_START, 2138 "bad char time value! %d\n", time)); 2139 time = hz/10; 2140 } 2141 } 2142 2143 if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 2144 untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 2145 } else { 2146 pp->sp_state |= SS_LSTART; 2147 } 2148 DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 2149 timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 2150 } 2151 2152out: 2153 splx(oldspl); 2154 DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 2155} 2156 2157/* 2158 * Note: called at splsoftclock from the timeout code 2159 * This has to deal with two things... cause wakeups while waiting for 2160 * tty drains on last process exit, and call l_start at about the right 2161 * time for protocols like ppp. 2162 */ 2163static void 2164si_lstart(pp) 2165 register struct si_port *pp; 2166{ 2167 register struct tty *tp; 2168 int oldspl; 2169 2170 DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 2171 pp, pp->sp_state)); 2172 2173 oldspl = spltty(); 2174 2175 if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 2176 splx(oldspl); 2177 return; 2178 } 2179 pp->sp_state &= ~SS_LSTART; 2180 pp->sp_state |= SS_INLSTART; 2181 2182 tp = pp->sp_tty; 2183 2184 /* deal with the process exit case */ 2185 ttwwakeup(tp); 2186 2187 /* nudge protocols - eg: ppp */ 2188 (*linesw[tp->t_line].l_start)(tp); 2189 2190 pp->sp_state &= ~SS_INLSTART; 2191 splx(oldspl); 2192} 2193 2194/* 2195 * Stop output on a line. called at spltty(); 2196 */ 2197void 2198sistop(tp, rw) 2199 register struct tty *tp; 2200 int rw; 2201{ 2202 volatile struct si_channel *ccbp; 2203 struct si_port *pp; 2204 2205 pp = TP2PP(tp); 2206 ccbp = pp->sp_ccb; 2207 2208 DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 2209 2210 /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 2211 if (rw & FWRITE) { 2212 /* what level are we meant to be flushing anyway? */ 2213 if (tp->t_state & TS_BUSY) { 2214 si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 2215 tp->t_state &= ~TS_BUSY; 2216 ttwwakeup(tp); /* Bruce???? */ 2217 } 2218 } 2219#if 1 /* XXX: this doesn't work right yet.. */ 2220 /* XXX: this may have been failing because we used to call l_rint() 2221 * while we were looping based on these two counters. Now, we collect 2222 * the data and then loop stuffing it into l_rint(), making this 2223 * useless. Should we cause this to blow away the staging buffer? 2224 */ 2225 if (rw & FREAD) { 2226 ccbp->hi_rxopos = ccbp->hi_rxipos; 2227 } 2228#endif 2229} 2230 2231/* 2232 * Issue a command to the Z280 host card CPU. 2233 */ 2234 2235static void 2236si_command(pp, cmd, waitflag) 2237 struct si_port *pp; /* port control block (local) */ 2238 int cmd; 2239 int waitflag; 2240{ 2241 int oldspl; 2242 volatile struct si_channel *ccbp = pp->sp_ccb; 2243 int x; 2244 2245 DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 2246 pp, cmd, waitflag, ccbp->hi_stat)); 2247 2248 oldspl = spltty(); /* Keep others out */ 2249 2250 /* wait until it's finished what it was doing.. */ 2251 while((x = ccbp->hi_stat) != IDLE_OPEN && 2252 x != IDLE_CLOSE && 2253 x != cmd) { 2254 if (in_intr) { /* Prevent sleep in intr */ 2255 DPRINT((pp, DBG_PARAM, 2256 "cmd intr collision - completing %d\trequested %d\n", 2257 x, cmd)); 2258 splx(oldspl); 2259 return; 2260 } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 2261 "sicmd1", 1)) { 2262 splx(oldspl); 2263 return; 2264 } 2265 } 2266 /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 2267 2268 /* if there was a pending command, cause a state-change wakeup */ 2269 if (pp->sp_pend != IDLE_OPEN) { 2270 switch(pp->sp_pend) { 2271 case LOPEN: 2272 case MPEND: 2273 case MOPEN: 2274 case CONFIG: 2275 wakeup(&pp->sp_state); 2276 break; 2277 default: 2278 break; 2279 } 2280 } 2281 2282 pp->sp_pend = cmd; /* New command pending */ 2283 ccbp->hi_stat = cmd; /* Post it */ 2284 2285 if (waitflag) { 2286 if (in_intr) { /* If in interrupt handler */ 2287 DPRINT((pp, DBG_PARAM, 2288 "attempt to sleep in si_intr - cmd req %d\n", 2289 cmd)); 2290 splx(oldspl); 2291 return; 2292 } else while(ccbp->hi_stat != IDLE_OPEN) { 2293 if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 2294 "sicmd2", 0)) 2295 break; 2296 } 2297 } 2298 splx(oldspl); 2299} 2300 2301static void 2302si_disc_optim(tp, t, pp) 2303 struct tty *tp; 2304 struct termios *t; 2305 struct si_port *pp; 2306{ 2307 /* 2308 * XXX can skip a lot more cases if Smarts. Maybe 2309 * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 2310 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 2311 */ 2312 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 2313 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 2314 && (!(t->c_iflag & PARMRK) 2315 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 2316 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 2317 && linesw[tp->t_line].l_rint == ttyinput) 2318 tp->t_state |= TS_CAN_BYPASS_L_RINT; 2319 else 2320 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2321 2322 /* 2323 * Prepare to reduce input latency for packet 2324 * discplines with a end of packet character. 2325 */ 2326 if (tp->t_line == SLIPDISC) 2327 pp->sp_hotchar = 0xc0; 2328 else if (tp->t_line == PPPDISC) 2329 pp->sp_hotchar = 0x7e; 2330 else 2331 pp->sp_hotchar = 0; 2332 2333 DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 2334 (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 2335 pp->sp_hotchar)); 2336} 2337 2338 2339#ifdef SI_DEBUG 2340 2341static void 2342#ifdef __STDC__ 2343si_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 2344#else 2345si_dprintf(pp, flags, fmt, va_alist) 2346 struct si_port *pp; 2347 int flags; 2348 char *fmt; 2349#endif 2350{ 2351 va_list ap; 2352 2353 if ((pp == NULL && (si_debug&flags)) || 2354 (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 2355 if (pp != NULL) 2356 printf("%ci%d(%d): ", 's', 2357 (int)SI_CARD(pp->sp_tty->t_dev), 2358 (int)SI_PORT(pp->sp_tty->t_dev)); 2359 va_start(ap, fmt); 2360 vprintf(fmt, ap); 2361 va_end(ap); 2362 } 2363} 2364 2365static char * 2366si_mctl2str(cmd) 2367 enum si_mctl cmd; 2368{ 2369 switch (cmd) { 2370 case GET: return("GET"); 2371 case SET: return("SET"); 2372 case BIS: return("BIS"); 2373 case BIC: return("BIC"); 2374 } 2375 return("BAD"); 2376} 2377 2378#endif /* DEBUG */ 2379 2380 2381 2382static si_devsw_installed = 0; 2383 2384static void si_drvinit(void *unused) 2385{ 2386 dev_t dev; 2387 2388 if( ! si_devsw_installed ) { 2389 dev = makedev(CDEV_MAJOR, 0); 2390 cdevsw_add(&dev,&si_cdevsw, NULL); 2391 si_devsw_installed = 1; 2392 } 2393} 2394 2395SYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 2396 2397