si.c revision 46112
110015Speter/* 212496Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors. 310015Speter * 434832Speter * Copyright (C) 1990, 1992, 1998 Specialix International, 510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 634832Speter * Copyright (C) 1995, Peter Wemm <peter@netplex.com.au> 710015Speter * 810015Speter * Originally derived from: SunOS 4.x version 910015Speter * Ported from BSDI version to FreeBSD by Peter Wemm. 1010015Speter * 1110015Speter * Redistribution and use in source and binary forms, with or without 1210015Speter * modification, are permitted provided that the following conditions 1310015Speter * are met: 1410015Speter * 1. Redistributions of source code must retain the above copyright 1510015Speter * notices, this list of conditions and the following disclaimer. 1610015Speter * 2. Redistributions in binary form must reproduce the above copyright 1710015Speter * notices, this list of conditions and the following disclaimer in the 1810015Speter * documentation and/or other materials provided with the distribution. 1910015Speter * 3. All advertising materials mentioning features or use of this software 2010015Speter * must display the following acknowledgement: 2110015Speter * This product includes software developed by Andy Rutter of 2210015Speter * Advanced Methods and Tools Ltd. based on original information 2310015Speter * from Specialix International. 2410015Speter * 4. Neither the name of Advanced Methods and Tools, nor Specialix 2510015Speter * International may be used to endorse or promote products derived from 2610015Speter * this software without specific prior written permission. 2710015Speter * 2810015Speter * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 2910015Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 3010015Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 3110015Speter * NO EVENT SHALL THE AUTHORS BE LIABLE. 3210015Speter * 3346112Sphk * $Id: si.c,v 1.80 1999/04/24 20:17:03 peter Exp $ 3410015Speter */ 3510015Speter 3610015Speter#ifndef lint 3734832Speterstatic const char si_copyright1[] = "@(#) Copyright (C) Specialix International, 1990,1992,1998", 3834832Speter si_copyright2[] = "@(#) Copyright (C) Andy Rutter 1993", 3934832Speter si_copyright3[] = "@(#) Copyright (C) Peter Wemm 1995"; 4010015Speter#endif /* not lint */ 4110015Speter 4231778Seivind#include "opt_compat.h" 4332929Seivind#include "opt_debug_si.h" 4432726Seivind#include "opt_devfs.h" 4531778Seivind 4610015Speter#include <sys/param.h> 4710015Speter#include <sys/systm.h> 4824207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 4924207Sbde#include <sys/ioctl_compat.h> 5024207Sbde#endif 5110015Speter#include <sys/tty.h> 5210015Speter#include <sys/proc.h> 5310015Speter#include <sys/conf.h> 5424131Sbde#include <sys/fcntl.h> 5510015Speter#include <sys/dkstat.h> 5610015Speter#include <sys/kernel.h> 5710015Speter#include <sys/malloc.h> 5815683Speter#include <sys/sysctl.h> 5912675Sjulian#ifdef DEVFS 6012675Sjulian#include <sys/devfsext.h> 6112675Sjulian#endif /*DEVFS*/ 6210015Speter 6310015Speter#include <machine/clock.h> 6410015Speter 6512659Sbde#include <vm/vm.h> 6612662Sdg#include <vm/pmap.h> 6712659Sbde 6810015Speter#include <i386/isa/icu.h> 6910015Speter#include <i386/isa/isa.h> 7010015Speter#include <i386/isa/isa_device.h> 7110015Speter 7210015Speter#include <i386/isa/sireg.h> 7310015Speter#include <machine/si.h> 7413353Speter#include <machine/stdarg.h> 7510015Speter 7633395Speter#include "pci.h" 7733395Speter#if NPCI > 0 7833395Speter#include <pci/pcivar.h> 7933395Speter#endif 8033395Speter 8134832Speter#include "eisa.h" 8234832Speter#if NEISA > 0 8334832Speter#include <i386/eisa/eisaconf.h> 8434832Speter#include <i386/isa/icu.h> 8534832Speter#endif 8634832Speter 8710015Speter#include "si.h" 8810015Speter 8910015Speter/* 9010015Speter * This device driver is designed to interface the Specialix International 9134832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 9234832Speter * EISA or PCI bus machine. 9310015Speter * 9434832Speter * The controller is interfaced to the host via dual port RAM 9534832Speter * and an interrupt. 9633395Speter * 9734832Speter * The code for the Host 1 (very old ISA cards) has not been tested. 9810015Speter */ 9910015Speter 10017547Speter#define POLL /* turn on poller to scan for lost interrupts */ 10117547Speter#define REALPOLL /* on each poll, scan for work regardless */ 10217547Speter#define POLLHZ (hz/10) /* 10 times per second */ 10312496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 10434832Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 10534832Speter#define JET_INT_COUNT 100 /* max of 100 ints per second */ 10615639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 10710015Speter 10810015Speterenum si_mctl { GET, SET, BIS, BIC }; 10910015Speter 11010015Speterstatic void si_command __P((struct si_port *, int, int)); 11110015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 11210015Speterstatic void si_write_enable __P((struct si_port *, int)); 11338351Sbdestatic int si_Sioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 11410015Speterstatic void si_start __P((struct tty *)); 11525047Sbdestatic timeout_t si_lstart; 11610015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 11710015Speter struct si_port *pp)); 11810015Speterstatic void sihardclose __P((struct si_port *pp)); 11910015Speterstatic void sidtrwakeup __P((void *chan)); 12010015Speter 12112724Sphkstatic int siparam __P((struct tty *, struct termios *)); 12210015Speter 12312724Sphkstatic int siprobe __P((struct isa_device *id)); 12412724Sphkstatic int siattach __P((struct isa_device *id)); 12510708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 12634735Speterstatic void si_intr __P((int unit)); 12734832Speterstatic char * si_modulename __P((int host_type, int uart_type)); 12810708Speter 12912675Sjulianstruct isa_driver sidriver = 13012675Sjulian { siprobe, siattach, "si" }; 13112675Sjulian 13234832Speterstatic u_long sipcieisacount = 0; 13334832Speter 13433395Speter#if NPCI > 0 13512675Sjulian 13642546Seivindstatic const char *sipciprobe __P((pcici_t, pcidi_t)); 13733395Speterstatic void sipciattach __P((pcici_t, int)); 13833395Speter 13933395Speterstatic struct pci_device sipcidev = { 14033395Speter "si", 14133395Speter sipciprobe, 14233395Speter sipciattach, 14334832Speter &sipcieisacount, 14433395Speter NULL, 14533395Speter}; 14633395Speter 14746024Speter#ifdef COMPAT_PCI_DRIVER 14846024SpeterCOMPAT_PCI_DRIVER (sipci, sipcidev); 14946024Speter#else 15033395SpeterDATA_SET (pcidevice_set, sipcidev); 15146024Speter#endif /* COMPAT_PCI_DRIVER */ 15233395Speter 15333395Speter#endif 15433395Speter 15534832Speter#if NEISA > 0 15634832Speter 15734832Speterstatic int si_eisa_probe __P((void)); 15834832Speterstatic int si_eisa_attach __P((struct eisa_device *ed)); 15934832Speter 16034832Speterstatic struct eisa_driver si_eisa_driver = { 16134832Speter "si", 16234832Speter si_eisa_probe, 16334832Speter si_eisa_attach, 16434832Speter NULL, 16534832Speter &sipcieisacount, 16634832Speter}; 16734832Speter 16834832SpeterDATA_SET(eisadriver_set, si_eisa_driver); 16934832Speter 17034832Speter#endif 17134832Speter 17212675Sjulianstatic d_open_t siopen; 17312675Sjulianstatic d_close_t siclose; 17412675Sjulianstatic d_read_t siread; 17512675Sjulianstatic d_write_t siwrite; 17612675Sjulianstatic d_ioctl_t siioctl; 17712675Sjulianstatic d_stop_t sistop; 17812731Sbdestatic d_devtotty_t sidevtotty; 17912675Sjulian 18038485Sbde#define CDEV_MAJOR 68 18138485Sbdestatic struct cdevsw si_cdevsw = { 18238485Sbde siopen, siclose, siread, siwrite, 18338485Sbde siioctl, sistop, noreset, sidevtotty, 18438485Sbde ttpoll, nommap, NULL, "si", 18538485Sbde NULL, -1, nodump, nopsize, 18638485Sbde D_TTY, 18738485Sbde}; 18812675Sjulian 18912174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 19013353Speter 19113353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 19213353Speter ...)); 19310708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 19413353Speter 19510708Speter#define DPRINT(x) si_dprintf x 19613353Speter 19710708Speter#else 19810708Speter#define DPRINT(x) /* void */ 19910708Speter#endif 20010708Speter 20110962Speterstatic int si_Nports; 20210962Speterstatic int si_Nmodules; 20310962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 20410015Speter 20534832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 20634832Speter 20710962Speterstatic struct tty *si_tty; 20810962Speter 20934832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */ 21034832Speter/* old: si2_z280.c */ 21134832Speterextern unsigned char si2_z280_download[]; 21234832Speterextern unsigned short si2_z280_downloadaddr; 21334832Speterextern int si2_z280_dsize; 21434832Speter/* new: si3_t225.c */ 21534832Speterextern unsigned char si3_t225_download[]; 21634832Speterextern unsigned short si3_t225_downloadaddr; 21734832Speterextern int si3_t225_dsize; 21834832Speterextern unsigned char si3_t225_bootstrap[]; 21934832Speterextern unsigned short si3_t225_bootloadaddr; 22034832Speterextern int si3_t225_bsize; 22110015Speter 22233395Speter 22310044Speterstruct si_softc { 22410044Speter int sc_type; /* adapter type */ 22510044Speter char *sc_typename; /* adapter type string */ 22610044Speter 22710044Speter struct si_port *sc_ports; /* port structures for this card */ 22810044Speter 22910044Speter caddr_t sc_paddr; /* physical addr of iomem */ 23010044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 23110044Speter int sc_nport; /* # ports on this card */ 23210044Speter int sc_irq; /* copy of attach irq */ 23334832Speter#if NEISA > 0 23410044Speter int sc_eisa_iobase; /* EISA io port address */ 23534832Speter int sc_eisa_irq; /* EISA irq number */ 23634832Speter#endif 23712675Sjulian#ifdef DEVFS 23812675Sjulian struct { 23934735Speter void *ttya; 24012826Speter void *cuaa; 24112675Sjulian void *ttyl; 24234735Speter void *cual; 24312675Sjulian void *ttyi; 24434735Speter void *cuai; 24512675Sjulian } devfs_token[32]; /* what is the max per card? */ 24613165Speter void *control_token; 24712675Sjulian#endif 24810044Speter}; 24912724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 25010044Speter 25112174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 25210015Speter# define B2000 2000 25310015Speter#endif 25410015Speterstatic struct speedtab bdrates[] = { 25510015Speter B75, CLK75, /* 0x0 */ 25610015Speter B110, CLK110, /* 0x1 */ 25710015Speter B150, CLK150, /* 0x3 */ 25810015Speter B300, CLK300, /* 0x4 */ 25910015Speter B600, CLK600, /* 0x5 */ 26010015Speter B1200, CLK1200, /* 0x6 */ 26110015Speter B2000, CLK2000, /* 0x7 */ 26210015Speter B2400, CLK2400, /* 0x8 */ 26310015Speter B4800, CLK4800, /* 0x9 */ 26410015Speter B9600, CLK9600, /* 0xb */ 26510015Speter B19200, CLK19200, /* 0xc */ 26610015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 26710015Speter B57600, CLK57600, /* 0xd */ 26810015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 26910015Speter -1, -1 27010015Speter}; 27110015Speter 27210015Speter 27310015Speter/* populated with approx character/sec rates - translated at card 27410015Speter * initialisation time to chars per tick of the clock */ 27510015Speterstatic int done_chartimes = 0; 27610015Speterstatic struct speedtab chartimes[] = { 27710015Speter B75, 8, 27810015Speter B110, 11, 27910015Speter B150, 15, 28010015Speter B300, 30, 28110015Speter B600, 60, 28210015Speter B1200, 120, 28310015Speter B2000, 200, 28410015Speter B2400, 240, 28510015Speter B4800, 480, 28610015Speter B9600, 960, 28710015Speter B19200, 1920, 28810015Speter B38400, 3840, 28910015Speter B57600, 5760, 29010015Speter B115200, 11520, 29110015Speter -1, -1 29210015Speter}; 29310015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 29410015Speter 29510015Speter#ifdef POLL 29615683Speterstatic int si_pollrate; /* in addition to irq */ 29717547Speterstatic int si_realpoll; /* poll HW on timer */ 29815639Speter 29916403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 30017547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 30115639Speter 30210015Speterstatic int init_finished = 0; 30310015Speterstatic void si_poll __P((void *)); 30410015Speter#endif 30510015Speter 30610015Speter/* 30710015Speter * Array of adapter types and the corresponding RAM size. The order of 30810015Speter * entries here MUST match the ordinal of the adapter type. 30910015Speter */ 31010015Speterstatic char *si_type[] = { 31110015Speter "EMPTY", 31210015Speter "SIHOST", 31334832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 31410015Speter "SIHOST2", 31510015Speter "SIEISA", 31633395Speter "SIPCI", 31733395Speter "SXPCI", 31833395Speter "SXISA", 31910015Speter}; 32010015Speter 32133395Speter#if NPCI > 0 32233395Speter 32342546Seivindstatic const char * 32433395Spetersipciprobe(configid, deviceid) 32533395Speterpcici_t configid; 32633395Speterpcidi_t deviceid; 32733395Speter{ 32833395Speter switch (deviceid) 32933395Speter { 33033395Speter case 0x400011cb: 33133395Speter return("Specialix SI/XIO PCI host card"); 33233395Speter break; 33333395Speter case 0x200011cb: 33433395Speter if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb) 33533395Speter return("Specialix SX PCI host card"); 33633395Speter else 33733395Speter return NULL; 33833395Speter break; 33933395Speter default: 34033395Speter return NULL; 34133395Speter } 34233395Speter /*NOTREACHED*/ 34333395Speter} 34433395Speter 34533395Spetervoid 34633395Spetersipciattach(configid, unit) 34733395Speterpcici_t configid; 34833395Speterint unit; 34933395Speter{ 35033395Speter struct isa_device id; 35133395Speter vm_offset_t vaddr,paddr; 35233395Speter u_long mapval = 0; /* shut up gcc, should not be needed */ 35333395Speter 35433395Speter switch ( pci_conf_read(configid, 0) >> 16 ) 35533395Speter { 35633395Speter case 0x4000: 35733395Speter si_softc[unit].sc_type = SIPCI; 35833395Speter mapval = SIPCIBADR; 35934832Speter break; 36033395Speter case 0x2000: 36133395Speter si_softc[unit].sc_type = SIJETPCI; 36233395Speter mapval = SIJETBADR; 36334832Speter break; 36433395Speter } 36533395Speter if (!pci_map_mem(configid, mapval, &vaddr, &paddr)) 36633395Speter { 36733395Speter printf("si%d: couldn't map memory\n", unit); 36833395Speter } 36933395Speter 37033395Speter /* 37133395Speter * We're cheating here a little bit. The argument to an ISA 37233395Speter * interrupt routine is the unit number. The argument to a 37333395Speter * PCI interrupt handler is a void *, but we're simply going 37433395Speter * to be lazy and hand it the unit number. 37533395Speter */ 37634735Speter if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) { 37733395Speter printf("si%d: couldn't map interrupt\n", unit); 37833395Speter } 37933395Speter si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type]; 38033395Speter 38133395Speter /* 38233395Speter * More cheating: We're going to dummy up a struct isa_device 38333395Speter * and call the other attach routine. We don't really have to 38433395Speter * fill in very much of the structure, since we filled in a 38533395Speter * little of the soft state already. 38633395Speter */ 38734735Speter id.id_unit = unit; 38834735Speter id.id_maddr = (caddr_t) vaddr; 38933395Speter siattach(&id); 39033395Speter} 39133395Speter 39233395Speter#endif 39333395Speter 39434832Speter#if NEISA > 0 39534832Speter 39634832Speterstatic const char *si_eisa_match __P((eisa_id_t id)); 39734832Speter 39834832Speterstatic const char * 39934832Spetersi_eisa_match(id) 40034832Speter eisa_id_t id; 40134832Speter{ 40234832Speter if (id == SIEISADEVID) 40334832Speter return ("Specialix SI/XIO EISA host card"); 40434832Speter return (NULL); 40534832Speter} 40634832Speter 40734832Speterstatic int 40834832Spetersi_eisa_probe(void) 40934832Speter{ 41034832Speter struct eisa_device *ed = NULL; 41134832Speter int count, irq; 41234832Speter 41334832Speter for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++) 41434832Speter { 41534832Speter u_long port,maddr; 41634832Speter 41734832Speter port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE; 41834832Speter eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE); 41934832Speter maddr = (inb(port+1) << 24) | (inb(port) << 16); 42034832Speter irq = ((inb(port+2) >> 4) & 0xf); 42134832Speter eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE); 42234832Speter eisa_add_intr(ed, irq); 42334832Speter eisa_registerdev(ed, &si_eisa_driver); 42434832Speter count++; 42534832Speter } 42634832Speter return count; 42734832Speter} 42834832Speter 42934832Speterstatic int 43034832Spetersi_eisa_attach(ed) 43134832Speter struct eisa_device *ed; 43234832Speter{ 43334832Speter struct isa_device id; 43434832Speter resvaddr_t *maddr,*iospace; 43534832Speter u_int irq; 43634832Speter struct si_softc *sc; 43734832Speter 43834832Speter sc = &si_softc[ed->unit]; 43934832Speter 44034832Speter sc->sc_type = SIEISA; 44134832Speter sc->sc_typename = si_type[sc->sc_type]; 44234832Speter 44334832Speter if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) { 44438487Sbde printf("si%lu: no iospace??\n", ed->unit); 44534832Speter return -1; 44634832Speter } 44734832Speter sc->sc_eisa_iobase = iospace->addr; 44834832Speter 44934832Speter irq = ((inb(iospace->addr + 2) >> 4) & 0xf); 45034832Speter sc->sc_eisa_irq = irq; 45134832Speter 45234832Speter if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) { 45338487Sbde printf("si%lu: where am I??\n", ed->unit); 45434832Speter return -1; 45534832Speter } 45634832Speter eisa_reg_start(ed); 45734832Speter if (eisa_reg_iospace(ed, iospace)) { 45838487Sbde printf("si%lu: failed to register iospace %p\n", 45938487Sbde ed->unit, (void *)iospace); 46034832Speter return -1; 46134832Speter } 46234832Speter if (eisa_reg_mspace(ed, maddr)) { 46338487Sbde printf("si%lu: failed to register memspace %p\n", 46438487Sbde ed->unit, (void *)maddr); 46534832Speter return -1; 46634832Speter } 46734832Speter /* 46834832Speter * We're cheating here a little bit. The argument to an ISA 46934832Speter * interrupt routine is the unit number. The argument to a 47034832Speter * EISA interrupt handler is a void *, but we're simply going 47134832Speter * to be lazy and hand it the unit number. 47234832Speter */ 47334832Speter if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr, 47438353Sbde (void *)(intptr_t)(ed->unit), &tty_imask, 1)) { 47538487Sbde printf("si%lu: failed to register interrupt %d\n", 47634832Speter ed->unit, irq); 47734832Speter return -1; 47834832Speter } 47934832Speter eisa_reg_end(ed); 48034832Speter if (eisa_enable_intr(ed, irq)) { 48134832Speter return -1; 48234832Speter } 48334832Speter 48434832Speter /* 48534832Speter * More cheating: We're going to dummy up a struct isa_device 48634832Speter * and call the other attach routine. We don't really have to 48734832Speter * fill in very much of the structure, since we filled in a 48834832Speter * little of the soft state already. 48934832Speter */ 49034832Speter id.id_unit = ed->unit; 49134832Speter id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE); 49234832Speter return (siattach(&id)); 49334832Speter} 49434832Speter 49534832Speter#endif 49634832Speter 49734832Speter 49810015Speter/* Look for a valid board at the given mem addr */ 49912724Sphkstatic int 50010015Spetersiprobe(id) 50110015Speter struct isa_device *id; 50210015Speter{ 50310015Speter struct si_softc *sc; 50410015Speter int type; 50510015Speter u_int i, ramsize; 50610015Speter volatile BYTE was, *ux; 50710015Speter volatile unsigned char *maddr; 50810015Speter unsigned char *paddr; 50910015Speter 51017547Speter si_pollrate = POLLHZ; /* default 10 per second */ 51117547Speter#ifdef REALPOLL 51217547Speter si_realpoll = 1; /* scan always */ 51317547Speter#endif 51410015Speter maddr = id->id_maddr; /* virtual address... */ 51510015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 51610015Speter 51712496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 51812496Speter id->id_unit, id->id_maddr, paddr)); 51910015Speter 52010015Speter /* 52110015Speter * this is a lie, but it's easier than trying to handle caching 52210015Speter * and ram conflicts in the >1M and <16M region. 52310015Speter */ 52410015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 52510015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 52638353Sbde printf("si%d: iomem (%p) out of range\n", 52738353Sbde id->id_unit, (void *)paddr); 52810015Speter return(0); 52910015Speter } 53010015Speter 53110015Speter if (id->id_unit >= NSI) { 53210015Speter /* THIS IS IMPOSSIBLE */ 53310015Speter return(0); 53410015Speter } 53510015Speter 53610015Speter if (((u_int)paddr & 0x7fff) != 0) { 53710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 53810015Speter "si%d: iomem (%x) not on 32k boundary\n", 53910015Speter id->id_unit, paddr)); 54010015Speter return(0); 54110015Speter } 54210015Speter 54334735Speter if (si_softc[id->id_unit].sc_typename) { 54434832Speter /* EISA or PCI has taken this unit, choose another */ 54534735Speter for (i=0; i < NSI; i++) { 54634735Speter if (si_softc[i].sc_typename == NULL) { 54734735Speter id->id_unit = i; 54834735Speter break; 54934735Speter } 55034735Speter } 55134735Speter if (i >= NSI) { 55234735Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 55334735Speter "si%d: cannot realloc unit\n", id->id_unit)); 55434735Speter return (0); 55534735Speter } 55634735Speter } 55734735Speter 55810015Speter for (i=0; i < NSI; i++) { 55934735Speter sc = &si_softc[i]; 56010015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 56110015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 56210015Speter "si%d: iomem (%x) already configured to si%d\n", 56310015Speter id->id_unit, sc->sc_paddr, i)); 56410015Speter return(0); 56510015Speter } 56610015Speter } 56710015Speter 56810015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 56910015Speter *maddr = 0x17; 57010015Speter if (*maddr != 0x17) { 57110015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 57210015Speter "si%d: 0x17 check fail at phys 0x%x\n", 57310015Speter id->id_unit, paddr)); 57410015Speterfail: 57510015Speter return(0); 57610015Speter } 57710015Speter /* 57833395Speter * Let's look first for a JET ISA card, since that's pretty easy 57934832Speter * 58034832Speter * All jet hosts are supposed to have this string in the IDROM, 58134832Speter * but it's not worth checking on self-IDing busses like PCI. 58233395Speter */ 58334832Speter { 58434832Speter unsigned char *jet_chk_str = "JET HOST BY KEV#"; 58534832Speter 58634832Speter for (i = 0; i < strlen(jet_chk_str); i++) 58734832Speter if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i)) 58834832Speter goto try_mk2; 58934832Speter } 59033395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 59133395Speter "si%d: JET first check - 0x%x\n", 59233395Speter id->id_unit, (*(maddr+SIJETIDBASE)))); 59333395Speter if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff)) 59433395Speter goto try_mk2; 59533395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 59633395Speter "si%d: JET second check - 0x%x\n", 59733395Speter id->id_unit, (*(maddr+SIJETIDBASE+2)))); 59833395Speter if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8)) 59933395Speter goto try_mk2; 60033395Speter /* It must be a Jet ISA or RIO card */ 60133395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 60233395Speter "si%d: JET id check - 0x%x\n", 60333395Speter id->id_unit, (*(maddr+SIUNIQID)))); 60433395Speter if ((*(maddr+SIUNIQID) & 0xf0) !=0x20) 60533395Speter goto try_mk2; 60633395Speter /* It must be a Jet ISA SI/XIO card */ 60733395Speter *(maddr + SIJETCONFIG) = 0; 60833395Speter type = SIJETISA; 60933395Speter ramsize = SIJET_RAMSIZE; 61033395Speter goto got_card; 61133395Speter /* 61210015Speter * OK, now to see if whatever responded is really an SI card. 61333395Speter * Try for a MK II next (SIHOST2) 61410015Speter */ 61533395Spetertry_mk2: 61634832Speter for (i = SIPLSIG; i < SIPLSIG + 8; i++) 61710015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 61810015Speter goto try_mk1; 61910015Speter 62010015Speter /* It must be an SIHOST2 */ 62110015Speter *(maddr + SIPLRESET) = 0; 62210015Speter *(maddr + SIPLIRQCLR) = 0; 62310015Speter *(maddr + SIPLIRQSET) = 0x10; 62410015Speter type = SIHOST2; 62510015Speter ramsize = SIHOST2_RAMSIZE; 62610015Speter goto got_card; 62710015Speter 62810015Speter /* 62910015Speter * Its not a MK II, so try for a MK I (SIHOST) 63010015Speter */ 63110015Spetertry_mk1: 63210015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 63310015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 63410015Speter *(maddr+SIRAM) = 0x17; 63510015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 63610015Speter goto fail; 63710015Speter *(maddr+0x7ff8) = 0x17; 63810015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 63910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 64010015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 64110015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 64210015Speter goto fail; 64310015Speter } 64410015Speter 64534832Speter /* It must be an SIHOST (maybe?) - there must be a better way XXX */ 64610015Speter type = SIHOST; 64710015Speter ramsize = SIHOST_RAMSIZE; 64810015Speter 64910015Spetergot_card: 65012496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 65112496Speter id->id_unit, type)); 65210015Speter /* Try the acid test */ 65318515Speter ux = maddr + SIRAM; 65434832Speter for (i = 0; i < ramsize; i++, ux++) 65510015Speter *ux = (BYTE)(i&0xff); 65618515Speter ux = maddr + SIRAM; 65734832Speter for (i = 0; i < ramsize; i++, ux++) { 65810015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 65910015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 66012174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 66134832Speter id->id_unit, paddr + i, was, i&0xff)); 66210015Speter goto fail; 66310015Speter } 66410015Speter } 66510015Speter 66610015Speter /* clear out the RAM */ 66718515Speter ux = maddr + SIRAM; 66834832Speter for (i = 0; i < ramsize; i++) 66910015Speter *ux++ = 0; 67018515Speter ux = maddr + SIRAM; 67134832Speter for (i = 0; i < ramsize; i++) { 67210015Speter if ((was = *ux++) != 0) { 67310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 67412174Speter "si%d: clear fail at phys 0x%x, was %x\n", 67534832Speter id->id_unit, paddr + i, was)); 67610015Speter goto fail; 67710015Speter } 67810015Speter } 67910015Speter 68010015Speter /* 68110015Speter * Success, we've found a valid board, now fill in 68210015Speter * the adapter structure. 68310015Speter */ 68410015Speter switch (type) { 68510015Speter case SIHOST2: 68634832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 68710015Speterbad_irq: 68810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 68910015Speter "si%d: bad IRQ value - %d\n", 69010015Speter id->id_unit, id->id_irq)); 69110015Speter return(0); 69210015Speter } 69310015Speter id->id_msize = SIHOST2_MEMSIZE; 69410015Speter break; 69510015Speter case SIHOST: 69634832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 69710015Speter goto bad_irq; 69810015Speter } 69910015Speter id->id_msize = SIHOST_MEMSIZE; 70010015Speter break; 70133395Speter case SIJETISA: 70234832Speter if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) { 70333395Speter goto bad_irq; 70433395Speter } 70534832Speter id->id_msize = SIJETISA_MEMSIZE; 70633395Speter break; 70734832Speter case SIMCA: /* MCA */ 70810015Speter default: 70910015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 71010015Speter return(0); 71110015Speter } 71234832Speter id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */ 71310015Speter si_softc[id->id_unit].sc_type = type; 71410015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 71510015Speter return(-1); /* -1 == found */ 71610015Speter} 71710015Speter 71810015Speter/* 71934832Speter * We have to make an 8 bit version of bcopy, since some cards can't 72034832Speter * deal with 32 bit I/O 72134832Speter */ 72234832Speter#if 1 72334832Speterstatic void 72434832Spetersi_bcopy(const void *src, void *dst, size_t len) 72534832Speter{ 72634832Speter while (len--) 72734832Speter *(((u_char *)dst)++) = *(((u_char *)src)++); 72834832Speter} 72934832Speter#else 73034832Speter#define si_bcopy bcopy 73134832Speter#endif 73234832Speter 73334832Speter 73434832Speter/* 73510015Speter * Attach the device. Initialize the card. 73634832Speter * 73734832Speter * This routine also gets called by the EISA and PCI attach routines. 73834832Speter * It presumes that the softstate for the unit has had had its type field 73934832Speter * and the EISA specific stuff filled in, as well as the kernel virtual 74034832Speter * base address and the unit number of the isa_device struct. 74110015Speter */ 74212724Sphkstatic int 74310015Spetersiattach(id) 74410015Speter struct isa_device *id; 74510015Speter{ 74610015Speter int unit = id->id_unit; 74710015Speter struct si_softc *sc = &si_softc[unit]; 74810015Speter struct si_port *pp; 74910015Speter volatile struct si_channel *ccbp; 75010015Speter volatile struct si_reg *regp; 75110015Speter volatile caddr_t maddr; 75210015Speter struct si_module *modp; 75310015Speter struct tty *tp; 75410015Speter struct speedtab *spt; 75510015Speter int nmodule, nport, x, y; 75612174Speter int uart_type; 75710015Speter 75812496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 75910015Speter 76010015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 76110015Speter sc->sc_maddr = id->id_maddr; 76210015Speter sc->sc_irq = id->id_irq; 76310015Speter 76433395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 76533395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 76633395Speter 76710015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 76810015Speter 76910015Speter maddr = sc->sc_maddr; 77010015Speter 77134832Speter /* Stop the CPU first so it won't stomp around while we load */ 77234832Speter 77334832Speter switch (sc->sc_type) { 77434832Speter#if NEISA > 0 77534832Speter case SIEISA: 77634832Speter outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4); 77734832Speter break; 77834832Speter#endif 77934832Speter#if NPCI > 0 78034832Speter case SIPCI: 78134832Speter *(maddr+SIPCIRESET) = 0; 78234832Speter break; 78334832Speter case SIJETPCI: /* fall through to JET ISA */ 78434832Speter#endif 78534832Speter case SIJETISA: 78634832Speter *(maddr+SIJETCONFIG) = 0; 78734832Speter break; 78834832Speter case SIHOST2: 78934832Speter *(maddr+SIPLRESET) = 0; 79034832Speter break; 79134832Speter case SIHOST: 79234832Speter *(maddr+SIRESET) = 0; 79334832Speter break; 79434832Speter default: /* this should never happen */ 79534832Speter printf("si%d: unsupported configuration\n", unit); 79634832Speter return 0; 79734832Speter break; 79834832Speter } 79934832Speter 80034832Speter /* OK, now lets download the download code */ 80134832Speter 80236956Ssteve if (SI_ISJET(sc->sc_type)) { 80333395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 80434832Speter id->id_unit, si3_t225_dsize)); 80534832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 80634832Speter si3_t225_dsize); 80734832Speter DPRINT((0, DBG_DOWNLOAD, 80834832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 80934832Speter id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr)); 81034832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 81134832Speter si3_t225_bsize); 81234832Speter } else { 81333395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 81434832Speter id->id_unit, si2_z280_dsize)); 81534832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 81634832Speter si2_z280_dsize); 81733395Speter } 81810015Speter 81934832Speter /* Now start the CPU */ 82034832Speter 82110015Speter switch (sc->sc_type) { 82234832Speter#if NEISA > 0 82310015Speter case SIEISA: 82434832Speter /* modify the download code to tell it that it's on an EISA */ 82534832Speter *(maddr + 0x42) = 1; 82634832Speter outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4); 82734832Speter (void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */ 82810015Speter break; 82934832Speter#endif 83033395Speter case SIPCI: 83134832Speter /* modify the download code to tell it that it's on a PCI */ 83233395Speter *(maddr+0x42) = 1; 83333395Speter *(maddr+SIPCIRESET) = 1; 83433395Speter *(maddr+SIPCIINTCL) = 0; 83533395Speter break; 83633395Speter case SIJETPCI: 83733395Speter *(maddr+SIJETRESET) = 0; 83833395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 83933395Speter break; 84033395Speter case SIJETISA: 84133395Speter *(maddr+SIJETRESET) = 0; 84234832Speter switch (sc->sc_irq) { 84334832Speter case IRQ9: 84434832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 84534832Speter break; 84634832Speter case IRQ10: 84734832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 84834832Speter break; 84934832Speter case IRQ11: 85034832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 85134832Speter break; 85234832Speter case IRQ12: 85334832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 85434832Speter break; 85534832Speter case IRQ15: 85634832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 85734832Speter break; 85834832Speter } 85933395Speter break; 86010015Speter case SIHOST: 86110015Speter *(maddr+SIRESET_CL) = 0; 86210015Speter *(maddr+SIINTCL_CL) = 0; 86310015Speter break; 86410015Speter case SIHOST2: 86510015Speter *(maddr+SIPLRESET) = 0x10; 86610015Speter switch (sc->sc_irq) { 86710015Speter case IRQ11: 86810015Speter *(maddr+SIPLIRQ11) = 0x10; 86910015Speter break; 87010015Speter case IRQ12: 87110015Speter *(maddr+SIPLIRQ12) = 0x10; 87210015Speter break; 87310015Speter case IRQ15: 87410015Speter *(maddr+SIPLIRQ15) = 0x10; 87510015Speter break; 87610015Speter } 87710015Speter *(maddr+SIPLIRQCLR) = 0x10; 87810015Speter break; 87934832Speter default: /* this should _REALLY_ never happen */ 88034832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 88134832Speter return 0; 88210015Speter } 88310015Speter 88410015Speter DELAY(1000000); /* wait around for a second */ 88510015Speter 88610015Speter regp = (struct si_reg *)maddr; 88710015Speter y = 0; 88810015Speter /* wait max of 5 sec for init OK */ 88910015Speter while (regp->initstat == 0 && y++ < 10) { 89010015Speter DELAY(500000); 89110015Speter } 89210015Speter switch (regp->initstat) { 89310015Speter case 0: 89410015Speter printf("si%d: startup timeout - aborting\n", unit); 89512174Speter sc->sc_type = SIEMPTY; 89610015Speter return 0; 89710015Speter case 1: 89836956Ssteve if (SI_ISJET(sc->sc_type)) { 89934832Speter /* set throttle to 100 times per second */ 90034832Speter regp->int_count = JET_INT_COUNT; 90134832Speter /* rx_intr_count is a NOP in Jet */ 90234832Speter } else { 90334832Speter /* set throttle to 125 times per second */ 90434832Speter regp->int_count = INT_COUNT; 90534832Speter /* rx intr max of 25 times per second */ 90634832Speter regp->rx_int_count = RXINT_COUNT; 90734832Speter } 90810015Speter regp->int_pending = 0; /* no intr pending */ 90910015Speter regp->int_scounter = 0; /* reset counter */ 91010015Speter break; 91110015Speter case 0xff: 91210015Speter /* 91310015Speter * No modules found, so give up on this one. 91410015Speter */ 91510015Speter printf("si%d: %s - no ports found\n", unit, 91610015Speter si_type[sc->sc_type]); 91710015Speter return 0; 91810015Speter default: 91934832Speter printf("si%d: download code version error - initstat %x\n", 92010015Speter unit, regp->initstat); 92110015Speter return 0; 92210015Speter } 92310015Speter 92410015Speter /* 92510015Speter * First time around the ports just count them in order 92610015Speter * to allocate some memory. 92710015Speter */ 92810015Speter nport = 0; 92910015Speter modp = (struct si_module *)(maddr + 0x80); 93010015Speter for (;;) { 93112174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 93234832Speter switch (modp->sm_type) { 93334832Speter case TA4: 93410015Speter DPRINT((0, DBG_DOWNLOAD, 93534832Speter "si%d: Found old TA4 module, 4 ports\n", 93634832Speter unit)); 93734832Speter x = 4; 93810015Speter break; 93934832Speter case TA8: 94034832Speter DPRINT((0, DBG_DOWNLOAD, 94134832Speter "si%d: Found old TA8 module, 8 ports\n", 94234832Speter unit)); 94334832Speter x = 8; 94434832Speter break; 94534832Speter case TA4_ASIC: 94634832Speter DPRINT((0, DBG_DOWNLOAD, 94734832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 94834832Speter unit)); 94934832Speter x = 4; 95034832Speter break; 95134832Speter case TA8_ASIC: 95234832Speter DPRINT((0, DBG_DOWNLOAD, 95334832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 95434832Speter unit)); 95534832Speter x = 8; 95634832Speter break; 95734832Speter case MTA: 95834832Speter DPRINT((0, DBG_DOWNLOAD, 95934832Speter "si%d: Found CD1400 module, 8 ports\n", 96034832Speter unit)); 96134832Speter x = 8; 96234832Speter break; 96334832Speter case SXDC: 96434832Speter DPRINT((0, DBG_DOWNLOAD, 96534832Speter "si%d: Found SXDC module, 8 ports\n", 96634832Speter unit)); 96734832Speter x = 8; 96834832Speter break; 96910015Speter default: 97010015Speter printf("si%d: unknown module type %d\n", 97110015Speter unit, modp->sm_type); 97234832Speter goto try_next; 97310015Speter } 97434832Speter 97534832Speter /* this was limited in firmware and is also a driver issue */ 97634832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 97734832Speter printf("si%d: extra ports ignored\n", unit); 97834832Speter goto try_next; 97934832Speter } 98034832Speter 98134832Speter nport += x; 98234832Speter si_Nports += x; 98334832Speter si_Nmodules++; 98434832Speter 98534832Spetertry_next: 98610015Speter if (modp->sm_next == 0) 98710015Speter break; 98810015Speter modp = (struct si_module *) 98910015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 99010015Speter } 99110015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 99210015Speter M_DEVBUF, M_NOWAIT); 99310015Speter if (sc->sc_ports == 0) { 99410015Spetermem_fail: 99510015Speter printf("si%d: fail to malloc memory for port structs\n", 99610015Speter unit); 99710015Speter return 0; 99810015Speter } 99910015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 100010015Speter sc->sc_nport = nport; 100110015Speter 100210015Speter /* 100310015Speter * allocate tty structures for ports 100410015Speter */ 100510015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 100610015Speter if (tp == 0) 100710015Speter goto mem_fail; 100810015Speter bzero(tp, sizeof(*tp) * nport); 100910962Speter si_tty = tp; 101010015Speter 101110015Speter /* 101210015Speter * Scan round the ports again, this time initialising. 101310015Speter */ 101410015Speter pp = sc->sc_ports; 101510015Speter nmodule = 0; 101610015Speter modp = (struct si_module *)(maddr + 0x80); 101734832Speter uart_type = 1000; /* arbitary, > uchar_max */ 101810015Speter for (;;) { 101934832Speter switch (modp->sm_type) { 102034832Speter case TA4: 102134832Speter nport = 4; 102210015Speter break; 102334832Speter case TA8: 102434832Speter nport = 8; 102534832Speter break; 102634832Speter case TA4_ASIC: 102734832Speter nport = 4; 102834832Speter break; 102934832Speter case TA8_ASIC: 103034832Speter nport = 8; 103134832Speter break; 103234832Speter case MTA: 103334832Speter nport = 8; 103434832Speter break; 103534832Speter case SXDC: 103634832Speter nport = 8; 103734832Speter break; 103810015Speter default: 103934832Speter goto try_next2; 104010015Speter } 104134832Speter nmodule++; 104234832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 104334832Speter if (uart_type == 1000) 104434832Speter uart_type = ccbp->type; 104534832Speter else if (uart_type != ccbp->type) 104634832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 104734832Speter unit, nmodule, 104834832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 104934832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 105034832Speter 105134832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 105234832Speter pp->sp_ccb = ccbp; /* save the address */ 105334832Speter pp->sp_tty = tp++; 105434832Speter pp->sp_pend = IDLE_CLOSE; 105534832Speter pp->sp_state = 0; /* internal flag */ 105634832Speter pp->sp_dtr_wait = 3 * hz; 105734832Speter pp->sp_iin.c_iflag = TTYDEF_IFLAG; 105834832Speter pp->sp_iin.c_oflag = TTYDEF_OFLAG; 105934832Speter pp->sp_iin.c_cflag = TTYDEF_CFLAG; 106034832Speter pp->sp_iin.c_lflag = TTYDEF_LFLAG; 106134832Speter termioschars(&pp->sp_iin); 106234832Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 106334832Speter TTYDEF_SPEED;; 106434832Speter pp->sp_iout = pp->sp_iin; 106534832Speter } 106634832Spetertry_next2: 106710015Speter if (modp->sm_next == 0) { 106834832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 106910015Speter unit, 107010015Speter sc->sc_typename, 107110015Speter sc->sc_nport, 107212174Speter nmodule, 107334832Speter uart_type, 107434832Speter si_modulename(sc->sc_type, uart_type)); 107510015Speter break; 107610015Speter } 107710015Speter modp = (struct si_module *) 107810015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 107910015Speter } 108010015Speter if (done_chartimes == 0) { 108110015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 108210015Speter if ((spt->sp_code /= hz) == 0) 108310015Speter spt->sp_code = 1; 108410015Speter } 108510015Speter done_chartimes = 1; 108610015Speter } 108712502Sjulian 108812675Sjulian#ifdef DEVFS 108912675Sjulian/* path name devsw minor type uid gid perm*/ 109013169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 109134735Speter /* sync with the manuals that start at 1 */ 109234735Speter y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT); 109334735Speter sc->devfs_token[x].ttya = devfs_add_devswf( 109413630Sphk &si_cdevsw, x, 109513630Sphk DV_CHR, 0, 0, 0600, "ttyA%02d", y); 109613630Sphk sc->devfs_token[x].cuaa = devfs_add_devswf( 109734735Speter &si_cdevsw, x + 0x00080, 109813630Sphk DV_CHR, 0, 0, 0600, "cuaA%02d", y); 109913630Sphk sc->devfs_token[x].ttyi = devfs_add_devswf( 110013630Sphk &si_cdevsw, x + 0x10000, 110113630Sphk DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 110234735Speter sc->devfs_token[x].cuai = devfs_add_devswf( 110334735Speter &si_cdevsw, x + 0x10080, 110434735Speter DV_CHR, 0, 0, 0600, "cuaiA%02d", y); 110513630Sphk sc->devfs_token[x].ttyl = devfs_add_devswf( 110613630Sphk &si_cdevsw, x + 0x20000, 110713630Sphk DV_CHR, 0, 0, 0600, "ttylA%02d", y); 110834735Speter sc->devfs_token[x].cual = devfs_add_devswf( 110934735Speter &si_cdevsw, x + 0x20080, 111034735Speter DV_CHR, 0, 0, 0600, "cualA%02d", y); 111112675Sjulian } 111214873Sscrappy sc->control_token = 111314873Sscrappy devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 111414873Sscrappy "si_control"); 111512675Sjulian#endif 111610015Speter return (1); 111710015Speter} 111810015Speter 111912675Sjulianstatic int 112010015Spetersiopen(dev, flag, mode, p) 112110015Speter dev_t dev; 112210015Speter int flag, mode; 112310015Speter struct proc *p; 112410015Speter{ 112510015Speter int oldspl, error; 112610015Speter int card, port; 112710015Speter register struct si_softc *sc; 112810015Speter register struct tty *tp; 112910015Speter volatile struct si_channel *ccbp; 113010015Speter struct si_port *pp; 113110015Speter int mynor = minor(dev); 113210015Speter 113310015Speter /* quickly let in /dev/si_control */ 113410015Speter if (IS_CONTROLDEV(mynor)) { 113546112Sphk if ((error = suser(p))) 113610015Speter return(error); 113710015Speter return(0); 113810015Speter } 113910015Speter 114010015Speter card = SI_CARD(mynor); 114110015Speter if (card >= NSI) 114210015Speter return (ENXIO); 114310015Speter sc = &si_softc[card]; 114410015Speter 114512174Speter if (sc->sc_type == SIEMPTY) { 114612174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 114710015Speter card, sc->sc_typename)); 114810015Speter return(ENXIO); 114910015Speter } 115010015Speter 115110015Speter port = SI_PORT(mynor); 115210015Speter if (port >= sc->sc_nport) { 115312174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 115410015Speter card, sc->sc_nport)); 115510015Speter return(ENXIO); 115610015Speter } 115710015Speter 115810015Speter#ifdef POLL 115910015Speter /* 116010015Speter * We've now got a device, so start the poller. 116110015Speter */ 116210015Speter if (init_finished == 0) { 116315639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 116410015Speter init_finished = 1; 116510015Speter } 116610015Speter#endif 116710015Speter 116810015Speter /* initial/lock device */ 116910015Speter if (IS_STATE(mynor)) { 117010015Speter return(0); 117110015Speter } 117210015Speter 117310015Speter pp = sc->sc_ports + port; 117410015Speter tp = pp->sp_tty; /* the "real" tty */ 117510015Speter ccbp = pp->sp_ccb; /* Find control block */ 117610015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 117710015Speter dev, flag, mode, p)); 117810015Speter 117910015Speter oldspl = spltty(); /* Keep others out */ 118010015Speter error = 0; 118110015Speter 118210015Speteropen_top: 118310015Speter while (pp->sp_state & SS_DTR_OFF) { 118410015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 118510015Speter if (error != 0) 118610015Speter goto out; 118710015Speter } 118810015Speter 118910015Speter if (tp->t_state & TS_ISOPEN) { 119010015Speter /* 119110015Speter * The device is open, so everything has been initialised. 119210015Speter * handle conflicts. 119310015Speter */ 119410015Speter if (IS_CALLOUT(mynor)) { 119510015Speter if (!pp->sp_active_out) { 119610015Speter error = EBUSY; 119710015Speter goto out; 119810015Speter } 119910015Speter } else { 120010015Speter if (pp->sp_active_out) { 120110015Speter if (flag & O_NONBLOCK) { 120210015Speter error = EBUSY; 120310015Speter goto out; 120410015Speter } 120510015Speter error = tsleep(&pp->sp_active_out, 120610015Speter TTIPRI|PCATCH, "sibi", 0); 120710015Speter if (error != 0) 120810015Speter goto out; 120910015Speter goto open_top; 121010015Speter } 121110015Speter } 121243425Sphk if (tp->t_state & TS_XCLUDE && 121346112Sphk suser(p)) { 121410015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 121510015Speter "already open and EXCLUSIVE set\n")); 121610015Speter error = EBUSY; 121710015Speter goto out; 121810015Speter } 121910015Speter } else { 122010015Speter /* 122110015Speter * The device isn't open, so there are no conflicts. 122210015Speter * Initialize it. Avoid sleep... :-) 122310015Speter */ 122410015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 122510015Speter tp->t_oproc = si_start; 122610015Speter tp->t_param = siparam; 122710015Speter tp->t_dev = dev; 122810015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 122910015Speter ? pp->sp_iout : pp->sp_iin; 123010015Speter 123110015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 123210015Speter 123310015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 123410015Speter 123510015Speter error = siparam(tp, &tp->t_termios); 123610015Speter 123710015Speter --pp->sp_wopeners; 123810015Speter if (error != 0) 123910015Speter goto out; 124010015Speter /* XXX: we should goto_top if siparam slept */ 124110015Speter 124210015Speter /* set initial DCD state */ 124310015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 124410015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 124510015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 124610015Speter } 124710015Speter } 124810015Speter 124910015Speter /* whoops! we beat the close! */ 125010015Speter if (pp->sp_state & SS_CLOSING) { 125110015Speter /* try and stop it from proceeding to bash the hardware */ 125210015Speter pp->sp_state &= ~SS_CLOSING; 125310015Speter } 125410015Speter 125510015Speter /* 125610015Speter * Wait for DCD if necessary 125710015Speter */ 125810015Speter if (!(tp->t_state & TS_CARR_ON) 125910015Speter && !IS_CALLOUT(mynor) 126010015Speter && !(tp->t_cflag & CLOCAL) 126110015Speter && !(flag & O_NONBLOCK)) { 126210015Speter ++pp->sp_wopeners; 126310015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 126410015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 126510015Speter --pp->sp_wopeners; 126610015Speter if (error != 0) 126710015Speter goto out; 126810015Speter goto open_top; 126910015Speter } 127010015Speter 127110015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 127210015Speter si_disc_optim(tp, &tp->t_termios, pp); 127310015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 127410015Speter pp->sp_active_out = TRUE; 127510015Speter 127610015Speter pp->sp_state |= SS_OPEN; /* made it! */ 127710015Speter 127810015Speterout: 127910015Speter splx(oldspl); 128010015Speter 128110015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 128210015Speter 128310015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 128410015Speter sihardclose(pp); 128510015Speter 128610015Speter return(error); 128710015Speter} 128810015Speter 128912675Sjulianstatic int 129010015Spetersiclose(dev, flag, mode, p) 129110015Speter dev_t dev; 129210015Speter int flag, mode; 129310015Speter struct proc *p; 129410015Speter{ 129510015Speter register struct si_port *pp; 129610015Speter register struct tty *tp; 129710015Speter int oldspl; 129810015Speter int error = 0; 129910015Speter int mynor = minor(dev); 130010015Speter 130110015Speter if (IS_SPECIAL(mynor)) 130210015Speter return(0); 130310015Speter 130410015Speter oldspl = spltty(); 130510015Speter 130610015Speter pp = MINOR2PP(mynor); 130710015Speter tp = pp->sp_tty; 130810015Speter 130910015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 131010015Speter dev, flag, mode, p, pp->sp_state)); 131110015Speter 131210015Speter /* did we sleep and loose a race? */ 131310015Speter if (pp->sp_state & SS_CLOSING) { 131410015Speter /* error = ESOMETING? */ 131510015Speter goto out; 131610015Speter } 131710015Speter 131810015Speter /* begin race detection.. */ 131910015Speter pp->sp_state |= SS_CLOSING; 132010015Speter 132110015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 132210015Speter 132310015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 132410015Speter (*linesw[tp->t_line].l_close)(tp, flag); 132510015Speter 132610015Speter si_write_enable(pp, 1); 132710015Speter 132810015Speter /* did we sleep and somebody started another open? */ 132910015Speter if (!(pp->sp_state & SS_CLOSING)) { 133010015Speter /* error = ESOMETING? */ 133110015Speter goto out; 133210015Speter } 133310015Speter /* ok. we are now still on the right track.. nuke the hardware */ 133410015Speter 133510015Speter if (pp->sp_state & SS_LSTART) { 133629677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 133710015Speter pp->sp_state &= ~SS_LSTART; 133810015Speter } 133910015Speter 134010015Speter sistop(tp, FREAD | FWRITE); 134110015Speter 134210015Speter sihardclose(pp); 134310015Speter ttyclose(tp); 134410015Speter pp->sp_state &= ~SS_OPEN; 134510015Speter 134610015Speterout: 134710015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 134810015Speter splx(oldspl); 134910015Speter return(error); 135010015Speter} 135110015Speter 135210015Speterstatic void 135310015Spetersihardclose(pp) 135410015Speter struct si_port *pp; 135510015Speter{ 135610015Speter int oldspl; 135710015Speter struct tty *tp; 135810015Speter volatile struct si_channel *ccbp; 135910015Speter 136010015Speter oldspl = spltty(); 136110015Speter 136210015Speter tp = pp->sp_tty; 136310015Speter ccbp = pp->sp_ccb; /* Find control block */ 136410015Speter if (tp->t_cflag & HUPCL 136518515Speter || (!pp->sp_active_out 136634832Speter && !(ccbp->hi_ip & IP_DCD) 136734832Speter && !(pp->sp_iin.c_cflag && CLOCAL)) 136810015Speter || !(tp->t_state & TS_ISOPEN)) { 136910015Speter 137010015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 137110015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 137210015Speter 137310015Speter if (pp->sp_dtr_wait != 0) { 137410015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 137510015Speter pp->sp_state |= SS_DTR_OFF; 137610015Speter } 137710015Speter 137810015Speter } 137910015Speter pp->sp_active_out = FALSE; 138010015Speter wakeup((caddr_t)&pp->sp_active_out); 138110015Speter wakeup(TSA_CARR_ON(tp)); 138210015Speter 138310015Speter splx(oldspl); 138410015Speter} 138510015Speter 138610015Speter 138710015Speter/* 138810015Speter * called at splsoftclock()... 138910015Speter */ 139010015Speterstatic void 139110015Spetersidtrwakeup(chan) 139210015Speter void *chan; 139310015Speter{ 139410015Speter struct si_port *pp; 139510015Speter int oldspl; 139610015Speter 139710015Speter oldspl = spltty(); 139810015Speter 139910015Speter pp = (struct si_port *)chan; 140010015Speter pp->sp_state &= ~SS_DTR_OFF; 140110015Speter wakeup(&pp->sp_dtr_wait); 140210015Speter 140310015Speter splx(oldspl); 140410015Speter} 140510015Speter 140610015Speter/* 140710015Speter * User level stuff - read and write 140810015Speter */ 140912675Sjulianstatic int 141010015Spetersiread(dev, uio, flag) 141110015Speter register dev_t dev; 141210015Speter struct uio *uio; 141310015Speter int flag; 141410015Speter{ 141510015Speter register struct tty *tp; 141610015Speter int mynor = minor(dev); 141710015Speter 141810015Speter if (IS_SPECIAL(mynor)) { 141910015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 142010015Speter return(ENODEV); 142110015Speter } 142210015Speter tp = MINOR2TP(mynor); 142310015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 142410015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 142510015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 142610015Speter} 142710015Speter 142810015Speter 142912675Sjulianstatic int 143010015Spetersiwrite(dev, uio, flag) 143110015Speter dev_t dev; 143210015Speter struct uio *uio; 143310015Speter int flag; 143410015Speter{ 143510015Speter register struct si_port *pp; 143610015Speter register struct tty *tp; 143710015Speter int error = 0; 143810015Speter int mynor = minor(dev); 143910015Speter int oldspl; 144010015Speter 144110015Speter if (IS_SPECIAL(mynor)) { 144210015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 144310015Speter return(ENODEV); 144410015Speter } 144510015Speter pp = MINOR2PP(mynor); 144610015Speter tp = pp->sp_tty; 144710015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 144810015Speter 144910015Speter oldspl = spltty(); 145010015Speter /* 145110015Speter * If writes are currently blocked, wait on the "real" tty 145210015Speter */ 145310015Speter while (pp->sp_state & SS_BLOCKWRITE) { 145410015Speter pp->sp_state |= SS_WAITWRITE; 145510015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 145618515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 145718515Speter "siwrite", tp->t_timeout))) { 145817291Speter if (error == EWOULDBLOCK) 145917290Speter error = EIO; 146010015Speter goto out; 146117290Speter } 146210015Speter } 146310015Speter 146410015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 146510015Speterout: 146610015Speter splx(oldspl); 146710015Speter return (error); 146810015Speter} 146910015Speter 147010015Speter 147112675Sjulianstatic struct tty * 147210015Spetersidevtotty(dev_t dev) 147310015Speter{ 147410015Speter struct si_port *pp; 147510015Speter int mynor = minor(dev); 147610015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 147710015Speter 147810015Speter if (IS_SPECIAL(mynor)) 147910015Speter return(NULL); 148010015Speter if (SI_PORT(mynor) >= sc->sc_nport) 148110015Speter return(NULL); 148210015Speter pp = MINOR2PP(mynor); 148310015Speter return (pp->sp_tty); 148410015Speter} 148510015Speter 148612675Sjulianstatic int 148710015Spetersiioctl(dev, cmd, data, flag, p) 148810015Speter dev_t dev; 148936735Sdfr u_long cmd; 149010015Speter caddr_t data; 149110015Speter int flag; 149210015Speter struct proc *p; 149310015Speter{ 149410015Speter struct si_port *pp; 149510015Speter register struct tty *tp; 149610015Speter int error; 149710015Speter int mynor = minor(dev); 149810015Speter int oldspl; 149910015Speter int blocked = 0; 150010015Speter#if defined(COMPAT_43) 150138351Sbde u_long oldcmd; 150210015Speter struct termios term; 150310015Speter#endif 150410015Speter 150510015Speter if (IS_SI_IOCTL(cmd)) 150610015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 150710015Speter 150810015Speter pp = MINOR2PP(mynor); 150910015Speter tp = pp->sp_tty; 151010015Speter 151138351Sbde DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%lx,%x,%x)\n", 151210015Speter dev, cmd, data, flag)); 151310015Speter if (IS_STATE(mynor)) { 151410015Speter struct termios *ct; 151510015Speter 151610015Speter switch (mynor & SI_STATE_MASK) { 151710015Speter case SI_INIT_STATE_MASK: 151810015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 151910015Speter break; 152010015Speter case SI_LOCK_STATE_MASK: 152116839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 152210015Speter break; 152310015Speter default: 152410015Speter return (ENODEV); 152510015Speter } 152610015Speter switch (cmd) { 152710015Speter case TIOCSETA: 152846112Sphk error = suser(p); 152910015Speter if (error != 0) 153010015Speter return (error); 153110015Speter *ct = *(struct termios *)data; 153210015Speter return (0); 153310015Speter case TIOCGETA: 153410015Speter *(struct termios *)data = *ct; 153510015Speter return (0); 153610015Speter case TIOCGETD: 153710015Speter *(int *)data = TTYDISC; 153810015Speter return (0); 153910015Speter case TIOCGWINSZ: 154010015Speter bzero(data, sizeof(struct winsize)); 154110015Speter return (0); 154210015Speter default: 154310015Speter return (ENOTTY); 154410015Speter } 154510015Speter } 154610015Speter /* 154710015Speter * Do the old-style ioctl compat routines... 154810015Speter */ 154910015Speter#if defined(COMPAT_43) 155010015Speter term = tp->t_termios; 155110015Speter oldcmd = cmd; 155210015Speter error = ttsetcompat(tp, &cmd, data, &term); 155310015Speter if (error != 0) 155410015Speter return (error); 155510015Speter if (cmd != oldcmd) 155610015Speter data = (caddr_t)&term; 155710015Speter#endif 155810015Speter /* 155910015Speter * Do the initial / lock state business 156010015Speter */ 156110015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 156210015Speter int cc; 156310015Speter struct termios *dt = (struct termios *)data; 156410015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 156510015Speter ? &pp->sp_lout : &pp->sp_lin; 156610015Speter 156710015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 156810015Speter | (dt->c_iflag & ~lt->c_iflag); 156910015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 157010015Speter | (dt->c_oflag & ~lt->c_oflag); 157110015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 157210015Speter | (dt->c_cflag & ~lt->c_cflag); 157310015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 157410015Speter | (dt->c_lflag & ~lt->c_lflag); 157510015Speter for (cc = 0; cc < NCCS; ++cc) 157610015Speter if (lt->c_cc[cc] != 0) 157710015Speter dt->c_cc[cc] = tp->t_cc[cc]; 157810015Speter if (lt->c_ispeed != 0) 157910015Speter dt->c_ispeed = tp->t_ispeed; 158010015Speter if (lt->c_ospeed != 0) 158110015Speter dt->c_ospeed = tp->t_ospeed; 158210015Speter } 158310015Speter 158410015Speter /* 158510015Speter * Block user-level writes to give the ttywait() 158610015Speter * a chance to completely drain for commands 158710015Speter * that require the port to be in a quiescent state. 158810015Speter */ 158910015Speter switch (cmd) { 159034832Speter case TIOCSETAW: 159134832Speter case TIOCSETAF: 159217396Speter case TIOCDRAIN: 159317396Speter#ifdef COMPAT_43 159417396Speter case TIOCSETP: 159517396Speter#endif 159610015Speter blocked++; /* block writes for ttywait() and siparam() */ 159710015Speter si_write_enable(pp, 0); 159810015Speter } 159910015Speter 160010015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 160131577Sbde if (error != ENOIOCTL) 160210015Speter goto out; 160310015Speter 160410015Speter oldspl = spltty(); 160510015Speter 160610015Speter error = ttioctl(tp, cmd, data, flag); 160710015Speter si_disc_optim(tp, &tp->t_termios, pp); 160831577Sbde if (error != ENOIOCTL) 160910015Speter goto outspl; 161010015Speter 161110015Speter switch (cmd) { 161210015Speter case TIOCSBRK: 161316575Speter si_command(pp, SBREAK, SI_WAIT); 161410015Speter break; 161510015Speter case TIOCCBRK: 161616575Speter si_command(pp, EBREAK, SI_WAIT); 161710015Speter break; 161810015Speter case TIOCSDTR: 161910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 162010015Speter break; 162110015Speter case TIOCCDTR: 162210015Speter (void) si_modem(pp, SET, 0); 162310015Speter break; 162410015Speter case TIOCMSET: 162510015Speter (void) si_modem(pp, SET, *(int *)data); 162610015Speter break; 162710015Speter case TIOCMBIS: 162810015Speter (void) si_modem(pp, BIS, *(int *)data); 162910015Speter break; 163010015Speter case TIOCMBIC: 163110015Speter (void) si_modem(pp, BIC, *(int *)data); 163210015Speter break; 163310015Speter case TIOCMGET: 163410015Speter *(int *)data = si_modem(pp, GET, 0); 163510015Speter break; 163610015Speter case TIOCMSDTRWAIT: 163710015Speter /* must be root since the wait applies to following logins */ 163846112Sphk error = suser(p); 163910015Speter if (error != 0) { 164010015Speter goto outspl; 164110015Speter } 164210015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 164310015Speter break; 164410015Speter case TIOCMGDTRWAIT: 164510015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 164610015Speter break; 164710015Speter 164810015Speter default: 164910015Speter error = ENOTTY; 165010015Speter } 165110015Speter error = 0; 165210015Speteroutspl: 165310015Speter splx(oldspl); 165410015Speterout: 165510015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 165610015Speter if (blocked) 165710015Speter si_write_enable(pp, 1); 165810015Speter return(error); 165910015Speter} 166010015Speter 166110015Speter/* 166210015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 166310015Speter */ 166410015Speterstatic int 166538351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 166610015Speter{ 166710015Speter struct si_softc *xsc; 166810015Speter register struct si_port *xpp; 166910015Speter volatile struct si_reg *regp; 167010015Speter struct si_tcsi *dp; 167110044Speter struct si_pstat *sps; 167211872Sphk int *ip, error = 0; 167310015Speter int oldspl; 167410015Speter int card, port; 167510015Speter int mynor = minor(dev); 167610015Speter 167738351Sbde DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%lx,%x,%x)\n", 167810015Speter dev, cmd, data, flag)); 167910015Speter 168010044Speter#if 1 168110044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 168210044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 168310044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 168410044Speter#endif 168510044Speter 168610015Speter if (!IS_CONTROLDEV(mynor)) { 168710015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 168810015Speter return(ENODEV); 168910015Speter } 169010015Speter 169110015Speter oldspl = spltty(); /* better safe than sorry */ 169210015Speter 169310015Speter ip = (int *)data; 169410015Speter 169546112Sphk#define SUCHECK if ((error = suser(p))) goto out 169610015Speter 169710015Speter switch (cmd) { 169810015Speter case TCSIPORTS: 169910015Speter *ip = si_Nports; 170010015Speter goto out; 170110015Speter case TCSIMODULES: 170210015Speter *ip = si_Nmodules; 170310015Speter goto out; 170410015Speter case TCSISDBG_ALL: 170510015Speter SUCHECK; 170610015Speter si_debug = *ip; 170710015Speter goto out; 170810015Speter case TCSIGDBG_ALL: 170910015Speter *ip = si_debug; 171010015Speter goto out; 171110015Speter default: 171210015Speter /* 171310015Speter * Check that a controller for this port exists 171410015Speter */ 171510044Speter 171610044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 171710044Speter 171810015Speter dp = (struct si_tcsi *)data; 171910044Speter sps = (struct si_pstat *)data; 172010015Speter card = dp->tc_card; 172110015Speter xsc = &si_softc[card]; /* check.. */ 172212174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 172310015Speter error = ENOENT; 172410015Speter goto out; 172510015Speter } 172610015Speter /* 172710015Speter * And check that a port exists 172810015Speter */ 172910015Speter port = dp->tc_port; 173010015Speter if (port < 0 || port >= xsc->sc_nport) { 173110015Speter error = ENOENT; 173210015Speter goto out; 173310015Speter } 173410015Speter xpp = xsc->sc_ports + port; 173510015Speter regp = (struct si_reg *)xsc->sc_maddr; 173610015Speter } 173710015Speter 173810015Speter switch (cmd) { 173910015Speter case TCSIDEBUG: 174010015Speter#ifdef SI_DEBUG 174110015Speter SUCHECK; 174210015Speter if (xpp->sp_debug) 174310015Speter xpp->sp_debug = 0; 174410015Speter else { 174510015Speter xpp->sp_debug = DBG_ALL; 174610015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 174710015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 174810015Speter } 174910015Speter break; 175010015Speter#else 175110015Speter error = ENODEV; 175210015Speter goto out; 175310015Speter#endif 175410015Speter case TCSISDBG_LEVEL: 175510015Speter case TCSIGDBG_LEVEL: 175610015Speter#ifdef SI_DEBUG 175710015Speter if (cmd == TCSIGDBG_LEVEL) { 175810015Speter dp->tc_dbglvl = xpp->sp_debug; 175910015Speter } else { 176010015Speter SUCHECK; 176110015Speter xpp->sp_debug = dp->tc_dbglvl; 176210015Speter } 176310015Speter break; 176410015Speter#else 176510015Speter error = ENODEV; 176610015Speter goto out; 176710015Speter#endif 176810015Speter case TCSIGRXIT: 176910015Speter dp->tc_int = regp->rx_int_count; 177010015Speter break; 177110015Speter case TCSIRXIT: 177210015Speter SUCHECK; 177310015Speter regp->rx_int_count = dp->tc_int; 177410015Speter break; 177510015Speter case TCSIGIT: 177610015Speter dp->tc_int = regp->int_count; 177710015Speter break; 177810015Speter case TCSIIT: 177910015Speter SUCHECK; 178010015Speter regp->int_count = dp->tc_int; 178110015Speter break; 178210044Speter case TCSISTATE: 178310044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 178410015Speter break; 178510044Speter /* these next three use a different structure */ 178610044Speter case TCSI_PORT: 178710015Speter SUCHECK; 178834832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 178910015Speter break; 179010044Speter case TCSI_CCB: 179110044Speter SUCHECK; 179234832Speter si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 179310015Speter break; 179410044Speter case TCSI_TTY: 179510044Speter SUCHECK; 179634832Speter si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 179710015Speter break; 179810015Speter default: 179910015Speter error = EINVAL; 180010015Speter goto out; 180110015Speter } 180210015Speterout: 180310015Speter splx(oldspl); 180410015Speter return(error); /* success */ 180510015Speter} 180610015Speter 180710015Speter/* 180810015Speter * siparam() : Configure line params 180910015Speter * called at spltty(); 181010015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 181110015Speter * caller must arrange this if it's important.. 181210015Speter */ 181312724Sphkstatic int 181410015Spetersiparam(tp, t) 181510015Speter register struct tty *tp; 181610015Speter register struct termios *t; 181710015Speter{ 181810015Speter register struct si_port *pp = TP2PP(tp); 181910015Speter volatile struct si_channel *ccbp; 182010015Speter int oldspl, cflag, iflag, oflag, lflag; 182110015Speter int error = 0; /* shutup gcc */ 182210015Speter int ispeed = 0; /* shutup gcc */ 182310015Speter int ospeed = 0; /* shutup gcc */ 182410161Speter BYTE val; 182510015Speter 182610015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 182710015Speter cflag = t->c_cflag; 182810015Speter iflag = t->c_iflag; 182910015Speter oflag = t->c_oflag; 183010015Speter lflag = t->c_lflag; 183110044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 183210044Speter oflag, cflag, iflag, lflag)); 183310015Speter 183434832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 183510015Speter 183610015Speter /* if not hung up.. */ 183710015Speter if (t->c_ospeed != 0) { 183810015Speter /* translate baud rate to firmware values */ 183910015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 184010015Speter ispeed = t->c_ispeed ? 184110015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 184210015Speter 184310015Speter /* enforce legit baud rate */ 184410015Speter if (ospeed < 0 || ispeed < 0) 184510015Speter return (EINVAL); 184610015Speter } 184710015Speter 184810015Speter oldspl = spltty(); 184910015Speter 185010015Speter ccbp = pp->sp_ccb; 185110015Speter 185210161Speter /* ========== set hi_break ========== */ 185310161Speter val = 0; 185410161Speter if (iflag & IGNBRK) /* Breaks */ 185510161Speter val |= BR_IGN; 185610161Speter if (iflag & BRKINT) /* Interrupt on break? */ 185710161Speter val |= BR_INT; 185810161Speter if (iflag & PARMRK) /* Parity mark? */ 185910161Speter val |= BR_PARMRK; 186010161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 186110161Speter val |= BR_PARIGN; 186210161Speter ccbp->hi_break = val; 186310161Speter 186410161Speter /* ========== set hi_csr ========== */ 186510015Speter /* if not hung up.. */ 186610015Speter if (t->c_ospeed != 0) { 186710015Speter /* Set I/O speeds */ 186810161Speter val = (ispeed << 4) | ospeed; 186910015Speter } 187010161Speter ccbp->hi_csr = val; 187110015Speter 187210161Speter /* ========== set hi_mr2 ========== */ 187310161Speter val = 0; 187410015Speter if (cflag & CSTOPB) /* Stop bits */ 187510161Speter val |= MR2_2_STOP; 187610015Speter else 187710161Speter val |= MR2_1_STOP; 187810161Speter /* 187910161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 188010161Speter * a DCE, hence the reverse sense of RTS and CTS 188110161Speter */ 188210161Speter /* Output Flow - RTS must be raised before data can be sent */ 188310161Speter if (cflag & CCTS_OFLOW) 188410161Speter val |= MR2_RTSCONT; 188510161Speter 188616575Speter ccbp->hi_mr2 = val; 188710161Speter 188810161Speter /* ========== set hi_mr1 ========== */ 188910161Speter val = 0; 189010015Speter if (!(cflag & PARENB)) /* Parity */ 189110161Speter val |= MR1_NONE; 189210015Speter else 189310161Speter val |= MR1_WITH; 189410015Speter if (cflag & PARODD) 189510161Speter val |= MR1_ODD; 189610015Speter 189710015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 189810161Speter val |= MR1_8_BITS; 189910015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 190010161Speter val |= MR1_7_BITS; 190110015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 190210161Speter val |= MR1_6_BITS; 190310015Speter } else { /* Must be 5 */ 190410161Speter val |= MR1_5_BITS; 190510015Speter } 190610161Speter /* 190710161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 190810161Speter * a DCE, hence the reverse sense of RTS and CTS 190910161Speter */ 191010161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 191110161Speter if (cflag & CRTS_IFLOW) 191210161Speter val |= MR1_CTSCONT; 191310015Speter 191410161Speter ccbp->hi_mr1 = val; 191510161Speter 191610161Speter /* ========== set hi_mask ========== */ 191710161Speter val = 0xff; 191810161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 191910161Speter val &= 0xFF; 192010161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 192110161Speter val &= 0x7F; 192210161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 192310161Speter val &= 0x3F; 192410161Speter } else { /* Must be 5 */ 192510161Speter val &= 0x1F; 192610161Speter } 192710015Speter if (iflag & ISTRIP) 192810161Speter val &= 0x7F; 192910015Speter 193010161Speter ccbp->hi_mask = val; 193110161Speter 193210161Speter /* ========== set hi_prtcl ========== */ 193310161Speter val = 0; 193410015Speter /* Monitor DCD etc. if a modem */ 193510015Speter if (!(cflag & CLOCAL)) 193610161Speter val |= SP_DCEN; 193710161Speter if (iflag & IXANY) 193810161Speter val |= SP_TANY; 193910161Speter if (iflag & IXON) 194010161Speter val |= SP_TXEN; 194110161Speter if (iflag & IXOFF) 194210161Speter val |= SP_RXEN; 194310161Speter if (iflag & INPCK) 194410161Speter val |= SP_PAEN; 194510015Speter 194610161Speter ccbp->hi_prtcl = val; 194710161Speter 194810161Speter 194910161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 195010161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 195110015Speter ccbp->hi_txon = t->c_cc[VSTART]; 195210015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 195310015Speter 195410015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 195510015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 195610015Speter 195710161Speter /* ========== send settings to the card ========== */ 195810015Speter /* potential sleep here */ 195910015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 196010015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 196110015Speter else 196210015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 196310015Speter 196410161Speter /* ========== set DTR etc ========== */ 196510015Speter /* Hangup if ospeed == 0 */ 196610015Speter if (t->c_ospeed == 0) { 196710015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 196810015Speter } else { 196910015Speter /* 197010015Speter * If the previous speed was 0, may need to re-enable 197134832Speter * the modem signals 197234832Speter */ 197310015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 197410015Speter } 197510015Speter 197610044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 197710044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 197810015Speter 197910015Speter splx(oldspl); 198010015Speter return(error); 198110015Speter} 198210015Speter 198310015Speter/* 198410015Speter * Enable or Disable the writes to this channel... 198510015Speter * "state" -> enabled = 1; disabled = 0; 198610015Speter */ 198710015Speterstatic void 198810015Spetersi_write_enable(pp, state) 198910015Speter register struct si_port *pp; 199010015Speter int state; 199110015Speter{ 199210015Speter int oldspl; 199310015Speter 199410015Speter oldspl = spltty(); 199510015Speter 199610015Speter if (state) { 199710015Speter pp->sp_state &= ~SS_BLOCKWRITE; 199810015Speter if (pp->sp_state & SS_WAITWRITE) { 199910015Speter pp->sp_state &= ~SS_WAITWRITE; 200010015Speter /* thunder away! */ 200110015Speter wakeup((caddr_t)pp); 200210015Speter } 200310015Speter } else { 200410015Speter pp->sp_state |= SS_BLOCKWRITE; 200510015Speter } 200610015Speter 200710015Speter splx(oldspl); 200810015Speter} 200910015Speter 201010015Speter/* 201110015Speter * Set/Get state of modem control lines. 201210015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 201310015Speter * TIOCM_DTR DSR 201410015Speter * TIOCM_RTS CTS 201510015Speter */ 201610015Speterstatic int 201710015Spetersi_modem(pp, cmd, bits) 201810015Speter struct si_port *pp; 201910015Speter enum si_mctl cmd; 202010015Speter int bits; 202110015Speter{ 202210015Speter volatile struct si_channel *ccbp; 202310015Speter int x; 202410015Speter 202510015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 202610015Speter ccbp = pp->sp_ccb; /* Find channel address */ 202710015Speter switch (cmd) { 202810015Speter case GET: 202910015Speter x = ccbp->hi_ip; 203010015Speter bits = TIOCM_LE; 203110015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 203210015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 203310015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 203410015Speter if (x & IP_RI) bits |= TIOCM_RI; 203510015Speter return(bits); 203610015Speter case SET: 203710015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 203810015Speter /* fall through */ 203910015Speter case BIS: 204010015Speter x = 0; 204110015Speter if (bits & TIOCM_DTR) 204210015Speter x |= OP_DSR; 204310015Speter if (bits & TIOCM_RTS) 204410015Speter x |= OP_CTS; 204510015Speter ccbp->hi_op |= x; 204610015Speter break; 204710015Speter case BIC: 204810015Speter if (bits & TIOCM_DTR) 204910015Speter ccbp->hi_op &= ~OP_DSR; 205010015Speter if (bits & TIOCM_RTS) 205110015Speter ccbp->hi_op &= ~OP_CTS; 205210015Speter } 205310015Speter return 0; 205410015Speter} 205510015Speter 205610015Speter/* 205710015Speter * Handle change of modem state 205810015Speter */ 205910015Speterstatic void 206010015Spetersi_modem_state(pp, tp, hi_ip) 206110015Speter register struct si_port *pp; 206210015Speter register struct tty *tp; 206310015Speter register int hi_ip; 206410015Speter{ 206510015Speter /* if a modem dev */ 206610015Speter if (hi_ip & IP_DCD) { 206710015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 206810015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 206910015Speter tp->t_line)); 207010015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 207110015Speter } 207210015Speter } else { 207310015Speter if (pp->sp_last_hi_ip & IP_DCD) { 207410015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 207510015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 207610015Speter (void) si_modem(pp, SET, 0); 207710015Speter } 207810015Speter } 207910015Speter pp->sp_last_hi_ip = hi_ip; 208010015Speter 208110015Speter} 208210015Speter 208310015Speter/* 208410015Speter * Poller to catch missed interrupts. 208512174Speter * 208612496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 208712496Speter * better response. We could really use a "periodic" version timeout(). :-) 208810015Speter */ 208910015Speter#ifdef POLL 209010708Speterstatic void 209110015Spetersi_poll(void *nothing) 209210015Speter{ 209310015Speter register struct si_softc *sc; 209410015Speter register int i; 209510015Speter volatile struct si_reg *regp; 209612174Speter register struct si_port *pp; 209712174Speter int lost, oldspl, port; 209810015Speter 209910015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 210011609Speter oldspl = spltty(); 210110015Speter if (in_intr) 210210015Speter goto out; 210310015Speter lost = 0; 210410015Speter for (i=0; i<NSI; i++) { 210510015Speter sc = &si_softc[i]; 210612174Speter if (sc->sc_type == SIEMPTY) 210710015Speter continue; 210810015Speter regp = (struct si_reg *)sc->sc_maddr; 210934832Speter 211010015Speter /* 211110015Speter * See if there has been a pending interrupt for 2 seconds 211233395Speter * or so. The test (int_scounter >= 200) won't correspond 211310015Speter * to 2 seconds if int_count gets changed. 211410015Speter */ 211510015Speter if (regp->int_pending != 0) { 211610015Speter if (regp->int_scounter >= 200 && 211710015Speter regp->initstat == 1) { 211812174Speter printf("si%d: lost intr\n", i); 211910015Speter lost++; 212010015Speter } 212110015Speter } else { 212210015Speter regp->int_scounter = 0; 212310015Speter } 212410015Speter 212512174Speter /* 212612174Speter * gripe about no input flow control.. 212712174Speter */ 212812174Speter pp = sc->sc_ports; 212912174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 213012174Speter if (pp->sp_delta_overflows > 0) { 213112174Speter printf("si%d: %d tty level buffer overflows\n", 213212174Speter i, pp->sp_delta_overflows); 213312174Speter pp->sp_delta_overflows = 0; 213412174Speter } 213512174Speter } 213610015Speter } 213717547Speter if (lost || si_realpoll) 213834735Speter si_intr(-1); /* call intr with fake vector */ 213911609Speterout: 214010015Speter splx(oldspl); 214110015Speter 214215639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 214310015Speter} 214410015Speter#endif /* ifdef POLL */ 214510015Speter 214610015Speter/* 214710015Speter * The interrupt handler polls ALL ports on ALL adapters each time 214810015Speter * it is called. 214910015Speter */ 215010015Speter 215112496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 215234832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 215310015Speter 215434735Speterstatic void 215534735Spetersi_intr(int unit) 215610015Speter{ 215710015Speter register struct si_softc *sc; 215810015Speter 215910015Speter register struct si_port *pp; 216010015Speter volatile struct si_channel *ccbp; 216110015Speter register struct tty *tp; 216210015Speter volatile caddr_t maddr; 216311872Sphk BYTE op, ip; 216412174Speter int x, card, port, n, i, isopen; 216510015Speter volatile BYTE *z; 216610015Speter BYTE c; 216710015Speter 216834735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit)); 216911609Speter if (in_intr) { 217011609Speter if (unit < 0) /* should never happen */ 217134832Speter printf("si%d: Warning poll entered during interrupt\n", 217234832Speter unit); 217334832Speter else 217434832Speter printf("si%d: Warning interrupt handler re-entered\n", 217534832Speter unit); 217610708Speter return; 217710015Speter } 217810015Speter in_intr = 1; 217910015Speter 218010015Speter /* 218110015Speter * When we get an int we poll all the channels and do ALL pending 218210015Speter * work, not just the first one we find. This allows all cards to 218310015Speter * share the same vector. 218434832Speter * 218534832Speter * XXX - But if we're sharing the vector with something that's NOT 218634832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 218710015Speter */ 218834832Speter for (card = 0; card < NSI; card++) { 218910015Speter sc = &si_softc[card]; 219012174Speter if (sc->sc_type == SIEMPTY) 219110015Speter continue; 219212174Speter 219312174Speter /* 219412174Speter * First, clear the interrupt 219512174Speter */ 219610015Speter switch(sc->sc_type) { 219734832Speter case SIHOST: 219810015Speter maddr = sc->sc_maddr; 219910015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 220010015Speter /* flag nothing pending */ 220110015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 220210015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 220310015Speter break; 220410015Speter case SIHOST2: 220510015Speter maddr = sc->sc_maddr; 220610015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 220710015Speter *(maddr+SIPLIRQCLR) = 0x00; 220810015Speter *(maddr+SIPLIRQCLR) = 0x10; 220910015Speter break; 221034832Speter#if NPCI > 0 221133395Speter case SIPCI: 221233395Speter maddr = sc->sc_maddr; 221333395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 221433395Speter *(maddr+SIPCIINTCL) = 0x0; 221533395Speter break; 221634832Speter case SIJETPCI: /* fall through to JETISA case */ 221734832Speter#endif 221833395Speter case SIJETISA: 221933395Speter maddr = sc->sc_maddr; 222033395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 222133395Speter *(maddr+SIJETINTCL) = 0x0; 222233395Speter break; 222334832Speter#if NEISA > 0 222410015Speter case SIEISA: 222510015Speter maddr = sc->sc_maddr; 222610015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 222734832Speter (void)inb(sc->sc_eisa_iobase + 3); 222810015Speter break; 222934832Speter#endif 223010015Speter case SIEMPTY: 223110015Speter default: 223210015Speter continue; 223310015Speter } 223410015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 223510015Speter 223612174Speter /* 223712174Speter * check each port 223812174Speter */ 223934832Speter for (pp = sc->sc_ports, port=0; port < sc->sc_nport; 224034832Speter pp++, port++) { 224110015Speter ccbp = pp->sp_ccb; 224210015Speter tp = pp->sp_tty; 224310015Speter 224410015Speter /* 224510015Speter * See if a command has completed ? 224610015Speter */ 224710015Speter if (ccbp->hi_stat != pp->sp_pend) { 224810015Speter DPRINT((pp, DBG_INTR, 224934735Speter "si_intr hi_stat = 0x%x, pend = %d\n", 225010015Speter ccbp->hi_stat, pp->sp_pend)); 225110015Speter switch(pp->sp_pend) { 225210015Speter case LOPEN: 225310015Speter case MPEND: 225410015Speter case MOPEN: 225510015Speter case CONFIG: 225616575Speter case SBREAK: 225716575Speter case EBREAK: 225810015Speter pp->sp_pend = ccbp->hi_stat; 225910015Speter /* sleeping in si_command */ 226010015Speter wakeup(&pp->sp_state); 226110015Speter break; 226210015Speter default: 226310015Speter pp->sp_pend = ccbp->hi_stat; 226410015Speter } 226534832Speter } 226610015Speter 226710015Speter /* 226810015Speter * Continue on if it's closed 226910015Speter */ 227010015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 227110015Speter continue; 227210015Speter } 227310015Speter 227410015Speter /* 227510015Speter * Do modem state change if not a local device 227610015Speter */ 227710015Speter si_modem_state(pp, tp, ccbp->hi_ip); 227810015Speter 227910015Speter /* 228034832Speter * Check to see if we should 'receive' characters. 228112174Speter */ 228212174Speter if (tp->t_state & TS_CONNECTED && 228312174Speter tp->t_state & TS_ISOPEN) 228412174Speter isopen = 1; 228512174Speter else 228612174Speter isopen = 0; 228712174Speter 228812174Speter /* 228916575Speter * Do input break processing 229010015Speter */ 229110015Speter if (ccbp->hi_state & ST_BREAK) { 229212174Speter if (isopen) { 229312174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 229410015Speter } 229510015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 229610015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 229710015Speter } 229810015Speter 229910015Speter /* 230012174Speter * Do RX stuff - if not open then dump any characters. 230112174Speter * XXX: This is VERY messy and needs to be cleaned up. 230212174Speter * 230312174Speter * XXX: can we leave data in the host adapter buffer 230412174Speter * when the clists are full? That may be dangerous 230512174Speter * if the user cannot get an interrupt signal through. 230610015Speter */ 230710015Speter 230812174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 230912174Speter 231012174Speter if (!isopen) { 231110015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 231212174Speter goto end_rx; 231312174Speter } 231410015Speter 231512174Speter /* 231615640Speter * If the tty input buffers are blocked, stop emptying 231715640Speter * the incoming buffers and let the auto flow control 231815640Speter * assert.. 231915640Speter */ 232015640Speter if (tp->t_state & TS_TBLOCK) { 232115640Speter goto end_rx; 232215640Speter } 232315640Speter 232415640Speter /* 232512174Speter * Process read characters if not skipped above 232612174Speter */ 232715640Speter op = ccbp->hi_rxopos; 232815640Speter ip = ccbp->hi_rxipos; 232915640Speter c = ip - op; 233012174Speter if (c == 0) { 233112174Speter goto end_rx; 233212174Speter } 233310015Speter 233412174Speter n = c & 0xff; 233515640Speter if (n > 250) 233615640Speter n = 250; 233712174Speter 233812174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 233910015Speter n, op, ip)); 234010015Speter 234112174Speter /* 234212174Speter * Suck characters out of host card buffer into the 234312174Speter * "input staging buffer" - so that we dont leave the 234412174Speter * host card in limbo while we're possibly echoing 234512174Speter * characters and possibly flushing input inside the 234612174Speter * ldisc l_rint() routine. 234712174Speter */ 234812496Speter if (n <= SI_BUFFERSIZE - op) { 234910015Speter 235012174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 235112174Speter z = ccbp->hi_rxbuf + op; 235234832Speter si_bcopy((caddr_t)z, si_rxbuf, n); 235310015Speter 235412174Speter op += n; 235512174Speter } else { 235612496Speter x = SI_BUFFERSIZE - op; 235710015Speter 235812174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 235912174Speter z = ccbp->hi_rxbuf + op; 236034832Speter si_bcopy((caddr_t)z, si_rxbuf, x); 236110015Speter 236234832Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 236334832Speter n - x)); 236412174Speter z = ccbp->hi_rxbuf; 236534832Speter si_bcopy((caddr_t)z, si_rxbuf + x, n - x); 236610015Speter 236712174Speter op += n; 236812174Speter } 236910015Speter 237012174Speter /* clear collected characters from buffer */ 237112174Speter ccbp->hi_rxopos = op; 237212174Speter 237312174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 237410015Speter n, op, ip)); 237510015Speter 237612174Speter /* 237712174Speter * at this point... 237812174Speter * n = number of chars placed in si_rxbuf 237912174Speter */ 238010015Speter 238112174Speter /* 238212174Speter * Avoid the grotesquely inefficient lineswitch 238312174Speter * routine (ttyinput) in "raw" mode. It usually 238412174Speter * takes about 450 instructions (that's without 238512174Speter * canonical processing or echo!). slinput is 238612174Speter * reasonably fast (usually 40 instructions 238712174Speter * plus call overhead). 238812174Speter */ 238912174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 239010015Speter 239112174Speter /* block if the driver supports it */ 239212174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 239312174Speter && (tp->t_cflag & CRTS_IFLOW 239412174Speter || tp->t_iflag & IXOFF) 239512174Speter && !(tp->t_state & TS_TBLOCK)) 239612174Speter ttyblock(tp); 239710015Speter 239812174Speter tk_nin += n; 239912174Speter tk_rawcc += n; 240012174Speter tp->t_rawcc += n; 240112174Speter 240212174Speter pp->sp_delta_overflows += 240312174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 240412174Speter 240512174Speter ttwakeup(tp); 240612174Speter if (tp->t_state & TS_TTSTOP 240712174Speter && (tp->t_iflag & IXANY 240812174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 240912174Speter tp->t_state &= ~TS_TTSTOP; 241012174Speter tp->t_lflag &= ~FLUSHO; 241112174Speter si_start(tp); 241212174Speter } 241312174Speter } else { 241412174Speter /* 241512174Speter * It'd be nice to not have to go through the 241612174Speter * function call overhead for each char here. 241712174Speter * It'd be nice to block input it, saving a 241812174Speter * loop here and the call/return overhead. 241912174Speter */ 242012174Speter for(x = 0; x < n; x++) { 242112174Speter i = si_rxbuf[x]; 242212174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 242312174Speter == -1) { 242412174Speter pp->sp_delta_overflows++; 242510015Speter } 242612174Speter /* 242712174Speter * doesn't seem to be much point doing 242812174Speter * this here.. this driver has no 242912174Speter * softtty processing! ?? 243012174Speter */ 243112174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 243212174Speter setsofttty(); 243312174Speter } 243412174Speter } 243512174Speter } 243612174Speter goto more_rx; /* try for more until RXbuf is empty */ 243710015Speter 243812174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 243910015Speter 244010015Speter /* 244110015Speter * Do TX stuff 244210015Speter */ 244310015Speter (*linesw[tp->t_line].l_start)(tp); 244410015Speter 244510015Speter } /* end of for (all ports on this controller) */ 244610015Speter } /* end of for (all controllers) */ 244710015Speter 244811609Speter in_intr = 0; 244934735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit)); 245010015Speter} 245110015Speter 245210015Speter/* 245310015Speter * Nudge the transmitter... 245412174Speter * 245512174Speter * XXX: I inherited some funny code here. It implies the host card only 245612174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 245712174Speter * not interrupt when it's actually hits empty. In some cases, we have 245812174Speter * processes waiting for complete drain, and we need to simulate an interrupt 245912174Speter * about when we think the buffer is going to be empty (and retry if not). 246012174Speter * I really am not certain about this... I *need* the hardware manuals. 246110015Speter */ 246210015Speterstatic void 246310015Spetersi_start(tp) 246410015Speter register struct tty *tp; 246510015Speter{ 246610015Speter struct si_port *pp; 246710015Speter volatile struct si_channel *ccbp; 246810015Speter register struct clist *qp; 246910015Speter BYTE ipos; 247010015Speter int nchar; 247110015Speter int oldspl, count, n, amount, buffer_full; 247210015Speter 247310015Speter oldspl = spltty(); 247410015Speter 247510015Speter qp = &tp->t_outq; 247610015Speter pp = TP2PP(tp); 247710015Speter 247810015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 247910015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 248010015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 248110015Speter 248210015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 248310015Speter goto out; 248410015Speter 248510015Speter buffer_full = 0; 248610015Speter ccbp = pp->sp_ccb; 248710015Speter 248810015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 248910015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 249010015Speter 249110015Speter while ((nchar = qp->c_cc) > 0) { 249210015Speter if ((BYTE)count >= 255) { 249310015Speter buffer_full++; 249410015Speter break; 249510015Speter } 249610015Speter amount = min(nchar, (255 - (BYTE)count)); 249710015Speter ipos = (unsigned int)ccbp->hi_txipos; 249834832Speter n = q_to_b(&tp->t_outq, si_txbuf, amount); 249910015Speter /* will it fit in one lump? */ 250034832Speter if ((SI_BUFFERSIZE - ipos) >= n) { 250134832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n); 250210015Speter } else { 250334832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], 250434832Speter SI_BUFFERSIZE - ipos); 250534832Speter si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos), 250634832Speter (char *)&ccbp->hi_txbuf[0], 250734832Speter n - (SI_BUFFERSIZE - ipos)); 250810015Speter } 250910015Speter ccbp->hi_txipos += n; 251010015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 251110015Speter } 251210015Speter 251310015Speter if (count != 0 && nchar == 0) { 251410015Speter tp->t_state |= TS_BUSY; 251510015Speter } else { 251610015Speter tp->t_state &= ~TS_BUSY; 251710015Speter } 251810015Speter 251910015Speter /* wakeup time? */ 252010015Speter ttwwakeup(tp); 252110015Speter 252210015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 252310015Speter (BYTE)count, nchar, tp->t_state)); 252410015Speter 252534735Speter if (tp->t_state & TS_BUSY) 252610015Speter { 252710015Speter int time; 252810015Speter 252934735Speter time = ttspeedtab(tp->t_ospeed, chartimes); 253034735Speter 253134735Speter if (time > 0) { 253234735Speter if (time < nchar) 253334735Speter time = nchar / time; 253434735Speter else 253534735Speter time = 2; 253610015Speter } else { 253734735Speter DPRINT((pp, DBG_START, 253834735Speter "bad char time value! %d\n", time)); 253934735Speter time = hz/10; 254010015Speter } 254110015Speter 254210015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 254329677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 254410015Speter } else { 254510015Speter pp->sp_state |= SS_LSTART; 254610015Speter } 254710015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 254829677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 254910015Speter } 255010015Speter 255110015Speterout: 255210015Speter splx(oldspl); 255310015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 255410015Speter} 255510015Speter 255610015Speter/* 255710015Speter * Note: called at splsoftclock from the timeout code 255810015Speter * This has to deal with two things... cause wakeups while waiting for 255910015Speter * tty drains on last process exit, and call l_start at about the right 256010015Speter * time for protocols like ppp. 256110015Speter */ 256210015Speterstatic void 256325047Sbdesi_lstart(void *arg) 256410015Speter{ 256525047Sbde register struct si_port *pp = arg; 256610015Speter register struct tty *tp; 256710015Speter int oldspl; 256810015Speter 256910015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 257010015Speter pp, pp->sp_state)); 257110015Speter 257210015Speter oldspl = spltty(); 257310015Speter 257410015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 257510015Speter splx(oldspl); 257610015Speter return; 257710015Speter } 257810015Speter pp->sp_state &= ~SS_LSTART; 257910015Speter pp->sp_state |= SS_INLSTART; 258010015Speter 258110015Speter tp = pp->sp_tty; 258210015Speter 258310015Speter /* deal with the process exit case */ 258410015Speter ttwwakeup(tp); 258510015Speter 258612174Speter /* nudge protocols - eg: ppp */ 258710015Speter (*linesw[tp->t_line].l_start)(tp); 258810015Speter 258910015Speter pp->sp_state &= ~SS_INLSTART; 259010015Speter splx(oldspl); 259110015Speter} 259210015Speter 259310015Speter/* 259410015Speter * Stop output on a line. called at spltty(); 259510015Speter */ 259610015Spetervoid 259710015Spetersistop(tp, rw) 259810015Speter register struct tty *tp; 259910015Speter int rw; 260010015Speter{ 260110015Speter volatile struct si_channel *ccbp; 260210015Speter struct si_port *pp; 260310015Speter 260410015Speter pp = TP2PP(tp); 260510015Speter ccbp = pp->sp_ccb; 260610015Speter 260710015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 260810015Speter 260910015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 261010015Speter if (rw & FWRITE) { 261110015Speter /* what level are we meant to be flushing anyway? */ 261210015Speter if (tp->t_state & TS_BUSY) { 261310015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 261410015Speter tp->t_state &= ~TS_BUSY; 261510015Speter ttwwakeup(tp); /* Bruce???? */ 261610015Speter } 261710015Speter } 261812174Speter#if 1 /* XXX: this doesn't work right yet.. */ 261912174Speter /* XXX: this may have been failing because we used to call l_rint() 262012174Speter * while we were looping based on these two counters. Now, we collect 262112174Speter * the data and then loop stuffing it into l_rint(), making this 262212174Speter * useless. Should we cause this to blow away the staging buffer? 262312174Speter */ 262410015Speter if (rw & FREAD) { 262510015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 262610015Speter } 262710015Speter#endif 262810015Speter} 262910015Speter 263010015Speter/* 263134832Speter * Issue a command to the host card CPU. 263210015Speter */ 263310015Speter 263410015Speterstatic void 263510015Spetersi_command(pp, cmd, waitflag) 263610015Speter struct si_port *pp; /* port control block (local) */ 263710015Speter int cmd; 263810015Speter int waitflag; 263910015Speter{ 264010015Speter int oldspl; 264110015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 264210015Speter int x; 264310015Speter 264410015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 264510015Speter pp, cmd, waitflag, ccbp->hi_stat)); 264610015Speter 264710015Speter oldspl = spltty(); /* Keep others out */ 264810015Speter 264910015Speter /* wait until it's finished what it was doing.. */ 265016575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 265116575Speter * is turned off. */ 265210015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 265310015Speter x != IDLE_CLOSE && 265416575Speter x != IDLE_BREAK && 265510015Speter x != cmd) { 265610015Speter if (in_intr) { /* Prevent sleep in intr */ 265710015Speter DPRINT((pp, DBG_PARAM, 265810015Speter "cmd intr collision - completing %d\trequested %d\n", 265910015Speter x, cmd)); 266010015Speter splx(oldspl); 266110015Speter return; 266210015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 266310015Speter "sicmd1", 1)) { 266410015Speter splx(oldspl); 266510015Speter return; 266610015Speter } 266710015Speter } 266816575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 266910015Speter 267010015Speter /* if there was a pending command, cause a state-change wakeup */ 267116575Speter switch(pp->sp_pend) { 267216575Speter case LOPEN: 267316575Speter case MPEND: 267416575Speter case MOPEN: 267516575Speter case CONFIG: 267616575Speter case SBREAK: 267716575Speter case EBREAK: 267816575Speter wakeup(&pp->sp_state); 267916575Speter break; 268016575Speter default: 268116575Speter break; 268210015Speter } 268310015Speter 268410015Speter pp->sp_pend = cmd; /* New command pending */ 268510015Speter ccbp->hi_stat = cmd; /* Post it */ 268610015Speter 268710015Speter if (waitflag) { 268810015Speter if (in_intr) { /* If in interrupt handler */ 268910015Speter DPRINT((pp, DBG_PARAM, 269010015Speter "attempt to sleep in si_intr - cmd req %d\n", 269110015Speter cmd)); 269210015Speter splx(oldspl); 269310015Speter return; 269416575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 269516575Speter ccbp->hi_stat != IDLE_BREAK) { 269610015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 269710015Speter "sicmd2", 0)) 269810015Speter break; 269910015Speter } 270010015Speter } 270110015Speter splx(oldspl); 270210015Speter} 270310015Speter 270410015Speterstatic void 270510015Spetersi_disc_optim(tp, t, pp) 270610015Speter struct tty *tp; 270710015Speter struct termios *t; 270810015Speter struct si_port *pp; 270910015Speter{ 271010015Speter /* 271110015Speter * XXX can skip a lot more cases if Smarts. Maybe 271210015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 271310015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 271410015Speter */ 271510015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 271610015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 271710015Speter && (!(t->c_iflag & PARMRK) 271810015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 271910015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 272010015Speter && linesw[tp->t_line].l_rint == ttyinput) 272110015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 272210015Speter else 272310015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 272433322Sphk pp->sp_hotchar = linesw[tp->t_line].l_hotchar; 272510161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 272610161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 272710161Speter pp->sp_hotchar)); 272810015Speter} 272910015Speter 273010015Speter 273110015Speter#ifdef SI_DEBUG 273213353Speter 273310015Speterstatic void 273413353Speter#ifdef __STDC__ 273513353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 273613353Speter#else 273713353Spetersi_dprintf(pp, flags, fmt, va_alist) 273810015Speter struct si_port *pp; 273910015Speter int flags; 274013353Speter char *fmt; 274113353Speter#endif 274210015Speter{ 274313353Speter va_list ap; 274413630Sphk 274510015Speter if ((pp == NULL && (si_debug&flags)) || 274610015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 274734832Speter if (pp != NULL) 274834832Speter printf("%ci%d(%d): ", 's', 274934832Speter (int)SI_CARD(pp->sp_tty->t_dev), 275034832Speter (int)SI_PORT(pp->sp_tty->t_dev)); 275113630Sphk va_start(ap, fmt); 275213630Sphk vprintf(fmt, ap); 275313353Speter va_end(ap); 275410015Speter } 275510015Speter} 275610015Speter 275710015Speterstatic char * 275810015Spetersi_mctl2str(cmd) 275910015Speter enum si_mctl cmd; 276010015Speter{ 276110015Speter switch (cmd) { 276234832Speter case GET: 276334832Speter return("GET"); 276434832Speter case SET: 276534832Speter return("SET"); 276634832Speter case BIS: 276734832Speter return("BIS"); 276834832Speter case BIC: 276934832Speter return("BIC"); 277010015Speter } 277110015Speter return("BAD"); 277210015Speter} 277312502Sjulian 277412624Speter#endif /* DEBUG */ 277512502Sjulian 277634832Speterstatic char * 277734832Spetersi_modulename(host_type, uart_type) 277834832Speter int host_type, uart_type; 277934832Speter{ 278034832Speter switch (host_type) { 278134832Speter /* Z280 based cards */ 278234832Speter#if NEISA > 0 278334832Speter case SIEISA: 278434832Speter#endif 278534832Speter case SIHOST2: 278634832Speter case SIHOST: 278734832Speter#if NPCI > 0 278834832Speter case SIPCI: 278934832Speter#endif 279034832Speter switch (uart_type) { 279134832Speter case 0: 279234832Speter return(" (XIO)"); 279334832Speter case 1: 279434832Speter return(" (SI)"); 279534832Speter } 279634832Speter break; 279734832Speter /* T225 based hosts */ 279834832Speter#if NPCI > 0 279934832Speter case SIJETPCI: 280034832Speter#endif 280134832Speter case SIJETISA: 280234832Speter switch (uart_type) { 280334832Speter case 0: 280434832Speter return(" (SI)"); 280534832Speter case 40: 280634832Speter return(" (XIO)"); 280736856Sphk case 72: 280836856Sphk return(" (SXDC)"); 280934832Speter } 281034832Speter break; 281134832Speter } 281234832Speter return(""); 281334832Speter} 281412624Speter 281512502Sjulianstatic si_devsw_installed = 0; 281612502Sjulian 281734832Speterstatic void 281834832Spetersi_drvinit(void *unused) 281912502Sjulian{ 282012517Sjulian dev_t dev; 282112517Sjulian 282234832Speter if (!si_devsw_installed) { 282312675Sjulian dev = makedev(CDEV_MAJOR, 0); 282412675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 282512502Sjulian si_devsw_installed = 1; 282634832Speter } 282712502Sjulian} 282812517Sjulian 282912517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 2830