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