si.c revision 12502
110015Speter/*
212496Speter * Device driver for Specialix range (SI/XIO) 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 *
3312502Sjulian *	$Id: si.c,v 1.16 1995/11/28 07:29:29 bde 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#include <sys/param.h>
4310015Speter#include <sys/systm.h>
4410015Speter#include <sys/ioctl.h>
4510015Speter#include <sys/tty.h>
4610015Speter#include <sys/ttydefaults.h>
4710015Speter#include <sys/proc.h>
4810015Speter#include <sys/user.h>
4910015Speter#include <sys/conf.h>
5010015Speter#include <sys/file.h>
5110015Speter#include <sys/uio.h>
5210015Speter#include <sys/dkstat.h>
5310015Speter#include <sys/kernel.h>
5410015Speter#include <sys/syslog.h>
5510015Speter#include <sys/malloc.h>
5610015Speter#include <sys/devconf.h>
5710015Speter
5810015Speter#include <machine/clock.h>
5910015Speter
6010015Speter#include <i386/isa/icu.h>
6110015Speter#include <i386/isa/isa.h>
6210015Speter#include <i386/isa/isa_device.h>
6310015Speter
6410015Speter#include <i386/isa/sireg.h>
6510015Speter#include <machine/si.h>
6610015Speter
6710015Speter#include "si.h"
6810015Speter
6910015Speter/*
7010015Speter * This device driver is designed to interface the Specialix International
7112496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine.
7210015Speter *
7310015Speter * The controller is interfaced to the host via dual port ram
7410015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
7510015Speter */
7610015Speter
7710015Speter#define	POLL		/* turn on poller to generate buffer empty interrupt */
7812174Speter#undef	FASTPOLL	/* turn on 100Hz poller, (XXX: NOTYET!) */
7910047Speter#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
8012496Speter#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
8110015Speter
8210015Speterenum si_mctl { GET, SET, BIS, BIC };
8310015Speter
8412502Sjulian#ifdef JREMOD
8512502Sjulian#define CDEV_MAJOR 68
8612502Sjulianstatic void 	si_devsw_install();
8712502Sjulian#endif /*JREMOD*/
8812502Sjulian
8912502Sjulian
9010015Speterstatic void si_command __P((struct si_port *, int, int));
9110015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
9210015Speterstatic void si_write_enable __P((struct si_port *, int));
9310015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
9410015Speterstatic void si_start __P((struct tty *));
9510015Speterstatic void si_lstart __P((struct si_port *));
9610015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
9710015Speter					struct si_port *pp));
9810015Speterstatic void sihardclose __P((struct si_port *pp));
9910015Speterstatic void sidtrwakeup __P((void *chan));
10010015Speter
10110015Speterint	siparam __P((struct tty *, struct termios *));
10210015Speter
10310708Speterextern	void	si_registerdev __P((struct isa_device *id));
10410708Speterextern	int	siprobe __P((struct isa_device *id));
10510708Speterextern	int	siattach __P((struct isa_device *id));
10610708Speterstatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
10710708Speter
10812174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
10912174Speter/* XXX: should be varargs, I know.. but where's vprintf()? */
11012174Speterstatic	void	si_dprintf __P((/* struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */));
11110708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
11210708Speter#define	DPRINT(x)	si_dprintf x
11310708Speter#else
11410708Speter#define	DPRINT(x)	/* void */
11510708Speter#endif
11610708Speter
11710962Speterstatic int si_Nports;
11810962Speterstatic int si_Nmodules;
11910962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
12010015Speter
12110962Speterstatic struct tty *si_tty;
12210962Speter
12312174Speter/* where the firmware lives; defined in si_code.c */
12410015Speterextern int si_dsize;
12510015Speterextern unsigned char si_download[];
12610015Speter
12710044Speterstruct si_softc {
12810044Speter	int 		sc_type;	/* adapter type */
12910044Speter	char 		*sc_typename;	/* adapter type string */
13010044Speter
13110044Speter	struct si_port	*sc_ports;	/* port structures for this card */
13210044Speter
13310044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
13410044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
13510044Speter	int		sc_nport;	/* # ports on this card */
13610044Speter	int		sc_irq;		/* copy of attach irq */
13710044Speter	int		sc_eisa_iobase;	/* EISA io port address */
13810044Speter	int		sc_eisa_irqbits;
13910044Speter	struct kern_devconf sc_kdc;
14010044Speter};
14110044Speterstruct si_softc si_softc[NSI];		/* up to 4 elements */
14210044Speter
14312174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
14410015Speter# define B2000 2000
14510015Speter#endif
14610015Speterstatic struct speedtab bdrates[] = {
14710015Speter	B75,	CLK75,		/* 0x0 */
14810015Speter	B110,	CLK110,		/* 0x1 */
14910015Speter	B150,	CLK150,		/* 0x3 */
15010015Speter	B300,	CLK300,		/* 0x4 */
15110015Speter	B600,	CLK600,		/* 0x5 */
15210015Speter	B1200,	CLK1200,	/* 0x6 */
15310015Speter	B2000,	CLK2000,	/* 0x7 */
15410015Speter	B2400,	CLK2400,	/* 0x8 */
15510015Speter	B4800,	CLK4800,	/* 0x9 */
15610015Speter	B9600,	CLK9600,	/* 0xb */
15710015Speter	B19200,	CLK19200,	/* 0xc */
15810015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
15910015Speter	B57600, CLK57600,	/* 0xd */
16010015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
16110015Speter	-1,	-1
16210015Speter};
16310015Speter
16410015Speter
16510015Speter/* populated with approx character/sec rates - translated at card
16610015Speter * initialisation time to chars per tick of the clock */
16710015Speterstatic int done_chartimes = 0;
16810015Speterstatic struct speedtab chartimes[] = {
16910015Speter	B75,	8,
17010015Speter	B110,	11,
17110015Speter	B150,	15,
17210015Speter	B300,	30,
17310015Speter	B600,	60,
17410015Speter	B1200,	120,
17510015Speter	B2000,	200,
17610015Speter	B2400,	240,
17710015Speter	B4800,	480,
17810015Speter	B9600,	960,
17910015Speter	B19200,	1920,
18010015Speter	B38400, 3840,
18110015Speter	B57600, 5760,
18210015Speter	B115200, 11520,
18310015Speter	-1,	-1
18410015Speter};
18510015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
18610015Speter
18710047Speterstatic int si_default_rate =	TTYDEF_SPEED;
18810047Speterstatic int si_default_iflag =	0;
18910047Speterstatic int si_default_oflag =	0;
19010047Speterstatic int si_default_lflag =	0;
19110047Speter#ifdef SI_DEF_HWFLOW
19210047Speterstatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
19310047Speter#else
19410047Speterstatic int si_default_cflag =	TTYDEF_CFLAG;
19510047Speter#endif
19610047Speter
19710015Speter#ifdef POLL
19810015Speter#define	POLL_INTERVAL	(hz/2)
19910015Speterstatic int init_finished = 0;
20012174Speterstatic int fastpoll = 0;
20110015Speterstatic void si_poll __P((void *));
20210015Speter#endif
20310015Speter
20410015Speter/*
20510015Speter * Array of adapter types and the corresponding RAM size. The order of
20610015Speter * entries here MUST match the ordinal of the adapter type.
20710015Speter */
20810015Speterstatic char *si_type[] = {
20910015Speter	"EMPTY",
21010015Speter	"SIHOST",
21110015Speter	"SI2",				/* MCA */
21210015Speter	"SIHOST2",
21310015Speter	"SIEISA",
21410015Speter};
21510015Speter
21610015Speter
21710015Speterstatic struct kern_devconf si_kdc[NSI] = { {
21810015Speter	0, 0, 0,		/* filled in by dev_attach */
21910015Speter	"si", 0, { MDDT_ISA, 0, "tty" },
22010015Speter	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
22110015Speter	&kdc_isa0,		/* parent */
22210015Speter	0,			/* parent data */
22310015Speter	DC_UNCONFIGURED,	/* state */
22410015Speter	"Specialix SI/XIO Host adapter",
22510015Speter	DC_CLS_SERIAL,		/* class */
22610015Speter} };
22710015Speter
22810015Spetervoid
22910015Spetersi_registerdev(id)
23010015Speter	struct isa_device *id;
23110015Speter{
23210015Speter	if (id->id_unit != 0) {
23310015Speter		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
23410015Speter	}
23510015Speter	si_kdc[id->id_unit].kdc_unit = id->id_unit;
23610015Speter	si_kdc[id->id_unit].kdc_isa = id;
23712174Speter	si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED;
23810015Speter	dev_attach(&si_kdc[id->id_unit]);
23910015Speter}
24010015Speter
24110015Speter/* Look for a valid board at the given mem addr */
24210015Speterint
24310015Spetersiprobe(id)
24410015Speter	struct isa_device *id;
24510015Speter{
24610015Speter	struct si_softc *sc;
24710015Speter	int type;
24810015Speter	u_int i, ramsize;
24910015Speter	volatile BYTE was, *ux;
25010015Speter	volatile unsigned char *maddr;
25110015Speter	unsigned char *paddr;
25210015Speter
25310015Speter	si_registerdev(id);
25410015Speter
25510015Speter	maddr = id->id_maddr;		/* virtual address... */
25610015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
25710015Speter
25812496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
25912496Speter		id->id_unit, id->id_maddr, paddr));
26010015Speter
26110015Speter	/*
26210015Speter	 * this is a lie, but it's easier than trying to handle caching
26310015Speter	 * and ram conflicts in the >1M and <16M region.
26410015Speter	 */
26510015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
26610015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
26712174Speter		printf("si%d: iomem (%lx) out of range\n",
26812174Speter			id->id_unit, (long)paddr);
26910015Speter		return(0);
27010015Speter	}
27110015Speter
27210015Speter	if (id->id_unit >= NSI) {
27310015Speter		/* THIS IS IMPOSSIBLE */
27410015Speter		return(0);
27510015Speter	}
27610015Speter
27710015Speter	if (((u_int)paddr & 0x7fff) != 0) {
27810015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
27910015Speter			"si%d: iomem (%x) not on 32k boundary\n",
28010015Speter			id->id_unit, paddr));
28110015Speter		return(0);
28210015Speter	}
28310015Speter
28410015Speter
28510015Speter	for (i=0; i < NSI; i++) {
28610015Speter		if ((sc = &si_softc[i]) == NULL)
28710015Speter			continue;
28810015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
28910015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
29010015Speter				"si%d: iomem (%x) already configured to si%d\n",
29110015Speter				id->id_unit, sc->sc_paddr, i));
29210015Speter			return(0);
29310015Speter		}
29410015Speter	}
29510015Speter
29610015Speter#if NEISA > 0
29710015Speter	if (id->id_iobase > 0x0fff) {	/* EISA card */
29810015Speter		int irq, port;
29910015Speter		unsigned long base;
30010015Speter		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
30110015Speter			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
30210015Speter
30310015Speter		port = id->id_iobase;
30410015Speter		base = (inb(port+1) << 24) | (inb(port) << 16);
30510015Speter		irq  = ((inb(port+2) >> 4) & 0xf);
30610015Speter
30710015Speter		id->id_irq = eisa_irqs[irq];
30810015Speter
30910015Speter		DPRINT((0, DBG_AUTOBOOT,
31012496Speter		    "si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
31110015Speter		    id->id_unit, base, irq, id->id_irq, port));
31210015Speter
31310015Speter		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
31410015Speter			goto bad_irq;
31510015Speter
31610015Speter		id->id_iobase &= 0xf000;
31710015Speter		id->id_iosize  = 0x0fff;
31810015Speter
31910015Speter		type = EISA;
32010015Speter		outb(p+2, (BYTE)irq << 4);
32110015Speter
32210015Speter		sc->sc_eisa_iobase = p;
32310015Speter		sc->sc_eisa_irqbits = irq << 4;
32410015Speter		ramsize = SIEISA_RAMSIZE;
32510015Speter		goto got_card;
32610015Speter	}
32710015Speter#endif
32810015Speter
32910015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
33010015Speter	*maddr = 0x17;
33110015Speter	if (*maddr != 0x17) {
33210015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
33310015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
33410015Speter			id->id_unit, paddr));
33510015Speterfail:
33610015Speter		return(0);
33710015Speter	}
33810015Speter	/*
33910015Speter	 * OK, now to see if whatever responded is really an SI card.
34010015Speter	 * Try for a MK II first (SIHOST2)
34110015Speter	 */
34210015Speter	for (i=SIPLSIG; i<SIPLSIG+8; i++)
34310015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
34410015Speter			goto try_mk1;
34510015Speter
34610015Speter	/* It must be an SIHOST2 */
34710015Speter	*(maddr + SIPLRESET) = 0;
34810015Speter	*(maddr + SIPLIRQCLR) = 0;
34910015Speter	*(maddr + SIPLIRQSET) = 0x10;
35010015Speter	type = SIHOST2;
35110015Speter	ramsize = SIHOST2_RAMSIZE;
35210015Speter	goto got_card;
35310015Speter
35410015Speter	/*
35510015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
35610015Speter	 */
35710015Spetertry_mk1:
35810015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
35910015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
36010015Speter	*(maddr+SIRAM) = 0x17;
36110015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
36210015Speter		goto fail;
36310015Speter	*(maddr+0x7ff8) = 0x17;
36410015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
36510015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
36610015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
36710015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
36810015Speter		goto fail;
36910015Speter	}
37010015Speter
37110015Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
37210015Speter	type = SIHOST;
37310015Speter	ramsize = SIHOST_RAMSIZE;
37410015Speter
37510015Spetergot_card:
37612496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
37712496Speter		id->id_unit, type));
37810015Speter	/* Try the acid test */
37910015Speter	ux = (BYTE *)(maddr + SIRAM);
38010015Speter	for (i=0; i<ramsize; i++, ux++)
38110015Speter		*ux = (BYTE)(i&0xff);
38210015Speter	ux = (BYTE *)(maddr + SIRAM);
38310015Speter	for (i=0; i<ramsize; i++, ux++) {
38410015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
38510015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
38612174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
38710015Speter				id->id_unit, paddr+i, was, i&0xff));
38810015Speter			goto fail;
38910015Speter		}
39010015Speter	}
39110015Speter
39210015Speter	/* clear out the RAM */
39310015Speter	ux = (BYTE *)(maddr + SIRAM);
39410015Speter	for (i=0; i<ramsize; i++)
39510015Speter		*ux++ = 0;
39610015Speter	ux = (BYTE *)(maddr + SIRAM);
39710015Speter	for (i=0; i<ramsize; i++) {
39810015Speter		if ((was = *ux++) != 0) {
39910015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
40012174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
40110015Speter				id->id_unit, paddr+i, was));
40210015Speter			goto fail;
40310015Speter		}
40410015Speter	}
40510015Speter
40610015Speter	/*
40710015Speter	 * Success, we've found a valid board, now fill in
40810015Speter	 * the adapter structure.
40910015Speter	 */
41010015Speter	switch (type) {
41110015Speter	case SIHOST2:
41210015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
41310015Speterbad_irq:
41410015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
41510015Speter				"si%d: bad IRQ value - %d\n",
41610015Speter				id->id_unit, id->id_irq));
41710015Speter			return(0);
41810015Speter		}
41910015Speter		id->id_msize = SIHOST2_MEMSIZE;
42010015Speter		break;
42110015Speter	case SIHOST:
42210015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
42310015Speter			goto bad_irq;
42410015Speter		}
42510015Speter		id->id_msize = SIHOST_MEMSIZE;
42610015Speter		break;
42710015Speter	case SIEISA:
42810015Speter		id->id_msize = SIEISA_MEMSIZE;
42910015Speter		break;
43010015Speter	case SI2:		/* MCA */
43110015Speter	default:
43210015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
43310015Speter		return(0);
43410015Speter	}
43510015Speter	si_softc[id->id_unit].sc_type = type;
43610015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
43710015Speter	return(-1);	/* -1 == found */
43810015Speter}
43910015Speter
44010015Speter/*
44110015Speter * Attach the device.  Initialize the card.
44210015Speter */
44310015Speterint
44410015Spetersiattach(id)
44510015Speter	struct isa_device *id;
44610015Speter{
44710015Speter	int unit = id->id_unit;
44810015Speter	struct si_softc *sc = &si_softc[unit];
44910015Speter	struct si_port *pp;
45010015Speter	volatile struct si_channel *ccbp;
45110015Speter	volatile struct si_reg *regp;
45210015Speter	volatile caddr_t maddr;
45310015Speter	struct si_module *modp;
45410015Speter	struct tty *tp;
45510015Speter	struct speedtab *spt;
45610015Speter	int nmodule, nport, x, y;
45712174Speter	int uart_type;
45810015Speter
45912496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
46010015Speter
46110015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
46210015Speter	sc->sc_maddr = id->id_maddr;
46310015Speter	sc->sc_irq = id->id_irq;
46410015Speter
46510015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
46610015Speter
46710015Speter	maddr = sc->sc_maddr;
46810015Speter
46910015Speter	/*
47010015Speter	 * OK, now lets download the firmware and try and boot the CPU..
47110015Speter	 */
47210015Speter
47312496Speter	DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
47412496Speter		id->id_unit, si_dsize));
47510015Speter	bcopy(si_download, maddr, si_dsize);
47610015Speter
47710015Speter	switch (sc->sc_type) {
47810015Speter	case SIEISA:
47910015Speter#if NEISA > 0
48010015Speter		/* modify the Z280 firmware to tell it that it's on an EISA */
48110015Speter		*(maddr+0x42) = 1;
48210015Speter		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
48310015Speter		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
48410015Speter		break;
48510015Speter#endif	/* fall-through if not EISA */
48610015Speter	case SI2:
48712174Speter		/*
48812174Speter		 * must get around to converting the code for
48912174Speter		 * these one day, if FreeBSD ever supports it.
49012174Speter		 */
49110015Speter		return 0;
49210015Speter	case SIHOST:
49310015Speter		*(maddr+SIRESET_CL) = 0;
49410015Speter		*(maddr+SIINTCL_CL) = 0;
49510015Speter		break;
49610015Speter	case SIHOST2:
49710015Speter		*(maddr+SIPLRESET) = 0x10;
49810015Speter		switch (sc->sc_irq) {
49910015Speter		case IRQ11:
50010015Speter			*(maddr+SIPLIRQ11) = 0x10;
50110015Speter			break;
50210015Speter		case IRQ12:
50310015Speter			*(maddr+SIPLIRQ12) = 0x10;
50410015Speter			break;
50510015Speter		case IRQ15:
50610015Speter			*(maddr+SIPLIRQ15) = 0x10;
50710015Speter			break;
50810015Speter		}
50910015Speter		*(maddr+SIPLIRQCLR) = 0x10;
51010015Speter		break;
51110015Speter	}
51210015Speter
51310015Speter	DELAY(1000000);			/* wait around for a second */
51410015Speter
51510015Speter	regp = (struct si_reg *)maddr;
51610015Speter	y = 0;
51710015Speter					/* wait max of 5 sec for init OK */
51810015Speter	while (regp->initstat == 0 && y++ < 10) {
51910015Speter		DELAY(500000);
52010015Speter	}
52110015Speter	switch (regp->initstat) {
52210015Speter	case 0:
52310015Speter		printf("si%d: startup timeout - aborting\n", unit);
52412174Speter		sc->sc_type = SIEMPTY;
52510015Speter		return 0;
52610015Speter	case 1:
52712174Speter			/* set throttle to 125 intr per second */
52810015Speter		regp->int_count = 25000;
52910015Speter			/* rx intr max of 25 timer per second */
53010015Speter		regp->rx_int_count = 4;
53110015Speter		regp->int_pending = 0;		/* no intr pending */
53210015Speter		regp->int_scounter = 0;	/* reset counter */
53310015Speter		break;
53410015Speter	case 0xff:
53510015Speter		/*
53610015Speter		 * No modules found, so give up on this one.
53710015Speter		 */
53810015Speter		printf("si%d: %s - no ports found\n", unit,
53910015Speter			si_type[sc->sc_type]);
54010015Speter		return 0;
54110015Speter	default:
54210015Speter		printf("si%d: Z280 version error - initstat %x\n",
54310015Speter			unit, regp->initstat);
54410015Speter		return 0;
54510015Speter	}
54610015Speter
54710015Speter	/*
54810015Speter	 * First time around the ports just count them in order
54910015Speter	 * to allocate some memory.
55010015Speter	 */
55110015Speter	nport = 0;
55210015Speter	modp = (struct si_module *)(maddr + 0x80);
55310015Speter	for (;;) {
55412174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
55510015Speter		switch (modp->sm_type & (~MMASK)) {
55610015Speter		case M232:
55710015Speter		case M422:
55810015Speter			DPRINT((0, DBG_DOWNLOAD,
55912174Speter				"si%d: Found 232/422 module, %d ports\n",
56010015Speter				unit, (int)(modp->sm_type & MMASK)));
56110015Speter
56210015Speter			/* this is a firmware issue */
56310015Speter			if (si_Nports == SI_MAXPORTPERCARD) {
56410015Speter				printf("si%d: extra ports ignored\n", unit);
56510015Speter				continue;
56610015Speter			}
56710015Speter
56810015Speter			x = modp->sm_type & MMASK;
56910015Speter			nport += x;
57010015Speter			si_Nports += x;
57110015Speter			si_Nmodules++;
57210015Speter			break;
57310015Speter		default:
57410015Speter			printf("si%d: unknown module type %d\n",
57510015Speter				unit, modp->sm_type);
57610015Speter			break;
57710015Speter		}
57810015Speter		if (modp->sm_next == 0)
57910015Speter			break;
58010015Speter		modp = (struct si_module *)
58110015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
58210015Speter	}
58310015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
58410015Speter		M_DEVBUF, M_NOWAIT);
58510015Speter	if (sc->sc_ports == 0) {
58610015Spetermem_fail:
58710015Speter		printf("si%d: fail to malloc memory for port structs\n",
58810015Speter			unit);
58910015Speter		return 0;
59010015Speter	}
59110015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
59210015Speter	sc->sc_nport = nport;
59310015Speter
59410015Speter	/*
59510015Speter	 * allocate tty structures for ports
59610015Speter	 */
59710015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
59810015Speter	if (tp == 0)
59910015Speter		goto mem_fail;
60010015Speter	bzero(tp, sizeof(*tp) * nport);
60110962Speter	si_tty = tp;
60210015Speter
60310015Speter	/* mark the device state as attached */
60410015Speter	si_kdc[unit].kdc_state = DC_BUSY;
60510015Speter
60610015Speter	/*
60710015Speter	 * Scan round the ports again, this time initialising.
60810015Speter	 */
60910015Speter	pp = sc->sc_ports;
61010015Speter	nmodule = 0;
61110015Speter	modp = (struct si_module *)(maddr + 0x80);
61212174Speter	uart_type = 0;
61310015Speter	for (;;) {
61410015Speter		switch (modp->sm_type & (~MMASK)) {
61510015Speter		case M232:
61610015Speter		case M422:
61710015Speter			nmodule++;
61810015Speter			nport = (modp->sm_type & MMASK);
61910015Speter			ccbp = (struct si_channel *)((char *)modp+0x100);
62012174Speter			if (uart_type == 0)
62112174Speter				uart_type = ccbp->type;
62210015Speter			for (x = 0; x < nport; x++, pp++, ccbp++) {
62310015Speter				pp->sp_ccb = ccbp;	/* save the address */
62410015Speter				pp->sp_tty = tp++;
62510015Speter				pp->sp_pend = IDLE_CLOSE;
62610015Speter				pp->sp_state = 0;	/* internal flag */
62710015Speter				pp->sp_dtr_wait = 3 * hz;
62810047Speter				pp->sp_iin.c_iflag = si_default_iflag;
62910047Speter				pp->sp_iin.c_oflag = si_default_oflag;
63010047Speter				pp->sp_iin.c_cflag = si_default_cflag;
63110047Speter				pp->sp_iin.c_lflag = si_default_lflag;
63210015Speter				termioschars(&pp->sp_iin);
63310015Speter				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
63410047Speter					si_default_rate;
63510015Speter				pp->sp_iout = pp->sp_iin;
63610015Speter			}
63710015Speter			break;
63810015Speter		default:
63910015Speter			break;
64010015Speter		}
64110015Speter		if (modp->sm_next == 0) {
64212174Speter			printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n",
64310015Speter				unit,
64410015Speter				sc->sc_typename,
64510015Speter				sc->sc_nport,
64612174Speter				nmodule,
64712174Speter				uart_type);
64810015Speter			break;
64910015Speter		}
65010015Speter		modp = (struct si_module *)
65110015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
65210015Speter	}
65310015Speter	if (done_chartimes == 0) {
65410015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
65510015Speter			if ((spt->sp_code /= hz) == 0)
65610015Speter				spt->sp_code = 1;
65710015Speter		}
65810015Speter		done_chartimes = 1;
65910015Speter	}
66012502Sjulian#ifdef JREMOD
66112502Sjulian	si_devsw_install();
66212502Sjulian#endif /*JREMOD*/
66312502Sjulian
66410015Speter	return (1);
66510015Speter}
66610015Speter
66710015Speterstruct isa_driver sidriver =
66810015Speter	{ siprobe, siattach, "si" };
66910015Speter
67010015Speter
67110015Speterint
67210015Spetersiopen(dev, flag, mode, p)
67310015Speter	dev_t dev;
67410015Speter	int flag, mode;
67510015Speter	struct proc *p;
67610015Speter{
67710015Speter	int oldspl, error;
67810015Speter	int card, port;
67910015Speter	register struct si_softc *sc;
68010015Speter	register struct tty *tp;
68110015Speter	volatile struct si_channel *ccbp;
68210015Speter	struct si_port *pp;
68310015Speter	int mynor = minor(dev);
68410015Speter
68510015Speter	/* quickly let in /dev/si_control */
68610015Speter	if (IS_CONTROLDEV(mynor)) {
68710015Speter		if (error = suser(p->p_ucred, &p->p_acflag))
68810015Speter			return(error);
68910015Speter		return(0);
69010015Speter	}
69110015Speter
69210015Speter	card = SI_CARD(mynor);
69310015Speter	if (card >= NSI)
69410015Speter		return (ENXIO);
69510015Speter	sc = &si_softc[card];
69610015Speter
69712174Speter	if (sc->sc_type == SIEMPTY) {
69812174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
69910015Speter			card, sc->sc_typename));
70010015Speter		return(ENXIO);
70110015Speter	}
70210015Speter
70310015Speter	port = SI_PORT(mynor);
70410015Speter	if (port >= sc->sc_nport) {
70512174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
70610015Speter			card, sc->sc_nport));
70710015Speter		return(ENXIO);
70810015Speter	}
70910015Speter
71010015Speter#ifdef	POLL
71110015Speter	/*
71210015Speter	 * We've now got a device, so start the poller.
71310015Speter	 */
71410015Speter	if (init_finished == 0) {
71510015Speter		timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
71610015Speter		init_finished = 1;
71710015Speter	}
71810015Speter#endif
71910015Speter
72010015Speter	/* initial/lock device */
72110015Speter	if (IS_STATE(mynor)) {
72210015Speter		return(0);
72310015Speter	}
72410015Speter
72510015Speter	pp = sc->sc_ports + port;
72610015Speter	tp = pp->sp_tty;			/* the "real" tty */
72710015Speter	ccbp = pp->sp_ccb;			/* Find control block */
72810015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
72910015Speter		dev, flag, mode, p));
73010015Speter
73110015Speter	oldspl = spltty();			/* Keep others out */
73210015Speter	error = 0;
73310015Speter
73410015Speteropen_top:
73510015Speter	while (pp->sp_state & SS_DTR_OFF) {
73610015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
73710015Speter		if (error != 0)
73810015Speter			goto out;
73910015Speter	}
74010015Speter
74110015Speter	if (tp->t_state & TS_ISOPEN) {
74210015Speter		/*
74310015Speter		 * The device is open, so everything has been initialised.
74410015Speter		 * handle conflicts.
74510015Speter		 */
74610015Speter		if (IS_CALLOUT(mynor)) {
74710015Speter			if (!pp->sp_active_out) {
74810015Speter				error = EBUSY;
74910015Speter				goto out;
75010015Speter			}
75110015Speter		} else {
75210015Speter			if (pp->sp_active_out) {
75310015Speter				if (flag & O_NONBLOCK) {
75410015Speter					error = EBUSY;
75510015Speter					goto out;
75610015Speter				}
75710015Speter				error = tsleep(&pp->sp_active_out,
75810015Speter						TTIPRI|PCATCH, "sibi", 0);
75910015Speter				if (error != 0)
76010015Speter					goto out;
76110015Speter				goto open_top;
76210015Speter			}
76310015Speter		}
76410015Speter		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
76510015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
76610015Speter				"already open and EXCLUSIVE set\n"));
76710015Speter			error = EBUSY;
76810015Speter			goto out;
76910015Speter		}
77010015Speter	} else {
77110015Speter		/*
77210015Speter		 * The device isn't open, so there are no conflicts.
77310015Speter		 * Initialize it. Avoid sleep... :-)
77410015Speter		 */
77510015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
77610015Speter		tp->t_oproc = si_start;
77710015Speter		tp->t_param = siparam;
77810015Speter		tp->t_dev = dev;
77910015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
78010015Speter				? pp->sp_iout : pp->sp_iin;
78110015Speter
78210015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
78310015Speter
78410015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
78510015Speter
78610015Speter		error = siparam(tp, &tp->t_termios);
78710015Speter
78810015Speter		--pp->sp_wopeners;
78910015Speter		if (error != 0)
79010015Speter			goto out;
79110015Speter		/* XXX: we should goto_top if siparam slept */
79210015Speter
79310015Speter		ttsetwater(tp);
79410015Speter
79510015Speter		/* set initial DCD state */
79610015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
79710015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
79810015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
79910015Speter		}
80010015Speter	}
80110015Speter
80210015Speter	/* whoops! we beat the close! */
80310015Speter	if (pp->sp_state & SS_CLOSING) {
80410015Speter		/* try and stop it from proceeding to bash the hardware */
80510015Speter		pp->sp_state &= ~SS_CLOSING;
80610015Speter	}
80710015Speter
80810015Speter	/*
80910015Speter	 * Wait for DCD if necessary
81010015Speter	 */
81110015Speter	if (!(tp->t_state & TS_CARR_ON)
81210015Speter	    && !IS_CALLOUT(mynor)
81310015Speter	    && !(tp->t_cflag & CLOCAL)
81410015Speter	    && !(flag & O_NONBLOCK)) {
81510015Speter		++pp->sp_wopeners;
81610015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
81710015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
81810015Speter		--pp->sp_wopeners;
81910015Speter		if (error != 0)
82010015Speter			goto out;
82110015Speter		goto open_top;
82210015Speter	}
82310015Speter
82410015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
82510015Speter	si_disc_optim(tp, &tp->t_termios, pp);
82610015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
82710015Speter		pp->sp_active_out = TRUE;
82810015Speter
82910015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
83010015Speter
83110015Speterout:
83210015Speter	splx(oldspl);
83310015Speter
83410015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
83510015Speter
83610015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
83710015Speter		sihardclose(pp);
83810015Speter
83910015Speter	return(error);
84010015Speter}
84110015Speter
84210015Speterint
84310015Spetersiclose(dev, flag, mode, p)
84410015Speter	dev_t dev;
84510015Speter	int flag, mode;
84610015Speter	struct proc *p;
84710015Speter{
84810015Speter	register struct si_port *pp;
84910015Speter	register struct tty *tp;
85010015Speter	int oldspl;
85110015Speter	int error = 0;
85210015Speter	int mynor = minor(dev);
85310015Speter
85410015Speter	if (IS_SPECIAL(mynor))
85510015Speter		return(0);
85610015Speter
85710015Speter	oldspl = spltty();
85810015Speter
85910015Speter	pp = MINOR2PP(mynor);
86010015Speter	tp = pp->sp_tty;
86110015Speter
86210015Speter	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
86310015Speter		dev, flag, mode, p, pp->sp_state));
86410015Speter
86510015Speter	/* did we sleep and loose a race? */
86610015Speter	if (pp->sp_state & SS_CLOSING) {
86710015Speter		/* error = ESOMETING? */
86810015Speter		goto out;
86910015Speter	}
87010015Speter
87110015Speter	/* begin race detection.. */
87210015Speter	pp->sp_state |= SS_CLOSING;
87310015Speter
87410015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
87510015Speter
87610015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
87710015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
87810015Speter
87910015Speter	si_write_enable(pp, 1);
88010015Speter
88110015Speter	/* did we sleep and somebody started another open? */
88210015Speter	if (!(pp->sp_state & SS_CLOSING)) {
88310015Speter		/* error = ESOMETING? */
88410015Speter		goto out;
88510015Speter	}
88610015Speter	/* ok. we are now still on the right track.. nuke the hardware */
88710015Speter
88810015Speter	if (pp->sp_state & SS_LSTART) {
88910015Speter		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
89010015Speter		pp->sp_state &= ~SS_LSTART;
89110015Speter	}
89210015Speter
89310015Speter	sistop(tp, FREAD | FWRITE);
89410015Speter
89510015Speter	sihardclose(pp);
89610015Speter	ttyclose(tp);
89710015Speter	pp->sp_state &= ~SS_OPEN;
89810015Speter
89910015Speterout:
90010015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
90110015Speter	splx(oldspl);
90210015Speter	return(error);
90310015Speter}
90410015Speter
90510015Speterstatic void
90610015Spetersihardclose(pp)
90710015Speter	struct si_port *pp;
90810015Speter{
90910015Speter	int oldspl;
91010015Speter	struct tty *tp;
91110015Speter	volatile struct si_channel *ccbp;
91210015Speter
91310015Speter	oldspl = spltty();
91410015Speter
91510015Speter	tp = pp->sp_tty;
91610015Speter	ccbp = pp->sp_ccb;			/* Find control block */
91710015Speter	if (tp->t_cflag & HUPCL
91810015Speter	    || !pp->sp_active_out
91910015Speter	       && !(ccbp->hi_ip & IP_DCD)
92010015Speter	       && !(pp->sp_iin.c_cflag && CLOCAL)
92110015Speter	    || !(tp->t_state & TS_ISOPEN)) {
92210015Speter
92310015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
92410015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
92510015Speter
92610015Speter		if (pp->sp_dtr_wait != 0) {
92710015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
92810015Speter			pp->sp_state |= SS_DTR_OFF;
92910015Speter		}
93010015Speter
93110015Speter	}
93210015Speter	pp->sp_active_out = FALSE;
93310015Speter	wakeup((caddr_t)&pp->sp_active_out);
93410015Speter	wakeup(TSA_CARR_ON(tp));
93510015Speter
93610015Speter	splx(oldspl);
93710015Speter}
93810015Speter
93910015Speter
94010015Speter/*
94110015Speter * called at splsoftclock()...
94210015Speter */
94310015Speterstatic void
94410015Spetersidtrwakeup(chan)
94510015Speter	void *chan;
94610015Speter{
94710015Speter	struct si_port *pp;
94810015Speter	int oldspl;
94910015Speter
95010015Speter	oldspl = spltty();
95110015Speter
95210015Speter	pp = (struct si_port *)chan;
95310015Speter	pp->sp_state &= ~SS_DTR_OFF;
95410015Speter	wakeup(&pp->sp_dtr_wait);
95510015Speter
95610015Speter	splx(oldspl);
95710015Speter}
95810015Speter
95910015Speter/*
96010015Speter * User level stuff - read and write
96110015Speter */
96210015Speterint
96310015Spetersiread(dev, uio, flag)
96410015Speter	register dev_t dev;
96510015Speter	struct uio *uio;
96610015Speter	int flag;
96710015Speter{
96810015Speter	register struct tty *tp;
96910015Speter	int mynor = minor(dev);
97010015Speter
97110015Speter	if (IS_SPECIAL(mynor)) {
97210015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
97310015Speter		return(ENODEV);
97410015Speter	}
97510015Speter	tp = MINOR2TP(mynor);
97610015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
97710015Speter		"siread(%x,%x,%x)\n", dev, uio, flag));
97810015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
97910015Speter}
98010015Speter
98110015Speter
98210015Speterint
98310015Spetersiwrite(dev, uio, flag)
98410015Speter	dev_t dev;
98510015Speter	struct uio *uio;
98610015Speter	int flag;
98710015Speter{
98810015Speter	register struct si_port *pp;
98910015Speter	register struct tty *tp;
99010015Speter	int error = 0;
99110015Speter	int mynor = minor(dev);
99210015Speter	int oldspl;
99310015Speter
99410015Speter	if (IS_SPECIAL(mynor)) {
99510015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
99610015Speter		return(ENODEV);
99710015Speter	}
99810015Speter	pp = MINOR2PP(mynor);
99910015Speter	tp = pp->sp_tty;
100010015Speter	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
100110015Speter
100210015Speter	oldspl = spltty();
100310015Speter	/*
100410015Speter	 * If writes are currently blocked, wait on the "real" tty
100510015Speter	 */
100610015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
100710015Speter		pp->sp_state |= SS_WAITWRITE;
100810015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
100910015Speter		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
101010015Speter				     "siwrite", 0))
101110015Speter			goto out;
101210015Speter	}
101310015Speter
101410015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
101510015Speterout:
101610015Speter	splx(oldspl);
101710015Speter	return (error);
101810015Speter}
101910015Speter
102010015Speter
102110015Speterstruct tty *
102210015Spetersidevtotty(dev_t dev)
102310015Speter{
102410015Speter	struct si_port *pp;
102510015Speter	int mynor = minor(dev);
102610015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
102710015Speter
102810015Speter	if (IS_SPECIAL(mynor))
102910015Speter		return(NULL);
103010015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
103110015Speter		return(NULL);
103210015Speter	pp = MINOR2PP(mynor);
103310015Speter	return (pp->sp_tty);
103410015Speter}
103510015Speter
103610015Speterint
103710015Spetersiioctl(dev, cmd, data, flag, p)
103810015Speter	dev_t dev;
103910015Speter	int cmd;
104010015Speter	caddr_t data;
104110015Speter	int flag;
104210015Speter	struct proc *p;
104310015Speter{
104410015Speter	struct si_port *pp;
104510015Speter	register struct tty *tp;
104610015Speter	int error;
104710015Speter	int mynor = minor(dev);
104810015Speter	int oldspl;
104910015Speter	int blocked = 0;
105010015Speter#if defined(COMPAT_43)
105110015Speter	int oldcmd;
105210015Speter	struct termios term;
105310015Speter#endif
105410015Speter
105510015Speter	if (IS_SI_IOCTL(cmd))
105610015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
105710015Speter
105810015Speter	pp = MINOR2PP(mynor);
105910015Speter	tp = pp->sp_tty;
106010015Speter
106110015Speter	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
106210015Speter		dev, cmd, data, flag));
106310015Speter	if (IS_STATE(mynor)) {
106410015Speter		struct termios *ct;
106510015Speter
106610015Speter		switch (mynor & SI_STATE_MASK) {
106710015Speter		case SI_INIT_STATE_MASK:
106810015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
106910015Speter			break;
107010015Speter		case SI_LOCK_STATE_MASK:
107110015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
107210015Speter			break;
107310015Speter		default:
107410015Speter			return (ENODEV);
107510015Speter		}
107610015Speter		switch (cmd) {
107710015Speter		case TIOCSETA:
107810015Speter			error = suser(p->p_ucred, &p->p_acflag);
107910015Speter			if (error != 0)
108010015Speter				return (error);
108110015Speter			*ct = *(struct termios *)data;
108210015Speter			return (0);
108310015Speter		case TIOCGETA:
108410015Speter			*(struct termios *)data = *ct;
108510015Speter			return (0);
108610015Speter		case TIOCGETD:
108710015Speter			*(int *)data = TTYDISC;
108810015Speter			return (0);
108910015Speter		case TIOCGWINSZ:
109010015Speter			bzero(data, sizeof(struct winsize));
109110015Speter			return (0);
109210015Speter		default:
109310015Speter			return (ENOTTY);
109410015Speter		}
109510015Speter	}
109610015Speter	/*
109710015Speter	 * Do the old-style ioctl compat routines...
109810015Speter	 */
109910015Speter#if defined(COMPAT_43)
110010015Speter	term = tp->t_termios;
110110015Speter	oldcmd = cmd;
110210015Speter	error = ttsetcompat(tp, &cmd, data, &term);
110310015Speter	if (error != 0)
110410015Speter		return (error);
110510015Speter	if (cmd != oldcmd)
110610015Speter		data = (caddr_t)&term;
110710015Speter#endif
110810015Speter	/*
110910015Speter	 * Do the initial / lock state business
111010015Speter	 */
111110015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
111210015Speter		int     cc;
111310015Speter		struct termios *dt = (struct termios *)data;
111410015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
111510015Speter				     ? &pp->sp_lout : &pp->sp_lin;
111610015Speter
111710015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
111810015Speter			| (dt->c_iflag & ~lt->c_iflag);
111910015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
112010015Speter			| (dt->c_oflag & ~lt->c_oflag);
112110015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
112210015Speter			| (dt->c_cflag & ~lt->c_cflag);
112310015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
112410015Speter			| (dt->c_lflag & ~lt->c_lflag);
112510015Speter		for (cc = 0; cc < NCCS; ++cc)
112610015Speter			if (lt->c_cc[cc] != 0)
112710015Speter				dt->c_cc[cc] = tp->t_cc[cc];
112810015Speter		if (lt->c_ispeed != 0)
112910015Speter			dt->c_ispeed = tp->t_ispeed;
113010015Speter		if (lt->c_ospeed != 0)
113110015Speter			dt->c_ospeed = tp->t_ospeed;
113210015Speter	}
113310015Speter
113410015Speter	/*
113510015Speter	 * Block user-level writes to give the ttywait()
113610015Speter	 * a chance to completely drain for commands
113710015Speter	 * that require the port to be in a quiescent state.
113810015Speter	 */
113910015Speter	switch (cmd) {
114010015Speter	case TIOCSETAW: case TIOCSETAF:
114110015Speter	case TIOCDRAIN: case TIOCSETP:
114210015Speter		blocked++;	/* block writes for ttywait() and siparam() */
114310015Speter		si_write_enable(pp, 0);
114410015Speter	}
114510015Speter
114610015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
114710015Speter	if (error >= 0)
114810015Speter		goto out;
114910015Speter
115010015Speter	oldspl = spltty();
115110015Speter
115210015Speter	error = ttioctl(tp, cmd, data, flag);
115310015Speter	si_disc_optim(tp, &tp->t_termios, pp);
115410015Speter	if (error >= 0)
115510015Speter		goto outspl;
115610015Speter
115710015Speter	switch (cmd) {
115810015Speter	case TIOCSBRK:
115910015Speter		si_command(pp, SBREAK, SI_NOWAIT);
116010015Speter		break;
116110015Speter	case TIOCCBRK:
116210015Speter		si_command(pp, EBREAK, SI_NOWAIT);
116310015Speter		break;
116410015Speter	case TIOCSDTR:
116510015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
116610015Speter		break;
116710015Speter	case TIOCCDTR:
116810015Speter		(void) si_modem(pp, SET, 0);
116910015Speter		break;
117010015Speter	case TIOCMSET:
117110015Speter		(void) si_modem(pp, SET, *(int *)data);
117210015Speter		break;
117310015Speter	case TIOCMBIS:
117410015Speter		(void) si_modem(pp, BIS, *(int *)data);
117510015Speter		break;
117610015Speter	case TIOCMBIC:
117710015Speter		(void) si_modem(pp, BIC, *(int *)data);
117810015Speter		break;
117910015Speter	case TIOCMGET:
118010015Speter		*(int *)data = si_modem(pp, GET, 0);
118110015Speter		break;
118210015Speter	case TIOCMSDTRWAIT:
118310015Speter		/* must be root since the wait applies to following logins */
118410015Speter		error = suser(p->p_ucred, &p->p_acflag);
118510015Speter		if (error != 0) {
118610015Speter			goto outspl;
118710015Speter		}
118810015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
118910015Speter		break;
119010015Speter	case TIOCMGDTRWAIT:
119110015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
119210015Speter		break;
119310015Speter
119410015Speter	default:
119510015Speter		error = ENOTTY;
119610015Speter	}
119710015Speter	error = 0;
119810015Speteroutspl:
119910015Speter	splx(oldspl);
120010015Speterout:
120110015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
120210015Speter	if (blocked)
120310015Speter		si_write_enable(pp, 1);
120410015Speter	return(error);
120510015Speter}
120610015Speter
120710015Speter/*
120810015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
120910015Speter */
121010015Speterstatic int
121110015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
121210015Speter{
121310015Speter	struct si_softc *xsc;
121410015Speter	register struct si_port *xpp;
121510015Speter	volatile struct si_reg *regp;
121610015Speter	struct si_tcsi *dp;
121710044Speter	struct si_pstat *sps;
121811872Sphk	int *ip, error = 0;
121910015Speter	int oldspl;
122010015Speter	int card, port;
122110015Speter	int mynor = minor(dev);
122210015Speter
122310015Speter	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
122410015Speter		dev, cmd, data, flag));
122510015Speter
122610044Speter#if 1
122710044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
122810044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
122910044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
123010044Speter#endif
123110044Speter
123210015Speter	if (!IS_CONTROLDEV(mynor)) {
123310015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
123410015Speter		return(ENODEV);
123510015Speter	}
123610015Speter
123710015Speter	oldspl = spltty();	/* better safe than sorry */
123810015Speter
123910015Speter	ip = (int *)data;
124010015Speter
124110015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
124210015Speter
124310015Speter	switch (cmd) {
124410015Speter	case TCSIPORTS:
124510015Speter		*ip = si_Nports;
124610015Speter		goto out;
124710015Speter	case TCSIMODULES:
124810015Speter		*ip = si_Nmodules;
124910015Speter		goto out;
125010015Speter	case TCSISDBG_ALL:
125110015Speter		SUCHECK;
125210015Speter		si_debug = *ip;
125310015Speter		goto out;
125410015Speter	case TCSIGDBG_ALL:
125510015Speter		*ip = si_debug;
125610015Speter		goto out;
125710015Speter	default:
125810015Speter		/*
125910015Speter		 * Check that a controller for this port exists
126010015Speter		 */
126110044Speter
126210044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
126310044Speter
126410015Speter		dp = (struct si_tcsi *)data;
126510044Speter		sps = (struct si_pstat *)data;
126610015Speter		card = dp->tc_card;
126710015Speter		xsc = &si_softc[card];	/* check.. */
126812174Speter		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
126910015Speter			error = ENOENT;
127010015Speter			goto out;
127110015Speter		}
127210015Speter		/*
127310015Speter		 * And check that a port exists
127410015Speter		 */
127510015Speter		port = dp->tc_port;
127610015Speter		if (port < 0 || port >= xsc->sc_nport) {
127710015Speter			error = ENOENT;
127810015Speter			goto out;
127910015Speter		}
128010015Speter		xpp = xsc->sc_ports + port;
128110015Speter		regp = (struct si_reg *)xsc->sc_maddr;
128210015Speter	}
128310015Speter
128410015Speter	switch (cmd) {
128510015Speter	case TCSIDEBUG:
128610015Speter#ifdef	SI_DEBUG
128710015Speter		SUCHECK;
128810015Speter		if (xpp->sp_debug)
128910015Speter			xpp->sp_debug = 0;
129010015Speter		else {
129110015Speter			xpp->sp_debug = DBG_ALL;
129210015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
129310015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
129410015Speter		}
129510015Speter		break;
129610015Speter#else
129710015Speter		error = ENODEV;
129810015Speter		goto out;
129910015Speter#endif
130010015Speter	case TCSISDBG_LEVEL:
130110015Speter	case TCSIGDBG_LEVEL:
130210015Speter#ifdef	SI_DEBUG
130310015Speter		if (cmd == TCSIGDBG_LEVEL) {
130410015Speter			dp->tc_dbglvl = xpp->sp_debug;
130510015Speter		} else {
130610015Speter			SUCHECK;
130710015Speter			xpp->sp_debug = dp->tc_dbglvl;
130810015Speter		}
130910015Speter		break;
131010015Speter#else
131110015Speter		error = ENODEV;
131210015Speter		goto out;
131310015Speter#endif
131410015Speter	case TCSIGRXIT:
131510015Speter		dp->tc_int = regp->rx_int_count;
131610015Speter		break;
131710015Speter	case TCSIRXIT:
131810015Speter		SUCHECK;
131910015Speter		regp->rx_int_count = dp->tc_int;
132010015Speter		break;
132110015Speter	case TCSIGIT:
132210015Speter		dp->tc_int = regp->int_count;
132310015Speter		break;
132410015Speter	case TCSIIT:
132510015Speter		SUCHECK;
132610015Speter		regp->int_count = dp->tc_int;
132710015Speter		break;
132810044Speter	case TCSISTATE:
132910044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
133010015Speter		break;
133110044Speter	/* these next three use a different structure */
133210044Speter	case TCSI_PORT:
133310015Speter		SUCHECK;
133410044Speter		sps->tc_siport = *xpp;
133510015Speter		break;
133610044Speter	case TCSI_CCB:
133710044Speter		SUCHECK;
133810044Speter		sps->tc_ccb = *xpp->sp_ccb;
133910015Speter		break;
134010044Speter	case TCSI_TTY:
134110044Speter		SUCHECK;
134210044Speter		sps->tc_tty = *xpp->sp_tty;
134310015Speter		break;
134410015Speter	default:
134510015Speter		error = EINVAL;
134610015Speter		goto out;
134710015Speter	}
134810015Speterout:
134910015Speter	splx(oldspl);
135010015Speter	return(error);		/* success */
135110015Speter}
135210015Speter
135310015Speter/*
135410015Speter *	siparam()	: Configure line params
135510015Speter *	called at spltty();
135610015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
135710015Speter *	caller must arrange this if it's important..
135810015Speter */
135910015Speterint
136010015Spetersiparam(tp, t)
136110015Speter	register struct tty *tp;
136210015Speter	register struct termios *t;
136310015Speter{
136410015Speter	register struct si_port *pp = TP2PP(tp);
136510015Speter	volatile struct si_channel *ccbp;
136610015Speter	int oldspl, cflag, iflag, oflag, lflag;
136710015Speter	int error = 0;		/* shutup gcc */
136810015Speter	int ispeed = 0;		/* shutup gcc */
136910015Speter	int ospeed = 0;		/* shutup gcc */
137010161Speter	BYTE val;
137110015Speter
137210015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
137310015Speter	cflag = t->c_cflag;
137410015Speter	iflag = t->c_iflag;
137510015Speter	oflag = t->c_oflag;
137610015Speter	lflag = t->c_lflag;
137710044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
137810044Speter		oflag, cflag, iflag, lflag));
137910015Speter
138010015Speter
138110015Speter	/* if not hung up.. */
138210015Speter	if (t->c_ospeed != 0) {
138310015Speter		/* translate baud rate to firmware values */
138410015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
138510015Speter		ispeed = t->c_ispeed ?
138610015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
138710015Speter
138810015Speter		/* enforce legit baud rate */
138910015Speter		if (ospeed < 0 || ispeed < 0)
139010015Speter			return (EINVAL);
139110015Speter	}
139210015Speter
139310015Speter
139410015Speter	oldspl = spltty();
139510015Speter
139610015Speter	ccbp = pp->sp_ccb;
139710015Speter
139810161Speter	/* ========== set hi_break ========== */
139910161Speter	val = 0;
140010161Speter	if (iflag & IGNBRK)		/* Breaks */
140110161Speter		val |= BR_IGN;
140210161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
140310161Speter		val |= BR_INT;
140410161Speter	if (iflag & PARMRK)		/* Parity mark? */
140510161Speter		val |= BR_PARMRK;
140610161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
140710161Speter		val |= BR_PARIGN;
140810161Speter	ccbp->hi_break = val;
140910161Speter
141010161Speter	/* ========== set hi_csr ========== */
141110015Speter	/* if not hung up.. */
141210015Speter	if (t->c_ospeed != 0) {
141310015Speter		/* Set I/O speeds */
141410161Speter		 val = (ispeed << 4) | ospeed;
141510015Speter	}
141610161Speter	ccbp->hi_csr = val;
141710015Speter
141810161Speter	/* ========== set hi_mr2 ========== */
141910161Speter	val = 0;
142010015Speter	if (cflag & CSTOPB)				/* Stop bits */
142110161Speter		val |= MR2_2_STOP;
142210015Speter	else
142310161Speter		val |= MR2_1_STOP;
142410161Speter	/*
142510161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
142610161Speter	 * a DCE, hence the reverse sense of RTS and CTS
142710161Speter	 */
142810161Speter	/* Output Flow - RTS must be raised before data can be sent */
142910161Speter	if (cflag & CCTS_OFLOW)
143010161Speter		val |= MR2_RTSCONT;
143110161Speter
143210161Speter	ccbp->hi_mr1 = val;
143310161Speter
143410161Speter	/* ========== set hi_mr1 ========== */
143510161Speter	val = 0;
143610015Speter	if (!(cflag & PARENB))				/* Parity */
143710161Speter		val |= MR1_NONE;
143810015Speter	else
143910161Speter		val |= MR1_WITH;
144010015Speter	if (cflag & PARODD)
144110161Speter		val |= MR1_ODD;
144210015Speter
144310015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
144410161Speter		val |= MR1_8_BITS;
144510015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
144610161Speter		val |= MR1_7_BITS;
144710015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
144810161Speter		val |= MR1_6_BITS;
144910015Speter	} else {					/* Must be 5 */
145010161Speter		val |= MR1_5_BITS;
145110015Speter	}
145210161Speter	/*
145310161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
145410161Speter	 * a DCE, hence the reverse sense of RTS and CTS
145510161Speter	 */
145610161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
145710161Speter	if (cflag & CRTS_IFLOW)
145810161Speter		val |= MR1_CTSCONT;
145910015Speter
146010161Speter	ccbp->hi_mr1 = val;
146110161Speter
146210161Speter	/* ========== set hi_mask ========== */
146310161Speter	val = 0xff;
146410161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
146510161Speter		val &= 0xFF;
146610161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
146710161Speter		val &= 0x7F;
146810161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
146910161Speter		val &= 0x3F;
147010161Speter	} else {					/* Must be 5 */
147110161Speter		val &= 0x1F;
147210161Speter	}
147310015Speter	if (iflag & ISTRIP)
147410161Speter		val &= 0x7F;
147510015Speter
147610161Speter	ccbp->hi_mask = val;
147710161Speter
147810161Speter	/* ========== set hi_prtcl ========== */
147910161Speter	val = 0;
148010015Speter				/* Monitor DCD etc. if a modem */
148110015Speter	if (!(cflag & CLOCAL))
148210161Speter		val |= SP_DCEN;
148310161Speter	if (iflag & IXANY)
148410161Speter		val |= SP_TANY;
148510161Speter	if (iflag & IXON)
148610161Speter		val |= SP_TXEN;
148710161Speter	if (iflag & IXOFF)
148810161Speter		val |= SP_RXEN;
148910161Speter	if (iflag & INPCK)
149010161Speter		val |= SP_PAEN;
149110015Speter
149210161Speter	ccbp->hi_prtcl = val;
149310161Speter
149410161Speter
149510161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
149610161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
149710015Speter	ccbp->hi_txon = t->c_cc[VSTART];
149810015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
149910015Speter
150010015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
150110015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
150210015Speter
150310161Speter	/* ========== send settings to the card ========== */
150410015Speter	/* potential sleep here */
150510015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
150610015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
150710015Speter	else
150810015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
150910015Speter
151010161Speter	/* ========== set DTR etc ========== */
151110015Speter	/* Hangup if ospeed == 0 */
151210015Speter	if (t->c_ospeed == 0) {
151310015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
151410015Speter	} else {
151510015Speter		/*
151610015Speter		 * If the previous speed was 0, may need to re-enable
151710015Speter	 	 * the modem signals
151810015Speter	 	 */
151910015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
152010015Speter	}
152110015Speter
152210044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
152310044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
152410015Speter
152510015Speter	splx(oldspl);
152610015Speter	return(error);
152710015Speter}
152810015Speter
152910015Speter/*
153010015Speter * Enable or Disable the writes to this channel...
153110015Speter * "state" ->  enabled = 1; disabled = 0;
153210015Speter */
153310015Speterstatic void
153410015Spetersi_write_enable(pp, state)
153510015Speter	register struct si_port *pp;
153610015Speter	int state;
153710015Speter{
153810015Speter	int oldspl;
153910015Speter
154010015Speter	oldspl = spltty();
154110015Speter
154210015Speter	if (state) {
154310015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
154410015Speter		if (pp->sp_state & SS_WAITWRITE) {
154510015Speter			pp->sp_state &= ~SS_WAITWRITE;
154610015Speter			/* thunder away! */
154710015Speter			wakeup((caddr_t)pp);
154810015Speter		}
154910015Speter	} else {
155010015Speter		pp->sp_state |= SS_BLOCKWRITE;
155110015Speter	}
155210015Speter
155310015Speter	splx(oldspl);
155410015Speter}
155510015Speter
155610015Speter/*
155710015Speter * Set/Get state of modem control lines.
155810015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
155910015Speter *	TIOCM_DTR	DSR
156010015Speter *	TIOCM_RTS	CTS
156110015Speter */
156210015Speterstatic int
156310015Spetersi_modem(pp, cmd, bits)
156410015Speter	struct si_port *pp;
156510015Speter	enum si_mctl cmd;
156610015Speter	int bits;
156710015Speter{
156810015Speter	volatile struct si_channel *ccbp;
156910015Speter	int x;
157010015Speter
157110015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
157210015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
157310015Speter	switch (cmd) {
157410015Speter	case GET:
157510015Speter		x = ccbp->hi_ip;
157610015Speter		bits = TIOCM_LE;
157710015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
157810015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
157910015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
158010015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
158110015Speter		return(bits);
158210015Speter	case SET:
158310015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
158410015Speter		/* fall through */
158510015Speter	case BIS:
158610015Speter		x = 0;
158710015Speter		if (bits & TIOCM_DTR)
158810015Speter			x |= OP_DSR;
158910015Speter		if (bits & TIOCM_RTS)
159010015Speter			x |= OP_CTS;
159110015Speter		ccbp->hi_op |= x;
159210015Speter		break;
159310015Speter	case BIC:
159410015Speter		if (bits & TIOCM_DTR)
159510015Speter			ccbp->hi_op &= ~OP_DSR;
159610015Speter		if (bits & TIOCM_RTS)
159710015Speter			ccbp->hi_op &= ~OP_CTS;
159810015Speter	}
159910015Speter	return 0;
160010015Speter}
160110015Speter
160210015Speter/*
160310015Speter * Handle change of modem state
160410015Speter */
160510015Speterstatic void
160610015Spetersi_modem_state(pp, tp, hi_ip)
160710015Speter	register struct si_port *pp;
160810015Speter	register struct tty *tp;
160910015Speter	register int hi_ip;
161010015Speter{
161110015Speter							/* if a modem dev */
161210015Speter	if (hi_ip & IP_DCD) {
161310015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
161410015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
161510015Speter				tp->t_line));
161610015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
161710015Speter		}
161810015Speter	} else {
161910015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
162010015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
162110015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
162210015Speter				(void) si_modem(pp, SET, 0);
162310015Speter		}
162410015Speter	}
162510015Speter	pp->sp_last_hi_ip = hi_ip;
162610015Speter
162710015Speter}
162810015Speter
162910015Speter/*
163010015Speter * Poller to catch missed interrupts.
163112174Speter *
163212496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get
163312496Speter * better response.  We could really use a "periodic" version timeout(). :-)
163410015Speter */
163510015Speter#ifdef POLL
163610708Speterstatic void
163710015Spetersi_poll(void *nothing)
163810015Speter{
163910015Speter	register struct si_softc *sc;
164010015Speter	register int i;
164110015Speter	volatile struct si_reg *regp;
164212174Speter	register struct si_port *pp;
164312174Speter	int lost, oldspl, port;
164410015Speter
164510015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
164611609Speter	oldspl = spltty();
164710015Speter	if (in_intr)
164810015Speter		goto out;
164910015Speter	lost = 0;
165010015Speter	for (i=0; i<NSI; i++) {
165110015Speter		sc = &si_softc[i];
165212174Speter		if (sc->sc_type == SIEMPTY)
165310015Speter			continue;
165410015Speter		regp = (struct si_reg *)sc->sc_maddr;
165510015Speter		/*
165610015Speter		 * See if there has been a pending interrupt for 2 seconds
165710015Speter		 * or so. The test <int_scounter >= 200) won't correspond
165810015Speter		 * to 2 seconds if int_count gets changed.
165910015Speter		 */
166010015Speter		if (regp->int_pending != 0) {
166110015Speter			if (regp->int_scounter >= 200 &&
166210015Speter			    regp->initstat == 1) {
166312174Speter				printf("si%d: lost intr\n", i);
166410015Speter				lost++;
166510015Speter			}
166610015Speter		} else {
166710015Speter			regp->int_scounter = 0;
166810015Speter		}
166910015Speter
167012174Speter		/*
167112174Speter		 * gripe about no input flow control..
167212174Speter		 */
167312174Speter		pp = sc->sc_ports;
167412174Speter		for (port = 0; port < sc->sc_nport; pp++, port++) {
167512174Speter			if (pp->sp_delta_overflows > 0) {
167612174Speter				printf("si%d: %d tty level buffer overflows\n",
167712174Speter					i, pp->sp_delta_overflows);
167812174Speter				pp->sp_delta_overflows = 0;
167912174Speter			}
168012174Speter		}
168110015Speter	}
168210015Speter	if (lost)
168310015Speter		siintr(-1);	/* call intr with fake vector */
168411609Speterout:
168510015Speter	splx(oldspl);
168610015Speter
168710015Speter	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
168810015Speter}
168910015Speter#endif	/* ifdef POLL */
169010015Speter
169110015Speter/*
169210015Speter * The interrupt handler polls ALL ports on ALL adapters each time
169310015Speter * it is called.
169410015Speter */
169510015Speter
169612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
169710015Speter
169810708Spetervoid
169911609Spetersiintr(int unit)
170010015Speter{
170110015Speter	register struct si_softc *sc;
170210015Speter
170310015Speter	register struct si_port *pp;
170410015Speter	volatile struct si_channel *ccbp;
170510015Speter	register struct tty *tp;
170610015Speter	volatile caddr_t maddr;
170711872Sphk	BYTE op, ip;
170812174Speter	int x, card, port, n, i, isopen;
170910015Speter	volatile BYTE *z;
171010015Speter	BYTE c;
171110015Speter
171211609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
171311609Speter	if (in_intr) {
171411609Speter		if (unit < 0)	/* should never happen */
171510708Speter			return;
171612174Speter		printf("si%d: Warning interrupt handler re-entered\n",
171711609Speter			unit);
171810708Speter		return;
171910015Speter	}
172010015Speter	in_intr = 1;
172110015Speter
172210015Speter	/*
172310015Speter	 * When we get an int we poll all the channels and do ALL pending
172410015Speter	 * work, not just the first one we find. This allows all cards to
172510015Speter	 * share the same vector.
172610015Speter	 */
172710015Speter	for (card=0; card < NSI; card++) {
172810015Speter		sc = &si_softc[card];
172912174Speter		if (sc->sc_type == SIEMPTY)
173010015Speter			continue;
173112174Speter
173212174Speter		/*
173312174Speter		 * First, clear the interrupt
173412174Speter		 */
173510015Speter		switch(sc->sc_type) {
173610015Speter		case SIHOST :
173710015Speter			maddr = sc->sc_maddr;
173810015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
173910015Speter							/* flag nothing pending */
174010015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
174110015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
174210015Speter			break;
174310015Speter		case SIHOST2:
174410015Speter			maddr = sc->sc_maddr;
174510015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
174610015Speter			*(maddr+SIPLIRQCLR) = 0x00;
174710015Speter			*(maddr+SIPLIRQCLR) = 0x10;
174810015Speter			break;
174910015Speter		case SIEISA:
175010015Speter#if NEISA > 0
175110015Speter			maddr = sc->sc_maddr;
175210015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
175310015Speter			(void)inb(sc->sc_eisa_iobase+3);
175410015Speter			break;
175510015Speter#endif	/* fall through if not EISA kernel */
175610015Speter		case SIEMPTY:
175710015Speter		default:
175810015Speter			continue;
175910015Speter		}
176010015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
176110015Speter
176212174Speter		/*
176312174Speter		 * check each port
176412174Speter		 */
176512174Speter		for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) {
176610015Speter			ccbp = pp->sp_ccb;
176710015Speter			tp = pp->sp_tty;
176810015Speter
176912174Speter
177010015Speter			/*
177110015Speter			 * See if a command has completed ?
177210015Speter			 */
177310015Speter			if (ccbp->hi_stat != pp->sp_pend) {
177410015Speter				DPRINT((pp, DBG_INTR,
177510015Speter					"siintr hi_stat = 0x%x, pend = %d\n",
177610015Speter					ccbp->hi_stat, pp->sp_pend));
177710015Speter				switch(pp->sp_pend) {
177810015Speter				case LOPEN:
177910015Speter				case MPEND:
178010015Speter				case MOPEN:
178110015Speter				case CONFIG:
178210015Speter					pp->sp_pend = ccbp->hi_stat;
178310015Speter						/* sleeping in si_command */
178410015Speter					wakeup(&pp->sp_state);
178510015Speter					break;
178610015Speter				default:
178710015Speter					pp->sp_pend = ccbp->hi_stat;
178810015Speter				}
178910015Speter	 		}
179010015Speter
179110015Speter			/*
179210015Speter			 * Continue on if it's closed
179310015Speter			 */
179410015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
179510015Speter				continue;
179610015Speter			}
179710015Speter
179810015Speter			/*
179910015Speter			 * Do modem state change if not a local device
180010015Speter			 */
180110015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
180210015Speter
180310015Speter			/*
180412174Speter			 * Check to see if there's we should 'receive'
180512174Speter			 * characters.
180612174Speter			 */
180712174Speter			if (tp->t_state & TS_CONNECTED &&
180812174Speter			    tp->t_state & TS_ISOPEN)
180912174Speter				isopen = 1;
181012174Speter			else
181112174Speter				isopen = 0;
181212174Speter
181312174Speter			/*
181410015Speter			 * Do break processing
181510015Speter			 */
181610015Speter			if (ccbp->hi_state & ST_BREAK) {
181712174Speter				if (isopen) {
181812174Speter				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
181910015Speter				}
182010015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
182110015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
182210015Speter			}
182310015Speter
182410015Speter			/*
182512174Speter			 * Do RX stuff - if not open then dump any characters.
182612174Speter			 * XXX: This is VERY messy and needs to be cleaned up.
182712174Speter			 *
182812174Speter			 * XXX: can we leave data in the host adapter buffer
182912174Speter			 * when the clists are full?  That may be dangerous
183012174Speter			 * if the user cannot get an interrupt signal through.
183110015Speter			 */
183210015Speter
183312174Speter	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
183412174Speter
183512174Speter			if (!isopen) {
183610015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
183712174Speter				goto end_rx;
183812174Speter			}
183910015Speter
184012174Speter			/*
184112174Speter			 * Process read characters if not skipped above
184212174Speter			 */
184312174Speter			c = ccbp->hi_rxipos - ccbp->hi_rxopos;
184412174Speter			if (c == 0) {
184512174Speter				goto end_rx;
184612174Speter			}
184710015Speter
184812174Speter			op = ccbp->hi_rxopos;
184912174Speter			ip = ccbp->hi_rxipos;
185012174Speter			n = c & 0xff;
185112174Speter
185212174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
185310015Speter						n, op, ip));
185410015Speter
185512174Speter			/*
185612174Speter			 * Suck characters out of host card buffer into the
185712174Speter			 * "input staging buffer" - so that we dont leave the
185812174Speter			 * host card in limbo while we're possibly echoing
185912174Speter			 * characters and possibly flushing input inside the
186012174Speter			 * ldisc l_rint() routine.
186112174Speter			 */
186212496Speter			if (n <= SI_BUFFERSIZE - op) {
186310015Speter
186412174Speter				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
186512174Speter				z = ccbp->hi_rxbuf + op;
186612174Speter				bcopy((caddr_t)z, si_rxbuf, n);
186710015Speter
186812174Speter				op += n;
186912174Speter			} else {
187012496Speter				x = SI_BUFFERSIZE - op;
187110015Speter
187212174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
187312174Speter				z = ccbp->hi_rxbuf + op;
187412174Speter				bcopy((caddr_t)z, si_rxbuf, x);
187510015Speter
187612174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
187712174Speter				z = ccbp->hi_rxbuf;
187812174Speter				bcopy((caddr_t)z, si_rxbuf+x, n-x);
187910015Speter
188012174Speter				op += n;
188112174Speter			}
188210015Speter
188312174Speter			/* clear collected characters from buffer */
188412174Speter			ccbp->hi_rxopos = op;
188512174Speter
188612174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
188710015Speter						n, op, ip));
188810015Speter
188912174Speter			/*
189012174Speter			 * at this point...
189112174Speter			 * n = number of chars placed in si_rxbuf
189212174Speter			 */
189310015Speter
189412174Speter			/*
189512174Speter			 * Avoid the grotesquely inefficient lineswitch
189612174Speter			 * routine (ttyinput) in "raw" mode. It usually
189712174Speter			 * takes about 450 instructions (that's without
189812174Speter			 * canonical processing or echo!). slinput is
189912174Speter			 * reasonably fast (usually 40 instructions
190012174Speter			 * plus call overhead).
190112174Speter			 */
190212174Speter			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
190310015Speter
190412174Speter				/* block if the driver supports it */
190512174Speter				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
190612174Speter				    && (tp->t_cflag & CRTS_IFLOW
190712174Speter					|| tp->t_iflag & IXOFF)
190812174Speter				    && !(tp->t_state & TS_TBLOCK))
190912174Speter					ttyblock(tp);
191010015Speter
191112174Speter				tk_nin += n;
191212174Speter				tk_rawcc += n;
191312174Speter				tp->t_rawcc += n;
191412174Speter
191512174Speter				pp->sp_delta_overflows +=
191612174Speter				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
191712174Speter
191812174Speter				ttwakeup(tp);
191912174Speter				if (tp->t_state & TS_TTSTOP
192012174Speter				    && (tp->t_iflag & IXANY
192112174Speter					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
192212174Speter					tp->t_state &= ~TS_TTSTOP;
192312174Speter					tp->t_lflag &= ~FLUSHO;
192412174Speter					si_start(tp);
192512174Speter				}
192612174Speter			} else {
192712174Speter				/*
192812174Speter				 * It'd be nice to not have to go through the
192912174Speter				 * function call overhead for each char here.
193012174Speter				 * It'd be nice to block input it, saving a
193112174Speter				 * loop here and the call/return overhead.
193212174Speter				 */
193312174Speter				for(x = 0; x < n; x++) {
193412174Speter					i = si_rxbuf[x];
193512174Speter					if ((*linesw[tp->t_line].l_rint)(i, tp)
193612174Speter					     == -1) {
193712174Speter						pp->sp_delta_overflows++;
193810015Speter					}
193912174Speter					/*
194012174Speter					 * doesn't seem to be much point doing
194112174Speter					 * this here.. this driver has no
194212174Speter					 * softtty processing! ??
194312174Speter					 */
194412174Speter					if (pp->sp_hotchar && i == pp->sp_hotchar) {
194512174Speter						setsofttty();
194612174Speter					}
194712174Speter				}
194812174Speter			}
194912174Speter			goto more_rx;	/* try for more until RXbuf is empty */
195010015Speter
195112174Speter	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
195210015Speter
195310015Speter			/*
195410015Speter			 * Do TX stuff
195510015Speter			 */
195610015Speter			(*linesw[tp->t_line].l_start)(tp);
195710015Speter
195810015Speter		} /* end of for (all ports on this controller) */
195910015Speter	} /* end of for (all controllers) */
196010015Speter
196111609Speter	in_intr = 0;
196211609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
196310015Speter}
196410015Speter
196510015Speter/*
196610015Speter * Nudge the transmitter...
196712174Speter *
196812174Speter * XXX: I inherited some funny code here.  It implies the host card only
196912174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does
197012174Speter * not interrupt when it's actually hits empty.  In some cases, we have
197112174Speter * processes waiting for complete drain, and we need to simulate an interrupt
197212174Speter * about when we think the buffer is going to be empty (and retry if not).
197312174Speter * I really am not certain about this...  I *need* the hardware manuals.
197410015Speter */
197510015Speterstatic void
197610015Spetersi_start(tp)
197710015Speter	register struct tty *tp;
197810015Speter{
197910015Speter	struct si_port *pp;
198010015Speter	volatile struct si_channel *ccbp;
198110015Speter	register struct clist *qp;
198210015Speter	register char *dptr;
198310015Speter	BYTE ipos;
198410015Speter	int nchar;
198510015Speter	int oldspl, count, n, amount, buffer_full;
198610015Speter	int do_exitproc;
198710015Speter
198810015Speter	oldspl = spltty();
198910015Speter
199010015Speter	qp = &tp->t_outq;
199110015Speter	pp = TP2PP(tp);
199210015Speter
199310015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
199410015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
199510015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
199610015Speter
199710015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
199810015Speter		goto out;
199910015Speter
200010015Speter	do_exitproc = 0;
200110015Speter	buffer_full = 0;
200210015Speter	ccbp = pp->sp_ccb;
200310015Speter
200410015Speter	/*
200510015Speter	 * Handle the case where ttywait() is called on process exit
200610015Speter	 * this may be BSDI specific, I dont know...
200710015Speter	 */
200810015Speter	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
200910015Speter	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
201010015Speter		do_exitproc++;
201110015Speter	}
201210015Speter
201310015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
201410015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
201510015Speter
201610015Speter	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
201710015Speter
201810015Speter	while ((nchar = qp->c_cc) > 0) {
201910015Speter		if ((BYTE)count >= 255) {
202010015Speter			buffer_full++;
202110015Speter			break;
202210015Speter		}
202310015Speter		amount = min(nchar, (255 - (BYTE)count));
202410015Speter		ipos = (unsigned int)ccbp->hi_txipos;
202510015Speter		/* will it fit in one lump? */
202612496Speter		if ((SI_BUFFERSIZE - ipos) >= amount) {
202710015Speter			n = q_to_b(&tp->t_outq,
202810015Speter				(char *)&ccbp->hi_txbuf[ipos], amount);
202910015Speter		} else {
203010015Speter			n = q_to_b(&tp->t_outq,
203110015Speter				(char *)&ccbp->hi_txbuf[ipos],
203212496Speter				SI_BUFFERSIZE-ipos);
203312496Speter			if (n == SI_BUFFERSIZE-ipos) {
203410015Speter				n += q_to_b(&tp->t_outq,
203510015Speter					(char *)&ccbp->hi_txbuf[0],
203612496Speter					amount - (SI_BUFFERSIZE-ipos));
203710015Speter			}
203810015Speter		}
203910015Speter		ccbp->hi_txipos += n;
204010015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
204110015Speter	}
204210015Speter
204310015Speter	if (count != 0 && nchar == 0) {
204410015Speter		tp->t_state |= TS_BUSY;
204510015Speter	} else {
204610015Speter		tp->t_state &= ~TS_BUSY;
204710015Speter	}
204810015Speter
204910015Speter	/* wakeup time? */
205010015Speter	ttwwakeup(tp);
205110015Speter
205210015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
205310015Speter		(BYTE)count, nchar, tp->t_state));
205410015Speter
205510015Speter	if ((tp->t_state & TS_BUSY) || do_exitproc)
205610015Speter	{
205710015Speter		int time;
205810015Speter
205910015Speter		if (do_exitproc != 0) {
206010015Speter			time = hz / 10;
206110015Speter		} else {
206210015Speter			time = ttspeedtab(tp->t_ospeed, chartimes);
206310015Speter
206410015Speter			if (time > 0) {
206510015Speter				if (time < nchar)
206610015Speter					time = nchar / time;
206710015Speter				else
206810015Speter					time = 2;
206910015Speter			} else {
207012174Speter				printf("si%d: bad char time value!!\n",
207112174Speter					(int)SI_CARD(tp->t_dev));
207210015Speter				goto out;
207310015Speter			}
207410015Speter		}
207510015Speter
207610015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
207710015Speter			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
207810015Speter		} else {
207910015Speter			pp->sp_state |= SS_LSTART;
208010015Speter		}
208110015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
208210015Speter		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
208310015Speter	}
208410015Speter
208510015Speterout:
208610015Speter	splx(oldspl);
208710015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
208810015Speter}
208910015Speter
209010015Speter/*
209110015Speter * Note: called at splsoftclock from the timeout code
209210015Speter * This has to deal with two things...  cause wakeups while waiting for
209310015Speter * tty drains on last process exit, and call l_start at about the right
209410015Speter * time for protocols like ppp.
209510015Speter */
209610015Speterstatic void
209710015Spetersi_lstart(pp)
209810015Speter	register struct si_port *pp;
209910015Speter{
210010015Speter	register struct tty *tp;
210110015Speter	int oldspl;
210210015Speter
210310015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
210410015Speter		pp, pp->sp_state));
210510015Speter
210610015Speter	oldspl = spltty();
210710015Speter
210810015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
210910015Speter		splx(oldspl);
211010015Speter		return;
211110015Speter	}
211210015Speter	pp->sp_state &= ~SS_LSTART;
211310015Speter	pp->sp_state |= SS_INLSTART;
211410015Speter
211510015Speter	tp = pp->sp_tty;
211610015Speter
211710015Speter	/* deal with the process exit case */
211810015Speter	ttwwakeup(tp);
211910015Speter
212012174Speter	/* nudge protocols - eg: ppp */
212110015Speter	(*linesw[tp->t_line].l_start)(tp);
212210015Speter
212310015Speter	pp->sp_state &= ~SS_INLSTART;
212410015Speter	splx(oldspl);
212510015Speter}
212610015Speter
212710015Speter/*
212810015Speter * Stop output on a line. called at spltty();
212910015Speter */
213010015Spetervoid
213110015Spetersistop(tp, rw)
213210015Speter	register struct tty *tp;
213310015Speter	int rw;
213410015Speter{
213510015Speter	volatile struct si_channel *ccbp;
213610015Speter	struct si_port *pp;
213710015Speter
213810015Speter	pp = TP2PP(tp);
213910015Speter	ccbp = pp->sp_ccb;
214010015Speter
214110015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
214210015Speter
214310015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
214410015Speter	if (rw & FWRITE) {
214510015Speter		/* what level are we meant to be flushing anyway? */
214610015Speter		if (tp->t_state & TS_BUSY) {
214710015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
214810015Speter			tp->t_state &= ~TS_BUSY;
214910015Speter			ttwwakeup(tp);	/* Bruce???? */
215010015Speter		}
215110015Speter	}
215212174Speter#if 1	/* XXX: this doesn't work right yet.. */
215312174Speter	/* XXX: this may have been failing because we used to call l_rint()
215412174Speter	 * while we were looping based on these two counters. Now, we collect
215512174Speter	 * the data and then loop stuffing it into l_rint(), making this
215612174Speter	 * useless.  Should we cause this to blow away the staging buffer?
215712174Speter	 */
215810015Speter	if (rw & FREAD) {
215910015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
216010015Speter	}
216110015Speter#endif
216210015Speter}
216310015Speter
216410015Speter/*
216510015Speter * Issue a command to the Z280 host card CPU.
216610015Speter */
216710015Speter
216810015Speterstatic void
216910015Spetersi_command(pp, cmd, waitflag)
217010015Speter	struct si_port *pp;		/* port control block (local) */
217110015Speter	int cmd;
217210015Speter	int waitflag;
217310015Speter{
217410015Speter	int oldspl;
217510015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
217610015Speter	int x;
217710015Speter
217810015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
217910015Speter		pp, cmd, waitflag, ccbp->hi_stat));
218010015Speter
218110015Speter	oldspl = spltty();		/* Keep others out */
218210015Speter
218310015Speter	/* wait until it's finished what it was doing.. */
218410015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
218510015Speter			x != IDLE_CLOSE &&
218610015Speter			x != cmd) {
218710015Speter		if (in_intr) {			/* Prevent sleep in intr */
218810015Speter			DPRINT((pp, DBG_PARAM,
218910015Speter				"cmd intr collision - completing %d\trequested %d\n",
219010015Speter				x, cmd));
219110015Speter			splx(oldspl);
219210015Speter			return;
219310015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
219410015Speter				"sicmd1", 1)) {
219510015Speter			splx(oldspl);
219610015Speter			return;
219710015Speter		}
219810015Speter	}
219910015Speter	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
220010015Speter
220110015Speter	/* if there was a pending command, cause a state-change wakeup */
220210015Speter	if (pp->sp_pend != IDLE_OPEN) {
220310015Speter		switch(pp->sp_pend) {
220410015Speter		case LOPEN:
220510015Speter		case MPEND:
220610015Speter		case MOPEN:
220710015Speter		case CONFIG:
220810015Speter			wakeup(&pp->sp_state);
220910015Speter			break;
221010015Speter		default:
221110015Speter			break;
221210015Speter		}
221310015Speter	}
221410015Speter
221510015Speter	pp->sp_pend = cmd;		/* New command pending */
221610015Speter	ccbp->hi_stat = cmd;		/* Post it */
221710015Speter
221810015Speter	if (waitflag) {
221910015Speter		if (in_intr) {		/* If in interrupt handler */
222010015Speter			DPRINT((pp, DBG_PARAM,
222110015Speter				"attempt to sleep in si_intr - cmd req %d\n",
222210015Speter				cmd));
222310015Speter			splx(oldspl);
222410015Speter			return;
222510015Speter		} else while(ccbp->hi_stat != IDLE_OPEN) {
222610015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
222710015Speter			    "sicmd2", 0))
222810015Speter				break;
222910015Speter		}
223010015Speter	}
223110015Speter	splx(oldspl);
223210015Speter}
223310015Speter
223410015Speterstatic void
223510015Spetersi_disc_optim(tp, t, pp)
223610015Speter	struct tty	*tp;
223710015Speter	struct termios	*t;
223810015Speter	struct si_port	*pp;
223910015Speter{
224010015Speter	/*
224110015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
224210015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
224310015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
224410015Speter	 */
224510015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
224610015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
224710015Speter	    && (!(t->c_iflag & PARMRK)
224810015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
224910015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
225010015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
225110015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
225210015Speter	else
225310015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
225410161Speter
225510015Speter	/*
225610015Speter	 * Prepare to reduce input latency for packet
225710015Speter	 * discplines with a end of packet character.
225810015Speter	 */
225910015Speter	if (tp->t_line == SLIPDISC)
226010015Speter		pp->sp_hotchar = 0xc0;
226110015Speter	else if (tp->t_line == PPPDISC)
226210015Speter		pp->sp_hotchar = 0x7e;
226310015Speter	else
226410015Speter		pp->sp_hotchar = 0;
226510161Speter
226610161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
226710161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
226810161Speter		pp->sp_hotchar));
226910015Speter}
227010015Speter
227110015Speter
227210015Speter#ifdef	SI_DEBUG
227310015Speterstatic void
227410015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6)
227510015Speter	struct si_port *pp;
227610015Speter	int flags;
227710015Speter	char *str;
227810015Speter	int a1, a2, a3, a4, a5, a6;
227910015Speter{
228010015Speter	if ((pp == NULL && (si_debug&flags)) ||
228110015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
228210015Speter	    	if (pp != NULL)
228312496Speter	    		printf("%ci%d(%d): ", 's',
228412174Speter	    			(int)SI_CARD(pp->sp_tty->t_dev),
228512174Speter	    			(int)SI_PORT(pp->sp_tty->t_dev));
228610015Speter		printf(str, a1, a2, a3, a4, a5, a6);
228710015Speter	}
228810015Speter}
228910015Speter
229010015Speterstatic char *
229110015Spetersi_mctl2str(cmd)
229210015Speter	enum si_mctl cmd;
229310015Speter{
229410015Speter	switch (cmd) {
229510015Speter	case GET:	return("GET");
229610015Speter	case SET:	return("SET");
229710015Speter	case BIS:	return("BIS");
229810015Speter	case BIC:	return("BIC");
229910015Speter	}
230010015Speter	return("BAD");
230110015Speter}
230212502Sjulian
230312502Sjulian
230412502Sjulian#ifdef JREMOD
230512502Sjulianstruct cdevsw si_cdevsw =
230612502Sjulian	{ siopen,	siclose,	siread,		siwrite,	/*68*/
230712502Sjulian	  siioctl,	sistop,		nxreset,	sidevtotty,/* si */
230812502Sjulian	  ttselect,	nxmmap,		NULL };
230912502Sjulian
231012502Sjulianstatic si_devsw_installed = 0;
231112502Sjulian
231212502Sjulianstatic void 	si_devsw_install()
231312502Sjulian{
231412502Sjulian	dev_t descript;
231512502Sjulian	if( ! si_devsw_installed ) {
231612502Sjulian		descript = makedev(CDEV_MAJOR,0);
231712502Sjulian		cdevsw_add(&descript,&si_cdevsw,NULL);
231812502Sjulian#if defined(BDEV_MAJOR)
231912502Sjulian		descript = makedev(BDEV_MAJOR,0);
232012502Sjulian		bdevsw_add(&descript,&si_bdevsw,NULL);
232112502Sjulian#endif /*BDEV_MAJOR*/
232212502Sjulian		si_devsw_installed = 1;
232312502Sjulian	}
232412502Sjulian}
232512502Sjulian#endif /* JREMOD */
232610015Speter#endif
2327