si.c revision 56592
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> 656505Speter * Copyright (C) 2000, 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 * 3350477Speter * $FreeBSD: head/sys/dev/si/si.c 56592 2000-01-25 16:45:54Z peter $ 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", 3956505Speter si_copyright3[] = "@(#) Copyright (C) Peter Wemm 2000"; 4010015Speter#endif /* not lint */ 4110015Speter 4231778Seivind#include "opt_compat.h" 4332929Seivind#include "opt_debug_si.h" 4431778Seivind 4510015Speter#include <sys/param.h> 4610015Speter#include <sys/systm.h> 4724207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 4824207Sbde#include <sys/ioctl_compat.h> 4924207Sbde#endif 5010015Speter#include <sys/tty.h> 5110015Speter#include <sys/proc.h> 5210015Speter#include <sys/conf.h> 5324131Sbde#include <sys/fcntl.h> 5410015Speter#include <sys/dkstat.h> 5510015Speter#include <sys/kernel.h> 5610015Speter#include <sys/malloc.h> 5715683Speter#include <sys/sysctl.h> 5856498Speter#include <sys/bus.h> 5956498Speter#include <machine/bus.h> 6056498Speter#include <sys/rman.h> 6156498Speter#include <machine/resource.h> 6210015Speter 6310015Speter#include <machine/clock.h> 6410015Speter 6512659Sbde#include <vm/vm.h> 6612662Sdg#include <vm/pmap.h> 6712659Sbde 6813353Speter#include <machine/stdarg.h> 6910015Speter 7056498Speter#include <dev/si/sireg.h> 7156505Speter#include <dev/si/sivar.h> 7256498Speter#include <dev/si/si.h> 7356498Speter 7410015Speter/* 7510015Speter * This device driver is designed to interface the Specialix International 7634832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, 7734832Speter * EISA or PCI bus machine. 7810015Speter * 7934832Speter * The controller is interfaced to the host via dual port RAM 8034832Speter * and an interrupt. 8133395Speter * 8234832Speter * The code for the Host 1 (very old ISA cards) has not been tested. 8310015Speter */ 8410015Speter 8517547Speter#define POLL /* turn on poller to scan for lost interrupts */ 8617547Speter#define REALPOLL /* on each poll, scan for work regardless */ 8717547Speter#define POLLHZ (hz/10) /* 10 times per second */ 8812496Speter#define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE) 8934832Speter#define INT_COUNT 25000 /* max of 125 ints per second */ 9034832Speter#define JET_INT_COUNT 100 /* max of 100 ints per second */ 9115639Speter#define RXINT_COUNT 1 /* one rxint per 10 milliseconds */ 9210015Speter 9310015Speterenum si_mctl { GET, SET, BIS, BIC }; 9410015Speter 9556498Speterstatic void si_command(struct si_port *, int, int); 9656498Speterstatic int si_modem(struct si_port *, enum si_mctl, int); 9756498Speterstatic void si_write_enable(struct si_port *, int); 9856498Speterstatic int si_Sioctl(dev_t, u_long, caddr_t, int, struct proc *); 9956498Speterstatic void si_start(struct tty *); 10056498Speterstatic void si_stop(struct tty *, int); 10125047Sbdestatic timeout_t si_lstart; 10256498Speterstatic void si_disc_optim(struct tty *tp, struct termios *t,struct si_port *pp); 10356498Speterstatic void sihardclose(struct si_port *pp); 10456498Speterstatic void sidtrwakeup(void *chan); 10510015Speter 10656505Speter#ifdef SI_DEBUG 10756505Speterstatic char *si_mctl2str(enum si_mctl cmd); 10856505Speter#endif 10956505Speter 11056498Speterstatic int siparam(struct tty *, struct termios *); 11110015Speter 11256498Speterstatic void si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip); 11356498Speterstatic char * si_modulename(int host_type, int uart_type); 11410708Speter 11512675Sjulianstatic d_open_t siopen; 11612675Sjulianstatic d_close_t siclose; 11712675Sjulianstatic d_write_t siwrite; 11812675Sjulianstatic d_ioctl_t siioctl; 11912675Sjulian 12038485Sbde#define CDEV_MAJOR 68 12147625Sphkstatic struct cdevsw si_cdevsw = { 12247625Sphk /* open */ siopen, 12347625Sphk /* close */ siclose, 12451756Sphk /* read */ ttyread, 12547625Sphk /* write */ siwrite, 12647625Sphk /* ioctl */ siioctl, 12751654Sphk /* poll */ ttypoll, 12847625Sphk /* mmap */ nommap, 12947625Sphk /* strategy */ nostrategy, 13047625Sphk /* name */ "si", 13147625Sphk /* maj */ CDEV_MAJOR, 13247625Sphk /* dump */ nodump, 13347625Sphk /* psize */ nopsize, 13447625Sphk /* flags */ D_TTY, 13547625Sphk /* bmaj */ -1 13638485Sbde}; 13712675Sjulian 13810962Speterstatic int si_Nports; 13910962Speterstatic int si_Nmodules; 14010962Speterstatic int si_debug = 0; /* data, not bss, so it's patchable */ 14110015Speter 14234832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, ""); 14334832Speter 14450669Sphkstatic struct tty *si__tty; 14510962Speter 14656498Speterstatic int si_numunits; 14710044Speter 14856505Speterdevclass_t si_devclass; 14956498Speter 15012174Speter#ifndef B2000 /* not standard, but the hardware knows it. */ 15110015Speter# define B2000 2000 15210015Speter#endif 15310015Speterstatic struct speedtab bdrates[] = { 15450442Speter { B75, CLK75, }, /* 0x0 */ 15550442Speter { B110, CLK110, }, /* 0x1 */ 15650442Speter { B150, CLK150, }, /* 0x3 */ 15750442Speter { B300, CLK300, }, /* 0x4 */ 15850442Speter { B600, CLK600, }, /* 0x5 */ 15950442Speter { B1200, CLK1200, }, /* 0x6 */ 16050442Speter { B2000, CLK2000, }, /* 0x7 */ 16150442Speter { B2400, CLK2400, }, /* 0x8 */ 16250442Speter { B4800, CLK4800, }, /* 0x9 */ 16350442Speter { B9600, CLK9600, }, /* 0xb */ 16450442Speter { B19200, CLK19200, }, /* 0xc */ 16550442Speter { B38400, CLK38400, }, /* 0x2 (out of order!) */ 16650442Speter { B57600, CLK57600, }, /* 0xd */ 16750442Speter { B115200, CLK110, }, /* 0x1 (dupe!, 110 baud on "si") */ 16850442Speter { -1, -1 }, 16910015Speter}; 17010015Speter 17110015Speter 17210015Speter/* populated with approx character/sec rates - translated at card 17310015Speter * initialisation time to chars per tick of the clock */ 17410015Speterstatic int done_chartimes = 0; 17510015Speterstatic struct speedtab chartimes[] = { 17650442Speter { B75, 8, }, 17750442Speter { B110, 11, }, 17850442Speter { B150, 15, }, 17950442Speter { B300, 30, }, 18050442Speter { B600, 60, }, 18150442Speter { B1200, 120, }, 18250442Speter { B2000, 200, }, 18350442Speter { B2400, 240, }, 18450442Speter { B4800, 480, }, 18550442Speter { B9600, 960, }, 18650442Speter { B19200, 1920, }, 18750442Speter { B38400, 3840, }, 18850442Speter { B57600, 5760, }, 18950442Speter { B115200, 11520, }, 19050442Speter { -1, -1 }, 19110015Speter}; 19210015Speterstatic volatile int in_intr = 0; /* Inside interrupt handler? */ 19310015Speter 19410015Speter#ifdef POLL 19515683Speterstatic int si_pollrate; /* in addition to irq */ 19656498Speterstatic int si_realpoll = 0; /* poll HW on timer */ 19715639Speter 19816403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, ""); 19917547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, ""); 20050442Speter 20110015Speterstatic int init_finished = 0; 20256498Speterstatic void si_poll(void *); 20310015Speter#endif 20410015Speter 20510015Speter/* 20610015Speter * Array of adapter types and the corresponding RAM size. The order of 20710015Speter * entries here MUST match the ordinal of the adapter type. 20810015Speter */ 20910015Speterstatic char *si_type[] = { 21010015Speter "EMPTY", 21110015Speter "SIHOST", 21234832Speter "SIMCA", /* FreeBSD does not support Microchannel */ 21310015Speter "SIHOST2", 21410015Speter "SIEISA", 21533395Speter "SIPCI", 21633395Speter "SXPCI", 21733395Speter "SXISA", 21810015Speter}; 21910015Speter 22056498Speter/* 22156498Speter * We have to make an 8 bit version of bcopy, since some cards can't 22256498Speter * deal with 32 bit I/O 22356498Speter */ 22456498Speterstatic void __inline 22556498Spetersi_bcopy(const void *src, void *dst, size_t len) 22656498Speter{ 22756498Speter while (len--) 22856498Speter *(((u_char *)dst)++) = *(((const u_char *)src)++); 22956498Speter} 23056498Speterstatic void __inline 23156498Spetersi_vbcopy(const volatile void *src, void *dst, size_t len) 23256498Speter{ 23356498Speter while (len--) 23456498Speter *(((u_char *)dst)++) = *(((const volatile u_char *)src)++); 23556498Speter} 23656498Speterstatic void __inline 23756498Spetersi_bcopyv(const void *src, volatile void *dst, size_t len) 23856498Speter{ 23956498Speter while (len--) 24056498Speter *(((volatile u_char *)dst)++) = *(((const u_char *)src)++); 24156498Speter} 24256498Speter 24356498Speter 24434832Speter/* 24510015Speter * Attach the device. Initialize the card. 24610015Speter */ 24756505Speterint 24856498Spetersiattach(device_t dev) 24910015Speter{ 25056498Speter int unit; 25156498Speter struct si_softc *sc; 25210015Speter struct si_port *pp; 25310015Speter volatile struct si_channel *ccbp; 25410015Speter volatile struct si_reg *regp; 25510015Speter volatile caddr_t maddr; 25610015Speter struct si_module *modp; 25710015Speter struct tty *tp; 25810015Speter struct speedtab *spt; 25910015Speter int nmodule, nport, x, y; 26012174Speter int uart_type; 26110015Speter 26256498Speter sc = device_get_softc(dev); 26356498Speter unit = device_get_unit(dev); 26410015Speter 26556505Speter sc->sc_typename = si_type[sc->sc_type]; 26656505Speter if (si_numunits < unit + 1) 26756505Speter si_numunits = unit + 1; 26856505Speter 26956498Speter DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", unit)); 27010015Speter 27156498Speter#ifdef POLL 27256498Speter if (si_pollrate == 0) { 27356498Speter si_pollrate = POLLHZ; /* in addition to irq */ 27456498Speter#ifdef REALPOLL 27556498Speter si_realpoll = 1; /* scan always */ 27656498Speter#endif 27756498Speter } 27856498Speter#endif 27956498Speter 28033395Speter DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit, 28133395Speter sc->sc_typename, sc->sc_paddr, sc->sc_maddr)); 28233395Speter 28310015Speter sc->sc_ports = NULL; /* mark as uninitialised */ 28410015Speter 28510015Speter maddr = sc->sc_maddr; 28610015Speter 28734832Speter /* Stop the CPU first so it won't stomp around while we load */ 28834832Speter 28934832Speter switch (sc->sc_type) { 29034832Speter case SIEISA: 29156498Speter outb(sc->sc_iobase + 2, sc->sc_irq << 4); 29234832Speter break; 29334832Speter case SIPCI: 29434832Speter *(maddr+SIPCIRESET) = 0; 29534832Speter break; 29634832Speter case SIJETPCI: /* fall through to JET ISA */ 29734832Speter case SIJETISA: 29834832Speter *(maddr+SIJETCONFIG) = 0; 29934832Speter break; 30034832Speter case SIHOST2: 30134832Speter *(maddr+SIPLRESET) = 0; 30234832Speter break; 30334832Speter case SIHOST: 30434832Speter *(maddr+SIRESET) = 0; 30534832Speter break; 30634832Speter default: /* this should never happen */ 30734832Speter printf("si%d: unsupported configuration\n", unit); 30856498Speter return EINVAL; 30934832Speter break; 31034832Speter } 31134832Speter 31234832Speter /* OK, now lets download the download code */ 31334832Speter 31436956Ssteve if (SI_ISJET(sc->sc_type)) { 31533395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n", 31656498Speter unit, si3_t225_dsize)); 31734832Speter si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr, 31834832Speter si3_t225_dsize); 31934832Speter DPRINT((0, DBG_DOWNLOAD, 32034832Speter "si%d: jet_bootstrap: nbytes %d -> %x\n", 32156498Speter unit, si3_t225_bsize, si3_t225_bootloadaddr)); 32234832Speter si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr, 32334832Speter si3_t225_bsize); 32434832Speter } else { 32533395Speter DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n", 32656498Speter unit, si2_z280_dsize)); 32734832Speter si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr, 32834832Speter si2_z280_dsize); 32933395Speter } 33010015Speter 33134832Speter /* Now start the CPU */ 33234832Speter 33310015Speter switch (sc->sc_type) { 33410015Speter case SIEISA: 33534832Speter /* modify the download code to tell it that it's on an EISA */ 33634832Speter *(maddr + 0x42) = 1; 33756498Speter outb(sc->sc_iobase + 2, (sc->sc_irq << 4) | 4); 33856498Speter (void)inb(sc->sc_iobase + 3); /* reset interrupt */ 33910015Speter break; 34033395Speter case SIPCI: 34134832Speter /* modify the download code to tell it that it's on a PCI */ 34233395Speter *(maddr+0x42) = 1; 34333395Speter *(maddr+SIPCIRESET) = 1; 34433395Speter *(maddr+SIPCIINTCL) = 0; 34533395Speter break; 34633395Speter case SIJETPCI: 34733395Speter *(maddr+SIJETRESET) = 0; 34833395Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN; 34933395Speter break; 35033395Speter case SIJETISA: 35133395Speter *(maddr+SIJETRESET) = 0; 35234832Speter switch (sc->sc_irq) { 35356498Speter case 9: 35434832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90; 35534832Speter break; 35656498Speter case 10: 35734832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0; 35834832Speter break; 35956498Speter case 11: 36034832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0; 36134832Speter break; 36256498Speter case 12: 36334832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0; 36434832Speter break; 36556498Speter case 15: 36634832Speter *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0; 36734832Speter break; 36834832Speter } 36933395Speter break; 37010015Speter case SIHOST: 37110015Speter *(maddr+SIRESET_CL) = 0; 37210015Speter *(maddr+SIINTCL_CL) = 0; 37310015Speter break; 37410015Speter case SIHOST2: 37510015Speter *(maddr+SIPLRESET) = 0x10; 37610015Speter switch (sc->sc_irq) { 37756498Speter case 11: 37810015Speter *(maddr+SIPLIRQ11) = 0x10; 37910015Speter break; 38056498Speter case 12: 38110015Speter *(maddr+SIPLIRQ12) = 0x10; 38210015Speter break; 38356498Speter case 15: 38410015Speter *(maddr+SIPLIRQ15) = 0x10; 38510015Speter break; 38610015Speter } 38710015Speter *(maddr+SIPLIRQCLR) = 0x10; 38810015Speter break; 38934832Speter default: /* this should _REALLY_ never happen */ 39034832Speter printf("si%d: Uh, it was supported a second ago...\n", unit); 39156498Speter return EINVAL; 39210015Speter } 39310015Speter 39410015Speter DELAY(1000000); /* wait around for a second */ 39510015Speter 39610015Speter regp = (struct si_reg *)maddr; 39710015Speter y = 0; 39810015Speter /* wait max of 5 sec for init OK */ 39910015Speter while (regp->initstat == 0 && y++ < 10) { 40010015Speter DELAY(500000); 40110015Speter } 40210015Speter switch (regp->initstat) { 40310015Speter case 0: 40410015Speter printf("si%d: startup timeout - aborting\n", unit); 40512174Speter sc->sc_type = SIEMPTY; 40656498Speter return EINVAL; 40710015Speter case 1: 40836956Ssteve if (SI_ISJET(sc->sc_type)) { 40934832Speter /* set throttle to 100 times per second */ 41034832Speter regp->int_count = JET_INT_COUNT; 41134832Speter /* rx_intr_count is a NOP in Jet */ 41234832Speter } else { 41334832Speter /* set throttle to 125 times per second */ 41434832Speter regp->int_count = INT_COUNT; 41534832Speter /* rx intr max of 25 times per second */ 41634832Speter regp->rx_int_count = RXINT_COUNT; 41734832Speter } 41810015Speter regp->int_pending = 0; /* no intr pending */ 41910015Speter regp->int_scounter = 0; /* reset counter */ 42010015Speter break; 42110015Speter case 0xff: 42210015Speter /* 42310015Speter * No modules found, so give up on this one. 42410015Speter */ 42510015Speter printf("si%d: %s - no ports found\n", unit, 42610015Speter si_type[sc->sc_type]); 42710015Speter return 0; 42810015Speter default: 42934832Speter printf("si%d: download code version error - initstat %x\n", 43010015Speter unit, regp->initstat); 43156498Speter return EINVAL; 43210015Speter } 43310015Speter 43410015Speter /* 43510015Speter * First time around the ports just count them in order 43610015Speter * to allocate some memory. 43710015Speter */ 43810015Speter nport = 0; 43910015Speter modp = (struct si_module *)(maddr + 0x80); 44010015Speter for (;;) { 44112174Speter DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp)); 44234832Speter switch (modp->sm_type) { 44334832Speter case TA4: 44410015Speter DPRINT((0, DBG_DOWNLOAD, 44534832Speter "si%d: Found old TA4 module, 4 ports\n", 44634832Speter unit)); 44734832Speter x = 4; 44810015Speter break; 44934832Speter case TA8: 45034832Speter DPRINT((0, DBG_DOWNLOAD, 45134832Speter "si%d: Found old TA8 module, 8 ports\n", 45234832Speter unit)); 45334832Speter x = 8; 45434832Speter break; 45534832Speter case TA4_ASIC: 45634832Speter DPRINT((0, DBG_DOWNLOAD, 45734832Speter "si%d: Found ASIC TA4 module, 4 ports\n", 45834832Speter unit)); 45934832Speter x = 4; 46034832Speter break; 46134832Speter case TA8_ASIC: 46234832Speter DPRINT((0, DBG_DOWNLOAD, 46334832Speter "si%d: Found ASIC TA8 module, 8 ports\n", 46434832Speter unit)); 46534832Speter x = 8; 46634832Speter break; 46734832Speter case MTA: 46834832Speter DPRINT((0, DBG_DOWNLOAD, 46934832Speter "si%d: Found CD1400 module, 8 ports\n", 47034832Speter unit)); 47134832Speter x = 8; 47234832Speter break; 47334832Speter case SXDC: 47434832Speter DPRINT((0, DBG_DOWNLOAD, 47534832Speter "si%d: Found SXDC module, 8 ports\n", 47634832Speter unit)); 47734832Speter x = 8; 47834832Speter break; 47910015Speter default: 48010015Speter printf("si%d: unknown module type %d\n", 48110015Speter unit, modp->sm_type); 48234832Speter goto try_next; 48310015Speter } 48434832Speter 48534832Speter /* this was limited in firmware and is also a driver issue */ 48634832Speter if ((nport + x) > SI_MAXPORTPERCARD) { 48734832Speter printf("si%d: extra ports ignored\n", unit); 48834832Speter goto try_next; 48934832Speter } 49034832Speter 49134832Speter nport += x; 49234832Speter si_Nports += x; 49334832Speter si_Nmodules++; 49434832Speter 49534832Spetertry_next: 49610015Speter if (modp->sm_next == 0) 49710015Speter break; 49810015Speter modp = (struct si_module *) 49910015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 50010015Speter } 50110015Speter sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, 50210015Speter M_DEVBUF, M_NOWAIT); 50310015Speter if (sc->sc_ports == 0) { 50410015Spetermem_fail: 50510015Speter printf("si%d: fail to malloc memory for port structs\n", 50610015Speter unit); 50756498Speter return EINVAL; 50810015Speter } 50910015Speter bzero(sc->sc_ports, sizeof(struct si_port) * nport); 51010015Speter sc->sc_nport = nport; 51110015Speter 51210015Speter /* 51310015Speter * allocate tty structures for ports 51410015Speter */ 51510015Speter tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); 51610015Speter if (tp == 0) 51710015Speter goto mem_fail; 51810015Speter bzero(tp, sizeof(*tp) * nport); 51950669Sphk si__tty = tp; 52010015Speter 52110015Speter /* 52210015Speter * Scan round the ports again, this time initialising. 52310015Speter */ 52410015Speter pp = sc->sc_ports; 52510015Speter nmodule = 0; 52610015Speter modp = (struct si_module *)(maddr + 0x80); 52734832Speter uart_type = 1000; /* arbitary, > uchar_max */ 52810015Speter for (;;) { 52934832Speter switch (modp->sm_type) { 53034832Speter case TA4: 53134832Speter nport = 4; 53210015Speter break; 53334832Speter case TA8: 53434832Speter nport = 8; 53534832Speter break; 53634832Speter case TA4_ASIC: 53734832Speter nport = 4; 53834832Speter break; 53934832Speter case TA8_ASIC: 54034832Speter nport = 8; 54134832Speter break; 54234832Speter case MTA: 54334832Speter nport = 8; 54434832Speter break; 54534832Speter case SXDC: 54634832Speter nport = 8; 54734832Speter break; 54810015Speter default: 54934832Speter goto try_next2; 55010015Speter } 55134832Speter nmodule++; 55234832Speter ccbp = (struct si_channel *)((char *)modp + 0x100); 55334832Speter if (uart_type == 1000) 55434832Speter uart_type = ccbp->type; 55534832Speter else if (uart_type != ccbp->type) 55634832Speter printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n", 55734832Speter unit, nmodule, 55834832Speter ccbp->type, si_modulename(sc->sc_type, ccbp->type), 55934832Speter uart_type, si_modulename(sc->sc_type, uart_type)); 56034832Speter 56134832Speter for (x = 0; x < nport; x++, pp++, ccbp++) { 56234832Speter pp->sp_ccb = ccbp; /* save the address */ 56334832Speter pp->sp_tty = tp++; 56434832Speter pp->sp_pend = IDLE_CLOSE; 56534832Speter pp->sp_state = 0; /* internal flag */ 56634832Speter pp->sp_dtr_wait = 3 * hz; 56734832Speter pp->sp_iin.c_iflag = TTYDEF_IFLAG; 56834832Speter pp->sp_iin.c_oflag = TTYDEF_OFLAG; 56934832Speter pp->sp_iin.c_cflag = TTYDEF_CFLAG; 57034832Speter pp->sp_iin.c_lflag = TTYDEF_LFLAG; 57134832Speter termioschars(&pp->sp_iin); 57234832Speter pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = 57334832Speter TTYDEF_SPEED;; 57434832Speter pp->sp_iout = pp->sp_iin; 57534832Speter } 57634832Spetertry_next2: 57710015Speter if (modp->sm_next == 0) { 57834832Speter printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n", 57910015Speter unit, 58010015Speter sc->sc_typename, 58110015Speter sc->sc_nport, 58212174Speter nmodule, 58334832Speter uart_type, 58434832Speter si_modulename(sc->sc_type, uart_type)); 58510015Speter break; 58610015Speter } 58710015Speter modp = (struct si_module *) 58810015Speter (maddr + (unsigned)(modp->sm_next & 0x7fff)); 58910015Speter } 59010015Speter if (done_chartimes == 0) { 59110015Speter for (spt = chartimes ; spt->sp_speed != -1; spt++) { 59210015Speter if ((spt->sp_code /= hz) == 0) 59310015Speter spt->sp_code = 1; 59410015Speter } 59510015Speter done_chartimes = 1; 59610015Speter } 59712502Sjulian 59812675Sjulian/* path name devsw minor type uid gid perm*/ 59950442Speter for (x = 0; x < sc->sc_nport; x++) { 60034735Speter /* sync with the manuals that start at 1 */ 60156498Speter y = x + 1 + unit * (1 << SI_CARDSHIFT); 60250442Speter make_dev(&si_cdevsw, x, 0, 0, 0600, "ttyA%02d", y); 60350442Speter make_dev(&si_cdevsw, x + 0x00080, 0, 0, 0600, "cuaA%02d", y); 60450442Speter make_dev(&si_cdevsw, x + 0x10000, 0, 0, 0600, "ttyiA%02d", y); 60550442Speter make_dev(&si_cdevsw, x + 0x10080, 0, 0, 0600, "cuaiA%02d", y); 60650442Speter make_dev(&si_cdevsw, x + 0x20000, 0, 0, 0600, "ttylA%02d", y); 60750442Speter make_dev(&si_cdevsw, x + 0x20080, 0, 0, 0600, "cualA%02d", y); 60812675Sjulian } 60950254Sphk make_dev(&si_cdevsw, 0x40000, 0, 0, 0600, "si_control"); 61056498Speter return (0); 61110015Speter} 61210015Speter 61312675Sjulianstatic int 61456498Spetersiopen(dev_t dev, int flag, int mode, struct proc *p) 61510015Speter{ 61610015Speter int oldspl, error; 61710015Speter int card, port; 61856498Speter struct si_softc *sc; 61956498Speter struct tty *tp; 62010015Speter volatile struct si_channel *ccbp; 62110015Speter struct si_port *pp; 62210015Speter int mynor = minor(dev); 62310015Speter 62410015Speter /* quickly let in /dev/si_control */ 62510015Speter if (IS_CONTROLDEV(mynor)) { 62646112Sphk if ((error = suser(p))) 62710015Speter return(error); 62810015Speter return(0); 62910015Speter } 63010015Speter 63110015Speter card = SI_CARD(mynor); 63256498Speter sc = devclass_get_softc(si_devclass, card); 63356498Speter if (sc == NULL) 63410015Speter return (ENXIO); 63510015Speter 63612174Speter if (sc->sc_type == SIEMPTY) { 63712174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", 63810015Speter card, sc->sc_typename)); 63910015Speter return(ENXIO); 64010015Speter } 64110015Speter 64210015Speter port = SI_PORT(mynor); 64310015Speter if (port >= sc->sc_nport) { 64412174Speter DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", 64510015Speter card, sc->sc_nport)); 64610015Speter return(ENXIO); 64710015Speter } 64810015Speter 64910015Speter#ifdef POLL 65010015Speter /* 65110015Speter * We've now got a device, so start the poller. 65210015Speter */ 65310015Speter if (init_finished == 0) { 65415639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 65510015Speter init_finished = 1; 65610015Speter } 65710015Speter#endif 65810015Speter 65910015Speter /* initial/lock device */ 66010015Speter if (IS_STATE(mynor)) { 66110015Speter return(0); 66210015Speter } 66310015Speter 66410015Speter pp = sc->sc_ports + port; 66510015Speter tp = pp->sp_tty; /* the "real" tty */ 66651654Sphk dev->si_tty = tp; 66710015Speter ccbp = pp->sp_ccb; /* Find control block */ 66850016Snsayer DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%s,%x,%x,%x)\n", 66950016Snsayer devtoname(dev), flag, mode, p)); 67010015Speter 67110015Speter oldspl = spltty(); /* Keep others out */ 67210015Speter error = 0; 67310015Speter 67410015Speteropen_top: 67510015Speter while (pp->sp_state & SS_DTR_OFF) { 67610015Speter error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); 67710015Speter if (error != 0) 67810015Speter goto out; 67910015Speter } 68010015Speter 68110015Speter if (tp->t_state & TS_ISOPEN) { 68210015Speter /* 68310015Speter * The device is open, so everything has been initialised. 68410015Speter * handle conflicts. 68510015Speter */ 68610015Speter if (IS_CALLOUT(mynor)) { 68710015Speter if (!pp->sp_active_out) { 68810015Speter error = EBUSY; 68910015Speter goto out; 69010015Speter } 69110015Speter } else { 69210015Speter if (pp->sp_active_out) { 69310015Speter if (flag & O_NONBLOCK) { 69410015Speter error = EBUSY; 69510015Speter goto out; 69610015Speter } 69710015Speter error = tsleep(&pp->sp_active_out, 69810015Speter TTIPRI|PCATCH, "sibi", 0); 69910015Speter if (error != 0) 70010015Speter goto out; 70110015Speter goto open_top; 70210015Speter } 70310015Speter } 70443425Sphk if (tp->t_state & TS_XCLUDE && 70546112Sphk suser(p)) { 70610015Speter DPRINT((pp, DBG_OPEN|DBG_FAIL, 70710015Speter "already open and EXCLUSIVE set\n")); 70810015Speter error = EBUSY; 70910015Speter goto out; 71010015Speter } 71110015Speter } else { 71210015Speter /* 71310015Speter * The device isn't open, so there are no conflicts. 71410015Speter * Initialize it. Avoid sleep... :-) 71510015Speter */ 71610015Speter DPRINT((pp, DBG_OPEN, "first open\n")); 71710015Speter tp->t_oproc = si_start; 71851654Sphk tp->t_stop = si_stop; 71910015Speter tp->t_param = siparam; 72010015Speter tp->t_dev = dev; 72110015Speter tp->t_termios = mynor & SI_CALLOUT_MASK 72210015Speter ? pp->sp_iout : pp->sp_iin; 72310015Speter 72410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 72510015Speter 72610015Speter ++pp->sp_wopeners; /* in case of sleep in siparam */ 72710015Speter 72810015Speter error = siparam(tp, &tp->t_termios); 72910015Speter 73010015Speter --pp->sp_wopeners; 73110015Speter if (error != 0) 73210015Speter goto out; 73310015Speter /* XXX: we should goto_top if siparam slept */ 73410015Speter 73510015Speter /* set initial DCD state */ 73610015Speter pp->sp_last_hi_ip = ccbp->hi_ip; 73710015Speter if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { 73810015Speter (*linesw[tp->t_line].l_modem)(tp, 1); 73910015Speter } 74010015Speter } 74110015Speter 74210015Speter /* whoops! we beat the close! */ 74310015Speter if (pp->sp_state & SS_CLOSING) { 74410015Speter /* try and stop it from proceeding to bash the hardware */ 74510015Speter pp->sp_state &= ~SS_CLOSING; 74610015Speter } 74710015Speter 74810015Speter /* 74910015Speter * Wait for DCD if necessary 75010015Speter */ 75150442Speter if (!(tp->t_state & TS_CARR_ON) && 75250442Speter !IS_CALLOUT(mynor) && 75350442Speter !(tp->t_cflag & CLOCAL) && 75450442Speter !(flag & O_NONBLOCK)) { 75510015Speter ++pp->sp_wopeners; 75610015Speter DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); 75710015Speter error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); 75810015Speter --pp->sp_wopeners; 75910015Speter if (error != 0) 76010015Speter goto out; 76110015Speter goto open_top; 76210015Speter } 76310015Speter 76410015Speter error = (*linesw[tp->t_line].l_open)(dev, tp); 76510015Speter si_disc_optim(tp, &tp->t_termios, pp); 76610015Speter if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) 76710015Speter pp->sp_active_out = TRUE; 76810015Speter 76910015Speter pp->sp_state |= SS_OPEN; /* made it! */ 77010015Speter 77110015Speterout: 77210015Speter splx(oldspl); 77310015Speter 77410015Speter DPRINT((pp, DBG_OPEN, "leaving siopen\n")); 77510015Speter 77610015Speter if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) 77710015Speter sihardclose(pp); 77810015Speter 77910015Speter return(error); 78010015Speter} 78110015Speter 78212675Sjulianstatic int 78356498Spetersiclose(dev_t dev, int flag, int mode, struct proc *p) 78410015Speter{ 78556498Speter struct si_port *pp; 78656498Speter struct tty *tp; 78710015Speter int oldspl; 78810015Speter int error = 0; 78910015Speter int mynor = minor(dev); 79010015Speter 79110015Speter if (IS_SPECIAL(mynor)) 79210015Speter return(0); 79310015Speter 79410015Speter oldspl = spltty(); 79510015Speter 79610015Speter pp = MINOR2PP(mynor); 79710015Speter tp = pp->sp_tty; 79810015Speter 79950016Snsayer DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%s,%x,%x,%x) sp_state:%x\n", 80050016Snsayer devtoname(dev), flag, mode, p, pp->sp_state)); 80110015Speter 80210015Speter /* did we sleep and loose a race? */ 80310015Speter if (pp->sp_state & SS_CLOSING) { 80410015Speter /* error = ESOMETING? */ 80510015Speter goto out; 80610015Speter } 80710015Speter 80810015Speter /* begin race detection.. */ 80910015Speter pp->sp_state |= SS_CLOSING; 81010015Speter 81110015Speter si_write_enable(pp, 0); /* block writes for ttywait() */ 81210015Speter 81310015Speter /* THIS MAY SLEEP IN TTYWAIT!!! */ 81410015Speter (*linesw[tp->t_line].l_close)(tp, flag); 81510015Speter 81610015Speter si_write_enable(pp, 1); 81710015Speter 81810015Speter /* did we sleep and somebody started another open? */ 81910015Speter if (!(pp->sp_state & SS_CLOSING)) { 82010015Speter /* error = ESOMETING? */ 82110015Speter goto out; 82210015Speter } 82310015Speter /* ok. we are now still on the right track.. nuke the hardware */ 82410015Speter 82510015Speter if (pp->sp_state & SS_LSTART) { 82629677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 82710015Speter pp->sp_state &= ~SS_LSTART; 82810015Speter } 82910015Speter 83051654Sphk si_stop(tp, FREAD | FWRITE); 83110015Speter 83210015Speter sihardclose(pp); 83310015Speter ttyclose(tp); 83410015Speter pp->sp_state &= ~SS_OPEN; 83510015Speter 83610015Speterout: 83710015Speter DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); 83810015Speter splx(oldspl); 83910015Speter return(error); 84010015Speter} 84110015Speter 84210015Speterstatic void 84356498Spetersihardclose(struct si_port *pp) 84410015Speter{ 84510015Speter int oldspl; 84610015Speter struct tty *tp; 84710015Speter volatile struct si_channel *ccbp; 84810015Speter 84910015Speter oldspl = spltty(); 85010015Speter 85110015Speter tp = pp->sp_tty; 85210015Speter ccbp = pp->sp_ccb; /* Find control block */ 85350442Speter if (tp->t_cflag & HUPCL || 85450442Speter (!pp->sp_active_out && 85550442Speter !(ccbp->hi_ip & IP_DCD) && 85650442Speter !(pp->sp_iin.c_cflag && CLOCAL)) || 85750442Speter !(tp->t_state & TS_ISOPEN)) { 85810015Speter 85910015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 86010015Speter (void) si_command(pp, FCLOSE, SI_NOWAIT); 86110015Speter 86210015Speter if (pp->sp_dtr_wait != 0) { 86310015Speter timeout(sidtrwakeup, pp, pp->sp_dtr_wait); 86410015Speter pp->sp_state |= SS_DTR_OFF; 86510015Speter } 86610015Speter 86710015Speter } 86810015Speter pp->sp_active_out = FALSE; 86910015Speter wakeup((caddr_t)&pp->sp_active_out); 87010015Speter wakeup(TSA_CARR_ON(tp)); 87110015Speter 87210015Speter splx(oldspl); 87310015Speter} 87410015Speter 87510015Speter 87610015Speter/* 87710015Speter * called at splsoftclock()... 87810015Speter */ 87910015Speterstatic void 88056498Spetersidtrwakeup(void *chan) 88110015Speter{ 88210015Speter struct si_port *pp; 88310015Speter int oldspl; 88410015Speter 88510015Speter oldspl = spltty(); 88610015Speter 88710015Speter pp = (struct si_port *)chan; 88810015Speter pp->sp_state &= ~SS_DTR_OFF; 88910015Speter wakeup(&pp->sp_dtr_wait); 89010015Speter 89110015Speter splx(oldspl); 89210015Speter} 89310015Speter 89412675Sjulianstatic int 89556498Spetersiwrite(dev_t dev, struct uio *uio, int flag) 89610015Speter{ 89756498Speter struct si_port *pp; 89856498Speter struct tty *tp; 89910015Speter int error = 0; 90010015Speter int mynor = minor(dev); 90110015Speter int oldspl; 90210015Speter 90310015Speter if (IS_SPECIAL(mynor)) { 90410015Speter DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); 90510015Speter return(ENODEV); 90610015Speter } 90710015Speter pp = MINOR2PP(mynor); 90810015Speter tp = pp->sp_tty; 90950016Snsayer DPRINT((pp, DBG_WRITE, "siwrite(%s,%x,%x)\n", devtoname(dev), uio, flag)); 91010015Speter 91110015Speter oldspl = spltty(); 91210015Speter /* 91310015Speter * If writes are currently blocked, wait on the "real" tty 91410015Speter */ 91510015Speter while (pp->sp_state & SS_BLOCKWRITE) { 91610015Speter pp->sp_state |= SS_WAITWRITE; 91710015Speter DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); 91818515Speter if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, 91918515Speter "siwrite", tp->t_timeout))) { 92017291Speter if (error == EWOULDBLOCK) 92117290Speter error = EIO; 92210015Speter goto out; 92317290Speter } 92410015Speter } 92510015Speter 92610015Speter error = (*linesw[tp->t_line].l_write)(tp, uio, flag); 92710015Speterout: 92810015Speter splx(oldspl); 92910015Speter return (error); 93010015Speter} 93110015Speter 93210015Speter 93312675Sjulianstatic int 93456498Spetersiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 93510015Speter{ 93610015Speter struct si_port *pp; 93756498Speter struct tty *tp; 93810015Speter int error; 93910015Speter int mynor = minor(dev); 94010015Speter int oldspl; 94110015Speter int blocked = 0; 94210015Speter#if defined(COMPAT_43) 94338351Sbde u_long oldcmd; 94410015Speter struct termios term; 94510015Speter#endif 94610015Speter 94710015Speter if (IS_SI_IOCTL(cmd)) 94810015Speter return(si_Sioctl(dev, cmd, data, flag, p)); 94910015Speter 95010015Speter pp = MINOR2PP(mynor); 95110015Speter tp = pp->sp_tty; 95210015Speter 95350016Snsayer DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%s,%lx,%x,%x)\n", 95450016Snsayer devtoname(dev), cmd, data, flag)); 95510015Speter if (IS_STATE(mynor)) { 95610015Speter struct termios *ct; 95710015Speter 95810015Speter switch (mynor & SI_STATE_MASK) { 95910015Speter case SI_INIT_STATE_MASK: 96010015Speter ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; 96110015Speter break; 96210015Speter case SI_LOCK_STATE_MASK: 96316839Speter ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; 96410015Speter break; 96510015Speter default: 96610015Speter return (ENODEV); 96710015Speter } 96810015Speter switch (cmd) { 96910015Speter case TIOCSETA: 97046112Sphk error = suser(p); 97110015Speter if (error != 0) 97210015Speter return (error); 97310015Speter *ct = *(struct termios *)data; 97410015Speter return (0); 97510015Speter case TIOCGETA: 97610015Speter *(struct termios *)data = *ct; 97710015Speter return (0); 97810015Speter case TIOCGETD: 97910015Speter *(int *)data = TTYDISC; 98010015Speter return (0); 98110015Speter case TIOCGWINSZ: 98210015Speter bzero(data, sizeof(struct winsize)); 98310015Speter return (0); 98410015Speter default: 98510015Speter return (ENOTTY); 98610015Speter } 98710015Speter } 98810015Speter /* 98910015Speter * Do the old-style ioctl compat routines... 99010015Speter */ 99110015Speter#if defined(COMPAT_43) 99210015Speter term = tp->t_termios; 99310015Speter oldcmd = cmd; 99410015Speter error = ttsetcompat(tp, &cmd, data, &term); 99510015Speter if (error != 0) 99610015Speter return (error); 99710015Speter if (cmd != oldcmd) 99810015Speter data = (caddr_t)&term; 99910015Speter#endif 100010015Speter /* 100110015Speter * Do the initial / lock state business 100210015Speter */ 100310015Speter if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 100410015Speter int cc; 100510015Speter struct termios *dt = (struct termios *)data; 100610015Speter struct termios *lt = mynor & SI_CALLOUT_MASK 100710015Speter ? &pp->sp_lout : &pp->sp_lin; 100810015Speter 100950442Speter dt->c_iflag = (tp->t_iflag & lt->c_iflag) | 101050442Speter (dt->c_iflag & ~lt->c_iflag); 101150442Speter dt->c_oflag = (tp->t_oflag & lt->c_oflag) | 101250442Speter (dt->c_oflag & ~lt->c_oflag); 101350442Speter dt->c_cflag = (tp->t_cflag & lt->c_cflag) | 101450442Speter (dt->c_cflag & ~lt->c_cflag); 101550442Speter dt->c_lflag = (tp->t_lflag & lt->c_lflag) | 101650442Speter (dt->c_lflag & ~lt->c_lflag); 101710015Speter for (cc = 0; cc < NCCS; ++cc) 101810015Speter if (lt->c_cc[cc] != 0) 101910015Speter dt->c_cc[cc] = tp->t_cc[cc]; 102010015Speter if (lt->c_ispeed != 0) 102110015Speter dt->c_ispeed = tp->t_ispeed; 102210015Speter if (lt->c_ospeed != 0) 102310015Speter dt->c_ospeed = tp->t_ospeed; 102410015Speter } 102510015Speter 102610015Speter /* 102710015Speter * Block user-level writes to give the ttywait() 102810015Speter * a chance to completely drain for commands 102910015Speter * that require the port to be in a quiescent state. 103010015Speter */ 103110015Speter switch (cmd) { 103234832Speter case TIOCSETAW: 103334832Speter case TIOCSETAF: 103417396Speter case TIOCDRAIN: 103517396Speter#ifdef COMPAT_43 103617396Speter case TIOCSETP: 103717396Speter#endif 103810015Speter blocked++; /* block writes for ttywait() and siparam() */ 103910015Speter si_write_enable(pp, 0); 104010015Speter } 104110015Speter 104210015Speter error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 104331577Sbde if (error != ENOIOCTL) 104410015Speter goto out; 104510015Speter 104610015Speter oldspl = spltty(); 104710015Speter 104810015Speter error = ttioctl(tp, cmd, data, flag); 104910015Speter si_disc_optim(tp, &tp->t_termios, pp); 105050435Speter if (error != ENOIOCTL) { 105150435Speter splx(oldspl); 105250435Speter goto out; 105350435Speter } 105410015Speter 105550435Speter error = 0; 105610015Speter switch (cmd) { 105710015Speter case TIOCSBRK: 105816575Speter si_command(pp, SBREAK, SI_WAIT); 105910015Speter break; 106010015Speter case TIOCCBRK: 106116575Speter si_command(pp, EBREAK, SI_WAIT); 106210015Speter break; 106310015Speter case TIOCSDTR: 106410015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 106510015Speter break; 106610015Speter case TIOCCDTR: 106710015Speter (void) si_modem(pp, SET, 0); 106810015Speter break; 106910015Speter case TIOCMSET: 107010015Speter (void) si_modem(pp, SET, *(int *)data); 107110015Speter break; 107210015Speter case TIOCMBIS: 107310015Speter (void) si_modem(pp, BIS, *(int *)data); 107410015Speter break; 107510015Speter case TIOCMBIC: 107610015Speter (void) si_modem(pp, BIC, *(int *)data); 107710015Speter break; 107810015Speter case TIOCMGET: 107910015Speter *(int *)data = si_modem(pp, GET, 0); 108010015Speter break; 108110015Speter case TIOCMSDTRWAIT: 108210015Speter /* must be root since the wait applies to following logins */ 108346112Sphk error = suser(p); 108450435Speter if (error == 0) 108550435Speter pp->sp_dtr_wait = *(int *)data * hz / 100; 108610015Speter break; 108710015Speter case TIOCMGDTRWAIT: 108810015Speter *(int *)data = pp->sp_dtr_wait * 100 / hz; 108910015Speter break; 109010015Speter default: 109110015Speter error = ENOTTY; 109210015Speter } 109310015Speter splx(oldspl); 109450435Speter 109510015Speterout: 109610015Speter DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error)); 109710015Speter if (blocked) 109810015Speter si_write_enable(pp, 1); 109910015Speter return(error); 110010015Speter} 110110015Speter 110210015Speter/* 110310015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device 110410015Speter */ 110510015Speterstatic int 110638351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 110710015Speter{ 110810015Speter struct si_softc *xsc; 110956498Speter struct si_port *xpp; 111010015Speter volatile struct si_reg *regp; 111110015Speter struct si_tcsi *dp; 111210044Speter struct si_pstat *sps; 111311872Sphk int *ip, error = 0; 111410015Speter int oldspl; 111510015Speter int card, port; 111610015Speter int mynor = minor(dev); 111710015Speter 111850016Snsayer DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n", 111950016Snsayer devtoname(dev), cmd, data, flag)); 112010015Speter 112110044Speter#if 1 112210044Speter DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT)); 112310044Speter DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB)); 112410044Speter DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY)); 112510044Speter#endif 112610044Speter 112710015Speter if (!IS_CONTROLDEV(mynor)) { 112810015Speter DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n")); 112910015Speter return(ENODEV); 113010015Speter } 113110015Speter 113210015Speter oldspl = spltty(); /* better safe than sorry */ 113310015Speter 113410015Speter ip = (int *)data; 113510015Speter 113646112Sphk#define SUCHECK if ((error = suser(p))) goto out 113710015Speter 113810015Speter switch (cmd) { 113910015Speter case TCSIPORTS: 114010015Speter *ip = si_Nports; 114110015Speter goto out; 114210015Speter case TCSIMODULES: 114310015Speter *ip = si_Nmodules; 114410015Speter goto out; 114510015Speter case TCSISDBG_ALL: 114610015Speter SUCHECK; 114710015Speter si_debug = *ip; 114810015Speter goto out; 114910015Speter case TCSIGDBG_ALL: 115010015Speter *ip = si_debug; 115110015Speter goto out; 115210015Speter default: 115310015Speter /* 115410015Speter * Check that a controller for this port exists 115510015Speter */ 115610044Speter 115710044Speter /* may also be a struct si_pstat, a superset of si_tcsi */ 115810044Speter 115910015Speter dp = (struct si_tcsi *)data; 116010044Speter sps = (struct si_pstat *)data; 116110015Speter card = dp->tc_card; 116256498Speter xsc = devclass_get_softc(si_devclass, card); /* check.. */ 116356498Speter if (xsc == NULL || xsc->sc_type == SIEMPTY) { 116410015Speter error = ENOENT; 116510015Speter goto out; 116610015Speter } 116710015Speter /* 116810015Speter * And check that a port exists 116910015Speter */ 117010015Speter port = dp->tc_port; 117110015Speter if (port < 0 || port >= xsc->sc_nport) { 117210015Speter error = ENOENT; 117310015Speter goto out; 117410015Speter } 117510015Speter xpp = xsc->sc_ports + port; 117610015Speter regp = (struct si_reg *)xsc->sc_maddr; 117710015Speter } 117810015Speter 117910015Speter switch (cmd) { 118010015Speter case TCSIDEBUG: 118110015Speter#ifdef SI_DEBUG 118210015Speter SUCHECK; 118310015Speter if (xpp->sp_debug) 118410015Speter xpp->sp_debug = 0; 118510015Speter else { 118610015Speter xpp->sp_debug = DBG_ALL; 118710015Speter DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n", 118810015Speter (xpp->sp_debug&DBG_ALL)?"ON":"OFF")); 118910015Speter } 119010015Speter break; 119110015Speter#else 119210015Speter error = ENODEV; 119310015Speter goto out; 119410015Speter#endif 119510015Speter case TCSISDBG_LEVEL: 119610015Speter case TCSIGDBG_LEVEL: 119710015Speter#ifdef SI_DEBUG 119810015Speter if (cmd == TCSIGDBG_LEVEL) { 119910015Speter dp->tc_dbglvl = xpp->sp_debug; 120010015Speter } else { 120110015Speter SUCHECK; 120210015Speter xpp->sp_debug = dp->tc_dbglvl; 120310015Speter } 120410015Speter break; 120510015Speter#else 120610015Speter error = ENODEV; 120710015Speter goto out; 120810015Speter#endif 120910015Speter case TCSIGRXIT: 121010015Speter dp->tc_int = regp->rx_int_count; 121110015Speter break; 121210015Speter case TCSIRXIT: 121310015Speter SUCHECK; 121410015Speter regp->rx_int_count = dp->tc_int; 121510015Speter break; 121610015Speter case TCSIGIT: 121710015Speter dp->tc_int = regp->int_count; 121810015Speter break; 121910015Speter case TCSIIT: 122010015Speter SUCHECK; 122110015Speter regp->int_count = dp->tc_int; 122210015Speter break; 122310044Speter case TCSISTATE: 122410044Speter dp->tc_int = xpp->sp_ccb->hi_ip; 122510015Speter break; 122610044Speter /* these next three use a different structure */ 122710044Speter case TCSI_PORT: 122810015Speter SUCHECK; 122934832Speter si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport)); 123010015Speter break; 123110044Speter case TCSI_CCB: 123210044Speter SUCHECK; 123350442Speter si_vbcopy(xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb)); 123410015Speter break; 123510044Speter case TCSI_TTY: 123610044Speter SUCHECK; 123734832Speter si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty)); 123810015Speter break; 123910015Speter default: 124010015Speter error = EINVAL; 124110015Speter goto out; 124210015Speter } 124310015Speterout: 124410015Speter splx(oldspl); 124510015Speter return(error); /* success */ 124610015Speter} 124710015Speter 124810015Speter/* 124910015Speter * siparam() : Configure line params 125010015Speter * called at spltty(); 125110015Speter * this may sleep, does not flush, nor wait for drain, nor block writes 125210015Speter * caller must arrange this if it's important.. 125310015Speter */ 125412724Sphkstatic int 125556498Spetersiparam(struct tty *tp, struct termios *t) 125610015Speter{ 125756498Speter struct si_port *pp = TP2PP(tp); 125810015Speter volatile struct si_channel *ccbp; 125910015Speter int oldspl, cflag, iflag, oflag, lflag; 126010015Speter int error = 0; /* shutup gcc */ 126110015Speter int ispeed = 0; /* shutup gcc */ 126210015Speter int ospeed = 0; /* shutup gcc */ 126310161Speter BYTE val; 126410015Speter 126510015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t)); 126610015Speter cflag = t->c_cflag; 126710015Speter iflag = t->c_iflag; 126810015Speter oflag = t->c_oflag; 126910015Speter lflag = t->c_lflag; 127010044Speter DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n", 127110044Speter oflag, cflag, iflag, lflag)); 127210015Speter 127334832Speter /* XXX - if Jet host and SXDC module, use extended baud rates */ 127410015Speter 127510015Speter /* if not hung up.. */ 127610015Speter if (t->c_ospeed != 0) { 127710015Speter /* translate baud rate to firmware values */ 127810015Speter ospeed = ttspeedtab(t->c_ospeed, bdrates); 127910015Speter ispeed = t->c_ispeed ? 128010015Speter ttspeedtab(t->c_ispeed, bdrates) : ospeed; 128110015Speter 128210015Speter /* enforce legit baud rate */ 128310015Speter if (ospeed < 0 || ispeed < 0) 128410015Speter return (EINVAL); 128510015Speter } 128610015Speter 128710015Speter oldspl = spltty(); 128810015Speter 128910015Speter ccbp = pp->sp_ccb; 129010015Speter 129110161Speter /* ========== set hi_break ========== */ 129210161Speter val = 0; 129310161Speter if (iflag & IGNBRK) /* Breaks */ 129410161Speter val |= BR_IGN; 129510161Speter if (iflag & BRKINT) /* Interrupt on break? */ 129610161Speter val |= BR_INT; 129710161Speter if (iflag & PARMRK) /* Parity mark? */ 129810161Speter val |= BR_PARMRK; 129910161Speter if (iflag & IGNPAR) /* Ignore chars with parity errors? */ 130010161Speter val |= BR_PARIGN; 130110161Speter ccbp->hi_break = val; 130210161Speter 130310161Speter /* ========== set hi_csr ========== */ 130410015Speter /* if not hung up.. */ 130510015Speter if (t->c_ospeed != 0) { 130610015Speter /* Set I/O speeds */ 130710161Speter val = (ispeed << 4) | ospeed; 130810015Speter } 130910161Speter ccbp->hi_csr = val; 131010015Speter 131110161Speter /* ========== set hi_mr2 ========== */ 131210161Speter val = 0; 131310015Speter if (cflag & CSTOPB) /* Stop bits */ 131410161Speter val |= MR2_2_STOP; 131510015Speter else 131610161Speter val |= MR2_1_STOP; 131710161Speter /* 131810161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 131910161Speter * a DCE, hence the reverse sense of RTS and CTS 132010161Speter */ 132110161Speter /* Output Flow - RTS must be raised before data can be sent */ 132210161Speter if (cflag & CCTS_OFLOW) 132310161Speter val |= MR2_RTSCONT; 132410161Speter 132516575Speter ccbp->hi_mr2 = val; 132610161Speter 132710161Speter /* ========== set hi_mr1 ========== */ 132810161Speter val = 0; 132910015Speter if (!(cflag & PARENB)) /* Parity */ 133010161Speter val |= MR1_NONE; 133110015Speter else 133210161Speter val |= MR1_WITH; 133310015Speter if (cflag & PARODD) 133410161Speter val |= MR1_ODD; 133510015Speter 133610015Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 133710161Speter val |= MR1_8_BITS; 133810015Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 133910161Speter val |= MR1_7_BITS; 134010015Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 134110161Speter val |= MR1_6_BITS; 134210015Speter } else { /* Must be 5 */ 134310161Speter val |= MR1_5_BITS; 134410015Speter } 134510161Speter /* 134610161Speter * Enable H/W RTS/CTS handshaking. The default TA/MTA is 134710161Speter * a DCE, hence the reverse sense of RTS and CTS 134810161Speter */ 134910161Speter /* Input Flow - CTS is raised when port is ready to receive data */ 135010161Speter if (cflag & CRTS_IFLOW) 135110161Speter val |= MR1_CTSCONT; 135210015Speter 135310161Speter ccbp->hi_mr1 = val; 135410161Speter 135510161Speter /* ========== set hi_mask ========== */ 135610161Speter val = 0xff; 135710161Speter if ((cflag & CS8) == CS8) { /* 8 data bits? */ 135810161Speter val &= 0xFF; 135910161Speter } else if ((cflag & CS7) == CS7) { /* 7 data bits? */ 136010161Speter val &= 0x7F; 136110161Speter } else if ((cflag & CS6) == CS6) { /* 6 data bits? */ 136210161Speter val &= 0x3F; 136310161Speter } else { /* Must be 5 */ 136410161Speter val &= 0x1F; 136510161Speter } 136610015Speter if (iflag & ISTRIP) 136710161Speter val &= 0x7F; 136810015Speter 136910161Speter ccbp->hi_mask = val; 137010161Speter 137110161Speter /* ========== set hi_prtcl ========== */ 137256592Speter val = SP_DCEN; /* Monitor DCD always, or TIOCMGET misses it */ 137310161Speter if (iflag & IXANY) 137410161Speter val |= SP_TANY; 137510161Speter if (iflag & IXON) 137610161Speter val |= SP_TXEN; 137710161Speter if (iflag & IXOFF) 137810161Speter val |= SP_RXEN; 137910161Speter if (iflag & INPCK) 138010161Speter val |= SP_PAEN; 138110015Speter 138210161Speter ccbp->hi_prtcl = val; 138310161Speter 138410161Speter 138510161Speter /* ========== set hi_{rx|tx}{on|off} ========== */ 138610161Speter /* XXX: the card TOTALLY shields us from the flow control... */ 138710015Speter ccbp->hi_txon = t->c_cc[VSTART]; 138810015Speter ccbp->hi_txoff = t->c_cc[VSTOP]; 138910015Speter 139010015Speter ccbp->hi_rxon = t->c_cc[VSTART]; 139110015Speter ccbp->hi_rxoff = t->c_cc[VSTOP]; 139210015Speter 139310161Speter /* ========== send settings to the card ========== */ 139410015Speter /* potential sleep here */ 139510015Speter if (ccbp->hi_stat == IDLE_CLOSE) /* Not yet open */ 139610015Speter si_command(pp, LOPEN, SI_WAIT); /* open it */ 139710015Speter else 139810015Speter si_command(pp, CONFIG, SI_WAIT); /* change params */ 139910015Speter 140010161Speter /* ========== set DTR etc ========== */ 140110015Speter /* Hangup if ospeed == 0 */ 140210015Speter if (t->c_ospeed == 0) { 140310015Speter (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); 140410015Speter } else { 140510015Speter /* 140610015Speter * If the previous speed was 0, may need to re-enable 140734832Speter * the modem signals 140834832Speter */ 140910015Speter (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); 141010015Speter } 141110015Speter 141210044Speter DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n", 141310044Speter ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break)); 141410015Speter 141510015Speter splx(oldspl); 141610015Speter return(error); 141710015Speter} 141810015Speter 141910015Speter/* 142010015Speter * Enable or Disable the writes to this channel... 142110015Speter * "state" -> enabled = 1; disabled = 0; 142210015Speter */ 142310015Speterstatic void 142456498Spetersi_write_enable(struct si_port *pp, int state) 142510015Speter{ 142610015Speter int oldspl; 142710015Speter 142810015Speter oldspl = spltty(); 142910015Speter 143010015Speter if (state) { 143110015Speter pp->sp_state &= ~SS_BLOCKWRITE; 143210015Speter if (pp->sp_state & SS_WAITWRITE) { 143310015Speter pp->sp_state &= ~SS_WAITWRITE; 143410015Speter /* thunder away! */ 143510015Speter wakeup((caddr_t)pp); 143610015Speter } 143710015Speter } else { 143810015Speter pp->sp_state |= SS_BLOCKWRITE; 143910015Speter } 144010015Speter 144110015Speter splx(oldspl); 144210015Speter} 144310015Speter 144410015Speter/* 144510015Speter * Set/Get state of modem control lines. 144610015Speter * Due to DCE-like behaviour of the adapter, some signals need translation: 144710015Speter * TIOCM_DTR DSR 144810015Speter * TIOCM_RTS CTS 144910015Speter */ 145010015Speterstatic int 145156498Spetersi_modem(struct si_port *pp, enum si_mctl cmd, int bits) 145210015Speter{ 145310015Speter volatile struct si_channel *ccbp; 145410015Speter int x; 145510015Speter 145610015Speter DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits)); 145710015Speter ccbp = pp->sp_ccb; /* Find channel address */ 145810015Speter switch (cmd) { 145910015Speter case GET: 146010015Speter x = ccbp->hi_ip; 146110015Speter bits = TIOCM_LE; 146210015Speter if (x & IP_DCD) bits |= TIOCM_CAR; 146310015Speter if (x & IP_DTR) bits |= TIOCM_DTR; 146410015Speter if (x & IP_RTS) bits |= TIOCM_RTS; 146510015Speter if (x & IP_RI) bits |= TIOCM_RI; 146610015Speter return(bits); 146710015Speter case SET: 146810015Speter ccbp->hi_op &= ~(OP_DSR|OP_CTS); 146910015Speter /* fall through */ 147010015Speter case BIS: 147110015Speter x = 0; 147210015Speter if (bits & TIOCM_DTR) 147310015Speter x |= OP_DSR; 147410015Speter if (bits & TIOCM_RTS) 147510015Speter x |= OP_CTS; 147610015Speter ccbp->hi_op |= x; 147710015Speter break; 147810015Speter case BIC: 147910015Speter if (bits & TIOCM_DTR) 148010015Speter ccbp->hi_op &= ~OP_DSR; 148110015Speter if (bits & TIOCM_RTS) 148210015Speter ccbp->hi_op &= ~OP_CTS; 148310015Speter } 148410015Speter return 0; 148510015Speter} 148610015Speter 148710015Speter/* 148810015Speter * Handle change of modem state 148910015Speter */ 149010015Speterstatic void 149156498Spetersi_modem_state(struct si_port *pp, struct tty *tp, int hi_ip) 149210015Speter{ 149310015Speter /* if a modem dev */ 149410015Speter if (hi_ip & IP_DCD) { 149550442Speter if (!(pp->sp_last_hi_ip & IP_DCD)) { 149610015Speter DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n", 149710015Speter tp->t_line)); 149810015Speter (void)(*linesw[tp->t_line].l_modem)(tp, 1); 149910015Speter } 150010015Speter } else { 150110015Speter if (pp->sp_last_hi_ip & IP_DCD) { 150210015Speter DPRINT((pp, DBG_INTR, "modem carr off\n")); 150310015Speter if ((*linesw[tp->t_line].l_modem)(tp, 0)) 150410015Speter (void) si_modem(pp, SET, 0); 150510015Speter } 150610015Speter } 150710015Speter pp->sp_last_hi_ip = hi_ip; 150810015Speter 150910015Speter} 151010015Speter 151110015Speter/* 151210015Speter * Poller to catch missed interrupts. 151312174Speter * 151412496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get 151512496Speter * better response. We could really use a "periodic" version timeout(). :-) 151610015Speter */ 151710015Speter#ifdef POLL 151810708Speterstatic void 151910015Spetersi_poll(void *nothing) 152010015Speter{ 152156498Speter struct si_softc *sc; 152256498Speter int i; 152310015Speter volatile struct si_reg *regp; 152456498Speter struct si_port *pp; 152512174Speter int lost, oldspl, port; 152610015Speter 152710015Speter DPRINT((0, DBG_POLL, "si_poll()\n")); 152811609Speter oldspl = spltty(); 152910015Speter if (in_intr) 153010015Speter goto out; 153110015Speter lost = 0; 153256498Speter for (i = 0; i < si_numunits; i++) { 153356498Speter sc = devclass_get_softc(si_devclass, i); 153456498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 153510015Speter continue; 153610015Speter regp = (struct si_reg *)sc->sc_maddr; 153734832Speter 153810015Speter /* 153910015Speter * See if there has been a pending interrupt for 2 seconds 154033395Speter * or so. The test (int_scounter >= 200) won't correspond 154110015Speter * to 2 seconds if int_count gets changed. 154210015Speter */ 154310015Speter if (regp->int_pending != 0) { 154410015Speter if (regp->int_scounter >= 200 && 154510015Speter regp->initstat == 1) { 154612174Speter printf("si%d: lost intr\n", i); 154710015Speter lost++; 154810015Speter } 154910015Speter } else { 155010015Speter regp->int_scounter = 0; 155110015Speter } 155210015Speter 155312174Speter /* 155412174Speter * gripe about no input flow control.. 155512174Speter */ 155612174Speter pp = sc->sc_ports; 155712174Speter for (port = 0; port < sc->sc_nport; pp++, port++) { 155812174Speter if (pp->sp_delta_overflows > 0) { 155912174Speter printf("si%d: %d tty level buffer overflows\n", 156012174Speter i, pp->sp_delta_overflows); 156112174Speter pp->sp_delta_overflows = 0; 156212174Speter } 156312174Speter } 156410015Speter } 156517547Speter if (lost || si_realpoll) 156656498Speter si_intr(NULL); /* call intr with fake vector */ 156711609Speterout: 156810015Speter splx(oldspl); 156910015Speter 157015639Speter timeout(si_poll, (caddr_t)0L, si_pollrate); 157110015Speter} 157210015Speter#endif /* ifdef POLL */ 157310015Speter 157410015Speter/* 157510015Speter * The interrupt handler polls ALL ports on ALL adapters each time 157610015Speter * it is called. 157710015Speter */ 157810015Speter 157912496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE]; /* input staging area */ 158034832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE]; /* output staging area */ 158110015Speter 158256505Spetervoid 158356498Spetersi_intr(void *arg) 158410015Speter{ 158556498Speter struct si_softc *sc; 158656498Speter struct si_port *pp; 158710015Speter volatile struct si_channel *ccbp; 158856498Speter struct tty *tp; 158910015Speter volatile caddr_t maddr; 159011872Sphk BYTE op, ip; 159112174Speter int x, card, port, n, i, isopen; 159210015Speter volatile BYTE *z; 159310015Speter BYTE c; 159410015Speter 159556498Speter sc = arg; 159656498Speter 159756498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); 159856498Speter if (in_intr) 159910708Speter return; 160010015Speter in_intr = 1; 160110015Speter 160210015Speter /* 160310015Speter * When we get an int we poll all the channels and do ALL pending 160410015Speter * work, not just the first one we find. This allows all cards to 160510015Speter * share the same vector. 160634832Speter * 160734832Speter * XXX - But if we're sharing the vector with something that's NOT 160834832Speter * a SI/XIO/SX card, we may be making more work for ourselves. 160910015Speter */ 161056498Speter for (card = 0; card < si_numunits; card++) { 161156498Speter sc = devclass_get_softc(si_devclass, card); 161256498Speter if (sc == NULL || sc->sc_type == SIEMPTY) 161310015Speter continue; 161412174Speter 161512174Speter /* 161612174Speter * First, clear the interrupt 161712174Speter */ 161810015Speter switch(sc->sc_type) { 161934832Speter case SIHOST: 162010015Speter maddr = sc->sc_maddr; 162110015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 162210015Speter /* flag nothing pending */ 162310015Speter *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ 162410015Speter *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ 162510015Speter break; 162610015Speter case SIHOST2: 162710015Speter maddr = sc->sc_maddr; 162810015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 162910015Speter *(maddr+SIPLIRQCLR) = 0x00; 163010015Speter *(maddr+SIPLIRQCLR) = 0x10; 163110015Speter break; 163233395Speter case SIPCI: 163333395Speter maddr = sc->sc_maddr; 163433395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 163533395Speter *(maddr+SIPCIINTCL) = 0x0; 163633395Speter break; 163734832Speter case SIJETPCI: /* fall through to JETISA case */ 163833395Speter case SIJETISA: 163933395Speter maddr = sc->sc_maddr; 164033395Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 164133395Speter *(maddr+SIJETINTCL) = 0x0; 164233395Speter break; 164310015Speter case SIEISA: 164410015Speter maddr = sc->sc_maddr; 164510015Speter ((volatile struct si_reg *)maddr)->int_pending = 0; 164656498Speter (void)inb(sc->sc_iobase + 3); 164710015Speter break; 164810015Speter case SIEMPTY: 164910015Speter default: 165010015Speter continue; 165110015Speter } 165210015Speter ((volatile struct si_reg *)maddr)->int_scounter = 0; 165310015Speter 165412174Speter /* 165512174Speter * check each port 165612174Speter */ 165750442Speter for (pp = sc->sc_ports, port = 0; port < sc->sc_nport; 165834832Speter pp++, port++) { 165910015Speter ccbp = pp->sp_ccb; 166010015Speter tp = pp->sp_tty; 166110015Speter 166210015Speter /* 166310015Speter * See if a command has completed ? 166410015Speter */ 166510015Speter if (ccbp->hi_stat != pp->sp_pend) { 166610015Speter DPRINT((pp, DBG_INTR, 166734735Speter "si_intr hi_stat = 0x%x, pend = %d\n", 166810015Speter ccbp->hi_stat, pp->sp_pend)); 166910015Speter switch(pp->sp_pend) { 167010015Speter case LOPEN: 167110015Speter case MPEND: 167210015Speter case MOPEN: 167310015Speter case CONFIG: 167416575Speter case SBREAK: 167516575Speter case EBREAK: 167610015Speter pp->sp_pend = ccbp->hi_stat; 167710015Speter /* sleeping in si_command */ 167810015Speter wakeup(&pp->sp_state); 167910015Speter break; 168010015Speter default: 168110015Speter pp->sp_pend = ccbp->hi_stat; 168210015Speter } 168334832Speter } 168410015Speter 168510015Speter /* 168610015Speter * Continue on if it's closed 168710015Speter */ 168810015Speter if (ccbp->hi_stat == IDLE_CLOSE) { 168910015Speter continue; 169010015Speter } 169110015Speter 169210015Speter /* 169310015Speter * Do modem state change if not a local device 169410015Speter */ 169510015Speter si_modem_state(pp, tp, ccbp->hi_ip); 169610015Speter 169710015Speter /* 169834832Speter * Check to see if we should 'receive' characters. 169912174Speter */ 170012174Speter if (tp->t_state & TS_CONNECTED && 170112174Speter tp->t_state & TS_ISOPEN) 170212174Speter isopen = 1; 170312174Speter else 170412174Speter isopen = 0; 170512174Speter 170612174Speter /* 170716575Speter * Do input break processing 170810015Speter */ 170910015Speter if (ccbp->hi_state & ST_BREAK) { 171012174Speter if (isopen) { 171112174Speter (*linesw[tp->t_line].l_rint)(TTY_BI, tp); 171210015Speter } 171310015Speter ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ 171410015Speter DPRINT((pp, DBG_INTR, "si_intr break\n")); 171510015Speter } 171610015Speter 171710015Speter /* 171812174Speter * Do RX stuff - if not open then dump any characters. 171912174Speter * XXX: This is VERY messy and needs to be cleaned up. 172012174Speter * 172112174Speter * XXX: can we leave data in the host adapter buffer 172212174Speter * when the clists are full? That may be dangerous 172312174Speter * if the user cannot get an interrupt signal through. 172410015Speter */ 172510015Speter 172612174Speter more_rx: /* XXX Sorry. the nesting was driving me bats! :-( */ 172712174Speter 172812174Speter if (!isopen) { 172910015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 173012174Speter goto end_rx; 173112174Speter } 173210015Speter 173312174Speter /* 173415640Speter * If the tty input buffers are blocked, stop emptying 173515640Speter * the incoming buffers and let the auto flow control 173615640Speter * assert.. 173715640Speter */ 173815640Speter if (tp->t_state & TS_TBLOCK) { 173915640Speter goto end_rx; 174015640Speter } 174115640Speter 174215640Speter /* 174312174Speter * Process read characters if not skipped above 174412174Speter */ 174515640Speter op = ccbp->hi_rxopos; 174615640Speter ip = ccbp->hi_rxipos; 174715640Speter c = ip - op; 174812174Speter if (c == 0) { 174912174Speter goto end_rx; 175012174Speter } 175110015Speter 175212174Speter n = c & 0xff; 175315640Speter if (n > 250) 175415640Speter n = 250; 175512174Speter 175612174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 175710015Speter n, op, ip)); 175810015Speter 175912174Speter /* 176012174Speter * Suck characters out of host card buffer into the 176112174Speter * "input staging buffer" - so that we dont leave the 176212174Speter * host card in limbo while we're possibly echoing 176312174Speter * characters and possibly flushing input inside the 176412174Speter * ldisc l_rint() routine. 176512174Speter */ 176612496Speter if (n <= SI_BUFFERSIZE - op) { 176710015Speter 176812174Speter DPRINT((pp, DBG_INTR, "\tsingle copy\n")); 176912174Speter z = ccbp->hi_rxbuf + op; 177050442Speter si_vbcopy(z, si_rxbuf, n); 177110015Speter 177212174Speter op += n; 177312174Speter } else { 177412496Speter x = SI_BUFFERSIZE - op; 177510015Speter 177612174Speter DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); 177712174Speter z = ccbp->hi_rxbuf + op; 177850442Speter si_vbcopy(z, si_rxbuf, x); 177910015Speter 178034832Speter DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", 178134832Speter n - x)); 178212174Speter z = ccbp->hi_rxbuf; 178350442Speter si_vbcopy(z, si_rxbuf + x, n - x); 178410015Speter 178512174Speter op += n; 178612174Speter } 178710015Speter 178812174Speter /* clear collected characters from buffer */ 178912174Speter ccbp->hi_rxopos = op; 179012174Speter 179112174Speter DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", 179210015Speter n, op, ip)); 179310015Speter 179412174Speter /* 179512174Speter * at this point... 179612174Speter * n = number of chars placed in si_rxbuf 179712174Speter */ 179810015Speter 179912174Speter /* 180012174Speter * Avoid the grotesquely inefficient lineswitch 180112174Speter * routine (ttyinput) in "raw" mode. It usually 180212174Speter * takes about 450 instructions (that's without 180312174Speter * canonical processing or echo!). slinput is 180412174Speter * reasonably fast (usually 40 instructions 180512174Speter * plus call overhead). 180612174Speter */ 180712174Speter if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 180810015Speter 180912174Speter /* block if the driver supports it */ 181050442Speter if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER && 181150442Speter (tp->t_cflag & CRTS_IFLOW || 181250442Speter tp->t_iflag & IXOFF) && 181350442Speter !(tp->t_state & TS_TBLOCK)) 181412174Speter ttyblock(tp); 181510015Speter 181612174Speter tk_nin += n; 181712174Speter tk_rawcc += n; 181812174Speter tp->t_rawcc += n; 181912174Speter 182012174Speter pp->sp_delta_overflows += 182112174Speter b_to_q((char *)si_rxbuf, n, &tp->t_rawq); 182212174Speter 182312174Speter ttwakeup(tp); 182450442Speter if (tp->t_state & TS_TTSTOP && 182550442Speter (tp->t_iflag & IXANY || 182650442Speter tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 182712174Speter tp->t_state &= ~TS_TTSTOP; 182812174Speter tp->t_lflag &= ~FLUSHO; 182912174Speter si_start(tp); 183012174Speter } 183112174Speter } else { 183212174Speter /* 183312174Speter * It'd be nice to not have to go through the 183412174Speter * function call overhead for each char here. 183512174Speter * It'd be nice to block input it, saving a 183612174Speter * loop here and the call/return overhead. 183712174Speter */ 183812174Speter for(x = 0; x < n; x++) { 183912174Speter i = si_rxbuf[x]; 184012174Speter if ((*linesw[tp->t_line].l_rint)(i, tp) 184112174Speter == -1) { 184212174Speter pp->sp_delta_overflows++; 184310015Speter } 184412174Speter /* 184512174Speter * doesn't seem to be much point doing 184612174Speter * this here.. this driver has no 184712174Speter * softtty processing! ?? 184812174Speter */ 184912174Speter if (pp->sp_hotchar && i == pp->sp_hotchar) { 185012174Speter setsofttty(); 185112174Speter } 185212174Speter } 185312174Speter } 185412174Speter goto more_rx; /* try for more until RXbuf is empty */ 185510015Speter 185612174Speter end_rx: /* XXX: Again, sorry about the gotos.. :-) */ 185710015Speter 185810015Speter /* 185910015Speter * Do TX stuff 186010015Speter */ 186110015Speter (*linesw[tp->t_line].l_start)(tp); 186210015Speter 186310015Speter } /* end of for (all ports on this controller) */ 186410015Speter } /* end of for (all controllers) */ 186510015Speter 186611609Speter in_intr = 0; 186756498Speter DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); 186810015Speter} 186910015Speter 187010015Speter/* 187110015Speter * Nudge the transmitter... 187212174Speter * 187312174Speter * XXX: I inherited some funny code here. It implies the host card only 187412174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does 187512174Speter * not interrupt when it's actually hits empty. In some cases, we have 187612174Speter * processes waiting for complete drain, and we need to simulate an interrupt 187712174Speter * about when we think the buffer is going to be empty (and retry if not). 187812174Speter * I really am not certain about this... I *need* the hardware manuals. 187910015Speter */ 188010015Speterstatic void 188156498Spetersi_start(struct tty *tp) 188210015Speter{ 188310015Speter struct si_port *pp; 188410015Speter volatile struct si_channel *ccbp; 188556498Speter struct clist *qp; 188610015Speter BYTE ipos; 188710015Speter int nchar; 188810015Speter int oldspl, count, n, amount, buffer_full; 188910015Speter 189010015Speter oldspl = spltty(); 189110015Speter 189210015Speter qp = &tp->t_outq; 189310015Speter pp = TP2PP(tp); 189410015Speter 189510015Speter DPRINT((pp, DBG_ENTRY|DBG_START, 189610015Speter "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", 189710015Speter tp, tp->t_state, pp->sp_state, qp->c_cc)); 189810015Speter 189910015Speter if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 190010015Speter goto out; 190110015Speter 190210015Speter buffer_full = 0; 190310015Speter ccbp = pp->sp_ccb; 190410015Speter 190510015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 190610015Speter DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); 190710015Speter 190810015Speter while ((nchar = qp->c_cc) > 0) { 190910015Speter if ((BYTE)count >= 255) { 191010015Speter buffer_full++; 191110015Speter break; 191210015Speter } 191310015Speter amount = min(nchar, (255 - (BYTE)count)); 191410015Speter ipos = (unsigned int)ccbp->hi_txipos; 191534832Speter n = q_to_b(&tp->t_outq, si_txbuf, amount); 191610015Speter /* will it fit in one lump? */ 191734832Speter if ((SI_BUFFERSIZE - ipos) >= n) { 191850442Speter si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); 191910015Speter } else { 192050442Speter si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], 192134832Speter SI_BUFFERSIZE - ipos); 192250442Speter si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos), 192350442Speter &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos)); 192410015Speter } 192510015Speter ccbp->hi_txipos += n; 192610015Speter count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; 192710015Speter } 192810015Speter 192910015Speter if (count != 0 && nchar == 0) { 193010015Speter tp->t_state |= TS_BUSY; 193110015Speter } else { 193210015Speter tp->t_state &= ~TS_BUSY; 193310015Speter } 193410015Speter 193510015Speter /* wakeup time? */ 193610015Speter ttwwakeup(tp); 193710015Speter 193810015Speter DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", 193910015Speter (BYTE)count, nchar, tp->t_state)); 194010015Speter 194134735Speter if (tp->t_state & TS_BUSY) 194210015Speter { 194310015Speter int time; 194410015Speter 194534735Speter time = ttspeedtab(tp->t_ospeed, chartimes); 194634735Speter 194734735Speter if (time > 0) { 194834735Speter if (time < nchar) 194934735Speter time = nchar / time; 195034735Speter else 195134735Speter time = 2; 195210015Speter } else { 195334735Speter DPRINT((pp, DBG_START, 195434735Speter "bad char time value! %d\n", time)); 195534735Speter time = hz/10; 195610015Speter } 195710015Speter 195810015Speter if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { 195929677Sgibbs untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); 196010015Speter } else { 196110015Speter pp->sp_state |= SS_LSTART; 196210015Speter } 196310015Speter DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); 196429677Sgibbs pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); 196510015Speter } 196610015Speter 196710015Speterout: 196810015Speter splx(oldspl); 196910015Speter DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); 197010015Speter} 197110015Speter 197210015Speter/* 197310015Speter * Note: called at splsoftclock from the timeout code 197410015Speter * This has to deal with two things... cause wakeups while waiting for 197510015Speter * tty drains on last process exit, and call l_start at about the right 197610015Speter * time for protocols like ppp. 197710015Speter */ 197810015Speterstatic void 197925047Sbdesi_lstart(void *arg) 198010015Speter{ 198156498Speter struct si_port *pp = arg; 198256498Speter struct tty *tp; 198310015Speter int oldspl; 198410015Speter 198510015Speter DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", 198610015Speter pp, pp->sp_state)); 198710015Speter 198810015Speter oldspl = spltty(); 198910015Speter 199010015Speter if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { 199110015Speter splx(oldspl); 199210015Speter return; 199310015Speter } 199410015Speter pp->sp_state &= ~SS_LSTART; 199510015Speter pp->sp_state |= SS_INLSTART; 199610015Speter 199710015Speter tp = pp->sp_tty; 199810015Speter 199910015Speter /* deal with the process exit case */ 200010015Speter ttwwakeup(tp); 200110015Speter 200212174Speter /* nudge protocols - eg: ppp */ 200310015Speter (*linesw[tp->t_line].l_start)(tp); 200410015Speter 200510015Speter pp->sp_state &= ~SS_INLSTART; 200610015Speter splx(oldspl); 200710015Speter} 200810015Speter 200910015Speter/* 201010015Speter * Stop output on a line. called at spltty(); 201110015Speter */ 201210015Spetervoid 201356498Spetersi_stop(struct tty *tp, int rw) 201410015Speter{ 201510015Speter volatile struct si_channel *ccbp; 201610015Speter struct si_port *pp; 201710015Speter 201810015Speter pp = TP2PP(tp); 201910015Speter ccbp = pp->sp_ccb; 202010015Speter 202151654Sphk DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw)); 202210015Speter 202310015Speter /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ 202410015Speter if (rw & FWRITE) { 202510015Speter /* what level are we meant to be flushing anyway? */ 202610015Speter if (tp->t_state & TS_BUSY) { 202710015Speter si_command(TP2PP(tp), WFLUSH, SI_NOWAIT); 202810015Speter tp->t_state &= ~TS_BUSY; 202910015Speter ttwwakeup(tp); /* Bruce???? */ 203010015Speter } 203110015Speter } 203212174Speter#if 1 /* XXX: this doesn't work right yet.. */ 203312174Speter /* XXX: this may have been failing because we used to call l_rint() 203412174Speter * while we were looping based on these two counters. Now, we collect 203512174Speter * the data and then loop stuffing it into l_rint(), making this 203612174Speter * useless. Should we cause this to blow away the staging buffer? 203712174Speter */ 203810015Speter if (rw & FREAD) { 203910015Speter ccbp->hi_rxopos = ccbp->hi_rxipos; 204010015Speter } 204110015Speter#endif 204210015Speter} 204310015Speter 204410015Speter/* 204534832Speter * Issue a command to the host card CPU. 204610015Speter */ 204710015Speter 204810015Speterstatic void 204956498Spetersi_command(struct si_port *pp, int cmd, int waitflag) 205010015Speter{ 205110015Speter int oldspl; 205210015Speter volatile struct si_channel *ccbp = pp->sp_ccb; 205310015Speter int x; 205410015Speter 205510015Speter DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n", 205610015Speter pp, cmd, waitflag, ccbp->hi_stat)); 205710015Speter 205810015Speter oldspl = spltty(); /* Keep others out */ 205910015Speter 206010015Speter /* wait until it's finished what it was doing.. */ 206116575Speter /* XXX: sits in IDLE_BREAK until something disturbs it or break 206216575Speter * is turned off. */ 206310015Speter while((x = ccbp->hi_stat) != IDLE_OPEN && 206410015Speter x != IDLE_CLOSE && 206516575Speter x != IDLE_BREAK && 206610015Speter x != cmd) { 206710015Speter if (in_intr) { /* Prevent sleep in intr */ 206810015Speter DPRINT((pp, DBG_PARAM, 206910015Speter "cmd intr collision - completing %d\trequested %d\n", 207010015Speter x, cmd)); 207110015Speter splx(oldspl); 207210015Speter return; 207310015Speter } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 207410015Speter "sicmd1", 1)) { 207510015Speter splx(oldspl); 207610015Speter return; 207710015Speter } 207810015Speter } 207916575Speter /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */ 208010015Speter 208110015Speter /* if there was a pending command, cause a state-change wakeup */ 208216575Speter switch(pp->sp_pend) { 208316575Speter case LOPEN: 208416575Speter case MPEND: 208516575Speter case MOPEN: 208616575Speter case CONFIG: 208716575Speter case SBREAK: 208816575Speter case EBREAK: 208916575Speter wakeup(&pp->sp_state); 209016575Speter break; 209116575Speter default: 209216575Speter break; 209310015Speter } 209410015Speter 209510015Speter pp->sp_pend = cmd; /* New command pending */ 209610015Speter ccbp->hi_stat = cmd; /* Post it */ 209710015Speter 209810015Speter if (waitflag) { 209910015Speter if (in_intr) { /* If in interrupt handler */ 210010015Speter DPRINT((pp, DBG_PARAM, 210110015Speter "attempt to sleep in si_intr - cmd req %d\n", 210210015Speter cmd)); 210310015Speter splx(oldspl); 210410015Speter return; 210516575Speter } else while(ccbp->hi_stat != IDLE_OPEN && 210616575Speter ccbp->hi_stat != IDLE_BREAK) { 210710015Speter if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH, 210810015Speter "sicmd2", 0)) 210910015Speter break; 211010015Speter } 211110015Speter } 211210015Speter splx(oldspl); 211310015Speter} 211410015Speter 211510015Speterstatic void 211656498Spetersi_disc_optim(struct tty *tp, struct termios *t, struct si_port *pp) 211710015Speter{ 211810015Speter /* 211910015Speter * XXX can skip a lot more cases if Smarts. Maybe 212010015Speter * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we 212110015Speter * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state. 212210015Speter */ 212350442Speter if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) && 212450442Speter (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) && 212550442Speter (!(t->c_iflag & PARMRK) || 212650442Speter (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) && 212750442Speter !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) && 212850442Speter linesw[tp->t_line].l_rint == ttyinput) 212910015Speter tp->t_state |= TS_CAN_BYPASS_L_RINT; 213010015Speter else 213110015Speter tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 213233322Sphk pp->sp_hotchar = linesw[tp->t_line].l_hotchar; 213350442Speter DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n", 213410161Speter (tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off", 213510161Speter pp->sp_hotchar)); 213610015Speter} 213710015Speter 213810015Speter 213910015Speter#ifdef SI_DEBUG 214013353Speter 214156505Spetervoid 214213353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...) 214310015Speter{ 214413353Speter va_list ap; 214513630Sphk 214610015Speter if ((pp == NULL && (si_debug&flags)) || 214710015Speter (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) { 214834832Speter if (pp != NULL) 214934832Speter printf("%ci%d(%d): ", 's', 215046679Sphk (int)SI_CARD(minor(pp->sp_tty->t_dev)), 215146679Sphk (int)SI_PORT(minor(pp->sp_tty->t_dev))); 215213630Sphk va_start(ap, fmt); 215313630Sphk vprintf(fmt, ap); 215413353Speter va_end(ap); 215510015Speter } 215610015Speter} 215710015Speter 215810015Speterstatic char * 215956498Spetersi_mctl2str(enum si_mctl cmd) 216010015Speter{ 216110015Speter switch (cmd) { 216234832Speter case GET: 216334832Speter return("GET"); 216434832Speter case SET: 216534832Speter return("SET"); 216634832Speter case BIS: 216734832Speter return("BIS"); 216834832Speter case BIC: 216934832Speter return("BIC"); 217010015Speter } 217110015Speter return("BAD"); 217210015Speter} 217312502Sjulian 217412624Speter#endif /* DEBUG */ 217512502Sjulian 217634832Speterstatic char * 217756498Spetersi_modulename(int host_type, int uart_type) 217834832Speter{ 217934832Speter switch (host_type) { 218034832Speter /* Z280 based cards */ 218150442Speter case SIEISA: 218250442Speter case SIHOST2: 218334832Speter case SIHOST: 218434832Speter case SIPCI: 218534832Speter switch (uart_type) { 218634832Speter case 0: 218734832Speter return(" (XIO)"); 218834832Speter case 1: 218934832Speter return(" (SI)"); 219034832Speter } 219134832Speter break; 219234832Speter /* T225 based hosts */ 219334832Speter case SIJETPCI: 219434832Speter case SIJETISA: 219534832Speter switch (uart_type) { 219634832Speter case 0: 219734832Speter return(" (SI)"); 219834832Speter case 40: 219934832Speter return(" (XIO)"); 220036856Sphk case 72: 220136856Sphk return(" (SXDC)"); 220234832Speter } 220334832Speter break; 220434832Speter } 220534832Speter return(""); 220634832Speter} 2207