si.c revision 13630
182498Sroberto/* 282498Sroberto * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 382498Sroberto * 482498Sroberto * Copyright (C) 1990, 1992 Specialix International, 582498Sroberto * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 682498Sroberto * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> 782498Sroberto * 8285612Sdelphij * Originally derived from: SunOS 4.x version 982498Sroberto * Ported from BSDI version to FreeBSD by Peter Wemm. 10285612Sdelphij * 1182498Sroberto * Redistribution and use in source and binary forms, with or without 12132451Sroberto * modification, are permitted provided that the following conditions 1382498Sroberto * are met: 1482498Sroberto * 1. Redistributions of source code must retain the above copyright 1582498Sroberto * notices, this list of conditions and the following disclaimer. 1682498Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1782498Sroberto * notices, this list of conditions and the following disclaimer in the 18132451Sroberto * documentation and/or other materials provided with the distribution. 1982498Sroberto * 3. All advertising materials mentioning features or use of this software 20285612Sdelphij * must display the following acknowledgement: 21285612Sdelphij * This product includes software developed by Andy Rutter of 22285612Sdelphij * Advanced Methods and Tools Ltd. based on original information 23285612Sdelphij * from Specialix International. 2482498Sroberto * 4. Neither the name of Advanced Methods and Tools, nor Specialix 25316722Sdelphij * International may be used to endorse or promote products derived from 26132451Sroberto * this software without specific prior written permission. 27316722Sdelphij * 28132451Sroberto * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 29132451Sroberto * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30316722Sdelphij * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 31132451Sroberto * NO EVENT SHALL THE AUTHORS BE LIABLE. 32132451Sroberto * 33316722Sdelphij * $Id: si.c,v 1.35 1996/01/16 18:13:18 phk Exp $ 34132451Sroberto */ 35310419Sdelphij 36132451Sroberto#ifndef lint 3782498Srobertostatic char si_copyright1[] = "@(#) (C) Specialix International, 1990,1992", 3882498Sroberto si_copyright2[] = "@(#) (C) Andy Rutter 1993", 3982498Sroberto si_copyright3[] = "@(#) (C) Peter Wemm 1995"; 4082498Sroberto#endif /* not lint */ 4182498Sroberto 42285612Sdelphij#include <sys/param.h> 43285612Sdelphij#include <sys/systm.h> 44285612Sdelphij#include <sys/ioctl.h> 45285612Sdelphij#include <sys/tty.h> 46285612Sdelphij#include <sys/ttydefaults.h> 47285612Sdelphij#include <sys/proc.h> 48285612Sdelphij#include <sys/conf.h> 49285612Sdelphij#include <sys/file.h> 50285612Sdelphij#include <sys/uio.h> 51285612Sdelphij#include <sys/dkstat.h> 52285612Sdelphij#include <sys/kernel.h> 53285612Sdelphij#include <sys/syslog.h> 54285612Sdelphij#include <sys/malloc.h> 55285612Sdelphij#include <sys/devconf.h> 56285612Sdelphij#ifdef DEVFS 57285612Sdelphij#include <sys/devfsext.h> 58285612Sdelphij#endif /*DEVFS*/ 59285612Sdelphij 60285612Sdelphij#include <machine/clock.h> 61285612Sdelphij 62285612Sdelphij#include <vm/vm.h> 63285612Sdelphij#include <vm/vm_param.h> 64285612Sdelphij#include <vm/pmap.h> 65285612Sdelphij 66285612Sdelphij#include <i386/isa/icu.h> 67285612Sdelphij#include <i386/isa/isa.h> 68285612Sdelphij#include <i386/isa/isa_device.h> 69132451Sroberto 7082498Sroberto#include <i386/isa/sireg.h> 71132451Sroberto#include <machine/si.h> 72132451Sroberto#include <machine/stdarg.h> 73132451Sroberto 7482498Sroberto#include "si.h" 75132451Sroberto 76132451Sroberto/* 77132451Sroberto * This device driver is designed to interface the Specialix International 78285612Sdelphij * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. 79132451Sroberto * 80132451Sroberto * The controller is interfaced to the host via dual port ram 81132451Sroberto * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. 82132451Sroberto */ 83132451Sroberto 84132451Sroberto#define POLL /* turn on poller to generate buffer empty interrupt */ 85132451Sroberto#undef FASTPOLL /* turn on 100Hz poller, (XXX: NOTYET!) */ 86132451Sroberto#define SI_DEF_HWFLOW /* turn on default CRTSCTS flow control */ 87132451Sroberto#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 88132451Sroberto 89132451Srobertoenum si_mctl { GET, SET, BIS, BIC }; 90132451Sroberto 91132451Srobertostatic void si_command __P((struct si_port *, int, int)); 92132451Srobertostatic int si_modem __P((struct si_port *, enum si_mctl, int)); 93132451Srobertostatic void si_write_enable __P((struct si_port *, int)); 94132451Srobertostatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *)); 95132451Srobertostatic void si_start __P((struct tty *)); 9682498Srobertostatic void si_lstart __P((struct si_port *)); 97132451Srobertostatic void si_disc_optim __P((struct tty *tp, struct termios *t, 98132451Sroberto struct si_port *pp)); 99132451Srobertostatic void sihardclose __P((struct si_port *pp)); 100132451Srobertostatic void sidtrwakeup __P((void *chan)); 101132451Sroberto 102132451Srobertostatic int siparam __P((struct tty *, struct termios *)); 103132451Sroberto 104132451Srobertostatic void si_registerdev __P((struct isa_device *id)); 105132451Srobertostatic int siprobe __P((struct isa_device *id)); 106132451Srobertostatic int siattach __P((struct isa_device *id)); 107132451Srobertostatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 108132451Sroberto 109132451Srobertostruct isa_driver sidriver = 110132451Sroberto { siprobe, siattach, "si" }; 111132451Sroberto 112132451Sroberto 113132451Srobertostatic d_open_t siopen; 114132451Srobertostatic d_close_t siclose; 115132451Srobertostatic d_read_t siread; 116132451Srobertostatic d_write_t siwrite; 117285612Sdelphijstatic d_ioctl_t siioctl; 118285612Sdelphijstatic d_stop_t sistop; 119285612Sdelphijstatic d_devtotty_t sidevtotty; 120285612Sdelphij 121285612Sdelphij#define CDEV_MAJOR 68 122285612Sdelphijstatic struct cdevsw si_cdevsw = 123285612Sdelphij { siopen, siclose, siread, siwrite, /*68*/ 124285612Sdelphij siioctl, sistop, noreset, sidevtotty,/* si */ 125285612Sdelphij ttselect, nommap, NULL, "si", NULL, -1 }; 126285612Sdelphij 127285612Sdelphij 128285612Sdelphij#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 129285612Sdelphij 130285612Sdelphijstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 131285612Sdelphij ...)); 132285612Sdelphijstatic char *si_mctl2str __P((enum si_mctl cmd)); 133285612Sdelphij 134285612Sdelphij#define DPRINT(x) si_dprintf x 135285612Sdelphij 136285612Sdelphij#else 137285612Sdelphij#define DPRINT(x) /* void */ 138285612Sdelphij#endif 13982498Sroberto 14082498Srobertostatic int si_Nports; 141132451Srobertostatic int si_Nmodules; 14282498Srobertostatic int si_debug = 0; /* data, not bss, so it's patchable */ 143132451Sroberto 144132451Srobertostatic struct tty *si_tty; 145132451Sroberto 146281230Sdelphij/* where the firmware lives; defined in si_code.c */ 147132451Srobertoextern int si_dsize; 14882498Srobertoextern unsigned char si_download[]; 14982498Sroberto 150132451Srobertostruct si_softc { 15182498Sroberto int sc_type; /* adapter type */ 152132451Sroberto char *sc_typename; /* adapter type string */ 153285612Sdelphij 154285612Sdelphij struct si_port *sc_ports; /* port structures for this card */ 155285612Sdelphij 156285612Sdelphij caddr_t sc_paddr; /* physical addr of iomem */ 157285612Sdelphij caddr_t sc_maddr; /* kvaddr of iomem */ 15882498Sroberto int sc_nport; /* # ports on this card */ 15982498Sroberto int sc_irq; /* copy of attach irq */ 160132451Sroberto int sc_eisa_iobase; /* EISA io port address */ 16182498Sroberto int sc_eisa_irqbits; 162285612Sdelphij struct kern_devconf sc_kdc; 163285612Sdelphij#ifdef DEVFS 164285612Sdelphij struct { 165132451Sroberto void *ttyd; 166132451Sroberto void *cuaa; 167285612Sdelphij void *ttyl; 168285612Sdelphij void *ttyi; 169285612Sdelphij } devfs_token[32]; /* what is the max per card? */ 170285612Sdelphij void *control_token; 17182498Sroberto#endif 17282498Sroberto}; 173132451Srobertostatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 17482498Sroberto 175132451Sroberto#ifndef B2000 /* not standard, but the hardware knows it. */ 176132451Sroberto# define B2000 2000 177132451Sroberto#endif 178132451Srobertostatic struct speedtab bdrates[] = { 179132451Sroberto B75, CLK75, /* 0x0 */ 180132451Sroberto B110, CLK110, /* 0x1 */ 18182498Sroberto B150, CLK150, /* 0x3 */ 18282498Sroberto B300, CLK300, /* 0x4 */ 18382498Sroberto B600, CLK600, /* 0x5 */ 18482498Sroberto B1200, CLK1200, /* 0x6 */ 185285612Sdelphij B2000, CLK2000, /* 0x7 */ 186285612Sdelphij B2400, CLK2400, /* 0x8 */ 187285612Sdelphij B4800, CLK4800, /* 0x9 */ 188285612Sdelphij B9600, CLK9600, /* 0xb */ 189285612Sdelphij B19200, CLK19200, /* 0xc */ 190285612Sdelphij B38400, CLK38400, /* 0x2 (out of order!) */ 191285612Sdelphij B57600, CLK57600, /* 0xd */ 192285612Sdelphij B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 193285612Sdelphij -1, -1 194285612Sdelphij}; 195285612Sdelphij 196285612Sdelphij 197285612Sdelphij/* populated with approx character/sec rates - translated at card 198285612Sdelphij * initialisation time to chars per tick of the clock */ 199285612Sdelphijstatic int done_chartimes = 0; 200316722Sdelphijstatic struct speedtab chartimes[] = { 201285612Sdelphij B75, 8, 202285612Sdelphij B110, 11, 203285612Sdelphij B150, 15, 204285612Sdelphij B300, 30, 205285612Sdelphij B600, 60, 206285612Sdelphij B1200, 120, 207285612Sdelphij B2000, 200, 208285612Sdelphij B2400, 240, 209289997Sglebius B4800, 480, 21082498Sroberto B9600, 960, 211132451Sroberto B19200, 1920, 212132451Sroberto B38400, 3840, 213132451Sroberto B57600, 5760, 214132451Sroberto B115200, 11520, 215132451Sroberto -1, -1 216132451Sroberto}; 21782498Srobertostatic volatile int in_intr = 0; /* Inside interrupt handler? */ 21882498Sroberto 21982498Srobertostatic int si_default_rate = TTYDEF_SPEED; 22082498Srobertostatic int si_default_iflag = 0; 22182498Srobertostatic int si_default_oflag = 0; 22282498Srobertostatic int si_default_lflag = 0; 22382498Sroberto#ifdef SI_DEF_HWFLOW 22482498Srobertostatic int si_default_cflag = TTYDEF_CFLAG | CRTSCTS; 225132451Sroberto#else 226285612Sdelphijstatic int si_default_cflag = TTYDEF_CFLAG; 22782498Sroberto#endif 228132451Sroberto 22982498Sroberto#ifdef POLL 230285612Sdelphij#define POLL_INTERVAL (hz/2) 231285612Sdelphijstatic int init_finished = 0; 232132451Srobertostatic int fastpoll = 0; 233132451Srobertostatic void si_poll __P((void *)); 234132451Sroberto#endif 23582498Sroberto 23682498Sroberto/* 237310419Sdelphij * Array of adapter types and the corresponding RAM size. The order of 238132451Sroberto * entries here MUST match the ordinal of the adapter type. 239132451Sroberto */ 240132451Srobertostatic char *si_type[] = { 241132451Sroberto "EMPTY", 24282498Sroberto "SIHOST", 243182007Sroberto "SI2", /* MCA */ 244182007Sroberto "SIHOST2", 245182007Sroberto "SIEISA", 24682498Sroberto}; 24782498Sroberto 24882498Sroberto 24982498Srobertostatic struct kern_devconf si_kdc[NSI] = { { 250132451Sroberto 0, 0, 0, /* filled in by dev_attach */ 251285612Sdelphij "si", 0, { MDDT_ISA, 0, "tty" }, 252132451Sroberto isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 253285612Sdelphij &kdc_isa0, /* parent */ 254285612Sdelphij 0, /* parent data */ 255132451Sroberto DC_UNCONFIGURED, /* state */ 256132451Sroberto "Specialix SI/XIO Host adapter", 257132451Sroberto DC_CLS_SERIAL, /* class */ 258132451Sroberto} }; 259182007Sroberto 260132451Srobertostatic void 261285612Sdelphijsi_registerdev(id) 262132451Sroberto struct isa_device *id; 263285612Sdelphij{ 264132451Sroberto if (id->id_unit != 0) { 265132451Sroberto si_kdc[id->id_unit] = si_kdc[0]; /* struct copy */ 266132451Sroberto } 267132451Sroberto si_kdc[id->id_unit].kdc_unit = id->id_unit; 268132451Sroberto si_kdc[id->id_unit].kdc_isa = id; 269132451Sroberto si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED; 270310419Sdelphij dev_attach(&si_kdc[id->id_unit]); 271330567Sgordon} 272330567Sgordon 273330567Sgordon/* Look for a valid board at the given mem addr */ 274330567Sgordonstatic int 275330567Sgordonsiprobe(id) 276310419Sdelphij struct isa_device *id; 277330567Sgordon{ 278310419Sdelphij struct si_softc *sc; 279310419Sdelphij int type; 280310419Sdelphij u_int i, ramsize; 281132451Sroberto volatile BYTE was, *ux; 28282498Sroberto volatile unsigned char *maddr; 28382498Sroberto unsigned char *paddr; 284294569Sdelphij 28582498Sroberto si_registerdev(id); 28682498Sroberto 287285612Sdelphij maddr = id->id_maddr; /* virtual address... */ 288132451Sroberto paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 289285612Sdelphij 290285612Sdelphij DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 29182498Sroberto id->id_unit, id->id_maddr, paddr)); 29282498Sroberto 29382498Sroberto /* 29482498Sroberto * this is a lie, but it's easier than trying to handle caching 29582498Sroberto * and ram conflicts in the >1M and <16M region. 29682498Sroberto */ 29782498Sroberto if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 298182007Sroberto (caddr_t)paddr >= (caddr_t)IOM_END) { 299182007Sroberto printf("si%d: iomem (%lx) out of range\n", 300285612Sdelphij id->id_unit, (long)paddr); 301182007Sroberto return(0); 30282498Sroberto } 30382498Sroberto 30482498Sroberto if (id->id_unit >= NSI) { 30582498Sroberto /* THIS IS IMPOSSIBLE */ 30682498Sroberto return(0); 30782498Sroberto } 308182007Sroberto 30982498Sroberto if (((u_int)paddr & 0x7fff) != 0) { 31082498Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 31182498Sroberto "si%d: iomem (%x) not on 32k boundary\n", 31282498Sroberto id->id_unit, paddr)); 31382498Sroberto return(0); 314310419Sdelphij } 315132451Sroberto 31682498Sroberto 317132451Sroberto for (i=0; i < NSI; i++) { 318132451Sroberto if ((sc = &si_softc[i]) == NULL) 319132451Sroberto continue; 320285612Sdelphij if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 321182007Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 322132451Sroberto "si%d: iomem (%x) already configured to si%d\n", 32382498Sroberto id->id_unit, sc->sc_paddr, i)); 324182007Sroberto return(0); 325285612Sdelphij } 326182007Sroberto } 32782498Sroberto 32882498Sroberto#if NEISA > 0 32982498Sroberto if (id->id_iobase > 0x0fff) { /* EISA card */ 330132451Sroberto int irq, port; 33182498Sroberto unsigned long base; 332285612Sdelphij int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, 333285612Sdelphij IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 }; 33482498Sroberto 33582498Sroberto port = id->id_iobase; 33682498Sroberto base = (inb(port+1) << 24) | (inb(port) << 16); 33782498Sroberto irq = ((inb(port+2) >> 4) & 0xf); 33882498Sroberto 33982498Sroberto id->id_irq = eisa_irqs[irq]; 340285612Sdelphij 341285612Sdelphij DPRINT((0, DBG_AUTOBOOT, 342285612Sdelphij "si%d: EISA base %x, irq %x, id_irq %x, port %x\n", 343285612Sdelphij id->id_unit, base, irq, id->id_irq, port)); 34482498Sroberto 34582498Sroberto if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0) 34682498Sroberto goto bad_irq; 34782498Sroberto 34882498Sroberto id->id_iobase &= 0xf000; 34982498Sroberto id->id_iosize = 0x0fff; 35082498Sroberto 35182498Sroberto type = EISA; 35282498Sroberto outb(p+2, (BYTE)irq << 4); 35382498Sroberto 35482498Sroberto sc->sc_eisa_iobase = p; 35582498Sroberto sc->sc_eisa_irqbits = irq << 4; 356182007Sroberto ramsize = SIEISA_RAMSIZE; 357285612Sdelphij goto got_card; 35882498Sroberto } 35982498Sroberto#endif 36082498Sroberto 361132451Sroberto /* Is there anything out there? (0x17 is just an arbitrary number) */ 36282498Sroberto *maddr = 0x17; 36382498Sroberto if (*maddr != 0x17) { 36482498Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 36582498Sroberto "si%d: 0x17 check fail at phys 0x%x\n", 366285612Sdelphij id->id_unit, paddr)); 367182007Srobertofail: 36882498Sroberto return(0); 369285612Sdelphij } 37082498Sroberto /* 37182498Sroberto * OK, now to see if whatever responded is really an SI card. 37282498Sroberto * Try for a MK II first (SIHOST2) 37382498Sroberto */ 37482498Sroberto for (i=SIPLSIG; i<SIPLSIG+8; i++) 37582498Sroberto if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 376132451Sroberto goto try_mk1; 377132451Sroberto 37882498Sroberto /* It must be an SIHOST2 */ 379132451Sroberto *(maddr + SIPLRESET) = 0; 380132451Sroberto *(maddr + SIPLIRQCLR) = 0; 381132451Sroberto *(maddr + SIPLIRQSET) = 0x10; 382132451Sroberto type = SIHOST2; 38382498Sroberto ramsize = SIHOST2_RAMSIZE; 38482498Sroberto goto got_card; 385132451Sroberto 386132451Sroberto /* 387132451Sroberto * Its not a MK II, so try for a MK I (SIHOST) 388132451Sroberto */ 389182007Srobertotry_mk1: 390132451Sroberto *(maddr+SIRESET) = 0x0; /* reset the card */ 391132451Sroberto *(maddr+SIINTCL) = 0x0; /* clear int */ 392310419Sdelphij *(maddr+SIRAM) = 0x17; 393310419Sdelphij if (*(maddr+SIRAM) != (BYTE)0x17) 394310419Sdelphij goto fail; 395310419Sdelphij *(maddr+0x7ff8) = 0x17; 396310419Sdelphij if (*(maddr+0x7ff8) != (BYTE)0x17) { 397289997Sglebius DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 398132451Sroberto "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 399285612Sdelphij id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 400285612Sdelphij goto fail; 401310419Sdelphij } 402132451Sroberto 403285612Sdelphij /* It must be an SIHOST (maybe?) - there must be a better way XXXX */ 404285612Sdelphij type = SIHOST; 405285612Sdelphij ramsize = SIHOST_RAMSIZE; 406182007Sroberto 40782498Srobertogot_card: 40882498Sroberto DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 40982498Sroberto id->id_unit, type)); 41082498Sroberto /* Try the acid test */ 41182498Sroberto ux = (BYTE *)(maddr + SIRAM); 41282498Sroberto for (i=0; i<ramsize; i++, ux++) 41382498Sroberto *ux = (BYTE)(i&0xff); 41482498Sroberto ux = (BYTE *)(maddr + SIRAM); 41582498Sroberto for (i=0; i<ramsize; i++, ux++) { 41682498Sroberto if ((was = *ux) != (BYTE)(i&0xff)) { 41782498Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 418132451Sroberto "si%d: match fail at phys 0x%x, was %x should be %x\n", 41982498Sroberto id->id_unit, paddr+i, was, i&0xff)); 420285612Sdelphij goto fail; 421285612Sdelphij } 422285612Sdelphij } 423285612Sdelphij 424285612Sdelphij /* clear out the RAM */ 42582498Sroberto ux = (BYTE *)(maddr + SIRAM); 426132451Sroberto for (i=0; i<ramsize; i++) 42782498Sroberto *ux++ = 0; 42882498Sroberto ux = (BYTE *)(maddr + SIRAM); 42982498Sroberto for (i=0; i<ramsize; i++) { 43082498Sroberto if ((was = *ux++) != 0) { 43182498Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 432132451Sroberto "si%d: clear fail at phys 0x%x, was %x\n", 433132451Sroberto id->id_unit, paddr+i, was)); 434132451Sroberto goto fail; 435132451Sroberto } 436285612Sdelphij } 437289997Sglebius 438132451Sroberto /* 439132451Sroberto * Success, we've found a valid board, now fill in 440132451Sroberto * the adapter structure. 441132451Sroberto */ 442132451Sroberto switch (type) { 443132451Sroberto case SIHOST2: 444132451Sroberto if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 445132451Srobertobad_irq: 446132451Sroberto DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 447182007Sroberto "si%d: bad IRQ value - %d\n", 448132451Sroberto id->id_unit, id->id_irq)); 449285612Sdelphij return(0); 450132451Sroberto } 45182498Sroberto id->id_msize = SIHOST2_MEMSIZE; 45282498Sroberto break; 45382498Sroberto case SIHOST: 454132451Sroberto if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) { 455132451Sroberto goto bad_irq; 456132451Sroberto } 457132451Sroberto id->id_msize = SIHOST_MEMSIZE; 458132451Sroberto break; 459132451Sroberto case SIEISA: 460132451Sroberto id->id_msize = SIEISA_MEMSIZE; 46182498Sroberto break; 46282498Sroberto case SI2: /* MCA */ 463182007Sroberto default: 464289997Sglebius printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 465289997Sglebius return(0); 466289997Sglebius } 467289997Sglebius si_softc[id->id_unit].sc_type = type; 468289997Sglebius si_softc[id->id_unit].sc_typename = si_type[type]; 469132451Sroberto return(-1); /* -1 == found */ 470132451Sroberto} 471132451Sroberto 472132451Sroberto/* 473285612Sdelphij * Attach the device. Initialize the card. 474285612Sdelphij */ 475132451Srobertostatic int 476285612Sdelphijsiattach(id) 477132451Sroberto struct isa_device *id; 478285612Sdelphij{ 479132451Sroberto int unit = id->id_unit; 480132451Sroberto struct si_softc *sc = &si_softc[unit]; 481132451Sroberto struct si_port *pp; 482132451Sroberto volatile struct si_channel *ccbp; 483132451Sroberto volatile struct si_reg *regp; 484182007Sroberto volatile caddr_t maddr; 485285612Sdelphij struct si_module *modp; 486132451Sroberto struct tty *tp; 487132451Sroberto struct speedtab *spt; 488132451Sroberto int nmodule, nport, x, y; 489289997Sglebius int uart_type; 490293650Sglebius#ifdef DEVFS 491289997Sglebius char name[32]; 492293650Sglebius#endif 493289997Sglebius 494289997Sglebius DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 495289997Sglebius 496289997Sglebius sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 497289997Sglebius sc->sc_maddr = id->id_maddr; 498289997Sglebius sc->sc_irq = id->id_irq; 499289997Sglebius 500289997Sglebius sc->sc_ports = NULL; /* mark as uninitialised */ 501132451Sroberto 502132451Sroberto maddr = sc->sc_maddr; 503132451Sroberto 504281230Sdelphij /* 505281230Sdelphij * OK, now lets download the firmware and try and boot the CPU.. 506281230Sdelphij */ 507281230Sdelphij 508281230Sdelphij DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 509281230Sdelphij id->id_unit, si_dsize)); 510132451Sroberto bcopy(si_download, maddr, si_dsize); 51182498Sroberto 51282498Sroberto switch (sc->sc_type) { 51382498Sroberto case SIEISA: 514132451Sroberto#if NEISA > 0 515132451Sroberto /* modify the Z280 firmware to tell it that it's on an EISA */ 516132451Sroberto *(maddr+0x42) = 1; 517132451Sroberto outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4); 518132451Sroberto (void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */ 519132451Sroberto break; 520182007Sroberto#endif /* fall-through if not EISA */ 521132451Sroberto case SI2: 52282498Sroberto /* 523132451Sroberto * must get around to converting the code for 524132451Sroberto * these one day, if FreeBSD ever supports it. 525132451Sroberto */ 526285612Sdelphij return 0; 527285612Sdelphij case SIHOST: 528285612Sdelphij *(maddr+SIRESET_CL) = 0; 529285612Sdelphij *(maddr+SIINTCL_CL) = 0; 530285612Sdelphij break; 531285612Sdelphij case SIHOST2: 532132451Sroberto *(maddr+SIPLRESET) = 0x10; 533285612Sdelphij switch (sc->sc_irq) { 534182007Sroberto case IRQ11: 535182007Sroberto *(maddr+SIPLIRQ11) = 0x10; 536182007Sroberto break; 537285612Sdelphij case IRQ12: 538285612Sdelphij *(maddr+SIPLIRQ12) = 0x10; 539285612Sdelphij break; 540285612Sdelphij case IRQ15: 541285612Sdelphij *(maddr+SIPLIRQ15) = 0x10; 542289997Sglebius break; 543285612Sdelphij } 544132451Sroberto *(maddr+SIPLIRQCLR) = 0x10; 545132451Sroberto break; 546285612Sdelphij } 547132451Sroberto 548132451Sroberto DELAY(1000000); /* wait around for a second */ 549132451Sroberto 55082498Sroberto regp = (struct si_reg *)maddr; 551132451Sroberto y = 0; 552132451Sroberto /* wait max of 5 sec for init OK */ 553132451Sroberto while (regp->initstat == 0 && y++ < 10) { 554182007Sroberto DELAY(500000); 555132451Sroberto } 556285612Sdelphij switch (regp->initstat) { 557285612Sdelphij case 0: 558285612Sdelphij printf("si%d: startup timeout - aborting\n", unit); 559132451Sroberto sc->sc_type = SIEMPTY; 560285612Sdelphij return 0; 561285612Sdelphij case 1: 562182007Sroberto /* set throttle to 125 intr per second */ 563281230Sdelphij regp->int_count = 25000; 564132451Sroberto /* rx intr max of 25 timer per second */ 565132451Sroberto regp->rx_int_count = 4; 56682498Sroberto regp->int_pending = 0; /* no intr pending */ 567285612Sdelphij regp->int_scounter = 0; /* reset counter */ 568285612Sdelphij break; 569285612Sdelphij case 0xff: 570285612Sdelphij /* 571132451Sroberto * No modules found, so give up on this one. 572132451Sroberto */ 573285612Sdelphij printf("si%d: %s - no ports found\n", unit, 574285612Sdelphij si_type[sc->sc_type]); 575285612Sdelphij return 0; 576285612Sdelphij default: 577285612Sdelphij printf("si%d: Z280 version error - initstat %x\n", 578285612Sdelphij unit, regp->initstat); 579132451Sroberto return 0; 580132451Sroberto } 581182007Sroberto 582132451Sroberto /* 583182007Sroberto * First time around the ports just count them in order 584285612Sdelphij * to allocate some memory. 585285612Sdelphij */ 586285612Sdelphij nport = 0; 587182007Sroberto modp = (struct si_module *)(maddr + 0x80); 588182007Sroberto for (;;) { 589285612Sdelphij DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 590285612Sdelphij switch (modp->sm_type & (~MMASK)) { 591182007Sroberto case M232: 592285612Sdelphij case M422: 593285612Sdelphij DPRINT((0, DBG_DOWNLOAD, 594285612Sdelphij "si%d: Found 232/422 module, %d ports\n", 595285612Sdelphij unit, (int)(modp->sm_type & MMASK))); 596285612Sdelphij 597285612Sdelphij /* this is a firmware issue */ 598285612Sdelphij if (si_Nports == SI_MAXPORTPERCARD) { 599285612Sdelphij printf("si%d: extra ports ignored\n", unit); 600285612Sdelphij continue; 601132451Sroberto } 602132451Sroberto 603132451Sroberto x = modp->sm_type & MMASK; 604182007Sroberto nport += x; 605182007Sroberto si_Nports += x; 606132451Sroberto si_Nmodules++; 607132451Sroberto break; 608132451Sroberto default: 609132451Sroberto printf("si%d: unknown module type %d\n", 610182007Sroberto unit, modp->sm_type); 611132451Sroberto break; 612132451Sroberto } 613182007Sroberto if (modp->sm_next == 0) 614132451Sroberto break; 615132451Sroberto modp = (struct si_module *) 616132451Sroberto (maddr + (unsigned)(modp->sm_next & 0x7fff)); 617285612Sdelphij } 618285612Sdelphij sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 619285612Sdelphij M_DEVBUF, M_NOWAIT); 620132451Sroberto if (sc->sc_ports == 0) { 621285612Sdelphijmem_fail: 622285612Sdelphij printf("si%d: fail to malloc memory for port structs\n", 623285612Sdelphij unit); 624285612Sdelphij return 0; 625285612Sdelphij } 626285612Sdelphij bzero(sc->sc_ports, sizeof(struct si_port) * nport); 627132451Sroberto sc->sc_nport = nport; 628132451Sroberto 629285612Sdelphij /* 630285612Sdelphij * allocate tty structures for ports 631132451Sroberto */ 632132451Sroberto tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 633132451Sroberto if (tp == 0) 634285612Sdelphij goto mem_fail; 635285612Sdelphij bzero(tp, sizeof(*tp) * nport); 636285612Sdelphij si_tty = tp; 637285612Sdelphij 638285612Sdelphij /* mark the device state as attached */ 639285612Sdelphij si_kdc[unit].kdc_state = DC_BUSY; 640285612Sdelphij 641132451Sroberto /* 642285612Sdelphij * Scan round the ports again, this time initialising. 64382498Sroberto */ 64482498Sroberto pp = sc->sc_ports; 64582498Sroberto nmodule = 0; 646132451Sroberto modp = (struct si_module *)(maddr + 0x80); 647132451Sroberto uart_type = 0; 648132451Sroberto for (;;) { 649132451Sroberto switch (modp->sm_type & (~MMASK)) { 650132451Sroberto case M232: 65182498Sroberto case M422: 652132451Sroberto nmodule++; 653132451Sroberto nport = (modp->sm_type & MMASK); 654132451Sroberto ccbp = (struct si_channel *)((char *)modp+0x100); 655285612Sdelphij if (uart_type == 0) 656132451Sroberto uart_type = ccbp->type; 657285612Sdelphij for (x = 0; x < nport; x++, pp++, ccbp++) { 658285612Sdelphij pp->sp_ccb = ccbp; /* save the address */ 659285612Sdelphij pp->sp_tty = tp++; 660132451Sroberto pp->sp_pend = IDLE_CLOSE; 661132451Sroberto pp->sp_state = 0; /* internal flag */ 662132451Sroberto pp->sp_dtr_wait = 3 * hz; 663132451Sroberto pp->sp_iin.c_iflag = si_default_iflag; 664132451Sroberto pp->sp_iin.c_oflag = si_default_oflag; 665132451Sroberto pp->sp_iin.c_cflag = si_default_cflag; 666132451Sroberto pp->sp_iin.c_lflag = si_default_lflag; 667285612Sdelphij termioschars(&pp->sp_iin); 668285612Sdelphij pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 669285612Sdelphij si_default_rate; 670132451Sroberto pp->sp_iout = pp->sp_iin; 671285612Sdelphij } 672285612Sdelphij break; 673132451Sroberto default: 674285612Sdelphij break; 675285612Sdelphij } 676285612Sdelphij if (modp->sm_next == 0) { 677132451Sroberto printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", 678132451Sroberto unit, 679182007Sroberto sc->sc_typename, 680132451Sroberto sc->sc_nport, 681132451Sroberto nmodule, 682132451Sroberto uart_type); 683132451Sroberto break; 684132451Sroberto } 685132451Sroberto modp = (struct si_module *) 686285612Sdelphij (maddr + (unsigned)(modp->sm_next & 0x7fff)); 687285612Sdelphij } 688285612Sdelphij if (done_chartimes == 0) { 689132451Sroberto for (spt = chartimes ; spt->sp_speed != -1; spt++) { 690132451Sroberto if ((spt->sp_code /= hz) == 0) 69182498Sroberto spt->sp_code = 1; 692182007Sroberto } 693285612Sdelphij done_chartimes = 1; 694285612Sdelphij } 695285612Sdelphij 696285612Sdelphij#ifdef DEVFS 697132451Sroberto/* path name devsw minor type uid gid perm*/ 698132451Sroberto for ( x = 0; x < sc->sc_nport; x++ ) { 699132451Sroberto y = x + 1; /* For sync with the manuals that start at 1 */ 700285612Sdelphij sc->devfs_token[x].ttyd = devfs_add_devswf( 70182498Sroberto &si_cdevsw, x, 70282498Sroberto DV_CHR, 0, 0, 0600, "ttyA%02d", y); 70382498Sroberto sc->devfs_token[x].cuaa = devfs_add_devswf( 704285612Sdelphij &si_cdevsw, x + 128, 705285612Sdelphij DV_CHR, 0, 0, 0600, "cuaA%02d", y); 706285612Sdelphij sc->devfs_token[x].ttyi = devfs_add_devswf( 707285612Sdelphij &si_cdevsw, x + 0x10000, 708285612Sdelphij DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 709285612Sdelphij sc->devfs_token[x].ttyl = devfs_add_devswf( 710132451Sroberto &si_cdevsw, x + 0x20000, 71182498Sroberto DV_CHR, 0, 0, 0600, "ttylA%02d", y); 712132451Sroberto } 71382498Sroberto sc->control_token = devfs_add_devsw("/", "si_control", 714132451Sroberto &si_cdevsw, 0x40000, 715285612Sdelphij DV_CHR, 0, 0, 0600); 716132451Sroberto#endif 717132451Sroberto return (1); 718132451Sroberto} 719132451Sroberto 720132451Srobertostatic int 72182498Srobertosiopen(dev, flag, mode, p) 722285612Sdelphij dev_t dev; 723285612Sdelphij int flag, mode; 724132451Sroberto struct proc *p; 725132451Sroberto{ 726285612Sdelphij int oldspl, error; 727285612Sdelphij int card, port; 72882498Sroberto register struct si_softc *sc; 729132451Sroberto register struct tty *tp; 730132451Sroberto volatile struct si_channel *ccbp; 731132451Sroberto struct si_port *pp; 732285612Sdelphij int mynor = minor(dev); 733182007Sroberto 734285612Sdelphij /* quickly let in /dev/si_control */ 735285612Sdelphij if (IS_CONTROLDEV(mynor)) { 736132451Sroberto if (error = suser(p->p_ucred, &p->p_acflag)) 737285612Sdelphij return(error); 73882498Sroberto return(0); 73982498Sroberto } 74082498Sroberto 741132451Sroberto card = SI_CARD(mynor); 742132451Sroberto if (card >= NSI) 743132451Sroberto return (ENXIO); 744132451Sroberto sc = &si_softc[card]; 745132451Sroberto 746132451Sroberto if (sc->sc_type == SIEMPTY) { 747132451Sroberto DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 748132451Sroberto card, sc->sc_typename)); 74982498Sroberto return(ENXIO); 750132451Sroberto } 751132451Sroberto 752132451Sroberto port = SI_PORT(mynor); 753285612Sdelphij if (port >= sc->sc_nport) { 754132451Sroberto DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 755132451Sroberto card, sc->sc_nport)); 756132451Sroberto return(ENXIO); 757132451Sroberto } 758132451Sroberto 759132451Sroberto#ifdef POLL 760285612Sdelphij /* 761285612Sdelphij * We've now got a device, so start the poller. 762132451Sroberto */ 763132451Sroberto if (init_finished == 0) { 764285612Sdelphij timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 765285612Sdelphij init_finished = 1; 766132451Sroberto } 767132451Sroberto#endif 768132451Sroberto 769132451Sroberto /* initial/lock device */ 770285612Sdelphij if (IS_STATE(mynor)) { 771182007Sroberto return(0); 772285612Sdelphij } 773285612Sdelphij 774132451Sroberto pp = sc->sc_ports + port; 775285612Sdelphij tp = pp->sp_tty; /* the "real" tty */ 77682498Sroberto ccbp = pp->sp_ccb; /* Find control block */ 77782498Sroberto DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 77882498Sroberto dev, flag, mode, p)); 779285612Sdelphij 780285612Sdelphij oldspl = spltty(); /* Keep others out */ 781285612Sdelphij error = 0; 782285612Sdelphij 783285612Sdelphijopen_top: 784285612Sdelphij while (pp->sp_state & SS_DTR_OFF) { 785285612Sdelphij error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 78682498Sroberto if (error != 0) 787132451Sroberto goto out; 788132451Sroberto } 789132451Sroberto 790285612Sdelphij if (tp->t_state & TS_ISOPEN) { 791132451Sroberto /* 792132451Sroberto * The device is open, so everything has been initialised. 793132451Sroberto * handle conflicts. 794132451Sroberto */ 795132451Sroberto if (IS_CALLOUT(mynor)) { 796132451Sroberto if (!pp->sp_active_out) { 797285612Sdelphij error = EBUSY; 798285612Sdelphij goto out; 799132451Sroberto } 800132451Sroberto } else { 801285612Sdelphij if (pp->sp_active_out) { 802285612Sdelphij if (flag & O_NONBLOCK) { 803132451Sroberto error = EBUSY; 804132451Sroberto goto out; 805132451Sroberto } 806132451Sroberto error = tsleep(&pp->sp_active_out, 807285612Sdelphij TTIPRI|PCATCH, "sibi", 0); 808182007Sroberto if (error != 0) 809285612Sdelphij goto out; 810285612Sdelphij goto open_top; 811132451Sroberto } 812285612Sdelphij } 813132451Sroberto if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 81482498Sroberto DPRINT((pp, DBG_OPEN|DBG_FAIL, 815132451Sroberto "already open and EXCLUSIVE set\n")); 816132451Sroberto error = EBUSY; 817132451Sroberto goto out; 818132451Sroberto } 819132451Sroberto } else { 820132451Sroberto /* 821132451Sroberto * The device isn't open, so there are no conflicts. 822132451Sroberto * Initialize it. Avoid sleep... :-) 82382498Sroberto */ 824285612Sdelphij DPRINT((pp, DBG_OPEN, "first open\n")); 825285612Sdelphij tp->t_oproc = si_start; 826285612Sdelphij tp->t_param = siparam; 82782498Sroberto tp->t_dev = dev; 828132451Sroberto tp->t_termios = mynor & SI_CALLOUT_MASK 829132451Sroberto ? pp->sp_iout : pp->sp_iin; 830132451Sroberto 831132451Sroberto (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 83282498Sroberto 833132451Sroberto ++pp->sp_wopeners; /* in case of sleep in siparam */ 834132451Sroberto 83582498Sroberto error = siparam(tp, &tp->t_termios); 836285612Sdelphij 837310419Sdelphij --pp->sp_wopeners; 838310419Sdelphij if (error != 0) 839285612Sdelphij goto out; 840276072Sdelphij /* XXX: we should goto_top if siparam slept */ 841276072Sdelphij 842276072Sdelphij ttsetwater(tp); 843285612Sdelphij 844276072Sdelphij /* set initial DCD state */ 845132451Sroberto pp->sp_last_hi_ip = ccbp->hi_ip; 846276072Sdelphij if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 847310419Sdelphij (*linesw[tp->t_line].l_modem)(tp, 1); 848276072Sdelphij } 849276072Sdelphij } 850276072Sdelphij 851276072Sdelphij /* whoops! we beat the close! */ 852276072Sdelphij if (pp->sp_state & SS_CLOSING) { 853276072Sdelphij /* try and stop it from proceeding to bash the hardware */ 854276072Sdelphij pp->sp_state &= ~SS_CLOSING; 855276072Sdelphij } 856132451Sroberto 857132451Sroberto /* 858132451Sroberto * Wait for DCD if necessary 859132451Sroberto */ 86082498Sroberto if (!(tp->t_state & TS_CARR_ON) 86182498Sroberto && !IS_CALLOUT(mynor) 862132451Sroberto && !(tp->t_cflag & CLOCAL) 863132451Sroberto && !(flag & O_NONBLOCK)) { 864132451Sroberto ++pp->sp_wopeners; 86582498Sroberto DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 866132451Sroberto error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 867285612Sdelphij --pp->sp_wopeners; 868285612Sdelphij if (error != 0) 869285612Sdelphij goto out; 870132451Sroberto goto open_top; 871132451Sroberto } 872285612Sdelphij 873182007Sroberto error = (*linesw[tp->t_line].l_open)(dev, tp); 874285612Sdelphij si_disc_optim(tp, &tp->t_termios, pp); 875285612Sdelphij if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 876285612Sdelphij pp->sp_active_out = TRUE; 877132451Sroberto 878285612Sdelphij pp->sp_state |= SS_OPEN; /* made it! */ 87982498Sroberto 88082498Srobertoout: 88182498Sroberto splx(oldspl); 882132451Sroberto 883132451Sroberto DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 884132451Sroberto 885132451Sroberto if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 886132451Sroberto sihardclose(pp); 887132451Sroberto 888132451Sroberto return(error); 889132451Sroberto} 89082498Sroberto 891132451Srobertostatic int 89282498Srobertosiclose(dev, flag, mode, p) 893132451Sroberto dev_t dev; 894285612Sdelphij int flag, mode; 895285612Sdelphij struct proc *p; 896285612Sdelphij{ 897132451Sroberto register struct si_port *pp; 898132451Sroberto register struct tty *tp; 899285612Sdelphij int oldspl; 900132451Sroberto int error = 0; 901132451Sroberto int mynor = minor(dev); 90282498Sroberto 903285612Sdelphij if (IS_SPECIAL(mynor)) 904285612Sdelphij return(0); 905285612Sdelphij 906285612Sdelphij oldspl = spltty(); 907285612Sdelphij 908285612Sdelphij pp = MINOR2PP(mynor); 909285612Sdelphij tp = pp->sp_tty; 910285612Sdelphij 911285612Sdelphij DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 912285612Sdelphij dev, flag, mode, p, pp->sp_state)); 913285612Sdelphij 914132451Sroberto /* did we sleep and loose a race? */ 915132451Sroberto if (pp->sp_state & SS_CLOSING) { 91682498Sroberto /* error = ESOMETING? */ 917285612Sdelphij goto out; 918285612Sdelphij } 919285612Sdelphij 920132451Sroberto /* begin race detection.. */ 921132451Sroberto pp->sp_state |= SS_CLOSING; 922132451Sroberto 923132451Sroberto si_write_enable(pp, 0); /* block writes for ttywait() */ 924132451Sroberto 925132451Sroberto /* THIS MAY SLEEP IN TTYWAIT!!! */ 926132451Sroberto (*linesw[tp->t_line].l_close)(tp, flag); 927132451Sroberto 928132451Sroberto si_write_enable(pp, 1); 929132451Sroberto 930132451Sroberto /* did we sleep and somebody started another open? */ 931182007Sroberto if (!(pp->sp_state & SS_CLOSING)) { 932285612Sdelphij /* error = ESOMETING? */ 933132451Sroberto goto out; 934132451Sroberto } 935132451Sroberto /* ok. we are now still on the right track.. nuke the hardware */ 936132451Sroberto 937285612Sdelphij if (pp->sp_state & SS_LSTART) { 93882498Sroberto untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 939182007Sroberto pp->sp_state &= ~SS_LSTART; 940182007Sroberto } 941182007Sroberto 942182007Sroberto sistop(tp, FREAD | FWRITE); 943182007Sroberto 944182007Sroberto sihardclose(pp); 945182007Sroberto ttyclose(tp); 946182007Sroberto pp->sp_state &= ~SS_OPEN; 947182007Sroberto 94882498Srobertoout: 949182007Sroberto DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 950285612Sdelphij splx(oldspl); 951182007Sroberto return(error); 952182007Sroberto} 953182007Sroberto 954182007Srobertostatic void 955182007Srobertosihardclose(pp) 956182007Sroberto struct si_port *pp; 957182007Sroberto{ 958182007Sroberto int oldspl; 959182007Sroberto struct tty *tp; 960182007Sroberto volatile struct si_channel *ccbp; 961285612Sdelphij 962285612Sdelphij oldspl = spltty(); 963182007Sroberto 964285612Sdelphij tp = pp->sp_tty; 965182007Sroberto ccbp = pp->sp_ccb; /* Find control block */ 966182007Sroberto if (tp->t_cflag & HUPCL 967285612Sdelphij || !pp->sp_active_out 968285612Sdelphij && !(ccbp->hi_ip & IP_DCD) 969285612Sdelphij && !(pp->sp_iin.c_cflag && CLOCAL) 970285612Sdelphij || !(tp->t_state & TS_ISOPEN)) { 971182007Sroberto 972182007Sroberto (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 973182007Sroberto (void) si_command(pp, FCLOSE, SI_NOWAIT); 974285612Sdelphij 975182007Sroberto if (pp->sp_dtr_wait != 0) { 976182007Sroberto timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 97782498Sroberto pp->sp_state |= SS_DTR_OFF; 978285612Sdelphij } 979285612Sdelphij 980285612Sdelphij } 981285612Sdelphij pp->sp_active_out = FALSE; 98282498Sroberto wakeup((caddr_t)&pp->sp_active_out); 983285612Sdelphij wakeup(TSA_CARR_ON(tp)); 984132451Sroberto 985285612Sdelphij splx(oldspl); 986285612Sdelphij} 987285612Sdelphij 988132451Sroberto 989285612Sdelphij/* 990285612Sdelphij * called at splsoftclock()... 991285612Sdelphij */ 992132451Srobertostatic void 993132451Srobertosidtrwakeup(chan) 994285612Sdelphij void *chan; 995285612Sdelphij{ 996285612Sdelphij struct si_port *pp; 997285612Sdelphij int oldspl; 998132451Sroberto 999285612Sdelphij oldspl = spltty(); 1000285612Sdelphij 1001285612Sdelphij pp = (struct si_port *)chan; 1002285612Sdelphij pp->sp_state &= ~SS_DTR_OFF; 1003285612Sdelphij wakeup(&pp->sp_dtr_wait); 1004285612Sdelphij 1005285612Sdelphij splx(oldspl); 1006285612Sdelphij} 1007132451Sroberto 1008182007Sroberto/* 1009285612Sdelphij * User level stuff - read and write 1010285612Sdelphij */ 1011285612Sdelphijstatic int 1012285612Sdelphijsiread(dev, uio, flag) 1013132451Sroberto register dev_t dev; 1014285612Sdelphij struct uio *uio; 101582498Sroberto int flag; 101682498Sroberto{ 101782498Sroberto register struct tty *tp; 1018132451Sroberto int mynor = minor(dev); 1019132451Sroberto 1020132451Sroberto if (IS_SPECIAL(mynor)) { 1021285612Sdelphij DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 1022285612Sdelphij return(ENODEV); 102382498Sroberto } 1024182007Sroberto tp = MINOR2TP(mynor); 1025132451Sroberto DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 1026132451Sroberto "siread(%x,%x,%x)\n", dev, uio, flag)); 1027132451Sroberto return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 1028285612Sdelphij} 1029132451Sroberto 1030132451Sroberto 1031132451Srobertostatic int 103282498Srobertosiwrite(dev, uio, flag) 1033132451Sroberto dev_t dev; 1034132451Sroberto struct uio *uio; 1035132451Sroberto int flag; 1036132451Sroberto{ 1037285612Sdelphij register struct si_port *pp; 1038285612Sdelphij register struct tty *tp; 1039285612Sdelphij int error = 0; 1040285612Sdelphij int mynor = minor(dev); 1041285612Sdelphij int oldspl; 1042285612Sdelphij 1043132451Sroberto if (IS_SPECIAL(mynor)) { 1044132451Sroberto DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 1045132451Sroberto return(ENODEV); 1046182007Sroberto } 1047285612Sdelphij pp = MINOR2PP(mynor); 1048132451Sroberto tp = pp->sp_tty; 1049132451Sroberto DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 1050132451Sroberto 1051132451Sroberto oldspl = spltty(); 105282498Sroberto /* 1053132451Sroberto * If writes are currently blocked, wait on the "real" tty 1054132451Sroberto */ 1055132451Sroberto while (pp->sp_state & SS_BLOCKWRITE) { 1056285612Sdelphij pp->sp_state |= SS_WAITWRITE; 1057132451Sroberto DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 1058285612Sdelphij if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 1059285612Sdelphij "siwrite", 0)) 1060285612Sdelphij goto out; 1061285612Sdelphij } 1062182007Sroberto 1063285612Sdelphij error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 1064285612Sdelphijout: 1065132451Sroberto splx(oldspl); 1066285612Sdelphij return (error); 106782498Sroberto} 1068132451Sroberto 106982498Sroberto 107082498Srobertostatic struct tty * 107182498Srobertosidevtotty(dev_t dev) 107282498Sroberto{ 107382498Sroberto struct si_port *pp; 107482498Sroberto int mynor = minor(dev); 107582498Sroberto struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 1076132451Sroberto 1077132451Sroberto if (IS_SPECIAL(mynor)) 107882498Sroberto return(NULL); 1079132451Sroberto if (SI_PORT(mynor) >= sc->sc_nport) 1080285612Sdelphij return(NULL); 1081285612Sdelphij pp = MINOR2PP(mynor); 1082285612Sdelphij return (pp->sp_tty); 1083285612Sdelphij} 1084285612Sdelphij 1085285612Sdelphijstatic int 1086285612Sdelphijsiioctl(dev, cmd, data, flag, p) 1087285612Sdelphij dev_t dev; 108882498Sroberto int cmd; 1089132451Sroberto caddr_t data; 109082498Sroberto int flag; 1091285612Sdelphij struct proc *p; 1092132451Sroberto{ 1093285612Sdelphij struct si_port *pp; 1094132451Sroberto register struct tty *tp; 1095132451Sroberto int error; 1096132451Sroberto int mynor = minor(dev); 109782498Sroberto int oldspl; 109882498Sroberto int blocked = 0; 1099285612Sdelphij#if defined(COMPAT_43) 1100285612Sdelphij int oldcmd; 1101285612Sdelphij struct termios term; 1102132451Sroberto#endif 1103132451Sroberto 1104132451Sroberto if (IS_SI_IOCTL(cmd)) 1105132451Sroberto return(si_Sioctl(dev, cmd, data, flag, p)); 1106182007Sroberto 1107285612Sdelphij pp = MINOR2PP(mynor); 1108132451Sroberto tp = pp->sp_tty; 1109132451Sroberto 1110132451Sroberto DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", 1111132451Sroberto dev, cmd, data, flag)); 1112285612Sdelphij if (IS_STATE(mynor)) { 1113132451Sroberto struct termios *ct; 111482498Sroberto 111582498Sroberto switch (mynor & SI_STATE_MASK) { 111682498Sroberto case SI_INIT_STATE_MASK: 1117132451Sroberto ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 1118132451Sroberto break; 111982498Sroberto case SI_LOCK_STATE_MASK: 1120132451Sroberto ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 1121132451Sroberto break; 1122132451Sroberto default: 1123285612Sdelphij return (ENODEV); 1124285612Sdelphij } 1125285612Sdelphij switch (cmd) { 1126285612Sdelphij case TIOCSETA: 1127285612Sdelphij error = suser(p->p_ucred, &p->p_acflag); 1128285612Sdelphij if (error != 0) 1129285612Sdelphij return (error); 1130132451Sroberto *ct = *(struct termios *)data; 113182498Sroberto return (0); 1132285612Sdelphij case TIOCGETA: 1133285612Sdelphij *(struct termios *)data = *ct; 1134132451Sroberto return (0); 1135182007Sroberto case TIOCGETD: 1136132451Sroberto *(int *)data = TTYDISC; 113782498Sroberto return (0); 113882498Sroberto case TIOCGWINSZ: 1139132451Sroberto bzero(data, sizeof(struct winsize)); 1140132451Sroberto return (0); 1141182007Sroberto default: 114282498Sroberto return (ENOTTY); 1143285612Sdelphij } 114482498Sroberto } 1145285612Sdelphij /* 1146182007Sroberto * Do the old-style ioctl compat routines... 1147182007Sroberto */ 1148182007Sroberto#if defined(COMPAT_43) 114982498Sroberto term = tp->t_termios; 1150132451Sroberto oldcmd = cmd; 1151132451Sroberto error = ttsetcompat(tp, &cmd, data, &term); 115282498Sroberto if (error != 0) 1153132451Sroberto return (error); 1154132451Sroberto if (cmd != oldcmd) 1155132451Sroberto data = (caddr_t)&term; 1156132451Sroberto#endif 1157132451Sroberto /* 1158182007Sroberto * Do the initial / lock state business 1159285612Sdelphij */ 1160132451Sroberto if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 1161132451Sroberto int cc; 1162132451Sroberto struct termios *dt = (struct termios *)data; 1163285612Sdelphij struct termios *lt = mynor & SI_CALLOUT_MASK 1164285612Sdelphij ? &pp->sp_lout : &pp->sp_lin; 1165132451Sroberto 1166132451Sroberto dt->c_iflag = (tp->t_iflag & lt->c_iflag) 1167285612Sdelphij | (dt->c_iflag & ~lt->c_iflag); 1168285612Sdelphij dt->c_oflag = (tp->t_oflag & lt->c_oflag) 1169285612Sdelphij | (dt->c_oflag & ~lt->c_oflag); 1170285612Sdelphij dt->c_cflag = (tp->t_cflag & lt->c_cflag) 1171285612Sdelphij | (dt->c_cflag & ~lt->c_cflag); 1172285612Sdelphij dt->c_lflag = (tp->t_lflag & lt->c_lflag) 1173285612Sdelphij | (dt->c_lflag & ~lt->c_lflag); 1174285612Sdelphij for (cc = 0; cc < NCCS; ++cc) 1175285612Sdelphij if (lt->c_cc[cc] != 0) 1176285612Sdelphij dt->c_cc[cc] = tp->t_cc[cc]; 1177285612Sdelphij if (lt->c_ispeed != 0) 1178285612Sdelphij dt->c_ispeed = tp->t_ispeed; 1179285612Sdelphij if (lt->c_ospeed != 0) 1180285612Sdelphij dt->c_ospeed = tp->t_ospeed; 1181285612Sdelphij } 1182285612Sdelphij 1183285612Sdelphij /* 1184285612Sdelphij * Block user-level writes to give the ttywait() 1185285612Sdelphij * a chance to completely drain for commands 1186285612Sdelphij * that require the port to be in a quiescent state. 1187132451Sroberto */ 1188289997Sglebius switch (cmd) { 1189289997Sglebius case TIOCSETAW: case TIOCSETAF: 1190182007Sroberto case TIOCDRAIN: case TIOCSETP: 119182498Sroberto blocked++; /* block writes for ttywait() and siparam() */ 119282498Sroberto si_write_enable(pp, 0); 1193182007Sroberto } 1194182007Sroberto 1195285612Sdelphij error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1196285612Sdelphij if (error >= 0) 1197285612Sdelphij goto out; 1198285612Sdelphij 1199182007Sroberto oldspl = spltty(); 1200285612Sdelphij 1201285612Sdelphij error = ttioctl(tp, cmd, data, flag); 1202285612Sdelphij si_disc_optim(tp, &tp->t_termios, pp); 1203132451Sroberto if (error >= 0) 1204285612Sdelphij goto outspl; 1205132451Sroberto 1206182007Sroberto switch (cmd) { 1207285612Sdelphij case TIOCSBRK: 1208285612Sdelphij si_command(pp, SBREAK, SI_NOWAIT); 1209285612Sdelphij break; 1210285612Sdelphij case TIOCCBRK: 1211285612Sdelphij si_command(pp, EBREAK, SI_NOWAIT); 1212285612Sdelphij break; 1213285612Sdelphij case TIOCSDTR: 1214285612Sdelphij (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 1215132451Sroberto break; 1216182007Sroberto case TIOCCDTR: 1217182007Sroberto (void) si_modem(pp, SET, 0); 1218285612Sdelphij break; 1219285612Sdelphij case TIOCMSET: 1220285612Sdelphij (void) si_modem(pp, SET, *(int *)data); 1221182007Sroberto break; 1222285612Sdelphij case TIOCMBIS: 1223182007Sroberto (void) si_modem(pp, BIS, *(int *)data); 1224182007Sroberto break; 1225182007Sroberto case TIOCMBIC: 1226182007Sroberto (void) si_modem(pp, BIC, *(int *)data); 1227182007Sroberto break; 1228285612Sdelphij case TIOCMGET: 1229182007Sroberto *(int *)data = si_modem(pp, GET, 0); 1230182007Sroberto break; 1231285612Sdelphij case TIOCMSDTRWAIT: 1232285612Sdelphij /* must be root since the wait applies to following logins */ 1233285612Sdelphij error = suser(p->p_ucred, &p->p_acflag); 1234285612Sdelphij if (error != 0) { 1235285612Sdelphij goto outspl; 1236182007Sroberto } 1237182007Sroberto pp->sp_dtr_wait = *(int *)data * hz / 100; 1238182007Sroberto break; 1239285612Sdelphij case TIOCMGDTRWAIT: 124082498Sroberto *(int *)data = pp->sp_dtr_wait * 100 / hz; 124182498Sroberto break; 124282498Sroberto 1243132451Sroberto default: 124482498Sroberto error = ENOTTY; 1245132451Sroberto } 1246285612Sdelphij error = 0; 1247285612Sdelphijoutspl: 1248285612Sdelphij splx(oldspl); 1249182007Srobertoout: 1250285612Sdelphij DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 1251182007Sroberto if (blocked) 1252182007Sroberto si_write_enable(pp, 1); 125382498Sroberto return(error); 125482498Sroberto} 125582498Sroberto 1256132451Sroberto/* 125782498Sroberto * Handle the Specialix ioctls. All MUST be called via the CONTROL device 1258132451Sroberto */ 1259182007Srobertostatic int 1260285612Sdelphijsi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 1261182007Sroberto{ 1262182007Sroberto struct si_softc *xsc; 1263132451Sroberto register struct si_port *xpp; 1264132451Sroberto volatile struct si_reg *regp; 126582498Sroberto struct si_tcsi *dp; 1266132451Sroberto struct si_pstat *sps; 126782498Sroberto int *ip, error = 0; 1268132451Sroberto int oldspl; 1269285612Sdelphij int card, port; 1270285612Sdelphij int mynor = minor(dev); 1271285612Sdelphij 1272182007Sroberto DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n", 1273285612Sdelphij dev, cmd, data, flag)); 1274182007Sroberto 1275182007Sroberto#if 1 127682498Sroberto DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 127782498Sroberto DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 127882498Sroberto DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 1279132451Sroberto#endif 128082498Sroberto 1281132451Sroberto if (!IS_CONTROLDEV(mynor)) { 1282182007Sroberto DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 1283285612Sdelphij return(ENODEV); 1284182007Sroberto } 1285182007Sroberto 1286132451Sroberto oldspl = spltty(); /* better safe than sorry */ 1287132451Sroberto 1288132451Sroberto ip = (int *)data; 1289132451Sroberto 1290132451Sroberto#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out 1291132451Sroberto 1292285612Sdelphij switch (cmd) { 1293285612Sdelphij case TCSIPORTS: 1294285612Sdelphij *ip = si_Nports; 1295182007Sroberto goto out; 1296285612Sdelphij case TCSIMODULES: 1297182007Sroberto *ip = si_Nmodules; 1298182007Sroberto goto out; 129982498Sroberto case TCSISDBG_ALL: 130082498Sroberto SUCHECK; 130182498Sroberto si_debug = *ip; 1302132451Sroberto goto out; 130382498Sroberto case TCSIGDBG_ALL: 1304132451Sroberto *ip = si_debug; 1305182007Sroberto goto out; 1306285612Sdelphij default: 1307182007Sroberto /* 1308182007Sroberto * Check that a controller for this port exists 1309132451Sroberto */ 1310132451Sroberto 1311132451Sroberto /* may also be a struct si_pstat, a superset of si_tcsi */ 1312132451Sroberto 1313132451Sroberto dp = (struct si_tcsi *)data; 1314132451Sroberto sps = (struct si_pstat *)data; 1315132451Sroberto card = dp->tc_card; 1316132451Sroberto xsc = &si_softc[card]; /* check.. */ 1317132451Sroberto if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 1318132451Sroberto error = ENOENT; 1319132451Sroberto goto out; 1320285612Sdelphij } 1321285612Sdelphij /* 1322285612Sdelphij * And check that a port exists 1323285612Sdelphij */ 1324132451Sroberto port = dp->tc_port; 1325132451Sroberto if (port < 0 || port >= xsc->sc_nport) { 1326132451Sroberto error = ENOENT; 1327132451Sroberto goto out; 1328132451Sroberto } 1329132451Sroberto xpp = xsc->sc_ports + port; 1330132451Sroberto regp = (struct si_reg *)xsc->sc_maddr; 1331285612Sdelphij } 1332132451Sroberto 1333132451Sroberto switch (cmd) { 1334132451Sroberto case TCSIDEBUG: 1335132451Sroberto#ifdef SI_DEBUG 1336132451Sroberto SUCHECK; 1337132451Sroberto if (xpp->sp_debug) 1338132451Sroberto xpp->sp_debug = 0; 1339281230Sdelphij else { 1340281230Sdelphij xpp->sp_debug = DBG_ALL; 1341281230Sdelphij DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 1342281230Sdelphij (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 1343182007Sroberto } 134482498Sroberto break; 134582498Sroberto#else 1346285612Sdelphij error = ENODEV; 1347132451Sroberto goto out; 1348285612Sdelphij#endif 1349285612Sdelphij case TCSISDBG_LEVEL: 1350281230Sdelphij case TCSIGDBG_LEVEL: 1351281230Sdelphij#ifdef SI_DEBUG 1352285612Sdelphij if (cmd == TCSIGDBG_LEVEL) { 1353281230Sdelphij dp->tc_dbglvl = xpp->sp_debug; 1354281230Sdelphij } else { 135582498Sroberto SUCHECK; 135682498Sroberto xpp->sp_debug = dp->tc_dbglvl; 135782498Sroberto } 1358132451Sroberto break; 1359132451Sroberto#else 1360132451Sroberto error = ENODEV; 1361132451Sroberto goto out; 1362132451Sroberto#endif 136382498Sroberto case TCSIGRXIT: 1364132451Sroberto dp->tc_int = regp->rx_int_count; 1365285612Sdelphij break; 1366285612Sdelphij case TCSIRXIT: 1367285612Sdelphij SUCHECK; 1368285612Sdelphij regp->rx_int_count = dp->tc_int; 1369285612Sdelphij break; 137082498Sroberto case TCSIGIT: 1371132451Sroberto dp->tc_int = regp->int_count; 1372285612Sdelphij break; 137382498Sroberto case TCSIIT: 137482498Sroberto SUCHECK; 137582498Sroberto regp->int_count = dp->tc_int; 1376285612Sdelphij break; 1377285612Sdelphij case TCSISTATE: 1378182007Sroberto dp->tc_int = xpp->sp_ccb->hi_ip; 137982498Sroberto break; 1380285612Sdelphij /* these next three use a different structure */ 1381285612Sdelphij case TCSI_PORT: 138282498Sroberto SUCHECK; 138382498Sroberto sps->tc_siport = *xpp; 138482498Sroberto break; 1385285612Sdelphij case TCSI_CCB: 1386285612Sdelphij SUCHECK; 138782498Sroberto sps->tc_ccb = *xpp->sp_ccb; 138882498Sroberto break; 138982498Sroberto case TCSI_TTY: 1390182007Sroberto SUCHECK; 139182498Sroberto sps->tc_tty = *xpp->sp_tty; 139282498Sroberto break; 139382498Sroberto default: 1394182007Sroberto error = EINVAL; 1395182007Sroberto goto out; 1396132451Sroberto } 1397182007Srobertoout: 1398285612Sdelphij splx(oldspl); 1399285612Sdelphij return(error); /* success */ 1400285612Sdelphij} 1401285612Sdelphij 1402285612Sdelphij/* 1403285612Sdelphij * siparam() : Configure line params 1404285612Sdelphij * called at spltty(); 1405285612Sdelphij * this may sleep, does not flush, nor wait for drain, nor block writes 1406132451Sroberto * caller must arrange this if it's important.. 1407285612Sdelphij */ 1408182007Srobertostatic int 1409182007Srobertosiparam(tp, t) 1410132451Sroberto register struct tty *tp; 1411285612Sdelphij register struct termios *t; 1412285612Sdelphij{ 141382498Sroberto register struct si_port *pp = TP2PP(tp); 141482498Sroberto volatile struct si_channel *ccbp; 141582498Sroberto int oldspl, cflag, iflag, oflag, lflag; 1416132451Sroberto int error = 0; /* shutup gcc */ 141782498Sroberto int ispeed = 0; /* shutup gcc */ 1418285612Sdelphij int ospeed = 0; /* shutup gcc */ 1419132451Sroberto BYTE val; 1420132451Sroberto 1421132451Sroberto DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 1422285612Sdelphij cflag = t->c_cflag; 1423285612Sdelphij iflag = t->c_iflag; 1424132451Sroberto oflag = t->c_oflag; 1425132451Sroberto lflag = t->c_lflag; 1426132451Sroberto DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 1427132451Sroberto oflag, cflag, iflag, lflag)); 1428285612Sdelphij 142982498Sroberto 1430132451Sroberto /* if not hung up.. */ 1431132451Sroberto if (t->c_ospeed != 0) { 1432132451Sroberto /* translate baud rate to firmware values */ 1433132451Sroberto ospeed = ttspeedtab(t->c_ospeed, bdrates); 1434132451Sroberto ispeed = t->c_ispeed ? 1435132451Sroberto ttspeedtab(t->c_ispeed, bdrates) : ospeed; 143682498Sroberto 1437132451Sroberto /* enforce legit baud rate */ 1438310419Sdelphij if (ospeed < 0 || ispeed < 0) 1439182007Sroberto return (EINVAL); 1440182007Sroberto } 1441132451Sroberto 1442132451Sroberto 1443132451Sroberto oldspl = spltty(); 1444132451Sroberto 144582498Sroberto ccbp = pp->sp_ccb; 144682498Sroberto 1447285612Sdelphij /* ========== set hi_break ========== */ 1448285612Sdelphij val = 0; 1449285612Sdelphij if (iflag & IGNBRK) /* Breaks */ 1450285612Sdelphij val |= BR_IGN; 145182498Sroberto if (iflag & BRKINT) /* Interrupt on break? */ 1452132451Sroberto val |= BR_INT; 1453132451Sroberto if (iflag & PARMRK) /* Parity mark? */ 145482498Sroberto val |= BR_PARMRK; 145582498Sroberto if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 1456285612Sdelphij val |= BR_PARIGN; 1457285612Sdelphij ccbp->hi_break = val; 1458285612Sdelphij 1459285612Sdelphij /* ========== set hi_csr ========== */ 146082498Sroberto /* if not hung up.. */ 1461132451Sroberto if (t->c_ospeed != 0) { 1462182007Sroberto /* Set I/O speeds */ 1463182007Sroberto val = (ispeed << 4) | ospeed; 1464285612Sdelphij } 1465285612Sdelphij ccbp->hi_csr = val; 1466285612Sdelphij 1467285612Sdelphij /* ========== set hi_mr2 ========== */ 1468285612Sdelphij val = 0; 1469285612Sdelphij if (cflag & CSTOPB) /* Stop bits */ 1470285612Sdelphij val |= MR2_2_STOP; 1471132451Sroberto else 1472285612Sdelphij val |= MR2_1_STOP; 1473285612Sdelphij /* 1474132451Sroberto * Enable H/W RTS/CTS handshaking. The default TA/MTA is 1475182007Sroberto * a DCE, hence the reverse sense of RTS and CTS 1476132451Sroberto */ 1477285612Sdelphij /* Output Flow - RTS must be raised before data can be sent */ 1478285612Sdelphij if (cflag & CCTS_OFLOW) 1479285612Sdelphij val |= MR2_RTSCONT; 1480285612Sdelphij 1481285612Sdelphij ccbp->hi_mr1 = val; 1482132451Sroberto 1483132451Sroberto /* ========== set hi_mr1 ========== */ 1484281230Sdelphij val = 0; 1485281230Sdelphij if (!(cflag & PARENB)) /* Parity */ 1486281230Sdelphij val |= MR1_NONE; 1487285612Sdelphij else 1488132451Sroberto val |= MR1_WITH; 1489132451Sroberto if (cflag & PARODD) 1490281230Sdelphij val |= MR1_ODD; 1491281230Sdelphij 1492281230Sdelphij if ((cflag & CS8) == CS8) { /* 8 data bits? */ 1493281230Sdelphij val |= MR1_8_BITS; 1494132451Sroberto } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 1495132451Sroberto val |= MR1_7_BITS; 1496182007Sroberto } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 1497182007Sroberto val |= MR1_6_BITS; 1498182007Sroberto } else { /* Must be 5 */ 1499285612Sdelphij val |= MR1_5_BITS; 1500182007Sroberto } 1501285612Sdelphij /* 1502285612Sdelphij * Enable H/W RTS/CTS handshaking. The default TA/MTA is 1503182007Sroberto * a DCE, hence the reverse sense of RTS and CTS 1504182007Sroberto */ 1505182007Sroberto /* Input Flow - CTS is raised when port is ready to receive data */ 1506285612Sdelphij if (cflag & CRTS_IFLOW) 1507182007Sroberto val |= MR1_CTSCONT; 1508182007Sroberto 1509182007Sroberto ccbp->hi_mr1 = val; 1510182007Sroberto 1511182007Sroberto /* ========== set hi_mask ========== */ 1512182007Sroberto val = 0xff; 1513182007Sroberto if ((cflag & CS8) == CS8) { /* 8 data bits? */ 1514285612Sdelphij val &= 0xFF; 1515285612Sdelphij } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 1516285612Sdelphij val &= 0x7F; 1517182007Sroberto } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 1518285612Sdelphij val &= 0x3F; 1519285612Sdelphij } else { /* Must be 5 */ 1520285612Sdelphij val &= 0x1F; 1521182007Sroberto } 1522182007Sroberto if (iflag & ISTRIP) 1523182007Sroberto val &= 0x7F; 1524285612Sdelphij 1525285612Sdelphij ccbp->hi_mask = val; 1526285612Sdelphij 1527285612Sdelphij /* ========== set hi_prtcl ========== */ 1528285612Sdelphij val = 0; 1529285612Sdelphij /* Monitor DCD etc. if a modem */ 1530285612Sdelphij if (!(cflag & CLOCAL)) 1531285612Sdelphij val |= SP_DCEN; 1532182007Sroberto if (iflag & IXANY) 1533182007Sroberto val |= SP_TANY; 1534182007Sroberto if (iflag & IXON) 1535132451Sroberto val |= SP_TXEN; 1536132451Sroberto if (iflag & IXOFF) 1537132451Sroberto val |= SP_RXEN; 1538132451Sroberto if (iflag & INPCK) 1539182007Sroberto val |= SP_PAEN; 1540285612Sdelphij 1541132451Sroberto ccbp->hi_prtcl = val; 1542182007Sroberto 1543182007Sroberto 1544182007Sroberto /* ========== set hi_{rx|tx}{on|off} ========== */ 1545132451Sroberto /* XXX: the card TOTALLY shields us from the flow control... */ 1546182007Sroberto ccbp->hi_txon = t->c_cc[VSTART]; 1547182007Sroberto ccbp->hi_txoff = t->c_cc[VSTOP]; 1548285612Sdelphij 1549132451Sroberto ccbp->hi_rxon = t->c_cc[VSTART]; 1550310419Sdelphij ccbp->hi_rxoff = t->c_cc[VSTOP]; 1551310419Sdelphij 1552281230Sdelphij /* ========== send settings to the card ========== */ 1553310419Sdelphij /* potential sleep here */ 1554310419Sdelphij if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 1555310419Sdelphij si_command(pp, LOPEN, SI_WAIT); /* open it */ 1556310419Sdelphij else 1557182007Sroberto si_command(pp, CONFIG, SI_WAIT); /* change params */ 1558310419Sdelphij 1559310419Sdelphij /* ========== set DTR etc ========== */ 1560182007Sroberto /* Hangup if ospeed == 0 */ 1561285612Sdelphij if (t->c_ospeed == 0) { 1562182007Sroberto (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 1563182007Sroberto } else { 1564132451Sroberto /* 1565132451Sroberto * If the previous speed was 0, may need to re-enable 1566132451Sroberto * the modem signals 1567132451Sroberto */ 1568281230Sdelphij (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 1569281230Sdelphij } 1570132451Sroberto 1571281230Sdelphij DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 1572132451Sroberto ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 1573285612Sdelphij 1574132451Sroberto splx(oldspl); 1575132451Sroberto return(error); 1576132451Sroberto} 1577132451Sroberto 1578281230Sdelphij/* 1579281230Sdelphij * Enable or Disable the writes to this channel... 1580281230Sdelphij * "state" -> enabled = 1; disabled = 0; 1581281230Sdelphij */ 1582132451Srobertostatic void 1583132451Srobertosi_write_enable(pp, state) 1584132451Sroberto register struct si_port *pp; 1585310419Sdelphij int state; 1586132451Sroberto{ 1587132451Sroberto int oldspl; 1588285612Sdelphij 1589132451Sroberto oldspl = spltty(); 1590132451Sroberto 1591132451Sroberto if (state) { 1592132451Sroberto pp->sp_state &= ~SS_BLOCKWRITE; 1593281230Sdelphij if (pp->sp_state & SS_WAITWRITE) { 1594132451Sroberto pp->sp_state &= ~SS_WAITWRITE; 1595285612Sdelphij /* thunder away! */ 1596132451Sroberto wakeup((caddr_t)pp); 1597132451Sroberto } 159882498Sroberto } else { 159982498Sroberto pp->sp_state |= SS_BLOCKWRITE; 160082498Sroberto } 1601132451Sroberto 160282498Sroberto splx(oldspl); 1603285612Sdelphij} 1604132451Sroberto 1605132451Sroberto/* 1606132451Sroberto * Set/Get state of modem control lines. 1607281230Sdelphij * Due to DCE-like behaviour of the adapter, some signals need translation: 1608281230Sdelphij * TIOCM_DTR DSR 1609281230Sdelphij * TIOCM_RTS CTS 1610285612Sdelphij */ 1611132451Srobertostatic int 1612285612Sdelphijsi_modem(pp, cmd, bits) 1613310419Sdelphij struct si_port *pp; 1614285612Sdelphij enum si_mctl cmd; 1615132451Sroberto int bits; 1616285612Sdelphij{ 1617132451Sroberto volatile struct si_channel *ccbp; 1618132451Sroberto int x; 1619132451Sroberto 1620132451Sroberto DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 1621132451Sroberto ccbp = pp->sp_ccb; /* Find channel address */ 1622132451Sroberto switch (cmd) { 1623182007Sroberto case GET: 1624132451Sroberto x = ccbp->hi_ip; 1625310419Sdelphij bits = TIOCM_LE; 1626310419Sdelphij if (x & IP_DCD) bits |= TIOCM_CAR; 1627310419Sdelphij if (x & IP_DTR) bits |= TIOCM_DTR; 1628310419Sdelphij if (x & IP_RTS) bits |= TIOCM_RTS; 1629310419Sdelphij if (x & IP_RI) bits |= TIOCM_RI; 1630289997Sglebius return(bits); 1631285612Sdelphij case SET: 1632285612Sdelphij ccbp->hi_op &= ~(OP_DSR|OP_CTS); 1633310419Sdelphij /* fall through */ 1634132451Sroberto case BIS: 1635132451Sroberto x = 0; 163682498Sroberto if (bits & TIOCM_DTR) 1637132451Sroberto x |= OP_DSR; 1638132451Sroberto if (bits & TIOCM_RTS) 1639132451Sroberto x |= OP_CTS; 1640132451Sroberto ccbp->hi_op |= x; 1641132451Sroberto break; 1642132451Sroberto case BIC: 1643285612Sdelphij if (bits & TIOCM_DTR) 1644285612Sdelphij ccbp->hi_op &= ~OP_DSR; 1645285612Sdelphij if (bits & TIOCM_RTS) 1646285612Sdelphij ccbp->hi_op &= ~OP_CTS; 1647285612Sdelphij } 1648285612Sdelphij return 0; 1649132451Sroberto} 1650132451Sroberto 1651132451Sroberto/* 1652132451Sroberto * Handle change of modem state 1653132451Sroberto */ 1654132451Srobertostatic void 1655285612Sdelphijsi_modem_state(pp, tp, hi_ip) 1656285612Sdelphij register struct si_port *pp; 1657285612Sdelphij register struct tty *tp; 1658132451Sroberto register int hi_ip; 165982498Sroberto{ 1660285612Sdelphij /* if a modem dev */ 1661285612Sdelphij if (hi_ip & IP_DCD) { 1662285612Sdelphij if ( !(pp->sp_last_hi_ip & IP_DCD)) { 1663285612Sdelphij DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 166482498Sroberto tp->t_line)); 1665285612Sdelphij (void)(*linesw[tp->t_line].l_modem)(tp, 1); 1666132451Sroberto } 1667285612Sdelphij } else { 1668285612Sdelphij if (pp->sp_last_hi_ip & IP_DCD) { 1669285612Sdelphij DPRINT((pp, DBG_INTR, "modem carr off\n")); 1670285612Sdelphij if ((*linesw[tp->t_line].l_modem)(tp, 0)) 1671285612Sdelphij (void) si_modem(pp, SET, 0); 1672285612Sdelphij } 1673285612Sdelphij } 1674285612Sdelphij pp->sp_last_hi_ip = hi_ip; 1675132451Sroberto 1676132451Sroberto} 1677285612Sdelphij 1678285612Sdelphij/* 1679285612Sdelphij * Poller to catch missed interrupts. 1680285612Sdelphij * 1681285612Sdelphij * Note that the SYSV Specialix drivers poll at 100 times per second to get 1682132451Sroberto * better response. We could really use a "periodic" version timeout(). :-) 1683285612Sdelphij */ 1684132451Sroberto#ifdef POLL 1685132451Srobertostatic void 1686285612Sdelphijsi_poll(void *nothing) 1687285612Sdelphij{ 1688285612Sdelphij register struct si_softc *sc; 1689285612Sdelphij register int i; 1690285612Sdelphij volatile struct si_reg *regp; 1691132451Sroberto register struct si_port *pp; 169282498Sroberto int lost, oldspl, port; 1693132451Sroberto 1694132451Sroberto DPRINT((0, DBG_POLL, "si_poll()\n")); 1695132451Sroberto oldspl = spltty(); 1696132451Sroberto if (in_intr) 1697132451Sroberto goto out; 1698132451Sroberto lost = 0; 1699132451Sroberto for (i=0; i<NSI; i++) { 1700132451Sroberto sc = &si_softc[i]; 1701132451Sroberto if (sc->sc_type == SIEMPTY) 1702285612Sdelphij continue; 1703281230Sdelphij regp = (struct si_reg *)sc->sc_maddr; 1704281230Sdelphij /* 1705281230Sdelphij * See if there has been a pending interrupt for 2 seconds 1706132451Sroberto * or so. The test <int_scounter >= 200) won't correspond 1707132451Sroberto * to 2 seconds if int_count gets changed. 1708132451Sroberto */ 1709132451Sroberto if (regp->int_pending != 0) { 1710132451Sroberto if (regp->int_scounter >= 200 && 1711285612Sdelphij regp->initstat == 1) { 1712132451Sroberto printf("si%d: lost intr\n", i); 1713132451Sroberto lost++; 1714132451Sroberto } 1715132451Sroberto } else { 1716132451Sroberto regp->int_scounter = 0; 1717132451Sroberto } 1718285612Sdelphij 1719132451Sroberto /* 1720132451Sroberto * gripe about no input flow control.. 1721132451Sroberto */ 1722281230Sdelphij pp = sc->sc_ports; 1723281230Sdelphij for (port = 0; port < sc->sc_nport; pp++, port++) { 1724285612Sdelphij if (pp->sp_delta_overflows > 0) { 1725281230Sdelphij printf("si%d: %d tty level buffer overflows\n", 1726281230Sdelphij i, pp->sp_delta_overflows); 1727285612Sdelphij pp->sp_delta_overflows = 0; 1728182007Sroberto } 1729182007Sroberto } 1730182007Sroberto } 1731285612Sdelphij if (lost) 1732285612Sdelphij siintr(-1); /* call intr with fake vector */ 1733285612Sdelphijout: 1734132451Sroberto splx(oldspl); 1735285612Sdelphij 1736132451Sroberto timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); 1737132451Sroberto} 1738132451Sroberto#endif /* ifdef POLL */ 1739132451Sroberto 1740281230Sdelphij/* 1741281230Sdelphij * The interrupt handler polls ALL ports on ALL adapters each time 1742132451Sroberto * it is called. 1743132451Sroberto */ 174482498Sroberto 174582498Srobertostatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 174682498Sroberto 174782498Srobertovoid 1748132451Srobertosiintr(int unit) 1749132451Sroberto{ 1750285612Sdelphij register struct si_softc *sc; 1751285612Sdelphij 1752285612Sdelphij register struct si_port *pp; 1753285612Sdelphij volatile struct si_channel *ccbp; 1754281230Sdelphij register struct tty *tp; 1755281230Sdelphij volatile caddr_t maddr; 175682498Sroberto BYTE op, ip; 1757285612Sdelphij int x, card, port, n, i, isopen; 1758132451Sroberto volatile BYTE *z; 1759132451Sroberto BYTE c; 1760285612Sdelphij 1761285612Sdelphij DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit)); 1762132451Sroberto if (in_intr) { 176382498Sroberto if (unit < 0) /* should never happen */ 1764285612Sdelphij return; 1765285612Sdelphij printf("si%d: Warning interrupt handler re-entered\n", 176682498Sroberto unit); 176782498Sroberto return; 1768285612Sdelphij } 1769285612Sdelphij in_intr = 1; 177082498Sroberto 1771285612Sdelphij /* 1772285612Sdelphij * When we get an int we poll all the channels and do ALL pending 1773285612Sdelphij * work, not just the first one we find. This allows all cards to 1774285612Sdelphij * share the same vector. 1775285612Sdelphij */ 1776285612Sdelphij for (card=0; card < NSI; card++) { 1777285612Sdelphij sc = &si_softc[card]; 1778285612Sdelphij if (sc->sc_type == SIEMPTY) 1779285612Sdelphij continue; 1780285612Sdelphij 1781285612Sdelphij /* 1782285612Sdelphij * First, clear the interrupt 1783132451Sroberto */ 1784132451Sroberto switch(sc->sc_type) { 1785132451Sroberto case SIHOST : 1786132451Sroberto maddr = sc->sc_maddr; 1787132451Sroberto ((volatile struct si_reg *)maddr)->int_pending = 0; 1788285612Sdelphij /* flag nothing pending */ 1789285612Sdelphij *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 1790285612Sdelphij *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 1791285612Sdelphij break; 1792285612Sdelphij case SIHOST2: 1793285612Sdelphij maddr = sc->sc_maddr; 1794285612Sdelphij ((volatile struct si_reg *)maddr)->int_pending = 0; 1795285612Sdelphij *(maddr+SIPLIRQCLR) = 0x00; 1796285612Sdelphij *(maddr+SIPLIRQCLR) = 0x10; 1797285612Sdelphij break; 1798285612Sdelphij case SIEISA: 1799285612Sdelphij#if NEISA > 0 1800285612Sdelphij maddr = sc->sc_maddr; 1801132451Sroberto ((volatile struct si_reg *)maddr)->int_pending = 0; 1802132451Sroberto (void)inb(sc->sc_eisa_iobase+3); 1803132451Sroberto break; 1804132451Sroberto#endif /* fall through if not EISA kernel */ 1805285612Sdelphij case SIEMPTY: 1806285612Sdelphij default: 1807285612Sdelphij continue; 1808285612Sdelphij } 1809285612Sdelphij ((volatile struct si_reg *)maddr)->int_scounter = 0; 1810289997Sglebius 1811285612Sdelphij /* 1812285612Sdelphij * check each port 1813285612Sdelphij */ 1814285612Sdelphij for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) { 1815132451Sroberto ccbp = pp->sp_ccb; 1816132451Sroberto tp = pp->sp_tty; 1817132451Sroberto 1818132451Sroberto 1819132451Sroberto /* 1820132451Sroberto * See if a command has completed ? 1821132451Sroberto */ 1822132451Sroberto if (ccbp->hi_stat != pp->sp_pend) { 1823132451Sroberto DPRINT((pp, DBG_INTR, 1824132451Sroberto "siintr hi_stat = 0x%x, pend = %d\n", 1825132451Sroberto ccbp->hi_stat, pp->sp_pend)); 1826132451Sroberto switch(pp->sp_pend) { 1827132451Sroberto case LOPEN: 1828132451Sroberto case MPEND: 1829285612Sdelphij case MOPEN: 1830132451Sroberto case CONFIG: 1831285612Sdelphij pp->sp_pend = ccbp->hi_stat; 1832285612Sdelphij /* sleeping in si_command */ 1833285612Sdelphij wakeup(&pp->sp_state); 1834132451Sroberto break; 1835132451Sroberto default: 1836132451Sroberto pp->sp_pend = ccbp->hi_stat; 1837132451Sroberto } 1838132451Sroberto } 1839132451Sroberto 1840310419Sdelphij /* 1841285612Sdelphij * Continue on if it's closed 1842132451Sroberto */ 1843285612Sdelphij if (ccbp->hi_stat == IDLE_CLOSE) { 1844132451Sroberto continue; 1845285612Sdelphij } 1846132451Sroberto 1847285612Sdelphij /* 1848285612Sdelphij * Do modem state change if not a local device 184982498Sroberto */ 1850182007Sroberto si_modem_state(pp, tp, ccbp->hi_ip); 1851310419Sdelphij 1852310419Sdelphij /* 185382498Sroberto * Check to see if there's we should 'receive' 1854132451Sroberto * characters. 1855132451Sroberto */ 1856132451Sroberto if (tp->t_state & TS_CONNECTED && 185782498Sroberto tp->t_state & TS_ISOPEN) 1858132451Sroberto isopen = 1; 1859132451Sroberto else 1860132451Sroberto isopen = 0; 1861132451Sroberto 1862132451Sroberto /* 1863310419Sdelphij * Do break processing 1864310419Sdelphij */ 1865310419Sdelphij if (ccbp->hi_state & ST_BREAK) { 1866310419Sdelphij if (isopen) { 1867289997Sglebius (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 1868132451Sroberto } 1869285612Sdelphij ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 187082498Sroberto DPRINT((pp, DBG_INTR, "si_intr break\n")); 187182498Sroberto } 187282498Sroberto 1873132451Sroberto /* 1874132451Sroberto * Do RX stuff - if not open then dump any characters. 1875182007Sroberto * XXX: This is VERY messy and needs to be cleaned up. 1876182007Sroberto * 187782498Sroberto * XXX: can we leave data in the host adapter buffer 1878285612Sdelphij * when the clists are full? That may be dangerous 1879182007Sroberto * if the user cannot get an interrupt signal through. 1880182007Sroberto */ 1881182007Sroberto 1882182007Sroberto more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 1883310419Sdelphij 1884310419Sdelphij if (!isopen) { 1885310419Sdelphij ccbp->hi_rxopos = ccbp->hi_rxipos; 1886182007Sroberto goto end_rx; 1887310419Sdelphij } 1888289997Sglebius 1889182007Sroberto /* 1890285612Sdelphij * Process read characters if not skipped above 189182498Sroberto */ 189282498Sroberto c = ccbp->hi_rxipos - ccbp->hi_rxopos; 189382498Sroberto if (c == 0) { 1894285612Sdelphij goto end_rx; 1895285612Sdelphij } 189682498Sroberto 1897285612Sdelphij op = ccbp->hi_rxopos; 1898285612Sdelphij ip = ccbp->hi_rxipos; 1899285612Sdelphij n = c & 0xff; 1900285612Sdelphij 1901285612Sdelphij DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1902285612Sdelphij n, op, ip)); 1903285612Sdelphij 1904285612Sdelphij /* 1905285612Sdelphij * Suck characters out of host card buffer into the 1906285612Sdelphij * "input staging buffer" - so that we dont leave the 1907285612Sdelphij * host card in limbo while we're possibly echoing 190882498Sroberto * characters and possibly flushing input inside the 1909285612Sdelphij * ldisc l_rint() routine. 1910285612Sdelphij */ 1911285612Sdelphij if (n <= SI_BUFFERSIZE - op) { 1912285612Sdelphij 1913285612Sdelphij DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 1914285612Sdelphij z = ccbp->hi_rxbuf + op; 1915285612Sdelphij bcopy((caddr_t)z, si_rxbuf, n); 1916285612Sdelphij 1917285612Sdelphij op += n; 1918285612Sdelphij } else { 1919285612Sdelphij x = SI_BUFFERSIZE - op; 1920285612Sdelphij 1921285612Sdelphij DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 1922285612Sdelphij z = ccbp->hi_rxbuf + op; 1923285612Sdelphij bcopy((caddr_t)z, si_rxbuf, x); 1924285612Sdelphij 1925285612Sdelphij DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x)); 1926285612Sdelphij z = ccbp->hi_rxbuf; 1927285612Sdelphij bcopy((caddr_t)z, si_rxbuf+x, n-x); 1928285612Sdelphij 1929285612Sdelphij op += n; 1930285612Sdelphij } 1931285612Sdelphij 1932285612Sdelphij /* clear collected characters from buffer */ 1933285612Sdelphij ccbp->hi_rxopos = op; 1934310419Sdelphij 1935310419Sdelphij DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 1936310419Sdelphij n, op, ip)); 1937310419Sdelphij 1938289997Sglebius /* 1939285612Sdelphij * at this point... 1940285612Sdelphij * n = number of chars placed in si_rxbuf 1941285612Sdelphij */ 1942285612Sdelphij 1943285612Sdelphij /* 1944285612Sdelphij * Avoid the grotesquely inefficient lineswitch 1945132451Sroberto * routine (ttyinput) in "raw" mode. It usually 1946285612Sdelphij * takes about 450 instructions (that's without 1947310419Sdelphij * canonical processing or echo!). slinput is 194882498Sroberto * reasonably fast (usually 40 instructions 194982498Sroberto * plus call overhead). 1950285612Sdelphij */ 1951285612Sdelphij if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 1952285612Sdelphij 1953285612Sdelphij /* block if the driver supports it */ 1954285612Sdelphij if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 1955285612Sdelphij && (tp->t_cflag & CRTS_IFLOW 1956285612Sdelphij || tp->t_iflag & IXOFF) 1957285612Sdelphij && !(tp->t_state & TS_TBLOCK)) 1958285612Sdelphij ttyblock(tp); 1959285612Sdelphij 1960285612Sdelphij tk_nin += n; 1961285612Sdelphij tk_rawcc += n; 1962285612Sdelphij tp->t_rawcc += n; 1963285612Sdelphij 1964285612Sdelphij pp->sp_delta_overflows += 1965285612Sdelphij b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 1966285612Sdelphij 1967285612Sdelphij ttwakeup(tp); 196882498Sroberto if (tp->t_state & TS_TTSTOP 1969285612Sdelphij && (tp->t_iflag & IXANY 1970285612Sdelphij || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 1971285612Sdelphij tp->t_state &= ~TS_TTSTOP; 1972285612Sdelphij tp->t_lflag &= ~FLUSHO; 1973285612Sdelphij si_start(tp); 1974285612Sdelphij } 1975285612Sdelphij } else { 1976285612Sdelphij /* 1977285612Sdelphij * It'd be nice to not have to go through the 1978285612Sdelphij * function call overhead for each char here. 1979285612Sdelphij * It'd be nice to block input it, saving a 1980285612Sdelphij * loop here and the call/return overhead. 198182498Sroberto */ 1982132451Sroberto for(x = 0; x < n; x++) { 1983132451Sroberto i = si_rxbuf[x]; 1984132451Sroberto if ((*linesw[tp->t_line].l_rint)(i, tp) 198582498Sroberto == -1) { 1986132451Sroberto pp->sp_delta_overflows++; 1987132451Sroberto } 1988132451Sroberto /* 198982498Sroberto * doesn't seem to be much point doing 199082498Sroberto * this here.. this driver has no 1991132451Sroberto * softtty processing! ?? 1992132451Sroberto */ 1993132451Sroberto if (pp->sp_hotchar && i == pp->sp_hotchar) { 1994132451Sroberto setsofttty(); 1995132451Sroberto } 1996132451Sroberto } 199782498Sroberto } 1998132451Sroberto goto more_rx; /* try for more until RXbuf is empty */ 1999132451Sroberto 2000285612Sdelphij end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 2001285612Sdelphij 2002285612Sdelphij /* 2003132451Sroberto * Do TX stuff 2004132451Sroberto */ 2005132451Sroberto (*linesw[tp->t_line].l_start)(tp); 2006132451Sroberto 2007285612Sdelphij } /* end of for (all ports on this controller) */ 2008132451Sroberto } /* end of for (all controllers) */ 2009132451Sroberto 2010132451Sroberto in_intr = 0; 2011132451Sroberto DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit)); 2012132451Sroberto} 2013132451Sroberto 2014132451Sroberto/* 2015132451Sroberto * Nudge the transmitter... 2016132451Sroberto * 2017285612Sdelphij * XXX: I inherited some funny code here. It implies the host card only 2018285612Sdelphij * interrupts when the transmit buffer reaches the low-water-mark, and does 2019132451Sroberto * not interrupt when it's actually hits empty. In some cases, we have 2020285612Sdelphij * processes waiting for complete drain, and we need to simulate an interrupt 2021285612Sdelphij * about when we think the buffer is going to be empty (and retry if not). 2022285612Sdelphij * I really am not certain about this... I *need* the hardware manuals. 2023316722Sdelphij */ 2024285612Sdelphijstatic void 2025132451Srobertosi_start(tp) 2026132451Sroberto register struct tty *tp; 2027285612Sdelphij{ 2028285612Sdelphij struct si_port *pp; 2029285612Sdelphij volatile struct si_channel *ccbp; 2030132451Sroberto register struct clist *qp; 203182498Sroberto register char *dptr; 2032132451Sroberto BYTE ipos; 2033285612Sdelphij int nchar; 2034132451Sroberto int oldspl, count, n, amount, buffer_full; 2035285612Sdelphij int do_exitproc; 2036285612Sdelphij 2037285612Sdelphij oldspl = spltty(); 203882498Sroberto 2039285612Sdelphij qp = &tp->t_outq; 2040289997Sglebius pp = TP2PP(tp); 2041285612Sdelphij 2042289997Sglebius DPRINT((pp, DBG_ENTRY|DBG_START, 2043285612Sdelphij "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 2044285612Sdelphij tp, tp->t_state, pp->sp_state, qp->c_cc)); 2045285612Sdelphij 2046182007Sroberto if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 2047285612Sdelphij goto out; 2048285612Sdelphij 2049285612Sdelphij do_exitproc = 0; 2050285612Sdelphij buffer_full = 0; 2051285612Sdelphij ccbp = pp->sp_ccb; 2052285612Sdelphij 2053285612Sdelphij /* 2054285612Sdelphij * Handle the case where ttywait() is called on process exit 2055285612Sdelphij * this may be BSDI specific, I dont know... 2056285612Sdelphij */ 2057285612Sdelphij if (tp->t_session != NULL && tp->t_session->s_leader != NULL && 2058285612Sdelphij (tp->t_session->s_leader->p_flag & P_WEXIT)) { 2059285612Sdelphij do_exitproc++; 2060285612Sdelphij } 2061285612Sdelphij 2062285612Sdelphij count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 2063285612Sdelphij DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 2064285612Sdelphij 2065285612Sdelphij dptr = (char *)ccbp->hi_txbuf; /* data buffer */ 2066285612Sdelphij 2067285612Sdelphij while ((nchar = qp->c_cc) > 0) { 2068285612Sdelphij if ((BYTE)count >= 255) { 2069285612Sdelphij buffer_full++; 2070285612Sdelphij break; 2071285612Sdelphij } 2072285612Sdelphij amount = min(nchar, (255 - (BYTE)count)); 2073132451Sroberto ipos = (unsigned int)ccbp->hi_txipos; 2074132451Sroberto /* will it fit in one lump? */ 2075132451Sroberto if ((SI_BUFFERSIZE - ipos) >= amount) { 2076132451Sroberto n = q_to_b(&tp->t_outq, 2077132451Sroberto (char *)&ccbp->hi_txbuf[ipos], amount); 2078285612Sdelphij } else { 2079285612Sdelphij n = q_to_b(&tp->t_outq, 2080132451Sroberto (char *)&ccbp->hi_txbuf[ipos], 2081285612Sdelphij SI_BUFFERSIZE-ipos); 2082132451Sroberto if (n == SI_BUFFERSIZE-ipos) { 2083132451Sroberto n += q_to_b(&tp->t_outq, 2084132451Sroberto (char *)&ccbp->hi_txbuf[0], 2085132451Sroberto amount - (SI_BUFFERSIZE-ipos)); 2086132451Sroberto } 2087310419Sdelphij } 2088132451Sroberto ccbp->hi_txipos += n; 2089132451Sroberto count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 2090132451Sroberto } 2091132451Sroberto 2092132451Sroberto if (count != 0 && nchar == 0) { 2093132451Sroberto tp->t_state |= TS_BUSY; 2094132451Sroberto } else { 2095310419Sdelphij tp->t_state &= ~TS_BUSY; 2096330567Sgordon } 2097330567Sgordon 2098330567Sgordon /* wakeup time? */ 2099330567Sgordon ttwwakeup(tp); 2100330567Sgordon 2101310419Sdelphij DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 2102330567Sgordon (BYTE)count, nchar, tp->t_state)); 2103310419Sdelphij 2104310419Sdelphij if ((tp->t_state & TS_BUSY) || do_exitproc) 2105310419Sdelphij { 2106132451Sroberto int time; 2107285612Sdelphij 2108132451Sroberto if (do_exitproc != 0) { 2109132451Sroberto time = hz / 10; 2110132451Sroberto } else { 2111132451Sroberto time = ttspeedtab(tp->t_ospeed, chartimes); 2112132451Sroberto 2113132451Sroberto if (time > 0) { 2114132451Sroberto if (time < nchar) 2115132451Sroberto time = nchar / time; 2116132451Sroberto else 2117132451Sroberto time = 2; 2118132451Sroberto } else { 2119285612Sdelphij printf("si%d: bad char time value!!\n", 2120285612Sdelphij (int)SI_CARD(tp->t_dev)); 2121285612Sdelphij goto out; 2122285612Sdelphij } 2123285612Sdelphij } 2124285612Sdelphij 2125285612Sdelphij if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 2126285612Sdelphij untimeout((timeout_func_t)si_lstart, (caddr_t)pp); 2127285612Sdelphij } else { 2128132451Sroberto pp->sp_state |= SS_LSTART; 2129285612Sdelphij } 2130285612Sdelphij DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 2131285612Sdelphij timeout((timeout_func_t)si_lstart, (caddr_t)pp, time); 2132285612Sdelphij } 2133285612Sdelphij 2134285612Sdelphijout: 2135285612Sdelphij splx(oldspl); 2136285612Sdelphij DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 2137285612Sdelphij} 2138132451Sroberto 2139132451Sroberto/* 2140132451Sroberto * Note: called at splsoftclock from the timeout code 2141132451Sroberto * This has to deal with two things... cause wakeups while waiting for 2142132451Sroberto * tty drains on last process exit, and call l_start at about the right 2143285612Sdelphij * time for protocols like ppp. 2144132451Sroberto */ 2145285612Sdelphijstatic void 2146285612Sdelphijsi_lstart(pp) 2147285612Sdelphij register struct si_port *pp; 2148285612Sdelphij{ 2149285612Sdelphij register struct tty *tp; 2150285612Sdelphij int oldspl; 2151132451Sroberto 2152132451Sroberto DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 2153132451Sroberto pp, pp->sp_state)); 2154132451Sroberto 2155132451Sroberto oldspl = spltty(); 2156132451Sroberto 2157132451Sroberto if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 2158132451Sroberto splx(oldspl); 2159132451Sroberto return; 2160132451Sroberto } 2161132451Sroberto pp->sp_state &= ~SS_LSTART; 2162285612Sdelphij pp->sp_state |= SS_INLSTART; 2163132451Sroberto 2164132451Sroberto tp = pp->sp_tty; 2165132451Sroberto 2166132451Sroberto /* deal with the process exit case */ 2167132451Sroberto ttwwakeup(tp); 2168132451Sroberto 2169132451Sroberto /* nudge protocols - eg: ppp */ 2170132451Sroberto (*linesw[tp->t_line].l_start)(tp); 2171132451Sroberto 2172132451Sroberto pp->sp_state &= ~SS_INLSTART; 2173310419Sdelphij splx(oldspl); 2174132451Sroberto} 2175132451Sroberto 2176310419Sdelphij/* 2177132451Sroberto * Stop output on a line. called at spltty(); 2178132451Sroberto */ 2179132451Srobertovoid 2180132451Srobertosistop(tp, rw) 2181285612Sdelphij register struct tty *tp; 2182285612Sdelphij int rw; 2183132451Sroberto{ 2184285612Sdelphij volatile struct si_channel *ccbp; 2185182007Sroberto struct si_port *pp; 2186310419Sdelphij 2187285612Sdelphij pp = TP2PP(tp); 2188132451Sroberto ccbp = pp->sp_ccb; 2189132451Sroberto 2190132451Sroberto DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 2191132451Sroberto 2192285612Sdelphij /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 2193132451Sroberto if (rw & FWRITE) { 2194132451Sroberto /* what level are we meant to be flushing anyway? */ 2195132451Sroberto if (tp->t_state & TS_BUSY) { 2196132451Sroberto si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 2197310419Sdelphij tp->t_state &= ~TS_BUSY; 2198310419Sdelphij ttwwakeup(tp); /* Bruce???? */ 2199285612Sdelphij } 2200285612Sdelphij } 2201310419Sdelphij#if 1 /* XXX: this doesn't work right yet.. */ 2202132451Sroberto /* XXX: this may have been failing because we used to call l_rint() 2203132451Sroberto * while we were looping based on these two counters. Now, we collect 2204132451Sroberto * the data and then loop stuffing it into l_rint(), making this 2205132451Sroberto * useless. Should we cause this to blow away the staging buffer? 2206132451Sroberto */ 2207285612Sdelphij if (rw & FREAD) { 2208132451Sroberto ccbp->hi_rxopos = ccbp->hi_rxipos; 2209132451Sroberto } 2210285612Sdelphij#endif 2211132451Sroberto} 2212132451Sroberto 2213132451Sroberto/* 2214132451Sroberto * Issue a command to the Z280 host card CPU. 2215132451Sroberto */ 2216182007Sroberto 2217132451Srobertostatic void 2218310419Sdelphijsi_command(pp, cmd, waitflag) 2219310419Sdelphij struct si_port *pp; /* port control block (local) */ 2220310419Sdelphij int cmd; 2221310419Sdelphij int waitflag; 2222310419Sdelphij{ 2223289997Sglebius int oldspl; 2224132451Sroberto volatile struct si_channel *ccbp = pp->sp_ccb; 2225285612Sdelphij int x; 2226310419Sdelphij 2227132451Sroberto DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 2228132451Sroberto pp, cmd, waitflag, ccbp->hi_stat)); 2229132451Sroberto 2230132451Sroberto oldspl = spltty(); /* Keep others out */ 2231132451Sroberto 2232132451Sroberto /* wait until it's finished what it was doing.. */ 2233132451Sroberto while((x = ccbp->hi_stat) != IDLE_OPEN && 2234132451Sroberto x != IDLE_CLOSE && 2235132451Sroberto x != cmd) { 2236285612Sdelphij if (in_intr) { /* Prevent sleep in intr */ 2237182007Sroberto DPRINT((pp, DBG_PARAM, 2238132451Sroberto "cmd intr collision - completing %d\trequested %d\n", 2239132451Sroberto x, cmd)); 2240132451Sroberto splx(oldspl); 2241132451Sroberto return; 2242132451Sroberto } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 2243132451Sroberto "sicmd1", 1)) { 2244132451Sroberto splx(oldspl); 2245132451Sroberto return; 2246132451Sroberto } 2247132451Sroberto } 2248310419Sdelphij /* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */ 2249132451Sroberto 2250132451Sroberto /* if there was a pending command, cause a state-change wakeup */ 2251132451Sroberto if (pp->sp_pend != IDLE_OPEN) { 2252289997Sglebius switch(pp->sp_pend) { 2253310419Sdelphij case LOPEN: 2254310419Sdelphij case MPEND: 2255132451Sroberto case MOPEN: 2256132451Sroberto case CONFIG: 2257132451Sroberto wakeup(&pp->sp_state); 2258132451Sroberto break; 2259132451Sroberto default: 2260285612Sdelphij break; 2261285612Sdelphij } 2262182007Sroberto } 2263132451Sroberto 2264310419Sdelphij pp->sp_pend = cmd; /* New command pending */ 2265310419Sdelphij ccbp->hi_stat = cmd; /* Post it */ 2266310419Sdelphij 2267132451Sroberto if (waitflag) { 2268132451Sroberto if (in_intr) { /* If in interrupt handler */ 2269132451Sroberto DPRINT((pp, DBG_PARAM, 2270132451Sroberto "attempt to sleep in si_intr - cmd req %d\n", 2271289997Sglebius cmd)); 2272289997Sglebius splx(oldspl); 2273289997Sglebius return; 2274289997Sglebius } else while(ccbp->hi_stat != IDLE_OPEN) { 2275285612Sdelphij if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 2276132451Sroberto "sicmd2", 0)) 2277182007Sroberto break; 2278132451Sroberto } 2279132451Sroberto } 2280132451Sroberto splx(oldspl); 2281132451Sroberto} 2282132451Sroberto 2283132451Srobertostatic void 2284132451Srobertosi_disc_optim(tp, t, pp) 2285132451Sroberto struct tty *tp; 2286289997Sglebius struct termios *t; 2287310419Sdelphij struct si_port *pp; 2288132451Sroberto{ 2289310419Sdelphij /* 2290310419Sdelphij * XXX can skip a lot more cases if Smarts. Maybe 2291132451Sroberto * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 2292310419Sdelphij * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 2293132451Sroberto */ 2294310419Sdelphij if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 2295285612Sdelphij && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 2296285612Sdelphij && (!(t->c_iflag & PARMRK) 2297285612Sdelphij || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 2298285612Sdelphij && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 2299132451Sroberto && linesw[tp->t_line].l_rint == ttyinput) 2300132451Sroberto tp->t_state |= TS_CAN_BYPASS_L_RINT; 2301285612Sdelphij else 2302285612Sdelphij tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 2303132451Sroberto 2304289997Sglebius /* 2305289997Sglebius * Prepare to reduce input latency for packet 2306285612Sdelphij * discplines with a end of packet character. 2307132451Sroberto */ 2308132451Sroberto if (tp->t_line == SLIPDISC) 2309182007Sroberto pp->sp_hotchar = 0xc0; 2310132451Sroberto else if (tp->t_line == PPPDISC) 2311289997Sglebius pp->sp_hotchar = 0x7e; 2312289997Sglebius else 2313289997Sglebius pp->sp_hotchar = 0; 2314281230Sdelphij 2315281230Sdelphij DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 2316281230Sdelphij (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 2317281230Sdelphij pp->sp_hotchar)); 2318281230Sdelphij} 2319281230Sdelphij 2320285612Sdelphij 2321289997Sglebius#ifdef SI_DEBUG 2322289997Sglebius 2323132451Srobertostatic void 2324132451Sroberto#ifdef __STDC__ 2325132451Srobertosi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 2326132451Sroberto#else 2327132451Srobertosi_dprintf(pp, flags, fmt, va_alist) 2328182007Sroberto struct si_port *pp; 2329281230Sdelphij int flags; 2330132451Sroberto char *fmt; 2331310419Sdelphij#endif 2332310419Sdelphij{ 2333310419Sdelphij va_list ap; 2334310419Sdelphij 2335310419Sdelphij if ((pp == NULL && (si_debug&flags)) || 2336289997Sglebius (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 2337289997Sglebius if (pp != NULL) 2338285612Sdelphij printf("%ci%d(%d): ", 's', 2339310419Sdelphij (int)SI_CARD(pp->sp_tty->t_dev), 2340132451Sroberto (int)SI_PORT(pp->sp_tty->t_dev)); 2341132451Sroberto va_start(ap, fmt); 2342132451Sroberto vprintf(fmt, ap); 2343132451Sroberto va_end(ap); 2344132451Sroberto } 2345132451Sroberto} 2346132451Sroberto 2347132451Srobertostatic char * 2348132451Srobertosi_mctl2str(cmd) 2349285612Sdelphij enum si_mctl cmd; 2350285612Sdelphij{ 2351132451Sroberto switch (cmd) { 2352132451Sroberto case GET: return("GET"); 2353132451Sroberto case SET: return("SET"); 2354132451Sroberto case BIS: return("BIS"); 2355132451Sroberto case BIC: return("BIC"); 2356132451Sroberto } 2357132451Sroberto return("BAD"); 2358132451Sroberto} 2359132451Sroberto 2360132451Sroberto#endif /* DEBUG */ 2361132451Sroberto 2362132451Sroberto 2363132451Sroberto 2364285612Sdelphijstatic si_devsw_installed = 0; 2365132451Sroberto 2366310419Sdelphijstatic void si_drvinit(void *unused) 2367310419Sdelphij{ 2368310419Sdelphij dev_t dev; 2369132451Sroberto 2370132451Sroberto if( ! si_devsw_installed ) { 2371132451Sroberto dev = makedev(CDEV_MAJOR, 0); 2372132451Sroberto cdevsw_add(&dev,&si_cdevsw, NULL); 2373132451Sroberto si_devsw_installed = 1; 2374132451Sroberto } 2375285612Sdelphij} 2376182007Sroberto 2377132451SrobertoSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 2378285612Sdelphij 2379285612Sdelphij