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