si.c revision 10672
110015Speter/*
210015Speter * Device driver for Specialix range (SLXOS) of serial line multiplexors.
310015Speter *
410015Speter * Copyright (C) 1990, 1992 Specialix International,
510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
610015Speter * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com>
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 *
3310672Speter *	$Id: si.c,v 1.5 1995/08/22 00:48:17 peter Exp $
3410015Speter */
3510015Speter
3610015Speter#ifndef lint
3710015Speterstatic char si_copyright1[] =  "@(#) (C) Specialix International, 1990,1992",
3810015Speter            si_copyright2[] =  "@(#) (C) Andy Rutter 1993",
3910015Speter            si_copyright3[] =  "@(#) (C) Peter Wemm 1995";
4010015Speter#endif	/* not lint */
4110015Speter
4210015Speter#define	SI_DEBUG			/* turn driver debugging on */
4310015Speter
4410015Speter#include <sys/param.h>
4510015Speter#include <sys/systm.h>
4610015Speter#include <sys/ioctl.h>
4710015Speter#include <sys/tty.h>
4810015Speter#include <sys/ttydefaults.h>
4910015Speter#include <sys/proc.h>
5010015Speter#include <sys/user.h>
5110015Speter#include <sys/conf.h>
5210015Speter#include <sys/file.h>
5310015Speter#include <sys/uio.h>
5410015Speter#include <sys/dkstat.h>
5510015Speter#include <sys/kernel.h>
5610015Speter#include <sys/syslog.h>
5710015Speter#include <sys/device.h>
5810015Speter#include <sys/malloc.h>
5910015Speter#include <sys/devconf.h>
6010015Speter
6110015Speter#include <machine/clock.h>
6210015Speter
6310015Speter#include <i386/isa/icu.h>
6410015Speter#include <i386/isa/isa.h>
6510015Speter#include <i386/isa/isa_device.h>
6610015Speter
6710015Speter#include <i386/isa/sireg.h>
6810015Speter#include <machine/si.h>
6910015Speter
7010015Speter#include "si.h"
7110015Speter
7210015Speter/*
7310015Speter * This device driver is designed to interface the Specialix International
7410015Speter * range of serial multiplexor cards (SLXOS) to BSDI/386 on an ISA bus machine.
7510015Speter *
7610015Speter * The controller is interfaced to the host via dual port ram
7710015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
7810015Speter */
7910015Speter
8010015Speter#define	POLL		/* turn on poller to generate buffer empty interrupt */
8110047Speter#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
8210015Speter#define SI_I_HIGH_WATER	(TTYHOG - SLXOS_BUFFERSIZE)
8310015Speter
8410015Speterenum si_mctl { GET, SET, BIS, BIC };
8510015Speter
8610015Speterstatic void si_command __P((struct si_port *, int, int));
8710015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
8810015Speterstatic void si_write_enable __P((struct si_port *, int));
8910015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
9010015Speterstatic void si_start __P((struct tty *));
9110015Speterstatic void si_lstart __P((struct si_port *));
9210015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
9310015Speter					struct si_port *pp));
9410015Speterstatic void sihardclose __P((struct si_port *pp));
9510015Speterstatic void sidtrwakeup __P((void *chan));
9610015Speter
9710015Spetervoid	sistop __P((struct tty *tp, int rw));
9810015Speterint	siparam __P((struct tty *, struct termios *));
9910015Speterint	siintr __P((int bdnum));
10010015Speter
10110015Speterstatic int si_Nports = 0;
10210015Speterstatic int si_Nmodules = 0;
10310015Speterstatic int si_debug = 0;
10410015Speter
10510015Speter/* where the firmware lives */
10610015Speterextern int si_dsize;
10710015Speterextern unsigned char si_download[];
10810015Speter
10910044Speterstruct si_softc {
11010044Speter	struct device	sc_dev;  	/* base device */
11110015Speter
11210044Speter	int 		sc_type;	/* adapter type */
11310044Speter	char 		*sc_typename;	/* adapter type string */
11410044Speter
11510044Speter	struct si_port	*sc_ports;	/* port structures for this card */
11610044Speter
11710044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
11810044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
11910044Speter	int		sc_nport;	/* # ports on this card */
12010044Speter	int		sc_irq;		/* copy of attach irq */
12110044Speter	int		sc_eisa_iobase;	/* EISA io port address */
12210044Speter	int		sc_eisa_irqbits;
12310044Speter	struct kern_devconf sc_kdc;
12410044Speter};
12510044Speterstruct si_softc si_softc[NSI];		/* up to 4 elements */
12610044Speter
12710015Speter#ifndef B2000	/* not standard */
12810015Speter# define B2000 2000
12910015Speter#endif
13010015Speterstatic struct speedtab bdrates[] = {
13110015Speter	B75,	CLK75,		/* 0x0 */
13210015Speter	B110,	CLK110,		/* 0x1 */
13310015Speter	B150,	CLK150,		/* 0x3 */
13410015Speter	B300,	CLK300,		/* 0x4 */
13510015Speter	B600,	CLK600,		/* 0x5 */
13610015Speter	B1200,	CLK1200,	/* 0x6 */
13710015Speter	B2000,	CLK2000,	/* 0x7 */
13810015Speter	B2400,	CLK2400,	/* 0x8 */
13910015Speter	B4800,	CLK4800,	/* 0x9 */
14010015Speter	B9600,	CLK9600,	/* 0xb */
14110015Speter	B19200,	CLK19200,	/* 0xc */
14210015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
14310015Speter	B57600, CLK57600,	/* 0xd */
14410015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
14510015Speter	-1,	-1
14610015Speter};
14710015Speter
14810015Speter
14910015Speter/* populated with approx character/sec rates - translated at card
15010015Speter * initialisation time to chars per tick of the clock */
15110015Speterstatic int done_chartimes = 0;
15210015Speterstatic struct speedtab chartimes[] = {
15310015Speter	B75,	8,
15410015Speter	B110,	11,
15510015Speter	B150,	15,
15610015Speter	B300,	30,
15710015Speter	B600,	60,
15810015Speter	B1200,	120,
15910015Speter	B2000,	200,
16010015Speter	B2400,	240,
16110015Speter	B4800,	480,
16210015Speter	B9600,	960,
16310015Speter	B19200,	1920,
16410015Speter	B38400, 3840,
16510015Speter	B57600, 5760,
16610015Speter	B115200, 11520,
16710015Speter	-1,	-1
16810015Speter};
16910015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
17010015Speter
17110047Speterstatic int si_default_rate =	TTYDEF_SPEED;
17210047Speterstatic int si_default_iflag =	0;
17310047Speterstatic int si_default_oflag =	0;
17410047Speterstatic int si_default_lflag =	0;
17510047Speter#ifdef SI_DEF_HWFLOW
17610047Speterstatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
17710047Speter#else
17810047Speterstatic int si_default_cflag =	TTYDEF_CFLAG;
17910047Speter#endif
18010047Speter
18110015Speter#ifdef POLL
18210015Speter#define	POLL_INTERVAL	(hz/2)
18310015Speterstatic int init_finished = 0;
18410015Speterstatic void si_poll __P((void *));
18510015Speter#endif
18610015Speter
18710015Speter/*
18810015Speter * Array of adapter types and the corresponding RAM size. The order of
18910015Speter * entries here MUST match the ordinal of the adapter type.
19010015Speter */
19110015Speterstatic char *si_type[] = {
19210015Speter	"EMPTY",
19310015Speter	"SIHOST",
19410015Speter	"SI2",				/* MCA */
19510015Speter	"SIHOST2",
19610015Speter	"SIEISA",
19710015Speter};
19810015Speter
19910015Speter
20010015Speterstatic struct kern_devconf si_kdc[NSI] = { {
20110015Speter	0, 0, 0,		/* filled in by dev_attach */
20210015Speter	"si", 0, { MDDT_ISA, 0, "tty" },
20310015Speter	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
20410015Speter	&kdc_isa0,		/* parent */
20510015Speter	0,			/* parent data */
20610015Speter	DC_UNCONFIGURED,	/* state */
20710015Speter	"Specialix SI/XIO Host adapter",
20810015Speter	DC_CLS_SERIAL,		/* class */
20910015Speter} };
21010015Speter
21110015Spetervoid
21210015Spetersi_registerdev(id)
21310015Speter	struct isa_device *id;
21410015Speter{
21510015Speter	if (id->id_unit != 0) {
21610015Speter		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
21710015Speter	}
21810015Speter	si_kdc[id->id_unit].kdc_unit = id->id_unit;
21910015Speter	si_kdc[id->id_unit].kdc_isa = id;
22010015Speter	dev_attach(&si_kdc[id->id_unit]);
22110015Speter}
22210015Speter
22310015Speter/* Look for a valid board at the given mem addr */
22410015Speterint
22510015Spetersiprobe(id)
22610015Speter	struct isa_device *id;
22710015Speter{
22810015Speter	struct si_softc *sc;
22910015Speter	int type;
23010015Speter	u_int i, ramsize;
23110015Speter	volatile BYTE was, *ux;
23210015Speter	volatile unsigned char *maddr;
23310015Speter	unsigned char *paddr;
23410015Speter
23510015Speter	si_registerdev(id);
23610015Speter
23710015Speter	maddr = id->id_maddr;		/* virtual address... */
23810015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
23910015Speter
24010015Speter	DPRINT((0, DBG_AUTOBOOT, "SLXOS probe at virtual=0x%x physical=0x%x\n",
24110015Speter		id->id_maddr, paddr));
24210015Speter
24310015Speter	/*
24410015Speter	 * this is a lie, but it's easier than trying to handle caching
24510015Speter	 * and ram conflicts in the >1M and <16M region.
24610015Speter	 */
24710015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
24810015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
24910015Speter		printf("si%d: iomem (%x) out of range\n",
25010015Speter			id->id_unit, paddr);
25110015Speter		return(0);
25210015Speter	}
25310015Speter
25410015Speter	if (id->id_unit >= NSI) {
25510015Speter		/* THIS IS IMPOSSIBLE */
25610015Speter		return(0);
25710015Speter	}
25810015Speter
25910015Speter	if (((u_int)paddr & 0x7fff) != 0) {
26010015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
26110015Speter			"si%d: iomem (%x) not on 32k boundary\n",
26210015Speter			id->id_unit, paddr));
26310015Speter		return(0);
26410015Speter	}
26510015Speter
26610015Speter
26710015Speter	for (i=0; i < NSI; i++) {
26810015Speter		if ((sc = &si_softc[i]) == NULL)
26910015Speter			continue;
27010015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
27110015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
27210015Speter				"si%d: iomem (%x) already configured to si%d\n",
27310015Speter				id->id_unit, sc->sc_paddr, i));
27410015Speter			return(0);
27510015Speter		}
27610015Speter	}
27710015Speter
27810015Speter#if NEISA > 0
27910015Speter	if (id->id_iobase > 0x0fff) {	/* EISA card */
28010015Speter		int irq, port;
28110015Speter		unsigned long base;
28210015Speter		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
28310015Speter			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
28410015Speter
28510015Speter		port = id->id_iobase;
28610015Speter		base = (inb(port+1) << 24) | (inb(port) << 16);
28710015Speter		irq  = ((inb(port+2) >> 4) & 0xf);
28810015Speter
28910015Speter		id->id_irq = eisa_irqs[irq];
29010015Speter
29110015Speter		DPRINT((0, DBG_AUTOBOOT,
29210015Speter		    "SLXOS: si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
29310015Speter		    id->id_unit, base, irq, id->id_irq, port));
29410015Speter
29510015Speter		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
29610015Speter			goto bad_irq;
29710015Speter
29810015Speter		id->id_iobase &= 0xf000;
29910015Speter		id->id_iosize  = 0x0fff;
30010015Speter
30110015Speter		type = EISA;
30210015Speter		outb(p+2, (BYTE)irq << 4);
30310015Speter
30410015Speter		sc->sc_eisa_iobase = p;
30510015Speter		sc->sc_eisa_irqbits = irq << 4;
30610015Speter		ramsize = SIEISA_RAMSIZE;
30710015Speter		goto got_card;
30810015Speter	}
30910015Speter#endif
31010015Speter
31110015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
31210015Speter	*maddr = 0x17;
31310015Speter	if (*maddr != 0x17) {
31410015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
31510015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
31610015Speter			id->id_unit, paddr));
31710015Speterfail:
31810015Speter		return(0);
31910015Speter	}
32010015Speter	/*
32110015Speter	 * OK, now to see if whatever responded is really an SI card.
32210015Speter	 * Try for a MK II first (SIHOST2)
32310015Speter	 */
32410015Speter	for (i=SIPLSIG; i<SIPLSIG+8; i++)
32510015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
32610015Speter			goto try_mk1;
32710015Speter
32810015Speter	/* It must be an SIHOST2 */
32910015Speter	*(maddr + SIPLRESET) = 0;
33010015Speter	*(maddr + SIPLIRQCLR) = 0;
33110015Speter	*(maddr + SIPLIRQSET) = 0x10;
33210015Speter	type = SIHOST2;
33310015Speter	ramsize = SIHOST2_RAMSIZE;
33410015Speter	goto got_card;
33510015Speter
33610015Speter	/*
33710015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
33810015Speter	 */
33910015Spetertry_mk1:
34010015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
34110015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
34210015Speter	*(maddr+SIRAM) = 0x17;
34310015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
34410015Speter		goto fail;
34510015Speter	*(maddr+0x7ff8) = 0x17;
34610015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
34710015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
34810015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
34910015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
35010015Speter		goto fail;
35110015Speter	}
35210015Speter
35310015Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
35410015Speter	type = SIHOST;
35510015Speter	ramsize = SIHOST_RAMSIZE;
35610015Speter
35710015Spetergot_card:
35810015Speter	DPRINT((0, DBG_AUTOBOOT, "SLXOS: found type %d card, try memory test\n", type));
35910015Speter	/* Try the acid test */
36010015Speter	ux = (BYTE *)(maddr + SIRAM);
36110015Speter	for (i=0; i<ramsize; i++, ux++)
36210015Speter		*ux = (BYTE)(i&0xff);
36310015Speter	ux = (BYTE *)(maddr + SIRAM);
36410015Speter	for (i=0; i<ramsize; i++, ux++) {
36510015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
36610015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
36710015Speter				"SLXOS si%d: match fail at phys 0x%x, was %x should be %x\n",
36810015Speter				id->id_unit, paddr+i, was, i&0xff));
36910015Speter			goto fail;
37010015Speter		}
37110015Speter	}
37210015Speter
37310015Speter	/* clear out the RAM */
37410015Speter	ux = (BYTE *)(maddr + SIRAM);
37510015Speter	for (i=0; i<ramsize; i++)
37610015Speter		*ux++ = 0;
37710015Speter	ux = (BYTE *)(maddr + SIRAM);
37810015Speter	for (i=0; i<ramsize; i++) {
37910015Speter		if ((was = *ux++) != 0) {
38010015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
38110015Speter				"SLXOS si%d: clear fail at phys 0x%x, was %x\n",
38210015Speter				id->id_unit, paddr+i, was));
38310015Speter			goto fail;
38410015Speter		}
38510015Speter	}
38610015Speter
38710015Speter	/*
38810015Speter	 * Success, we've found a valid board, now fill in
38910015Speter	 * the adapter structure.
39010015Speter	 */
39110015Speter	switch (type) {
39210015Speter	case SIHOST2:
39310015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
39410015Speterbad_irq:
39510015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
39610015Speter				"si%d: bad IRQ value - %d\n",
39710015Speter				id->id_unit, id->id_irq));
39810015Speter			return(0);
39910015Speter		}
40010015Speter		id->id_msize = SIHOST2_MEMSIZE;
40110015Speter		break;
40210015Speter	case SIHOST:
40310015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
40410015Speter			goto bad_irq;
40510015Speter		}
40610015Speter		id->id_msize = SIHOST_MEMSIZE;
40710015Speter		break;
40810015Speter	case SIEISA:
40910015Speter		id->id_msize = SIEISA_MEMSIZE;
41010015Speter		break;
41110015Speter	case SI2:		/* MCA */
41210015Speter	default:
41310015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
41410015Speter		return(0);
41510015Speter	}
41610015Speter	si_softc[id->id_unit].sc_type = type;
41710015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
41810015Speter	return(-1);	/* -1 == found */
41910015Speter}
42010015Speter
42110015Speter/*
42210015Speter * Attach the device.  Initialize the card.
42310015Speter */
42410015Speterint
42510015Spetersiattach(id)
42610015Speter	struct isa_device *id;
42710015Speter{
42810015Speter	int unit = id->id_unit;
42910015Speter	struct si_softc *sc = &si_softc[unit];
43010015Speter	struct si_port *pp;
43110015Speter	volatile struct si_channel *ccbp;
43210015Speter	volatile struct si_reg *regp;
43310015Speter	volatile caddr_t maddr;
43410015Speter	struct si_module *modp;
43510015Speter	struct tty *tp;
43610015Speter	struct speedtab *spt;
43710015Speter	int nmodule, nport, x, y;
43810015Speter
43910015Speter	DPRINT((0, DBG_AUTOBOOT, "SLXOS siattach\n"));
44010015Speter
44110015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
44210015Speter	sc->sc_maddr = id->id_maddr;
44310015Speter	sc->sc_irq = id->id_irq;
44410015Speter
44510015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
44610015Speter
44710015Speter	maddr = sc->sc_maddr;
44810015Speter
44910015Speter	/*
45010015Speter	 * OK, now lets download the firmware and try and boot the CPU..
45110015Speter	 */
45210015Speter
45310015Speter	DPRINT((0, DBG_DOWNLOAD, "SLXOS si_download: nbytes %d\n", si_dsize));
45410015Speter	bcopy(si_download, maddr, si_dsize);
45510015Speter
45610015Speter	switch (sc->sc_type) {
45710015Speter	case SIEISA:
45810015Speter#if NEISA > 0
45910015Speter		/* modify the Z280 firmware to tell it that it's on an EISA */
46010015Speter		*(maddr+0x42) = 1;
46110015Speter		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
46210015Speter		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
46310015Speter		break;
46410015Speter#endif	/* fall-through if not EISA */
46510015Speter	case SI2:
46610015Speter		/* must get around to writing the code for
46710015Speter		 * these one day */
46810015Speter		return 0;
46910015Speter	case SIHOST:
47010015Speter		*(maddr+SIRESET_CL) = 0;
47110015Speter		*(maddr+SIINTCL_CL) = 0;
47210015Speter		break;
47310015Speter	case SIHOST2:
47410015Speter		*(maddr+SIPLRESET) = 0x10;
47510015Speter		switch (sc->sc_irq) {
47610015Speter		case IRQ11:
47710015Speter			*(maddr+SIPLIRQ11) = 0x10;
47810015Speter			break;
47910015Speter		case IRQ12:
48010015Speter			*(maddr+SIPLIRQ12) = 0x10;
48110015Speter			break;
48210015Speter		case IRQ15:
48310015Speter			*(maddr+SIPLIRQ15) = 0x10;
48410015Speter			break;
48510015Speter		}
48610015Speter		*(maddr+SIPLIRQCLR) = 0x10;
48710015Speter		break;
48810015Speter	}
48910015Speter
49010015Speter	DELAY(1000000);			/* wait around for a second */
49110015Speter
49210015Speter	regp = (struct si_reg *)maddr;
49310015Speter	y = 0;
49410015Speter					/* wait max of 5 sec for init OK */
49510015Speter	while (regp->initstat == 0 && y++ < 10) {
49610015Speter		DELAY(500000);
49710015Speter	}
49810015Speter	switch (regp->initstat) {
49910015Speter	case 0:
50010015Speter		printf("si%d: startup timeout - aborting\n", unit);
50110015Speter		sc->sc_type = NULL;
50210015Speter		return 0;
50310015Speter	case 1:
50410015Speter			/* set throttle to 100 intr per second */
50510015Speter		regp->int_count = 25000;
50610015Speter			/* rx intr max of 25 timer per second */
50710015Speter		regp->rx_int_count = 4;
50810015Speter		regp->int_pending = 0;		/* no intr pending */
50910015Speter		regp->int_scounter = 0;	/* reset counter */
51010015Speter		break;
51110015Speter	case 0xff:
51210015Speter		/*
51310015Speter		 * No modules found, so give up on this one.
51410015Speter		 */
51510015Speter		printf("si%d: %s - no ports found\n", unit,
51610015Speter			si_type[sc->sc_type]);
51710015Speter		return 0;
51810015Speter	default:
51910015Speter		printf("si%d: Z280 version error - initstat %x\n",
52010015Speter			unit, regp->initstat);
52110015Speter		return 0;
52210015Speter	}
52310015Speter
52410015Speter	/*
52510015Speter	 * First time around the ports just count them in order
52610015Speter	 * to allocate some memory.
52710015Speter	 */
52810015Speter	nport = 0;
52910015Speter	modp = (struct si_module *)(maddr + 0x80);
53010015Speter	for (;;) {
53110015Speter		DPRINT((0, DBG_DOWNLOAD, "SLXOS si%d: ccb addr 0x%x\n", unit, modp));
53210015Speter		switch (modp->sm_type & (~MMASK)) {
53310015Speter		case M232:
53410015Speter		case M422:
53510015Speter			DPRINT((0, DBG_DOWNLOAD,
53610015Speter				"SLXOS si%d: Found 232/422 module, %d ports\n",
53710015Speter				unit, (int)(modp->sm_type & MMASK)));
53810015Speter
53910015Speter			/* this is a firmware issue */
54010015Speter			if (si_Nports == SI_MAXPORTPERCARD) {
54110015Speter				printf("si%d: extra ports ignored\n", unit);
54210015Speter				continue;
54310015Speter			}
54410015Speter
54510015Speter			x = modp->sm_type & MMASK;
54610015Speter			nport += x;
54710015Speter			si_Nports += x;
54810015Speter			si_Nmodules++;
54910015Speter			break;
55010015Speter		default:
55110015Speter			printf("si%d: unknown module type %d\n",
55210015Speter				unit, modp->sm_type);
55310015Speter			break;
55410015Speter		}
55510015Speter		if (modp->sm_next == 0)
55610015Speter			break;
55710015Speter		modp = (struct si_module *)
55810015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
55910015Speter	}
56010015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
56110015Speter		M_DEVBUF, M_NOWAIT);
56210015Speter	if (sc->sc_ports == 0) {
56310015Spetermem_fail:
56410015Speter		printf("si%d: fail to malloc memory for port structs\n",
56510015Speter			unit);
56610015Speter		return 0;
56710015Speter	}
56810015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
56910015Speter	sc->sc_nport = nport;
57010015Speter
57110015Speter	/*
57210015Speter	 * allocate tty structures for ports
57310015Speter	 */
57410015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
57510015Speter	if (tp == 0)
57610015Speter		goto mem_fail;
57710015Speter	bzero(tp, sizeof(*tp) * nport);
57810015Speter
57910015Speter	/* mark the device state as attached */
58010015Speter	si_kdc[unit].kdc_state = DC_BUSY;
58110015Speter
58210015Speter	/*
58310015Speter	 * Scan round the ports again, this time initialising.
58410015Speter	 */
58510015Speter	pp = sc->sc_ports;
58610015Speter	nmodule = 0;
58710015Speter	modp = (struct si_module *)(maddr + 0x80);
58810015Speter	for (;;) {
58910015Speter		switch (modp->sm_type & (~MMASK)) {
59010015Speter		case M232:
59110015Speter		case M422:
59210015Speter			nmodule++;
59310015Speter			nport = (modp->sm_type & MMASK);
59410015Speter			ccbp = (struct si_channel *)((char *)modp+0x100);
59510015Speter			for (x = 0; x < nport; x++, pp++, ccbp++) {
59610015Speter				pp->sp_ccb = ccbp;	/* save the address */
59710015Speter				pp->sp_tty = tp++;
59810015Speter				pp->sp_pend = IDLE_CLOSE;
59910044Speter				pp->sp_flags = 0;
60010015Speter				pp->sp_state = 0;	/* internal flag */
60110015Speter				pp->sp_dtr_wait = 3 * hz;
60210047Speter				pp->sp_iin.c_iflag = si_default_iflag;
60310047Speter				pp->sp_iin.c_oflag = si_default_oflag;
60410047Speter				pp->sp_iin.c_cflag = si_default_cflag;
60510047Speter				pp->sp_iin.c_lflag = si_default_lflag;
60610015Speter				termioschars(&pp->sp_iin);
60710015Speter				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
60810047Speter					si_default_rate;
60910015Speter				pp->sp_iout = pp->sp_iin;
61010015Speter			}
61110015Speter			break;
61210015Speter		default:
61310015Speter			break;
61410015Speter		}
61510015Speter		if (modp->sm_next == 0) {
61610015Speter			printf("si%d: %s, ports: %d, modules: %d\n",
61710015Speter				unit,
61810015Speter				sc->sc_typename,
61910015Speter				sc->sc_nport,
62010015Speter				nmodule);
62110015Speter			break;
62210015Speter		}
62310015Speter		modp = (struct si_module *)
62410015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
62510015Speter	}
62610015Speter	if (done_chartimes == 0) {
62710015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
62810015Speter			if ((spt->sp_code /= hz) == 0)
62910015Speter				spt->sp_code = 1;
63010015Speter		}
63110015Speter		done_chartimes = 1;
63210015Speter
63310015Speter/* tell them where we stand.. */
63410015Speterprintf("\
63510015Spetersi%d: -------------------USE AT YOUR OWN RISK!!!!--------------------\n\
63610015Spetersi%d: WARNING!! THIS DRIVER IS NOT COMPLETE NOR SUFFICIENTLY TESTED!!\n\
63710015Spetersi%d: -------------------USE AT YOUR OWN RISK!!!!--------------------\n\
63810015Speter", unit, unit, unit);
63910015Speter
64010015Speter	}
64110015Speter	return (1);
64210015Speter}
64310015Speter
64410015Speterstruct isa_driver sidriver =
64510015Speter	{ siprobe, siattach, "si" };
64610015Speter
64710015Speter
64810015Speterint
64910015Spetersiopen(dev, flag, mode, p)
65010015Speter	dev_t dev;
65110015Speter	int flag, mode;
65210015Speter	struct proc *p;
65310015Speter{
65410015Speter	int oldspl, error;
65510015Speter	int card, port;
65610015Speter	register struct si_softc *sc;
65710015Speter	register struct tty *tp;
65810015Speter	volatile struct si_channel *ccbp;
65910015Speter	struct si_port *pp;
66010015Speter	int mynor = minor(dev);
66110015Speter
66210015Speter	/* quickly let in /dev/si_control */
66310015Speter	if (IS_CONTROLDEV(mynor)) {
66410015Speter		if (error = suser(p->p_ucred, &p->p_acflag))
66510015Speter			return(error);
66610015Speter		return(0);
66710015Speter	}
66810015Speter
66910015Speter	card = SI_CARD(mynor);
67010015Speter	if (card >= NSI)
67110015Speter		return (ENXIO);
67210015Speter	sc = &si_softc[card];
67310015Speter
67410015Speter	if (sc->sc_type == NULL) {
67510015Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: type %s??\n",
67610015Speter			card, sc->sc_typename));
67710015Speter		return(ENXIO);
67810015Speter	}
67910015Speter
68010015Speter	port = SI_PORT(mynor);
68110015Speter	if (port >= sc->sc_nport) {
68210015Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: nports %d\n",
68310015Speter			card, sc->sc_nport));
68410015Speter		return(ENXIO);
68510015Speter	}
68610015Speter
68710015Speter#ifdef	POLL
68810015Speter	/*
68910015Speter	 * We've now got a device, so start the poller.
69010015Speter	 */
69110015Speter	if (init_finished == 0) {
69210015Speter		timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
69310015Speter		init_finished = 1;
69410015Speter	}
69510015Speter#endif
69610015Speter
69710015Speter	/* initial/lock device */
69810015Speter	if (IS_STATE(mynor)) {
69910015Speter		return(0);
70010015Speter	}
70110015Speter
70210015Speter	pp = sc->sc_ports + port;
70310015Speter	tp = pp->sp_tty;			/* the "real" tty */
70410015Speter	ccbp = pp->sp_ccb;			/* Find control block */
70510015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
70610015Speter		dev, flag, mode, p));
70710015Speter
70810015Speter	oldspl = spltty();			/* Keep others out */
70910015Speter	error = 0;
71010015Speter
71110015Speteropen_top:
71210015Speter	while (pp->sp_state & SS_DTR_OFF) {
71310015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
71410015Speter		if (error != 0)
71510015Speter			goto out;
71610015Speter	}
71710015Speter
71810015Speter	if (tp->t_state & TS_ISOPEN) {
71910015Speter		/*
72010015Speter		 * The device is open, so everything has been initialised.
72110015Speter		 * handle conflicts.
72210015Speter		 */
72310015Speter		if (IS_CALLOUT(mynor)) {
72410015Speter			if (!pp->sp_active_out) {
72510015Speter				error = EBUSY;
72610015Speter				goto out;
72710015Speter			}
72810015Speter		} else {
72910015Speter			if (pp->sp_active_out) {
73010015Speter				if (flag & O_NONBLOCK) {
73110015Speter					error = EBUSY;
73210015Speter					goto out;
73310015Speter				}
73410015Speter				error = tsleep(&pp->sp_active_out,
73510015Speter						TTIPRI|PCATCH, "sibi", 0);
73610015Speter				if (error != 0)
73710015Speter					goto out;
73810015Speter				goto open_top;
73910015Speter			}
74010015Speter		}
74110015Speter		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
74210015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
74310015Speter				"already open and EXCLUSIVE set\n"));
74410015Speter			error = EBUSY;
74510015Speter			goto out;
74610015Speter		}
74710015Speter	} else {
74810015Speter		/*
74910015Speter		 * The device isn't open, so there are no conflicts.
75010015Speter		 * Initialize it. Avoid sleep... :-)
75110015Speter		 */
75210015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
75310015Speter		tp->t_oproc = si_start;
75410015Speter		tp->t_param = siparam;
75510015Speter		tp->t_dev = dev;
75610015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
75710015Speter				? pp->sp_iout : pp->sp_iin;
75810015Speter
75910015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
76010015Speter
76110015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
76210015Speter
76310015Speter		error = siparam(tp, &tp->t_termios);
76410015Speter
76510015Speter		--pp->sp_wopeners;
76610015Speter		if (error != 0)
76710015Speter			goto out;
76810015Speter		/* XXX: we should goto_top if siparam slept */
76910015Speter
77010015Speter		ttsetwater(tp);
77110015Speter
77210015Speter		/* set initial DCD state */
77310015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
77410015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
77510015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
77610015Speter		}
77710015Speter	}
77810015Speter
77910015Speter	/* whoops! we beat the close! */
78010015Speter	if (pp->sp_state & SS_CLOSING) {
78110015Speter		/* try and stop it from proceeding to bash the hardware */
78210015Speter		pp->sp_state &= ~SS_CLOSING;
78310015Speter	}
78410015Speter
78510015Speter	/*
78610015Speter	 * Wait for DCD if necessary
78710015Speter	 */
78810015Speter	if (!(tp->t_state & TS_CARR_ON)
78910015Speter	    && !IS_CALLOUT(mynor)
79010015Speter	    && !(tp->t_cflag & CLOCAL)
79110015Speter	    && !(flag & O_NONBLOCK)) {
79210015Speter		++pp->sp_wopeners;
79310015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
79410015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
79510015Speter		--pp->sp_wopeners;
79610015Speter		if (error != 0)
79710015Speter			goto out;
79810015Speter		goto open_top;
79910015Speter	}
80010015Speter
80110015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
80210015Speter	si_disc_optim(tp, &tp->t_termios, pp);
80310015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
80410015Speter		pp->sp_active_out = TRUE;
80510015Speter
80610015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
80710015Speter
80810015Speterout:
80910015Speter	splx(oldspl);
81010015Speter
81110015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
81210015Speter
81310015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
81410015Speter		sihardclose(pp);
81510015Speter
81610015Speter	return(error);
81710015Speter}
81810015Speter
81910015Speterint
82010015Spetersiclose(dev, flag, mode, p)
82110015Speter	dev_t dev;
82210015Speter	int flag, mode;
82310015Speter	struct proc *p;
82410015Speter{
82510015Speter	register struct si_port *pp;
82610015Speter	register struct tty *tp;
82710015Speter	int oldspl;
82810015Speter	int error = 0;
82910015Speter	int mynor = minor(dev);
83010015Speter
83110015Speter	if (IS_SPECIAL(mynor))
83210015Speter		return(0);
83310015Speter
83410015Speter	oldspl = spltty();
83510015Speter
83610015Speter	pp = MINOR2PP(mynor);
83710015Speter	tp = pp->sp_tty;
83810015Speter
83910015Speter	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
84010015Speter		dev, flag, mode, p, pp->sp_state));
84110015Speter
84210015Speter	/* did we sleep and loose a race? */
84310015Speter	if (pp->sp_state & SS_CLOSING) {
84410015Speter		/* error = ESOMETING? */
84510015Speter		goto out;
84610015Speter	}
84710015Speter
84810015Speter	/* begin race detection.. */
84910015Speter	pp->sp_state |= SS_CLOSING;
85010015Speter
85110015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
85210015Speter
85310015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
85410015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
85510015Speter
85610015Speter	si_write_enable(pp, 1);
85710015Speter
85810015Speter	/* did we sleep and somebody started another open? */
85910015Speter	if (!(pp->sp_state & SS_CLOSING)) {
86010015Speter		/* error = ESOMETING? */
86110015Speter		goto out;
86210015Speter	}
86310015Speter	/* ok. we are now still on the right track.. nuke the hardware */
86410015Speter
86510015Speter	if (pp->sp_state & SS_LSTART) {
86610015Speter		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
86710015Speter		pp->sp_state &= ~SS_LSTART;
86810015Speter	}
86910015Speter
87010015Speter	sistop(tp, FREAD | FWRITE);
87110015Speter
87210015Speter	sihardclose(pp);
87310015Speter	ttyclose(tp);
87410015Speter	pp->sp_state &= ~SS_OPEN;
87510015Speter
87610015Speterout:
87710015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
87810015Speter	splx(oldspl);
87910015Speter	return(error);
88010015Speter}
88110015Speter
88210015Speterstatic void
88310015Spetersihardclose(pp)
88410015Speter	struct si_port *pp;
88510015Speter{
88610015Speter	int oldspl;
88710015Speter	struct tty *tp;
88810015Speter	volatile struct si_channel *ccbp;
88910015Speter
89010015Speter	oldspl = spltty();
89110015Speter
89210015Speter	tp = pp->sp_tty;
89310015Speter	ccbp = pp->sp_ccb;			/* Find control block */
89410015Speter	if (tp->t_cflag & HUPCL
89510015Speter	    || !pp->sp_active_out
89610015Speter	       && !(ccbp->hi_ip & IP_DCD)
89710015Speter	       && !(pp->sp_iin.c_cflag && CLOCAL)
89810015Speter	    || !(tp->t_state & TS_ISOPEN)) {
89910015Speter
90010015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
90110015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
90210015Speter
90310015Speter		if (pp->sp_dtr_wait != 0) {
90410015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
90510015Speter			pp->sp_state |= SS_DTR_OFF;
90610015Speter		}
90710015Speter
90810015Speter	}
90910015Speter	pp->sp_active_out = FALSE;
91010015Speter	wakeup((caddr_t)&pp->sp_active_out);
91110015Speter	wakeup(TSA_CARR_ON(tp));
91210015Speter
91310015Speter	splx(oldspl);
91410015Speter}
91510015Speter
91610015Speter
91710015Speter/*
91810015Speter * called at splsoftclock()...
91910015Speter */
92010015Speterstatic void
92110015Spetersidtrwakeup(chan)
92210015Speter	void *chan;
92310015Speter{
92410015Speter	struct si_port *pp;
92510015Speter	int oldspl;
92610015Speter
92710015Speter	oldspl = spltty();
92810015Speter
92910015Speter	pp = (struct si_port *)chan;
93010015Speter	pp->sp_state &= ~SS_DTR_OFF;
93110015Speter	wakeup(&pp->sp_dtr_wait);
93210015Speter
93310015Speter	splx(oldspl);
93410015Speter}
93510015Speter
93610015Speter/*
93710015Speter * User level stuff - read and write
93810015Speter */
93910015Speterint
94010015Spetersiread(dev, uio, flag)
94110015Speter	register dev_t dev;
94210015Speter	struct uio *uio;
94310015Speter	int flag;
94410015Speter{
94510015Speter	register struct tty *tp;
94610015Speter	int mynor = minor(dev);
94710015Speter
94810015Speter	if (IS_SPECIAL(mynor)) {
94910015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
95010015Speter		return(ENODEV);
95110015Speter	}
95210015Speter	tp = MINOR2TP(mynor);
95310015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
95410015Speter		"siread(%x,%x,%x)\n", dev, uio, flag));
95510015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
95610015Speter}
95710015Speter
95810015Speter
95910015Speterint
96010015Spetersiwrite(dev, uio, flag)
96110015Speter	dev_t dev;
96210015Speter	struct uio *uio;
96310015Speter	int flag;
96410015Speter{
96510015Speter	register struct si_port *pp;
96610015Speter	register struct tty *tp;
96710015Speter	int error = 0;
96810015Speter	int mynor = minor(dev);
96910015Speter	int oldspl;
97010015Speter
97110015Speter	if (IS_SPECIAL(mynor)) {
97210015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
97310015Speter		return(ENODEV);
97410015Speter	}
97510015Speter	pp = MINOR2PP(mynor);
97610015Speter	tp = pp->sp_tty;
97710015Speter	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
97810015Speter
97910015Speter	oldspl = spltty();
98010015Speter	/*
98110015Speter	 * If writes are currently blocked, wait on the "real" tty
98210015Speter	 */
98310015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
98410015Speter		pp->sp_state |= SS_WAITWRITE;
98510015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
98610015Speter		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
98710015Speter				     "siwrite", 0))
98810015Speter			goto out;
98910015Speter	}
99010015Speter
99110015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
99210015Speterout:
99310015Speter	splx(oldspl);
99410015Speter	return (error);
99510015Speter}
99610015Speter
99710015Speter
99810015Speterstruct tty *
99910015Spetersidevtotty(dev_t dev)
100010015Speter{
100110015Speter	struct si_port *pp;
100210015Speter	int mynor = minor(dev);
100310015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
100410015Speter
100510015Speter	if (IS_SPECIAL(mynor))
100610015Speter		return(NULL);
100710015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
100810015Speter		return(NULL);
100910015Speter	pp = MINOR2PP(mynor);
101010015Speter	return (pp->sp_tty);
101110015Speter}
101210015Speter
101310015Speterint
101410015Spetersiioctl(dev, cmd, data, flag, p)
101510015Speter	dev_t dev;
101610015Speter	int cmd;
101710015Speter	caddr_t data;
101810015Speter	int flag;
101910015Speter	struct proc *p;
102010015Speter{
102110015Speter	struct si_port *pp;
102210015Speter	register struct tty *tp;
102310015Speter	int error;
102410015Speter	int mynor = minor(dev);
102510015Speter	int oldspl;
102610015Speter	int blocked = 0;
102710015Speter#if defined(COMPAT_43)
102810015Speter	int oldcmd;
102910015Speter	struct termios term;
103010015Speter#endif
103110015Speter
103210015Speter	if (IS_SI_IOCTL(cmd))
103310015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
103410015Speter
103510015Speter	pp = MINOR2PP(mynor);
103610015Speter	tp = pp->sp_tty;
103710015Speter
103810015Speter	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
103910015Speter		dev, cmd, data, flag));
104010015Speter	if (IS_STATE(mynor)) {
104110015Speter		struct termios *ct;
104210015Speter
104310015Speter		switch (mynor & SI_STATE_MASK) {
104410015Speter		case SI_INIT_STATE_MASK:
104510015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
104610015Speter			break;
104710015Speter		case SI_LOCK_STATE_MASK:
104810015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
104910015Speter			break;
105010015Speter		default:
105110015Speter			return (ENODEV);
105210015Speter		}
105310015Speter		switch (cmd) {
105410015Speter		case TIOCSETA:
105510015Speter			error = suser(p->p_ucred, &p->p_acflag);
105610015Speter			if (error != 0)
105710015Speter				return (error);
105810015Speter			*ct = *(struct termios *)data;
105910015Speter			return (0);
106010015Speter		case TIOCGETA:
106110015Speter			*(struct termios *)data = *ct;
106210015Speter			return (0);
106310015Speter		case TIOCGETD:
106410015Speter			*(int *)data = TTYDISC;
106510015Speter			return (0);
106610015Speter		case TIOCGWINSZ:
106710015Speter			bzero(data, sizeof(struct winsize));
106810015Speter			return (0);
106910015Speter		default:
107010015Speter			return (ENOTTY);
107110015Speter		}
107210015Speter	}
107310015Speter	/*
107410015Speter	 * Do the old-style ioctl compat routines...
107510015Speter	 */
107610015Speter#if defined(COMPAT_43)
107710015Speter	term = tp->t_termios;
107810015Speter	oldcmd = cmd;
107910015Speter	error = ttsetcompat(tp, &cmd, data, &term);
108010015Speter	if (error != 0)
108110015Speter		return (error);
108210015Speter	if (cmd != oldcmd)
108310015Speter		data = (caddr_t)&term;
108410015Speter#endif
108510015Speter	/*
108610015Speter	 * Do the initial / lock state business
108710015Speter	 */
108810015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
108910015Speter		int     cc;
109010015Speter		struct termios *dt = (struct termios *)data;
109110015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
109210015Speter				     ? &pp->sp_lout : &pp->sp_lin;
109310015Speter
109410015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
109510015Speter			| (dt->c_iflag & ~lt->c_iflag);
109610015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
109710015Speter			| (dt->c_oflag & ~lt->c_oflag);
109810015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
109910015Speter			| (dt->c_cflag & ~lt->c_cflag);
110010015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
110110015Speter			| (dt->c_lflag & ~lt->c_lflag);
110210015Speter		for (cc = 0; cc < NCCS; ++cc)
110310015Speter			if (lt->c_cc[cc] != 0)
110410015Speter				dt->c_cc[cc] = tp->t_cc[cc];
110510015Speter		if (lt->c_ispeed != 0)
110610015Speter			dt->c_ispeed = tp->t_ispeed;
110710015Speter		if (lt->c_ospeed != 0)
110810015Speter			dt->c_ospeed = tp->t_ospeed;
110910015Speter	}
111010015Speter
111110015Speter	/*
111210015Speter	 * Block user-level writes to give the ttywait()
111310015Speter	 * a chance to completely drain for commands
111410015Speter	 * that require the port to be in a quiescent state.
111510015Speter	 */
111610015Speter	switch (cmd) {
111710015Speter	case TIOCSETAW: case TIOCSETAF:
111810015Speter	case TIOCDRAIN: case TIOCSETP:
111910015Speter		blocked++;	/* block writes for ttywait() and siparam() */
112010015Speter		si_write_enable(pp, 0);
112110015Speter	}
112210015Speter
112310015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
112410015Speter	if (error >= 0)
112510015Speter		goto out;
112610015Speter
112710015Speter	oldspl = spltty();
112810015Speter
112910015Speter	error = ttioctl(tp, cmd, data, flag);
113010015Speter	si_disc_optim(tp, &tp->t_termios, pp);
113110015Speter	if (error >= 0)
113210015Speter		goto outspl;
113310015Speter
113410015Speter	switch (cmd) {
113510015Speter	case TIOCSBRK:
113610015Speter		si_command(pp, SBREAK, SI_NOWAIT);
113710015Speter		break;
113810015Speter	case TIOCCBRK:
113910015Speter		si_command(pp, EBREAK, SI_NOWAIT);
114010015Speter		break;
114110015Speter	case TIOCSDTR:
114210015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
114310015Speter		break;
114410015Speter	case TIOCCDTR:
114510015Speter		(void) si_modem(pp, SET, 0);
114610015Speter		break;
114710015Speter	case TIOCMSET:
114810015Speter		(void) si_modem(pp, SET, *(int *)data);
114910015Speter		break;
115010015Speter	case TIOCMBIS:
115110015Speter		(void) si_modem(pp, BIS, *(int *)data);
115210015Speter		break;
115310015Speter	case TIOCMBIC:
115410015Speter		(void) si_modem(pp, BIC, *(int *)data);
115510015Speter		break;
115610015Speter	case TIOCMGET:
115710015Speter		*(int *)data = si_modem(pp, GET, 0);
115810015Speter		break;
115910015Speter	case TIOCMSDTRWAIT:
116010015Speter		/* must be root since the wait applies to following logins */
116110015Speter		error = suser(p->p_ucred, &p->p_acflag);
116210015Speter		if (error != 0) {
116310015Speter			goto outspl;
116410015Speter		}
116510015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
116610015Speter		break;
116710015Speter	case TIOCMGDTRWAIT:
116810015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
116910015Speter		break;
117010015Speter
117110015Speter	default:
117210015Speter		error = ENOTTY;
117310015Speter	}
117410015Speter	error = 0;
117510015Speteroutspl:
117610015Speter	splx(oldspl);
117710015Speterout:
117810015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
117910015Speter	if (blocked)
118010015Speter		si_write_enable(pp, 1);
118110015Speter	return(error);
118210015Speter}
118310015Speter
118410015Speter/*
118510015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
118610015Speter */
118710015Speterstatic int
118810015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
118910015Speter{
119010015Speter	struct si_softc *xsc;
119110015Speter	register struct si_port *xpp;
119210015Speter	volatile struct si_reg *regp;
119310015Speter	struct si_tcsi *dp;
119410044Speter	struct si_pstat *sps;
119510015Speter	BYTE *bp;
119610015Speter	int i, *ip, error = 0;
119710015Speter	int oldspl;
119810015Speter	int card, port;
119910015Speter	unsigned short *usp;
120010015Speter	int mynor = minor(dev);
120110015Speter
120210015Speter	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
120310015Speter		dev, cmd, data, flag));
120410015Speter
120510044Speter#if 1
120610044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
120710044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
120810044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
120910044Speter#endif
121010044Speter
121110015Speter	if (!IS_CONTROLDEV(mynor)) {
121210015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
121310015Speter		return(ENODEV);
121410015Speter	}
121510015Speter
121610015Speter	oldspl = spltty();	/* better safe than sorry */
121710015Speter
121810015Speter	ip = (int *)data;
121910015Speter
122010015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
122110015Speter
122210015Speter	switch (cmd) {
122310015Speter	case TCSIPORTS:
122410015Speter		*ip = si_Nports;
122510015Speter		goto out;
122610015Speter	case TCSIMODULES:
122710015Speter		*ip = si_Nmodules;
122810015Speter		goto out;
122910015Speter	case TCSISDBG_ALL:
123010015Speter		SUCHECK;
123110015Speter		si_debug = *ip;
123210015Speter		goto out;
123310015Speter	case TCSIGDBG_ALL:
123410015Speter		*ip = si_debug;
123510015Speter		goto out;
123610015Speter	default:
123710015Speter		/*
123810015Speter		 * Check that a controller for this port exists
123910015Speter		 */
124010044Speter
124110044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
124210044Speter
124310015Speter		dp = (struct si_tcsi *)data;
124410044Speter		sps = (struct si_pstat *)data;
124510015Speter		card = dp->tc_card;
124610015Speter		xsc = &si_softc[card];	/* check.. */
124710015Speter		if (card < 0 || card >= NSI || xsc->sc_type == NULL) {
124810015Speter			error = ENOENT;
124910015Speter			goto out;
125010015Speter		}
125110015Speter		/*
125210015Speter		 * And check that a port exists
125310015Speter		 */
125410015Speter		port = dp->tc_port;
125510015Speter		if (port < 0 || port >= xsc->sc_nport) {
125610015Speter			error = ENOENT;
125710015Speter			goto out;
125810015Speter		}
125910015Speter		xpp = xsc->sc_ports + port;
126010015Speter		regp = (struct si_reg *)xsc->sc_maddr;
126110015Speter	}
126210015Speter
126310015Speter	switch (cmd) {
126410015Speter	case TCSIDEBUG:
126510015Speter#ifdef	SI_DEBUG
126610015Speter		SUCHECK;
126710015Speter		if (xpp->sp_debug)
126810015Speter			xpp->sp_debug = 0;
126910015Speter		else {
127010015Speter			xpp->sp_debug = DBG_ALL;
127110015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
127210015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
127310015Speter		}
127410015Speter		break;
127510015Speter#else
127610015Speter		error = ENODEV;
127710015Speter		goto out;
127810015Speter#endif
127910015Speter	case TCSISDBG_LEVEL:
128010015Speter	case TCSIGDBG_LEVEL:
128110015Speter#ifdef	SI_DEBUG
128210015Speter		if (cmd == TCSIGDBG_LEVEL) {
128310015Speter			dp->tc_dbglvl = xpp->sp_debug;
128410015Speter		} else {
128510015Speter			SUCHECK;
128610015Speter			xpp->sp_debug = dp->tc_dbglvl;
128710015Speter		}
128810015Speter		break;
128910015Speter#else
129010015Speter		error = ENODEV;
129110015Speter		goto out;
129210015Speter#endif
129310015Speter	case TCSIGRXIT:
129410015Speter		dp->tc_int = regp->rx_int_count;
129510015Speter		break;
129610015Speter	case TCSIRXIT:
129710015Speter		SUCHECK;
129810015Speter		regp->rx_int_count = dp->tc_int;
129910015Speter		break;
130010015Speter	case TCSIGIT:
130110015Speter		dp->tc_int = regp->int_count;
130210015Speter		break;
130310015Speter	case TCSIIT:
130410015Speter		SUCHECK;
130510015Speter		regp->int_count = dp->tc_int;
130610015Speter		break;
130710044Speter	case TCSISTATE:
130810044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
130910015Speter		break;
131010044Speter	/* these next three use a different structure */
131110044Speter	case TCSI_PORT:
131210015Speter		SUCHECK;
131310044Speter		sps->tc_siport = *xpp;
131410015Speter		break;
131510044Speter	case TCSI_CCB:
131610044Speter		SUCHECK;
131710044Speter		sps->tc_ccb = *xpp->sp_ccb;
131810015Speter		break;
131910044Speter	case TCSI_TTY:
132010044Speter		SUCHECK;
132110044Speter		sps->tc_tty = *xpp->sp_tty;
132210015Speter		break;
132310015Speter	default:
132410015Speter		error = EINVAL;
132510015Speter		goto out;
132610015Speter	}
132710015Speterout:
132810015Speter	splx(oldspl);
132910015Speter	return(error);		/* success */
133010015Speter}
133110015Speter
133210015Speter/*
133310015Speter *	siparam()	: Configure line params
133410015Speter *	called at spltty();
133510015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
133610015Speter *	caller must arrange this if it's important..
133710015Speter */
133810015Speterint
133910015Spetersiparam(tp, t)
134010015Speter	register struct tty *tp;
134110015Speter	register struct termios *t;
134210015Speter{
134310015Speter	register struct si_port *pp = TP2PP(tp);
134410015Speter	volatile struct si_channel *ccbp;
134510015Speter	int oldspl, cflag, iflag, oflag, lflag;
134610015Speter	int error = 0;		/* shutup gcc */
134710015Speter	int ispeed = 0;		/* shutup gcc */
134810015Speter	int ospeed = 0;		/* shutup gcc */
134910161Speter	BYTE val;
135010015Speter
135110015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
135210015Speter	cflag = t->c_cflag;
135310015Speter	iflag = t->c_iflag;
135410015Speter	oflag = t->c_oflag;
135510015Speter	lflag = t->c_lflag;
135610044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
135710044Speter		oflag, cflag, iflag, lflag));
135810015Speter
135910015Speter
136010015Speter	/* if not hung up.. */
136110015Speter	if (t->c_ospeed != 0) {
136210015Speter		/* translate baud rate to firmware values */
136310015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
136410015Speter		ispeed = t->c_ispeed ?
136510015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
136610015Speter
136710015Speter		/* enforce legit baud rate */
136810015Speter		if (ospeed < 0 || ispeed < 0)
136910015Speter			return (EINVAL);
137010015Speter	}
137110015Speter
137210015Speter
137310015Speter	oldspl = spltty();
137410015Speter
137510015Speter	ccbp = pp->sp_ccb;
137610015Speter
137710161Speter	/* ========== set hi_break ========== */
137810161Speter	val = 0;
137910161Speter	if (iflag & IGNBRK)		/* Breaks */
138010161Speter		val |= BR_IGN;
138110161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
138210161Speter		val |= BR_INT;
138310161Speter	if (iflag & PARMRK)		/* Parity mark? */
138410161Speter		val |= BR_PARMRK;
138510161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
138610161Speter		val |= BR_PARIGN;
138710161Speter	ccbp->hi_break = val;
138810161Speter
138910161Speter	/* ========== set hi_csr ========== */
139010015Speter	/* if not hung up.. */
139110015Speter	if (t->c_ospeed != 0) {
139210015Speter		/* Set I/O speeds */
139310161Speter		 val = (ispeed << 4) | ospeed;
139410015Speter	}
139510161Speter	ccbp->hi_csr = val;
139610015Speter
139710161Speter	/* ========== set hi_mr2 ========== */
139810161Speter	val = 0;
139910015Speter	if (cflag & CSTOPB)				/* Stop bits */
140010161Speter		val |= MR2_2_STOP;
140110015Speter	else
140210161Speter		val |= MR2_1_STOP;
140310161Speter	/*
140410161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
140510161Speter	 * a DCE, hence the reverse sense of RTS and CTS
140610161Speter	 */
140710161Speter	/* Output Flow - RTS must be raised before data can be sent */
140810161Speter	if (cflag & CCTS_OFLOW)
140910161Speter		val |= MR2_RTSCONT;
141010161Speter
141110161Speter	ccbp->hi_mr1 = val;
141210161Speter
141310161Speter	/* ========== set hi_mr1 ========== */
141410161Speter	val = 0;
141510015Speter	if (!(cflag & PARENB))				/* Parity */
141610161Speter		val |= MR1_NONE;
141710015Speter	else
141810161Speter		val |= MR1_WITH;
141910015Speter	if (cflag & PARODD)
142010161Speter		val |= MR1_ODD;
142110015Speter
142210015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
142310161Speter		val |= MR1_8_BITS;
142410015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
142510161Speter		val |= MR1_7_BITS;
142610015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
142710161Speter		val |= MR1_6_BITS;
142810015Speter	} else {					/* Must be 5 */
142910161Speter		val |= MR1_5_BITS;
143010015Speter	}
143110161Speter	/*
143210161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
143310161Speter	 * a DCE, hence the reverse sense of RTS and CTS
143410161Speter	 */
143510161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
143610161Speter	if (cflag & CRTS_IFLOW)
143710161Speter		val |= MR1_CTSCONT;
143810015Speter
143910161Speter	ccbp->hi_mr1 = val;
144010161Speter
144110161Speter	/* ========== set hi_mask ========== */
144210161Speter	val = 0xff;
144310161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
144410161Speter		val &= 0xFF;
144510161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
144610161Speter		val &= 0x7F;
144710161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
144810161Speter		val &= 0x3F;
144910161Speter	} else {					/* Must be 5 */
145010161Speter		val &= 0x1F;
145110161Speter	}
145210015Speter	if (iflag & ISTRIP)
145310161Speter		val &= 0x7F;
145410015Speter
145510161Speter	ccbp->hi_mask = val;
145610161Speter
145710161Speter	/* ========== set hi_prtcl ========== */
145810161Speter	val = 0;
145910015Speter				/* Monitor DCD etc. if a modem */
146010015Speter	if (!(cflag & CLOCAL))
146110161Speter		val |= SP_DCEN;
146210161Speter	if (iflag & IXANY)
146310161Speter		val |= SP_TANY;
146410161Speter	if (iflag & IXON)
146510161Speter		val |= SP_TXEN;
146610161Speter	if (iflag & IXOFF)
146710161Speter		val |= SP_RXEN;
146810161Speter	if (iflag & INPCK)
146910161Speter		val |= SP_PAEN;
147010015Speter
147110161Speter	ccbp->hi_prtcl = val;
147210161Speter
147310161Speter
147410161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
147510161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
147610015Speter	ccbp->hi_txon = t->c_cc[VSTART];
147710015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
147810015Speter
147910015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
148010015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
148110015Speter
148210161Speter	/* ========== send settings to the card ========== */
148310015Speter	/* potential sleep here */
148410015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
148510015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
148610015Speter	else
148710015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
148810015Speter
148910161Speter	/* ========== set DTR etc ========== */
149010015Speter	/* Hangup if ospeed == 0 */
149110015Speter	if (t->c_ospeed == 0) {
149210015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
149310015Speter	} else {
149410015Speter		/*
149510015Speter		 * If the previous speed was 0, may need to re-enable
149610015Speter	 	 * the modem signals
149710015Speter	 	 */
149810015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
149910015Speter	}
150010015Speter
150110044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
150210044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
150310015Speter
150410015Speter	splx(oldspl);
150510015Speterout:
150610015Speter	return(error);
150710015Speter}
150810015Speter
150910015Speter/*
151010015Speter * Enable or Disable the writes to this channel...
151110015Speter * "state" ->  enabled = 1; disabled = 0;
151210015Speter */
151310015Speterstatic void
151410015Spetersi_write_enable(pp, state)
151510015Speter	register struct si_port *pp;
151610015Speter	int state;
151710015Speter{
151810015Speter	int oldspl;
151910015Speter
152010015Speter	oldspl = spltty();
152110015Speter
152210015Speter	if (state) {
152310015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
152410015Speter		if (pp->sp_state & SS_WAITWRITE) {
152510015Speter			pp->sp_state &= ~SS_WAITWRITE;
152610015Speter			/* thunder away! */
152710015Speter			wakeup((caddr_t)pp);
152810015Speter		}
152910015Speter	} else {
153010015Speter		pp->sp_state |= SS_BLOCKWRITE;
153110015Speter	}
153210015Speter
153310015Speter	splx(oldspl);
153410015Speter}
153510015Speter
153610015Speter/*
153710015Speter * Set/Get state of modem control lines.
153810015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
153910015Speter *	TIOCM_DTR	DSR
154010015Speter *	TIOCM_RTS	CTS
154110015Speter */
154210015Speterstatic int
154310015Spetersi_modem(pp, cmd, bits)
154410015Speter	struct si_port *pp;
154510015Speter	enum si_mctl cmd;
154610015Speter	int bits;
154710015Speter{
154810015Speter	volatile struct si_channel *ccbp;
154910015Speter	int x;
155010015Speter
155110015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
155210015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
155310015Speter	switch (cmd) {
155410015Speter	case GET:
155510015Speter		x = ccbp->hi_ip;
155610015Speter		bits = TIOCM_LE;
155710015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
155810015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
155910015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
156010015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
156110015Speter		return(bits);
156210015Speter	case SET:
156310015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
156410015Speter		/* fall through */
156510015Speter	case BIS:
156610015Speter		x = 0;
156710015Speter		if (bits & TIOCM_DTR)
156810015Speter			x |= OP_DSR;
156910015Speter		if (bits & TIOCM_RTS)
157010015Speter			x |= OP_CTS;
157110015Speter		ccbp->hi_op |= x;
157210015Speter		break;
157310015Speter	case BIC:
157410015Speter		if (bits & TIOCM_DTR)
157510015Speter			ccbp->hi_op &= ~OP_DSR;
157610015Speter		if (bits & TIOCM_RTS)
157710015Speter			ccbp->hi_op &= ~OP_CTS;
157810015Speter	}
157910015Speter	return 0;
158010015Speter}
158110015Speter
158210015Speter/*
158310015Speter * Handle change of modem state
158410015Speter */
158510015Speterstatic void
158610015Spetersi_modem_state(pp, tp, hi_ip)
158710015Speter	register struct si_port *pp;
158810015Speter	register struct tty *tp;
158910015Speter	register int hi_ip;
159010015Speter{
159110015Speter							/* if a modem dev */
159210015Speter	if (hi_ip & IP_DCD) {
159310015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
159410015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
159510015Speter				tp->t_line));
159610015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
159710015Speter		}
159810015Speter	} else {
159910015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
160010015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
160110015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
160210015Speter				(void) si_modem(pp, SET, 0);
160310015Speter		}
160410015Speter	}
160510015Speter	pp->sp_last_hi_ip = hi_ip;
160610015Speter
160710015Speter}
160810015Speter
160910015Speter/*
161010015Speter * Poller to catch missed interrupts.
161110015Speter */
161210015Speter#ifdef POLL
161310015Spetervoid
161410015Spetersi_poll(void *nothing)
161510015Speter{
161610015Speter	register struct si_softc *sc;
161710015Speter	register int i;
161810015Speter	volatile struct si_reg *regp;
161910015Speter	int lost, oldspl;
162010015Speter
162110015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
162210015Speter	if (in_intr)
162310015Speter		goto out;
162410015Speter	oldspl = spltty();
162510015Speter	lost = 0;
162610015Speter	for (i=0; i<NSI; i++) {
162710015Speter		sc = &si_softc[i];
162810015Speter		if (sc->sc_type == NULL)
162910015Speter			continue;
163010015Speter		regp = (struct si_reg *)sc->sc_maddr;
163110015Speter		/*
163210015Speter		 * See if there has been a pending interrupt for 2 seconds
163310015Speter		 * or so. The test <int_scounter >= 200) won't correspond
163410015Speter		 * to 2 seconds if int_count gets changed.
163510015Speter		 */
163610015Speter		if (regp->int_pending != 0) {
163710015Speter			if (regp->int_scounter >= 200 &&
163810015Speter			    regp->initstat == 1) {
163910015Speter				printf("SLXOS si%d: lost intr\n", i);
164010015Speter				lost++;
164110015Speter			}
164210015Speter		} else {
164310015Speter			regp->int_scounter = 0;
164410015Speter		}
164510015Speter
164610015Speter	}
164710015Speter	if (lost)
164810015Speter		siintr(-1);	/* call intr with fake vector */
164910015Speter	splx(oldspl);
165010015Speter
165110015Speterout:
165210015Speter	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
165310015Speter}
165410015Speter#endif	/* ifdef POLL */
165510015Speter
165610015Speter/*
165710015Speter * The interrupt handler polls ALL ports on ALL adapters each time
165810015Speter * it is called.
165910015Speter */
166010015Speter
166110161Speterstatic BYTE rxbuf[SLXOS_BUFFERSIZE];	/* input staging area */
166210015Speter
166310015Speterint
166410015Spetersiintr(int bdnum)
166510015Speter{
166610015Speter	struct si_softc *Isc = NULL;
166710015Speter	register struct si_softc *sc;
166810015Speter
166910015Speter	register struct si_port *pp;
167010015Speter	volatile struct si_channel *ccbp;
167110015Speter	register struct tty *tp;
167210015Speter	volatile caddr_t maddr;
167310015Speter	BYTE op, ip, cc;
167410161Speter	int x, card, port, n, i;
167510015Speter	volatile BYTE *z;
167610015Speter	BYTE c;
167710015Speter	static int in_poll = 0;
167810015Speter
167910015Speter	if (bdnum < 0) {
168010015Speter		Isc = NULL;
168110015Speter		in_poll = 1;
168210015Speter	} else {
168310015Speter		Isc = &si_softc[bdnum];
168410015Speter	}
168510015Speter
168610015Speter	DPRINT((0, (Isc == 0)?DBG_POLL:DBG_INTR, "siintr(0x%x)\n", Isc));
168710015Speter	if (in_intr != 0) {
168810015Speter		if (Isc == NULL)	/* should never happen */
168910015Speter			return(0);
169010015Speter		printf("SLXOS si%d: Warning interrupt handler re-entered\n",
169110015Speter			Isc==0 ? -1 : Isc->sc_dev.dv_unit);
169210015Speter		return(0);
169310015Speter	}
169410015Speter	in_intr = 1;
169510015Speter
169610015Speter	/*
169710015Speter	 * When we get an int we poll all the channels and do ALL pending
169810015Speter	 * work, not just the first one we find. This allows all cards to
169910015Speter	 * share the same vector.
170010015Speter	 */
170110015Speter	for (card=0; card < NSI; card++) {
170210015Speter		sc = &si_softc[card];
170310015Speter		if (sc->sc_type == NULL)
170410015Speter			continue;
170510015Speter		switch(sc->sc_type) {
170610015Speter		case SIHOST :
170710015Speter			maddr = sc->sc_maddr;
170810015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
170910015Speter							/* flag nothing pending */
171010015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
171110015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
171210015Speter			break;
171310015Speter		case SIHOST2:
171410015Speter			maddr = sc->sc_maddr;
171510015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
171610015Speter			*(maddr+SIPLIRQCLR) = 0x00;
171710015Speter			*(maddr+SIPLIRQCLR) = 0x10;
171810015Speter			break;
171910015Speter		case SIEISA:
172010015Speter#if NEISA > 0
172110015Speter			maddr = sc->sc_maddr;
172210015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
172310015Speter			(void)inb(sc->sc_eisa_iobase+3);
172410015Speter			break;
172510015Speter#endif	/* fall through if not EISA kernel */
172610015Speter		case SIEMPTY:
172710015Speter		default:
172810015Speter			continue;
172910015Speter		}
173010015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
173110015Speter
173210015Speter		for (pp = sc->sc_ports, port=0;
173310015Speter		     port < sc->sc_nport;
173410015Speter		     pp++, port++) {
173510015Speter			ccbp = pp->sp_ccb;
173610015Speter			tp = pp->sp_tty;
173710015Speter
173810015Speter			/*
173910015Speter			 * See if a command has completed ?
174010015Speter			 */
174110015Speter			if (ccbp->hi_stat != pp->sp_pend) {
174210015Speter				DPRINT((pp, DBG_INTR,
174310015Speter					"siintr hi_stat = 0x%x, pend = %d\n",
174410015Speter					ccbp->hi_stat, pp->sp_pend));
174510015Speter				switch(pp->sp_pend) {
174610015Speter				case LOPEN:
174710015Speter				case MPEND:
174810015Speter				case MOPEN:
174910015Speter				case CONFIG:
175010015Speter					pp->sp_pend = ccbp->hi_stat;
175110015Speter						/* sleeping in si_command */
175210015Speter					wakeup(&pp->sp_state);
175310015Speter					break;
175410015Speter				default:
175510015Speter					pp->sp_pend = ccbp->hi_stat;
175610015Speter				}
175710015Speter	 		}
175810015Speter
175910015Speter			/*
176010015Speter			 * Continue on if it's closed
176110015Speter			 */
176210015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
176310015Speter				continue;
176410015Speter			}
176510015Speter
176610015Speter			/*
176710015Speter			 * Do modem state change if not a local device
176810015Speter			 */
176910015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
177010015Speter
177110015Speter			/*
177210015Speter			 * Do break processing
177310015Speter			 */
177410015Speter			if (ccbp->hi_state & ST_BREAK) {
177510672Speter				if (tp->t_state & TS_CONNECTED &&
177610672Speter				    tp->t_state & TS_ISOPEN) {
177710015Speter					(*linesw[tp->t_line].l_rint)(TTY_BI, tp);
177810015Speter				}
177910015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
178010015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
178110015Speter			}
178210015Speter
178310015Speter			/*
178410015Speter			 * Do RX stuff - if not open then
178510015Speter			 * dump any characters.
178610015Speter			 */
178710015Speter
178810672Speter			if ((tp->t_state & TS_CONNECTED) == 0 ||
178910672Speter			    (tp->t_state & TS_ISOPEN) == 0) {
179010015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
179110015Speter			} else {
179210015Speter				while ((c = ccbp->hi_rxipos - ccbp->hi_rxopos) != 0) {
179310015Speter
179410015Speter					op = ccbp->hi_rxopos;
179510015Speter					ip = ccbp->hi_rxipos;
179610015Speter					n = c & 0xff;
179710015Speter
179810015Speter					DPRINT((pp, DBG_INTR,
179910015Speter						"n = %d, op = %d, ip = %d\n",
180010015Speter						n, op, ip));
180110015Speter					if (n <= SLXOS_BUFFERSIZE - op) {
180210015Speter
180310015Speter						DPRINT((pp, DBG_INTR,
180410015Speter							"\tsingle copy\n"));
180510015Speter						z = ccbp->hi_rxbuf + op;
180610015Speter						bcopy((caddr_t)z, rxbuf, n);
180710015Speter
180810015Speter						op += n;
180910015Speter					} else {
181010015Speter						x = SLXOS_BUFFERSIZE - op;
181110015Speter
181210015Speter						DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
181310015Speter						z = ccbp->hi_rxbuf + op;
181410015Speter						bcopy((caddr_t)z, rxbuf, x);
181510015Speter
181610015Speter						DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
181710015Speter						z = ccbp->hi_rxbuf;
181810015Speter						bcopy((caddr_t)z, rxbuf+x, n-x);
181910015Speter
182010015Speter						op += n;
182110015Speter					}
182210015Speter
182310015Speter					ccbp->hi_rxopos = op;
182410015Speter
182510015Speter					DPRINT((pp, DBG_INTR,
182610015Speter						"n = %d, op = %d, ip = %d\n",
182710015Speter						n, op, ip));
182810015Speter
182910015Speter					/*
183010015Speter					 * at this point...
183110015Speter					 * n = number of chars placed in rxbuf
183210015Speter					 */
183310015Speter		/*
183410015Speter		 * Avoid the grotesquely inefficient lineswitch routine
183510015Speter		 * (ttyinput) in "raw" mode.  It usually takes about 450
183610015Speter		 * instructions (that's without canonical processing or echo!).
183710015Speter		 * slinput is reasonably fast (usually 40 instructions plus
183810015Speter		 * call overhead).
183910015Speter		 */
184010015Speter					if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
184110015Speter
184210015Speter						/* block if the driver supports it */
184310015Speter						if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
184410015Speter						    && (tp->t_cflag & CRTS_IFLOW
184510015Speter							|| tp->t_iflag & IXOFF)
184610015Speter						    && !(tp->t_state & TS_TBLOCK))
184710015Speter							ttyblock(tp);
184810015Speter
184910015Speter						tk_nin += n;
185010015Speter						tk_rawcc += n;
185110015Speter						tp->t_rawcc += n;
185210015Speter
185310015Speter						b_to_q((char *)rxbuf, n, &tp->t_rawq);
185410015Speter						ttwakeup(tp);
185510015Speter						if (tp->t_state & TS_TTSTOP
185610015Speter						    && (tp->t_iflag & IXANY
185710015Speter							|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
185810015Speter							tp->t_state &= ~TS_TTSTOP;
185910015Speter							tp->t_lflag &= ~FLUSHO;
186010015Speter							si_start(tp);
186110015Speter						}
186210015Speter					} else {
186310015Speter						for(x = 0; x < n; x++) {
186410161Speter							i = rxbuf[x];
186510161Speter							(*linesw[tp->t_line].l_rint)(rxbuf[x], tp);
186610161Speter							if (pp->sp_hotchar && i == pp->sp_hotchar) {
186710161Speter								setsofttty();
186810161Speter							}
186910015Speter						}
187010015Speter					}
187110015Speter
187210015Speter				} /* end of RX while */
187310015Speter			} /* end TS_CONNECTED */
187410015Speter
187510015Speter			/*
187610015Speter			 * Do TX stuff
187710015Speter			 */
187810015Speter			(*linesw[tp->t_line].l_start)(tp);
187910015Speter
188010015Speter		} /* end of for (all ports on this controller) */
188110015Speter	} /* end of for (all controllers) */
188210015Speter
188310015Speter	in_poll = in_intr = 0;
188410015Speter	DPRINT((0, (Isc==0)?DBG_POLL:DBG_INTR, "end of siintr()\n"));
188510015Speter	return(1);		/* say it was expected */
188610015Speter}
188710015Speter
188810015Speter/*
188910015Speter * Nudge the transmitter...
189010015Speter */
189110015Speterstatic void
189210015Spetersi_start(tp)
189310015Speter	register struct tty *tp;
189410015Speter{
189510015Speter	struct si_port *pp;
189610015Speter	volatile struct si_channel *ccbp;
189710015Speter	register struct clist *qp;
189810015Speter	register char *dptr;
189910015Speter	BYTE ipos;
190010015Speter	int nchar;
190110015Speter	int oldspl, count, n, amount, buffer_full;
190210015Speter	int do_exitproc;
190310015Speter
190410015Speter	oldspl = spltty();
190510015Speter
190610015Speter	qp = &tp->t_outq;
190710015Speter	pp = TP2PP(tp);
190810015Speter
190910015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
191010015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
191110015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
191210015Speter
191310015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
191410015Speter		goto out;
191510015Speter
191610015Speter	do_exitproc = 0;
191710015Speter	buffer_full = 0;
191810015Speter	ccbp = pp->sp_ccb;
191910015Speter
192010015Speter	/*
192110015Speter	 * Handle the case where ttywait() is called on process exit
192210015Speter	 * this may be BSDI specific, I dont know...
192310015Speter	 */
192410015Speter	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
192510015Speter	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
192610015Speter		do_exitproc++;
192710015Speter	}
192810015Speter
192910015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
193010015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
193110015Speter
193210015Speter	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
193310015Speter
193410015Speter	while ((nchar = qp->c_cc) > 0) {
193510015Speter		if ((BYTE)count >= 255) {
193610015Speter			buffer_full++;
193710015Speter			break;
193810015Speter		}
193910015Speter		amount = min(nchar, (255 - (BYTE)count));
194010015Speter		ipos = (unsigned int)ccbp->hi_txipos;
194110015Speter		/* will it fit in one lump? */
194210015Speter		if ((SLXOS_BUFFERSIZE - ipos) >= amount) {
194310015Speter			n = q_to_b(&tp->t_outq,
194410015Speter				(char *)&ccbp->hi_txbuf[ipos], amount);
194510015Speter		} else {
194610015Speter			n = q_to_b(&tp->t_outq,
194710015Speter				(char *)&ccbp->hi_txbuf[ipos],
194810015Speter				SLXOS_BUFFERSIZE-ipos);
194910015Speter			if (n == SLXOS_BUFFERSIZE-ipos) {
195010015Speter				n += q_to_b(&tp->t_outq,
195110015Speter					(char *)&ccbp->hi_txbuf[0],
195210015Speter					amount - (SLXOS_BUFFERSIZE-ipos));
195310015Speter			}
195410015Speter		}
195510015Speter		ccbp->hi_txipos += n;
195610015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
195710015Speter	}
195810015Speter
195910015Speter	if (count != 0 && nchar == 0) {
196010015Speter		tp->t_state |= TS_BUSY;
196110015Speter	} else {
196210015Speter		tp->t_state &= ~TS_BUSY;
196310015Speter	}
196410015Speter
196510015Speter	/* wakeup time? */
196610015Speter	ttwwakeup(tp);
196710015Speter
196810015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
196910015Speter		(BYTE)count, nchar, tp->t_state));
197010015Speter
197110015Speter	if ((tp->t_state & TS_BUSY) || do_exitproc)
197210015Speter	{
197310015Speter		int time;
197410015Speter
197510015Speter		if (do_exitproc != 0) {
197610015Speter			time = hz / 10;
197710015Speter		} else {
197810015Speter			time = ttspeedtab(tp->t_ospeed, chartimes);
197910015Speter
198010015Speter			if (time > 0) {
198110015Speter				if (time < nchar)
198210015Speter					time = nchar / time;
198310015Speter				else
198410015Speter					time = 2;
198510015Speter			} else {
198610015Speter				printf("SLXOS si%d: bad char time value!!\n",
198710015Speter					SI_CARD(tp->t_dev));
198810015Speter				goto out;
198910015Speter			}
199010015Speter		}
199110015Speter
199210015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
199310015Speter			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
199410015Speter		} else {
199510015Speter			pp->sp_state |= SS_LSTART;
199610015Speter		}
199710015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
199810015Speter		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
199910015Speter	}
200010015Speter
200110015Speterout:
200210015Speter	splx(oldspl);
200310015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
200410015Speter}
200510015Speter
200610015Speter/*
200710015Speter * Note: called at splsoftclock from the timeout code
200810015Speter * This has to deal with two things...  cause wakeups while waiting for
200910015Speter * tty drains on last process exit, and call l_start at about the right
201010015Speter * time for protocols like ppp.
201110015Speter */
201210015Speterstatic void
201310015Spetersi_lstart(pp)
201410015Speter	register struct si_port *pp;
201510015Speter{
201610015Speter	register struct tty *tp;
201710015Speter	int oldspl;
201810015Speter
201910015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
202010015Speter		pp, pp->sp_state));
202110015Speter
202210015Speter	oldspl = spltty();
202310015Speter
202410015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
202510015Speter		splx(oldspl);
202610015Speter		return;
202710015Speter	}
202810015Speter	pp->sp_state &= ~SS_LSTART;
202910015Speter	pp->sp_state |= SS_INLSTART;
203010015Speter
203110015Speter	tp = pp->sp_tty;
203210015Speter
203310015Speter	/* deal with the process exit case */
203410015Speter	ttwwakeup(tp);
203510015Speter
203610015Speter	/* nudge protocols */
203710015Speter	(*linesw[tp->t_line].l_start)(tp);
203810015Speter
203910015Speter	pp->sp_state &= ~SS_INLSTART;
204010015Speter	splx(oldspl);
204110015Speter}
204210015Speter
204310015Speter/*
204410015Speter * Stop output on a line. called at spltty();
204510015Speter */
204610015Spetervoid
204710015Spetersistop(tp, rw)
204810015Speter	register struct tty *tp;
204910015Speter	int rw;
205010015Speter{
205110015Speter	volatile struct si_channel *ccbp;
205210015Speter	struct si_port *pp;
205310015Speter
205410015Speter	pp = TP2PP(tp);
205510015Speter	ccbp = pp->sp_ccb;
205610015Speter
205710015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
205810015Speter
205910015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
206010015Speter	if (rw & FWRITE) {
206110015Speter		/* what level are we meant to be flushing anyway? */
206210015Speter		if (tp->t_state & TS_BUSY) {
206310015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
206410015Speter			tp->t_state &= ~TS_BUSY;
206510015Speter			ttwwakeup(tp);	/* Bruce???? */
206610015Speter		}
206710015Speter	}
206810015Speter#if 0	/* this doesn't work right yet.. */
206910015Speter	if (rw & FREAD) {
207010015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
207110015Speter	}
207210015Speter#endif
207310015Speter}
207410015Speter
207510015Speter/*
207610015Speter * Issue a command to the Z280 host card CPU.
207710015Speter */
207810015Speter
207910015Speterstatic void
208010015Spetersi_command(pp, cmd, waitflag)
208110015Speter	struct si_port *pp;		/* port control block (local) */
208210015Speter	int cmd;
208310015Speter	int waitflag;
208410015Speter{
208510015Speter	int oldspl;
208610015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
208710015Speter	int x;
208810015Speter
208910015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
209010015Speter		pp, cmd, waitflag, ccbp->hi_stat));
209110015Speter
209210015Speter	oldspl = spltty();		/* Keep others out */
209310015Speter
209410015Speter	/* wait until it's finished what it was doing.. */
209510015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
209610015Speter			x != IDLE_CLOSE &&
209710015Speter			x != cmd) {
209810015Speter		if (in_intr) {			/* Prevent sleep in intr */
209910015Speter			DPRINT((pp, DBG_PARAM,
210010015Speter				"cmd intr collision - completing %d\trequested %d\n",
210110015Speter				x, cmd));
210210015Speter			splx(oldspl);
210310015Speter			return;
210410015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
210510015Speter				"sicmd1", 1)) {
210610015Speter			splx(oldspl);
210710015Speter			return;
210810015Speter		}
210910015Speter	}
211010015Speter	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
211110015Speter
211210015Speter	/* if there was a pending command, cause a state-change wakeup */
211310015Speter	if (pp->sp_pend != IDLE_OPEN) {
211410015Speter		switch(pp->sp_pend) {
211510015Speter		case LOPEN:
211610015Speter		case MPEND:
211710015Speter		case MOPEN:
211810015Speter		case CONFIG:
211910015Speter			wakeup(&pp->sp_state);
212010015Speter			break;
212110015Speter		default:
212210015Speter			break;
212310015Speter		}
212410015Speter	}
212510015Speter
212610015Speter	pp->sp_pend = cmd;		/* New command pending */
212710015Speter	ccbp->hi_stat = cmd;		/* Post it */
212810015Speter
212910015Speter	if (waitflag) {
213010015Speter		if (in_intr) {		/* If in interrupt handler */
213110015Speter			DPRINT((pp, DBG_PARAM,
213210015Speter				"attempt to sleep in si_intr - cmd req %d\n",
213310015Speter				cmd));
213410015Speter			splx(oldspl);
213510015Speter			return;
213610015Speter		} else while(ccbp->hi_stat != IDLE_OPEN) {
213710015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
213810015Speter			    "sicmd2", 0))
213910015Speter				break;
214010015Speter		}
214110015Speter	}
214210015Speter	splx(oldspl);
214310015Speter}
214410015Speter
214510015Speterstatic void
214610015Spetersi_disc_optim(tp, t, pp)
214710015Speter	struct tty	*tp;
214810015Speter	struct termios	*t;
214910015Speter	struct si_port	*pp;
215010015Speter{
215110015Speter	/*
215210015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
215310015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
215410015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
215510015Speter	 */
215610015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
215710015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
215810015Speter	    && (!(t->c_iflag & PARMRK)
215910015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
216010015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
216110015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
216210015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
216310015Speter	else
216410015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
216510161Speter
216610015Speter	/*
216710015Speter	 * Prepare to reduce input latency for packet
216810015Speter	 * discplines with a end of packet character.
216910015Speter	 */
217010015Speter	if (tp->t_line == SLIPDISC)
217110015Speter		pp->sp_hotchar = 0xc0;
217210015Speter	else if (tp->t_line == PPPDISC)
217310015Speter		pp->sp_hotchar = 0x7e;
217410015Speter	else
217510015Speter		pp->sp_hotchar = 0;
217610161Speter
217710161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
217810161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
217910161Speter		pp->sp_hotchar));
218010015Speter}
218110015Speter
218210015Speter
218310015Speter#ifdef	SI_DEBUG
218410015Speterstatic void
218510015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6)
218610015Speter	struct si_port *pp;
218710015Speter	int flags;
218810015Speter	char *str;
218910015Speter	int a1, a2, a3, a4, a5, a6;
219010015Speter{
219110015Speter	if ((pp == NULL && (si_debug&flags)) ||
219210015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
219310015Speter	    	if (pp != NULL)
219410015Speter	    		printf("SLXOS %ci%d(%d): ", 's',
219510015Speter	    			SI_CARD(pp->sp_tty->t_dev),
219610015Speter	    			SI_PORT(pp->sp_tty->t_dev));
219710015Speter		printf(str, a1, a2, a3, a4, a5, a6);
219810015Speter	}
219910015Speter}
220010015Speter
220110015Speterstatic char *
220210015Spetersi_mctl2str(cmd)
220310015Speter	enum si_mctl cmd;
220410015Speter{
220510015Speter	switch (cmd) {
220610015Speter	case GET:	return("GET");
220710015Speter	case SET:	return("SET");
220810015Speter	case BIS:	return("BIS");
220910015Speter	case BIC:	return("BIC");
221010015Speter	}
221110015Speter	return("BAD");
221210015Speter}
221310015Speter#endif
2214