si.c revision 12826
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 *
3312826Speter *	$Id: si.c,v 1.28 1995/12/10 20:54:35 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/conf.h>
4910015Speter#include <sys/file.h>
5010015Speter#include <sys/uio.h>
5110015Speter#include <sys/dkstat.h>
5210015Speter#include <sys/kernel.h>
5310015Speter#include <sys/syslog.h>
5410015Speter#include <sys/malloc.h>
5510015Speter#include <sys/devconf.h>
5612675Sjulian#ifdef DEVFS
5712675Sjulian#include <sys/devfsext.h>
5812675Sjulian#endif /*DEVFS*/
5910015Speter
6010015Speter#include <machine/clock.h>
6110015Speter
6212659Sbde#include <vm/vm.h>
6312662Sdg#include <vm/vm_param.h>
6412662Sdg#include <vm/pmap.h>
6512659Sbde
6610015Speter#include <i386/isa/icu.h>
6710015Speter#include <i386/isa/isa.h>
6810015Speter#include <i386/isa/isa_device.h>
6910015Speter
7010015Speter#include <i386/isa/sireg.h>
7110015Speter#include <machine/si.h>
7210015Speter
7310015Speter#include "si.h"
7410015Speter
7510015Speter/*
7610015Speter * This device driver is designed to interface the Specialix International
7712496Speter * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine.
7810015Speter *
7910015Speter * The controller is interfaced to the host via dual port ram
8010015Speter * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
8110015Speter */
8210015Speter
8310015Speter#define	POLL		/* turn on poller to generate buffer empty interrupt */
8412174Speter#undef	FASTPOLL	/* turn on 100Hz poller, (XXX: NOTYET!) */
8510047Speter#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
8612496Speter#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
8710015Speter
8810015Speterenum si_mctl { GET, SET, BIS, BIC };
8910015Speter
9012675Sjulianstatic	const char devchar[] = "ABCDEFGHIJK";
9112675Sjulianstatic	const char portchar[] = "0123456789abcdefghijklmnopqrstuvwxyz";
9212502Sjulian
9312502Sjulian
9410015Speterstatic void si_command __P((struct si_port *, int, int));
9510015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
9610015Speterstatic void si_write_enable __P((struct si_port *, int));
9710015Speterstatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
9810015Speterstatic void si_start __P((struct tty *));
9910015Speterstatic void si_lstart __P((struct si_port *));
10010015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
10110015Speter					struct si_port *pp));
10210015Speterstatic void sihardclose __P((struct si_port *pp));
10310015Speterstatic void sidtrwakeup __P((void *chan));
10410015Speter
10512724Sphkstatic int	siparam __P((struct tty *, struct termios *));
10610015Speter
10712724Sphkstatic	void	si_registerdev __P((struct isa_device *id));
10812724Sphkstatic	int	siprobe __P((struct isa_device *id));
10912724Sphkstatic	int	siattach __P((struct isa_device *id));
11010708Speterstatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
11110708Speter
11212675Sjulianstruct isa_driver sidriver =
11312675Sjulian	{ siprobe, siattach, "si" };
11412675Sjulian
11512675Sjulian
11612675Sjulianstatic	d_open_t	siopen;
11712675Sjulianstatic	d_close_t	siclose;
11812675Sjulianstatic	d_read_t	siread;
11912675Sjulianstatic	d_write_t	siwrite;
12012675Sjulianstatic	d_ioctl_t	siioctl;
12112675Sjulianstatic	d_stop_t	sistop;
12212731Sbdestatic	d_devtotty_t	sidevtotty;
12312675Sjulian
12412675Sjulian#define CDEV_MAJOR 68
12512678Sphkstatic struct cdevsw si_cdevsw =
12612675Sjulian	{ siopen,	siclose,	siread,		siwrite,	/*68*/
12712743Sbde	  siioctl,	sistop,		noreset,	sidevtotty,/* si */
12812742Sbde	  ttselect,	nommap,		NULL,	"si",	NULL,	-1 };
12912675Sjulian
13012675Sjulian
13112174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
13212174Speter/* XXX: should be varargs, I know.. but where's vprintf()? */
13312174Speterstatic	void	si_dprintf __P((/* struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */));
13410708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
13510708Speter#define	DPRINT(x)	si_dprintf x
13610708Speter#else
13710708Speter#define	DPRINT(x)	/* void */
13810708Speter#endif
13910708Speter
14010962Speterstatic int si_Nports;
14110962Speterstatic int si_Nmodules;
14210962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
14310015Speter
14410962Speterstatic struct tty *si_tty;
14510962Speter
14612174Speter/* where the firmware lives; defined in si_code.c */
14710015Speterextern int si_dsize;
14810015Speterextern unsigned char si_download[];
14910015Speter
15010044Speterstruct si_softc {
15110044Speter	int 		sc_type;	/* adapter type */
15210044Speter	char 		*sc_typename;	/* adapter type string */
15310044Speter
15410044Speter	struct si_port	*sc_ports;	/* port structures for this card */
15510044Speter
15610044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
15710044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
15810044Speter	int		sc_nport;	/* # ports on this card */
15910044Speter	int		sc_irq;		/* copy of attach irq */
16010044Speter	int		sc_eisa_iobase;	/* EISA io port address */
16110044Speter	int		sc_eisa_irqbits;
16210044Speter	struct kern_devconf sc_kdc;
16312675Sjulian#ifdef	DEVFS
16412675Sjulian	struct {
16512675Sjulian		void	*ttyd;
16612826Speter		void	*cuaa;
16712675Sjulian		void	*ttyl;
16812675Sjulian		void	*ttyi;
16912675Sjulian	} devfs_token[32]; /* what is the max per card? */
17012675Sjulian#endif
17110044Speter};
17212724Sphkstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
17310044Speter
17412174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
17510015Speter# define B2000 2000
17610015Speter#endif
17710015Speterstatic struct speedtab bdrates[] = {
17810015Speter	B75,	CLK75,		/* 0x0 */
17910015Speter	B110,	CLK110,		/* 0x1 */
18010015Speter	B150,	CLK150,		/* 0x3 */
18110015Speter	B300,	CLK300,		/* 0x4 */
18210015Speter	B600,	CLK600,		/* 0x5 */
18310015Speter	B1200,	CLK1200,	/* 0x6 */
18410015Speter	B2000,	CLK2000,	/* 0x7 */
18510015Speter	B2400,	CLK2400,	/* 0x8 */
18610015Speter	B4800,	CLK4800,	/* 0x9 */
18710015Speter	B9600,	CLK9600,	/* 0xb */
18810015Speter	B19200,	CLK19200,	/* 0xc */
18910015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
19010015Speter	B57600, CLK57600,	/* 0xd */
19110015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
19210015Speter	-1,	-1
19310015Speter};
19410015Speter
19510015Speter
19610015Speter/* populated with approx character/sec rates - translated at card
19710015Speter * initialisation time to chars per tick of the clock */
19810015Speterstatic int done_chartimes = 0;
19910015Speterstatic struct speedtab chartimes[] = {
20010015Speter	B75,	8,
20110015Speter	B110,	11,
20210015Speter	B150,	15,
20310015Speter	B300,	30,
20410015Speter	B600,	60,
20510015Speter	B1200,	120,
20610015Speter	B2000,	200,
20710015Speter	B2400,	240,
20810015Speter	B4800,	480,
20910015Speter	B9600,	960,
21010015Speter	B19200,	1920,
21110015Speter	B38400, 3840,
21210015Speter	B57600, 5760,
21310015Speter	B115200, 11520,
21410015Speter	-1,	-1
21510015Speter};
21610015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
21710015Speter
21810047Speterstatic int si_default_rate =	TTYDEF_SPEED;
21910047Speterstatic int si_default_iflag =	0;
22010047Speterstatic int si_default_oflag =	0;
22110047Speterstatic int si_default_lflag =	0;
22210047Speter#ifdef SI_DEF_HWFLOW
22310047Speterstatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
22410047Speter#else
22510047Speterstatic int si_default_cflag =	TTYDEF_CFLAG;
22610047Speter#endif
22710047Speter
22810015Speter#ifdef POLL
22910015Speter#define	POLL_INTERVAL	(hz/2)
23010015Speterstatic int init_finished = 0;
23112174Speterstatic int fastpoll = 0;
23210015Speterstatic void si_poll __P((void *));
23310015Speter#endif
23410015Speter
23510015Speter/*
23610015Speter * Array of adapter types and the corresponding RAM size. The order of
23710015Speter * entries here MUST match the ordinal of the adapter type.
23810015Speter */
23910015Speterstatic char *si_type[] = {
24010015Speter	"EMPTY",
24110015Speter	"SIHOST",
24210015Speter	"SI2",				/* MCA */
24310015Speter	"SIHOST2",
24410015Speter	"SIEISA",
24510015Speter};
24610015Speter
24710015Speter
24810015Speterstatic struct kern_devconf si_kdc[NSI] = { {
24910015Speter	0, 0, 0,		/* filled in by dev_attach */
25010015Speter	"si", 0, { MDDT_ISA, 0, "tty" },
25110015Speter	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
25210015Speter	&kdc_isa0,		/* parent */
25310015Speter	0,			/* parent data */
25410015Speter	DC_UNCONFIGURED,	/* state */
25510015Speter	"Specialix SI/XIO Host adapter",
25610015Speter	DC_CLS_SERIAL,		/* class */
25710015Speter} };
25810015Speter
25912724Sphkstatic void
26010015Spetersi_registerdev(id)
26110015Speter	struct isa_device *id;
26210015Speter{
26310015Speter	if (id->id_unit != 0) {
26410015Speter		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
26510015Speter	}
26610015Speter	si_kdc[id->id_unit].kdc_unit = id->id_unit;
26710015Speter	si_kdc[id->id_unit].kdc_isa = id;
26812174Speter	si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED;
26910015Speter	dev_attach(&si_kdc[id->id_unit]);
27010015Speter}
27110015Speter
27210015Speter/* Look for a valid board at the given mem addr */
27312724Sphkstatic int
27410015Spetersiprobe(id)
27510015Speter	struct isa_device *id;
27610015Speter{
27710015Speter	struct si_softc *sc;
27810015Speter	int type;
27910015Speter	u_int i, ramsize;
28010015Speter	volatile BYTE was, *ux;
28110015Speter	volatile unsigned char *maddr;
28210015Speter	unsigned char *paddr;
28310015Speter
28410015Speter	si_registerdev(id);
28510015Speter
28610015Speter	maddr = id->id_maddr;		/* virtual address... */
28710015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
28810015Speter
28912496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
29012496Speter		id->id_unit, id->id_maddr, paddr));
29110015Speter
29210015Speter	/*
29310015Speter	 * this is a lie, but it's easier than trying to handle caching
29410015Speter	 * and ram conflicts in the >1M and <16M region.
29510015Speter	 */
29610015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
29710015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
29812174Speter		printf("si%d: iomem (%lx) out of range\n",
29912174Speter			id->id_unit, (long)paddr);
30010015Speter		return(0);
30110015Speter	}
30210015Speter
30310015Speter	if (id->id_unit >= NSI) {
30410015Speter		/* THIS IS IMPOSSIBLE */
30510015Speter		return(0);
30610015Speter	}
30710015Speter
30810015Speter	if (((u_int)paddr & 0x7fff) != 0) {
30910015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
31010015Speter			"si%d: iomem (%x) not on 32k boundary\n",
31110015Speter			id->id_unit, paddr));
31210015Speter		return(0);
31310015Speter	}
31410015Speter
31510015Speter
31610015Speter	for (i=0; i < NSI; i++) {
31710015Speter		if ((sc = &si_softc[i]) == NULL)
31810015Speter			continue;
31910015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
32010015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
32110015Speter				"si%d: iomem (%x) already configured to si%d\n",
32210015Speter				id->id_unit, sc->sc_paddr, i));
32310015Speter			return(0);
32410015Speter		}
32510015Speter	}
32610015Speter
32710015Speter#if NEISA > 0
32810015Speter	if (id->id_iobase > 0x0fff) {	/* EISA card */
32910015Speter		int irq, port;
33010015Speter		unsigned long base;
33110015Speter		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
33210015Speter			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
33310015Speter
33410015Speter		port = id->id_iobase;
33510015Speter		base = (inb(port+1) << 24) | (inb(port) << 16);
33610015Speter		irq  = ((inb(port+2) >> 4) & 0xf);
33710015Speter
33810015Speter		id->id_irq = eisa_irqs[irq];
33910015Speter
34010015Speter		DPRINT((0, DBG_AUTOBOOT,
34112496Speter		    "si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
34210015Speter		    id->id_unit, base, irq, id->id_irq, port));
34310015Speter
34410015Speter		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
34510015Speter			goto bad_irq;
34610015Speter
34710015Speter		id->id_iobase &= 0xf000;
34810015Speter		id->id_iosize  = 0x0fff;
34910015Speter
35010015Speter		type = EISA;
35110015Speter		outb(p+2, (BYTE)irq << 4);
35210015Speter
35310015Speter		sc->sc_eisa_iobase = p;
35410015Speter		sc->sc_eisa_irqbits = irq << 4;
35510015Speter		ramsize = SIEISA_RAMSIZE;
35610015Speter		goto got_card;
35710015Speter	}
35810015Speter#endif
35910015Speter
36010015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
36110015Speter	*maddr = 0x17;
36210015Speter	if (*maddr != 0x17) {
36310015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
36410015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
36510015Speter			id->id_unit, paddr));
36610015Speterfail:
36710015Speter		return(0);
36810015Speter	}
36910015Speter	/*
37010015Speter	 * OK, now to see if whatever responded is really an SI card.
37110015Speter	 * Try for a MK II first (SIHOST2)
37210015Speter	 */
37310015Speter	for (i=SIPLSIG; i<SIPLSIG+8; i++)
37410015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
37510015Speter			goto try_mk1;
37610015Speter
37710015Speter	/* It must be an SIHOST2 */
37810015Speter	*(maddr + SIPLRESET) = 0;
37910015Speter	*(maddr + SIPLIRQCLR) = 0;
38010015Speter	*(maddr + SIPLIRQSET) = 0x10;
38110015Speter	type = SIHOST2;
38210015Speter	ramsize = SIHOST2_RAMSIZE;
38310015Speter	goto got_card;
38410015Speter
38510015Speter	/*
38610015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
38710015Speter	 */
38810015Spetertry_mk1:
38910015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
39010015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
39110015Speter	*(maddr+SIRAM) = 0x17;
39210015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
39310015Speter		goto fail;
39410015Speter	*(maddr+0x7ff8) = 0x17;
39510015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
39610015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
39710015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
39810015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
39910015Speter		goto fail;
40010015Speter	}
40110015Speter
40210015Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
40310015Speter	type = SIHOST;
40410015Speter	ramsize = SIHOST_RAMSIZE;
40510015Speter
40610015Spetergot_card:
40712496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
40812496Speter		id->id_unit, type));
40910015Speter	/* Try the acid test */
41010015Speter	ux = (BYTE *)(maddr + SIRAM);
41110015Speter	for (i=0; i<ramsize; i++, ux++)
41210015Speter		*ux = (BYTE)(i&0xff);
41310015Speter	ux = (BYTE *)(maddr + SIRAM);
41410015Speter	for (i=0; i<ramsize; i++, ux++) {
41510015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
41610015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
41712174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
41810015Speter				id->id_unit, paddr+i, was, i&0xff));
41910015Speter			goto fail;
42010015Speter		}
42110015Speter	}
42210015Speter
42310015Speter	/* clear out the RAM */
42410015Speter	ux = (BYTE *)(maddr + SIRAM);
42510015Speter	for (i=0; i<ramsize; i++)
42610015Speter		*ux++ = 0;
42710015Speter	ux = (BYTE *)(maddr + SIRAM);
42810015Speter	for (i=0; i<ramsize; i++) {
42910015Speter		if ((was = *ux++) != 0) {
43010015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
43112174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
43210015Speter				id->id_unit, paddr+i, was));
43310015Speter			goto fail;
43410015Speter		}
43510015Speter	}
43610015Speter
43710015Speter	/*
43810015Speter	 * Success, we've found a valid board, now fill in
43910015Speter	 * the adapter structure.
44010015Speter	 */
44110015Speter	switch (type) {
44210015Speter	case SIHOST2:
44310015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
44410015Speterbad_irq:
44510015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
44610015Speter				"si%d: bad IRQ value - %d\n",
44710015Speter				id->id_unit, id->id_irq));
44810015Speter			return(0);
44910015Speter		}
45010015Speter		id->id_msize = SIHOST2_MEMSIZE;
45110015Speter		break;
45210015Speter	case SIHOST:
45310015Speter		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
45410015Speter			goto bad_irq;
45510015Speter		}
45610015Speter		id->id_msize = SIHOST_MEMSIZE;
45710015Speter		break;
45810015Speter	case SIEISA:
45910015Speter		id->id_msize = SIEISA_MEMSIZE;
46010015Speter		break;
46110015Speter	case SI2:		/* MCA */
46210015Speter	default:
46310015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
46410015Speter		return(0);
46510015Speter	}
46610015Speter	si_softc[id->id_unit].sc_type = type;
46710015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
46810015Speter	return(-1);	/* -1 == found */
46910015Speter}
47010015Speter
47110015Speter/*
47210015Speter * Attach the device.  Initialize the card.
47310015Speter */
47412724Sphkstatic int
47510015Spetersiattach(id)
47610015Speter	struct isa_device *id;
47710015Speter{
47810015Speter	int unit = id->id_unit;
47910015Speter	struct si_softc *sc = &si_softc[unit];
48010015Speter	struct si_port *pp;
48110015Speter	volatile struct si_channel *ccbp;
48210015Speter	volatile struct si_reg *regp;
48310015Speter	volatile caddr_t maddr;
48410015Speter	struct si_module *modp;
48510015Speter	struct tty *tp;
48610015Speter	struct speedtab *spt;
48710015Speter	int nmodule, nport, x, y;
48812174Speter	int uart_type;
48912675Sjulian	char	name[32];
49010015Speter
49112496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
49210015Speter
49310015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
49410015Speter	sc->sc_maddr = id->id_maddr;
49510015Speter	sc->sc_irq = id->id_irq;
49610015Speter
49710015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
49810015Speter
49910015Speter	maddr = sc->sc_maddr;
50010015Speter
50110015Speter	/*
50210015Speter	 * OK, now lets download the firmware and try and boot the CPU..
50310015Speter	 */
50410015Speter
50512496Speter	DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
50612496Speter		id->id_unit, si_dsize));
50710015Speter	bcopy(si_download, maddr, si_dsize);
50810015Speter
50910015Speter	switch (sc->sc_type) {
51010015Speter	case SIEISA:
51110015Speter#if NEISA > 0
51210015Speter		/* modify the Z280 firmware to tell it that it's on an EISA */
51310015Speter		*(maddr+0x42) = 1;
51410015Speter		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
51510015Speter		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
51610015Speter		break;
51710015Speter#endif	/* fall-through if not EISA */
51810015Speter	case SI2:
51912174Speter		/*
52012174Speter		 * must get around to converting the code for
52112174Speter		 * these one day, if FreeBSD ever supports it.
52212174Speter		 */
52310015Speter		return 0;
52410015Speter	case SIHOST:
52510015Speter		*(maddr+SIRESET_CL) = 0;
52610015Speter		*(maddr+SIINTCL_CL) = 0;
52710015Speter		break;
52810015Speter	case SIHOST2:
52910015Speter		*(maddr+SIPLRESET) = 0x10;
53010015Speter		switch (sc->sc_irq) {
53110015Speter		case IRQ11:
53210015Speter			*(maddr+SIPLIRQ11) = 0x10;
53310015Speter			break;
53410015Speter		case IRQ12:
53510015Speter			*(maddr+SIPLIRQ12) = 0x10;
53610015Speter			break;
53710015Speter		case IRQ15:
53810015Speter			*(maddr+SIPLIRQ15) = 0x10;
53910015Speter			break;
54010015Speter		}
54110015Speter		*(maddr+SIPLIRQCLR) = 0x10;
54210015Speter		break;
54310015Speter	}
54410015Speter
54510015Speter	DELAY(1000000);			/* wait around for a second */
54610015Speter
54710015Speter	regp = (struct si_reg *)maddr;
54810015Speter	y = 0;
54910015Speter					/* wait max of 5 sec for init OK */
55010015Speter	while (regp->initstat == 0 && y++ < 10) {
55110015Speter		DELAY(500000);
55210015Speter	}
55310015Speter	switch (regp->initstat) {
55410015Speter	case 0:
55510015Speter		printf("si%d: startup timeout - aborting\n", unit);
55612174Speter		sc->sc_type = SIEMPTY;
55710015Speter		return 0;
55810015Speter	case 1:
55912174Speter			/* set throttle to 125 intr per second */
56010015Speter		regp->int_count = 25000;
56110015Speter			/* rx intr max of 25 timer per second */
56210015Speter		regp->rx_int_count = 4;
56310015Speter		regp->int_pending = 0;		/* no intr pending */
56410015Speter		regp->int_scounter = 0;	/* reset counter */
56510015Speter		break;
56610015Speter	case 0xff:
56710015Speter		/*
56810015Speter		 * No modules found, so give up on this one.
56910015Speter		 */
57010015Speter		printf("si%d: %s - no ports found\n", unit,
57110015Speter			si_type[sc->sc_type]);
57210015Speter		return 0;
57310015Speter	default:
57410015Speter		printf("si%d: Z280 version error - initstat %x\n",
57510015Speter			unit, regp->initstat);
57610015Speter		return 0;
57710015Speter	}
57810015Speter
57910015Speter	/*
58010015Speter	 * First time around the ports just count them in order
58110015Speter	 * to allocate some memory.
58210015Speter	 */
58310015Speter	nport = 0;
58410015Speter	modp = (struct si_module *)(maddr + 0x80);
58510015Speter	for (;;) {
58612174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
58710015Speter		switch (modp->sm_type & (~MMASK)) {
58810015Speter		case M232:
58910015Speter		case M422:
59010015Speter			DPRINT((0, DBG_DOWNLOAD,
59112174Speter				"si%d: Found 232/422 module, %d ports\n",
59210015Speter				unit, (int)(modp->sm_type & MMASK)));
59310015Speter
59410015Speter			/* this is a firmware issue */
59510015Speter			if (si_Nports == SI_MAXPORTPERCARD) {
59610015Speter				printf("si%d: extra ports ignored\n", unit);
59710015Speter				continue;
59810015Speter			}
59910015Speter
60010015Speter			x = modp->sm_type & MMASK;
60110015Speter			nport += x;
60210015Speter			si_Nports += x;
60310015Speter			si_Nmodules++;
60410015Speter			break;
60510015Speter		default:
60610015Speter			printf("si%d: unknown module type %d\n",
60710015Speter				unit, modp->sm_type);
60810015Speter			break;
60910015Speter		}
61010015Speter		if (modp->sm_next == 0)
61110015Speter			break;
61210015Speter		modp = (struct si_module *)
61310015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
61410015Speter	}
61510015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
61610015Speter		M_DEVBUF, M_NOWAIT);
61710015Speter	if (sc->sc_ports == 0) {
61810015Spetermem_fail:
61910015Speter		printf("si%d: fail to malloc memory for port structs\n",
62010015Speter			unit);
62110015Speter		return 0;
62210015Speter	}
62310015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
62410015Speter	sc->sc_nport = nport;
62510015Speter
62610015Speter	/*
62710015Speter	 * allocate tty structures for ports
62810015Speter	 */
62910015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
63010015Speter	if (tp == 0)
63110015Speter		goto mem_fail;
63210015Speter	bzero(tp, sizeof(*tp) * nport);
63310962Speter	si_tty = tp;
63410015Speter
63510015Speter	/* mark the device state as attached */
63610015Speter	si_kdc[unit].kdc_state = DC_BUSY;
63710015Speter
63810015Speter	/*
63910015Speter	 * Scan round the ports again, this time initialising.
64010015Speter	 */
64110015Speter	pp = sc->sc_ports;
64210015Speter	nmodule = 0;
64310015Speter	modp = (struct si_module *)(maddr + 0x80);
64412174Speter	uart_type = 0;
64510015Speter	for (;;) {
64610015Speter		switch (modp->sm_type & (~MMASK)) {
64710015Speter		case M232:
64810015Speter		case M422:
64910015Speter			nmodule++;
65010015Speter			nport = (modp->sm_type & MMASK);
65110015Speter			ccbp = (struct si_channel *)((char *)modp+0x100);
65212174Speter			if (uart_type == 0)
65312174Speter				uart_type = ccbp->type;
65410015Speter			for (x = 0; x < nport; x++, pp++, ccbp++) {
65510015Speter				pp->sp_ccb = ccbp;	/* save the address */
65610015Speter				pp->sp_tty = tp++;
65710015Speter				pp->sp_pend = IDLE_CLOSE;
65810015Speter				pp->sp_state = 0;	/* internal flag */
65910015Speter				pp->sp_dtr_wait = 3 * hz;
66010047Speter				pp->sp_iin.c_iflag = si_default_iflag;
66110047Speter				pp->sp_iin.c_oflag = si_default_oflag;
66210047Speter				pp->sp_iin.c_cflag = si_default_cflag;
66310047Speter				pp->sp_iin.c_lflag = si_default_lflag;
66410015Speter				termioschars(&pp->sp_iin);
66510015Speter				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
66610047Speter					si_default_rate;
66710015Speter				pp->sp_iout = pp->sp_iin;
66810015Speter			}
66910015Speter			break;
67010015Speter		default:
67110015Speter			break;
67210015Speter		}
67310015Speter		if (modp->sm_next == 0) {
67412174Speter			printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n",
67510015Speter				unit,
67610015Speter				sc->sc_typename,
67710015Speter				sc->sc_nport,
67812174Speter				nmodule,
67912174Speter				uart_type);
68010015Speter			break;
68110015Speter		}
68210015Speter		modp = (struct si_module *)
68310015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
68410015Speter	}
68510015Speter	if (done_chartimes == 0) {
68610015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
68710015Speter			if ((spt->sp_code /= hz) == 0)
68810015Speter				spt->sp_code = 1;
68910015Speter		}
69010015Speter		done_chartimes = 1;
69110015Speter	}
69212502Sjulian
69312675Sjulian#ifdef DEVFS
69412675Sjulian/*	path	name	devsw		minor	type   uid gid perm*/
69512675Sjulian	for ( x = 0; x < nport; x++ ) {
69612826Speter		sprintf(name,"ttyA%02d", x + 1);
69712675Sjulian		sc->devfs_token[x].ttyd = devfs_add_devsw(
69812675Sjulian			"/", name, &si_cdevsw, unit,
69912675Sjulian			DV_CHR, 0, 0, 0600);
70012826Speter		sprintf(name,"cuaA%02d", x + 1);
70112675Sjulian		sc->devfs_token[x].cuaa = devfs_add_devsw(
70212675Sjulian			"/", name, &si_cdevsw, unit + 128,
70312675Sjulian			DV_CHR, 0, 0, 0600);
70412826Speter		sprintf(name,"ttyiA%02d", x + 1);
70512826Speter		sc->devfs_token[x].ttyi = devfs_add_devsw(
70612826Speter			"/", name, &si_cdevsw, unit + 0x10000,
70712675Sjulian			DV_CHR, 0, 0, 0600);
70812826Speter		sprintf(name,"ttylA%02d", x + 1);
70912826Speter		sc->devfs_token[x].ttyl = devfs_add_devsw(
71012826Speter			"/", name, &si_cdevsw, unit + 0x20000,
71112675Sjulian			DV_CHR, 0, 0, 0600);
71212675Sjulian	}
71312826Speter	/* XXX: no global yet */
71412675Sjulian#endif
71510015Speter	return (1);
71610015Speter}
71710015Speter
71812675Sjulianstatic	int
71910015Spetersiopen(dev, flag, mode, p)
72010015Speter	dev_t dev;
72110015Speter	int flag, mode;
72210015Speter	struct proc *p;
72310015Speter{
72410015Speter	int oldspl, error;
72510015Speter	int card, port;
72610015Speter	register struct si_softc *sc;
72710015Speter	register struct tty *tp;
72810015Speter	volatile struct si_channel *ccbp;
72910015Speter	struct si_port *pp;
73010015Speter	int mynor = minor(dev);
73110015Speter
73210015Speter	/* quickly let in /dev/si_control */
73310015Speter	if (IS_CONTROLDEV(mynor)) {
73410015Speter		if (error = suser(p->p_ucred, &p->p_acflag))
73510015Speter			return(error);
73610015Speter		return(0);
73710015Speter	}
73810015Speter
73910015Speter	card = SI_CARD(mynor);
74010015Speter	if (card >= NSI)
74110015Speter		return (ENXIO);
74210015Speter	sc = &si_softc[card];
74310015Speter
74412174Speter	if (sc->sc_type == SIEMPTY) {
74512174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
74610015Speter			card, sc->sc_typename));
74710015Speter		return(ENXIO);
74810015Speter	}
74910015Speter
75010015Speter	port = SI_PORT(mynor);
75110015Speter	if (port >= sc->sc_nport) {
75212174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
75310015Speter			card, sc->sc_nport));
75410015Speter		return(ENXIO);
75510015Speter	}
75610015Speter
75710015Speter#ifdef	POLL
75810015Speter	/*
75910015Speter	 * We've now got a device, so start the poller.
76010015Speter	 */
76110015Speter	if (init_finished == 0) {
76210015Speter		timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
76310015Speter		init_finished = 1;
76410015Speter	}
76510015Speter#endif
76610015Speter
76710015Speter	/* initial/lock device */
76810015Speter	if (IS_STATE(mynor)) {
76910015Speter		return(0);
77010015Speter	}
77110015Speter
77210015Speter	pp = sc->sc_ports + port;
77310015Speter	tp = pp->sp_tty;			/* the "real" tty */
77410015Speter	ccbp = pp->sp_ccb;			/* Find control block */
77510015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
77610015Speter		dev, flag, mode, p));
77710015Speter
77810015Speter	oldspl = spltty();			/* Keep others out */
77910015Speter	error = 0;
78010015Speter
78110015Speteropen_top:
78210015Speter	while (pp->sp_state & SS_DTR_OFF) {
78310015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
78410015Speter		if (error != 0)
78510015Speter			goto out;
78610015Speter	}
78710015Speter
78810015Speter	if (tp->t_state & TS_ISOPEN) {
78910015Speter		/*
79010015Speter		 * The device is open, so everything has been initialised.
79110015Speter		 * handle conflicts.
79210015Speter		 */
79310015Speter		if (IS_CALLOUT(mynor)) {
79410015Speter			if (!pp->sp_active_out) {
79510015Speter				error = EBUSY;
79610015Speter				goto out;
79710015Speter			}
79810015Speter		} else {
79910015Speter			if (pp->sp_active_out) {
80010015Speter				if (flag & O_NONBLOCK) {
80110015Speter					error = EBUSY;
80210015Speter					goto out;
80310015Speter				}
80410015Speter				error = tsleep(&pp->sp_active_out,
80510015Speter						TTIPRI|PCATCH, "sibi", 0);
80610015Speter				if (error != 0)
80710015Speter					goto out;
80810015Speter				goto open_top;
80910015Speter			}
81010015Speter		}
81110015Speter		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
81210015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
81310015Speter				"already open and EXCLUSIVE set\n"));
81410015Speter			error = EBUSY;
81510015Speter			goto out;
81610015Speter		}
81710015Speter	} else {
81810015Speter		/*
81910015Speter		 * The device isn't open, so there are no conflicts.
82010015Speter		 * Initialize it. Avoid sleep... :-)
82110015Speter		 */
82210015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
82310015Speter		tp->t_oproc = si_start;
82410015Speter		tp->t_param = siparam;
82510015Speter		tp->t_dev = dev;
82610015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
82710015Speter				? pp->sp_iout : pp->sp_iin;
82810015Speter
82910015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
83010015Speter
83110015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
83210015Speter
83310015Speter		error = siparam(tp, &tp->t_termios);
83410015Speter
83510015Speter		--pp->sp_wopeners;
83610015Speter		if (error != 0)
83710015Speter			goto out;
83810015Speter		/* XXX: we should goto_top if siparam slept */
83910015Speter
84010015Speter		ttsetwater(tp);
84110015Speter
84210015Speter		/* set initial DCD state */
84310015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
84410015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
84510015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
84610015Speter		}
84710015Speter	}
84810015Speter
84910015Speter	/* whoops! we beat the close! */
85010015Speter	if (pp->sp_state & SS_CLOSING) {
85110015Speter		/* try and stop it from proceeding to bash the hardware */
85210015Speter		pp->sp_state &= ~SS_CLOSING;
85310015Speter	}
85410015Speter
85510015Speter	/*
85610015Speter	 * Wait for DCD if necessary
85710015Speter	 */
85810015Speter	if (!(tp->t_state & TS_CARR_ON)
85910015Speter	    && !IS_CALLOUT(mynor)
86010015Speter	    && !(tp->t_cflag & CLOCAL)
86110015Speter	    && !(flag & O_NONBLOCK)) {
86210015Speter		++pp->sp_wopeners;
86310015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
86410015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
86510015Speter		--pp->sp_wopeners;
86610015Speter		if (error != 0)
86710015Speter			goto out;
86810015Speter		goto open_top;
86910015Speter	}
87010015Speter
87110015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
87210015Speter	si_disc_optim(tp, &tp->t_termios, pp);
87310015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
87410015Speter		pp->sp_active_out = TRUE;
87510015Speter
87610015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
87710015Speter
87810015Speterout:
87910015Speter	splx(oldspl);
88010015Speter
88110015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
88210015Speter
88310015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
88410015Speter		sihardclose(pp);
88510015Speter
88610015Speter	return(error);
88710015Speter}
88810015Speter
88912675Sjulianstatic	int
89010015Spetersiclose(dev, flag, mode, p)
89110015Speter	dev_t dev;
89210015Speter	int flag, mode;
89310015Speter	struct proc *p;
89410015Speter{
89510015Speter	register struct si_port *pp;
89610015Speter	register struct tty *tp;
89710015Speter	int oldspl;
89810015Speter	int error = 0;
89910015Speter	int mynor = minor(dev);
90010015Speter
90110015Speter	if (IS_SPECIAL(mynor))
90210015Speter		return(0);
90310015Speter
90410015Speter	oldspl = spltty();
90510015Speter
90610015Speter	pp = MINOR2PP(mynor);
90710015Speter	tp = pp->sp_tty;
90810015Speter
90910015Speter	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
91010015Speter		dev, flag, mode, p, pp->sp_state));
91110015Speter
91210015Speter	/* did we sleep and loose a race? */
91310015Speter	if (pp->sp_state & SS_CLOSING) {
91410015Speter		/* error = ESOMETING? */
91510015Speter		goto out;
91610015Speter	}
91710015Speter
91810015Speter	/* begin race detection.. */
91910015Speter	pp->sp_state |= SS_CLOSING;
92010015Speter
92110015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
92210015Speter
92310015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
92410015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
92510015Speter
92610015Speter	si_write_enable(pp, 1);
92710015Speter
92810015Speter	/* did we sleep and somebody started another open? */
92910015Speter	if (!(pp->sp_state & SS_CLOSING)) {
93010015Speter		/* error = ESOMETING? */
93110015Speter		goto out;
93210015Speter	}
93310015Speter	/* ok. we are now still on the right track.. nuke the hardware */
93410015Speter
93510015Speter	if (pp->sp_state & SS_LSTART) {
93610015Speter		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
93710015Speter		pp->sp_state &= ~SS_LSTART;
93810015Speter	}
93910015Speter
94010015Speter	sistop(tp, FREAD | FWRITE);
94110015Speter
94210015Speter	sihardclose(pp);
94310015Speter	ttyclose(tp);
94410015Speter	pp->sp_state &= ~SS_OPEN;
94510015Speter
94610015Speterout:
94710015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
94810015Speter	splx(oldspl);
94910015Speter	return(error);
95010015Speter}
95110015Speter
95210015Speterstatic void
95310015Spetersihardclose(pp)
95410015Speter	struct si_port *pp;
95510015Speter{
95610015Speter	int oldspl;
95710015Speter	struct tty *tp;
95810015Speter	volatile struct si_channel *ccbp;
95910015Speter
96010015Speter	oldspl = spltty();
96110015Speter
96210015Speter	tp = pp->sp_tty;
96310015Speter	ccbp = pp->sp_ccb;			/* Find control block */
96410015Speter	if (tp->t_cflag & HUPCL
96510015Speter	    || !pp->sp_active_out
96610015Speter	       && !(ccbp->hi_ip & IP_DCD)
96710015Speter	       && !(pp->sp_iin.c_cflag && CLOCAL)
96810015Speter	    || !(tp->t_state & TS_ISOPEN)) {
96910015Speter
97010015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
97110015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
97210015Speter
97310015Speter		if (pp->sp_dtr_wait != 0) {
97410015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
97510015Speter			pp->sp_state |= SS_DTR_OFF;
97610015Speter		}
97710015Speter
97810015Speter	}
97910015Speter	pp->sp_active_out = FALSE;
98010015Speter	wakeup((caddr_t)&pp->sp_active_out);
98110015Speter	wakeup(TSA_CARR_ON(tp));
98210015Speter
98310015Speter	splx(oldspl);
98410015Speter}
98510015Speter
98610015Speter
98710015Speter/*
98810015Speter * called at splsoftclock()...
98910015Speter */
99010015Speterstatic void
99110015Spetersidtrwakeup(chan)
99210015Speter	void *chan;
99310015Speter{
99410015Speter	struct si_port *pp;
99510015Speter	int oldspl;
99610015Speter
99710015Speter	oldspl = spltty();
99810015Speter
99910015Speter	pp = (struct si_port *)chan;
100010015Speter	pp->sp_state &= ~SS_DTR_OFF;
100110015Speter	wakeup(&pp->sp_dtr_wait);
100210015Speter
100310015Speter	splx(oldspl);
100410015Speter}
100510015Speter
100610015Speter/*
100710015Speter * User level stuff - read and write
100810015Speter */
100912675Sjulianstatic	int
101010015Spetersiread(dev, uio, flag)
101110015Speter	register dev_t dev;
101210015Speter	struct uio *uio;
101310015Speter	int flag;
101410015Speter{
101510015Speter	register struct tty *tp;
101610015Speter	int mynor = minor(dev);
101710015Speter
101810015Speter	if (IS_SPECIAL(mynor)) {
101910015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
102010015Speter		return(ENODEV);
102110015Speter	}
102210015Speter	tp = MINOR2TP(mynor);
102310015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
102410015Speter		"siread(%x,%x,%x)\n", dev, uio, flag));
102510015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
102610015Speter}
102710015Speter
102810015Speter
102912675Sjulianstatic	int
103010015Spetersiwrite(dev, uio, flag)
103110015Speter	dev_t dev;
103210015Speter	struct uio *uio;
103310015Speter	int flag;
103410015Speter{
103510015Speter	register struct si_port *pp;
103610015Speter	register struct tty *tp;
103710015Speter	int error = 0;
103810015Speter	int mynor = minor(dev);
103910015Speter	int oldspl;
104010015Speter
104110015Speter	if (IS_SPECIAL(mynor)) {
104210015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
104310015Speter		return(ENODEV);
104410015Speter	}
104510015Speter	pp = MINOR2PP(mynor);
104610015Speter	tp = pp->sp_tty;
104710015Speter	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
104810015Speter
104910015Speter	oldspl = spltty();
105010015Speter	/*
105110015Speter	 * If writes are currently blocked, wait on the "real" tty
105210015Speter	 */
105310015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
105410015Speter		pp->sp_state |= SS_WAITWRITE;
105510015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
105610015Speter		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
105710015Speter				     "siwrite", 0))
105810015Speter			goto out;
105910015Speter	}
106010015Speter
106110015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
106210015Speterout:
106310015Speter	splx(oldspl);
106410015Speter	return (error);
106510015Speter}
106610015Speter
106710015Speter
106812675Sjulianstatic	struct tty *
106910015Spetersidevtotty(dev_t dev)
107010015Speter{
107110015Speter	struct si_port *pp;
107210015Speter	int mynor = minor(dev);
107310015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
107410015Speter
107510015Speter	if (IS_SPECIAL(mynor))
107610015Speter		return(NULL);
107710015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
107810015Speter		return(NULL);
107910015Speter	pp = MINOR2PP(mynor);
108010015Speter	return (pp->sp_tty);
108110015Speter}
108210015Speter
108312675Sjulianstatic	int
108410015Spetersiioctl(dev, cmd, data, flag, p)
108510015Speter	dev_t dev;
108610015Speter	int cmd;
108710015Speter	caddr_t data;
108810015Speter	int flag;
108910015Speter	struct proc *p;
109010015Speter{
109110015Speter	struct si_port *pp;
109210015Speter	register struct tty *tp;
109310015Speter	int error;
109410015Speter	int mynor = minor(dev);
109510015Speter	int oldspl;
109610015Speter	int blocked = 0;
109710015Speter#if defined(COMPAT_43)
109810015Speter	int oldcmd;
109910015Speter	struct termios term;
110010015Speter#endif
110110015Speter
110210015Speter	if (IS_SI_IOCTL(cmd))
110310015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
110410015Speter
110510015Speter	pp = MINOR2PP(mynor);
110610015Speter	tp = pp->sp_tty;
110710015Speter
110810015Speter	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
110910015Speter		dev, cmd, data, flag));
111010015Speter	if (IS_STATE(mynor)) {
111110015Speter		struct termios *ct;
111210015Speter
111310015Speter		switch (mynor & SI_STATE_MASK) {
111410015Speter		case SI_INIT_STATE_MASK:
111510015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
111610015Speter			break;
111710015Speter		case SI_LOCK_STATE_MASK:
111810015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
111910015Speter			break;
112010015Speter		default:
112110015Speter			return (ENODEV);
112210015Speter		}
112310015Speter		switch (cmd) {
112410015Speter		case TIOCSETA:
112510015Speter			error = suser(p->p_ucred, &p->p_acflag);
112610015Speter			if (error != 0)
112710015Speter				return (error);
112810015Speter			*ct = *(struct termios *)data;
112910015Speter			return (0);
113010015Speter		case TIOCGETA:
113110015Speter			*(struct termios *)data = *ct;
113210015Speter			return (0);
113310015Speter		case TIOCGETD:
113410015Speter			*(int *)data = TTYDISC;
113510015Speter			return (0);
113610015Speter		case TIOCGWINSZ:
113710015Speter			bzero(data, sizeof(struct winsize));
113810015Speter			return (0);
113910015Speter		default:
114010015Speter			return (ENOTTY);
114110015Speter		}
114210015Speter	}
114310015Speter	/*
114410015Speter	 * Do the old-style ioctl compat routines...
114510015Speter	 */
114610015Speter#if defined(COMPAT_43)
114710015Speter	term = tp->t_termios;
114810015Speter	oldcmd = cmd;
114910015Speter	error = ttsetcompat(tp, &cmd, data, &term);
115010015Speter	if (error != 0)
115110015Speter		return (error);
115210015Speter	if (cmd != oldcmd)
115310015Speter		data = (caddr_t)&term;
115410015Speter#endif
115510015Speter	/*
115610015Speter	 * Do the initial / lock state business
115710015Speter	 */
115810015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
115910015Speter		int     cc;
116010015Speter		struct termios *dt = (struct termios *)data;
116110015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
116210015Speter				     ? &pp->sp_lout : &pp->sp_lin;
116310015Speter
116410015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
116510015Speter			| (dt->c_iflag & ~lt->c_iflag);
116610015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
116710015Speter			| (dt->c_oflag & ~lt->c_oflag);
116810015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
116910015Speter			| (dt->c_cflag & ~lt->c_cflag);
117010015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
117110015Speter			| (dt->c_lflag & ~lt->c_lflag);
117210015Speter		for (cc = 0; cc < NCCS; ++cc)
117310015Speter			if (lt->c_cc[cc] != 0)
117410015Speter				dt->c_cc[cc] = tp->t_cc[cc];
117510015Speter		if (lt->c_ispeed != 0)
117610015Speter			dt->c_ispeed = tp->t_ispeed;
117710015Speter		if (lt->c_ospeed != 0)
117810015Speter			dt->c_ospeed = tp->t_ospeed;
117910015Speter	}
118010015Speter
118110015Speter	/*
118210015Speter	 * Block user-level writes to give the ttywait()
118310015Speter	 * a chance to completely drain for commands
118410015Speter	 * that require the port to be in a quiescent state.
118510015Speter	 */
118610015Speter	switch (cmd) {
118710015Speter	case TIOCSETAW: case TIOCSETAF:
118810015Speter	case TIOCDRAIN: case TIOCSETP:
118910015Speter		blocked++;	/* block writes for ttywait() and siparam() */
119010015Speter		si_write_enable(pp, 0);
119110015Speter	}
119210015Speter
119310015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
119410015Speter	if (error >= 0)
119510015Speter		goto out;
119610015Speter
119710015Speter	oldspl = spltty();
119810015Speter
119910015Speter	error = ttioctl(tp, cmd, data, flag);
120010015Speter	si_disc_optim(tp, &tp->t_termios, pp);
120110015Speter	if (error >= 0)
120210015Speter		goto outspl;
120310015Speter
120410015Speter	switch (cmd) {
120510015Speter	case TIOCSBRK:
120610015Speter		si_command(pp, SBREAK, SI_NOWAIT);
120710015Speter		break;
120810015Speter	case TIOCCBRK:
120910015Speter		si_command(pp, EBREAK, SI_NOWAIT);
121010015Speter		break;
121110015Speter	case TIOCSDTR:
121210015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
121310015Speter		break;
121410015Speter	case TIOCCDTR:
121510015Speter		(void) si_modem(pp, SET, 0);
121610015Speter		break;
121710015Speter	case TIOCMSET:
121810015Speter		(void) si_modem(pp, SET, *(int *)data);
121910015Speter		break;
122010015Speter	case TIOCMBIS:
122110015Speter		(void) si_modem(pp, BIS, *(int *)data);
122210015Speter		break;
122310015Speter	case TIOCMBIC:
122410015Speter		(void) si_modem(pp, BIC, *(int *)data);
122510015Speter		break;
122610015Speter	case TIOCMGET:
122710015Speter		*(int *)data = si_modem(pp, GET, 0);
122810015Speter		break;
122910015Speter	case TIOCMSDTRWAIT:
123010015Speter		/* must be root since the wait applies to following logins */
123110015Speter		error = suser(p->p_ucred, &p->p_acflag);
123210015Speter		if (error != 0) {
123310015Speter			goto outspl;
123410015Speter		}
123510015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
123610015Speter		break;
123710015Speter	case TIOCMGDTRWAIT:
123810015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
123910015Speter		break;
124010015Speter
124110015Speter	default:
124210015Speter		error = ENOTTY;
124310015Speter	}
124410015Speter	error = 0;
124510015Speteroutspl:
124610015Speter	splx(oldspl);
124710015Speterout:
124810015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
124910015Speter	if (blocked)
125010015Speter		si_write_enable(pp, 1);
125110015Speter	return(error);
125210015Speter}
125310015Speter
125410015Speter/*
125510015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
125610015Speter */
125710015Speterstatic int
125810015Spetersi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
125910015Speter{
126010015Speter	struct si_softc *xsc;
126110015Speter	register struct si_port *xpp;
126210015Speter	volatile struct si_reg *regp;
126310015Speter	struct si_tcsi *dp;
126410044Speter	struct si_pstat *sps;
126511872Sphk	int *ip, error = 0;
126610015Speter	int oldspl;
126710015Speter	int card, port;
126810015Speter	int mynor = minor(dev);
126910015Speter
127010015Speter	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
127110015Speter		dev, cmd, data, flag));
127210015Speter
127310044Speter#if 1
127410044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
127510044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
127610044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
127710044Speter#endif
127810044Speter
127910015Speter	if (!IS_CONTROLDEV(mynor)) {
128010015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
128110015Speter		return(ENODEV);
128210015Speter	}
128310015Speter
128410015Speter	oldspl = spltty();	/* better safe than sorry */
128510015Speter
128610015Speter	ip = (int *)data;
128710015Speter
128810015Speter#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
128910015Speter
129010015Speter	switch (cmd) {
129110015Speter	case TCSIPORTS:
129210015Speter		*ip = si_Nports;
129310015Speter		goto out;
129410015Speter	case TCSIMODULES:
129510015Speter		*ip = si_Nmodules;
129610015Speter		goto out;
129710015Speter	case TCSISDBG_ALL:
129810015Speter		SUCHECK;
129910015Speter		si_debug = *ip;
130010015Speter		goto out;
130110015Speter	case TCSIGDBG_ALL:
130210015Speter		*ip = si_debug;
130310015Speter		goto out;
130410015Speter	default:
130510015Speter		/*
130610015Speter		 * Check that a controller for this port exists
130710015Speter		 */
130810044Speter
130910044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
131010044Speter
131110015Speter		dp = (struct si_tcsi *)data;
131210044Speter		sps = (struct si_pstat *)data;
131310015Speter		card = dp->tc_card;
131410015Speter		xsc = &si_softc[card];	/* check.. */
131512174Speter		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
131610015Speter			error = ENOENT;
131710015Speter			goto out;
131810015Speter		}
131910015Speter		/*
132010015Speter		 * And check that a port exists
132110015Speter		 */
132210015Speter		port = dp->tc_port;
132310015Speter		if (port < 0 || port >= xsc->sc_nport) {
132410015Speter			error = ENOENT;
132510015Speter			goto out;
132610015Speter		}
132710015Speter		xpp = xsc->sc_ports + port;
132810015Speter		regp = (struct si_reg *)xsc->sc_maddr;
132910015Speter	}
133010015Speter
133110015Speter	switch (cmd) {
133210015Speter	case TCSIDEBUG:
133310015Speter#ifdef	SI_DEBUG
133410015Speter		SUCHECK;
133510015Speter		if (xpp->sp_debug)
133610015Speter			xpp->sp_debug = 0;
133710015Speter		else {
133810015Speter			xpp->sp_debug = DBG_ALL;
133910015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
134010015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
134110015Speter		}
134210015Speter		break;
134310015Speter#else
134410015Speter		error = ENODEV;
134510015Speter		goto out;
134610015Speter#endif
134710015Speter	case TCSISDBG_LEVEL:
134810015Speter	case TCSIGDBG_LEVEL:
134910015Speter#ifdef	SI_DEBUG
135010015Speter		if (cmd == TCSIGDBG_LEVEL) {
135110015Speter			dp->tc_dbglvl = xpp->sp_debug;
135210015Speter		} else {
135310015Speter			SUCHECK;
135410015Speter			xpp->sp_debug = dp->tc_dbglvl;
135510015Speter		}
135610015Speter		break;
135710015Speter#else
135810015Speter		error = ENODEV;
135910015Speter		goto out;
136010015Speter#endif
136110015Speter	case TCSIGRXIT:
136210015Speter		dp->tc_int = regp->rx_int_count;
136310015Speter		break;
136410015Speter	case TCSIRXIT:
136510015Speter		SUCHECK;
136610015Speter		regp->rx_int_count = dp->tc_int;
136710015Speter		break;
136810015Speter	case TCSIGIT:
136910015Speter		dp->tc_int = regp->int_count;
137010015Speter		break;
137110015Speter	case TCSIIT:
137210015Speter		SUCHECK;
137310015Speter		regp->int_count = dp->tc_int;
137410015Speter		break;
137510044Speter	case TCSISTATE:
137610044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
137710015Speter		break;
137810044Speter	/* these next three use a different structure */
137910044Speter	case TCSI_PORT:
138010015Speter		SUCHECK;
138110044Speter		sps->tc_siport = *xpp;
138210015Speter		break;
138310044Speter	case TCSI_CCB:
138410044Speter		SUCHECK;
138510044Speter		sps->tc_ccb = *xpp->sp_ccb;
138610015Speter		break;
138710044Speter	case TCSI_TTY:
138810044Speter		SUCHECK;
138910044Speter		sps->tc_tty = *xpp->sp_tty;
139010015Speter		break;
139110015Speter	default:
139210015Speter		error = EINVAL;
139310015Speter		goto out;
139410015Speter	}
139510015Speterout:
139610015Speter	splx(oldspl);
139710015Speter	return(error);		/* success */
139810015Speter}
139910015Speter
140010015Speter/*
140110015Speter *	siparam()	: Configure line params
140210015Speter *	called at spltty();
140310015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
140410015Speter *	caller must arrange this if it's important..
140510015Speter */
140612724Sphkstatic int
140710015Spetersiparam(tp, t)
140810015Speter	register struct tty *tp;
140910015Speter	register struct termios *t;
141010015Speter{
141110015Speter	register struct si_port *pp = TP2PP(tp);
141210015Speter	volatile struct si_channel *ccbp;
141310015Speter	int oldspl, cflag, iflag, oflag, lflag;
141410015Speter	int error = 0;		/* shutup gcc */
141510015Speter	int ispeed = 0;		/* shutup gcc */
141610015Speter	int ospeed = 0;		/* shutup gcc */
141710161Speter	BYTE val;
141810015Speter
141910015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
142010015Speter	cflag = t->c_cflag;
142110015Speter	iflag = t->c_iflag;
142210015Speter	oflag = t->c_oflag;
142310015Speter	lflag = t->c_lflag;
142410044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
142510044Speter		oflag, cflag, iflag, lflag));
142610015Speter
142710015Speter
142810015Speter	/* if not hung up.. */
142910015Speter	if (t->c_ospeed != 0) {
143010015Speter		/* translate baud rate to firmware values */
143110015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
143210015Speter		ispeed = t->c_ispeed ?
143310015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
143410015Speter
143510015Speter		/* enforce legit baud rate */
143610015Speter		if (ospeed < 0 || ispeed < 0)
143710015Speter			return (EINVAL);
143810015Speter	}
143910015Speter
144010015Speter
144110015Speter	oldspl = spltty();
144210015Speter
144310015Speter	ccbp = pp->sp_ccb;
144410015Speter
144510161Speter	/* ========== set hi_break ========== */
144610161Speter	val = 0;
144710161Speter	if (iflag & IGNBRK)		/* Breaks */
144810161Speter		val |= BR_IGN;
144910161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
145010161Speter		val |= BR_INT;
145110161Speter	if (iflag & PARMRK)		/* Parity mark? */
145210161Speter		val |= BR_PARMRK;
145310161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
145410161Speter		val |= BR_PARIGN;
145510161Speter	ccbp->hi_break = val;
145610161Speter
145710161Speter	/* ========== set hi_csr ========== */
145810015Speter	/* if not hung up.. */
145910015Speter	if (t->c_ospeed != 0) {
146010015Speter		/* Set I/O speeds */
146110161Speter		 val = (ispeed << 4) | ospeed;
146210015Speter	}
146310161Speter	ccbp->hi_csr = val;
146410015Speter
146510161Speter	/* ========== set hi_mr2 ========== */
146610161Speter	val = 0;
146710015Speter	if (cflag & CSTOPB)				/* Stop bits */
146810161Speter		val |= MR2_2_STOP;
146910015Speter	else
147010161Speter		val |= MR2_1_STOP;
147110161Speter	/*
147210161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
147310161Speter	 * a DCE, hence the reverse sense of RTS and CTS
147410161Speter	 */
147510161Speter	/* Output Flow - RTS must be raised before data can be sent */
147610161Speter	if (cflag & CCTS_OFLOW)
147710161Speter		val |= MR2_RTSCONT;
147810161Speter
147910161Speter	ccbp->hi_mr1 = val;
148010161Speter
148110161Speter	/* ========== set hi_mr1 ========== */
148210161Speter	val = 0;
148310015Speter	if (!(cflag & PARENB))				/* Parity */
148410161Speter		val |= MR1_NONE;
148510015Speter	else
148610161Speter		val |= MR1_WITH;
148710015Speter	if (cflag & PARODD)
148810161Speter		val |= MR1_ODD;
148910015Speter
149010015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
149110161Speter		val |= MR1_8_BITS;
149210015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
149310161Speter		val |= MR1_7_BITS;
149410015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
149510161Speter		val |= MR1_6_BITS;
149610015Speter	} else {					/* Must be 5 */
149710161Speter		val |= MR1_5_BITS;
149810015Speter	}
149910161Speter	/*
150010161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
150110161Speter	 * a DCE, hence the reverse sense of RTS and CTS
150210161Speter	 */
150310161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
150410161Speter	if (cflag & CRTS_IFLOW)
150510161Speter		val |= MR1_CTSCONT;
150610015Speter
150710161Speter	ccbp->hi_mr1 = val;
150810161Speter
150910161Speter	/* ========== set hi_mask ========== */
151010161Speter	val = 0xff;
151110161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
151210161Speter		val &= 0xFF;
151310161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
151410161Speter		val &= 0x7F;
151510161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
151610161Speter		val &= 0x3F;
151710161Speter	} else {					/* Must be 5 */
151810161Speter		val &= 0x1F;
151910161Speter	}
152010015Speter	if (iflag & ISTRIP)
152110161Speter		val &= 0x7F;
152210015Speter
152310161Speter	ccbp->hi_mask = val;
152410161Speter
152510161Speter	/* ========== set hi_prtcl ========== */
152610161Speter	val = 0;
152710015Speter				/* Monitor DCD etc. if a modem */
152810015Speter	if (!(cflag & CLOCAL))
152910161Speter		val |= SP_DCEN;
153010161Speter	if (iflag & IXANY)
153110161Speter		val |= SP_TANY;
153210161Speter	if (iflag & IXON)
153310161Speter		val |= SP_TXEN;
153410161Speter	if (iflag & IXOFF)
153510161Speter		val |= SP_RXEN;
153610161Speter	if (iflag & INPCK)
153710161Speter		val |= SP_PAEN;
153810015Speter
153910161Speter	ccbp->hi_prtcl = val;
154010161Speter
154110161Speter
154210161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
154310161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
154410015Speter	ccbp->hi_txon = t->c_cc[VSTART];
154510015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
154610015Speter
154710015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
154810015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
154910015Speter
155010161Speter	/* ========== send settings to the card ========== */
155110015Speter	/* potential sleep here */
155210015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
155310015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
155410015Speter	else
155510015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
155610015Speter
155710161Speter	/* ========== set DTR etc ========== */
155810015Speter	/* Hangup if ospeed == 0 */
155910015Speter	if (t->c_ospeed == 0) {
156010015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
156110015Speter	} else {
156210015Speter		/*
156310015Speter		 * If the previous speed was 0, may need to re-enable
156410015Speter	 	 * the modem signals
156510015Speter	 	 */
156610015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
156710015Speter	}
156810015Speter
156910044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
157010044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
157110015Speter
157210015Speter	splx(oldspl);
157310015Speter	return(error);
157410015Speter}
157510015Speter
157610015Speter/*
157710015Speter * Enable or Disable the writes to this channel...
157810015Speter * "state" ->  enabled = 1; disabled = 0;
157910015Speter */
158010015Speterstatic void
158110015Spetersi_write_enable(pp, state)
158210015Speter	register struct si_port *pp;
158310015Speter	int state;
158410015Speter{
158510015Speter	int oldspl;
158610015Speter
158710015Speter	oldspl = spltty();
158810015Speter
158910015Speter	if (state) {
159010015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
159110015Speter		if (pp->sp_state & SS_WAITWRITE) {
159210015Speter			pp->sp_state &= ~SS_WAITWRITE;
159310015Speter			/* thunder away! */
159410015Speter			wakeup((caddr_t)pp);
159510015Speter		}
159610015Speter	} else {
159710015Speter		pp->sp_state |= SS_BLOCKWRITE;
159810015Speter	}
159910015Speter
160010015Speter	splx(oldspl);
160110015Speter}
160210015Speter
160310015Speter/*
160410015Speter * Set/Get state of modem control lines.
160510015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
160610015Speter *	TIOCM_DTR	DSR
160710015Speter *	TIOCM_RTS	CTS
160810015Speter */
160910015Speterstatic int
161010015Spetersi_modem(pp, cmd, bits)
161110015Speter	struct si_port *pp;
161210015Speter	enum si_mctl cmd;
161310015Speter	int bits;
161410015Speter{
161510015Speter	volatile struct si_channel *ccbp;
161610015Speter	int x;
161710015Speter
161810015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
161910015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
162010015Speter	switch (cmd) {
162110015Speter	case GET:
162210015Speter		x = ccbp->hi_ip;
162310015Speter		bits = TIOCM_LE;
162410015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
162510015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
162610015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
162710015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
162810015Speter		return(bits);
162910015Speter	case SET:
163010015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
163110015Speter		/* fall through */
163210015Speter	case BIS:
163310015Speter		x = 0;
163410015Speter		if (bits & TIOCM_DTR)
163510015Speter			x |= OP_DSR;
163610015Speter		if (bits & TIOCM_RTS)
163710015Speter			x |= OP_CTS;
163810015Speter		ccbp->hi_op |= x;
163910015Speter		break;
164010015Speter	case BIC:
164110015Speter		if (bits & TIOCM_DTR)
164210015Speter			ccbp->hi_op &= ~OP_DSR;
164310015Speter		if (bits & TIOCM_RTS)
164410015Speter			ccbp->hi_op &= ~OP_CTS;
164510015Speter	}
164610015Speter	return 0;
164710015Speter}
164810015Speter
164910015Speter/*
165010015Speter * Handle change of modem state
165110015Speter */
165210015Speterstatic void
165310015Spetersi_modem_state(pp, tp, hi_ip)
165410015Speter	register struct si_port *pp;
165510015Speter	register struct tty *tp;
165610015Speter	register int hi_ip;
165710015Speter{
165810015Speter							/* if a modem dev */
165910015Speter	if (hi_ip & IP_DCD) {
166010015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
166110015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
166210015Speter				tp->t_line));
166310015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
166410015Speter		}
166510015Speter	} else {
166610015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
166710015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
166810015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
166910015Speter				(void) si_modem(pp, SET, 0);
167010015Speter		}
167110015Speter	}
167210015Speter	pp->sp_last_hi_ip = hi_ip;
167310015Speter
167410015Speter}
167510015Speter
167610015Speter/*
167710015Speter * Poller to catch missed interrupts.
167812174Speter *
167912496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get
168012496Speter * better response.  We could really use a "periodic" version timeout(). :-)
168110015Speter */
168210015Speter#ifdef POLL
168310708Speterstatic void
168410015Spetersi_poll(void *nothing)
168510015Speter{
168610015Speter	register struct si_softc *sc;
168710015Speter	register int i;
168810015Speter	volatile struct si_reg *regp;
168912174Speter	register struct si_port *pp;
169012174Speter	int lost, oldspl, port;
169110015Speter
169210015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
169311609Speter	oldspl = spltty();
169410015Speter	if (in_intr)
169510015Speter		goto out;
169610015Speter	lost = 0;
169710015Speter	for (i=0; i<NSI; i++) {
169810015Speter		sc = &si_softc[i];
169912174Speter		if (sc->sc_type == SIEMPTY)
170010015Speter			continue;
170110015Speter		regp = (struct si_reg *)sc->sc_maddr;
170210015Speter		/*
170310015Speter		 * See if there has been a pending interrupt for 2 seconds
170410015Speter		 * or so. The test <int_scounter >= 200) won't correspond
170510015Speter		 * to 2 seconds if int_count gets changed.
170610015Speter		 */
170710015Speter		if (regp->int_pending != 0) {
170810015Speter			if (regp->int_scounter >= 200 &&
170910015Speter			    regp->initstat == 1) {
171012174Speter				printf("si%d: lost intr\n", i);
171110015Speter				lost++;
171210015Speter			}
171310015Speter		} else {
171410015Speter			regp->int_scounter = 0;
171510015Speter		}
171610015Speter
171712174Speter		/*
171812174Speter		 * gripe about no input flow control..
171912174Speter		 */
172012174Speter		pp = sc->sc_ports;
172112174Speter		for (port = 0; port < sc->sc_nport; pp++, port++) {
172212174Speter			if (pp->sp_delta_overflows > 0) {
172312174Speter				printf("si%d: %d tty level buffer overflows\n",
172412174Speter					i, pp->sp_delta_overflows);
172512174Speter				pp->sp_delta_overflows = 0;
172612174Speter			}
172712174Speter		}
172810015Speter	}
172910015Speter	if (lost)
173010015Speter		siintr(-1);	/* call intr with fake vector */
173111609Speterout:
173210015Speter	splx(oldspl);
173310015Speter
173410015Speter	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
173510015Speter}
173610015Speter#endif	/* ifdef POLL */
173710015Speter
173810015Speter/*
173910015Speter * The interrupt handler polls ALL ports on ALL adapters each time
174010015Speter * it is called.
174110015Speter */
174210015Speter
174312496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
174410015Speter
174510708Spetervoid
174611609Spetersiintr(int unit)
174710015Speter{
174810015Speter	register struct si_softc *sc;
174910015Speter
175010015Speter	register struct si_port *pp;
175110015Speter	volatile struct si_channel *ccbp;
175210015Speter	register struct tty *tp;
175310015Speter	volatile caddr_t maddr;
175411872Sphk	BYTE op, ip;
175512174Speter	int x, card, port, n, i, isopen;
175610015Speter	volatile BYTE *z;
175710015Speter	BYTE c;
175810015Speter
175911609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
176011609Speter	if (in_intr) {
176111609Speter		if (unit < 0)	/* should never happen */
176210708Speter			return;
176312174Speter		printf("si%d: Warning interrupt handler re-entered\n",
176411609Speter			unit);
176510708Speter		return;
176610015Speter	}
176710015Speter	in_intr = 1;
176810015Speter
176910015Speter	/*
177010015Speter	 * When we get an int we poll all the channels and do ALL pending
177110015Speter	 * work, not just the first one we find. This allows all cards to
177210015Speter	 * share the same vector.
177310015Speter	 */
177410015Speter	for (card=0; card < NSI; card++) {
177510015Speter		sc = &si_softc[card];
177612174Speter		if (sc->sc_type == SIEMPTY)
177710015Speter			continue;
177812174Speter
177912174Speter		/*
178012174Speter		 * First, clear the interrupt
178112174Speter		 */
178210015Speter		switch(sc->sc_type) {
178310015Speter		case SIHOST :
178410015Speter			maddr = sc->sc_maddr;
178510015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
178610015Speter							/* flag nothing pending */
178710015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
178810015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
178910015Speter			break;
179010015Speter		case SIHOST2:
179110015Speter			maddr = sc->sc_maddr;
179210015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
179310015Speter			*(maddr+SIPLIRQCLR) = 0x00;
179410015Speter			*(maddr+SIPLIRQCLR) = 0x10;
179510015Speter			break;
179610015Speter		case SIEISA:
179710015Speter#if NEISA > 0
179810015Speter			maddr = sc->sc_maddr;
179910015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
180010015Speter			(void)inb(sc->sc_eisa_iobase+3);
180110015Speter			break;
180210015Speter#endif	/* fall through if not EISA kernel */
180310015Speter		case SIEMPTY:
180410015Speter		default:
180510015Speter			continue;
180610015Speter		}
180710015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
180810015Speter
180912174Speter		/*
181012174Speter		 * check each port
181112174Speter		 */
181212174Speter		for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) {
181310015Speter			ccbp = pp->sp_ccb;
181410015Speter			tp = pp->sp_tty;
181510015Speter
181612174Speter
181710015Speter			/*
181810015Speter			 * See if a command has completed ?
181910015Speter			 */
182010015Speter			if (ccbp->hi_stat != pp->sp_pend) {
182110015Speter				DPRINT((pp, DBG_INTR,
182210015Speter					"siintr hi_stat = 0x%x, pend = %d\n",
182310015Speter					ccbp->hi_stat, pp->sp_pend));
182410015Speter				switch(pp->sp_pend) {
182510015Speter				case LOPEN:
182610015Speter				case MPEND:
182710015Speter				case MOPEN:
182810015Speter				case CONFIG:
182910015Speter					pp->sp_pend = ccbp->hi_stat;
183010015Speter						/* sleeping in si_command */
183110015Speter					wakeup(&pp->sp_state);
183210015Speter					break;
183310015Speter				default:
183410015Speter					pp->sp_pend = ccbp->hi_stat;
183510015Speter				}
183610015Speter	 		}
183710015Speter
183810015Speter			/*
183910015Speter			 * Continue on if it's closed
184010015Speter			 */
184110015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
184210015Speter				continue;
184310015Speter			}
184410015Speter
184510015Speter			/*
184610015Speter			 * Do modem state change if not a local device
184710015Speter			 */
184810015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
184910015Speter
185010015Speter			/*
185112174Speter			 * Check to see if there's we should 'receive'
185212174Speter			 * characters.
185312174Speter			 */
185412174Speter			if (tp->t_state & TS_CONNECTED &&
185512174Speter			    tp->t_state & TS_ISOPEN)
185612174Speter				isopen = 1;
185712174Speter			else
185812174Speter				isopen = 0;
185912174Speter
186012174Speter			/*
186110015Speter			 * Do break processing
186210015Speter			 */
186310015Speter			if (ccbp->hi_state & ST_BREAK) {
186412174Speter				if (isopen) {
186512174Speter				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
186610015Speter				}
186710015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
186810015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
186910015Speter			}
187010015Speter
187110015Speter			/*
187212174Speter			 * Do RX stuff - if not open then dump any characters.
187312174Speter			 * XXX: This is VERY messy and needs to be cleaned up.
187412174Speter			 *
187512174Speter			 * XXX: can we leave data in the host adapter buffer
187612174Speter			 * when the clists are full?  That may be dangerous
187712174Speter			 * if the user cannot get an interrupt signal through.
187810015Speter			 */
187910015Speter
188012174Speter	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
188112174Speter
188212174Speter			if (!isopen) {
188310015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
188412174Speter				goto end_rx;
188512174Speter			}
188610015Speter
188712174Speter			/*
188812174Speter			 * Process read characters if not skipped above
188912174Speter			 */
189012174Speter			c = ccbp->hi_rxipos - ccbp->hi_rxopos;
189112174Speter			if (c == 0) {
189212174Speter				goto end_rx;
189312174Speter			}
189410015Speter
189512174Speter			op = ccbp->hi_rxopos;
189612174Speter			ip = ccbp->hi_rxipos;
189712174Speter			n = c & 0xff;
189812174Speter
189912174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
190010015Speter						n, op, ip));
190110015Speter
190212174Speter			/*
190312174Speter			 * Suck characters out of host card buffer into the
190412174Speter			 * "input staging buffer" - so that we dont leave the
190512174Speter			 * host card in limbo while we're possibly echoing
190612174Speter			 * characters and possibly flushing input inside the
190712174Speter			 * ldisc l_rint() routine.
190812174Speter			 */
190912496Speter			if (n <= SI_BUFFERSIZE - op) {
191010015Speter
191112174Speter				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
191212174Speter				z = ccbp->hi_rxbuf + op;
191312174Speter				bcopy((caddr_t)z, si_rxbuf, n);
191410015Speter
191512174Speter				op += n;
191612174Speter			} else {
191712496Speter				x = SI_BUFFERSIZE - op;
191810015Speter
191912174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
192012174Speter				z = ccbp->hi_rxbuf + op;
192112174Speter				bcopy((caddr_t)z, si_rxbuf, x);
192210015Speter
192312174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
192412174Speter				z = ccbp->hi_rxbuf;
192512174Speter				bcopy((caddr_t)z, si_rxbuf+x, n-x);
192610015Speter
192712174Speter				op += n;
192812174Speter			}
192910015Speter
193012174Speter			/* clear collected characters from buffer */
193112174Speter			ccbp->hi_rxopos = op;
193212174Speter
193312174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
193410015Speter						n, op, ip));
193510015Speter
193612174Speter			/*
193712174Speter			 * at this point...
193812174Speter			 * n = number of chars placed in si_rxbuf
193912174Speter			 */
194010015Speter
194112174Speter			/*
194212174Speter			 * Avoid the grotesquely inefficient lineswitch
194312174Speter			 * routine (ttyinput) in "raw" mode. It usually
194412174Speter			 * takes about 450 instructions (that's without
194512174Speter			 * canonical processing or echo!). slinput is
194612174Speter			 * reasonably fast (usually 40 instructions
194712174Speter			 * plus call overhead).
194812174Speter			 */
194912174Speter			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
195010015Speter
195112174Speter				/* block if the driver supports it */
195212174Speter				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
195312174Speter				    && (tp->t_cflag & CRTS_IFLOW
195412174Speter					|| tp->t_iflag & IXOFF)
195512174Speter				    && !(tp->t_state & TS_TBLOCK))
195612174Speter					ttyblock(tp);
195710015Speter
195812174Speter				tk_nin += n;
195912174Speter				tk_rawcc += n;
196012174Speter				tp->t_rawcc += n;
196112174Speter
196212174Speter				pp->sp_delta_overflows +=
196312174Speter				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
196412174Speter
196512174Speter				ttwakeup(tp);
196612174Speter				if (tp->t_state & TS_TTSTOP
196712174Speter				    && (tp->t_iflag & IXANY
196812174Speter					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
196912174Speter					tp->t_state &= ~TS_TTSTOP;
197012174Speter					tp->t_lflag &= ~FLUSHO;
197112174Speter					si_start(tp);
197212174Speter				}
197312174Speter			} else {
197412174Speter				/*
197512174Speter				 * It'd be nice to not have to go through the
197612174Speter				 * function call overhead for each char here.
197712174Speter				 * It'd be nice to block input it, saving a
197812174Speter				 * loop here and the call/return overhead.
197912174Speter				 */
198012174Speter				for(x = 0; x < n; x++) {
198112174Speter					i = si_rxbuf[x];
198212174Speter					if ((*linesw[tp->t_line].l_rint)(i, tp)
198312174Speter					     == -1) {
198412174Speter						pp->sp_delta_overflows++;
198510015Speter					}
198612174Speter					/*
198712174Speter					 * doesn't seem to be much point doing
198812174Speter					 * this here.. this driver has no
198912174Speter					 * softtty processing! ??
199012174Speter					 */
199112174Speter					if (pp->sp_hotchar && i == pp->sp_hotchar) {
199212174Speter						setsofttty();
199312174Speter					}
199412174Speter				}
199512174Speter			}
199612174Speter			goto more_rx;	/* try for more until RXbuf is empty */
199710015Speter
199812174Speter	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
199910015Speter
200010015Speter			/*
200110015Speter			 * Do TX stuff
200210015Speter			 */
200310015Speter			(*linesw[tp->t_line].l_start)(tp);
200410015Speter
200510015Speter		} /* end of for (all ports on this controller) */
200610015Speter	} /* end of for (all controllers) */
200710015Speter
200811609Speter	in_intr = 0;
200911609Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
201010015Speter}
201110015Speter
201210015Speter/*
201310015Speter * Nudge the transmitter...
201412174Speter *
201512174Speter * XXX: I inherited some funny code here.  It implies the host card only
201612174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does
201712174Speter * not interrupt when it's actually hits empty.  In some cases, we have
201812174Speter * processes waiting for complete drain, and we need to simulate an interrupt
201912174Speter * about when we think the buffer is going to be empty (and retry if not).
202012174Speter * I really am not certain about this...  I *need* the hardware manuals.
202110015Speter */
202210015Speterstatic void
202310015Spetersi_start(tp)
202410015Speter	register struct tty *tp;
202510015Speter{
202610015Speter	struct si_port *pp;
202710015Speter	volatile struct si_channel *ccbp;
202810015Speter	register struct clist *qp;
202910015Speter	register char *dptr;
203010015Speter	BYTE ipos;
203110015Speter	int nchar;
203210015Speter	int oldspl, count, n, amount, buffer_full;
203310015Speter	int do_exitproc;
203410015Speter
203510015Speter	oldspl = spltty();
203610015Speter
203710015Speter	qp = &tp->t_outq;
203810015Speter	pp = TP2PP(tp);
203910015Speter
204010015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
204110015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
204210015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
204310015Speter
204410015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
204510015Speter		goto out;
204610015Speter
204710015Speter	do_exitproc = 0;
204810015Speter	buffer_full = 0;
204910015Speter	ccbp = pp->sp_ccb;
205010015Speter
205110015Speter	/*
205210015Speter	 * Handle the case where ttywait() is called on process exit
205310015Speter	 * this may be BSDI specific, I dont know...
205410015Speter	 */
205510015Speter	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
205610015Speter	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
205710015Speter		do_exitproc++;
205810015Speter	}
205910015Speter
206010015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
206110015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
206210015Speter
206310015Speter	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
206410015Speter
206510015Speter	while ((nchar = qp->c_cc) > 0) {
206610015Speter		if ((BYTE)count >= 255) {
206710015Speter			buffer_full++;
206810015Speter			break;
206910015Speter		}
207010015Speter		amount = min(nchar, (255 - (BYTE)count));
207110015Speter		ipos = (unsigned int)ccbp->hi_txipos;
207210015Speter		/* will it fit in one lump? */
207312496Speter		if ((SI_BUFFERSIZE - ipos) >= amount) {
207410015Speter			n = q_to_b(&tp->t_outq,
207510015Speter				(char *)&ccbp->hi_txbuf[ipos], amount);
207610015Speter		} else {
207710015Speter			n = q_to_b(&tp->t_outq,
207810015Speter				(char *)&ccbp->hi_txbuf[ipos],
207912496Speter				SI_BUFFERSIZE-ipos);
208012496Speter			if (n == SI_BUFFERSIZE-ipos) {
208110015Speter				n += q_to_b(&tp->t_outq,
208210015Speter					(char *)&ccbp->hi_txbuf[0],
208312496Speter					amount - (SI_BUFFERSIZE-ipos));
208410015Speter			}
208510015Speter		}
208610015Speter		ccbp->hi_txipos += n;
208710015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
208810015Speter	}
208910015Speter
209010015Speter	if (count != 0 && nchar == 0) {
209110015Speter		tp->t_state |= TS_BUSY;
209210015Speter	} else {
209310015Speter		tp->t_state &= ~TS_BUSY;
209410015Speter	}
209510015Speter
209610015Speter	/* wakeup time? */
209710015Speter	ttwwakeup(tp);
209810015Speter
209910015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
210010015Speter		(BYTE)count, nchar, tp->t_state));
210110015Speter
210210015Speter	if ((tp->t_state & TS_BUSY) || do_exitproc)
210310015Speter	{
210410015Speter		int time;
210510015Speter
210610015Speter		if (do_exitproc != 0) {
210710015Speter			time = hz / 10;
210810015Speter		} else {
210910015Speter			time = ttspeedtab(tp->t_ospeed, chartimes);
211010015Speter
211110015Speter			if (time > 0) {
211210015Speter				if (time < nchar)
211310015Speter					time = nchar / time;
211410015Speter				else
211510015Speter					time = 2;
211610015Speter			} else {
211712174Speter				printf("si%d: bad char time value!!\n",
211812174Speter					(int)SI_CARD(tp->t_dev));
211910015Speter				goto out;
212010015Speter			}
212110015Speter		}
212210015Speter
212310015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
212410015Speter			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
212510015Speter		} else {
212610015Speter			pp->sp_state |= SS_LSTART;
212710015Speter		}
212810015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
212910015Speter		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
213010015Speter	}
213110015Speter
213210015Speterout:
213310015Speter	splx(oldspl);
213410015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
213510015Speter}
213610015Speter
213710015Speter/*
213810015Speter * Note: called at splsoftclock from the timeout code
213910015Speter * This has to deal with two things...  cause wakeups while waiting for
214010015Speter * tty drains on last process exit, and call l_start at about the right
214110015Speter * time for protocols like ppp.
214210015Speter */
214310015Speterstatic void
214410015Spetersi_lstart(pp)
214510015Speter	register struct si_port *pp;
214610015Speter{
214710015Speter	register struct tty *tp;
214810015Speter	int oldspl;
214910015Speter
215010015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
215110015Speter		pp, pp->sp_state));
215210015Speter
215310015Speter	oldspl = spltty();
215410015Speter
215510015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
215610015Speter		splx(oldspl);
215710015Speter		return;
215810015Speter	}
215910015Speter	pp->sp_state &= ~SS_LSTART;
216010015Speter	pp->sp_state |= SS_INLSTART;
216110015Speter
216210015Speter	tp = pp->sp_tty;
216310015Speter
216410015Speter	/* deal with the process exit case */
216510015Speter	ttwwakeup(tp);
216610015Speter
216712174Speter	/* nudge protocols - eg: ppp */
216810015Speter	(*linesw[tp->t_line].l_start)(tp);
216910015Speter
217010015Speter	pp->sp_state &= ~SS_INLSTART;
217110015Speter	splx(oldspl);
217210015Speter}
217310015Speter
217410015Speter/*
217510015Speter * Stop output on a line. called at spltty();
217610015Speter */
217710015Spetervoid
217810015Spetersistop(tp, rw)
217910015Speter	register struct tty *tp;
218010015Speter	int rw;
218110015Speter{
218210015Speter	volatile struct si_channel *ccbp;
218310015Speter	struct si_port *pp;
218410015Speter
218510015Speter	pp = TP2PP(tp);
218610015Speter	ccbp = pp->sp_ccb;
218710015Speter
218810015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
218910015Speter
219010015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
219110015Speter	if (rw & FWRITE) {
219210015Speter		/* what level are we meant to be flushing anyway? */
219310015Speter		if (tp->t_state & TS_BUSY) {
219410015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
219510015Speter			tp->t_state &= ~TS_BUSY;
219610015Speter			ttwwakeup(tp);	/* Bruce???? */
219710015Speter		}
219810015Speter	}
219912174Speter#if 1	/* XXX: this doesn't work right yet.. */
220012174Speter	/* XXX: this may have been failing because we used to call l_rint()
220112174Speter	 * while we were looping based on these two counters. Now, we collect
220212174Speter	 * the data and then loop stuffing it into l_rint(), making this
220312174Speter	 * useless.  Should we cause this to blow away the staging buffer?
220412174Speter	 */
220510015Speter	if (rw & FREAD) {
220610015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
220710015Speter	}
220810015Speter#endif
220910015Speter}
221010015Speter
221110015Speter/*
221210015Speter * Issue a command to the Z280 host card CPU.
221310015Speter */
221410015Speter
221510015Speterstatic void
221610015Spetersi_command(pp, cmd, waitflag)
221710015Speter	struct si_port *pp;		/* port control block (local) */
221810015Speter	int cmd;
221910015Speter	int waitflag;
222010015Speter{
222110015Speter	int oldspl;
222210015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
222310015Speter	int x;
222410015Speter
222510015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
222610015Speter		pp, cmd, waitflag, ccbp->hi_stat));
222710015Speter
222810015Speter	oldspl = spltty();		/* Keep others out */
222910015Speter
223010015Speter	/* wait until it's finished what it was doing.. */
223110015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
223210015Speter			x != IDLE_CLOSE &&
223310015Speter			x != cmd) {
223410015Speter		if (in_intr) {			/* Prevent sleep in intr */
223510015Speter			DPRINT((pp, DBG_PARAM,
223610015Speter				"cmd intr collision - completing %d\trequested %d\n",
223710015Speter				x, cmd));
223810015Speter			splx(oldspl);
223910015Speter			return;
224010015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
224110015Speter				"sicmd1", 1)) {
224210015Speter			splx(oldspl);
224310015Speter			return;
224410015Speter		}
224510015Speter	}
224610015Speter	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
224710015Speter
224810015Speter	/* if there was a pending command, cause a state-change wakeup */
224910015Speter	if (pp->sp_pend != IDLE_OPEN) {
225010015Speter		switch(pp->sp_pend) {
225110015Speter		case LOPEN:
225210015Speter		case MPEND:
225310015Speter		case MOPEN:
225410015Speter		case CONFIG:
225510015Speter			wakeup(&pp->sp_state);
225610015Speter			break;
225710015Speter		default:
225810015Speter			break;
225910015Speter		}
226010015Speter	}
226110015Speter
226210015Speter	pp->sp_pend = cmd;		/* New command pending */
226310015Speter	ccbp->hi_stat = cmd;		/* Post it */
226410015Speter
226510015Speter	if (waitflag) {
226610015Speter		if (in_intr) {		/* If in interrupt handler */
226710015Speter			DPRINT((pp, DBG_PARAM,
226810015Speter				"attempt to sleep in si_intr - cmd req %d\n",
226910015Speter				cmd));
227010015Speter			splx(oldspl);
227110015Speter			return;
227210015Speter		} else while(ccbp->hi_stat != IDLE_OPEN) {
227310015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
227410015Speter			    "sicmd2", 0))
227510015Speter				break;
227610015Speter		}
227710015Speter	}
227810015Speter	splx(oldspl);
227910015Speter}
228010015Speter
228110015Speterstatic void
228210015Spetersi_disc_optim(tp, t, pp)
228310015Speter	struct tty	*tp;
228410015Speter	struct termios	*t;
228510015Speter	struct si_port	*pp;
228610015Speter{
228710015Speter	/*
228810015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
228910015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
229010015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
229110015Speter	 */
229210015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
229310015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
229410015Speter	    && (!(t->c_iflag & PARMRK)
229510015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
229610015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
229710015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
229810015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
229910015Speter	else
230010015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
230110161Speter
230210015Speter	/*
230310015Speter	 * Prepare to reduce input latency for packet
230410015Speter	 * discplines with a end of packet character.
230510015Speter	 */
230610015Speter	if (tp->t_line == SLIPDISC)
230710015Speter		pp->sp_hotchar = 0xc0;
230810015Speter	else if (tp->t_line == PPPDISC)
230910015Speter		pp->sp_hotchar = 0x7e;
231010015Speter	else
231110015Speter		pp->sp_hotchar = 0;
231210161Speter
231310161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
231410161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
231510161Speter		pp->sp_hotchar));
231610015Speter}
231710015Speter
231810015Speter
231910015Speter#ifdef	SI_DEBUG
232010015Speterstatic void
232110015Spetersi_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6)
232210015Speter	struct si_port *pp;
232310015Speter	int flags;
232410015Speter	char *str;
232510015Speter	int a1, a2, a3, a4, a5, a6;
232610015Speter{
232710015Speter	if ((pp == NULL && (si_debug&flags)) ||
232810015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
232910015Speter	    	if (pp != NULL)
233012496Speter	    		printf("%ci%d(%d): ", 's',
233112174Speter	    			(int)SI_CARD(pp->sp_tty->t_dev),
233212174Speter	    			(int)SI_PORT(pp->sp_tty->t_dev));
233310015Speter		printf(str, a1, a2, a3, a4, a5, a6);
233410015Speter	}
233510015Speter}
233610015Speter
233710015Speterstatic char *
233810015Spetersi_mctl2str(cmd)
233910015Speter	enum si_mctl cmd;
234010015Speter{
234110015Speter	switch (cmd) {
234210015Speter	case GET:	return("GET");
234310015Speter	case SET:	return("SET");
234410015Speter	case BIS:	return("BIS");
234510015Speter	case BIC:	return("BIC");
234610015Speter	}
234710015Speter	return("BAD");
234810015Speter}
234912502Sjulian
235012624Speter#endif	/* DEBUG */
235112502Sjulian
235212624Speter
235312502Sjulian
235412502Sjulianstatic si_devsw_installed = 0;
235512502Sjulian
235612517Sjulianstatic void 	si_drvinit(void *unused)
235712502Sjulian{
235812517Sjulian	dev_t dev;
235912517Sjulian
236012502Sjulian	if( ! si_devsw_installed ) {
236112675Sjulian		dev = makedev(CDEV_MAJOR, 0);
236212675Sjulian		cdevsw_add(&dev,&si_cdevsw, NULL);
236312502Sjulian		si_devsw_installed = 1;
236412517Sjulian    	}
236512502Sjulian}
236612517Sjulian
236712517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
236812517Sjulian
2369