si.c revision 50016
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 * 3350016Snsayer * $Id: si.c,v 1.87 1999/05/31 11:26:28 phk 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 8346332Speter#warning "Fix si eisa code! - newbus casualty" 8446332Speter#undef NEISA 8546332Speter#define NEISA 0 8646332Speter#endif 8746332Speter#if NEISA > 0 8834832Speter#include <i386/eisa/eisaconf.h> 8934832Speter#include <i386/isa/icu.h> 9034832Speter#endif 9134832Speter 9210015Speter#include "si.h" 9310015Speter 9410015Speter/* 9510015Speter * This device driver is designed to interface the Specialix International 9634832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 9734832Speter * EISA or PCI bus machine. 9810015Speter * 9934832Speter * The controller is interfaced to the host via dual port RAM 10034832Speter * and an interrupt. 10133395Speter * 10234832Speter * The code for the Host 1 (very old ISA cards) has not been tested. 10310015Speter */ 10410015Speter 10517547Speter#define POLL /* turn on poller to scan for lost interrupts */ 10617547Speter#define REALPOLL /* on each poll, scan for work regardless */ 10717547Speter#define POLLHZ (hz/10) /* 10 times per second */ 10812496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 10934832Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 11034832Speter#define JET_INT_COUNT 100 /* max of 100 ints per second */ 11115639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 11210015Speter 11310015Speterenum si_mctl { GET, SET, BIS, BIC }; 11410015Speter 11510015Speterstatic void si_command __P((struct si_port *, int, int)); 11610015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int)); 11710015Speterstatic void si_write_enable __P((struct si_port *, int)); 11838351Sbdestatic int si_Sioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 11910015Speterstatic void si_start __P((struct tty *)); 12025047Sbdestatic timeout_t si_lstart; 12110015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t, 12210015Speter struct si_port *pp)); 12310015Speterstatic void sihardclose __P((struct si_port *pp)); 12410015Speterstatic void sidtrwakeup __P((void *chan)); 12510015Speter 12612724Sphkstatic int siparam __P((struct tty *, struct termios *)); 12710015Speter 12812724Sphkstatic int siprobe __P((struct isa_device *id)); 12912724Sphkstatic int siattach __P((struct isa_device *id)); 13010708Speterstatic void si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip)); 13134735Speterstatic void si_intr __P((int unit)); 13234832Speterstatic char * si_modulename __P((int host_type, int uart_type)); 13310708Speter 13412675Sjulianstruct isa_driver sidriver = 13512675Sjulian { siprobe, siattach, "si" }; 13612675Sjulian 13734832Speterstatic u_long sipcieisacount = 0; 13834832Speter 13933395Speter#if NPCI > 0 14012675Sjulian 14142546Seivindstatic const char *sipciprobe __P((pcici_t, pcidi_t)); 14233395Speterstatic void sipciattach __P((pcici_t, int)); 14333395Speter 14433395Speterstatic struct pci_device sipcidev = { 14533395Speter "si", 14633395Speter sipciprobe, 14733395Speter sipciattach, 14834832Speter &sipcieisacount, 14933395Speter NULL, 15033395Speter}; 15133395Speter 15246024SpeterCOMPAT_PCI_DRIVER (sipci, sipcidev); 15333395Speter 15433395Speter#endif 15533395Speter 15634832Speter#if NEISA > 0 15734832Speter 15834832Speterstatic int si_eisa_probe __P((void)); 15934832Speterstatic int si_eisa_attach __P((struct eisa_device *ed)); 16034832Speter 16134832Speterstatic struct eisa_driver si_eisa_driver = { 16234832Speter "si", 16334832Speter si_eisa_probe, 16434832Speter si_eisa_attach, 16534832Speter NULL, 16634832Speter &sipcieisacount, 16734832Speter}; 16834832Speter 16934832SpeterDATA_SET(eisadriver_set, si_eisa_driver); 17034832Speter 17134832Speter#endif 17234832Speter 17312675Sjulianstatic d_open_t siopen; 17412675Sjulianstatic d_close_t siclose; 17512675Sjulianstatic d_read_t siread; 17612675Sjulianstatic d_write_t siwrite; 17712675Sjulianstatic d_ioctl_t siioctl; 17812675Sjulianstatic d_stop_t sistop; 17912731Sbdestatic d_devtotty_t sidevtotty; 18012675Sjulian 18138485Sbde#define CDEV_MAJOR 68 18247625Sphkstatic struct cdevsw si_cdevsw = { 18347625Sphk /* open */ siopen, 18447625Sphk /* close */ siclose, 18547625Sphk /* read */ siread, 18647625Sphk /* write */ siwrite, 18747625Sphk /* ioctl */ siioctl, 18847625Sphk /* stop */ sistop, 18947625Sphk /* reset */ noreset, 19047625Sphk /* devtotty */ sidevtotty, 19147625Sphk /* poll */ ttpoll, 19247625Sphk /* mmap */ nommap, 19347625Sphk /* strategy */ nostrategy, 19447625Sphk /* name */ "si", 19547625Sphk /* parms */ noparms, 19647625Sphk /* maj */ CDEV_MAJOR, 19747625Sphk /* dump */ nodump, 19847625Sphk /* psize */ nopsize, 19947625Sphk /* flags */ D_TTY, 20047625Sphk /* maxio */ 0, 20147625Sphk /* bmaj */ -1 20238485Sbde}; 20312675Sjulian 20412174Speter#ifdef SI_DEBUG /* use: ``options "SI_DEBUG"'' in your config file */ 20513353Speter 20613353Speterstatic void si_dprintf __P((struct si_port *pp, int flags, const char *fmt, 20713353Speter ...)); 20810708Speterstatic char *si_mctl2str __P((enum si_mctl cmd)); 20913353Speter 21010708Speter#define DPRINT(x) si_dprintf x 21113353Speter 21210708Speter#else 21310708Speter#define DPRINT(x) /* void */ 21410708Speter#endif 21510708Speter 21610962Speterstatic int si_Nports; 21710962Speterstatic int si_Nmodules; 21810962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 21910015Speter 22034832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 22134832Speter 22210962Speterstatic struct tty *si_tty; 22310962Speter 22434832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */ 22534832Speter/* old: si2_z280.c */ 22634832Speterextern unsigned char si2_z280_download[]; 22734832Speterextern unsigned short si2_z280_downloadaddr; 22834832Speterextern int si2_z280_dsize; 22934832Speter/* new: si3_t225.c */ 23034832Speterextern unsigned char si3_t225_download[]; 23134832Speterextern unsigned short si3_t225_downloadaddr; 23234832Speterextern int si3_t225_dsize; 23334832Speterextern unsigned char si3_t225_bootstrap[]; 23434832Speterextern unsigned short si3_t225_bootloadaddr; 23534832Speterextern int si3_t225_bsize; 23610015Speter 23733395Speter 23810044Speterstruct si_softc { 23910044Speter int sc_type; /* adapter type */ 24010044Speter char *sc_typename; /* adapter type string */ 24110044Speter 24210044Speter struct si_port *sc_ports; /* port structures for this card */ 24310044Speter 24410044Speter caddr_t sc_paddr; /* physical addr of iomem */ 24510044Speter caddr_t sc_maddr; /* kvaddr of iomem */ 24610044Speter int sc_nport; /* # ports on this card */ 24710044Speter int sc_irq; /* copy of attach irq */ 24834832Speter#if NEISA > 0 24910044Speter int sc_eisa_iobase; /* EISA io port address */ 25034832Speter int sc_eisa_irq; /* EISA irq number */ 25134832Speter#endif 25212675Sjulian#ifdef DEVFS 25312675Sjulian struct { 25434735Speter void *ttya; 25512826Speter void *cuaa; 25612675Sjulian void *ttyl; 25734735Speter void *cual; 25812675Sjulian void *ttyi; 25934735Speter void *cuai; 26012675Sjulian } devfs_token[32]; /* what is the max per card? */ 26113165Speter void *control_token; 26212675Sjulian#endif 26310044Speter}; 26412724Sphkstatic struct si_softc si_softc[NSI]; /* up to 4 elements */ 26510044Speter 26612174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 26710015Speter# define B2000 2000 26810015Speter#endif 26910015Speterstatic struct speedtab bdrates[] = { 27010015Speter B75, CLK75, /* 0x0 */ 27110015Speter B110, CLK110, /* 0x1 */ 27210015Speter B150, CLK150, /* 0x3 */ 27310015Speter B300, CLK300, /* 0x4 */ 27410015Speter B600, CLK600, /* 0x5 */ 27510015Speter B1200, CLK1200, /* 0x6 */ 27610015Speter B2000, CLK2000, /* 0x7 */ 27710015Speter B2400, CLK2400, /* 0x8 */ 27810015Speter B4800, CLK4800, /* 0x9 */ 27910015Speter B9600, CLK9600, /* 0xb */ 28010015Speter B19200, CLK19200, /* 0xc */ 28110015Speter B38400, CLK38400, /* 0x2 (out of order!) */ 28210015Speter B57600, CLK57600, /* 0xd */ 28310015Speter B115200, CLK110, /* 0x1 (dupe!, 110 baud on "si") */ 28410015Speter -1, -1 28510015Speter}; 28610015Speter 28710015Speter 28810015Speter/* populated with approx character/sec rates - translated at card 28910015Speter * initialisation time to chars per tick of the clock */ 29010015Speterstatic int done_chartimes = 0; 29110015Speterstatic struct speedtab chartimes[] = { 29210015Speter B75, 8, 29310015Speter B110, 11, 29410015Speter B150, 15, 29510015Speter B300, 30, 29610015Speter B600, 60, 29710015Speter B1200, 120, 29810015Speter B2000, 200, 29910015Speter B2400, 240, 30010015Speter B4800, 480, 30110015Speter B9600, 960, 30210015Speter B19200, 1920, 30310015Speter B38400, 3840, 30410015Speter B57600, 5760, 30510015Speter B115200, 11520, 30610015Speter -1, -1 30710015Speter}; 30810015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 30910015Speter 31010015Speter#ifdef POLL 31115683Speterstatic int si_pollrate; /* in addition to irq */ 31217547Speterstatic int si_realpoll; /* poll HW on timer */ 31315639Speter 31416403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 31517547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 31615639Speter 31710015Speterstatic int init_finished = 0; 31810015Speterstatic void si_poll __P((void *)); 31910015Speter#endif 32010015Speter 32110015Speter/* 32210015Speter * Array of adapter types and the corresponding RAM size. The order of 32310015Speter * entries here MUST match the ordinal of the adapter type. 32410015Speter */ 32510015Speterstatic char *si_type[] = { 32610015Speter "EMPTY", 32710015Speter "SIHOST", 32834832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 32910015Speter "SIHOST2", 33010015Speter "SIEISA", 33133395Speter "SIPCI", 33233395Speter "SXPCI", 33333395Speter "SXISA", 33410015Speter}; 33510015Speter 33633395Speter#if NPCI > 0 33733395Speter 33842546Seivindstatic const char * 33933395Spetersipciprobe(configid, deviceid) 34033395Speterpcici_t configid; 34133395Speterpcidi_t deviceid; 34233395Speter{ 34333395Speter switch (deviceid) 34433395Speter { 34533395Speter case 0x400011cb: 34633395Speter return("Specialix SI/XIO PCI host card"); 34733395Speter break; 34833395Speter case 0x200011cb: 34933395Speter if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb) 35033395Speter return("Specialix SX PCI host card"); 35133395Speter else 35233395Speter return NULL; 35333395Speter break; 35433395Speter default: 35533395Speter return NULL; 35633395Speter } 35733395Speter /*NOTREACHED*/ 35833395Speter} 35933395Speter 36033395Spetervoid 36133395Spetersipciattach(configid, unit) 36233395Speterpcici_t configid; 36333395Speterint unit; 36433395Speter{ 36533395Speter struct isa_device id; 36633395Speter vm_offset_t vaddr,paddr; 36733395Speter u_long mapval = 0; /* shut up gcc, should not be needed */ 36833395Speter 36933395Speter switch ( pci_conf_read(configid, 0) >> 16 ) 37033395Speter { 37133395Speter case 0x4000: 37233395Speter si_softc[unit].sc_type = SIPCI; 37333395Speter mapval = SIPCIBADR; 37434832Speter break; 37533395Speter case 0x2000: 37633395Speter si_softc[unit].sc_type = SIJETPCI; 37733395Speter mapval = SIJETBADR; 37834832Speter break; 37933395Speter } 38033395Speter if (!pci_map_mem(configid, mapval, &vaddr, &paddr)) 38133395Speter { 38233395Speter printf("si%d: couldn't map memory\n", unit); 38333395Speter } 38433395Speter 38533395Speter /* 38633395Speter * We're cheating here a little bit. The argument to an ISA 38733395Speter * interrupt routine is the unit number. The argument to a 38833395Speter * PCI interrupt handler is a void *, but we're simply going 38933395Speter * to be lazy and hand it the unit number. 39033395Speter */ 39134735Speter if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) { 39233395Speter printf("si%d: couldn't map interrupt\n", unit); 39333395Speter } 39433395Speter si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type]; 39533395Speter 39633395Speter /* 39733395Speter * More cheating: We're going to dummy up a struct isa_device 39833395Speter * and call the other attach routine. We don't really have to 39933395Speter * fill in very much of the structure, since we filled in a 40033395Speter * little of the soft state already. 40133395Speter */ 40234735Speter id.id_unit = unit; 40334735Speter id.id_maddr = (caddr_t) vaddr; 40433395Speter siattach(&id); 40533395Speter} 40633395Speter 40733395Speter#endif 40833395Speter 40934832Speter#if NEISA > 0 41034832Speter 41134832Speterstatic const char *si_eisa_match __P((eisa_id_t id)); 41234832Speter 41334832Speterstatic const char * 41434832Spetersi_eisa_match(id) 41534832Speter eisa_id_t id; 41634832Speter{ 41734832Speter if (id == SIEISADEVID) 41834832Speter return ("Specialix SI/XIO EISA host card"); 41934832Speter return (NULL); 42034832Speter} 42134832Speter 42234832Speterstatic int 42334832Spetersi_eisa_probe(void) 42434832Speter{ 42534832Speter struct eisa_device *ed = NULL; 42634832Speter int count, irq; 42734832Speter 42834832Speter for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++) 42934832Speter { 43034832Speter u_long port,maddr; 43134832Speter 43234832Speter port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE; 43334832Speter eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE); 43434832Speter maddr = (inb(port+1) << 24) | (inb(port) << 16); 43534832Speter irq = ((inb(port+2) >> 4) & 0xf); 43634832Speter eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE); 43734832Speter eisa_add_intr(ed, irq); 43834832Speter eisa_registerdev(ed, &si_eisa_driver); 43934832Speter count++; 44034832Speter } 44134832Speter return count; 44234832Speter} 44334832Speter 44434832Speterstatic int 44534832Spetersi_eisa_attach(ed) 44634832Speter struct eisa_device *ed; 44734832Speter{ 44834832Speter struct isa_device id; 44934832Speter resvaddr_t *maddr,*iospace; 45034832Speter u_int irq; 45134832Speter struct si_softc *sc; 45234832Speter 45334832Speter sc = &si_softc[ed->unit]; 45434832Speter 45534832Speter sc->sc_type = SIEISA; 45634832Speter sc->sc_typename = si_type[sc->sc_type]; 45734832Speter 45834832Speter if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) { 45938487Sbde printf("si%lu: no iospace??\n", ed->unit); 46034832Speter return -1; 46134832Speter } 46234832Speter sc->sc_eisa_iobase = iospace->addr; 46334832Speter 46434832Speter irq = ((inb(iospace->addr + 2) >> 4) & 0xf); 46534832Speter sc->sc_eisa_irq = irq; 46634832Speter 46734832Speter if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) { 46838487Sbde printf("si%lu: where am I??\n", ed->unit); 46934832Speter return -1; 47034832Speter } 47134832Speter eisa_reg_start(ed); 47234832Speter if (eisa_reg_iospace(ed, iospace)) { 47338487Sbde printf("si%lu: failed to register iospace %p\n", 47438487Sbde ed->unit, (void *)iospace); 47534832Speter return -1; 47634832Speter } 47734832Speter if (eisa_reg_mspace(ed, maddr)) { 47838487Sbde printf("si%lu: failed to register memspace %p\n", 47938487Sbde ed->unit, (void *)maddr); 48034832Speter return -1; 48134832Speter } 48234832Speter /* 48334832Speter * We're cheating here a little bit. The argument to an ISA 48434832Speter * interrupt routine is the unit number. The argument to a 48534832Speter * EISA interrupt handler is a void *, but we're simply going 48634832Speter * to be lazy and hand it the unit number. 48734832Speter */ 48834832Speter if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr, 48938353Sbde (void *)(intptr_t)(ed->unit), &tty_imask, 1)) { 49038487Sbde printf("si%lu: failed to register interrupt %d\n", 49134832Speter ed->unit, irq); 49234832Speter return -1; 49334832Speter } 49434832Speter eisa_reg_end(ed); 49534832Speter if (eisa_enable_intr(ed, irq)) { 49634832Speter return -1; 49734832Speter } 49834832Speter 49934832Speter /* 50034832Speter * More cheating: We're going to dummy up a struct isa_device 50134832Speter * and call the other attach routine. We don't really have to 50234832Speter * fill in very much of the structure, since we filled in a 50334832Speter * little of the soft state already. 50434832Speter */ 50534832Speter id.id_unit = ed->unit; 50634832Speter id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE); 50734832Speter return (siattach(&id)); 50834832Speter} 50934832Speter 51034832Speter#endif 51134832Speter 51234832Speter 51310015Speter/* Look for a valid board at the given mem addr */ 51412724Sphkstatic int 51510015Spetersiprobe(id) 51610015Speter struct isa_device *id; 51710015Speter{ 51810015Speter struct si_softc *sc; 51910015Speter int type; 52010015Speter u_int i, ramsize; 52110015Speter volatile BYTE was, *ux; 52210015Speter volatile unsigned char *maddr; 52310015Speter unsigned char *paddr; 52410015Speter 52517547Speter si_pollrate = POLLHZ; /* default 10 per second */ 52617547Speter#ifdef REALPOLL 52717547Speter si_realpoll = 1; /* scan always */ 52817547Speter#endif 52910015Speter maddr = id->id_maddr; /* virtual address... */ 53010015Speter paddr = (caddr_t)vtophys(id->id_maddr); /* physical address... */ 53110015Speter 53212496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n", 53312496Speter id->id_unit, id->id_maddr, paddr)); 53410015Speter 53510015Speter /* 53610015Speter * this is a lie, but it's easier than trying to handle caching 53710015Speter * and ram conflicts in the >1M and <16M region. 53810015Speter */ 53910015Speter if ((caddr_t)paddr < (caddr_t)IOM_BEGIN || 54010015Speter (caddr_t)paddr >= (caddr_t)IOM_END) { 54138353Sbde printf("si%d: iomem (%p) out of range\n", 54238353Sbde id->id_unit, (void *)paddr); 54310015Speter return(0); 54410015Speter } 54510015Speter 54610015Speter if (id->id_unit >= NSI) { 54710015Speter /* THIS IS IMPOSSIBLE */ 54810015Speter return(0); 54910015Speter } 55010015Speter 55110015Speter if (((u_int)paddr & 0x7fff) != 0) { 55210015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 55310015Speter "si%d: iomem (%x) not on 32k boundary\n", 55410015Speter id->id_unit, paddr)); 55510015Speter return(0); 55610015Speter } 55710015Speter 55834735Speter if (si_softc[id->id_unit].sc_typename) { 55934832Speter /* EISA or PCI has taken this unit, choose another */ 56034735Speter for (i=0; i < NSI; i++) { 56134735Speter if (si_softc[i].sc_typename == NULL) { 56234735Speter id->id_unit = i; 56334735Speter break; 56434735Speter } 56534735Speter } 56634735Speter if (i >= NSI) { 56734735Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 56834735Speter "si%d: cannot realloc unit\n", id->id_unit)); 56934735Speter return (0); 57034735Speter } 57134735Speter } 57234735Speter 57310015Speter for (i=0; i < NSI; i++) { 57434735Speter sc = &si_softc[i]; 57510015Speter if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) { 57610015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 57710015Speter "si%d: iomem (%x) already configured to si%d\n", 57810015Speter id->id_unit, sc->sc_paddr, i)); 57910015Speter return(0); 58010015Speter } 58110015Speter } 58210015Speter 58310015Speter /* Is there anything out there? (0x17 is just an arbitrary number) */ 58410015Speter *maddr = 0x17; 58510015Speter if (*maddr != 0x17) { 58610015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 58710015Speter "si%d: 0x17 check fail at phys 0x%x\n", 58810015Speter id->id_unit, paddr)); 58910015Speterfail: 59010015Speter return(0); 59110015Speter } 59210015Speter /* 59333395Speter * Let's look first for a JET ISA card, since that's pretty easy 59434832Speter * 59534832Speter * All jet hosts are supposed to have this string in the IDROM, 59634832Speter * but it's not worth checking on self-IDing busses like PCI. 59733395Speter */ 59834832Speter { 59934832Speter unsigned char *jet_chk_str = "JET HOST BY KEV#"; 60034832Speter 60134832Speter for (i = 0; i < strlen(jet_chk_str); i++) 60234832Speter if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i)) 60334832Speter goto try_mk2; 60434832Speter } 60533395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 60633395Speter "si%d: JET first check - 0x%x\n", 60733395Speter id->id_unit, (*(maddr+SIJETIDBASE)))); 60833395Speter if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff)) 60933395Speter goto try_mk2; 61033395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 61133395Speter "si%d: JET second check - 0x%x\n", 61233395Speter id->id_unit, (*(maddr+SIJETIDBASE+2)))); 61333395Speter if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8)) 61433395Speter goto try_mk2; 61533395Speter /* It must be a Jet ISA or RIO card */ 61633395Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 61733395Speter "si%d: JET id check - 0x%x\n", 61833395Speter id->id_unit, (*(maddr+SIUNIQID)))); 61933395Speter if ((*(maddr+SIUNIQID) & 0xf0) !=0x20) 62033395Speter goto try_mk2; 62133395Speter /* It must be a Jet ISA SI/XIO card */ 62233395Speter *(maddr + SIJETCONFIG) = 0; 62333395Speter type = SIJETISA; 62433395Speter ramsize = SIJET_RAMSIZE; 62533395Speter goto got_card; 62633395Speter /* 62710015Speter * OK, now to see if whatever responded is really an SI card. 62833395Speter * Try for a MK II next (SIHOST2) 62910015Speter */ 63033395Spetertry_mk2: 63134832Speter for (i = SIPLSIG; i < SIPLSIG + 8; i++) 63210015Speter if ((*(maddr+i) & 7) != (~(BYTE)i & 7)) 63310015Speter goto try_mk1; 63410015Speter 63510015Speter /* It must be an SIHOST2 */ 63610015Speter *(maddr + SIPLRESET) = 0; 63710015Speter *(maddr + SIPLIRQCLR) = 0; 63810015Speter *(maddr + SIPLIRQSET) = 0x10; 63910015Speter type = SIHOST2; 64010015Speter ramsize = SIHOST2_RAMSIZE; 64110015Speter goto got_card; 64210015Speter 64310015Speter /* 64410015Speter * Its not a MK II, so try for a MK I (SIHOST) 64510015Speter */ 64610015Spetertry_mk1: 64710015Speter *(maddr+SIRESET) = 0x0; /* reset the card */ 64810015Speter *(maddr+SIINTCL) = 0x0; /* clear int */ 64910015Speter *(maddr+SIRAM) = 0x17; 65010015Speter if (*(maddr+SIRAM) != (BYTE)0x17) 65110015Speter goto fail; 65210015Speter *(maddr+0x7ff8) = 0x17; 65310015Speter if (*(maddr+0x7ff8) != (BYTE)0x17) { 65410015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 65510015Speter "si%d: 0x17 check fail at phys 0x%x = 0x%x\n", 65610015Speter id->id_unit, paddr+0x77f8, *(maddr+0x77f8))); 65710015Speter goto fail; 65810015Speter } 65910015Speter 66034832Speter /* It must be an SIHOST (maybe?) - there must be a better way XXX */ 66110015Speter type = SIHOST; 66210015Speter ramsize = SIHOST_RAMSIZE; 66310015Speter 66410015Spetergot_card: 66512496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n", 66612496Speter id->id_unit, type)); 66710015Speter /* Try the acid test */ 66818515Speter ux = maddr + SIRAM; 66934832Speter for (i = 0; i < ramsize; i++, ux++) 67010015Speter *ux = (BYTE)(i&0xff); 67118515Speter ux = maddr + SIRAM; 67234832Speter for (i = 0; i < ramsize; i++, ux++) { 67310015Speter if ((was = *ux) != (BYTE)(i&0xff)) { 67410015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 67512174Speter "si%d: match fail at phys 0x%x, was %x should be %x\n", 67634832Speter id->id_unit, paddr + i, was, i&0xff)); 67710015Speter goto fail; 67810015Speter } 67910015Speter } 68010015Speter 68110015Speter /* clear out the RAM */ 68218515Speter ux = maddr + SIRAM; 68334832Speter for (i = 0; i < ramsize; i++) 68410015Speter *ux++ = 0; 68518515Speter ux = maddr + SIRAM; 68634832Speter for (i = 0; i < ramsize; i++) { 68710015Speter if ((was = *ux++) != 0) { 68810015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 68912174Speter "si%d: clear fail at phys 0x%x, was %x\n", 69034832Speter id->id_unit, paddr + i, was)); 69110015Speter goto fail; 69210015Speter } 69310015Speter } 69410015Speter 69510015Speter /* 69610015Speter * Success, we've found a valid board, now fill in 69710015Speter * the adapter structure. 69810015Speter */ 69910015Speter switch (type) { 70010015Speter case SIHOST2: 70134832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 70210015Speterbad_irq: 70310015Speter DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, 70410015Speter "si%d: bad IRQ value - %d\n", 70510015Speter id->id_unit, id->id_irq)); 70610015Speter return(0); 70710015Speter } 70810015Speter id->id_msize = SIHOST2_MEMSIZE; 70910015Speter break; 71010015Speter case SIHOST: 71134832Speter if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) { 71210015Speter goto bad_irq; 71310015Speter } 71410015Speter id->id_msize = SIHOST_MEMSIZE; 71510015Speter break; 71633395Speter case SIJETISA: 71734832Speter if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) { 71833395Speter goto bad_irq; 71933395Speter } 72034832Speter id->id_msize = SIJETISA_MEMSIZE; 72133395Speter break; 72234832Speter case SIMCA: /* MCA */ 72310015Speter default: 72410015Speter printf("si%d: %s not supported\n", id->id_unit, si_type[type]); 72510015Speter return(0); 72610015Speter } 72734832Speter id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */ 72810015Speter si_softc[id->id_unit].sc_type = type; 72910015Speter si_softc[id->id_unit].sc_typename = si_type[type]; 73010015Speter return(-1); /* -1 == found */ 73110015Speter} 73210015Speter 73310015Speter/* 73434832Speter * We have to make an 8 bit version of bcopy, since some cards can't 73534832Speter * deal with 32 bit I/O 73634832Speter */ 73734832Speter#if 1 73834832Speterstatic void 73934832Spetersi_bcopy(const void *src, void *dst, size_t len) 74034832Speter{ 74134832Speter while (len--) 74234832Speter *(((u_char *)dst)++) = *(((u_char *)src)++); 74334832Speter} 74434832Speter#else 74534832Speter#define si_bcopy bcopy 74634832Speter#endif 74734832Speter 74834832Speter 74934832Speter/* 75010015Speter * Attach the device. Initialize the card. 75134832Speter * 75234832Speter * This routine also gets called by the EISA and PCI attach routines. 75334832Speter * It presumes that the softstate for the unit has had had its type field 75434832Speter * and the EISA specific stuff filled in, as well as the kernel virtual 75534832Speter * base address and the unit number of the isa_device struct. 75610015Speter */ 75712724Sphkstatic int 75810015Spetersiattach(id) 75910015Speter struct isa_device *id; 76010015Speter{ 76110015Speter int unit = id->id_unit; 76210015Speter struct si_softc *sc = &si_softc[unit]; 76310015Speter struct si_port *pp; 76410015Speter volatile struct si_channel *ccbp; 76510015Speter volatile struct si_reg *regp; 76610015Speter volatile caddr_t maddr; 76710015Speter struct si_module *modp; 76810015Speter struct tty *tp; 76910015Speter struct speedtab *spt; 77010015Speter int nmodule, nport, x, y; 77112174Speter int uart_type; 77210015Speter 77312496Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit)); 77410015Speter 77510015Speter sc->sc_paddr = (caddr_t)vtophys(id->id_maddr); 77610015Speter sc->sc_maddr = id->id_maddr; 77710015Speter sc->sc_irq = id->id_irq; 77810015Speter 77933395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 78033395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 78133395Speter 78210015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 78310015Speter 78410015Speter maddr = sc->sc_maddr; 78510015Speter 78634832Speter /* Stop the CPU first so it won't stomp around while we load */ 78734832Speter 78834832Speter switch (sc->sc_type) { 78934832Speter#if NEISA > 0 79034832Speter case SIEISA: 79134832Speter outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4); 79234832Speter break; 79334832Speter#endif 79434832Speter#if NPCI > 0 79534832Speter case SIPCI: 79634832Speter *(maddr+SIPCIRESET) = 0; 79734832Speter break; 79834832Speter case SIJETPCI: /* fall through to JET ISA */ 79934832Speter#endif 80034832Speter case SIJETISA: 80134832Speter *(maddr+SIJETCONFIG) = 0; 80234832Speter break; 80334832Speter case SIHOST2: 80434832Speter *(maddr+SIPLRESET) = 0; 80534832Speter break; 80634832Speter case SIHOST: 80734832Speter *(maddr+SIRESET) = 0; 80834832Speter break; 80934832Speter default: /* this should never happen */ 81034832Speter printf("si%d: unsupported configuration\n", unit); 81134832Speter return 0; 81234832Speter break; 81334832Speter } 81434832Speter 81534832Speter /* OK, now lets download the download code */ 81634832Speter 81736956Ssteve if (SI_ISJET(sc->sc_type)) { 81833395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 81934832Speter id->id_unit, si3_t225_dsize)); 82034832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 82134832Speter si3_t225_dsize); 82234832Speter DPRINT((0, DBG_DOWNLOAD, 82334832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 82434832Speter id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr)); 82534832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 82634832Speter si3_t225_bsize); 82734832Speter } else { 82833395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 82934832Speter id->id_unit, si2_z280_dsize)); 83034832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 83134832Speter si2_z280_dsize); 83233395Speter } 83310015Speter 83434832Speter /* Now start the CPU */ 83534832Speter 83610015Speter switch (sc->sc_type) { 83734832Speter#if NEISA > 0 83810015Speter case SIEISA: 83934832Speter /* modify the download code to tell it that it's on an EISA */ 84034832Speter *(maddr + 0x42) = 1; 84134832Speter outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4); 84234832Speter (void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */ 84310015Speter break; 84434832Speter#endif 84533395Speter case SIPCI: 84634832Speter /* modify the download code to tell it that it's on a PCI */ 84733395Speter *(maddr+0x42) = 1; 84833395Speter *(maddr+SIPCIRESET) = 1; 84933395Speter *(maddr+SIPCIINTCL) = 0; 85033395Speter break; 85133395Speter case SIJETPCI: 85233395Speter *(maddr+SIJETRESET) = 0; 85333395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 85433395Speter break; 85533395Speter case SIJETISA: 85633395Speter *(maddr+SIJETRESET) = 0; 85734832Speter switch (sc->sc_irq) { 85834832Speter case IRQ9: 85934832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 86034832Speter break; 86134832Speter case IRQ10: 86234832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 86334832Speter break; 86434832Speter case IRQ11: 86534832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 86634832Speter break; 86734832Speter case IRQ12: 86834832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 86934832Speter break; 87034832Speter case IRQ15: 87134832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 87234832Speter break; 87334832Speter } 87433395Speter break; 87510015Speter case SIHOST: 87610015Speter *(maddr+SIRESET_CL) = 0; 87710015Speter *(maddr+SIINTCL_CL) = 0; 87810015Speter break; 87910015Speter case SIHOST2: 88010015Speter *(maddr+SIPLRESET) = 0x10; 88110015Speter switch (sc->sc_irq) { 88210015Speter case IRQ11: 88310015Speter *(maddr+SIPLIRQ11) = 0x10; 88410015Speter break; 88510015Speter case IRQ12: 88610015Speter *(maddr+SIPLIRQ12) = 0x10; 88710015Speter break; 88810015Speter case IRQ15: 88910015Speter *(maddr+SIPLIRQ15) = 0x10; 89010015Speter break; 89110015Speter } 89210015Speter *(maddr+SIPLIRQCLR) = 0x10; 89310015Speter break; 89434832Speter default: /* this should _REALLY_ never happen */ 89534832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 89634832Speter return 0; 89710015Speter } 89810015Speter 89910015Speter DELAY(1000000); /* wait around for a second */ 90010015Speter 90110015Speter regp = (struct si_reg *)maddr; 90210015Speter y = 0; 90310015Speter /* wait max of 5 sec for init OK */ 90410015Speter while (regp->initstat == 0 && y++ < 10) { 90510015Speter DELAY(500000); 90610015Speter } 90710015Speter switch (regp->initstat) { 90810015Speter case 0: 90910015Speter printf("si%d: startup timeout - aborting\n", unit); 91012174Speter sc->sc_type = SIEMPTY; 91110015Speter return 0; 91210015Speter case 1: 91336956Ssteve if (SI_ISJET(sc->sc_type)) { 91434832Speter /* set throttle to 100 times per second */ 91534832Speter regp->int_count = JET_INT_COUNT; 91634832Speter /* rx_intr_count is a NOP in Jet */ 91734832Speter } else { 91834832Speter /* set throttle to 125 times per second */ 91934832Speter regp->int_count = INT_COUNT; 92034832Speter /* rx intr max of 25 times per second */ 92134832Speter regp->rx_int_count = RXINT_COUNT; 92234832Speter } 92310015Speter regp->int_pending = 0; /* no intr pending */ 92410015Speter regp->int_scounter = 0; /* reset counter */ 92510015Speter break; 92610015Speter case 0xff: 92710015Speter /* 92810015Speter * No modules found, so give up on this one. 92910015Speter */ 93010015Speter printf("si%d: %s - no ports found\n", unit, 93110015Speter si_type[sc->sc_type]); 93210015Speter return 0; 93310015Speter default: 93434832Speter printf("si%d: download code version error - initstat %x\n", 93510015Speter unit, regp->initstat); 93610015Speter return 0; 93710015Speter } 93810015Speter 93910015Speter /* 94010015Speter * First time around the ports just count them in order 94110015Speter * to allocate some memory. 94210015Speter */ 94310015Speter nport = 0; 94410015Speter modp = (struct si_module *)(maddr + 0x80); 94510015Speter for (;;) { 94612174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 94734832Speter switch (modp->sm_type) { 94834832Speter case TA4: 94910015Speter DPRINT((0, DBG_DOWNLOAD, 95034832Speter "si%d: Found old TA4 module, 4 ports\n", 95134832Speter unit)); 95234832Speter x = 4; 95310015Speter break; 95434832Speter case TA8: 95534832Speter DPRINT((0, DBG_DOWNLOAD, 95634832Speter "si%d: Found old TA8 module, 8 ports\n", 95734832Speter unit)); 95834832Speter x = 8; 95934832Speter break; 96034832Speter case TA4_ASIC: 96134832Speter DPRINT((0, DBG_DOWNLOAD, 96234832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 96334832Speter unit)); 96434832Speter x = 4; 96534832Speter break; 96634832Speter case TA8_ASIC: 96734832Speter DPRINT((0, DBG_DOWNLOAD, 96834832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 96934832Speter unit)); 97034832Speter x = 8; 97134832Speter break; 97234832Speter case MTA: 97334832Speter DPRINT((0, DBG_DOWNLOAD, 97434832Speter "si%d: Found CD1400 module, 8 ports\n", 97534832Speter unit)); 97634832Speter x = 8; 97734832Speter break; 97834832Speter case SXDC: 97934832Speter DPRINT((0, DBG_DOWNLOAD, 98034832Speter "si%d: Found SXDC module, 8 ports\n", 98134832Speter unit)); 98234832Speter x = 8; 98334832Speter break; 98410015Speter default: 98510015Speter printf("si%d: unknown module type %d\n", 98610015Speter unit, modp->sm_type); 98734832Speter goto try_next; 98810015Speter } 98934832Speter 99034832Speter /* this was limited in firmware and is also a driver issue */ 99134832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 99234832Speter printf("si%d: extra ports ignored\n", unit); 99334832Speter goto try_next; 99434832Speter } 99534832Speter 99634832Speter nport += x; 99734832Speter si_Nports += x; 99834832Speter si_Nmodules++; 99934832Speter 100034832Spetertry_next: 100110015Speter if (modp->sm_next == 0) 100210015Speter break; 100310015Speter modp = (struct si_module *) 100410015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 100510015Speter } 100610015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 100710015Speter M_DEVBUF, M_NOWAIT); 100810015Speter if (sc->sc_ports == 0) { 100910015Spetermem_fail: 101010015Speter printf("si%d: fail to malloc memory for port structs\n", 101110015Speter unit); 101210015Speter return 0; 101310015Speter } 101410015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 101510015Speter sc->sc_nport = nport; 101610015Speter 101710015Speter /* 101810015Speter * allocate tty structures for ports 101910015Speter */ 102010015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 102110015Speter if (tp == 0) 102210015Speter goto mem_fail; 102310015Speter bzero(tp, sizeof(*tp) * nport); 102410962Speter si_tty = tp; 102510015Speter 102610015Speter /* 102710015Speter * Scan round the ports again, this time initialising. 102810015Speter */ 102910015Speter pp = sc->sc_ports; 103010015Speter nmodule = 0; 103110015Speter modp = (struct si_module *)(maddr + 0x80); 103234832Speter uart_type = 1000; /* arbitary, > uchar_max */ 103310015Speter for (;;) { 103434832Speter switch (modp->sm_type) { 103534832Speter case TA4: 103634832Speter nport = 4; 103710015Speter break; 103834832Speter case TA8: 103934832Speter nport = 8; 104034832Speter break; 104134832Speter case TA4_ASIC: 104234832Speter nport = 4; 104334832Speter break; 104434832Speter case TA8_ASIC: 104534832Speter nport = 8; 104634832Speter break; 104734832Speter case MTA: 104834832Speter nport = 8; 104934832Speter break; 105034832Speter case SXDC: 105134832Speter nport = 8; 105234832Speter break; 105310015Speter default: 105434832Speter goto try_next2; 105510015Speter } 105634832Speter nmodule++; 105734832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 105834832Speter if (uart_type == 1000) 105934832Speter uart_type = ccbp->type; 106034832Speter else if (uart_type != ccbp->type) 106134832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 106234832Speter unit, nmodule, 106334832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 106434832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 106534832Speter 106634832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 106734832Speter pp->sp_ccb = ccbp; /* save the address */ 106834832Speter pp->sp_tty = tp++; 106934832Speter pp->sp_pend = IDLE_CLOSE; 107034832Speter pp->sp_state = 0; /* internal flag */ 107134832Speter pp->sp_dtr_wait = 3 * hz; 107234832Speter pp->sp_iin.c_iflag = TTYDEF_IFLAG; 107334832Speter pp->sp_iin.c_oflag = TTYDEF_OFLAG; 107434832Speter pp->sp_iin.c_cflag = TTYDEF_CFLAG; 107534832Speter pp->sp_iin.c_lflag = TTYDEF_LFLAG; 107634832Speter termioschars(&pp->sp_iin); 107734832Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 107834832Speter TTYDEF_SPEED;; 107934832Speter pp->sp_iout = pp->sp_iin; 108034832Speter } 108134832Spetertry_next2: 108210015Speter if (modp->sm_next == 0) { 108334832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 108410015Speter unit, 108510015Speter sc->sc_typename, 108610015Speter sc->sc_nport, 108712174Speter nmodule, 108834832Speter uart_type, 108934832Speter si_modulename(sc->sc_type, uart_type)); 109010015Speter break; 109110015Speter } 109210015Speter modp = (struct si_module *) 109310015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 109410015Speter } 109510015Speter if (done_chartimes == 0) { 109610015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 109710015Speter if ((spt->sp_code /= hz) == 0) 109810015Speter spt->sp_code = 1; 109910015Speter } 110010015Speter done_chartimes = 1; 110110015Speter } 110212502Sjulian 110312675Sjulian#ifdef DEVFS 110412675Sjulian/* path name devsw minor type uid gid perm*/ 110513169Speter for ( x = 0; x < sc->sc_nport; x++ ) { 110634735Speter /* sync with the manuals that start at 1 */ 110734735Speter y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT); 110834735Speter sc->devfs_token[x].ttya = devfs_add_devswf( 110913630Sphk &si_cdevsw, x, 111013630Sphk DV_CHR, 0, 0, 0600, "ttyA%02d", y); 111113630Sphk sc->devfs_token[x].cuaa = devfs_add_devswf( 111234735Speter &si_cdevsw, x + 0x00080, 111313630Sphk DV_CHR, 0, 0, 0600, "cuaA%02d", y); 111413630Sphk sc->devfs_token[x].ttyi = devfs_add_devswf( 111513630Sphk &si_cdevsw, x + 0x10000, 111613630Sphk DV_CHR, 0, 0, 0600, "ttyiA%02d", y); 111734735Speter sc->devfs_token[x].cuai = devfs_add_devswf( 111834735Speter &si_cdevsw, x + 0x10080, 111934735Speter DV_CHR, 0, 0, 0600, "cuaiA%02d", y); 112013630Sphk sc->devfs_token[x].ttyl = devfs_add_devswf( 112113630Sphk &si_cdevsw, x + 0x20000, 112213630Sphk DV_CHR, 0, 0, 0600, "ttylA%02d", y); 112334735Speter sc->devfs_token[x].cual = devfs_add_devswf( 112434735Speter &si_cdevsw, x + 0x20080, 112534735Speter DV_CHR, 0, 0, 0600, "cualA%02d", y); 112612675Sjulian } 112714873Sscrappy sc->control_token = 112814873Sscrappy devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600, 112914873Sscrappy "si_control"); 113012675Sjulian#endif 113110015Speter return (1); 113210015Speter} 113310015Speter 113412675Sjulianstatic int 113510015Spetersiopen(dev, flag, mode, p) 113610015Speter dev_t dev; 113710015Speter int flag, mode; 113810015Speter struct proc *p; 113910015Speter{ 114010015Speter int oldspl, error; 114110015Speter int card, port; 114210015Speter register struct si_softc *sc; 114310015Speter register struct tty *tp; 114410015Speter volatile struct si_channel *ccbp; 114510015Speter struct si_port *pp; 114610015Speter int mynor = minor(dev); 114710015Speter 114810015Speter /* quickly let in /dev/si_control */ 114910015Speter if (IS_CONTROLDEV(mynor)) { 115046112Sphk if ((error = suser(p))) 115110015Speter return(error); 115210015Speter return(0); 115310015Speter } 115410015Speter 115510015Speter card = SI_CARD(mynor); 115610015Speter if (card >= NSI) 115710015Speter return (ENXIO); 115810015Speter sc = &si_softc[card]; 115910015Speter 116012174Speter if (sc->sc_type == SIEMPTY) { 116112174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 116210015Speter card, sc->sc_typename)); 116310015Speter return(ENXIO); 116410015Speter } 116510015Speter 116610015Speter port = SI_PORT(mynor); 116710015Speter if (port >= sc->sc_nport) { 116812174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 116910015Speter card, sc->sc_nport)); 117010015Speter return(ENXIO); 117110015Speter } 117210015Speter 117310015Speter#ifdef POLL 117410015Speter /* 117510015Speter * We've now got a device, so start the poller. 117610015Speter */ 117710015Speter if (init_finished == 0) { 117815639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 117910015Speter init_finished = 1; 118010015Speter } 118110015Speter#endif 118210015Speter 118310015Speter /* initial/lock device */ 118410015Speter if (IS_STATE(mynor)) { 118510015Speter return(0); 118610015Speter } 118710015Speter 118810015Speter pp = sc->sc_ports + port; 118910015Speter tp = pp->sp_tty; /* the "real" tty */ 119010015Speter ccbp = pp->sp_ccb; /* Find control block */ 119150016Snsayer DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%s,%x,%x,%x)\n", 119250016Snsayer devtoname(dev), flag, mode, p)); 119310015Speter 119410015Speter oldspl = spltty(); /* Keep others out */ 119510015Speter error = 0; 119610015Speter 119710015Speteropen_top: 119810015Speter while (pp->sp_state & SS_DTR_OFF) { 119910015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 120010015Speter if (error != 0) 120110015Speter goto out; 120210015Speter } 120310015Speter 120410015Speter if (tp->t_state & TS_ISOPEN) { 120510015Speter /* 120610015Speter * The device is open, so everything has been initialised. 120710015Speter * handle conflicts. 120810015Speter */ 120910015Speter if (IS_CALLOUT(mynor)) { 121010015Speter if (!pp->sp_active_out) { 121110015Speter error = EBUSY; 121210015Speter goto out; 121310015Speter } 121410015Speter } else { 121510015Speter if (pp->sp_active_out) { 121610015Speter if (flag & O_NONBLOCK) { 121710015Speter error = EBUSY; 121810015Speter goto out; 121910015Speter } 122010015Speter error = tsleep(&pp->sp_active_out, 122110015Speter TTIPRI|PCATCH, "sibi", 0); 122210015Speter if (error != 0) 122310015Speter goto out; 122410015Speter goto open_top; 122510015Speter } 122610015Speter } 122743425Sphk if (tp->t_state & TS_XCLUDE && 122846112Sphk suser(p)) { 122910015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 123010015Speter "already open and EXCLUSIVE set\n")); 123110015Speter error = EBUSY; 123210015Speter goto out; 123310015Speter } 123410015Speter } else { 123510015Speter /* 123610015Speter * The device isn't open, so there are no conflicts. 123710015Speter * Initialize it. Avoid sleep... :-) 123810015Speter */ 123910015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 124010015Speter tp->t_oproc = si_start; 124110015Speter tp->t_param = siparam; 124210015Speter tp->t_dev = dev; 124310015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 124410015Speter ? pp->sp_iout : pp->sp_iin; 124510015Speter 124610015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 124710015Speter 124810015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 124910015Speter 125010015Speter error = siparam(tp, &tp->t_termios); 125110015Speter 125210015Speter --pp->sp_wopeners; 125310015Speter if (error != 0) 125410015Speter goto out; 125510015Speter /* XXX: we should goto_top if siparam slept */ 125610015Speter 125710015Speter /* set initial DCD state */ 125810015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 125910015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 126010015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 126110015Speter } 126210015Speter } 126310015Speter 126410015Speter /* whoops! we beat the close! */ 126510015Speter if (pp->sp_state & SS_CLOSING) { 126610015Speter /* try and stop it from proceeding to bash the hardware */ 126710015Speter pp->sp_state &= ~SS_CLOSING; 126810015Speter } 126910015Speter 127010015Speter /* 127110015Speter * Wait for DCD if necessary 127210015Speter */ 127310015Speter if (!(tp->t_state & TS_CARR_ON) 127410015Speter && !IS_CALLOUT(mynor) 127510015Speter && !(tp->t_cflag & CLOCAL) 127610015Speter && !(flag & O_NONBLOCK)) { 127710015Speter ++pp->sp_wopeners; 127810015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 127910015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 128010015Speter --pp->sp_wopeners; 128110015Speter if (error != 0) 128210015Speter goto out; 128310015Speter goto open_top; 128410015Speter } 128510015Speter 128610015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 128710015Speter si_disc_optim(tp, &tp->t_termios, pp); 128810015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 128910015Speter pp->sp_active_out = TRUE; 129010015Speter 129110015Speter pp->sp_state |= SS_OPEN; /* made it! */ 129210015Speter 129310015Speterout: 129410015Speter splx(oldspl); 129510015Speter 129610015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 129710015Speter 129810015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 129910015Speter sihardclose(pp); 130010015Speter 130110015Speter return(error); 130210015Speter} 130310015Speter 130412675Sjulianstatic int 130510015Spetersiclose(dev, flag, mode, p) 130610015Speter dev_t dev; 130710015Speter int flag, mode; 130810015Speter struct proc *p; 130910015Speter{ 131010015Speter register struct si_port *pp; 131110015Speter register struct tty *tp; 131210015Speter int oldspl; 131310015Speter int error = 0; 131410015Speter int mynor = minor(dev); 131510015Speter 131610015Speter if (IS_SPECIAL(mynor)) 131710015Speter return(0); 131810015Speter 131910015Speter oldspl = spltty(); 132010015Speter 132110015Speter pp = MINOR2PP(mynor); 132210015Speter tp = pp->sp_tty; 132310015Speter 132450016Snsayer DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%s,%x,%x,%x) sp_state:%x\n", 132550016Snsayer devtoname(dev), flag, mode, p, pp->sp_state)); 132610015Speter 132710015Speter /* did we sleep and loose a race? */ 132810015Speter if (pp->sp_state & SS_CLOSING) { 132910015Speter /* error = ESOMETING? */ 133010015Speter goto out; 133110015Speter } 133210015Speter 133310015Speter /* begin race detection.. */ 133410015Speter pp->sp_state |= SS_CLOSING; 133510015Speter 133610015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 133710015Speter 133810015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 133910015Speter (*linesw[tp->t_line].l_close)(tp, flag); 134010015Speter 134110015Speter si_write_enable(pp, 1); 134210015Speter 134310015Speter /* did we sleep and somebody started another open? */ 134410015Speter if (!(pp->sp_state & SS_CLOSING)) { 134510015Speter /* error = ESOMETING? */ 134610015Speter goto out; 134710015Speter } 134810015Speter /* ok. we are now still on the right track.. nuke the hardware */ 134910015Speter 135010015Speter if (pp->sp_state & SS_LSTART) { 135129677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 135210015Speter pp->sp_state &= ~SS_LSTART; 135310015Speter } 135410015Speter 135510015Speter sistop(tp, FREAD | FWRITE); 135610015Speter 135710015Speter sihardclose(pp); 135810015Speter ttyclose(tp); 135910015Speter pp->sp_state &= ~SS_OPEN; 136010015Speter 136110015Speterout: 136210015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 136310015Speter splx(oldspl); 136410015Speter return(error); 136510015Speter} 136610015Speter 136710015Speterstatic void 136810015Spetersihardclose(pp) 136910015Speter struct si_port *pp; 137010015Speter{ 137110015Speter int oldspl; 137210015Speter struct tty *tp; 137310015Speter volatile struct si_channel *ccbp; 137410015Speter 137510015Speter oldspl = spltty(); 137610015Speter 137710015Speter tp = pp->sp_tty; 137810015Speter ccbp = pp->sp_ccb; /* Find control block */ 137910015Speter if (tp->t_cflag & HUPCL 138018515Speter || (!pp->sp_active_out 138134832Speter && !(ccbp->hi_ip & IP_DCD) 138234832Speter && !(pp->sp_iin.c_cflag && CLOCAL)) 138310015Speter || !(tp->t_state & TS_ISOPEN)) { 138410015Speter 138510015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 138610015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 138710015Speter 138810015Speter if (pp->sp_dtr_wait != 0) { 138910015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 139010015Speter pp->sp_state |= SS_DTR_OFF; 139110015Speter } 139210015Speter 139310015Speter } 139410015Speter pp->sp_active_out = FALSE; 139510015Speter wakeup((caddr_t)&pp->sp_active_out); 139610015Speter wakeup(TSA_CARR_ON(tp)); 139710015Speter 139810015Speter splx(oldspl); 139910015Speter} 140010015Speter 140110015Speter 140210015Speter/* 140310015Speter * called at splsoftclock()... 140410015Speter */ 140510015Speterstatic void 140610015Spetersidtrwakeup(chan) 140710015Speter void *chan; 140810015Speter{ 140910015Speter struct si_port *pp; 141010015Speter int oldspl; 141110015Speter 141210015Speter oldspl = spltty(); 141310015Speter 141410015Speter pp = (struct si_port *)chan; 141510015Speter pp->sp_state &= ~SS_DTR_OFF; 141610015Speter wakeup(&pp->sp_dtr_wait); 141710015Speter 141810015Speter splx(oldspl); 141910015Speter} 142010015Speter 142110015Speter/* 142210015Speter * User level stuff - read and write 142310015Speter */ 142412675Sjulianstatic int 142510015Spetersiread(dev, uio, flag) 142610015Speter register dev_t dev; 142710015Speter struct uio *uio; 142810015Speter int flag; 142910015Speter{ 143010015Speter register struct tty *tp; 143110015Speter int mynor = minor(dev); 143210015Speter 143310015Speter if (IS_SPECIAL(mynor)) { 143410015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); 143510015Speter return(ENODEV); 143610015Speter } 143710015Speter tp = MINOR2TP(mynor); 143810015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, 143950016Snsayer "siread(%s,%x,%x)\n", devtoname(dev), uio, flag)); 144010015Speter return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 144110015Speter} 144210015Speter 144310015Speter 144412675Sjulianstatic int 144510015Spetersiwrite(dev, uio, flag) 144610015Speter dev_t dev; 144710015Speter struct uio *uio; 144810015Speter int flag; 144910015Speter{ 145010015Speter register struct si_port *pp; 145110015Speter register struct tty *tp; 145210015Speter int error = 0; 145310015Speter int mynor = minor(dev); 145410015Speter int oldspl; 145510015Speter 145610015Speter if (IS_SPECIAL(mynor)) { 145710015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 145810015Speter return(ENODEV); 145910015Speter } 146010015Speter pp = MINOR2PP(mynor); 146110015Speter tp = pp->sp_tty; 146250016Snsayer DPRINT((pp, DBG_WRITE, "siwrite(%s,%x,%x)\n", devtoname(dev), uio, flag)); 146310015Speter 146410015Speter oldspl = spltty(); 146510015Speter /* 146610015Speter * If writes are currently blocked, wait on the "real" tty 146710015Speter */ 146810015Speter while (pp->sp_state & SS_BLOCKWRITE) { 146910015Speter pp->sp_state |= SS_WAITWRITE; 147010015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 147118515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 147218515Speter "siwrite", tp->t_timeout))) { 147317291Speter if (error == EWOULDBLOCK) 147417290Speter error = EIO; 147510015Speter goto out; 147617290Speter } 147710015Speter } 147810015Speter 147910015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 148010015Speterout: 148110015Speter splx(oldspl); 148210015Speter return (error); 148310015Speter} 148410015Speter 148510015Speter 148612675Sjulianstatic struct tty * 148710015Spetersidevtotty(dev_t dev) 148810015Speter{ 148910015Speter struct si_port *pp; 149010015Speter int mynor = minor(dev); 149110015Speter struct si_softc *sc = &si_softc[SI_CARD(mynor)]; 149210015Speter 149310015Speter if (IS_SPECIAL(mynor)) 149410015Speter return(NULL); 149510015Speter if (SI_PORT(mynor) >= sc->sc_nport) 149610015Speter return(NULL); 149710015Speter pp = MINOR2PP(mynor); 149810015Speter return (pp->sp_tty); 149910015Speter} 150010015Speter 150112675Sjulianstatic int 150210015Spetersiioctl(dev, cmd, data, flag, p) 150310015Speter dev_t dev; 150436735Sdfr u_long cmd; 150510015Speter caddr_t data; 150610015Speter int flag; 150710015Speter struct proc *p; 150810015Speter{ 150910015Speter struct si_port *pp; 151010015Speter register struct tty *tp; 151110015Speter int error; 151210015Speter int mynor = minor(dev); 151310015Speter int oldspl; 151410015Speter int blocked = 0; 151510015Speter#if defined(COMPAT_43) 151638351Sbde u_long oldcmd; 151710015Speter struct termios term; 151810015Speter#endif 151910015Speter 152010015Speter if (IS_SI_IOCTL(cmd)) 152110015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 152210015Speter 152310015Speter pp = MINOR2PP(mynor); 152410015Speter tp = pp->sp_tty; 152510015Speter 152650016Snsayer DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%s,%lx,%x,%x)\n", 152750016Snsayer devtoname(dev), cmd, data, flag)); 152810015Speter if (IS_STATE(mynor)) { 152910015Speter struct termios *ct; 153010015Speter 153110015Speter switch (mynor & SI_STATE_MASK) { 153210015Speter case SI_INIT_STATE_MASK: 153310015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 153410015Speter break; 153510015Speter case SI_LOCK_STATE_MASK: 153616839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 153710015Speter break; 153810015Speter default: 153910015Speter return (ENODEV); 154010015Speter } 154110015Speter switch (cmd) { 154210015Speter case TIOCSETA: 154346112Sphk error = suser(p); 154410015Speter if (error != 0) 154510015Speter return (error); 154610015Speter *ct = *(struct termios *)data; 154710015Speter return (0); 154810015Speter case TIOCGETA: 154910015Speter *(struct termios *)data = *ct; 155010015Speter return (0); 155110015Speter case TIOCGETD: 155210015Speter *(int *)data = TTYDISC; 155310015Speter return (0); 155410015Speter case TIOCGWINSZ: 155510015Speter bzero(data, sizeof(struct winsize)); 155610015Speter return (0); 155710015Speter default: 155810015Speter return (ENOTTY); 155910015Speter } 156010015Speter } 156110015Speter /* 156210015Speter * Do the old-style ioctl compat routines... 156310015Speter */ 156410015Speter#if defined(COMPAT_43) 156510015Speter term = tp->t_termios; 156610015Speter oldcmd = cmd; 156710015Speter error = ttsetcompat(tp, &cmd, data, &term); 156810015Speter if (error != 0) 156910015Speter return (error); 157010015Speter if (cmd != oldcmd) 157110015Speter data = (caddr_t)&term; 157210015Speter#endif 157310015Speter /* 157410015Speter * Do the initial / lock state business 157510015Speter */ 157610015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 157710015Speter int cc; 157810015Speter struct termios *dt = (struct termios *)data; 157910015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 158010015Speter ? &pp->sp_lout : &pp->sp_lin; 158110015Speter 158210015Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) 158310015Speter | (dt->c_iflag & ~lt->c_iflag); 158410015Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) 158510015Speter | (dt->c_oflag & ~lt->c_oflag); 158610015Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) 158710015Speter | (dt->c_cflag & ~lt->c_cflag); 158810015Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) 158910015Speter | (dt->c_lflag & ~lt->c_lflag); 159010015Speter for (cc = 0; cc < NCCS; ++cc) 159110015Speter if (lt->c_cc[cc] != 0) 159210015Speter dt->c_cc[cc] = tp->t_cc[cc]; 159310015Speter if (lt->c_ispeed != 0) 159410015Speter dt->c_ispeed = tp->t_ispeed; 159510015Speter if (lt->c_ospeed != 0) 159610015Speter dt->c_ospeed = tp->t_ospeed; 159710015Speter } 159810015Speter 159910015Speter /* 160010015Speter * Block user-level writes to give the ttywait() 160110015Speter * a chance to completely drain for commands 160210015Speter * that require the port to be in a quiescent state. 160310015Speter */ 160410015Speter switch (cmd) { 160534832Speter case TIOCSETAW: 160634832Speter case TIOCSETAF: 160717396Speter case TIOCDRAIN: 160817396Speter#ifdef COMPAT_43 160917396Speter case TIOCSETP: 161017396Speter#endif 161110015Speter blocked++; /* block writes for ttywait() and siparam() */ 161210015Speter si_write_enable(pp, 0); 161310015Speter } 161410015Speter 161510015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 161631577Sbde if (error != ENOIOCTL) 161710015Speter goto out; 161810015Speter 161910015Speter oldspl = spltty(); 162010015Speter 162110015Speter error = ttioctl(tp, cmd, data, flag); 162210015Speter si_disc_optim(tp, &tp->t_termios, pp); 162331577Sbde if (error != ENOIOCTL) 162410015Speter goto outspl; 162510015Speter 162610015Speter switch (cmd) { 162710015Speter case TIOCSBRK: 162816575Speter si_command(pp, SBREAK, SI_WAIT); 162910015Speter break; 163010015Speter case TIOCCBRK: 163116575Speter si_command(pp, EBREAK, SI_WAIT); 163210015Speter break; 163310015Speter case TIOCSDTR: 163410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 163510015Speter break; 163610015Speter case TIOCCDTR: 163710015Speter (void) si_modem(pp, SET, 0); 163810015Speter break; 163910015Speter case TIOCMSET: 164010015Speter (void) si_modem(pp, SET, *(int *)data); 164110015Speter break; 164210015Speter case TIOCMBIS: 164310015Speter (void) si_modem(pp, BIS, *(int *)data); 164410015Speter break; 164510015Speter case TIOCMBIC: 164610015Speter (void) si_modem(pp, BIC, *(int *)data); 164710015Speter break; 164810015Speter case TIOCMGET: 164910015Speter *(int *)data = si_modem(pp, GET, 0); 165010015Speter break; 165110015Speter case TIOCMSDTRWAIT: 165210015Speter /* must be root since the wait applies to following logins */ 165346112Sphk error = suser(p); 165410015Speter if (error != 0) { 165510015Speter goto outspl; 165610015Speter } 165710015Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 165810015Speter break; 165910015Speter case TIOCMGDTRWAIT: 166010015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 166110015Speter break; 166210015Speter 166310015Speter default: 166410015Speter error = ENOTTY; 166510015Speter } 166610015Speter error = 0; 166710015Speteroutspl: 166810015Speter splx(oldspl); 166910015Speterout: 167010015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 167110015Speter if (blocked) 167210015Speter si_write_enable(pp, 1); 167310015Speter return(error); 167410015Speter} 167510015Speter 167610015Speter/* 167710015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 167810015Speter */ 167910015Speterstatic int 168038351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 168110015Speter{ 168210015Speter struct si_softc *xsc; 168310015Speter register struct si_port *xpp; 168410015Speter volatile struct si_reg *regp; 168510015Speter struct si_tcsi *dp; 168610044Speter struct si_pstat *sps; 168711872Sphk int *ip, error = 0; 168810015Speter int oldspl; 168910015Speter int card, port; 169010015Speter int mynor = minor(dev); 169110015Speter 169250016Snsayer DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n", 169350016Snsayer devtoname(dev), cmd, data, flag)); 169410015Speter 169510044Speter#if 1 169610044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 169710044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 169810044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 169910044Speter#endif 170010044Speter 170110015Speter if (!IS_CONTROLDEV(mynor)) { 170210015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 170310015Speter return(ENODEV); 170410015Speter } 170510015Speter 170610015Speter oldspl = spltty(); /* better safe than sorry */ 170710015Speter 170810015Speter ip = (int *)data; 170910015Speter 171046112Sphk#define SUCHECK if ((error = suser(p))) goto out 171110015Speter 171210015Speter switch (cmd) { 171310015Speter case TCSIPORTS: 171410015Speter *ip = si_Nports; 171510015Speter goto out; 171610015Speter case TCSIMODULES: 171710015Speter *ip = si_Nmodules; 171810015Speter goto out; 171910015Speter case TCSISDBG_ALL: 172010015Speter SUCHECK; 172110015Speter si_debug = *ip; 172210015Speter goto out; 172310015Speter case TCSIGDBG_ALL: 172410015Speter *ip = si_debug; 172510015Speter goto out; 172610015Speter default: 172710015Speter /* 172810015Speter * Check that a controller for this port exists 172910015Speter */ 173010044Speter 173110044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 173210044Speter 173310015Speter dp = (struct si_tcsi *)data; 173410044Speter sps = (struct si_pstat *)data; 173510015Speter card = dp->tc_card; 173610015Speter xsc = &si_softc[card]; /* check.. */ 173712174Speter if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) { 173810015Speter error = ENOENT; 173910015Speter goto out; 174010015Speter } 174110015Speter /* 174210015Speter * And check that a port exists 174310015Speter */ 174410015Speter port = dp->tc_port; 174510015Speter if (port < 0 || port >= xsc->sc_nport) { 174610015Speter error = ENOENT; 174710015Speter goto out; 174810015Speter } 174910015Speter xpp = xsc->sc_ports + port; 175010015Speter regp = (struct si_reg *)xsc->sc_maddr; 175110015Speter } 175210015Speter 175310015Speter switch (cmd) { 175410015Speter case TCSIDEBUG: 175510015Speter#ifdef SI_DEBUG 175610015Speter SUCHECK; 175710015Speter if (xpp->sp_debug) 175810015Speter xpp->sp_debug = 0; 175910015Speter else { 176010015Speter xpp->sp_debug = DBG_ALL; 176110015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 176210015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 176310015Speter } 176410015Speter break; 176510015Speter#else 176610015Speter error = ENODEV; 176710015Speter goto out; 176810015Speter#endif 176910015Speter case TCSISDBG_LEVEL: 177010015Speter case TCSIGDBG_LEVEL: 177110015Speter#ifdef SI_DEBUG 177210015Speter if (cmd == TCSIGDBG_LEVEL) { 177310015Speter dp->tc_dbglvl = xpp->sp_debug; 177410015Speter } else { 177510015Speter SUCHECK; 177610015Speter xpp->sp_debug = dp->tc_dbglvl; 177710015Speter } 177810015Speter break; 177910015Speter#else 178010015Speter error = ENODEV; 178110015Speter goto out; 178210015Speter#endif 178310015Speter case TCSIGRXIT: 178410015Speter dp->tc_int = regp->rx_int_count; 178510015Speter break; 178610015Speter case TCSIRXIT: 178710015Speter SUCHECK; 178810015Speter regp->rx_int_count = dp->tc_int; 178910015Speter break; 179010015Speter case TCSIGIT: 179110015Speter dp->tc_int = regp->int_count; 179210015Speter break; 179310015Speter case TCSIIT: 179410015Speter SUCHECK; 179510015Speter regp->int_count = dp->tc_int; 179610015Speter break; 179710044Speter case TCSISTATE: 179810044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 179910015Speter break; 180010044Speter /* these next three use a different structure */ 180110044Speter case TCSI_PORT: 180210015Speter SUCHECK; 180334832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 180410015Speter break; 180510044Speter case TCSI_CCB: 180610044Speter SUCHECK; 180734832Speter si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 180810015Speter break; 180910044Speter case TCSI_TTY: 181010044Speter SUCHECK; 181134832Speter si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 181210015Speter break; 181310015Speter default: 181410015Speter error = EINVAL; 181510015Speter goto out; 181610015Speter } 181710015Speterout: 181810015Speter splx(oldspl); 181910015Speter return(error); /* success */ 182010015Speter} 182110015Speter 182210015Speter/* 182310015Speter * siparam() : Configure line params 182410015Speter * called at spltty(); 182510015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 182610015Speter * caller must arrange this if it's important.. 182710015Speter */ 182812724Sphkstatic int 182910015Spetersiparam(tp, t) 183010015Speter register struct tty *tp; 183110015Speter register struct termios *t; 183210015Speter{ 183310015Speter register struct si_port *pp = TP2PP(tp); 183410015Speter volatile struct si_channel *ccbp; 183510015Speter int oldspl, cflag, iflag, oflag, lflag; 183610015Speter int error = 0; /* shutup gcc */ 183710015Speter int ispeed = 0; /* shutup gcc */ 183810015Speter int ospeed = 0; /* shutup gcc */ 183910161Speter BYTE val; 184010015Speter 184110015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 184210015Speter cflag = t->c_cflag; 184310015Speter iflag = t->c_iflag; 184410015Speter oflag = t->c_oflag; 184510015Speter lflag = t->c_lflag; 184610044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 184710044Speter oflag, cflag, iflag, lflag)); 184810015Speter 184934832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 185010015Speter 185110015Speter /* if not hung up.. */ 185210015Speter if (t->c_ospeed != 0) { 185310015Speter /* translate baud rate to firmware values */ 185410015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 185510015Speter ispeed = t->c_ispeed ? 185610015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 185710015Speter 185810015Speter /* enforce legit baud rate */ 185910015Speter if (ospeed < 0 || ispeed < 0) 186010015Speter return (EINVAL); 186110015Speter } 186210015Speter 186310015Speter oldspl = spltty(); 186410015Speter 186510015Speter ccbp = pp->sp_ccb; 186610015Speter 186710161Speter /* ========== set hi_break ========== */ 186810161Speter val = 0; 186910161Speter if (iflag & IGNBRK) /* Breaks */ 187010161Speter val |= BR_IGN; 187110161Speter if (iflag & BRKINT) /* Interrupt on break? */ 187210161Speter val |= BR_INT; 187310161Speter if (iflag & PARMRK) /* Parity mark? */ 187410161Speter val |= BR_PARMRK; 187510161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 187610161Speter val |= BR_PARIGN; 187710161Speter ccbp->hi_break = val; 187810161Speter 187910161Speter /* ========== set hi_csr ========== */ 188010015Speter /* if not hung up.. */ 188110015Speter if (t->c_ospeed != 0) { 188210015Speter /* Set I/O speeds */ 188310161Speter val = (ispeed << 4) | ospeed; 188410015Speter } 188510161Speter ccbp->hi_csr = val; 188610015Speter 188710161Speter /* ========== set hi_mr2 ========== */ 188810161Speter val = 0; 188910015Speter if (cflag & CSTOPB) /* Stop bits */ 189010161Speter val |= MR2_2_STOP; 189110015Speter else 189210161Speter val |= MR2_1_STOP; 189310161Speter /* 189410161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 189510161Speter * a DCE, hence the reverse sense of RTS and CTS 189610161Speter */ 189710161Speter /* Output Flow - RTS must be raised before data can be sent */ 189810161Speter if (cflag & CCTS_OFLOW) 189910161Speter val |= MR2_RTSCONT; 190010161Speter 190116575Speter ccbp->hi_mr2 = val; 190210161Speter 190310161Speter /* ========== set hi_mr1 ========== */ 190410161Speter val = 0; 190510015Speter if (!(cflag & PARENB)) /* Parity */ 190610161Speter val |= MR1_NONE; 190710015Speter else 190810161Speter val |= MR1_WITH; 190910015Speter if (cflag & PARODD) 191010161Speter val |= MR1_ODD; 191110015Speter 191210015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 191310161Speter val |= MR1_8_BITS; 191410015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 191510161Speter val |= MR1_7_BITS; 191610015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 191710161Speter val |= MR1_6_BITS; 191810015Speter } else { /* Must be 5 */ 191910161Speter val |= MR1_5_BITS; 192010015Speter } 192110161Speter /* 192210161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 192310161Speter * a DCE, hence the reverse sense of RTS and CTS 192410161Speter */ 192510161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 192610161Speter if (cflag & CRTS_IFLOW) 192710161Speter val |= MR1_CTSCONT; 192810015Speter 192910161Speter ccbp->hi_mr1 = val; 193010161Speter 193110161Speter /* ========== set hi_mask ========== */ 193210161Speter val = 0xff; 193310161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 193410161Speter val &= 0xFF; 193510161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 193610161Speter val &= 0x7F; 193710161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 193810161Speter val &= 0x3F; 193910161Speter } else { /* Must be 5 */ 194010161Speter val &= 0x1F; 194110161Speter } 194210015Speter if (iflag & ISTRIP) 194310161Speter val &= 0x7F; 194410015Speter 194510161Speter ccbp->hi_mask = val; 194610161Speter 194710161Speter /* ========== set hi_prtcl ========== */ 194810161Speter val = 0; 194910015Speter /* Monitor DCD etc. if a modem */ 195010015Speter if (!(cflag & CLOCAL)) 195110161Speter val |= SP_DCEN; 195210161Speter if (iflag & IXANY) 195310161Speter val |= SP_TANY; 195410161Speter if (iflag & IXON) 195510161Speter val |= SP_TXEN; 195610161Speter if (iflag & IXOFF) 195710161Speter val |= SP_RXEN; 195810161Speter if (iflag & INPCK) 195910161Speter val |= SP_PAEN; 196010015Speter 196110161Speter ccbp->hi_prtcl = val; 196210161Speter 196310161Speter 196410161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 196510161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 196610015Speter ccbp->hi_txon = t->c_cc[VSTART]; 196710015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 196810015Speter 196910015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 197010015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 197110015Speter 197210161Speter /* ========== send settings to the card ========== */ 197310015Speter /* potential sleep here */ 197410015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 197510015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 197610015Speter else 197710015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 197810015Speter 197910161Speter /* ========== set DTR etc ========== */ 198010015Speter /* Hangup if ospeed == 0 */ 198110015Speter if (t->c_ospeed == 0) { 198210015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 198310015Speter } else { 198410015Speter /* 198510015Speter * If the previous speed was 0, may need to re-enable 198634832Speter * the modem signals 198734832Speter */ 198810015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 198910015Speter } 199010015Speter 199110044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 199210044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 199310015Speter 199410015Speter splx(oldspl); 199510015Speter return(error); 199610015Speter} 199710015Speter 199810015Speter/* 199910015Speter * Enable or Disable the writes to this channel... 200010015Speter * "state" -> enabled = 1; disabled = 0; 200110015Speter */ 200210015Speterstatic void 200310015Spetersi_write_enable(pp, state) 200410015Speter register struct si_port *pp; 200510015Speter int state; 200610015Speter{ 200710015Speter int oldspl; 200810015Speter 200910015Speter oldspl = spltty(); 201010015Speter 201110015Speter if (state) { 201210015Speter pp->sp_state &= ~SS_BLOCKWRITE; 201310015Speter if (pp->sp_state & SS_WAITWRITE) { 201410015Speter pp->sp_state &= ~SS_WAITWRITE; 201510015Speter /* thunder away! */ 201610015Speter wakeup((caddr_t)pp); 201710015Speter } 201810015Speter } else { 201910015Speter pp->sp_state |= SS_BLOCKWRITE; 202010015Speter } 202110015Speter 202210015Speter splx(oldspl); 202310015Speter} 202410015Speter 202510015Speter/* 202610015Speter * Set/Get state of modem control lines. 202710015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 202810015Speter * TIOCM_DTR DSR 202910015Speter * TIOCM_RTS CTS 203010015Speter */ 203110015Speterstatic int 203210015Spetersi_modem(pp, cmd, bits) 203310015Speter struct si_port *pp; 203410015Speter enum si_mctl cmd; 203510015Speter int bits; 203610015Speter{ 203710015Speter volatile struct si_channel *ccbp; 203810015Speter int x; 203910015Speter 204010015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 204110015Speter ccbp = pp->sp_ccb; /* Find channel address */ 204210015Speter switch (cmd) { 204310015Speter case GET: 204410015Speter x = ccbp->hi_ip; 204510015Speter bits = TIOCM_LE; 204610015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 204710015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 204810015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 204910015Speter if (x & IP_RI) bits |= TIOCM_RI; 205010015Speter return(bits); 205110015Speter case SET: 205210015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 205310015Speter /* fall through */ 205410015Speter case BIS: 205510015Speter x = 0; 205610015Speter if (bits & TIOCM_DTR) 205710015Speter x |= OP_DSR; 205810015Speter if (bits & TIOCM_RTS) 205910015Speter x |= OP_CTS; 206010015Speter ccbp->hi_op |= x; 206110015Speter break; 206210015Speter case BIC: 206310015Speter if (bits & TIOCM_DTR) 206410015Speter ccbp->hi_op &= ~OP_DSR; 206510015Speter if (bits & TIOCM_RTS) 206610015Speter ccbp->hi_op &= ~OP_CTS; 206710015Speter } 206810015Speter return 0; 206910015Speter} 207010015Speter 207110015Speter/* 207210015Speter * Handle change of modem state 207310015Speter */ 207410015Speterstatic void 207510015Spetersi_modem_state(pp, tp, hi_ip) 207610015Speter register struct si_port *pp; 207710015Speter register struct tty *tp; 207810015Speter register int hi_ip; 207910015Speter{ 208010015Speter /* if a modem dev */ 208110015Speter if (hi_ip & IP_DCD) { 208210015Speter if ( !(pp->sp_last_hi_ip & IP_DCD)) { 208310015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 208410015Speter tp->t_line)); 208510015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 208610015Speter } 208710015Speter } else { 208810015Speter if (pp->sp_last_hi_ip & IP_DCD) { 208910015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 209010015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 209110015Speter (void) si_modem(pp, SET, 0); 209210015Speter } 209310015Speter } 209410015Speter pp->sp_last_hi_ip = hi_ip; 209510015Speter 209610015Speter} 209710015Speter 209810015Speter/* 209910015Speter * Poller to catch missed interrupts. 210012174Speter * 210112496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 210212496Speter * better response. We could really use a "periodic" version timeout(). :-) 210310015Speter */ 210410015Speter#ifdef POLL 210510708Speterstatic void 210610015Spetersi_poll(void *nothing) 210710015Speter{ 210810015Speter register struct si_softc *sc; 210910015Speter register int i; 211010015Speter volatile struct si_reg *regp; 211112174Speter register struct si_port *pp; 211212174Speter int lost, oldspl, port; 211310015Speter 211410015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 211511609Speter oldspl = spltty(); 211610015Speter if (in_intr) 211710015Speter goto out; 211810015Speter lost = 0; 211910015Speter for (i=0; i<NSI; i++) { 212010015Speter sc = &si_softc[i]; 212112174Speter if (sc->sc_type == SIEMPTY) 212210015Speter continue; 212310015Speter regp = (struct si_reg *)sc->sc_maddr; 212434832Speter 212510015Speter /* 212610015Speter * See if there has been a pending interrupt for 2 seconds 212733395Speter * or so. The test (int_scounter >= 200) won't correspond 212810015Speter * to 2 seconds if int_count gets changed. 212910015Speter */ 213010015Speter if (regp->int_pending != 0) { 213110015Speter if (regp->int_scounter >= 200 && 213210015Speter regp->initstat == 1) { 213312174Speter printf("si%d: lost intr\n", i); 213410015Speter lost++; 213510015Speter } 213610015Speter } else { 213710015Speter regp->int_scounter = 0; 213810015Speter } 213910015Speter 214012174Speter /* 214112174Speter * gripe about no input flow control.. 214212174Speter */ 214312174Speter pp = sc->sc_ports; 214412174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 214512174Speter if (pp->sp_delta_overflows > 0) { 214612174Speter printf("si%d: %d tty level buffer overflows\n", 214712174Speter i, pp->sp_delta_overflows); 214812174Speter pp->sp_delta_overflows = 0; 214912174Speter } 215012174Speter } 215110015Speter } 215217547Speter if (lost || si_realpoll) 215334735Speter si_intr(-1); /* call intr with fake vector */ 215411609Speterout: 215510015Speter splx(oldspl); 215610015Speter 215715639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 215810015Speter} 215910015Speter#endif /* ifdef POLL */ 216010015Speter 216110015Speter/* 216210015Speter * The interrupt handler polls ALL ports on ALL adapters each time 216310015Speter * it is called. 216410015Speter */ 216510015Speter 216612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 216734832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 216810015Speter 216934735Speterstatic void 217034735Spetersi_intr(int unit) 217110015Speter{ 217210015Speter register struct si_softc *sc; 217310015Speter 217410015Speter register struct si_port *pp; 217510015Speter volatile struct si_channel *ccbp; 217610015Speter register struct tty *tp; 217710015Speter volatile caddr_t maddr; 217811872Sphk BYTE op, ip; 217912174Speter int x, card, port, n, i, isopen; 218010015Speter volatile BYTE *z; 218110015Speter BYTE c; 218210015Speter 218334735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit)); 218411609Speter if (in_intr) { 218511609Speter if (unit < 0) /* should never happen */ 218634832Speter printf("si%d: Warning poll entered during interrupt\n", 218734832Speter unit); 218834832Speter else 218934832Speter printf("si%d: Warning interrupt handler re-entered\n", 219034832Speter unit); 219110708Speter return; 219210015Speter } 219310015Speter in_intr = 1; 219410015Speter 219510015Speter /* 219610015Speter * When we get an int we poll all the channels and do ALL pending 219710015Speter * work, not just the first one we find. This allows all cards to 219810015Speter * share the same vector. 219934832Speter * 220034832Speter * XXX - But if we're sharing the vector with something that's NOT 220134832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 220210015Speter */ 220334832Speter for (card = 0; card < NSI; card++) { 220410015Speter sc = &si_softc[card]; 220512174Speter if (sc->sc_type == SIEMPTY) 220610015Speter continue; 220712174Speter 220812174Speter /* 220912174Speter * First, clear the interrupt 221012174Speter */ 221110015Speter switch(sc->sc_type) { 221234832Speter case SIHOST: 221310015Speter maddr = sc->sc_maddr; 221410015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 221510015Speter /* flag nothing pending */ 221610015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 221710015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 221810015Speter break; 221910015Speter case SIHOST2: 222010015Speter maddr = sc->sc_maddr; 222110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 222210015Speter *(maddr+SIPLIRQCLR) = 0x00; 222310015Speter *(maddr+SIPLIRQCLR) = 0x10; 222410015Speter break; 222534832Speter#if NPCI > 0 222633395Speter case SIPCI: 222733395Speter maddr = sc->sc_maddr; 222833395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 222933395Speter *(maddr+SIPCIINTCL) = 0x0; 223033395Speter break; 223134832Speter case SIJETPCI: /* fall through to JETISA case */ 223234832Speter#endif 223333395Speter case SIJETISA: 223433395Speter maddr = sc->sc_maddr; 223533395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 223633395Speter *(maddr+SIJETINTCL) = 0x0; 223733395Speter break; 223834832Speter#if NEISA > 0 223910015Speter case SIEISA: 224010015Speter maddr = sc->sc_maddr; 224110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 224234832Speter (void)inb(sc->sc_eisa_iobase + 3); 224310015Speter break; 224434832Speter#endif 224510015Speter case SIEMPTY: 224610015Speter default: 224710015Speter continue; 224810015Speter } 224910015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 225010015Speter 225112174Speter /* 225212174Speter * check each port 225312174Speter */ 225434832Speter for (pp = sc->sc_ports, port=0; port < sc->sc_nport; 225534832Speter pp++, port++) { 225610015Speter ccbp = pp->sp_ccb; 225710015Speter tp = pp->sp_tty; 225810015Speter 225910015Speter /* 226010015Speter * See if a command has completed ? 226110015Speter */ 226210015Speter if (ccbp->hi_stat != pp->sp_pend) { 226310015Speter DPRINT((pp, DBG_INTR, 226434735Speter "si_intr hi_stat = 0x%x, pend = %d\n", 226510015Speter ccbp->hi_stat, pp->sp_pend)); 226610015Speter switch(pp->sp_pend) { 226710015Speter case LOPEN: 226810015Speter case MPEND: 226910015Speter case MOPEN: 227010015Speter case CONFIG: 227116575Speter case SBREAK: 227216575Speter case EBREAK: 227310015Speter pp->sp_pend = ccbp->hi_stat; 227410015Speter /* sleeping in si_command */ 227510015Speter wakeup(&pp->sp_state); 227610015Speter break; 227710015Speter default: 227810015Speter pp->sp_pend = ccbp->hi_stat; 227910015Speter } 228034832Speter } 228110015Speter 228210015Speter /* 228310015Speter * Continue on if it's closed 228410015Speter */ 228510015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 228610015Speter continue; 228710015Speter } 228810015Speter 228910015Speter /* 229010015Speter * Do modem state change if not a local device 229110015Speter */ 229210015Speter si_modem_state(pp, tp, ccbp->hi_ip); 229310015Speter 229410015Speter /* 229534832Speter * Check to see if we should 'receive' characters. 229612174Speter */ 229712174Speter if (tp->t_state & TS_CONNECTED && 229812174Speter tp->t_state & TS_ISOPEN) 229912174Speter isopen = 1; 230012174Speter else 230112174Speter isopen = 0; 230212174Speter 230312174Speter /* 230416575Speter * Do input break processing 230510015Speter */ 230610015Speter if (ccbp->hi_state & ST_BREAK) { 230712174Speter if (isopen) { 230812174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 230910015Speter } 231010015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 231110015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 231210015Speter } 231310015Speter 231410015Speter /* 231512174Speter * Do RX stuff - if not open then dump any characters. 231612174Speter * XXX: This is VERY messy and needs to be cleaned up. 231712174Speter * 231812174Speter * XXX: can we leave data in the host adapter buffer 231912174Speter * when the clists are full? That may be dangerous 232012174Speter * if the user cannot get an interrupt signal through. 232110015Speter */ 232210015Speter 232312174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 232412174Speter 232512174Speter if (!isopen) { 232610015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 232712174Speter goto end_rx; 232812174Speter } 232910015Speter 233012174Speter /* 233115640Speter * If the tty input buffers are blocked, stop emptying 233215640Speter * the incoming buffers and let the auto flow control 233315640Speter * assert.. 233415640Speter */ 233515640Speter if (tp->t_state & TS_TBLOCK) { 233615640Speter goto end_rx; 233715640Speter } 233815640Speter 233915640Speter /* 234012174Speter * Process read characters if not skipped above 234112174Speter */ 234215640Speter op = ccbp->hi_rxopos; 234315640Speter ip = ccbp->hi_rxipos; 234415640Speter c = ip - op; 234512174Speter if (c == 0) { 234612174Speter goto end_rx; 234712174Speter } 234810015Speter 234912174Speter n = c & 0xff; 235015640Speter if (n > 250) 235115640Speter n = 250; 235212174Speter 235312174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 235410015Speter n, op, ip)); 235510015Speter 235612174Speter /* 235712174Speter * Suck characters out of host card buffer into the 235812174Speter * "input staging buffer" - so that we dont leave the 235912174Speter * host card in limbo while we're possibly echoing 236012174Speter * characters and possibly flushing input inside the 236112174Speter * ldisc l_rint() routine. 236212174Speter */ 236312496Speter if (n <= SI_BUFFERSIZE - op) { 236410015Speter 236512174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 236612174Speter z = ccbp->hi_rxbuf + op; 236734832Speter si_bcopy((caddr_t)z, si_rxbuf, n); 236810015Speter 236912174Speter op += n; 237012174Speter } else { 237112496Speter x = SI_BUFFERSIZE - op; 237210015Speter 237312174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 237412174Speter z = ccbp->hi_rxbuf + op; 237534832Speter si_bcopy((caddr_t)z, si_rxbuf, x); 237610015Speter 237734832Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 237834832Speter n - x)); 237912174Speter z = ccbp->hi_rxbuf; 238034832Speter si_bcopy((caddr_t)z, si_rxbuf + x, n - x); 238110015Speter 238212174Speter op += n; 238312174Speter } 238410015Speter 238512174Speter /* clear collected characters from buffer */ 238612174Speter ccbp->hi_rxopos = op; 238712174Speter 238812174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 238910015Speter n, op, ip)); 239010015Speter 239112174Speter /* 239212174Speter * at this point... 239312174Speter * n = number of chars placed in si_rxbuf 239412174Speter */ 239510015Speter 239612174Speter /* 239712174Speter * Avoid the grotesquely inefficient lineswitch 239812174Speter * routine (ttyinput) in "raw" mode. It usually 239912174Speter * takes about 450 instructions (that's without 240012174Speter * canonical processing or echo!). slinput is 240112174Speter * reasonably fast (usually 40 instructions 240212174Speter * plus call overhead). 240312174Speter */ 240412174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 240510015Speter 240612174Speter /* block if the driver supports it */ 240712174Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER 240812174Speter && (tp->t_cflag & CRTS_IFLOW 240912174Speter || tp->t_iflag & IXOFF) 241012174Speter && !(tp->t_state & TS_TBLOCK)) 241112174Speter ttyblock(tp); 241210015Speter 241312174Speter tk_nin += n; 241412174Speter tk_rawcc += n; 241512174Speter tp->t_rawcc += n; 241612174Speter 241712174Speter pp->sp_delta_overflows += 241812174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 241912174Speter 242012174Speter ttwakeup(tp); 242112174Speter if (tp->t_state & TS_TTSTOP 242212174Speter && (tp->t_iflag & IXANY 242312174Speter || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 242412174Speter tp->t_state &= ~TS_TTSTOP; 242512174Speter tp->t_lflag &= ~FLUSHO; 242612174Speter si_start(tp); 242712174Speter } 242812174Speter } else { 242912174Speter /* 243012174Speter * It'd be nice to not have to go through the 243112174Speter * function call overhead for each char here. 243212174Speter * It'd be nice to block input it, saving a 243312174Speter * loop here and the call/return overhead. 243412174Speter */ 243512174Speter for(x = 0; x < n; x++) { 243612174Speter i = si_rxbuf[x]; 243712174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 243812174Speter == -1) { 243912174Speter pp->sp_delta_overflows++; 244010015Speter } 244112174Speter /* 244212174Speter * doesn't seem to be much point doing 244312174Speter * this here.. this driver has no 244412174Speter * softtty processing! ?? 244512174Speter */ 244612174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 244712174Speter setsofttty(); 244812174Speter } 244912174Speter } 245012174Speter } 245112174Speter goto more_rx; /* try for more until RXbuf is empty */ 245210015Speter 245312174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 245410015Speter 245510015Speter /* 245610015Speter * Do TX stuff 245710015Speter */ 245810015Speter (*linesw[tp->t_line].l_start)(tp); 245910015Speter 246010015Speter } /* end of for (all ports on this controller) */ 246110015Speter } /* end of for (all controllers) */ 246210015Speter 246311609Speter in_intr = 0; 246434735Speter DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit)); 246510015Speter} 246610015Speter 246710015Speter/* 246810015Speter * Nudge the transmitter... 246912174Speter * 247012174Speter * XXX: I inherited some funny code here. It implies the host card only 247112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 247212174Speter * not interrupt when it's actually hits empty. In some cases, we have 247312174Speter * processes waiting for complete drain, and we need to simulate an interrupt 247412174Speter * about when we think the buffer is going to be empty (and retry if not). 247512174Speter * I really am not certain about this... I *need* the hardware manuals. 247610015Speter */ 247710015Speterstatic void 247810015Spetersi_start(tp) 247910015Speter register struct tty *tp; 248010015Speter{ 248110015Speter struct si_port *pp; 248210015Speter volatile struct si_channel *ccbp; 248310015Speter register struct clist *qp; 248410015Speter BYTE ipos; 248510015Speter int nchar; 248610015Speter int oldspl, count, n, amount, buffer_full; 248710015Speter 248810015Speter oldspl = spltty(); 248910015Speter 249010015Speter qp = &tp->t_outq; 249110015Speter pp = TP2PP(tp); 249210015Speter 249310015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 249410015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 249510015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 249610015Speter 249710015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 249810015Speter goto out; 249910015Speter 250010015Speter buffer_full = 0; 250110015Speter ccbp = pp->sp_ccb; 250210015Speter 250310015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 250410015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 250510015Speter 250610015Speter while ((nchar = qp->c_cc) > 0) { 250710015Speter if ((BYTE)count >= 255) { 250810015Speter buffer_full++; 250910015Speter break; 251010015Speter } 251110015Speter amount = min(nchar, (255 - (BYTE)count)); 251210015Speter ipos = (unsigned int)ccbp->hi_txipos; 251334832Speter n = q_to_b(&tp->t_outq, si_txbuf, amount); 251410015Speter /* will it fit in one lump? */ 251534832Speter if ((SI_BUFFERSIZE - ipos) >= n) { 251634832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n); 251710015Speter } else { 251834832Speter si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], 251934832Speter SI_BUFFERSIZE - ipos); 252034832Speter si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos), 252134832Speter (char *)&ccbp->hi_txbuf[0], 252234832Speter n - (SI_BUFFERSIZE - ipos)); 252310015Speter } 252410015Speter ccbp->hi_txipos += n; 252510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 252610015Speter } 252710015Speter 252810015Speter if (count != 0 && nchar == 0) { 252910015Speter tp->t_state |= TS_BUSY; 253010015Speter } else { 253110015Speter tp->t_state &= ~TS_BUSY; 253210015Speter } 253310015Speter 253410015Speter /* wakeup time? */ 253510015Speter ttwwakeup(tp); 253610015Speter 253710015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 253810015Speter (BYTE)count, nchar, tp->t_state)); 253910015Speter 254034735Speter if (tp->t_state & TS_BUSY) 254110015Speter { 254210015Speter int time; 254310015Speter 254434735Speter time = ttspeedtab(tp->t_ospeed, chartimes); 254534735Speter 254634735Speter if (time > 0) { 254734735Speter if (time < nchar) 254834735Speter time = nchar / time; 254934735Speter else 255034735Speter time = 2; 255110015Speter } else { 255234735Speter DPRINT((pp, DBG_START, 255334735Speter "bad char time value! %d\n", time)); 255434735Speter time = hz/10; 255510015Speter } 255610015Speter 255710015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 255829677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 255910015Speter } else { 256010015Speter pp->sp_state |= SS_LSTART; 256110015Speter } 256210015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 256329677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 256410015Speter } 256510015Speter 256610015Speterout: 256710015Speter splx(oldspl); 256810015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 256910015Speter} 257010015Speter 257110015Speter/* 257210015Speter * Note: called at splsoftclock from the timeout code 257310015Speter * This has to deal with two things... cause wakeups while waiting for 257410015Speter * tty drains on last process exit, and call l_start at about the right 257510015Speter * time for protocols like ppp. 257610015Speter */ 257710015Speterstatic void 257825047Sbdesi_lstart(void *arg) 257910015Speter{ 258025047Sbde register struct si_port *pp = arg; 258110015Speter register struct tty *tp; 258210015Speter int oldspl; 258310015Speter 258410015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 258510015Speter pp, pp->sp_state)); 258610015Speter 258710015Speter oldspl = spltty(); 258810015Speter 258910015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 259010015Speter splx(oldspl); 259110015Speter return; 259210015Speter } 259310015Speter pp->sp_state &= ~SS_LSTART; 259410015Speter pp->sp_state |= SS_INLSTART; 259510015Speter 259610015Speter tp = pp->sp_tty; 259710015Speter 259810015Speter /* deal with the process exit case */ 259910015Speter ttwwakeup(tp); 260010015Speter 260112174Speter /* nudge protocols - eg: ppp */ 260210015Speter (*linesw[tp->t_line].l_start)(tp); 260310015Speter 260410015Speter pp->sp_state &= ~SS_INLSTART; 260510015Speter splx(oldspl); 260610015Speter} 260710015Speter 260810015Speter/* 260910015Speter * Stop output on a line. called at spltty(); 261010015Speter */ 261110015Spetervoid 261210015Spetersistop(tp, rw) 261310015Speter register struct tty *tp; 261410015Speter int rw; 261510015Speter{ 261610015Speter volatile struct si_channel *ccbp; 261710015Speter struct si_port *pp; 261810015Speter 261910015Speter pp = TP2PP(tp); 262010015Speter ccbp = pp->sp_ccb; 262110015Speter 262210015Speter DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw)); 262310015Speter 262410015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 262510015Speter if (rw & FWRITE) { 262610015Speter /* what level are we meant to be flushing anyway? */ 262710015Speter if (tp->t_state & TS_BUSY) { 262810015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 262910015Speter tp->t_state &= ~TS_BUSY; 263010015Speter ttwwakeup(tp); /* Bruce???? */ 263110015Speter } 263210015Speter } 263312174Speter#if 1 /* XXX: this doesn't work right yet.. */ 263412174Speter /* XXX: this may have been failing because we used to call l_rint() 263512174Speter * while we were looping based on these two counters. Now, we collect 263612174Speter * the data and then loop stuffing it into l_rint(), making this 263712174Speter * useless. Should we cause this to blow away the staging buffer? 263812174Speter */ 263910015Speter if (rw & FREAD) { 264010015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 264110015Speter } 264210015Speter#endif 264310015Speter} 264410015Speter 264510015Speter/* 264634832Speter * Issue a command to the host card CPU. 264710015Speter */ 264810015Speter 264910015Speterstatic void 265010015Spetersi_command(pp, cmd, waitflag) 265110015Speter struct si_port *pp; /* port control block (local) */ 265210015Speter int cmd; 265310015Speter int waitflag; 265410015Speter{ 265510015Speter int oldspl; 265610015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 265710015Speter int x; 265810015Speter 265910015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 266010015Speter pp, cmd, waitflag, ccbp->hi_stat)); 266110015Speter 266210015Speter oldspl = spltty(); /* Keep others out */ 266310015Speter 266410015Speter /* wait until it's finished what it was doing.. */ 266516575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 266616575Speter * is turned off. */ 266710015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 266810015Speter x != IDLE_CLOSE && 266916575Speter x != IDLE_BREAK && 267010015Speter x != cmd) { 267110015Speter if (in_intr) { /* Prevent sleep in intr */ 267210015Speter DPRINT((pp, DBG_PARAM, 267310015Speter "cmd intr collision - completing %d\trequested %d\n", 267410015Speter x, cmd)); 267510015Speter splx(oldspl); 267610015Speter return; 267710015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 267810015Speter "sicmd1", 1)) { 267910015Speter splx(oldspl); 268010015Speter return; 268110015Speter } 268210015Speter } 268316575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 268410015Speter 268510015Speter /* if there was a pending command, cause a state-change wakeup */ 268616575Speter switch(pp->sp_pend) { 268716575Speter case LOPEN: 268816575Speter case MPEND: 268916575Speter case MOPEN: 269016575Speter case CONFIG: 269116575Speter case SBREAK: 269216575Speter case EBREAK: 269316575Speter wakeup(&pp->sp_state); 269416575Speter break; 269516575Speter default: 269616575Speter break; 269710015Speter } 269810015Speter 269910015Speter pp->sp_pend = cmd; /* New command pending */ 270010015Speter ccbp->hi_stat = cmd; /* Post it */ 270110015Speter 270210015Speter if (waitflag) { 270310015Speter if (in_intr) { /* If in interrupt handler */ 270410015Speter DPRINT((pp, DBG_PARAM, 270510015Speter "attempt to sleep in si_intr - cmd req %d\n", 270610015Speter cmd)); 270710015Speter splx(oldspl); 270810015Speter return; 270916575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 271016575Speter ccbp->hi_stat != IDLE_BREAK) { 271110015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 271210015Speter "sicmd2", 0)) 271310015Speter break; 271410015Speter } 271510015Speter } 271610015Speter splx(oldspl); 271710015Speter} 271810015Speter 271910015Speterstatic void 272010015Spetersi_disc_optim(tp, t, pp) 272110015Speter struct tty *tp; 272210015Speter struct termios *t; 272310015Speter struct si_port *pp; 272410015Speter{ 272510015Speter /* 272610015Speter * XXX can skip a lot more cases if Smarts. Maybe 272710015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 272810015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 272910015Speter */ 273010015Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 273110015Speter && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 273210015Speter && (!(t->c_iflag & PARMRK) 273310015Speter || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 273410015Speter && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 273510015Speter && linesw[tp->t_line].l_rint == ttyinput) 273610015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 273710015Speter else 273810015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 273933322Sphk pp->sp_hotchar = linesw[tp->t_line].l_hotchar; 274010161Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 274110161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 274210161Speter pp->sp_hotchar)); 274310015Speter} 274410015Speter 274510015Speter 274610015Speter#ifdef SI_DEBUG 274713353Speter 274810015Speterstatic void 274913353Speter#ifdef __STDC__ 275013353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 275113353Speter#else 275213353Spetersi_dprintf(pp, flags, fmt, va_alist) 275310015Speter struct si_port *pp; 275410015Speter int flags; 275513353Speter char *fmt; 275613353Speter#endif 275710015Speter{ 275813353Speter va_list ap; 275913630Sphk 276010015Speter if ((pp == NULL && (si_debug&flags)) || 276110015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 276234832Speter if (pp != NULL) 276334832Speter printf("%ci%d(%d): ", 's', 276446679Sphk (int)SI_CARD(minor(pp->sp_tty->t_dev)), 276546679Sphk (int)SI_PORT(minor(pp->sp_tty->t_dev))); 276613630Sphk va_start(ap, fmt); 276713630Sphk vprintf(fmt, ap); 276813353Speter va_end(ap); 276910015Speter } 277010015Speter} 277110015Speter 277210015Speterstatic char * 277310015Spetersi_mctl2str(cmd) 277410015Speter enum si_mctl cmd; 277510015Speter{ 277610015Speter switch (cmd) { 277734832Speter case GET: 277834832Speter return("GET"); 277934832Speter case SET: 278034832Speter return("SET"); 278134832Speter case BIS: 278234832Speter return("BIS"); 278334832Speter case BIC: 278434832Speter return("BIC"); 278510015Speter } 278610015Speter return("BAD"); 278710015Speter} 278812502Sjulian 278912624Speter#endif /* DEBUG */ 279012502Sjulian 279134832Speterstatic char * 279234832Spetersi_modulename(host_type, uart_type) 279334832Speter int host_type, uart_type; 279434832Speter{ 279534832Speter switch (host_type) { 279634832Speter /* Z280 based cards */ 279734832Speter#if NEISA > 0 279834832Speter case SIEISA: 279934832Speter#endif 280034832Speter case SIHOST2: 280134832Speter case SIHOST: 280234832Speter#if NPCI > 0 280334832Speter case SIPCI: 280434832Speter#endif 280534832Speter switch (uart_type) { 280634832Speter case 0: 280734832Speter return(" (XIO)"); 280834832Speter case 1: 280934832Speter return(" (SI)"); 281034832Speter } 281134832Speter break; 281234832Speter /* T225 based hosts */ 281334832Speter#if NPCI > 0 281434832Speter case SIJETPCI: 281534832Speter#endif 281634832Speter case SIJETISA: 281734832Speter switch (uart_type) { 281834832Speter case 0: 281934832Speter return(" (SI)"); 282034832Speter case 40: 282134832Speter return(" (XIO)"); 282236856Sphk case 72: 282336856Sphk return(" (SXDC)"); 282434832Speter } 282534832Speter break; 282634832Speter } 282734832Speter return(""); 282834832Speter} 282912624Speter 283046153Sdtstatic int si_devsw_installed; 283112502Sjulian 283234832Speterstatic void 283334832Spetersi_drvinit(void *unused) 283412502Sjulian{ 283512517Sjulian 283647640Sphk cdevsw_add(&si_cdevsw); 283712502Sjulian} 283812517Sjulian 283912517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL) 2840