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