si.c revision 38351
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 * 3338351Sbde * $Id: si.c,v 1.73 1998/06/13 19:36:22 steve 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 13633395Speterstatic 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 14733395SpeterDATA_SET (pcidevice_set, sipcidev); 14833395Speter 14933395Speter#endif 15033395Speter 15134832Speter#if NEISA > 0 15234832Speter 15334832Speterstatic int si_eisa_probe __P((void)); 15434832Speterstatic int si_eisa_attach __P((struct eisa_device *ed)); 15534832Speter 15634832Speterstatic struct eisa_driver si_eisa_driver = { 15734832Speter "si", 15834832Speter si_eisa_probe, 15934832Speter si_eisa_attach, 16034832Speter NULL, 16134832Speter &sipcieisacount, 16234832Speter}; 16334832Speter 16434832SpeterDATA_SET(eisadriver_set, si_eisa_driver); 16534832Speter 16634832Speter#endif 16734832Speter 16812675Sjulianstatic d_open_t siopen; 16912675Sjulianstatic d_close_t siclose; 17012675Sjulianstatic d_read_t siread; 17112675Sjulianstatic d_write_t siwrite; 17212675Sjulianstatic d_ioctl_t siioctl; 17312675Sjulianstatic d_stop_t sistop; 17412731Sbdestatic d_devtotty_t sidevtotty; 17512675Sjulian 17612675Sjulian#define CDEV_MAJOR 68 17734832Speterstatic struct cdevsw si_cdevsw = 17812675Sjulian { siopen, siclose, siread, siwrite, /*68*/ 17912743Sbde siioctl, sistop, noreset, sidevtotty,/* si */ 18029368Speter ttpoll, nommap, NULL, "si", NULL, -1 }; 18112675Sjulian 18212675Sjulian 18312174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 18413353Speter 18513353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 18613353Speter ...)); 18710708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 18813353Speter 18910708Speter#define DPRINT(x) si_dprintf x 19013353Speter 19110708Speter#else 19210708Speter#define DPRINT(x) /* void */ 19310708Speter#endif 19410708Speter 19510962Speterstatic int si_Nports; 19610962Speterstatic int si_Nmodules; 19710962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 19810015Speter 19934832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 20034832Speter 20110962Speterstatic struct tty *si_tty; 20210962Speter 20334832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */ 20434832Speter/* old: si2_z280.c */ 20534832Speterextern unsigned char si2_z280_download[]; 20634832Speterextern unsigned short si2_z280_downloadaddr; 20734832Speterextern int si2_z280_dsize; 20834832Speter/* new: si3_t225.c */ 20934832Speterextern unsigned char si3_t225_download[]; 21034832Speterextern unsigned short si3_t225_downloadaddr; 21134832Speterextern int si3_t225_dsize; 21234832Speterextern unsigned char si3_t225_bootstrap[]; 21334832Speterextern unsigned short si3_t225_bootloadaddr; 21434832Speterextern int si3_t225_bsize; 21510015Speter 21633395Speter 21710044Speterstruct si_softc { 21810044Speter int sc_type; /* adapter type */ 21910044Speter char *sc_typename; /* adapter type string */ 22010044Speter 22110044Speter struct si_port *sc_ports; /* port structures for this card */ 22210044Speter 22310044Speter caddr_t sc_paddr; /* physical addr of iomem */ 22410044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 22510044Speter int sc_nport; /* # ports on this card */ 22610044Speter int sc_irq; /* copy of attach irq */ 22734832Speter#if NEISA > 0 22810044Speter int sc_eisa_iobase; /* EISA io port address */ 22934832Speter int sc_eisa_irq; /* EISA irq number */ 23034832Speter#endif 23112675Sjulian#ifdef DEVFS 23212675Sjulian struct { 23334735Speter void *ttya; 23412826Speter void *cuaa; 23512675Sjulian void *ttyl; 23634735Speter void *cual; 23712675Sjulian void *ttyi; 23834735Speter void *cuai; 23912675Sjulian } devfs_token[32]; /* what is the max per card? */ 24013165Speter void *control_token; 24112675Sjulian#endif 24210044Speter}; 24312724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 24410044Speter 24512174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 24610015Speter# define B2000 2000 24710015Speter#endif 24810015Speterstatic struct speedtab bdrates[] = { 24910015Speter B75, CLK75, /* 0x0 */ 25010015Speter B110, CLK110, /* 0x1 */ 25110015Speter B150, CLK150, /* 0x3 */ 25210015Speter B300, CLK300, /* 0x4 */ 25310015Speter B600, CLK600, /* 0x5 */ 25410015Speter B1200, CLK1200, /* 0x6 */ 25510015Speter B2000, CLK2000, /* 0x7 */ 25610015Speter B2400, CLK2400, /* 0x8 */ 25710015Speter B4800, CLK4800, /* 0x9 */ 25810015Speter B9600, CLK9600, /* 0xb */ 25910015Speter B19200, CLK19200, /* 0xc */ 26010015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 26110015Speter B57600, CLK57600, /* 0xd */ 26210015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 26310015Speter -1, -1 26410015Speter}; 26510015Speter 26610015Speter 26710015Speter/* populated with approx character/sec rates - translated at card 26810015Speter * initialisation time to chars per tick of the clock */ 26910015Speterstatic int done_chartimes = 0; 27010015Speterstatic struct speedtab chartimes[] = { 27110015Speter B75, 8, 27210015Speter B110, 11, 27310015Speter B150, 15, 27410015Speter B300, 30, 27510015Speter B600, 60, 27610015Speter B1200, 120, 27710015Speter B2000, 200, 27810015Speter B2400, 240, 27910015Speter B4800, 480, 28010015Speter B9600, 960, 28110015Speter B19200, 1920, 28210015Speter B38400, 3840, 28310015Speter B57600, 5760, 28410015Speter B115200, 11520, 28510015Speter -1, -1 28610015Speter}; 28710015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 28810015Speter 28910015Speter#ifdef POLL 29015683Speterstatic int si_pollrate; /* in addition to irq */ 29117547Speterstatic int si_realpoll; /* poll HW on timer */ 29215639Speter 29316403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 29417547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 29515639Speter 29610015Speterstatic int init_finished = 0; 29710015Speterstatic void si_poll __P((void *)); 29810015Speter#endif 29910015Speter 30010015Speter/* 30110015Speter * Array of adapter types and the corresponding RAM size. The order of 30210015Speter * entries here MUST match the ordinal of the adapter type. 30310015Speter */ 30410015Speterstatic char *si_type[] = { 30510015Speter "EMPTY", 30610015Speter "SIHOST", 30734832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 30810015Speter "SIHOST2", 30910015Speter "SIEISA", 31033395Speter "SIPCI", 31133395Speter "SXPCI", 31233395Speter "SXISA", 31310015Speter}; 31410015Speter 31533395Speter#if NPCI > 0 31633395Speter 31733395Speterstatic char * 31833395Spetersipciprobe(configid, deviceid) 31933395Speterpcici_t configid; 32033395Speterpcidi_t deviceid; 32133395Speter{ 32233395Speter switch (deviceid) 32333395Speter { 32433395Speter case 0x400011cb: 32533395Speter return("Specialix SI/XIO PCI host card"); 32633395Speter break; 32733395Speter case 0x200011cb: 32833395Speter if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb) 32933395Speter return("Specialix SX PCI host card"); 33033395Speter else 33133395Speter return NULL; 33233395Speter break; 33333395Speter default: 33433395Speter return NULL; 33533395Speter } 33633395Speter /*NOTREACHED*/ 33733395Speter} 33833395Speter 33933395Spetervoid 34033395Spetersipciattach(configid, unit) 34133395Speterpcici_t configid; 34233395Speterint unit; 34333395Speter{ 34433395Speter struct isa_device id; 34533395Speter vm_offset_t vaddr,paddr; 34633395Speter u_long mapval = 0; /* shut up gcc, should not be needed */ 34733395Speter 34833395Speter switch ( pci_conf_read(configid, 0) >> 16 ) 34933395Speter { 35033395Speter case 0x4000: 35133395Speter si_softc[unit].sc_type = SIPCI; 35233395Speter mapval = SIPCIBADR; 35334832Speter break; 35433395Speter case 0x2000: 35533395Speter si_softc[unit].sc_type = SIJETPCI; 35633395Speter mapval = SIJETBADR; 35734832Speter break; 35833395Speter } 35933395Speter if (!pci_map_mem(configid, mapval, &vaddr, &paddr)) 36033395Speter { 36133395Speter printf("si%d: couldn't map memory\n", unit); 36233395Speter } 36333395Speter 36433395Speter /* 36533395Speter * We're cheating here a little bit. The argument to an ISA 36633395Speter * interrupt routine is the unit number. The argument to a 36733395Speter * PCI interrupt handler is a void *, but we're simply going 36833395Speter * to be lazy and hand it the unit number. 36933395Speter */ 37034735Speter if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) { 37133395Speter printf("si%d: couldn't map interrupt\n", unit); 37233395Speter } 37333395Speter si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type]; 37433395Speter 37533395Speter /* 37633395Speter * More cheating: We're going to dummy up a struct isa_device 37733395Speter * and call the other attach routine. We don't really have to 37833395Speter * fill in very much of the structure, since we filled in a 37933395Speter * little of the soft state already. 38033395Speter */ 38134735Speter id.id_unit = unit; 38234735Speter id.id_maddr = (caddr_t) vaddr; 38333395Speter siattach(&id); 38433395Speter} 38533395Speter 38633395Speter#endif 38733395Speter 38834832Speter#if NEISA > 0 38934832Speter 39034832Speterstatic const char *si_eisa_match __P((eisa_id_t id)); 39134832Speter 39234832Speterstatic const char * 39334832Spetersi_eisa_match(id) 39434832Speter eisa_id_t id; 39534832Speter{ 39634832Speter if (id == SIEISADEVID) 39734832Speter return ("Specialix SI/XIO EISA host card"); 39834832Speter return (NULL); 39934832Speter} 40034832Speter 40134832Speterstatic int 40234832Spetersi_eisa_probe(void) 40334832Speter{ 40434832Speter struct eisa_device *ed = NULL; 40534832Speter int count, irq; 40634832Speter 40734832Speter for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++) 40834832Speter { 40934832Speter u_long port,maddr; 41034832Speter 41134832Speter port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE; 41234832Speter eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE); 41334832Speter maddr = (inb(port+1) << 24) | (inb(port) << 16); 41434832Speter irq = ((inb(port+2) >> 4) & 0xf); 41534832Speter eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE); 41634832Speter eisa_add_intr(ed, irq); 41734832Speter eisa_registerdev(ed, &si_eisa_driver); 41834832Speter count++; 41934832Speter } 42034832Speter return count; 42134832Speter} 42234832Speter 42334832Speterstatic int 42434832Spetersi_eisa_attach(ed) 42534832Speter struct eisa_device *ed; 42634832Speter{ 42734832Speter struct isa_device id; 42834832Speter resvaddr_t *maddr,*iospace; 42934832Speter u_int irq; 43034832Speter struct si_softc *sc; 43134832Speter 43234832Speter sc = &si_softc[ed->unit]; 43334832Speter 43434832Speter sc->sc_type = SIEISA; 43534832Speter sc->sc_typename = si_type[sc->sc_type]; 43634832Speter 43734832Speter if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) { 43834832Speter printf("si%d: no iospace??\n", ed->unit); 43934832Speter return -1; 44034832Speter } 44134832Speter sc->sc_eisa_iobase = iospace->addr; 44234832Speter 44334832Speter irq = ((inb(iospace->addr + 2) >> 4) & 0xf); 44434832Speter sc->sc_eisa_irq = irq; 44534832Speter 44634832Speter if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) { 44734832Speter printf("si%d: where am I??\n", ed->unit); 44834832Speter return -1; 44934832Speter } 45034832Speter eisa_reg_start(ed); 45134832Speter if (eisa_reg_iospace(ed, iospace)) { 45234832Speter printf("si%d: failed to register iospace 0x%x\n", 45334832Speter ed->unit, iospace); 45434832Speter return -1; 45534832Speter } 45634832Speter if (eisa_reg_mspace(ed, maddr)) { 45734832Speter printf("si%d: failed to register memspace 0x%x\n", 45834832Speter ed->unit, maddr); 45934832Speter return -1; 46034832Speter } 46134832Speter /* 46234832Speter * We're cheating here a little bit. The argument to an ISA 46334832Speter * interrupt routine is the unit number. The argument to a 46434832Speter * EISA interrupt handler is a void *, but we're simply going 46534832Speter * to be lazy and hand it the unit number. 46634832Speter */ 46734832Speter if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr, 46834832Speter (void *)(ed->unit), &tty_imask, 1)) { 46934832Speter printf("si%d: failed to register interrupt %d\n", 47034832Speter ed->unit, irq); 47134832Speter return -1; 47234832Speter } 47334832Speter eisa_reg_end(ed); 47434832Speter if (eisa_enable_intr(ed, irq)) { 47534832Speter return -1; 47634832Speter } 47734832Speter 47834832Speter /* 47934832Speter * More cheating: We're going to dummy up a struct isa_device 48034832Speter * and call the other attach routine. We don't really have to 48134832Speter * fill in very much of the structure, since we filled in a 48234832Speter * little of the soft state already. 48334832Speter */ 48434832Speter id.id_unit = ed->unit; 48534832Speter id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE); 48634832Speter return (siattach(&id)); 48734832Speter} 48834832Speter 48934832Speter#endif 49034832Speter 49134832Speter 49210015Speter/* Look for a valid board at the given mem addr */ 49312724Sphkstatic int 49410015Spetersiprobe(id) 49510015Speter struct isa_device *id; 49610015Speter{ 49710015Speter struct si_softc *sc; 49810015Speter int type; 49910015Speter u_int i, ramsize; 50010015Speter volatile BYTE was, *ux; 50110015Speter volatile unsigned char *maddr; 50210015Speter unsigned char *paddr; 50310015Speter 50417547Speter si_pollrate = POLLHZ; /* default 10 per second */ 50517547Speter#ifdef REALPOLL 50617547Speter si_realpoll = 1; /* scan always */ 50717547Speter#endif 50810015Speter maddr = id->id_maddr; /* virtual address... */ 50910015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 51010015Speter 51112496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 51212496Speter id->id_unit, id->id_maddr, paddr)); 51310015Speter 51410015Speter /* 51510015Speter * this is a lie, but it's easier than trying to handle caching 51610015Speter * and ram conflicts in the >1M and <16M region. 51710015Speter */ 51810015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 51910015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 52012174Speter printf("si%d: iomem (%lx) out of range\n", 52112174Speter id->id_unit, (long)paddr); 52210015Speter return(0); 52310015Speter } 52410015Speter 52510015Speter if (id->id_unit >= NSI) { 52610015Speter /* THIS IS IMPOSSIBLE */ 52710015Speter return(0); 52810015Speter } 52910015Speter 53010015Speter if (((u_int)paddr & 0x7fff) != 0) { 53110015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 53210015Speter "si%d: iomem (%x) not on 32k boundary\n", 53310015Speter id->id_unit, paddr)); 53410015Speter return(0); 53510015Speter } 53610015Speter 53734735Speter if (si_softc[id->id_unit].sc_typename) { 53834832Speter /* EISA or PCI has taken this unit, choose another */ 53934735Speter for (i=0; i < NSI; i++) { 54034735Speter if (si_softc[i].sc_typename == NULL) { 54134735Speter id->id_unit = i; 54234735Speter break; 54334735Speter } 54434735Speter } 54534735Speter if (i >= NSI) { 54634735Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 54734735Speter "si%d: cannot realloc unit\n", id->id_unit)); 54834735Speter return (0); 54934735Speter } 55034735Speter } 55134735Speter 55210015Speter for (i=0; i < NSI; i++) { 55334735Speter sc = &si_softc[i]; 55410015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 55510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 55610015Speter "si%d: iomem (%x) already configured to si%d\n", 55710015Speter id->id_unit, sc->sc_paddr, i)); 55810015Speter return(0); 55910015Speter } 56010015Speter } 56110015Speter 56210015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 56310015Speter *maddr = 0x17; 56410015Speter if (*maddr != 0x17) { 56510015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 56610015Speter "si%d: 0x17 check fail at phys 0x%x\n", 56710015Speter id->id_unit, paddr)); 56810015Speterfail: 56910015Speter return(0); 57010015Speter } 57110015Speter /* 57233395Speter * Let's look first for a JET ISA card, since that's pretty easy 57334832Speter * 57434832Speter * All jet hosts are supposed to have this string in the IDROM, 57534832Speter * but it's not worth checking on self-IDing busses like PCI. 57633395Speter */ 57734832Speter { 57834832Speter unsigned char *jet_chk_str = "JET HOST BY KEV#"; 57934832Speter 58034832Speter for (i = 0; i < strlen(jet_chk_str); i++) 58134832Speter if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i)) 58234832Speter goto try_mk2; 58334832Speter } 58433395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 58533395Speter "si%d: JET first check - 0x%x\n", 58633395Speter id->id_unit, (*(maddr+SIJETIDBASE)))); 58733395Speter if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff)) 58833395Speter goto try_mk2; 58933395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 59033395Speter "si%d: JET second check - 0x%x\n", 59133395Speter id->id_unit, (*(maddr+SIJETIDBASE+2)))); 59233395Speter if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8)) 59333395Speter goto try_mk2; 59433395Speter /* It must be a Jet ISA or RIO card */ 59533395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 59633395Speter "si%d: JET id check - 0x%x\n", 59733395Speter id->id_unit, (*(maddr+SIUNIQID)))); 59833395Speter if ((*(maddr+SIUNIQID) & 0xf0) !=0x20) 59933395Speter goto try_mk2; 60033395Speter /* It must be a Jet ISA SI/XIO card */ 60133395Speter *(maddr + SIJETCONFIG) = 0; 60233395Speter type = SIJETISA; 60333395Speter ramsize = SIJET_RAMSIZE; 60433395Speter goto got_card; 60533395Speter /* 60610015Speter * OK, now to see if whatever responded is really an SI card. 60733395Speter * Try for a MK II next (SIHOST2) 60810015Speter */ 60933395Spetertry_mk2: 61034832Speter for (i = SIPLSIG; i < SIPLSIG + 8; i++) 61110015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 61210015Speter goto try_mk1; 61310015Speter 61410015Speter /* It must be an SIHOST2 */ 61510015Speter *(maddr + SIPLRESET) = 0; 61610015Speter *(maddr + SIPLIRQCLR) = 0; 61710015Speter *(maddr + SIPLIRQSET) = 0x10; 61810015Speter type = SIHOST2; 61910015Speter ramsize = SIHOST2_RAMSIZE; 62010015Speter goto got_card; 62110015Speter 62210015Speter /* 62310015Speter * Its not a MK II, so try for a MK I (SIHOST) 62410015Speter */ 62510015Spetertry_mk1: 62610015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 62710015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 62810015Speter *(maddr+SIRAM) = 0x17; 62910015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 63010015Speter goto fail; 63110015Speter *(maddr+0x7ff8) = 0x17; 63210015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 63310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 63410015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 63510015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 63610015Speter goto fail; 63710015Speter } 63810015Speter 63934832Speter /* It must be an SIHOST (maybe?) - there must be a better way XXX */ 64010015Speter type = SIHOST; 64110015Speter ramsize = SIHOST_RAMSIZE; 64210015Speter 64310015Spetergot_card: 64412496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 64512496Speter id->id_unit, type)); 64610015Speter /* Try the acid test */ 64718515Speter ux = maddr + SIRAM; 64834832Speter for (i = 0; i < ramsize; i++, ux++) 64910015Speter *ux = (BYTE)(i&0xff); 65018515Speter ux = maddr + SIRAM; 65134832Speter for (i = 0; i < ramsize; i++, ux++) { 65210015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 65310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 65412174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 65534832Speter id->id_unit, paddr + i, was, i&0xff)); 65610015Speter goto fail; 65710015Speter } 65810015Speter } 65910015Speter 66010015Speter /* clear out the RAM */ 66118515Speter ux = maddr + SIRAM; 66234832Speter for (i = 0; i < ramsize; i++) 66310015Speter *ux++ = 0; 66418515Speter ux = maddr + SIRAM; 66534832Speter for (i = 0; i < ramsize; i++) { 66610015Speter if ((was = *ux++) != 0) { 66710015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 66812174Speter "si%d: clear fail at phys 0x%x, was %x\n", 66934832Speter id->id_unit, paddr + i, was)); 67010015Speter goto fail; 67110015Speter } 67210015Speter } 67310015Speter 67410015Speter /* 67510015Speter * Success, we've found a valid board, now fill in 67610015Speter * the adapter structure. 67710015Speter */ 67810015Speter switch (type) { 67910015Speter case SIHOST2: 68034832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 68110015Speterbad_irq: 68210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 68310015Speter "si%d: bad IRQ value - %d\n", 68410015Speter id->id_unit, id->id_irq)); 68510015Speter return(0); 68610015Speter } 68710015Speter id->id_msize = SIHOST2_MEMSIZE; 68810015Speter break; 68910015Speter case SIHOST: 69034832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 69110015Speter goto bad_irq; 69210015Speter } 69310015Speter id->id_msize = SIHOST_MEMSIZE; 69410015Speter break; 69533395Speter case SIJETISA: 69634832Speter if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) { 69733395Speter goto bad_irq; 69833395Speter } 69934832Speter id->id_msize = SIJETISA_MEMSIZE; 70033395Speter break; 70134832Speter case SIMCA: /* MCA */ 70210015Speter default: 70310015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 70410015Speter return(0); 70510015Speter } 70634832Speter id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */ 70710015Speter si_softc[id->id_unit].sc_type = type; 70810015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 70910015Speter return(-1); /* -1 == found */ 71010015Speter} 71110015Speter 71210015Speter/* 71334832Speter * We have to make an 8 bit version of bcopy, since some cards can't 71434832Speter * deal with 32 bit I/O 71534832Speter */ 71634832Speter#if 1 71734832Speterstatic void 71834832Spetersi_bcopy(const void *src, void *dst, size_t len) 71934832Speter{ 72034832Speter while (len--) 72134832Speter *(((u_char *)dst)++) = *(((u_char *)src)++); 72234832Speter} 72334832Speter#else 72434832Speter#define si_bcopy bcopy 72534832Speter#endif 72634832Speter 72734832Speter 72834832Speter/* 72910015Speter * Attach the device. Initialize the card. 73034832Speter * 73134832Speter * This routine also gets called by the EISA and PCI attach routines. 73234832Speter * It presumes that the softstate for the unit has had had its type field 73334832Speter * and the EISA specific stuff filled in, as well as the kernel virtual 73434832Speter * base address and the unit number of the isa_device struct. 73510015Speter */ 73612724Sphkstatic int 73710015Spetersiattach(id) 73810015Speter struct isa_device *id; 73910015Speter{ 74010015Speter int unit = id->id_unit; 74110015Speter struct si_softc *sc = &si_softc[unit]; 74210015Speter struct si_port *pp; 74310015Speter volatile struct si_channel *ccbp; 74410015Speter volatile struct si_reg *regp; 74510015Speter volatile caddr_t maddr; 74610015Speter struct si_module *modp; 74710015Speter struct tty *tp; 74810015Speter struct speedtab *spt; 74910015Speter int nmodule, nport, x, y; 75012174Speter int uart_type; 75110015Speter 75212496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 75310015Speter 75410015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 75510015Speter sc->sc_maddr = id->id_maddr; 75610015Speter sc->sc_irq = id->id_irq; 75710015Speter 75833395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 75933395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 76033395Speter 76110015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 76210015Speter 76310015Speter maddr = sc->sc_maddr; 76410015Speter 76534832Speter /* Stop the CPU first so it won't stomp around while we load */ 76634832Speter 76734832Speter switch (sc->sc_type) { 76834832Speter#if NEISA > 0 76934832Speter case SIEISA: 77034832Speter outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4); 77134832Speter break; 77234832Speter#endif 77334832Speter#if NPCI > 0 77434832Speter case SIPCI: 77534832Speter *(maddr+SIPCIRESET) = 0; 77634832Speter break; 77734832Speter case SIJETPCI: /* fall through to JET ISA */ 77834832Speter#endif 77934832Speter case SIJETISA: 78034832Speter *(maddr+SIJETCONFIG) = 0; 78134832Speter break; 78234832Speter case SIHOST2: 78334832Speter *(maddr+SIPLRESET) = 0; 78434832Speter break; 78534832Speter case SIHOST: 78634832Speter *(maddr+SIRESET) = 0; 78734832Speter break; 78834832Speter default: /* this should never happen */ 78934832Speter printf("si%d: unsupported configuration\n", unit); 79034832Speter return 0; 79134832Speter break; 79234832Speter } 79334832Speter 79434832Speter /* OK, now lets download the download code */ 79534832Speter 79636956Ssteve if (SI_ISJET(sc->sc_type)) { 79733395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 79834832Speter id->id_unit, si3_t225_dsize)); 79934832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 80034832Speter si3_t225_dsize); 80134832Speter DPRINT((0, DBG_DOWNLOAD, 80234832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 80334832Speter id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr)); 80434832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 80534832Speter si3_t225_bsize); 80634832Speter } else { 80733395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 80834832Speter id->id_unit, si2_z280_dsize)); 80934832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 81034832Speter si2_z280_dsize); 81133395Speter } 81210015Speter 81334832Speter /* Now start the CPU */ 81434832Speter 81510015Speter switch (sc->sc_type) { 81634832Speter#if NEISA > 0 81710015Speter case SIEISA: 81834832Speter /* modify the download code to tell it that it's on an EISA */ 81934832Speter *(maddr + 0x42) = 1; 82034832Speter outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4); 82134832Speter (void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */ 82210015Speter break; 82334832Speter#endif 82433395Speter case SIPCI: 82534832Speter /* modify the download code to tell it that it's on a PCI */ 82633395Speter *(maddr+0x42) = 1; 82733395Speter *(maddr+SIPCIRESET) = 1; 82833395Speter *(maddr+SIPCIINTCL) = 0; 82933395Speter break; 83033395Speter case SIJETPCI: 83133395Speter *(maddr+SIJETRESET) = 0; 83233395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 83333395Speter break; 83433395Speter case SIJETISA: 83533395Speter *(maddr+SIJETRESET) = 0; 83634832Speter switch (sc->sc_irq) { 83734832Speter case IRQ9: 83834832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 83934832Speter break; 84034832Speter case IRQ10: 84134832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 84234832Speter break; 84334832Speter case IRQ11: 84434832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 84534832Speter break; 84634832Speter case IRQ12: 84734832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 84834832Speter break; 84934832Speter case IRQ15: 85034832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 85134832Speter break; 85234832Speter } 85333395Speter break; 85410015Speter case SIHOST: 85510015Speter *(maddr+SIRESET_CL) = 0; 85610015Speter *(maddr+SIINTCL_CL) = 0; 85710015Speter break; 85810015Speter case SIHOST2: 85910015Speter *(maddr+SIPLRESET) = 0x10; 86010015Speter switch (sc->sc_irq) { 86110015Speter case IRQ11: 86210015Speter *(maddr+SIPLIRQ11) = 0x10; 86310015Speter break; 86410015Speter case IRQ12: 86510015Speter *(maddr+SIPLIRQ12) = 0x10; 86610015Speter break; 86710015Speter case IRQ15: 86810015Speter *(maddr+SIPLIRQ15) = 0x10; 86910015Speter break; 87010015Speter } 87110015Speter *(maddr+SIPLIRQCLR) = 0x10; 87210015Speter break; 87334832Speter default: /* this should _REALLY_ never happen */ 87434832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 87534832Speter return 0; 87610015Speter } 87710015Speter 87810015Speter DELAY(1000000); /* wait around for a second */ 87910015Speter 88010015Speter regp = (struct si_reg *)maddr; 88110015Speter y = 0; 88210015Speter /* wait max of 5 sec for init OK */ 88310015Speter while (regp->initstat == 0 && y++ < 10) { 88410015Speter DELAY(500000); 88510015Speter } 88610015Speter switch (regp->initstat) { 88710015Speter case 0: 88810015Speter printf("si%d: startup timeout - aborting\n", unit); 88912174Speter sc->sc_type = SIEMPTY; 89010015Speter return 0; 89110015Speter case 1: 89236956Ssteve if (SI_ISJET(sc->sc_type)) { 89334832Speter /* set throttle to 100 times per second */ 89434832Speter regp->int_count = JET_INT_COUNT; 89534832Speter /* rx_intr_count is a NOP in Jet */ 89634832Speter } else { 89734832Speter /* set throttle to 125 times per second */ 89834832Speter regp->int_count = INT_COUNT; 89934832Speter /* rx intr max of 25 times per second */ 90034832Speter regp->rx_int_count = RXINT_COUNT; 90134832Speter } 90210015Speter regp->int_pending = 0; /* no intr pending */ 90310015Speter regp->int_scounter = 0; /* reset counter */ 90410015Speter break; 90510015Speter case 0xff: 90610015Speter /* 90710015Speter * No modules found, so give up on this one. 90810015Speter */ 90910015Speter printf("si%d: %s - no ports found\n", unit, 91010015Speter si_type[sc->sc_type]); 91110015Speter return 0; 91210015Speter default: 91334832Speter printf("si%d: download code version error - initstat %x\n", 91410015Speter unit, regp->initstat); 91510015Speter return 0; 91610015Speter } 91710015Speter 91810015Speter /* 91910015Speter * First time around the ports just count them in order 92010015Speter * to allocate some memory. 92110015Speter */ 92210015Speter nport = 0; 92310015Speter modp = (struct si_module *)(maddr + 0x80); 92410015Speter for (;;) { 92512174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 92634832Speter switch (modp->sm_type) { 92734832Speter case TA4: 92810015Speter DPRINT((0, DBG_DOWNLOAD, 92934832Speter "si%d: Found old TA4 module, 4 ports\n", 93034832Speter unit)); 93134832Speter x = 4; 93210015Speter break; 93334832Speter case TA8: 93434832Speter DPRINT((0, DBG_DOWNLOAD, 93534832Speter "si%d: Found old TA8 module, 8 ports\n", 93634832Speter unit)); 93734832Speter x = 8; 93834832Speter break; 93934832Speter case TA4_ASIC: 94034832Speter DPRINT((0, DBG_DOWNLOAD, 94134832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 94234832Speter unit)); 94334832Speter x = 4; 94434832Speter break; 94534832Speter case TA8_ASIC: 94634832Speter DPRINT((0, DBG_DOWNLOAD, 94734832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 94834832Speter unit)); 94934832Speter x = 8; 95034832Speter break; 95134832Speter case MTA: 95234832Speter DPRINT((0, DBG_DOWNLOAD, 95334832Speter "si%d: Found CD1400 module, 8 ports\n", 95434832Speter unit)); 95534832Speter x = 8; 95634832Speter break; 95734832Speter case SXDC: 95834832Speter DPRINT((0, DBG_DOWNLOAD, 95934832Speter "si%d: Found SXDC module, 8 ports\n", 96034832Speter unit)); 96134832Speter x = 8; 96234832Speter break; 96310015Speter default: 96410015Speter printf("si%d: unknown module type %d\n", 96510015Speter unit, modp->sm_type); 96634832Speter goto try_next; 96710015Speter } 96834832Speter 96934832Speter /* this was limited in firmware and is also a driver issue */ 97034832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 97134832Speter printf("si%d: extra ports ignored\n", unit); 97234832Speter goto try_next; 97334832Speter } 97434832Speter 97534832Speter nport += x; 97634832Speter si_Nports += x; 97734832Speter si_Nmodules++; 97834832Speter 97934832Spetertry_next: 98010015Speter if (modp->sm_next == 0) 98110015Speter break; 98210015Speter modp = (struct si_module *) 98310015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 98410015Speter } 98510015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 98610015Speter M_DEVBUF, M_NOWAIT); 98710015Speter if (sc->sc_ports == 0) { 98810015Spetermem_fail: 98910015Speter printf("si%d: fail to malloc memory for port structs\n", 99010015Speter unit); 99110015Speter return 0; 99210015Speter } 99310015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 99410015Speter sc->sc_nport = nport; 99510015Speter 99610015Speter /* 99710015Speter * allocate tty structures for ports 99810015Speter */ 99910015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 100010015Speter if (tp == 0) 100110015Speter goto mem_fail; 100210015Speter bzero(tp, sizeof(*tp) * nport); 100310962Speter si_tty = tp; 100410015Speter 100510015Speter /* 100610015Speter * Scan round the ports again, this time initialising. 100710015Speter */ 100810015Speter pp = sc->sc_ports; 100910015Speter nmodule = 0; 101010015Speter modp = (struct si_module *)(maddr + 0x80); 101134832Speter uart_type = 1000; /* arbitary, > uchar_max */ 101210015Speter for (;;) { 101334832Speter switch (modp->sm_type) { 101434832Speter case TA4: 101534832Speter nport = 4; 101610015Speter break; 101734832Speter case TA8: 101834832Speter nport = 8; 101934832Speter break; 102034832Speter case TA4_ASIC: 102134832Speter nport = 4; 102234832Speter break; 102334832Speter case TA8_ASIC: 102434832Speter nport = 8; 102534832Speter break; 102634832Speter case MTA: 102734832Speter nport = 8; 102834832Speter break; 102934832Speter case SXDC: 103034832Speter nport = 8; 103134832Speter break; 103210015Speter default: 103334832Speter goto try_next2; 103410015Speter } 103534832Speter nmodule++; 103634832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 103734832Speter if (uart_type == 1000) 103834832Speter uart_type = ccbp->type; 103934832Speter else if (uart_type != ccbp->type) 104034832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 104134832Speter unit, nmodule, 104234832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 104334832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 104434832Speter 104534832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 104634832Speter pp->sp_ccb = ccbp; /* save the address */ 104734832Speter pp->sp_tty = tp++; 104834832Speter pp->sp_pend = IDLE_CLOSE; 104934832Speter pp->sp_state = 0; /* internal flag */ 105034832Speter pp->sp_dtr_wait = 3 * hz; 105134832Speter pp->sp_iin.c_iflag = TTYDEF_IFLAG; 105234832Speter pp->sp_iin.c_oflag = TTYDEF_OFLAG; 105334832Speter pp->sp_iin.c_cflag = TTYDEF_CFLAG; 105434832Speter pp->sp_iin.c_lflag = TTYDEF_LFLAG; 105534832Speter termioschars(&pp->sp_iin); 105634832Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 105734832Speter TTYDEF_SPEED;; 105834832Speter pp->sp_iout = pp->sp_iin; 105934832Speter } 106034832Spetertry_next2: 106110015Speter if (modp->sm_next == 0) { 106234832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 106310015Speter unit, 106410015Speter sc->sc_typename, 106510015Speter sc->sc_nport, 106612174Speter nmodule, 106734832Speter uart_type, 106834832Speter si_modulename(sc->sc_type, uart_type)); 106910015Speter break; 107010015Speter } 107110015Speter modp = (struct si_module *) 107210015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 107310015Speter } 107410015Speter if (done_chartimes == 0) { 107510015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 107610015Speter if ((spt->sp_code /= hz) == 0) 107710015Speter spt->sp_code = 1; 107810015Speter } 107910015Speter done_chartimes = 1; 108010015Speter } 108112502Sjulian 108212675Sjulian#ifdef DEVFS 108312675Sjulian/* path name devsw minor type uid gid perm*/ 108413169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 108534735Speter /* sync with the manuals that start at 1 */ 108634735Speter y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT); 108734735Speter sc->devfs_token[x].ttya = devfs_add_devswf( 108813630Sphk &si_cdevsw, x, 108913630Sphk DV_CHR, 0, 0, 0600, "ttyA%02d", y); 109013630Sphk sc->devfs_token[x].cuaa = devfs_add_devswf( 109134735Speter &si_cdevsw, x + 0x00080, 109213630Sphk DV_CHR, 0, 0, 0600, "cuaA%02d", y); 109313630Sphk sc->devfs_token[x].ttyi = devfs_add_devswf( 109413630Sphk &si_cdevsw, x + 0x10000, 109513630Sphk DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 109634735Speter sc->devfs_token[x].cuai = devfs_add_devswf( 109734735Speter &si_cdevsw, x + 0x10080, 109834735Speter DV_CHR, 0, 0, 0600, "cuaiA%02d", y); 109913630Sphk sc->devfs_token[x].ttyl = devfs_add_devswf( 110013630Sphk &si_cdevsw, x + 0x20000, 110113630Sphk DV_CHR, 0, 0, 0600, "ttylA%02d", y); 110234735Speter sc->devfs_token[x].cual = devfs_add_devswf( 110334735Speter &si_cdevsw, x + 0x20080, 110434735Speter DV_CHR, 0, 0, 0600, "cualA%02d", y); 110512675Sjulian } 110614873Sscrappy sc->control_token = 110714873Sscrappy devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 110814873Sscrappy "si_control"); 110912675Sjulian#endif 111010015Speter return (1); 111110015Speter} 111210015Speter 111312675Sjulianstatic int 111410015Spetersiopen(dev, flag, mode, p) 111510015Speter dev_t dev; 111610015Speter int flag, mode; 111710015Speter struct proc *p; 111810015Speter{ 111910015Speter int oldspl, error; 112010015Speter int card, port; 112110015Speter register struct si_softc *sc; 112210015Speter register struct tty *tp; 112310015Speter volatile struct si_channel *ccbp; 112410015Speter struct si_port *pp; 112510015Speter int mynor = minor(dev); 112610015Speter 112710015Speter /* quickly let in /dev/si_control */ 112810015Speter if (IS_CONTROLDEV(mynor)) { 112918515Speter if ((error = suser(p->p_ucred, &p->p_acflag))) 113010015Speter return(error); 113110015Speter return(0); 113210015Speter } 113310015Speter 113410015Speter card = SI_CARD(mynor); 113510015Speter if (card >= NSI) 113610015Speter return (ENXIO); 113710015Speter sc = &si_softc[card]; 113810015Speter 113912174Speter if (sc->sc_type == SIEMPTY) { 114012174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 114110015Speter card, sc->sc_typename)); 114210015Speter return(ENXIO); 114310015Speter } 114410015Speter 114510015Speter port = SI_PORT(mynor); 114610015Speter if (port >= sc->sc_nport) { 114712174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 114810015Speter card, sc->sc_nport)); 114910015Speter return(ENXIO); 115010015Speter } 115110015Speter 115210015Speter#ifdef POLL 115310015Speter /* 115410015Speter * We've now got a device, so start the poller. 115510015Speter */ 115610015Speter if (init_finished == 0) { 115715639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 115810015Speter init_finished = 1; 115910015Speter } 116010015Speter#endif 116110015Speter 116210015Speter /* initial/lock device */ 116310015Speter if (IS_STATE(mynor)) { 116410015Speter return(0); 116510015Speter } 116610015Speter 116710015Speter pp = sc->sc_ports + port; 116810015Speter tp = pp->sp_tty; /* the "real" tty */ 116910015Speter ccbp = pp->sp_ccb; /* Find control block */ 117010015Speter DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", 117110015Speter dev, flag, mode, p)); 117210015Speter 117310015Speter oldspl = spltty(); /* Keep others out */ 117410015Speter error = 0; 117510015Speter 117610015Speteropen_top: 117710015Speter while (pp->sp_state & SS_DTR_OFF) { 117810015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 117910015Speter if (error != 0) 118010015Speter goto out; 118110015Speter } 118210015Speter 118310015Speter if (tp->t_state & TS_ISOPEN) { 118410015Speter /* 118510015Speter * The device is open, so everything has been initialised. 118610015Speter * handle conflicts. 118710015Speter */ 118810015Speter if (IS_CALLOUT(mynor)) { 118910015Speter if (!pp->sp_active_out) { 119010015Speter error = EBUSY; 119110015Speter goto out; 119210015Speter } 119310015Speter } else { 119410015Speter if (pp->sp_active_out) { 119510015Speter if (flag & O_NONBLOCK) { 119610015Speter error = EBUSY; 119710015Speter goto out; 119810015Speter } 119910015Speter error = tsleep(&pp->sp_active_out, 120010015Speter TTIPRI|PCATCH, "sibi", 0); 120110015Speter if (error != 0) 120210015Speter goto out; 120310015Speter goto open_top; 120410015Speter } 120510015Speter } 120610015Speter if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 120710015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 120810015Speter "already open and EXCLUSIVE set\n")); 120910015Speter error = EBUSY; 121010015Speter goto out; 121110015Speter } 121210015Speter } else { 121310015Speter /* 121410015Speter * The device isn't open, so there are no conflicts. 121510015Speter * Initialize it. Avoid sleep... :-) 121610015Speter */ 121710015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 121810015Speter tp->t_oproc = si_start; 121910015Speter tp->t_param = siparam; 122010015Speter tp->t_dev = dev; 122110015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 122210015Speter ? pp->sp_iout : pp->sp_iin; 122310015Speter 122410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 122510015Speter 122610015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 122710015Speter 122810015Speter error = siparam(tp, &tp->t_termios); 122910015Speter 123010015Speter --pp->sp_wopeners; 123110015Speter if (error != 0) 123210015Speter goto out; 123310015Speter /* XXX: we should goto_top if siparam slept */ 123410015Speter 123510015Speter ttsetwater(tp); 123610015Speter 123710015Speter /* set initial DCD state */ 123810015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 123910015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 124010015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 124110015Speter } 124210015Speter } 124310015Speter 124410015Speter /* whoops! we beat the close! */ 124510015Speter if (pp->sp_state & SS_CLOSING) { 124610015Speter /* try and stop it from proceeding to bash the hardware */ 124710015Speter pp->sp_state &= ~SS_CLOSING; 124810015Speter } 124910015Speter 125010015Speter /* 125110015Speter * Wait for DCD if necessary 125210015Speter */ 125310015Speter if (!(tp->t_state & TS_CARR_ON) 125410015Speter && !IS_CALLOUT(mynor) 125510015Speter && !(tp->t_cflag & CLOCAL) 125610015Speter && !(flag & O_NONBLOCK)) { 125710015Speter ++pp->sp_wopeners; 125810015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 125910015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 126010015Speter --pp->sp_wopeners; 126110015Speter if (error != 0) 126210015Speter goto out; 126310015Speter goto open_top; 126410015Speter } 126510015Speter 126610015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 126710015Speter si_disc_optim(tp, &tp->t_termios, pp); 126810015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 126910015Speter pp->sp_active_out = TRUE; 127010015Speter 127110015Speter pp->sp_state |= SS_OPEN; /* made it! */ 127210015Speter 127310015Speterout: 127410015Speter splx(oldspl); 127510015Speter 127610015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 127710015Speter 127810015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 127910015Speter sihardclose(pp); 128010015Speter 128110015Speter return(error); 128210015Speter} 128310015Speter 128412675Sjulianstatic int 128510015Spetersiclose(dev, flag, mode, p) 128610015Speter dev_t dev; 128710015Speter int flag, mode; 128810015Speter struct proc *p; 128910015Speter{ 129010015Speter register struct si_port *pp; 129110015Speter register struct tty *tp; 129210015Speter int oldspl; 129310015Speter int error = 0; 129410015Speter int mynor = minor(dev); 129510015Speter 129610015Speter if (IS_SPECIAL(mynor)) 129710015Speter return(0); 129810015Speter 129910015Speter oldspl = spltty(); 130010015Speter 130110015Speter pp = MINOR2PP(mynor); 130210015Speter tp = pp->sp_tty; 130310015Speter 130410015Speter DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", 130510015Speter dev, flag, mode, p, pp->sp_state)); 130610015Speter 130710015Speter /* did we sleep and loose a race? */ 130810015Speter if (pp->sp_state & SS_CLOSING) { 130910015Speter /* error = ESOMETING? */ 131010015Speter goto out; 131110015Speter } 131210015Speter 131310015Speter /* begin race detection.. */ 131410015Speter pp->sp_state |= SS_CLOSING; 131510015Speter 131610015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 131710015Speter 131810015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 131910015Speter (*linesw[tp->t_line].l_close)(tp, flag); 132010015Speter 132110015Speter si_write_enable(pp, 1); 132210015Speter 132310015Speter /* did we sleep and somebody started another open? */ 132410015Speter if (!(pp->sp_state & SS_CLOSING)) { 132510015Speter /* error = ESOMETING? */ 132610015Speter goto out; 132710015Speter } 132810015Speter /* ok. we are now still on the right track.. nuke the hardware */ 132910015Speter 133010015Speter if (pp->sp_state & SS_LSTART) { 133129677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 133210015Speter pp->sp_state &= ~SS_LSTART; 133310015Speter } 133410015Speter 133510015Speter sistop(tp, FREAD | FWRITE); 133610015Speter 133710015Speter sihardclose(pp); 133810015Speter ttyclose(tp); 133910015Speter pp->sp_state &= ~SS_OPEN; 134010015Speter 134110015Speterout: 134210015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 134310015Speter splx(oldspl); 134410015Speter return(error); 134510015Speter} 134610015Speter 134710015Speterstatic void 134810015Spetersihardclose(pp) 134910015Speter struct si_port *pp; 135010015Speter{ 135110015Speter int oldspl; 135210015Speter struct tty *tp; 135310015Speter volatile struct si_channel *ccbp; 135410015Speter 135510015Speter oldspl = spltty(); 135610015Speter 135710015Speter tp = pp->sp_tty; 135810015Speter ccbp = pp->sp_ccb; /* Find control block */ 135910015Speter if (tp->t_cflag & HUPCL 136018515Speter || (!pp->sp_active_out 136134832Speter && !(ccbp->hi_ip & IP_DCD) 136234832Speter && !(pp->sp_iin.c_cflag && CLOCAL)) 136310015Speter || !(tp->t_state & TS_ISOPEN)) { 136410015Speter 136510015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 136610015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 136710015Speter 136810015Speter if (pp->sp_dtr_wait != 0) { 136910015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 137010015Speter pp->sp_state |= SS_DTR_OFF; 137110015Speter } 137210015Speter 137310015Speter } 137410015Speter pp->sp_active_out = FALSE; 137510015Speter wakeup((caddr_t)&pp->sp_active_out); 137610015Speter wakeup(TSA_CARR_ON(tp)); 137710015Speter 137810015Speter splx(oldspl); 137910015Speter} 138010015Speter 138110015Speter 138210015Speter/* 138310015Speter * called at splsoftclock()... 138410015Speter */ 138510015Speterstatic void 138610015Spetersidtrwakeup(chan) 138710015Speter void *chan; 138810015Speter{ 138910015Speter struct si_port *pp; 139010015Speter int oldspl; 139110015Speter 139210015Speter oldspl = spltty(); 139310015Speter 139410015Speter pp = (struct si_port *)chan; 139510015Speter pp->sp_state &= ~SS_DTR_OFF; 139610015Speter wakeup(&pp->sp_dtr_wait); 139710015Speter 139810015Speter splx(oldspl); 139910015Speter} 140010015Speter 140110015Speter/* 140210015Speter * User level stuff - read and write 140310015Speter */ 140412675Sjulianstatic int 140510015Spetersiread(dev, uio, flag) 140610015Speter register dev_t dev; 140710015Speter struct uio *uio; 140810015Speter int flag; 140910015Speter{ 141010015Speter register struct tty *tp; 141110015Speter int mynor = minor(dev); 141210015Speter 141310015Speter if (IS_SPECIAL(mynor)) { 141410015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 141510015Speter return(ENODEV); 141610015Speter } 141710015Speter tp = MINOR2TP(mynor); 141810015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 141910015Speter "siread(%x,%x,%x)\n", dev, uio, flag)); 142010015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 142110015Speter} 142210015Speter 142310015Speter 142412675Sjulianstatic int 142510015Spetersiwrite(dev, uio, flag) 142610015Speter dev_t dev; 142710015Speter struct uio *uio; 142810015Speter int flag; 142910015Speter{ 143010015Speter register struct si_port *pp; 143110015Speter register struct tty *tp; 143210015Speter int error = 0; 143310015Speter int mynor = minor(dev); 143410015Speter int oldspl; 143510015Speter 143610015Speter if (IS_SPECIAL(mynor)) { 143710015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 143810015Speter return(ENODEV); 143910015Speter } 144010015Speter pp = MINOR2PP(mynor); 144110015Speter tp = pp->sp_tty; 144210015Speter DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); 144310015Speter 144410015Speter oldspl = spltty(); 144510015Speter /* 144610015Speter * If writes are currently blocked, wait on the "real" tty 144710015Speter */ 144810015Speter while (pp->sp_state & SS_BLOCKWRITE) { 144910015Speter pp->sp_state |= SS_WAITWRITE; 145010015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 145118515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 145218515Speter "siwrite", tp->t_timeout))) { 145317291Speter if (error == EWOULDBLOCK) 145417290Speter error = EIO; 145510015Speter goto out; 145617290Speter } 145710015Speter } 145810015Speter 145910015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 146010015Speterout: 146110015Speter splx(oldspl); 146210015Speter return (error); 146310015Speter} 146410015Speter 146510015Speter 146612675Sjulianstatic struct tty * 146710015Spetersidevtotty(dev_t dev) 146810015Speter{ 146910015Speter struct si_port *pp; 147010015Speter int mynor = minor(dev); 147110015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 147210015Speter 147310015Speter if (IS_SPECIAL(mynor)) 147410015Speter return(NULL); 147510015Speter if (SI_PORT(mynor) >= sc->sc_nport) 147610015Speter return(NULL); 147710015Speter pp = MINOR2PP(mynor); 147810015Speter return (pp->sp_tty); 147910015Speter} 148010015Speter 148112675Sjulianstatic int 148210015Spetersiioctl(dev, cmd, data, flag, p) 148310015Speter dev_t dev; 148436735Sdfr u_long cmd; 148510015Speter caddr_t data; 148610015Speter int flag; 148710015Speter struct proc *p; 148810015Speter{ 148910015Speter struct si_port *pp; 149010015Speter register struct tty *tp; 149110015Speter int error; 149210015Speter int mynor = minor(dev); 149310015Speter int oldspl; 149410015Speter int blocked = 0; 149510015Speter#if defined(COMPAT_43) 149638351Sbde u_long oldcmd; 149710015Speter struct termios term; 149810015Speter#endif 149910015Speter 150010015Speter if (IS_SI_IOCTL(cmd)) 150110015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 150210015Speter 150310015Speter pp = MINOR2PP(mynor); 150410015Speter tp = pp->sp_tty; 150510015Speter 150638351Sbde DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%lx,%x,%x)\n", 150710015Speter dev, cmd, data, flag)); 150810015Speter if (IS_STATE(mynor)) { 150910015Speter struct termios *ct; 151010015Speter 151110015Speter switch (mynor & SI_STATE_MASK) { 151210015Speter case SI_INIT_STATE_MASK: 151310015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 151410015Speter break; 151510015Speter case SI_LOCK_STATE_MASK: 151616839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 151710015Speter break; 151810015Speter default: 151910015Speter return (ENODEV); 152010015Speter } 152110015Speter switch (cmd) { 152210015Speter case TIOCSETA: 152310015Speter error = suser(p->p_ucred, &p->p_acflag); 152410015Speter if (error != 0) 152510015Speter return (error); 152610015Speter *ct = *(struct termios *)data; 152710015Speter return (0); 152810015Speter case TIOCGETA: 152910015Speter *(struct termios *)data = *ct; 153010015Speter return (0); 153110015Speter case TIOCGETD: 153210015Speter *(int *)data = TTYDISC; 153310015Speter return (0); 153410015Speter case TIOCGWINSZ: 153510015Speter bzero(data, sizeof(struct winsize)); 153610015Speter return (0); 153710015Speter default: 153810015Speter return (ENOTTY); 153910015Speter } 154010015Speter } 154110015Speter /* 154210015Speter * Do the old-style ioctl compat routines... 154310015Speter */ 154410015Speter#if defined(COMPAT_43) 154510015Speter term = tp->t_termios; 154610015Speter oldcmd = cmd; 154710015Speter error = ttsetcompat(tp, &cmd, data, &term); 154810015Speter if (error != 0) 154910015Speter return (error); 155010015Speter if (cmd != oldcmd) 155110015Speter data = (caddr_t)&term; 155210015Speter#endif 155310015Speter /* 155410015Speter * Do the initial / lock state business 155510015Speter */ 155610015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 155710015Speter int cc; 155810015Speter struct termios *dt = (struct termios *)data; 155910015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 156010015Speter ? &pp->sp_lout : &pp->sp_lin; 156110015Speter 156210015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 156310015Speter | (dt->c_iflag & ~lt->c_iflag); 156410015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 156510015Speter | (dt->c_oflag & ~lt->c_oflag); 156610015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 156710015Speter | (dt->c_cflag & ~lt->c_cflag); 156810015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 156910015Speter | (dt->c_lflag & ~lt->c_lflag); 157010015Speter for (cc = 0; cc < NCCS; ++cc) 157110015Speter if (lt->c_cc[cc] != 0) 157210015Speter dt->c_cc[cc] = tp->t_cc[cc]; 157310015Speter if (lt->c_ispeed != 0) 157410015Speter dt->c_ispeed = tp->t_ispeed; 157510015Speter if (lt->c_ospeed != 0) 157610015Speter dt->c_ospeed = tp->t_ospeed; 157710015Speter } 157810015Speter 157910015Speter /* 158010015Speter * Block user-level writes to give the ttywait() 158110015Speter * a chance to completely drain for commands 158210015Speter * that require the port to be in a quiescent state. 158310015Speter */ 158410015Speter switch (cmd) { 158534832Speter case TIOCSETAW: 158634832Speter case TIOCSETAF: 158717396Speter case TIOCDRAIN: 158817396Speter#ifdef COMPAT_43 158917396Speter case TIOCSETP: 159017396Speter#endif 159110015Speter blocked++; /* block writes for ttywait() and siparam() */ 159210015Speter si_write_enable(pp, 0); 159310015Speter } 159410015Speter 159510015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 159631577Sbde if (error != ENOIOCTL) 159710015Speter goto out; 159810015Speter 159910015Speter oldspl = spltty(); 160010015Speter 160110015Speter error = ttioctl(tp, cmd, data, flag); 160210015Speter si_disc_optim(tp, &tp->t_termios, pp); 160331577Sbde if (error != ENOIOCTL) 160410015Speter goto outspl; 160510015Speter 160610015Speter switch (cmd) { 160710015Speter case TIOCSBRK: 160816575Speter si_command(pp, SBREAK, SI_WAIT); 160910015Speter break; 161010015Speter case TIOCCBRK: 161116575Speter si_command(pp, EBREAK, SI_WAIT); 161210015Speter break; 161310015Speter case TIOCSDTR: 161410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 161510015Speter break; 161610015Speter case TIOCCDTR: 161710015Speter (void) si_modem(pp, SET, 0); 161810015Speter break; 161910015Speter case TIOCMSET: 162010015Speter (void) si_modem(pp, SET, *(int *)data); 162110015Speter break; 162210015Speter case TIOCMBIS: 162310015Speter (void) si_modem(pp, BIS, *(int *)data); 162410015Speter break; 162510015Speter case TIOCMBIC: 162610015Speter (void) si_modem(pp, BIC, *(int *)data); 162710015Speter break; 162810015Speter case TIOCMGET: 162910015Speter *(int *)data = si_modem(pp, GET, 0); 163010015Speter break; 163110015Speter case TIOCMSDTRWAIT: 163210015Speter /* must be root since the wait applies to following logins */ 163310015Speter error = suser(p->p_ucred, &p->p_acflag); 163410015Speter if (error != 0) { 163510015Speter goto outspl; 163610015Speter } 163710015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 163810015Speter break; 163910015Speter case TIOCMGDTRWAIT: 164010015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 164110015Speter break; 164210015Speter 164310015Speter default: 164410015Speter error = ENOTTY; 164510015Speter } 164610015Speter error = 0; 164710015Speteroutspl: 164810015Speter splx(oldspl); 164910015Speterout: 165010015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 165110015Speter if (blocked) 165210015Speter si_write_enable(pp, 1); 165310015Speter return(error); 165410015Speter} 165510015Speter 165610015Speter/* 165710015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 165810015Speter */ 165910015Speterstatic int 166038351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 166110015Speter{ 166210015Speter struct si_softc *xsc; 166310015Speter register struct si_port *xpp; 166410015Speter volatile struct si_reg *regp; 166510015Speter struct si_tcsi *dp; 166610044Speter struct si_pstat *sps; 166711872Sphk int *ip, error = 0; 166810015Speter int oldspl; 166910015Speter int card, port; 167010015Speter int mynor = minor(dev); 167110015Speter 167238351Sbde DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%lx,%x,%x)\n", 167310015Speter dev, cmd, data, flag)); 167410015Speter 167510044Speter#if 1 167610044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 167710044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 167810044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 167910044Speter#endif 168010044Speter 168110015Speter if (!IS_CONTROLDEV(mynor)) { 168210015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 168310015Speter return(ENODEV); 168410015Speter } 168510015Speter 168610015Speter oldspl = spltty(); /* better safe than sorry */ 168710015Speter 168810015Speter ip = (int *)data; 168910015Speter 169018515Speter#define SUCHECK if ((error = suser(p->p_ucred, &p->p_acflag))) goto out 169110015Speter 169210015Speter switch (cmd) { 169310015Speter case TCSIPORTS: 169410015Speter *ip = si_Nports; 169510015Speter goto out; 169610015Speter case TCSIMODULES: 169710015Speter *ip = si_Nmodules; 169810015Speter goto out; 169910015Speter case TCSISDBG_ALL: 170010015Speter SUCHECK; 170110015Speter si_debug = *ip; 170210015Speter goto out; 170310015Speter case TCSIGDBG_ALL: 170410015Speter *ip = si_debug; 170510015Speter goto out; 170610015Speter default: 170710015Speter /* 170810015Speter * Check that a controller for this port exists 170910015Speter */ 171010044Speter 171110044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 171210044Speter 171310015Speter dp = (struct si_tcsi *)data; 171410044Speter sps = (struct si_pstat *)data; 171510015Speter card = dp->tc_card; 171610015Speter xsc = &si_softc[card]; /* check.. */ 171712174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 171810015Speter error = ENOENT; 171910015Speter goto out; 172010015Speter } 172110015Speter /* 172210015Speter * And check that a port exists 172310015Speter */ 172410015Speter port = dp->tc_port; 172510015Speter if (port < 0 || port >= xsc->sc_nport) { 172610015Speter error = ENOENT; 172710015Speter goto out; 172810015Speter } 172910015Speter xpp = xsc->sc_ports + port; 173010015Speter regp = (struct si_reg *)xsc->sc_maddr; 173110015Speter } 173210015Speter 173310015Speter switch (cmd) { 173410015Speter case TCSIDEBUG: 173510015Speter#ifdef SI_DEBUG 173610015Speter SUCHECK; 173710015Speter if (xpp->sp_debug) 173810015Speter xpp->sp_debug = 0; 173910015Speter else { 174010015Speter xpp->sp_debug = DBG_ALL; 174110015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 174210015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 174310015Speter } 174410015Speter break; 174510015Speter#else 174610015Speter error = ENODEV; 174710015Speter goto out; 174810015Speter#endif 174910015Speter case TCSISDBG_LEVEL: 175010015Speter case TCSIGDBG_LEVEL: 175110015Speter#ifdef SI_DEBUG 175210015Speter if (cmd == TCSIGDBG_LEVEL) { 175310015Speter dp->tc_dbglvl = xpp->sp_debug; 175410015Speter } else { 175510015Speter SUCHECK; 175610015Speter xpp->sp_debug = dp->tc_dbglvl; 175710015Speter } 175810015Speter break; 175910015Speter#else 176010015Speter error = ENODEV; 176110015Speter goto out; 176210015Speter#endif 176310015Speter case TCSIGRXIT: 176410015Speter dp->tc_int = regp->rx_int_count; 176510015Speter break; 176610015Speter case TCSIRXIT: 176710015Speter SUCHECK; 176810015Speter regp->rx_int_count = dp->tc_int; 176910015Speter break; 177010015Speter case TCSIGIT: 177110015Speter dp->tc_int = regp->int_count; 177210015Speter break; 177310015Speter case TCSIIT: 177410015Speter SUCHECK; 177510015Speter regp->int_count = dp->tc_int; 177610015Speter break; 177710044Speter case TCSISTATE: 177810044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 177910015Speter break; 178010044Speter /* these next three use a different structure */ 178110044Speter case TCSI_PORT: 178210015Speter SUCHECK; 178334832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 178410015Speter break; 178510044Speter case TCSI_CCB: 178610044Speter SUCHECK; 178734832Speter si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 178810015Speter break; 178910044Speter case TCSI_TTY: 179010044Speter SUCHECK; 179134832Speter si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 179210015Speter break; 179310015Speter default: 179410015Speter error = EINVAL; 179510015Speter goto out; 179610015Speter } 179710015Speterout: 179810015Speter splx(oldspl); 179910015Speter return(error); /* success */ 180010015Speter} 180110015Speter 180210015Speter/* 180310015Speter * siparam() : Configure line params 180410015Speter * called at spltty(); 180510015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 180610015Speter * caller must arrange this if it's important.. 180710015Speter */ 180812724Sphkstatic int 180910015Spetersiparam(tp, t) 181010015Speter register struct tty *tp; 181110015Speter register struct termios *t; 181210015Speter{ 181310015Speter register struct si_port *pp = TP2PP(tp); 181410015Speter volatile struct si_channel *ccbp; 181510015Speter int oldspl, cflag, iflag, oflag, lflag; 181610015Speter int error = 0; /* shutup gcc */ 181710015Speter int ispeed = 0; /* shutup gcc */ 181810015Speter int ospeed = 0; /* shutup gcc */ 181910161Speter BYTE val; 182010015Speter 182110015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 182210015Speter cflag = t->c_cflag; 182310015Speter iflag = t->c_iflag; 182410015Speter oflag = t->c_oflag; 182510015Speter lflag = t->c_lflag; 182610044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 182710044Speter oflag, cflag, iflag, lflag)); 182810015Speter 182934832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 183010015Speter 183110015Speter /* if not hung up.. */ 183210015Speter if (t->c_ospeed != 0) { 183310015Speter /* translate baud rate to firmware values */ 183410015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 183510015Speter ispeed = t->c_ispeed ? 183610015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 183710015Speter 183810015Speter /* enforce legit baud rate */ 183910015Speter if (ospeed < 0 || ispeed < 0) 184010015Speter return (EINVAL); 184110015Speter } 184210015Speter 184310015Speter oldspl = spltty(); 184410015Speter 184510015Speter ccbp = pp->sp_ccb; 184610015Speter 184710161Speter /* ========== set hi_break ========== */ 184810161Speter val = 0; 184910161Speter if (iflag & IGNBRK) /* Breaks */ 185010161Speter val |= BR_IGN; 185110161Speter if (iflag & BRKINT) /* Interrupt on break? */ 185210161Speter val |= BR_INT; 185310161Speter if (iflag & PARMRK) /* Parity mark? */ 185410161Speter val |= BR_PARMRK; 185510161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 185610161Speter val |= BR_PARIGN; 185710161Speter ccbp->hi_break = val; 185810161Speter 185910161Speter /* ========== set hi_csr ========== */ 186010015Speter /* if not hung up.. */ 186110015Speter if (t->c_ospeed != 0) { 186210015Speter /* Set I/O speeds */ 186310161Speter val = (ispeed << 4) | ospeed; 186410015Speter } 186510161Speter ccbp->hi_csr = val; 186610015Speter 186710161Speter /* ========== set hi_mr2 ========== */ 186810161Speter val = 0; 186910015Speter if (cflag & CSTOPB) /* Stop bits */ 187010161Speter val |= MR2_2_STOP; 187110015Speter else 187210161Speter val |= MR2_1_STOP; 187310161Speter /* 187410161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 187510161Speter * a DCE, hence the reverse sense of RTS and CTS 187610161Speter */ 187710161Speter /* Output Flow - RTS must be raised before data can be sent */ 187810161Speter if (cflag & CCTS_OFLOW) 187910161Speter val |= MR2_RTSCONT; 188010161Speter 188116575Speter ccbp->hi_mr2 = val; 188210161Speter 188310161Speter /* ========== set hi_mr1 ========== */ 188410161Speter val = 0; 188510015Speter if (!(cflag & PARENB)) /* Parity */ 188610161Speter val |= MR1_NONE; 188710015Speter else 188810161Speter val |= MR1_WITH; 188910015Speter if (cflag & PARODD) 189010161Speter val |= MR1_ODD; 189110015Speter 189210015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 189310161Speter val |= MR1_8_BITS; 189410015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 189510161Speter val |= MR1_7_BITS; 189610015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 189710161Speter val |= MR1_6_BITS; 189810015Speter } else { /* Must be 5 */ 189910161Speter val |= MR1_5_BITS; 190010015Speter } 190110161Speter /* 190210161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 190310161Speter * a DCE, hence the reverse sense of RTS and CTS 190410161Speter */ 190510161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 190610161Speter if (cflag & CRTS_IFLOW) 190710161Speter val |= MR1_CTSCONT; 190810015Speter 190910161Speter ccbp->hi_mr1 = val; 191010161Speter 191110161Speter /* ========== set hi_mask ========== */ 191210161Speter val = 0xff; 191310161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 191410161Speter val &= 0xFF; 191510161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 191610161Speter val &= 0x7F; 191710161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 191810161Speter val &= 0x3F; 191910161Speter } else { /* Must be 5 */ 192010161Speter val &= 0x1F; 192110161Speter } 192210015Speter if (iflag & ISTRIP) 192310161Speter val &= 0x7F; 192410015Speter 192510161Speter ccbp->hi_mask = val; 192610161Speter 192710161Speter /* ========== set hi_prtcl ========== */ 192810161Speter val = 0; 192910015Speter /* Monitor DCD etc. if a modem */ 193010015Speter if (!(cflag & CLOCAL)) 193110161Speter val |= SP_DCEN; 193210161Speter if (iflag & IXANY) 193310161Speter val |= SP_TANY; 193410161Speter if (iflag & IXON) 193510161Speter val |= SP_TXEN; 193610161Speter if (iflag & IXOFF) 193710161Speter val |= SP_RXEN; 193810161Speter if (iflag & INPCK) 193910161Speter val |= SP_PAEN; 194010015Speter 194110161Speter ccbp->hi_prtcl = val; 194210161Speter 194310161Speter 194410161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 194510161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 194610015Speter ccbp->hi_txon = t->c_cc[VSTART]; 194710015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 194810015Speter 194910015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 195010015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 195110015Speter 195210161Speter /* ========== send settings to the card ========== */ 195310015Speter /* potential sleep here */ 195410015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 195510015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 195610015Speter else 195710015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 195810015Speter 195910161Speter /* ========== set DTR etc ========== */ 196010015Speter /* Hangup if ospeed == 0 */ 196110015Speter if (t->c_ospeed == 0) { 196210015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 196310015Speter } else { 196410015Speter /* 196510015Speter * If the previous speed was 0, may need to re-enable 196634832Speter * the modem signals 196734832Speter */ 196810015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 196910015Speter } 197010015Speter 197110044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 197210044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 197310015Speter 197410015Speter splx(oldspl); 197510015Speter return(error); 197610015Speter} 197710015Speter 197810015Speter/* 197910015Speter * Enable or Disable the writes to this channel... 198010015Speter * "state" -> enabled = 1; disabled = 0; 198110015Speter */ 198210015Speterstatic void 198310015Spetersi_write_enable(pp, state) 198410015Speter register struct si_port *pp; 198510015Speter int state; 198610015Speter{ 198710015Speter int oldspl; 198810015Speter 198910015Speter oldspl = spltty(); 199010015Speter 199110015Speter if (state) { 199210015Speter pp->sp_state &= ~SS_BLOCKWRITE; 199310015Speter if (pp->sp_state & SS_WAITWRITE) { 199410015Speter pp->sp_state &= ~SS_WAITWRITE; 199510015Speter /* thunder away! */ 199610015Speter wakeup((caddr_t)pp); 199710015Speter } 199810015Speter } else { 199910015Speter pp->sp_state |= SS_BLOCKWRITE; 200010015Speter } 200110015Speter 200210015Speter splx(oldspl); 200310015Speter} 200410015Speter 200510015Speter/* 200610015Speter * Set/Get state of modem control lines. 200710015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 200810015Speter * TIOCM_DTR DSR 200910015Speter * TIOCM_RTS CTS 201010015Speter */ 201110015Speterstatic int 201210015Spetersi_modem(pp, cmd, bits) 201310015Speter struct si_port *pp; 201410015Speter enum si_mctl cmd; 201510015Speter int bits; 201610015Speter{ 201710015Speter volatile struct si_channel *ccbp; 201810015Speter int x; 201910015Speter 202010015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 202110015Speter ccbp = pp->sp_ccb; /* Find channel address */ 202210015Speter switch (cmd) { 202310015Speter case GET: 202410015Speter x = ccbp->hi_ip; 202510015Speter bits = TIOCM_LE; 202610015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 202710015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 202810015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 202910015Speter if (x & IP_RI) bits |= TIOCM_RI; 203010015Speter return(bits); 203110015Speter case SET: 203210015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 203310015Speter /* fall through */ 203410015Speter case BIS: 203510015Speter x = 0; 203610015Speter if (bits & TIOCM_DTR) 203710015Speter x |= OP_DSR; 203810015Speter if (bits & TIOCM_RTS) 203910015Speter x |= OP_CTS; 204010015Speter ccbp->hi_op |= x; 204110015Speter break; 204210015Speter case BIC: 204310015Speter if (bits & TIOCM_DTR) 204410015Speter ccbp->hi_op &= ~OP_DSR; 204510015Speter if (bits & TIOCM_RTS) 204610015Speter ccbp->hi_op &= ~OP_CTS; 204710015Speter } 204810015Speter return 0; 204910015Speter} 205010015Speter 205110015Speter/* 205210015Speter * Handle change of modem state 205310015Speter */ 205410015Speterstatic void 205510015Spetersi_modem_state(pp, tp, hi_ip) 205610015Speter register struct si_port *pp; 205710015Speter register struct tty *tp; 205810015Speter register int hi_ip; 205910015Speter{ 206010015Speter /* if a modem dev */ 206110015Speter if (hi_ip & IP_DCD) { 206210015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 206310015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 206410015Speter tp->t_line)); 206510015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 206610015Speter } 206710015Speter } else { 206810015Speter if (pp->sp_last_hi_ip & IP_DCD) { 206910015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 207010015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 207110015Speter (void) si_modem(pp, SET, 0); 207210015Speter } 207310015Speter } 207410015Speter pp->sp_last_hi_ip = hi_ip; 207510015Speter 207610015Speter} 207710015Speter 207810015Speter/* 207910015Speter * Poller to catch missed interrupts. 208012174Speter * 208112496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 208212496Speter * better response. We could really use a "periodic" version timeout(). :-) 208310015Speter */ 208410015Speter#ifdef POLL 208510708Speterstatic void 208610015Spetersi_poll(void *nothing) 208710015Speter{ 208810015Speter register struct si_softc *sc; 208910015Speter register int i; 209010015Speter volatile struct si_reg *regp; 209112174Speter register struct si_port *pp; 209212174Speter int lost, oldspl, port; 209310015Speter 209410015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 209511609Speter oldspl = spltty(); 209610015Speter if (in_intr) 209710015Speter goto out; 209810015Speter lost = 0; 209910015Speter for (i=0; i<NSI; i++) { 210010015Speter sc = &si_softc[i]; 210112174Speter if (sc->sc_type == SIEMPTY) 210210015Speter continue; 210310015Speter regp = (struct si_reg *)sc->sc_maddr; 210434832Speter 210510015Speter /* 210610015Speter * See if there has been a pending interrupt for 2 seconds 210733395Speter * or so. The test (int_scounter >= 200) won't correspond 210810015Speter * to 2 seconds if int_count gets changed. 210910015Speter */ 211010015Speter if (regp->int_pending != 0) { 211110015Speter if (regp->int_scounter >= 200 && 211210015Speter regp->initstat == 1) { 211312174Speter printf("si%d: lost intr\n", i); 211410015Speter lost++; 211510015Speter } 211610015Speter } else { 211710015Speter regp->int_scounter = 0; 211810015Speter } 211910015Speter 212012174Speter /* 212112174Speter * gripe about no input flow control.. 212212174Speter */ 212312174Speter pp = sc->sc_ports; 212412174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 212512174Speter if (pp->sp_delta_overflows > 0) { 212612174Speter printf("si%d: %d tty level buffer overflows\n", 212712174Speter i, pp->sp_delta_overflows); 212812174Speter pp->sp_delta_overflows = 0; 212912174Speter } 213012174Speter } 213110015Speter } 213217547Speter if (lost || si_realpoll) 213334735Speter si_intr(-1); /* call intr with fake vector */ 213411609Speterout: 213510015Speter splx(oldspl); 213610015Speter 213715639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 213810015Speter} 213910015Speter#endif /* ifdef POLL */ 214010015Speter 214110015Speter/* 214210015Speter * The interrupt handler polls ALL ports on ALL adapters each time 214310015Speter * it is called. 214410015Speter */ 214510015Speter 214612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 214734832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 214810015Speter 214934735Speterstatic void 215034735Spetersi_intr(int unit) 215110015Speter{ 215210015Speter register struct si_softc *sc; 215310015Speter 215410015Speter register struct si_port *pp; 215510015Speter volatile struct si_channel *ccbp; 215610015Speter register struct tty *tp; 215710015Speter volatile caddr_t maddr; 215811872Sphk BYTE op, ip; 215912174Speter int x, card, port, n, i, isopen; 216010015Speter volatile BYTE *z; 216110015Speter BYTE c; 216210015Speter 216334735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit)); 216411609Speter if (in_intr) { 216511609Speter if (unit < 0) /* should never happen */ 216634832Speter printf("si%d: Warning poll entered during interrupt\n", 216734832Speter unit); 216834832Speter else 216934832Speter printf("si%d: Warning interrupt handler re-entered\n", 217034832Speter unit); 217110708Speter return; 217210015Speter } 217310015Speter in_intr = 1; 217410015Speter 217510015Speter /* 217610015Speter * When we get an int we poll all the channels and do ALL pending 217710015Speter * work, not just the first one we find. This allows all cards to 217810015Speter * share the same vector. 217934832Speter * 218034832Speter * XXX - But if we're sharing the vector with something that's NOT 218134832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 218210015Speter */ 218334832Speter for (card = 0; card < NSI; card++) { 218410015Speter sc = &si_softc[card]; 218512174Speter if (sc->sc_type == SIEMPTY) 218610015Speter continue; 218712174Speter 218812174Speter /* 218912174Speter * First, clear the interrupt 219012174Speter */ 219110015Speter switch(sc->sc_type) { 219234832Speter case SIHOST: 219310015Speter maddr = sc->sc_maddr; 219410015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 219510015Speter /* flag nothing pending */ 219610015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 219710015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 219810015Speter break; 219910015Speter case SIHOST2: 220010015Speter maddr = sc->sc_maddr; 220110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 220210015Speter *(maddr+SIPLIRQCLR) = 0x00; 220310015Speter *(maddr+SIPLIRQCLR) = 0x10; 220410015Speter break; 220534832Speter#if NPCI > 0 220633395Speter case SIPCI: 220733395Speter maddr = sc->sc_maddr; 220833395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 220933395Speter *(maddr+SIPCIINTCL) = 0x0; 221033395Speter break; 221134832Speter case SIJETPCI: /* fall through to JETISA case */ 221234832Speter#endif 221333395Speter case SIJETISA: 221433395Speter maddr = sc->sc_maddr; 221533395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 221633395Speter *(maddr+SIJETINTCL) = 0x0; 221733395Speter break; 221834832Speter#if NEISA > 0 221910015Speter case SIEISA: 222010015Speter maddr = sc->sc_maddr; 222110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 222234832Speter (void)inb(sc->sc_eisa_iobase + 3); 222310015Speter break; 222434832Speter#endif 222510015Speter case SIEMPTY: 222610015Speter default: 222710015Speter continue; 222810015Speter } 222910015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 223010015Speter 223112174Speter /* 223212174Speter * check each port 223312174Speter */ 223434832Speter for (pp = sc->sc_ports, port=0; port < sc->sc_nport; 223534832Speter pp++, port++) { 223610015Speter ccbp = pp->sp_ccb; 223710015Speter tp = pp->sp_tty; 223810015Speter 223910015Speter /* 224010015Speter * See if a command has completed ? 224110015Speter */ 224210015Speter if (ccbp->hi_stat != pp->sp_pend) { 224310015Speter DPRINT((pp, DBG_INTR, 224434735Speter "si_intr hi_stat = 0x%x, pend = %d\n", 224510015Speter ccbp->hi_stat, pp->sp_pend)); 224610015Speter switch(pp->sp_pend) { 224710015Speter case LOPEN: 224810015Speter case MPEND: 224910015Speter case MOPEN: 225010015Speter case CONFIG: 225116575Speter case SBREAK: 225216575Speter case EBREAK: 225310015Speter pp->sp_pend = ccbp->hi_stat; 225410015Speter /* sleeping in si_command */ 225510015Speter wakeup(&pp->sp_state); 225610015Speter break; 225710015Speter default: 225810015Speter pp->sp_pend = ccbp->hi_stat; 225910015Speter } 226034832Speter } 226110015Speter 226210015Speter /* 226310015Speter * Continue on if it's closed 226410015Speter */ 226510015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 226610015Speter continue; 226710015Speter } 226810015Speter 226910015Speter /* 227010015Speter * Do modem state change if not a local device 227110015Speter */ 227210015Speter si_modem_state(pp, tp, ccbp->hi_ip); 227310015Speter 227410015Speter /* 227534832Speter * Check to see if we should 'receive' characters. 227612174Speter */ 227712174Speter if (tp->t_state & TS_CONNECTED && 227812174Speter tp->t_state & TS_ISOPEN) 227912174Speter isopen = 1; 228012174Speter else 228112174Speter isopen = 0; 228212174Speter 228312174Speter /* 228416575Speter * Do input break processing 228510015Speter */ 228610015Speter if (ccbp->hi_state & ST_BREAK) { 228712174Speter if (isopen) { 228812174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 228910015Speter } 229010015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 229110015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 229210015Speter } 229310015Speter 229410015Speter /* 229512174Speter * Do RX stuff - if not open then dump any characters. 229612174Speter * XXX: This is VERY messy and needs to be cleaned up. 229712174Speter * 229812174Speter * XXX: can we leave data in the host adapter buffer 229912174Speter * when the clists are full? That may be dangerous 230012174Speter * if the user cannot get an interrupt signal through. 230110015Speter */ 230210015Speter 230312174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 230412174Speter 230512174Speter if (!isopen) { 230610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 230712174Speter goto end_rx; 230812174Speter } 230910015Speter 231012174Speter /* 231115640Speter * If the tty input buffers are blocked, stop emptying 231215640Speter * the incoming buffers and let the auto flow control 231315640Speter * assert.. 231415640Speter */ 231515640Speter if (tp->t_state & TS_TBLOCK) { 231615640Speter goto end_rx; 231715640Speter } 231815640Speter 231915640Speter /* 232012174Speter * Process read characters if not skipped above 232112174Speter */ 232215640Speter op = ccbp->hi_rxopos; 232315640Speter ip = ccbp->hi_rxipos; 232415640Speter c = ip - op; 232512174Speter if (c == 0) { 232612174Speter goto end_rx; 232712174Speter } 232810015Speter 232912174Speter n = c & 0xff; 233015640Speter if (n > 250) 233115640Speter n = 250; 233212174Speter 233312174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 233410015Speter n, op, ip)); 233510015Speter 233612174Speter /* 233712174Speter * Suck characters out of host card buffer into the 233812174Speter * "input staging buffer" - so that we dont leave the 233912174Speter * host card in limbo while we're possibly echoing 234012174Speter * characters and possibly flushing input inside the 234112174Speter * ldisc l_rint() routine. 234212174Speter */ 234312496Speter if (n <= SI_BUFFERSIZE - op) { 234410015Speter 234512174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 234612174Speter z = ccbp->hi_rxbuf + op; 234734832Speter si_bcopy((caddr_t)z, si_rxbuf, n); 234810015Speter 234912174Speter op += n; 235012174Speter } else { 235112496Speter x = SI_BUFFERSIZE - op; 235210015Speter 235312174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 235412174Speter z = ccbp->hi_rxbuf + op; 235534832Speter si_bcopy((caddr_t)z, si_rxbuf, x); 235610015Speter 235734832Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 235834832Speter n - x)); 235912174Speter z = ccbp->hi_rxbuf; 236034832Speter si_bcopy((caddr_t)z, si_rxbuf + x, n - x); 236110015Speter 236212174Speter op += n; 236312174Speter } 236410015Speter 236512174Speter /* clear collected characters from buffer */ 236612174Speter ccbp->hi_rxopos = op; 236712174Speter 236812174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 236910015Speter n, op, ip)); 237010015Speter 237112174Speter /* 237212174Speter * at this point... 237312174Speter * n = number of chars placed in si_rxbuf 237412174Speter */ 237510015Speter 237612174Speter /* 237712174Speter * Avoid the grotesquely inefficient lineswitch 237812174Speter * routine (ttyinput) in "raw" mode. It usually 237912174Speter * takes about 450 instructions (that's without 238012174Speter * canonical processing or echo!). slinput is 238112174Speter * reasonably fast (usually 40 instructions 238212174Speter * plus call overhead). 238312174Speter */ 238412174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 238510015Speter 238612174Speter /* block if the driver supports it */ 238712174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 238812174Speter && (tp->t_cflag & CRTS_IFLOW 238912174Speter || tp->t_iflag & IXOFF) 239012174Speter && !(tp->t_state & TS_TBLOCK)) 239112174Speter ttyblock(tp); 239210015Speter 239312174Speter tk_nin += n; 239412174Speter tk_rawcc += n; 239512174Speter tp->t_rawcc += n; 239612174Speter 239712174Speter pp->sp_delta_overflows += 239812174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 239912174Speter 240012174Speter ttwakeup(tp); 240112174Speter if (tp->t_state & TS_TTSTOP 240212174Speter && (tp->t_iflag & IXANY 240312174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 240412174Speter tp->t_state &= ~TS_TTSTOP; 240512174Speter tp->t_lflag &= ~FLUSHO; 240612174Speter si_start(tp); 240712174Speter } 240812174Speter } else { 240912174Speter /* 241012174Speter * It'd be nice to not have to go through the 241112174Speter * function call overhead for each char here. 241212174Speter * It'd be nice to block input it, saving a 241312174Speter * loop here and the call/return overhead. 241412174Speter */ 241512174Speter for(x = 0; x < n; x++) { 241612174Speter i = si_rxbuf[x]; 241712174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 241812174Speter == -1) { 241912174Speter pp->sp_delta_overflows++; 242010015Speter } 242112174Speter /* 242212174Speter * doesn't seem to be much point doing 242312174Speter * this here.. this driver has no 242412174Speter * softtty processing! ?? 242512174Speter */ 242612174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 242712174Speter setsofttty(); 242812174Speter } 242912174Speter } 243012174Speter } 243112174Speter goto more_rx; /* try for more until RXbuf is empty */ 243210015Speter 243312174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 243410015Speter 243510015Speter /* 243610015Speter * Do TX stuff 243710015Speter */ 243810015Speter (*linesw[tp->t_line].l_start)(tp); 243910015Speter 244010015Speter } /* end of for (all ports on this controller) */ 244110015Speter } /* end of for (all controllers) */ 244210015Speter 244311609Speter in_intr = 0; 244434735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit)); 244510015Speter} 244610015Speter 244710015Speter/* 244810015Speter * Nudge the transmitter... 244912174Speter * 245012174Speter * XXX: I inherited some funny code here. It implies the host card only 245112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 245212174Speter * not interrupt when it's actually hits empty. In some cases, we have 245312174Speter * processes waiting for complete drain, and we need to simulate an interrupt 245412174Speter * about when we think the buffer is going to be empty (and retry if not). 245512174Speter * I really am not certain about this... I *need* the hardware manuals. 245610015Speter */ 245710015Speterstatic void 245810015Spetersi_start(tp) 245910015Speter register struct tty *tp; 246010015Speter{ 246110015Speter struct si_port *pp; 246210015Speter volatile struct si_channel *ccbp; 246310015Speter register struct clist *qp; 246410015Speter BYTE ipos; 246510015Speter int nchar; 246610015Speter int oldspl, count, n, amount, buffer_full; 246710015Speter 246810015Speter oldspl = spltty(); 246910015Speter 247010015Speter qp = &tp->t_outq; 247110015Speter pp = TP2PP(tp); 247210015Speter 247310015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 247410015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 247510015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 247610015Speter 247710015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 247810015Speter goto out; 247910015Speter 248010015Speter buffer_full = 0; 248110015Speter ccbp = pp->sp_ccb; 248210015Speter 248310015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 248410015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 248510015Speter 248610015Speter while ((nchar = qp->c_cc) > 0) { 248710015Speter if ((BYTE)count >= 255) { 248810015Speter buffer_full++; 248910015Speter break; 249010015Speter } 249110015Speter amount = min(nchar, (255 - (BYTE)count)); 249210015Speter ipos = (unsigned int)ccbp->hi_txipos; 249334832Speter n = q_to_b(&tp->t_outq, si_txbuf, amount); 249410015Speter /* will it fit in one lump? */ 249534832Speter if ((SI_BUFFERSIZE - ipos) >= n) { 249634832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n); 249710015Speter } else { 249834832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], 249934832Speter SI_BUFFERSIZE - ipos); 250034832Speter si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos), 250134832Speter (char *)&ccbp->hi_txbuf[0], 250234832Speter n - (SI_BUFFERSIZE - ipos)); 250310015Speter } 250410015Speter ccbp->hi_txipos += n; 250510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 250610015Speter } 250710015Speter 250810015Speter if (count != 0 && nchar == 0) { 250910015Speter tp->t_state |= TS_BUSY; 251010015Speter } else { 251110015Speter tp->t_state &= ~TS_BUSY; 251210015Speter } 251310015Speter 251410015Speter /* wakeup time? */ 251510015Speter ttwwakeup(tp); 251610015Speter 251710015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 251810015Speter (BYTE)count, nchar, tp->t_state)); 251910015Speter 252034735Speter if (tp->t_state & TS_BUSY) 252110015Speter { 252210015Speter int time; 252310015Speter 252434735Speter time = ttspeedtab(tp->t_ospeed, chartimes); 252534735Speter 252634735Speter if (time > 0) { 252734735Speter if (time < nchar) 252834735Speter time = nchar / time; 252934735Speter else 253034735Speter time = 2; 253110015Speter } else { 253234735Speter DPRINT((pp, DBG_START, 253334735Speter "bad char time value! %d\n", time)); 253434735Speter time = hz/10; 253510015Speter } 253610015Speter 253710015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 253829677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 253910015Speter } else { 254010015Speter pp->sp_state |= SS_LSTART; 254110015Speter } 254210015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 254329677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 254410015Speter } 254510015Speter 254610015Speterout: 254710015Speter splx(oldspl); 254810015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 254910015Speter} 255010015Speter 255110015Speter/* 255210015Speter * Note: called at splsoftclock from the timeout code 255310015Speter * This has to deal with two things... cause wakeups while waiting for 255410015Speter * tty drains on last process exit, and call l_start at about the right 255510015Speter * time for protocols like ppp. 255610015Speter */ 255710015Speterstatic void 255825047Sbdesi_lstart(void *arg) 255910015Speter{ 256025047Sbde register struct si_port *pp = arg; 256110015Speter register struct tty *tp; 256210015Speter int oldspl; 256310015Speter 256410015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 256510015Speter pp, pp->sp_state)); 256610015Speter 256710015Speter oldspl = spltty(); 256810015Speter 256910015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 257010015Speter splx(oldspl); 257110015Speter return; 257210015Speter } 257310015Speter pp->sp_state &= ~SS_LSTART; 257410015Speter pp->sp_state |= SS_INLSTART; 257510015Speter 257610015Speter tp = pp->sp_tty; 257710015Speter 257810015Speter /* deal with the process exit case */ 257910015Speter ttwwakeup(tp); 258010015Speter 258112174Speter /* nudge protocols - eg: ppp */ 258210015Speter (*linesw[tp->t_line].l_start)(tp); 258310015Speter 258410015Speter pp->sp_state &= ~SS_INLSTART; 258510015Speter splx(oldspl); 258610015Speter} 258710015Speter 258810015Speter/* 258910015Speter * Stop output on a line. called at spltty(); 259010015Speter */ 259110015Spetervoid 259210015Spetersistop(tp, rw) 259310015Speter register struct tty *tp; 259410015Speter int rw; 259510015Speter{ 259610015Speter volatile struct si_channel *ccbp; 259710015Speter struct si_port *pp; 259810015Speter 259910015Speter pp = TP2PP(tp); 260010015Speter ccbp = pp->sp_ccb; 260110015Speter 260210015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 260310015Speter 260410015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 260510015Speter if (rw & FWRITE) { 260610015Speter /* what level are we meant to be flushing anyway? */ 260710015Speter if (tp->t_state & TS_BUSY) { 260810015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 260910015Speter tp->t_state &= ~TS_BUSY; 261010015Speter ttwwakeup(tp); /* Bruce???? */ 261110015Speter } 261210015Speter } 261312174Speter#if 1 /* XXX: this doesn't work right yet.. */ 261412174Speter /* XXX: this may have been failing because we used to call l_rint() 261512174Speter * while we were looping based on these two counters. Now, we collect 261612174Speter * the data and then loop stuffing it into l_rint(), making this 261712174Speter * useless. Should we cause this to blow away the staging buffer? 261812174Speter */ 261910015Speter if (rw & FREAD) { 262010015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 262110015Speter } 262210015Speter#endif 262310015Speter} 262410015Speter 262510015Speter/* 262634832Speter * Issue a command to the host card CPU. 262710015Speter */ 262810015Speter 262910015Speterstatic void 263010015Spetersi_command(pp, cmd, waitflag) 263110015Speter struct si_port *pp; /* port control block (local) */ 263210015Speter int cmd; 263310015Speter int waitflag; 263410015Speter{ 263510015Speter int oldspl; 263610015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 263710015Speter int x; 263810015Speter 263910015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 264010015Speter pp, cmd, waitflag, ccbp->hi_stat)); 264110015Speter 264210015Speter oldspl = spltty(); /* Keep others out */ 264310015Speter 264410015Speter /* wait until it's finished what it was doing.. */ 264516575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 264616575Speter * is turned off. */ 264710015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 264810015Speter x != IDLE_CLOSE && 264916575Speter x != IDLE_BREAK && 265010015Speter x != cmd) { 265110015Speter if (in_intr) { /* Prevent sleep in intr */ 265210015Speter DPRINT((pp, DBG_PARAM, 265310015Speter "cmd intr collision - completing %d\trequested %d\n", 265410015Speter x, cmd)); 265510015Speter splx(oldspl); 265610015Speter return; 265710015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 265810015Speter "sicmd1", 1)) { 265910015Speter splx(oldspl); 266010015Speter return; 266110015Speter } 266210015Speter } 266316575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 266410015Speter 266510015Speter /* if there was a pending command, cause a state-change wakeup */ 266616575Speter switch(pp->sp_pend) { 266716575Speter case LOPEN: 266816575Speter case MPEND: 266916575Speter case MOPEN: 267016575Speter case CONFIG: 267116575Speter case SBREAK: 267216575Speter case EBREAK: 267316575Speter wakeup(&pp->sp_state); 267416575Speter break; 267516575Speter default: 267616575Speter break; 267710015Speter } 267810015Speter 267910015Speter pp->sp_pend = cmd; /* New command pending */ 268010015Speter ccbp->hi_stat = cmd; /* Post it */ 268110015Speter 268210015Speter if (waitflag) { 268310015Speter if (in_intr) { /* If in interrupt handler */ 268410015Speter DPRINT((pp, DBG_PARAM, 268510015Speter "attempt to sleep in si_intr - cmd req %d\n", 268610015Speter cmd)); 268710015Speter splx(oldspl); 268810015Speter return; 268916575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 269016575Speter ccbp->hi_stat != IDLE_BREAK) { 269110015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 269210015Speter "sicmd2", 0)) 269310015Speter break; 269410015Speter } 269510015Speter } 269610015Speter splx(oldspl); 269710015Speter} 269810015Speter 269910015Speterstatic void 270010015Spetersi_disc_optim(tp, t, pp) 270110015Speter struct tty *tp; 270210015Speter struct termios *t; 270310015Speter struct si_port *pp; 270410015Speter{ 270510015Speter /* 270610015Speter * XXX can skip a lot more cases if Smarts. Maybe 270710015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 270810015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 270910015Speter */ 271010015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 271110015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 271210015Speter && (!(t->c_iflag & PARMRK) 271310015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 271410015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 271510015Speter && linesw[tp->t_line].l_rint == ttyinput) 271610015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 271710015Speter else 271810015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 271933322Sphk pp->sp_hotchar = linesw[tp->t_line].l_hotchar; 272010161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 272110161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 272210161Speter pp->sp_hotchar)); 272310015Speter} 272410015Speter 272510015Speter 272610015Speter#ifdef SI_DEBUG 272713353Speter 272810015Speterstatic void 272913353Speter#ifdef __STDC__ 273013353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 273113353Speter#else 273213353Spetersi_dprintf(pp, flags, fmt, va_alist) 273310015Speter struct si_port *pp; 273410015Speter int flags; 273513353Speter char *fmt; 273613353Speter#endif 273710015Speter{ 273813353Speter va_list ap; 273913630Sphk 274010015Speter if ((pp == NULL && (si_debug&flags)) || 274110015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 274234832Speter if (pp != NULL) 274334832Speter printf("%ci%d(%d): ", 's', 274434832Speter (int)SI_CARD(pp->sp_tty->t_dev), 274534832Speter (int)SI_PORT(pp->sp_tty->t_dev)); 274613630Sphk va_start(ap, fmt); 274713630Sphk vprintf(fmt, ap); 274813353Speter va_end(ap); 274910015Speter } 275010015Speter} 275110015Speter 275210015Speterstatic char * 275310015Spetersi_mctl2str(cmd) 275410015Speter enum si_mctl cmd; 275510015Speter{ 275610015Speter switch (cmd) { 275734832Speter case GET: 275834832Speter return("GET"); 275934832Speter case SET: 276034832Speter return("SET"); 276134832Speter case BIS: 276234832Speter return("BIS"); 276334832Speter case BIC: 276434832Speter return("BIC"); 276510015Speter } 276610015Speter return("BAD"); 276710015Speter} 276812502Sjulian 276912624Speter#endif /* DEBUG */ 277012502Sjulian 277134832Speterstatic char * 277234832Spetersi_modulename(host_type, uart_type) 277334832Speter int host_type, uart_type; 277434832Speter{ 277534832Speter switch (host_type) { 277634832Speter /* Z280 based cards */ 277734832Speter#if NEISA > 0 277834832Speter case SIEISA: 277934832Speter#endif 278034832Speter case SIHOST2: 278134832Speter case SIHOST: 278234832Speter#if NPCI > 0 278334832Speter case SIPCI: 278434832Speter#endif 278534832Speter switch (uart_type) { 278634832Speter case 0: 278734832Speter return(" (XIO)"); 278834832Speter case 1: 278934832Speter return(" (SI)"); 279034832Speter } 279134832Speter break; 279234832Speter /* T225 based hosts */ 279334832Speter#if NPCI > 0 279434832Speter case SIJETPCI: 279534832Speter#endif 279634832Speter case SIJETISA: 279734832Speter switch (uart_type) { 279834832Speter case 0: 279934832Speter return(" (SI)"); 280034832Speter case 40: 280134832Speter return(" (XIO)"); 280236856Sphk case 72: 280336856Sphk return(" (SXDC)"); 280434832Speter } 280534832Speter break; 280634832Speter } 280734832Speter return(""); 280834832Speter} 280912624Speter 281012502Sjulianstatic si_devsw_installed = 0; 281112502Sjulian 281234832Speterstatic void 281334832Spetersi_drvinit(void *unused) 281412502Sjulian{ 281512517Sjulian dev_t dev; 281612517Sjulian 281734832Speter if (!si_devsw_installed) { 281812675Sjulian dev = makedev(CDEV_MAJOR, 0); 281912675Sjulian cdevsw_add(&dev,&si_cdevsw, NULL); 282012502Sjulian si_devsw_installed = 1; 282134832Speter } 282212502Sjulian} 282312517Sjulian 282412517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 2825