si.c revision 11872
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 *
3311872Sphk *	$Id: si.c,v 1.10 1995/10/21 09:10:49 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;
120111872Sphk	int *ip, error = 0;
120210015Speter	int oldspl;
120310015Speter	int card, port;
120410015Speter	int mynor = minor(dev);
120510015Speter
120610015Speter	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
120710015Speter		dev, cmd, data, flag));
120810015Speter
120910044Speter#if 1
121010044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
121110044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
121210044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
121310044Speter#endif
121410044Speter
121510015Speter	if (!IS_CONTROLDEV(mynor)) {
121610015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
121710015Speter		return(ENODEV);
121810015Speter	}
121910015Speter
122010015Speter	oldspl = spltty();	/* better safe than sorry */
122110015Speter
122210015Speter	ip = (int *)data;
122310015Speter
122410015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
122510015Speter
122610015Speter	switch (cmd) {
122710015Speter	case TCSIPORTS:
122810015Speter		*ip = si_Nports;
122910015Speter		goto out;
123010015Speter	case TCSIMODULES:
123110015Speter		*ip = si_Nmodules;
123210015Speter		goto out;
123310015Speter	case TCSISDBG_ALL:
123410015Speter		SUCHECK;
123510015Speter		si_debug = *ip;
123610015Speter		goto out;
123710015Speter	case TCSIGDBG_ALL:
123810015Speter		*ip = si_debug;
123910015Speter		goto out;
124010015Speter	default:
124110015Speter		/*
124210015Speter		 * Check that a controller for this port exists
124310015Speter		 */
124410044Speter
124510044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
124610044Speter
124710015Speter		dp = (struct si_tcsi *)data;
124810044Speter		sps = (struct si_pstat *)data;
124910015Speter		card = dp->tc_card;
125010015Speter		xsc = &si_softc[card];	/* check.. */
125110015Speter		if (card < 0 || card >= NSI || xsc->sc_type == NULL) {
125210015Speter			error = ENOENT;
125310015Speter			goto out;
125410015Speter		}
125510015Speter		/*
125610015Speter		 * And check that a port exists
125710015Speter		 */
125810015Speter		port = dp->tc_port;
125910015Speter		if (port < 0 || port >= xsc->sc_nport) {
126010015Speter			error = ENOENT;
126110015Speter			goto out;
126210015Speter		}
126310015Speter		xpp = xsc->sc_ports + port;
126410015Speter		regp = (struct si_reg *)xsc->sc_maddr;
126510015Speter	}
126610015Speter
126710015Speter	switch (cmd) {
126810015Speter	case TCSIDEBUG:
126910015Speter#ifdef	SI_DEBUG
127010015Speter		SUCHECK;
127110015Speter		if (xpp->sp_debug)
127210015Speter			xpp->sp_debug = 0;
127310015Speter		else {
127410015Speter			xpp->sp_debug = DBG_ALL;
127510015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
127610015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
127710015Speter		}
127810015Speter		break;
127910015Speter#else
128010015Speter		error = ENODEV;
128110015Speter		goto out;
128210015Speter#endif
128310015Speter	case TCSISDBG_LEVEL:
128410015Speter	case TCSIGDBG_LEVEL:
128510015Speter#ifdef	SI_DEBUG
128610015Speter		if (cmd == TCSIGDBG_LEVEL) {
128710015Speter			dp->tc_dbglvl = xpp->sp_debug;
128810015Speter		} else {
128910015Speter			SUCHECK;
129010015Speter			xpp->sp_debug = dp->tc_dbglvl;
129110015Speter		}
129210015Speter		break;
129310015Speter#else
129410015Speter		error = ENODEV;
129510015Speter		goto out;
129610015Speter#endif
129710015Speter	case TCSIGRXIT:
129810015Speter		dp->tc_int = regp->rx_int_count;
129910015Speter		break;
130010015Speter	case TCSIRXIT:
130110015Speter		SUCHECK;
130210015Speter		regp->rx_int_count = dp->tc_int;
130310015Speter		break;
130410015Speter	case TCSIGIT:
130510015Speter		dp->tc_int = regp->int_count;
130610015Speter		break;
130710015Speter	case TCSIIT:
130810015Speter		SUCHECK;
130910015Speter		regp->int_count = dp->tc_int;
131010015Speter		break;
131110044Speter	case TCSISTATE:
131210044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
131310015Speter		break;
131410044Speter	/* these next three use a different structure */
131510044Speter	case TCSI_PORT:
131610015Speter		SUCHECK;
131710044Speter		sps->tc_siport = *xpp;
131810015Speter		break;
131910044Speter	case TCSI_CCB:
132010044Speter		SUCHECK;
132110044Speter		sps->tc_ccb = *xpp->sp_ccb;
132210015Speter		break;
132310044Speter	case TCSI_TTY:
132410044Speter		SUCHECK;
132510044Speter		sps->tc_tty = *xpp->sp_tty;
132610015Speter		break;
132710015Speter	default:
132810015Speter		error = EINVAL;
132910015Speter		goto out;
133010015Speter	}
133110015Speterout:
133210015Speter	splx(oldspl);
133310015Speter	return(error);		/* success */
133410015Speter}
133510015Speter
133610015Speter/*
133710015Speter *	siparam()	: Configure line params
133810015Speter *	called at spltty();
133910015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
134010015Speter *	caller must arrange this if it's important..
134110015Speter */
134210015Speterint
134310015Spetersiparam(tp, t)
134410015Speter	register struct tty *tp;
134510015Speter	register struct termios *t;
134610015Speter{
134710015Speter	register struct si_port *pp = TP2PP(tp);
134810015Speter	volatile struct si_channel *ccbp;
134910015Speter	int oldspl, cflag, iflag, oflag, lflag;
135010015Speter	int error = 0;		/* shutup gcc */
135110015Speter	int ispeed = 0;		/* shutup gcc */
135210015Speter	int ospeed = 0;		/* shutup gcc */
135310161Speter	BYTE val;
135410015Speter
135510015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
135610015Speter	cflag = t->c_cflag;
135710015Speter	iflag = t->c_iflag;
135810015Speter	oflag = t->c_oflag;
135910015Speter	lflag = t->c_lflag;
136010044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
136110044Speter		oflag, cflag, iflag, lflag));
136210015Speter
136310015Speter
136410015Speter	/* if not hung up.. */
136510015Speter	if (t->c_ospeed != 0) {
136610015Speter		/* translate baud rate to firmware values */
136710015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
136810015Speter		ispeed = t->c_ispeed ?
136910015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
137010015Speter
137110015Speter		/* enforce legit baud rate */
137210015Speter		if (ospeed < 0 || ispeed < 0)
137310015Speter			return (EINVAL);
137410015Speter	}
137510015Speter
137610015Speter
137710015Speter	oldspl = spltty();
137810015Speter
137910015Speter	ccbp = pp->sp_ccb;
138010015Speter
138110161Speter	/* ========== set hi_break ========== */
138210161Speter	val = 0;
138310161Speter	if (iflag & IGNBRK)		/* Breaks */
138410161Speter		val |= BR_IGN;
138510161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
138610161Speter		val |= BR_INT;
138710161Speter	if (iflag & PARMRK)		/* Parity mark? */
138810161Speter		val |= BR_PARMRK;
138910161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
139010161Speter		val |= BR_PARIGN;
139110161Speter	ccbp->hi_break = val;
139210161Speter
139310161Speter	/* ========== set hi_csr ========== */
139410015Speter	/* if not hung up.. */
139510015Speter	if (t->c_ospeed != 0) {
139610015Speter		/* Set I/O speeds */
139710161Speter		 val = (ispeed << 4) | ospeed;
139810015Speter	}
139910161Speter	ccbp->hi_csr = val;
140010015Speter
140110161Speter	/* ========== set hi_mr2 ========== */
140210161Speter	val = 0;
140310015Speter	if (cflag & CSTOPB)				/* Stop bits */
140410161Speter		val |= MR2_2_STOP;
140510015Speter	else
140610161Speter		val |= MR2_1_STOP;
140710161Speter	/*
140810161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
140910161Speter	 * a DCE, hence the reverse sense of RTS and CTS
141010161Speter	 */
141110161Speter	/* Output Flow - RTS must be raised before data can be sent */
141210161Speter	if (cflag & CCTS_OFLOW)
141310161Speter		val |= MR2_RTSCONT;
141410161Speter
141510161Speter	ccbp->hi_mr1 = val;
141610161Speter
141710161Speter	/* ========== set hi_mr1 ========== */
141810161Speter	val = 0;
141910015Speter	if (!(cflag & PARENB))				/* Parity */
142010161Speter		val |= MR1_NONE;
142110015Speter	else
142210161Speter		val |= MR1_WITH;
142310015Speter	if (cflag & PARODD)
142410161Speter		val |= MR1_ODD;
142510015Speter
142610015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
142710161Speter		val |= MR1_8_BITS;
142810015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
142910161Speter		val |= MR1_7_BITS;
143010015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
143110161Speter		val |= MR1_6_BITS;
143210015Speter	} else {					/* Must be 5 */
143310161Speter		val |= MR1_5_BITS;
143410015Speter	}
143510161Speter	/*
143610161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
143710161Speter	 * a DCE, hence the reverse sense of RTS and CTS
143810161Speter	 */
143910161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
144010161Speter	if (cflag & CRTS_IFLOW)
144110161Speter		val |= MR1_CTSCONT;
144210015Speter
144310161Speter	ccbp->hi_mr1 = val;
144410161Speter
144510161Speter	/* ========== set hi_mask ========== */
144610161Speter	val = 0xff;
144710161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
144810161Speter		val &= 0xFF;
144910161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
145010161Speter		val &= 0x7F;
145110161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
145210161Speter		val &= 0x3F;
145310161Speter	} else {					/* Must be 5 */
145410161Speter		val &= 0x1F;
145510161Speter	}
145610015Speter	if (iflag & ISTRIP)
145710161Speter		val &= 0x7F;
145810015Speter
145910161Speter	ccbp->hi_mask = val;
146010161Speter
146110161Speter	/* ========== set hi_prtcl ========== */
146210161Speter	val = 0;
146310015Speter				/* Monitor DCD etc. if a modem */
146410015Speter	if (!(cflag & CLOCAL))
146510161Speter		val |= SP_DCEN;
146610161Speter	if (iflag & IXANY)
146710161Speter		val |= SP_TANY;
146810161Speter	if (iflag & IXON)
146910161Speter		val |= SP_TXEN;
147010161Speter	if (iflag & IXOFF)
147110161Speter		val |= SP_RXEN;
147210161Speter	if (iflag & INPCK)
147310161Speter		val |= SP_PAEN;
147410015Speter
147510161Speter	ccbp->hi_prtcl = val;
147610161Speter
147710161Speter
147810161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
147910161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
148010015Speter	ccbp->hi_txon = t->c_cc[VSTART];
148110015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
148210015Speter
148310015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
148410015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
148510015Speter
148610161Speter	/* ========== send settings to the card ========== */
148710015Speter	/* potential sleep here */
148810015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
148910015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
149010015Speter	else
149110015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
149210015Speter
149310161Speter	/* ========== set DTR etc ========== */
149410015Speter	/* Hangup if ospeed == 0 */
149510015Speter	if (t->c_ospeed == 0) {
149610015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
149710015Speter	} else {
149810015Speter		/*
149910015Speter		 * If the previous speed was 0, may need to re-enable
150010015Speter	 	 * the modem signals
150110015Speter	 	 */
150210015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
150310015Speter	}
150410015Speter
150510044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
150610044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
150710015Speter
150810015Speter	splx(oldspl);
150910015Speterout:
151010015Speter	return(error);
151110015Speter}
151210015Speter
151310015Speter/*
151410015Speter * Enable or Disable the writes to this channel...
151510015Speter * "state" ->  enabled = 1; disabled = 0;
151610015Speter */
151710015Speterstatic void
151810015Spetersi_write_enable(pp, state)
151910015Speter	register struct si_port *pp;
152010015Speter	int state;
152110015Speter{
152210015Speter	int oldspl;
152310015Speter
152410015Speter	oldspl = spltty();
152510015Speter
152610015Speter	if (state) {
152710015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
152810015Speter		if (pp->sp_state & SS_WAITWRITE) {
152910015Speter			pp->sp_state &= ~SS_WAITWRITE;
153010015Speter			/* thunder away! */
153110015Speter			wakeup((caddr_t)pp);
153210015Speter		}
153310015Speter	} else {
153410015Speter		pp->sp_state |= SS_BLOCKWRITE;
153510015Speter	}
153610015Speter
153710015Speter	splx(oldspl);
153810015Speter}
153910015Speter
154010015Speter/*
154110015Speter * Set/Get state of modem control lines.
154210015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
154310015Speter *	TIOCM_DTR	DSR
154410015Speter *	TIOCM_RTS	CTS
154510015Speter */
154610015Speterstatic int
154710015Spetersi_modem(pp, cmd, bits)
154810015Speter	struct si_port *pp;
154910015Speter	enum si_mctl cmd;
155010015Speter	int bits;
155110015Speter{
155210015Speter	volatile struct si_channel *ccbp;
155310015Speter	int x;
155410015Speter
155510015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
155610015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
155710015Speter	switch (cmd) {
155810015Speter	case GET:
155910015Speter		x = ccbp->hi_ip;
156010015Speter		bits = TIOCM_LE;
156110015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
156210015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
156310015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
156410015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
156510015Speter		return(bits);
156610015Speter	case SET:
156710015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
156810015Speter		/* fall through */
156910015Speter	case BIS:
157010015Speter		x = 0;
157110015Speter		if (bits & TIOCM_DTR)
157210015Speter			x |= OP_DSR;
157310015Speter		if (bits & TIOCM_RTS)
157410015Speter			x |= OP_CTS;
157510015Speter		ccbp->hi_op |= x;
157610015Speter		break;
157710015Speter	case BIC:
157810015Speter		if (bits & TIOCM_DTR)
157910015Speter			ccbp->hi_op &= ~OP_DSR;
158010015Speter		if (bits & TIOCM_RTS)
158110015Speter			ccbp->hi_op &= ~OP_CTS;
158210015Speter	}
158310015Speter	return 0;
158410015Speter}
158510015Speter
158610015Speter/*
158710015Speter * Handle change of modem state
158810015Speter */
158910015Speterstatic void
159010015Spetersi_modem_state(pp, tp, hi_ip)
159110015Speter	register struct si_port *pp;
159210015Speter	register struct tty *tp;
159310015Speter	register int hi_ip;
159410015Speter{
159510015Speter							/* if a modem dev */
159610015Speter	if (hi_ip & IP_DCD) {
159710015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
159810015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
159910015Speter				tp->t_line));
160010015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
160110015Speter		}
160210015Speter	} else {
160310015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
160410015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
160510015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
160610015Speter				(void) si_modem(pp, SET, 0);
160710015Speter		}
160810015Speter	}
160910015Speter	pp->sp_last_hi_ip = hi_ip;
161010015Speter
161110015Speter}
161210015Speter
161310015Speter/*
161410015Speter * Poller to catch missed interrupts.
161510015Speter */
161610015Speter#ifdef POLL
161710708Speterstatic void
161810015Spetersi_poll(void *nothing)
161910015Speter{
162010015Speter	register struct si_softc *sc;
162110015Speter	register int i;
162210015Speter	volatile struct si_reg *regp;
162310015Speter	int lost, oldspl;
162410015Speter
162510015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
162611609Speter	oldspl = spltty();
162710015Speter	if (in_intr)
162810015Speter		goto out;
162910015Speter	lost = 0;
163010015Speter	for (i=0; i<NSI; i++) {
163110015Speter		sc = &si_softc[i];
163210015Speter		if (sc->sc_type == NULL)
163310015Speter			continue;
163410015Speter		regp = (struct si_reg *)sc->sc_maddr;
163510015Speter		/*
163610015Speter		 * See if there has been a pending interrupt for 2 seconds
163710015Speter		 * or so. The test <int_scounter >= 200) won't correspond
163810015Speter		 * to 2 seconds if int_count gets changed.
163910015Speter		 */
164010015Speter		if (regp->int_pending != 0) {
164110015Speter			if (regp->int_scounter >= 200 &&
164210015Speter			    regp->initstat == 1) {
164310015Speter				printf("SLXOS si%d: lost intr\n", i);
164410015Speter				lost++;
164510015Speter			}
164610015Speter		} else {
164710015Speter			regp->int_scounter = 0;
164810015Speter		}
164910015Speter
165010015Speter	}
165110015Speter	if (lost)
165210015Speter		siintr(-1);	/* call intr with fake vector */
165311609Speterout:
165410015Speter	splx(oldspl);
165510015Speter
165610015Speter	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
165710015Speter}
165810015Speter#endif	/* ifdef POLL */
165910015Speter
166010015Speter/*
166110015Speter * The interrupt handler polls ALL ports on ALL adapters each time
166210015Speter * it is called.
166310015Speter */
166410015Speter
166510161Speterstatic BYTE rxbuf[SLXOS_BUFFERSIZE];	/* input staging area */
166610015Speter
166710708Spetervoid
166811609Spetersiintr(int unit)
166910015Speter{
167010015Speter	register struct si_softc *sc;
167110015Speter
167210015Speter	register struct si_port *pp;
167310015Speter	volatile struct si_channel *ccbp;
167410015Speter	register struct tty *tp;
167510015Speter	volatile caddr_t maddr;
167611872Sphk	BYTE op, ip;
167710161Speter	int x, card, port, n, i;
167810015Speter	volatile BYTE *z;
167910015Speter	BYTE c;
168010015Speter
168111609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
168211609Speter	if (in_intr) {
168311609Speter		if (unit < 0)	/* should never happen */
168410708Speter			return;
168510015Speter		printf("SLXOS si%d: Warning interrupt handler re-entered\n",
168611609Speter			unit);
168710708Speter		return;
168810015Speter	}
168910015Speter	in_intr = 1;
169010015Speter
169110015Speter	/*
169210015Speter	 * When we get an int we poll all the channels and do ALL pending
169310015Speter	 * work, not just the first one we find. This allows all cards to
169410015Speter	 * share the same vector.
169510015Speter	 */
169610015Speter	for (card=0; card < NSI; card++) {
169710015Speter		sc = &si_softc[card];
169810015Speter		if (sc->sc_type == NULL)
169910015Speter			continue;
170010015Speter		switch(sc->sc_type) {
170110015Speter		case SIHOST :
170210015Speter			maddr = sc->sc_maddr;
170310015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
170410015Speter							/* flag nothing pending */
170510015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
170610015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
170710015Speter			break;
170810015Speter		case SIHOST2:
170910015Speter			maddr = sc->sc_maddr;
171010015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
171110015Speter			*(maddr+SIPLIRQCLR) = 0x00;
171210015Speter			*(maddr+SIPLIRQCLR) = 0x10;
171310015Speter			break;
171410015Speter		case SIEISA:
171510015Speter#if NEISA > 0
171610015Speter			maddr = sc->sc_maddr;
171710015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
171810015Speter			(void)inb(sc->sc_eisa_iobase+3);
171910015Speter			break;
172010015Speter#endif	/* fall through if not EISA kernel */
172110015Speter		case SIEMPTY:
172210015Speter		default:
172310015Speter			continue;
172410015Speter		}
172510015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
172610015Speter
172710015Speter		for (pp = sc->sc_ports, port=0;
172810015Speter		     port < sc->sc_nport;
172910015Speter		     pp++, port++) {
173010015Speter			ccbp = pp->sp_ccb;
173110015Speter			tp = pp->sp_tty;
173210015Speter
173310015Speter			/*
173410015Speter			 * See if a command has completed ?
173510015Speter			 */
173610015Speter			if (ccbp->hi_stat != pp->sp_pend) {
173710015Speter				DPRINT((pp, DBG_INTR,
173810015Speter					"siintr hi_stat = 0x%x, pend = %d\n",
173910015Speter					ccbp->hi_stat, pp->sp_pend));
174010015Speter				switch(pp->sp_pend) {
174110015Speter				case LOPEN:
174210015Speter				case MPEND:
174310015Speter				case MOPEN:
174410015Speter				case CONFIG:
174510015Speter					pp->sp_pend = ccbp->hi_stat;
174610015Speter						/* sleeping in si_command */
174710015Speter					wakeup(&pp->sp_state);
174810015Speter					break;
174910015Speter				default:
175010015Speter					pp->sp_pend = ccbp->hi_stat;
175110015Speter				}
175210015Speter	 		}
175310015Speter
175410015Speter			/*
175510015Speter			 * Continue on if it's closed
175610015Speter			 */
175710015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
175810015Speter				continue;
175910015Speter			}
176010015Speter
176110015Speter			/*
176210015Speter			 * Do modem state change if not a local device
176310015Speter			 */
176410015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
176510015Speter
176610015Speter			/*
176710015Speter			 * Do break processing
176810015Speter			 */
176910015Speter			if (ccbp->hi_state & ST_BREAK) {
177010672Speter				if (tp->t_state & TS_CONNECTED &&
177110672Speter				    tp->t_state & TS_ISOPEN) {
177210015Speter					(*linesw[tp->t_line].l_rint)(TTY_BI, tp);
177310015Speter				}
177410015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
177510015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
177610015Speter			}
177710015Speter
177810015Speter			/*
177910015Speter			 * Do RX stuff - if not open then
178010015Speter			 * dump any characters.
178110015Speter			 */
178210015Speter
178310672Speter			if ((tp->t_state & TS_CONNECTED) == 0 ||
178410672Speter			    (tp->t_state & TS_ISOPEN) == 0) {
178510015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
178610015Speter			} else {
178710015Speter				while ((c = ccbp->hi_rxipos - ccbp->hi_rxopos) != 0) {
178810015Speter
178910015Speter					op = ccbp->hi_rxopos;
179010015Speter					ip = ccbp->hi_rxipos;
179110015Speter					n = c & 0xff;
179210015Speter
179310015Speter					DPRINT((pp, DBG_INTR,
179410015Speter						"n = %d, op = %d, ip = %d\n",
179510015Speter						n, op, ip));
179610015Speter					if (n <= SLXOS_BUFFERSIZE - op) {
179710015Speter
179810015Speter						DPRINT((pp, DBG_INTR,
179910015Speter							"\tsingle copy\n"));
180010015Speter						z = ccbp->hi_rxbuf + op;
180110015Speter						bcopy((caddr_t)z, rxbuf, n);
180210015Speter
180310015Speter						op += n;
180410015Speter					} else {
180510015Speter						x = SLXOS_BUFFERSIZE - op;
180610015Speter
180710015Speter						DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
180810015Speter						z = ccbp->hi_rxbuf + op;
180910015Speter						bcopy((caddr_t)z, rxbuf, x);
181010015Speter
181110015Speter						DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
181210015Speter						z = ccbp->hi_rxbuf;
181310015Speter						bcopy((caddr_t)z, rxbuf+x, n-x);
181410015Speter
181510015Speter						op += n;
181610015Speter					}
181710015Speter
181810015Speter					ccbp->hi_rxopos = op;
181910015Speter
182010015Speter					DPRINT((pp, DBG_INTR,
182110015Speter						"n = %d, op = %d, ip = %d\n",
182210015Speter						n, op, ip));
182310015Speter
182410015Speter					/*
182510015Speter					 * at this point...
182610015Speter					 * n = number of chars placed in rxbuf
182710015Speter					 */
182810015Speter		/*
182910015Speter		 * Avoid the grotesquely inefficient lineswitch routine
183010015Speter		 * (ttyinput) in "raw" mode.  It usually takes about 450
183110015Speter		 * instructions (that's without canonical processing or echo!).
183210015Speter		 * slinput is reasonably fast (usually 40 instructions plus
183310015Speter		 * call overhead).
183410015Speter		 */
183510015Speter					if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
183610015Speter
183710015Speter						/* block if the driver supports it */
183810015Speter						if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
183910015Speter						    && (tp->t_cflag & CRTS_IFLOW
184010015Speter							|| tp->t_iflag & IXOFF)
184110015Speter						    && !(tp->t_state & TS_TBLOCK))
184210015Speter							ttyblock(tp);
184310015Speter
184410015Speter						tk_nin += n;
184510015Speter						tk_rawcc += n;
184610015Speter						tp->t_rawcc += n;
184710015Speter
184810015Speter						b_to_q((char *)rxbuf, n, &tp->t_rawq);
184910015Speter						ttwakeup(tp);
185010015Speter						if (tp->t_state & TS_TTSTOP
185110015Speter						    && (tp->t_iflag & IXANY
185210015Speter							|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
185310015Speter							tp->t_state &= ~TS_TTSTOP;
185410015Speter							tp->t_lflag &= ~FLUSHO;
185510015Speter							si_start(tp);
185610015Speter						}
185710015Speter					} else {
185810015Speter						for(x = 0; x < n; x++) {
185910161Speter							i = rxbuf[x];
186010161Speter							(*linesw[tp->t_line].l_rint)(rxbuf[x], tp);
186110161Speter							if (pp->sp_hotchar && i == pp->sp_hotchar) {
186210161Speter								setsofttty();
186310161Speter							}
186410015Speter						}
186510015Speter					}
186610015Speter
186710015Speter				} /* end of RX while */
186810015Speter			} /* end TS_CONNECTED */
186910015Speter
187010015Speter			/*
187110015Speter			 * Do TX stuff
187210015Speter			 */
187310015Speter			(*linesw[tp->t_line].l_start)(tp);
187410015Speter
187510015Speter		} /* end of for (all ports on this controller) */
187610015Speter	} /* end of for (all controllers) */
187710015Speter
187811609Speter	in_intr = 0;
187911609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
188010015Speter}
188110015Speter
188210015Speter/*
188310015Speter * Nudge the transmitter...
188410015Speter */
188510015Speterstatic void
188610015Spetersi_start(tp)
188710015Speter	register struct tty *tp;
188810015Speter{
188910015Speter	struct si_port *pp;
189010015Speter	volatile struct si_channel *ccbp;
189110015Speter	register struct clist *qp;
189210015Speter	register char *dptr;
189310015Speter	BYTE ipos;
189410015Speter	int nchar;
189510015Speter	int oldspl, count, n, amount, buffer_full;
189610015Speter	int do_exitproc;
189710015Speter
189810015Speter	oldspl = spltty();
189910015Speter
190010015Speter	qp = &tp->t_outq;
190110015Speter	pp = TP2PP(tp);
190210015Speter
190310015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
190410015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
190510015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
190610015Speter
190710015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
190810015Speter		goto out;
190910015Speter
191010015Speter	do_exitproc = 0;
191110015Speter	buffer_full = 0;
191210015Speter	ccbp = pp->sp_ccb;
191310015Speter
191410015Speter	/*
191510015Speter	 * Handle the case where ttywait() is called on process exit
191610015Speter	 * this may be BSDI specific, I dont know...
191710015Speter	 */
191810015Speter	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
191910015Speter	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
192010015Speter		do_exitproc++;
192110015Speter	}
192210015Speter
192310015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
192410015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
192510015Speter
192610015Speter	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
192710015Speter
192810015Speter	while ((nchar = qp->c_cc) > 0) {
192910015Speter		if ((BYTE)count >= 255) {
193010015Speter			buffer_full++;
193110015Speter			break;
193210015Speter		}
193310015Speter		amount = min(nchar, (255 - (BYTE)count));
193410015Speter		ipos = (unsigned int)ccbp->hi_txipos;
193510015Speter		/* will it fit in one lump? */
193610015Speter		if ((SLXOS_BUFFERSIZE - ipos) >= amount) {
193710015Speter			n = q_to_b(&tp->t_outq,
193810015Speter				(char *)&ccbp->hi_txbuf[ipos], amount);
193910015Speter		} else {
194010015Speter			n = q_to_b(&tp->t_outq,
194110015Speter				(char *)&ccbp->hi_txbuf[ipos],
194210015Speter				SLXOS_BUFFERSIZE-ipos);
194310015Speter			if (n == SLXOS_BUFFERSIZE-ipos) {
194410015Speter				n += q_to_b(&tp->t_outq,
194510015Speter					(char *)&ccbp->hi_txbuf[0],
194610015Speter					amount - (SLXOS_BUFFERSIZE-ipos));
194710015Speter			}
194810015Speter		}
194910015Speter		ccbp->hi_txipos += n;
195010015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
195110015Speter	}
195210015Speter
195310015Speter	if (count != 0 && nchar == 0) {
195410015Speter		tp->t_state |= TS_BUSY;
195510015Speter	} else {
195610015Speter		tp->t_state &= ~TS_BUSY;
195710015Speter	}
195810015Speter
195910015Speter	/* wakeup time? */
196010015Speter	ttwwakeup(tp);
196110015Speter
196210015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
196310015Speter		(BYTE)count, nchar, tp->t_state));
196410015Speter
196510015Speter	if ((tp->t_state & TS_BUSY) || do_exitproc)
196610015Speter	{
196710015Speter		int time;
196810015Speter
196910015Speter		if (do_exitproc != 0) {
197010015Speter			time = hz / 10;
197110015Speter		} else {
197210015Speter			time = ttspeedtab(tp->t_ospeed, chartimes);
197310015Speter
197410015Speter			if (time > 0) {
197510015Speter				if (time < nchar)
197610015Speter					time = nchar / time;
197710015Speter				else
197810015Speter					time = 2;
197910015Speter			} else {
198010015Speter				printf("SLXOS si%d: bad char time value!!\n",
198110015Speter					SI_CARD(tp->t_dev));
198210015Speter				goto out;
198310015Speter			}
198410015Speter		}
198510015Speter
198610015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
198710015Speter			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
198810015Speter		} else {
198910015Speter			pp->sp_state |= SS_LSTART;
199010015Speter		}
199110015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
199210015Speter		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
199310015Speter	}
199410015Speter
199510015Speterout:
199610015Speter	splx(oldspl);
199710015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
199810015Speter}
199910015Speter
200010015Speter/*
200110015Speter * Note: called at splsoftclock from the timeout code
200210015Speter * This has to deal with two things...  cause wakeups while waiting for
200310015Speter * tty drains on last process exit, and call l_start at about the right
200410015Speter * time for protocols like ppp.
200510015Speter */
200610015Speterstatic void
200710015Spetersi_lstart(pp)
200810015Speter	register struct si_port *pp;
200910015Speter{
201010015Speter	register struct tty *tp;
201110015Speter	int oldspl;
201210015Speter
201310015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
201410015Speter		pp, pp->sp_state));
201510015Speter
201610015Speter	oldspl = spltty();
201710015Speter
201810015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
201910015Speter		splx(oldspl);
202010015Speter		return;
202110015Speter	}
202210015Speter	pp->sp_state &= ~SS_LSTART;
202310015Speter	pp->sp_state |= SS_INLSTART;
202410015Speter
202510015Speter	tp = pp->sp_tty;
202610015Speter
202710015Speter	/* deal with the process exit case */
202810015Speter	ttwwakeup(tp);
202910015Speter
203010015Speter	/* nudge protocols */
203110015Speter	(*linesw[tp->t_line].l_start)(tp);
203210015Speter
203310015Speter	pp->sp_state &= ~SS_INLSTART;
203410015Speter	splx(oldspl);
203510015Speter}
203610015Speter
203710015Speter/*
203810015Speter * Stop output on a line. called at spltty();
203910015Speter */
204010015Spetervoid
204110015Spetersistop(tp, rw)
204210015Speter	register struct tty *tp;
204310015Speter	int rw;
204410015Speter{
204510015Speter	volatile struct si_channel *ccbp;
204610015Speter	struct si_port *pp;
204710015Speter
204810015Speter	pp = TP2PP(tp);
204910015Speter	ccbp = pp->sp_ccb;
205010015Speter
205110015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
205210015Speter
205310015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
205410015Speter	if (rw & FWRITE) {
205510015Speter		/* what level are we meant to be flushing anyway? */
205610015Speter		if (tp->t_state & TS_BUSY) {
205710015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
205810015Speter			tp->t_state &= ~TS_BUSY;
205910015Speter			ttwwakeup(tp);	/* Bruce???? */
206010015Speter		}
206110015Speter	}
206210015Speter#if 0	/* this doesn't work right yet.. */
206310015Speter	if (rw & FREAD) {
206410015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
206510015Speter	}
206610015Speter#endif
206710015Speter}
206810015Speter
206910015Speter/*
207010015Speter * Issue a command to the Z280 host card CPU.
207110015Speter */
207210015Speter
207310015Speterstatic void
207410015Spetersi_command(pp, cmd, waitflag)
207510015Speter	struct si_port *pp;		/* port control block (local) */
207610015Speter	int cmd;
207710015Speter	int waitflag;
207810015Speter{
207910015Speter	int oldspl;
208010015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
208110015Speter	int x;
208210015Speter
208310015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
208410015Speter		pp, cmd, waitflag, ccbp->hi_stat));
208510015Speter
208610015Speter	oldspl = spltty();		/* Keep others out */
208710015Speter
208810015Speter	/* wait until it's finished what it was doing.. */
208910015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
209010015Speter			x != IDLE_CLOSE &&
209110015Speter			x != cmd) {
209210015Speter		if (in_intr) {			/* Prevent sleep in intr */
209310015Speter			DPRINT((pp, DBG_PARAM,
209410015Speter				"cmd intr collision - completing %d\trequested %d\n",
209510015Speter				x, cmd));
209610015Speter			splx(oldspl);
209710015Speter			return;
209810015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
209910015Speter				"sicmd1", 1)) {
210010015Speter			splx(oldspl);
210110015Speter			return;
210210015Speter		}
210310015Speter	}
210410015Speter	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
210510015Speter
210610015Speter	/* if there was a pending command, cause a state-change wakeup */
210710015Speter	if (pp->sp_pend != IDLE_OPEN) {
210810015Speter		switch(pp->sp_pend) {
210910015Speter		case LOPEN:
211010015Speter		case MPEND:
211110015Speter		case MOPEN:
211210015Speter		case CONFIG:
211310015Speter			wakeup(&pp->sp_state);
211410015Speter			break;
211510015Speter		default:
211610015Speter			break;
211710015Speter		}
211810015Speter	}
211910015Speter
212010015Speter	pp->sp_pend = cmd;		/* New command pending */
212110015Speter	ccbp->hi_stat = cmd;		/* Post it */
212210015Speter
212310015Speter	if (waitflag) {
212410015Speter		if (in_intr) {		/* If in interrupt handler */
212510015Speter			DPRINT((pp, DBG_PARAM,
212610015Speter				"attempt to sleep in si_intr - cmd req %d\n",
212710015Speter				cmd));
212810015Speter			splx(oldspl);
212910015Speter			return;
213010015Speter		} else while(ccbp->hi_stat != IDLE_OPEN) {
213110015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
213210015Speter			    "sicmd2", 0))
213310015Speter				break;
213410015Speter		}
213510015Speter	}
213610015Speter	splx(oldspl);
213710015Speter}
213810015Speter
213910015Speterstatic void
214010015Spetersi_disc_optim(tp, t, pp)
214110015Speter	struct tty	*tp;
214210015Speter	struct termios	*t;
214310015Speter	struct si_port	*pp;
214410015Speter{
214510015Speter	/*
214610015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
214710015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
214810015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
214910015Speter	 */
215010015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
215110015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
215210015Speter	    && (!(t->c_iflag & PARMRK)
215310015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
215410015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
215510015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
215610015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
215710015Speter	else
215810015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
215910161Speter
216010015Speter	/*
216110015Speter	 * Prepare to reduce input latency for packet
216210015Speter	 * discplines with a end of packet character.
216310015Speter	 */
216410015Speter	if (tp->t_line == SLIPDISC)
216510015Speter		pp->sp_hotchar = 0xc0;
216610015Speter	else if (tp->t_line == PPPDISC)
216710015Speter		pp->sp_hotchar = 0x7e;
216810015Speter	else
216910015Speter		pp->sp_hotchar = 0;
217010161Speter
217110161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
217210161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
217310161Speter		pp->sp_hotchar));
217410015Speter}
217510015Speter
217610015Speter
217710015Speter#ifdef	SI_DEBUG
217810015Speterstatic void
217910015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6)
218010015Speter	struct si_port *pp;
218110015Speter	int flags;
218210015Speter	char *str;
218310015Speter	int a1, a2, a3, a4, a5, a6;
218410015Speter{
218510015Speter	if ((pp == NULL && (si_debug&flags)) ||
218610015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
218710015Speter	    	if (pp != NULL)
218810015Speter	    		printf("SLXOS %ci%d(%d): ", 's',
218910015Speter	    			SI_CARD(pp->sp_tty->t_dev),
219010015Speter	    			SI_PORT(pp->sp_tty->t_dev));
219110015Speter		printf(str, a1, a2, a3, a4, a5, a6);
219210015Speter	}
219310015Speter}
219410015Speter
219510015Speterstatic char *
219610015Spetersi_mctl2str(cmd)
219710015Speter	enum si_mctl cmd;
219810015Speter{
219910015Speter	switch (cmd) {
220010015Speter	case GET:	return("GET");
220110015Speter	case SET:	return("SET");
220210015Speter	case BIS:	return("BIS");
220310015Speter	case BIC:	return("BIC");
220410015Speter	}
220510015Speter	return("BAD");
220610015Speter}
220710015Speter#endif
2208