si.c revision 16024
1169586Smarcel/*
2179854Smarcel * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
3169586Smarcel *
4169586Smarcel * Copyright (C) 1990, 1992 Specialix International,
5169586Smarcel * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
6169586Smarcel * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com>
7169586Smarcel *
8169586Smarcel * Originally derived from:	SunOS 4.x version
9169586Smarcel * Ported from BSDI version to FreeBSD by Peter Wemm.
10169586Smarcel *
11169586Smarcel * Redistribution and use in source and binary forms, with or without
12169586Smarcel * modification, are permitted provided that the following conditions
13169586Smarcel * are met:
14169586Smarcel * 1. Redistributions of source code must retain the above copyright
15169586Smarcel *    notices, this list of conditions and the following disclaimer.
16169586Smarcel * 2. Redistributions in binary form must reproduce the above copyright
17169586Smarcel *    notices, this list of conditions and the following disclaimer in the
18169586Smarcel *    documentation and/or other materials provided with the distribution.
19169586Smarcel * 3. All advertising materials mentioning features or use of this software
20169586Smarcel *    must display the following acknowledgement:
21169586Smarcel *	This product includes software developed by Andy Rutter of
22169586Smarcel *	Advanced Methods and Tools Ltd. based on original information
23169586Smarcel *	from Specialix International.
24169586Smarcel * 4. Neither the name of Advanced Methods and Tools, nor Specialix
25169586Smarcel *    International may be used to endorse or promote products derived from
26169586Smarcel *    this software without specific prior written permission.
27169586Smarcel *
28169586Smarcel * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
29169586Smarcel * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30185044Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
31208777Smarius * NO EVENT SHALL THE AUTHORS BE LIABLE.
32185044Smarcel *
33185044Smarcel *	$Id: si.c,v 1.40 1996/05/08 04:48:25 peter Exp $
34215570Sae */
35185044Smarcel
36185044Smarcel#ifndef lint
37185044Smarcelstatic char si_copyright1[] =  "@(#) (C) Specialix International, 1990,1992",
38185044Smarcel            si_copyright2[] =  "@(#) (C) Andy Rutter 1993",
39185046Smarcel            si_copyright3[] =  "@(#) (C) Peter Wemm 1995";
40185044Smarcel#endif	/* not lint */
41215672Sae
42185044Smarcel#include <sys/param.h>
43169586Smarcel#include <sys/systm.h>
44169586Smarcel#include <sys/ioctl.h>
45209388Sae#include <sys/tty.h>
46209388Sae#include <sys/ttydefaults.h>
47169586Smarcel#include <sys/proc.h>
48169586Smarcel#include <sys/conf.h>
49185044Smarcel#include <sys/file.h>
50169586Smarcel#include <sys/uio.h>
51169586Smarcel#include <sys/dkstat.h>
52169586Smarcel#include <sys/kernel.h>
53169586Smarcel#include <sys/syslog.h>
54179550Smarcel#include <sys/malloc.h>
55173313Smarcel#include <sys/sysctl.h>
56173313Smarcel#include <sys/devconf.h>
57173313Smarcel#ifdef DEVFS
58173313Smarcel#include <sys/devfsext.h>
59169586Smarcel#endif /*DEVFS*/
60173313Smarcel
61173313Smarcel#include <machine/clock.h>
62173313Smarcel
63209388Sae#include <vm/vm.h>
64209388Sae#include <vm/vm_param.h>
65215672Sae#include <vm/pmap.h>
66209388Sae
67212554Spjd#include <i386/isa/icu.h>
68212554Spjd#include <i386/isa/isa.h>
69179629Smarcel#include <i386/isa/isa_device.h>
70212554Spjd
71212554Spjd#include <i386/isa/sireg.h>
72212554Spjd#include <machine/si.h>
73212554Spjd#include <machine/stdarg.h>
74208777Smarius
75208777Smarius#include "si.h"
76208777Smarius
77208777Smarius/*
78209388Sae * This device driver is designed to interface the Specialix International
79208777Smarius * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine.
80208777Smarius *
81208777Smarius * The controller is interfaced to the host via dual port ram
82178180Smarcel * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
83208777Smarius */
84185454Smarcel
85178180Smarcel#define	POLL		/* turn on poller to generate buffer empty interrupt */
86219415Sae#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
87208777Smarius#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
88208777Smarius#define INT_COUNT 25000	/* max of 125 ints per second */
89208777Smarius#define RXINT_COUNT 1	/* one rxint per 10 milliseconds */
90213097Sae
91215570Saeenum si_mctl { GET, SET, BIS, BIC };
92215570Sae
93172837Smarcelstatic void si_command __P((struct si_port *, int, int));
94173313Smarcelstatic int si_modem __P((struct si_port *, enum si_mctl, int));
95185454Smarcelstatic void si_write_enable __P((struct si_port *, int));
96221363Saestatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
97212554Spjdstatic void si_start __P((struct tty *));
98212554Spjdstatic void si_lstart __P((struct si_port *));
99169586Smarcelstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
100212614Spjd					struct si_port *pp));
101212606Spjdstatic void sihardclose __P((struct si_port *pp));
102212554Spjdstatic void sidtrwakeup __P((void *chan));
103169586Smarcel
104222357Saestatic int	siparam __P((struct tty *, struct termios *));
105221363Sae
106169586Smarcelstatic	void	si_registerdev __P((struct isa_device *id));
107215671Saestatic	int	siprobe __P((struct isa_device *id));
108215671Saestatic	int	siattach __P((struct isa_device *id));
109215570Saestatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
110178180Smarcel
111212606Spjdstruct isa_driver sidriver =
112212606Spjd	{ siprobe, siattach, "si" };
113212614Spjd
114212554Spjd
115178180Smarcelstatic	d_open_t	siopen;
116222357Saestatic	d_close_t	siclose;
117178180Smarcelstatic	d_read_t	siread;
118212554Spjdstatic	d_write_t	siwrite;
119212554Spjdstatic	d_ioctl_t	siioctl;
120212554Spjdstatic	d_stop_t	sistop;
121185454Smarcelstatic	d_devtotty_t	sidevtotty;
122169586Smarcel
123212614Spjd#define CDEV_MAJOR 68
124212554Spjdstatic struct cdevsw si_cdevsw =
125169586Smarcel	{ siopen,	siclose,	siread,		siwrite,	/*68*/
126212554Spjd	  siioctl,	sistop,		noreset,	sidevtotty,/* si */
127169586Smarcel	  ttselect,	nommap,		NULL,	"si",	NULL,	-1 };
128185454Smarcel
129212614Spjd
130212554Spjd#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
131169586Smarcel
132212554Spjdstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
133169586Smarcel				...));
134214352Saestatic	char	*si_mctl2str __P((enum si_mctl cmd));
135214352Sae
136212554Spjd#define	DPRINT(x)	si_dprintf x
137169586Smarcel
138213097Sae#else
139212554Spjd#define	DPRINT(x)	/* void */
140185454Smarcel#endif
141212614Spjd
142212606Spjdstatic int si_Nports;
143212606Spjdstatic int si_Nmodules;
144212554Spjdstatic int si_debug = 0;	/* data, not bss, so it's patchable */
145169586Smarcel
146212554Spjdstatic struct tty *si_tty;
147169586Smarcel
148185454Smarcel/* where the firmware lives; defined in si_code.c */
149179854Smarcelextern int si_dsize;
150251588Smarcelextern unsigned char si_download[];
151212554Spjd
152179854Smarcelstruct si_softc {
153251588Smarcel	int 		sc_type;	/* adapter type */
154179854Smarcel	char 		*sc_typename;	/* adapter type string */
155179769Smarcel
156179769Smarcel	struct si_port	*sc_ports;	/* port structures for this card */
157179769Smarcel
158219415Sae	caddr_t		sc_paddr;	/* physical addr of iomem */
159179769Smarcel	caddr_t		sc_maddr;	/* kvaddr of iomem */
160222357Sae	int		sc_nport;	/* # ports on this card */
161179769Smarcel	int		sc_irq;		/* copy of attach irq */
162212554Spjd	int		sc_eisa_iobase;	/* EISA io port address */
163212554Spjd	int		sc_eisa_irqbits;
164212554Spjd	struct kern_devconf sc_kdc;
165185454Smarcel#ifdef	DEVFS
166179854Smarcel	struct {
167251588Smarcel		void	*ttyd;
168212554Spjd		void	*cuaa;
169179854Smarcel		void	*ttyl;
170251588Smarcel		void	*ttyi;
171208777Smarius	} devfs_token[32]; /* what is the max per card? */
172207095Smarcel	void	*control_token;
173221363Sae#endif
174212554Spjd};
175212614Spjdstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
176212554Spjd
177207095Smarcel#ifndef B2000	/* not standard, but the hardware knows it. */
178222357Sae# define B2000 2000
179207095Smarcel#endif
180215570Saestatic struct speedtab bdrates[] = {
181215570Sae	B75,	CLK75,		/* 0x0 */
182215671Sae	B110,	CLK110,		/* 0x1 */
183215570Sae	B150,	CLK150,		/* 0x3 */
184215570Sae	B300,	CLK300,		/* 0x4 */
185215671Sae	B600,	CLK600,		/* 0x5 */
186215570Sae	B1200,	CLK1200,	/* 0x6 */
187214352Sae	B2000,	CLK2000,	/* 0x7 */
188214352Sae	B2400,	CLK2400,	/* 0x8 */
189214352Sae	B4800,	CLK4800,	/* 0x9 */
190214352Sae	B9600,	CLK9600,	/* 0xb */
191214352Sae	B19200,	CLK19200,	/* 0xc */
192169586Smarcel	B38400, CLK38400,	/* 0x2 (out of order!) */
193169586Smarcel	B57600, CLK57600,	/* 0xd */
194172837Smarcel	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
195172837Smarcel	-1,	-1
196172837Smarcel};
197172837Smarcel
198172837Smarcel
199172837Smarcel/* populated with approx character/sec rates - translated at card
200172837Smarcel * initialisation time to chars per tick of the clock */
201172837Smarcelstatic int done_chartimes = 0;
202172837Smarcelstatic struct speedtab chartimes[] = {
203172837Smarcel	B75,	8,
204172837Smarcel	B110,	11,
205172837Smarcel	B150,	15,
206172837Smarcel	B300,	30,
207172837Smarcel	B600,	60,
208172837Smarcel	B1200,	120,
209172837Smarcel	B2000,	200,
210172837Smarcel	B2400,	240,
211172837Smarcel	B4800,	480,
212213662Sae	B9600,	960,
213213662Sae	B19200,	1920,
214172837Smarcel	B38400, 3840,
215172837Smarcel	B57600, 5760,
216172837Smarcel	B115200, 11520,
217172837Smarcel	-1,	-1
218172837Smarcel};
219172837Smarcelstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
220172837Smarcel
221172837Smarcelstatic int si_default_rate =	TTYDEF_SPEED;
222172837Smarcelstatic int si_default_iflag =	0;
223172837Smarcelstatic int si_default_oflag =	0;
224172837Smarcelstatic int si_default_lflag =	0;
225172837Smarcel#ifdef SI_DEF_HWFLOW
226172837Smarcelstatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
227172837Smarcel#else
228172837Smarcelstatic int si_default_cflag =	TTYDEF_CFLAG;
229172837Smarcel#endif
230172837Smarcel
231172837Smarcel#ifdef POLL
232172837Smarcelstatic int si_pollrate;			/* in addition to irq */
233172837Smarcel
234172837SmarcelSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RD, &si_pollrate, 0, "");
235172837Smarcel
236172837Smarcelstatic int init_finished = 0;
237172837Smarcelstatic int fastpoll = 0;
238172837Smarcelstatic void si_poll __P((void *));
239172837Smarcel#endif
240172837Smarcel
241172837Smarcel/*
242172837Smarcel * Array of adapter types and the corresponding RAM size. The order of
243172837Smarcel * entries here MUST match the ordinal of the adapter type.
244172837Smarcel */
245172837Smarcelstatic char *si_type[] = {
246209388Sae	"EMPTY",
247172837Smarcel	"SIHOST",
248172837Smarcel	"SI2",				/* MCA */
249188330Smarcel	"SIHOST2",
250209388Sae	"SIEISA",
251172837Smarcel};
252172837Smarcel
253198478Slulf
254172837Smarcelstatic struct kern_devconf si_kdc[NSI] = { {
255188330Smarcel	0, 0, 0,		/* filled in by dev_attach */
256221952Sae	"si", 0, { MDDT_ISA, 0, "tty" },
257172837Smarcel	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
258172837Smarcel	&kdc_isa0,		/* parent */
259172837Smarcel	0,			/* parent data */
260172837Smarcel	DC_UNCONFIGURED,	/* state */
261188330Smarcel	"Specialix SI/XIO Host adapter",
262172837Smarcel	DC_CLS_SERIAL,		/* class */
263172837Smarcel} };
264172837Smarcel
265172837Smarcelstatic void
266172837Smarcelsi_registerdev(id)
267172837Smarcel	struct isa_device *id;
268172837Smarcel{
269185046Smarcel	if (id->id_unit != 0) {
270172837Smarcel		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
271185046Smarcel	}
272172837Smarcel	si_kdc[id->id_unit].kdc_unit = id->id_unit;
273185046Smarcel	si_kdc[id->id_unit].kdc_isa = id;
274185046Smarcel	si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED;
275172837Smarcel	dev_attach(&si_kdc[id->id_unit]);
276172837Smarcel}
277172837Smarcel
278179854Smarcel/* Look for a valid board at the given mem addr */
279179854Smarcelstatic int
280179854Smarcelsiprobe(id)
281184070Smarcel	struct isa_device *id;
282184070Smarcel{
283184070Smarcel	struct si_softc *sc;
284179854Smarcel	int type;
285184070Smarcel	u_int i, ramsize;
286184070Smarcel	volatile BYTE was, *ux;
287184070Smarcel	volatile unsigned char *maddr;
288184070Smarcel	unsigned char *paddr;
289184070Smarcel
290184070Smarcel	si_registerdev(id);
291184070Smarcel
292184070Smarcel	si_pollrate = (hz / 10);	/* 10 per second */
293184070Smarcel
294184070Smarcel	maddr = id->id_maddr;		/* virtual address... */
295179854Smarcel	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
296179854Smarcel
297179854Smarcel	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
298222264Sae		id->id_unit, id->id_maddr, paddr));
299222263Sae
300221363Sae	/*
301193673Smarcel	 * this is a lie, but it's easier than trying to handle caching
302207095Smarcel	 * and ram conflicts in the >1M and <16M region.
303207095Smarcel	 */
304207095Smarcel	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
305207095Smarcel	    (caddr_t)paddr >= (caddr_t)IOM_END) {
306207095Smarcel		printf("si%d: iomem (%lx) out of range\n",
307207095Smarcel			id->id_unit, (long)paddr);
308209388Sae		return(0);
309222630Sae	}
310207095Smarcel
311225445Sae	if (id->id_unit >= NSI) {
312207095Smarcel		/* THIS IS IMPOSSIBLE */
313212708Spjd		return(0);
314212708Spjd	}
315207095Smarcel
316207095Smarcel	if (((u_int)paddr & 0x7fff) != 0) {
317207095Smarcel		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
318207095Smarcel			"si%d: iomem (%x) not on 32k boundary\n",
319207095Smarcel			id->id_unit, paddr));
320207095Smarcel		return(0);
321207095Smarcel	}
322207095Smarcel
323207095Smarcel
324207095Smarcel	for (i=0; i < NSI; i++) {
325207095Smarcel		if ((sc = &si_softc[i]) == NULL)
326212613Spjd			continue;
327207095Smarcel		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
328207095Smarcel			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
329207095Smarcel				"si%d: iomem (%x) already configured to si%d\n",
330207095Smarcel				id->id_unit, sc->sc_paddr, i));
331207095Smarcel			return(0);
332209388Sae		}
333209388Sae	}
334209388Sae
335207095Smarcel#if NEISA > 0
336221363Sae	if (id->id_iobase > 0x0fff) {	/* EISA card */
337225445Sae		int irq, port;
338221363Sae		unsigned long base;
339225445Sae		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
340221363Sae			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
341221363Sae
342221363Sae		port = id->id_iobase;
343221363Sae		base = (inb(port+1) << 24) | (inb(port) << 16);
344221363Sae		irq  = ((inb(port+2) >> 4) & 0xf);
345222819Sae
346222630Sae		id->id_irq = eisa_irqs[irq];
347222631Sae
348222819Sae		DPRINT((0, DBG_AUTOBOOT,
349221363Sae		    "si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
350221363Sae		    id->id_unit, base, irq, id->id_irq, port));
351221363Sae
352221363Sae		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
353221363Sae			goto bad_irq;
354209388Sae
355209388Sae		id->id_iobase &= 0xf000;
356209388Sae		id->id_iosize  = 0x0fff;
357209388Sae
358209388Sae		type = EISA;
359209388Sae		outb(p+2, (BYTE)irq << 4);
360209388Sae
361209388Sae		sc->sc_eisa_iobase = p;
362225445Sae		sc->sc_eisa_irqbits = irq << 4;
363221363Sae		ramsize = SIEISA_RAMSIZE;
364209388Sae		goto got_card;
365209388Sae	}
366223356Sdelphij#endif
367209388Sae
368207095Smarcel	/* Is there anything out there? (0x17 is just an arbitrary number) */
369207095Smarcel	*maddr = 0x17;
370207095Smarcel	if (*maddr != 0x17) {
371207095Smarcel		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
372207095Smarcel			"si%d: 0x17 check fail at phys 0x%x\n",
373207095Smarcel			id->id_unit, paddr));
374207095Smarcelfail:
375207095Smarcel		return(0);
376207095Smarcel	}
377207095Smarcel	/*
378207095Smarcel	 * OK, now to see if whatever responded is really an SI card.
379221952Sae	 * Try for a MK II first (SIHOST2)
380207095Smarcel	 */
381222630Sae	for (i=SIPLSIG; i<SIPLSIG+8; i++)
382222630Sae		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
383207095Smarcel			goto try_mk1;
384225445Sae
385225445Sae	/* It must be an SIHOST2 */
386222630Sae	*(maddr + SIPLRESET) = 0;
387222630Sae	*(maddr + SIPLIRQCLR) = 0;
388222630Sae	*(maddr + SIPLIRQSET) = 0x10;
389222630Sae	type = SIHOST2;
390222630Sae	ramsize = SIHOST2_RAMSIZE;
391222630Sae	goto got_card;
392209388Sae
393222630Sae	/*
394222630Sae	 * Its not a MK II, so try for a MK I (SIHOST)
395222630Sae	 */
396222630Saetry_mk1:
397222630Sae	*(maddr+SIRESET) = 0x0;		/* reset the card */
398222630Sae	*(maddr+SIINTCL) = 0x0;		/* clear int */
399207095Smarcel	*(maddr+SIRAM) = 0x17;
400221952Sae	if (*(maddr+SIRAM) != (BYTE)0x17)
401209388Sae		goto fail;
402209388Sae	*(maddr+0x7ff8) = 0x17;
403207095Smarcel	if (*(maddr+0x7ff8) != (BYTE)0x17) {
404207095Smarcel		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
405222630Sae			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
406207095Smarcel			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
407207095Smarcel		goto fail;
408209388Sae	}
409209388Sae
410207095Smarcel	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
411209388Sae	type = SIHOST;
412207095Smarcel	ramsize = SIHOST_RAMSIZE;
413209388Sae
414209388Saegot_card:
415209388Sae	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
416209388Sae		id->id_unit, type));
417207095Smarcel	/* Try the acid test */
418207095Smarcel	ux = (BYTE *)(maddr + SIRAM);
419207095Smarcel	for (i=0; i<ramsize; i++, ux++)
420207095Smarcel		*ux = (BYTE)(i&0xff);
421193673Smarcel	ux = (BYTE *)(maddr + SIRAM);
422193673Smarcel	for (i=0; i<ramsize; i++, ux++) {
423193673Smarcel		if ((was = *ux) != (BYTE)(i&0xff)) {
424193673Smarcel			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
425193673Smarcel				"si%d: match fail at phys 0x%x, was %x should be %x\n",
426193673Smarcel				id->id_unit, paddr+i, was, i&0xff));
427221363Sae			goto fail;
428221363Sae		}
429221967Sae	}
430209388Sae
431193673Smarcel	/* clear out the RAM */
432221363Sae	ux = (BYTE *)(maddr + SIRAM);
433193673Smarcel	for (i=0; i<ramsize; i++)
434193673Smarcel		*ux++ = 0;
435207095Smarcel	ux = (BYTE *)(maddr + SIRAM);
436207095Smarcel	for (i=0; i<ramsize; i++) {
437193673Smarcel		if ((was = *ux++) != 0) {
438193673Smarcel			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
439193673Smarcel				"si%d: clear fail at phys 0x%x, was %x\n",
440193673Smarcel				id->id_unit, paddr+i, was));
441193673Smarcel			goto fail;
442193673Smarcel		}
443196278Smarcel	}
444196278Smarcel
445196278Smarcel	/*
446196278Smarcel	 * Success, we've found a valid board, now fill in
447196278Smarcel	 * the adapter structure.
448196278Smarcel	 */
449212613Spjd	switch (type) {
450196278Smarcel	case SIHOST2:
451196278Smarcel		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
452196278Smarcelbad_irq:
453196278Smarcel			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
454196278Smarcel				"si%d: bad IRQ value - %d\n",
455209388Sae				id->id_unit, id->id_irq));
456209388Sae			return(0);
457209388Sae		}
458209388Sae		id->id_msize = SIHOST2_MEMSIZE;
459221363Sae		break;
460221363Sae	case SIHOST:
461221363Sae		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
462221363Sae			goto bad_irq;
463221363Sae		}
464221363Sae		id->id_msize = SIHOST_MEMSIZE;
465221363Sae		break;
466221363Sae	case SIEISA:
467221363Sae		id->id_msize = SIEISA_MEMSIZE;
468221363Sae		break;
469221363Sae	case SI2:		/* MCA */
470221363Sae	default:
471221363Sae		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
472221363Sae		return(0);
473209388Sae	}
474209388Sae	si_softc[id->id_unit].sc_type = type;
475209388Sae	si_softc[id->id_unit].sc_typename = si_type[type];
476209388Sae	return(-1);	/* -1 == found */
477209388Sae}
478209388Sae
479209388Sae/*
480209388Sae * Attach the device.  Initialize the card.
481209388Sae */
482209388Saestatic int
483209388Saesiattach(id)
484209388Sae	struct isa_device *id;
485209388Sae{
486209388Sae	int unit = id->id_unit;
487209388Sae	struct si_softc *sc = &si_softc[unit];
488209388Sae	struct si_port *pp;
489209388Sae	volatile struct si_channel *ccbp;
490209388Sae	volatile struct si_reg *regp;
491209388Sae	volatile caddr_t maddr;
492221363Sae	struct si_module *modp;
493209388Sae	struct tty *tp;
494209388Sae	struct speedtab *spt;
495222630Sae	int nmodule, nport, x, y;
496222819Sae	int uart_type;
497222819Sae#ifdef DEVFS
498222630Sae	char	name[32];
499222630Sae#endif
500223356Sdelphij
501221967Sae	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
502223355Sae
503223355Sae	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
504221967Sae	sc->sc_maddr = id->id_maddr;
505209388Sae	sc->sc_irq = id->id_irq;
506209388Sae
507193673Smarcel	sc->sc_ports = NULL;			/* mark as uninitialised */
508221967Sae
509221967Sae	maddr = sc->sc_maddr;
510235033Sae
511235033Sae	/*
512193673Smarcel	 * OK, now lets download the firmware and try and boot the CPU..
513193673Smarcel	 */
514221952Sae
515221967Sae	DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
516221363Sae		id->id_unit, si_dsize));
517193673Smarcel	bcopy(si_download, maddr, si_dsize);
518221363Sae
519193673Smarcel	switch (sc->sc_type) {
520209388Sae	case SIEISA:
521209388Sae#if NEISA > 0
522221363Sae		/* modify the Z280 firmware to tell it that it's on an EISA */
523193673Smarcel		*(maddr+0x42) = 1;
524193673Smarcel		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
525193673Smarcel		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
526221363Sae		break;
527221363Sae#endif	/* fall-through if not EISA */
528221363Sae	case SI2:
529193673Smarcel		/*
530193673Smarcel		 * must get around to converting the code for
531193673Smarcel		 * these one day, if FreeBSD ever supports it.
532221363Sae		 */
533193673Smarcel		return 0;
534193673Smarcel	case SIHOST:
535193673Smarcel		*(maddr+SIRESET_CL) = 0;
536193673Smarcel		*(maddr+SIINTCL_CL) = 0;
537193673Smarcel		break;
538193673Smarcel	case SIHOST2:
539193673Smarcel		*(maddr+SIPLRESET) = 0x10;
540221952Sae		switch (sc->sc_irq) {
541235033Sae		case IRQ11:
542235033Sae			*(maddr+SIPLIRQ11) = 0x10;
543193673Smarcel			break;
544221363Sae		case IRQ12:
545193673Smarcel			*(maddr+SIPLIRQ12) = 0x10;
546221363Sae			break;
547193673Smarcel		case IRQ15:
548209388Sae			*(maddr+SIPLIRQ15) = 0x10;
549209388Sae			break;
550221363Sae		}
551193673Smarcel		*(maddr+SIPLIRQCLR) = 0x10;
552193673Smarcel		break;
553193673Smarcel	}
554221363Sae
555221363Sae	DELAY(1000000);			/* wait around for a second */
556221363Sae
557193673Smarcel	regp = (struct si_reg *)maddr;
558193673Smarcel	y = 0;
559193673Smarcel					/* wait max of 5 sec for init OK */
560221363Sae	while (regp->initstat == 0 && y++ < 10) {
561193673Smarcel		DELAY(500000);
562193673Smarcel	}
563193673Smarcel	switch (regp->initstat) {
564193673Smarcel	case 0:
565193673Smarcel		printf("si%d: startup timeout - aborting\n", unit);
566209388Sae		sc->sc_type = SIEMPTY;
567209388Sae		return 0;
568193673Smarcel	case 1:
569209388Sae			/* set throttle to 125 intr per second */
570221967Sae		regp->int_count = INT_COUNT;
571209388Sae			/* rx intr max of 25 timer per second */
572209388Sae		regp->rx_int_count = RXINT_COUNT;
573209388Sae		regp->int_pending = 0;		/* no intr pending */
574209388Sae		regp->int_scounter = 0;	/* reset counter */
575209388Sae		break;
576209388Sae	case 0xff:
577193673Smarcel		/*
578193673Smarcel		 * No modules found, so give up on this one.
579193673Smarcel		 */
580172837Smarcel		printf("si%d: %s - no ports found\n", unit,
581219415Sae			si_type[sc->sc_type]);
582172837Smarcel		return 0;
583172837Smarcel	default:
584172837Smarcel		printf("si%d: Z280 version error - initstat %x\n",
585209388Sae			unit, regp->initstat);
586209388Sae		return 0;
587219415Sae	}
588172837Smarcel
589172837Smarcel	/*
590172837Smarcel	 * First time around the ports just count them in order
591209388Sae	 * to allocate some memory.
592172837Smarcel	 */
593209388Sae	nport = 0;
594172837Smarcel	modp = (struct si_module *)(maddr + 0x80);
595214352Sae	for (;;) {
596214352Sae		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
597214352Sae		switch (modp->sm_type & (~MMASK)) {
598219415Sae		case M232:
599219415Sae		case M422:
600219415Sae			DPRINT((0, DBG_DOWNLOAD,
601219415Sae				"si%d: Found 232/422 module, %d ports\n",
602219415Sae				unit, (int)(modp->sm_type & MMASK)));
603219415Sae
604219415Sae			/* this is a firmware issue */
605219415Sae			if (si_Nports == SI_MAXPORTPERCARD) {
606219415Sae				printf("si%d: extra ports ignored\n", unit);
607172837Smarcel				continue;
608172837Smarcel			}
609214352Sae
610209388Sae			x = modp->sm_type & MMASK;
611172837Smarcel			nport += x;
612214352Sae			si_Nports += x;
613214352Sae			si_Nmodules++;
614172837Smarcel			break;
615172837Smarcel		default:
616188330Smarcel			printf("si%d: unknown module type %d\n",
617221952Sae				unit, modp->sm_type);
618188330Smarcel			break;
619188330Smarcel		}
620221952Sae		if (modp->sm_next == 0)
621221952Sae			break;
622221952Sae		modp = (struct si_module *)
623172837Smarcel			(maddr + (unsigned)(modp->sm_next & 0x7fff));
624172837Smarcel	}
625172837Smarcel	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
626209388Sae		M_DEVBUF, M_NOWAIT);
627209388Sae	if (sc->sc_ports == 0) {
628209388Saemem_fail:
629172837Smarcel		printf("si%d: fail to malloc memory for port structs\n",
630172837Smarcel			unit);
631219415Sae		return 0;
632219415Sae	}
633219415Sae	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
634219415Sae	sc->sc_nport = nport;
635219415Sae
636219415Sae	/*
637219415Sae	 * allocate tty structures for ports
638219415Sae	 */
639219415Sae	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
640219415Sae	if (tp == 0)
641219415Sae		goto mem_fail;
642219415Sae	bzero(tp, sizeof(*tp) * nport);
643188330Smarcel	si_tty = tp;
644172837Smarcel
645172837Smarcel	/* mark the device state as attached */
646188330Smarcel	si_kdc[unit].kdc_state = DC_BUSY;
647209388Sae
648209388Sae	/*
649172837Smarcel	 * Scan round the ports again, this time initialising.
650188330Smarcel	 */
651172837Smarcel	pp = sc->sc_ports;
652172837Smarcel	nmodule = 0;
653172837Smarcel	modp = (struct si_module *)(maddr + 0x80);
654172837Smarcel	uart_type = 0;
655179769Smarcel	for (;;) {
656179769Smarcel		switch (modp->sm_type & (~MMASK)) {
657179769Smarcel		case M232:
658179769Smarcel		case M422:
659215704Sbrucec			nmodule++;
660179769Smarcel			nport = (modp->sm_type & MMASK);
661179769Smarcel			ccbp = (struct si_channel *)((char *)modp+0x100);
662179769Smarcel			if (uart_type == 0)
663179769Smarcel				uart_type = ccbp->type;
664179769Smarcel			for (x = 0; x < nport; x++, pp++, ccbp++) {
665179769Smarcel				pp->sp_ccb = ccbp;	/* save the address */
666179769Smarcel				pp->sp_tty = tp++;
667179769Smarcel				pp->sp_pend = IDLE_CLOSE;
668172837Smarcel				pp->sp_state = 0;	/* internal flag */
669178180Smarcel				pp->sp_dtr_wait = 3 * hz;
670172837Smarcel				pp->sp_iin.c_iflag = si_default_iflag;
671172837Smarcel				pp->sp_iin.c_oflag = si_default_oflag;
672172837Smarcel				pp->sp_iin.c_cflag = si_default_cflag;
673172837Smarcel				pp->sp_iin.c_lflag = si_default_lflag;
674179769Smarcel				termioschars(&pp->sp_iin);
675219415Sae				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
676172837Smarcel					si_default_rate;
677179769Smarcel				pp->sp_iout = pp->sp_iin;
678179769Smarcel			}
679179769Smarcel			break;
680179769Smarcel		default:
681179769Smarcel			break;
682179769Smarcel		}
683179769Smarcel		if (modp->sm_next == 0) {
684179769Smarcel			printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n",
685172837Smarcel				unit,
686172837Smarcel				sc->sc_typename,
687172837Smarcel				sc->sc_nport,
688172837Smarcel				nmodule,
689172837Smarcel				uart_type);
690172837Smarcel			break;
691172837Smarcel		}
692172837Smarcel		modp = (struct si_module *)
693172837Smarcel			(maddr + (unsigned)(modp->sm_next & 0x7fff));
694172837Smarcel	}
695172837Smarcel	if (done_chartimes == 0) {
696219415Sae		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
697172837Smarcel			if ((spt->sp_code /= hz) == 0)
698172837Smarcel				spt->sp_code = 1;
699172837Smarcel		}
700172837Smarcel		done_chartimes = 1;
701172837Smarcel	}
702172837Smarcel
703219415Sae#ifdef DEVFS
704172837Smarcel/*	path	name	devsw		minor	type   uid gid perm*/
705172837Smarcel	for ( x = 0; x < sc->sc_nport; x++ ) {
706172837Smarcel		y = x + 1;	/* For sync with the manuals that start at 1 */
707172837Smarcel		sc->devfs_token[x].ttyd = devfs_add_devswf(
708172837Smarcel			&si_cdevsw, x,
709219415Sae			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
710172837Smarcel		sc->devfs_token[x].cuaa = devfs_add_devswf(
711172837Smarcel			&si_cdevsw, x + 128,
712172837Smarcel			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
713172837Smarcel		sc->devfs_token[x].ttyi = devfs_add_devswf(
714178180Smarcel			&si_cdevsw, x + 0x10000,
715215570Sae			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
716215570Sae		sc->devfs_token[x].ttyl = devfs_add_devswf(
717215570Sae			&si_cdevsw, x + 0x20000,
718215570Sae			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
719215570Sae	}
720215570Sae	sc->control_token =
721215570Sae		devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600,
722215570Sae				 "si_control");
723215570Sae#endif
724229916Seadler	return (1);
725215671Sae}
726215570Sae
727215570Saestatic	int
728215570Saesiopen(dev, flag, mode, p)
729215570Sae	dev_t dev;
730215570Sae	int flag, mode;
731215570Sae	struct proc *p;
732215570Sae{
733215570Sae	int oldspl, error;
734215570Sae	int card, port;
735215570Sae	register struct si_softc *sc;
736215570Sae	register struct tty *tp;
737215570Sae	volatile struct si_channel *ccbp;
738215570Sae	struct si_port *pp;
739215570Sae	int mynor = minor(dev);
740215570Sae
741215570Sae	/* quickly let in /dev/si_control */
742215570Sae	if (IS_CONTROLDEV(mynor)) {
743215570Sae		if (error = suser(p->p_ucred, &p->p_acflag))
744215570Sae			return(error);
745215570Sae		return(0);
746215570Sae	}
747215570Sae
748215570Sae	card = SI_CARD(mynor);
749215570Sae	if (card >= NSI)
750215570Sae		return (ENXIO);
751215570Sae	sc = &si_softc[card];
752215570Sae
753215570Sae	if (sc->sc_type == SIEMPTY) {
754215570Sae		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
755215570Sae			card, sc->sc_typename));
756215570Sae		return(ENXIO);
757215570Sae	}
758215570Sae
759215570Sae	port = SI_PORT(mynor);
760215570Sae	if (port >= sc->sc_nport) {
761215570Sae		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
762215570Sae			card, sc->sc_nport));
763215570Sae		return(ENXIO);
764221952Sae	}
765215570Sae
766215570Sae#ifdef	POLL
767221952Sae	/*
768221952Sae	 * We've now got a device, so start the poller.
769221952Sae	 */
770215570Sae	if (init_finished == 0) {
771215671Sae		timeout(si_poll, (caddr_t)0L, si_pollrate);
772215570Sae		init_finished = 1;
773215570Sae	}
774215570Sae#endif
775215671Sae
776215671Sae	/* initial/lock device */
777215570Sae	if (IS_STATE(mynor)) {
778215570Sae		return(0);
779215570Sae	}
780215570Sae
781215570Sae	pp = sc->sc_ports + port;
782215570Sae	tp = pp->sp_tty;			/* the "real" tty */
783215570Sae	ccbp = pp->sp_ccb;			/* Find control block */
784215570Sae	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
785215570Sae		dev, flag, mode, p));
786215570Sae
787215570Sae	oldspl = spltty();			/* Keep others out */
788215570Sae	error = 0;
789215570Sae
790215570Saeopen_top:
791215570Sae	while (pp->sp_state & SS_DTR_OFF) {
792215570Sae		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
793215570Sae		if (error != 0)
794215570Sae			goto out;
795215570Sae	}
796215672Sae
797215672Sae	if (tp->t_state & TS_ISOPEN) {
798215672Sae		/*
799215672Sae		 * The device is open, so everything has been initialised.
800215672Sae		 * handle conflicts.
801215672Sae		 */
802215570Sae		if (IS_CALLOUT(mynor)) {
803215570Sae			if (!pp->sp_active_out) {
804215570Sae				error = EBUSY;
805215570Sae				goto out;
806215570Sae			}
807215570Sae		} else {
808215672Sae			if (pp->sp_active_out) {
809215570Sae				if (flag & O_NONBLOCK) {
810215570Sae					error = EBUSY;
811215671Sae					goto out;
812215570Sae				}
813215570Sae				error = tsleep(&pp->sp_active_out,
814215570Sae						TTIPRI|PCATCH, "sibi", 0);
815215570Sae				if (error != 0)
816215570Sae					goto out;
817215570Sae				goto open_top;
818215570Sae			}
819215570Sae		}
820215671Sae		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
821215570Sae			DPRINT((pp, DBG_OPEN|DBG_FAIL,
822215570Sae				"already open and EXCLUSIVE set\n"));
823215570Sae			error = EBUSY;
824215570Sae			goto out;
825215570Sae		}
826215570Sae	} else {
827215570Sae		/*
828215570Sae		 * The device isn't open, so there are no conflicts.
829215570Sae		 * Initialize it. Avoid sleep... :-)
830215570Sae		 */
831215570Sae		DPRINT((pp, DBG_OPEN, "first open\n"));
832215672Sae		tp->t_oproc = si_start;
833215672Sae		tp->t_param = siparam;
834215672Sae		tp->t_dev = dev;
835215672Sae		tp->t_termios = mynor & SI_CALLOUT_MASK
836215672Sae				? pp->sp_iout : pp->sp_iin;
837215672Sae
838215672Sae		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
839215570Sae
840215570Sae		++pp->sp_wopeners;	/* in case of sleep in siparam */
841215570Sae
842215570Sae		error = siparam(tp, &tp->t_termios);
843215570Sae
844215570Sae		--pp->sp_wopeners;
845215570Sae		if (error != 0)
846215570Sae			goto out;
847215570Sae		/* XXX: we should goto_top if siparam slept */
848215570Sae
849215570Sae		ttsetwater(tp);
850215570Sae
851215570Sae		/* set initial DCD state */
852215570Sae		pp->sp_last_hi_ip = ccbp->hi_ip;
853215570Sae		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
854215570Sae			(*linesw[tp->t_line].l_modem)(tp, 1);
855215570Sae		}
856215570Sae	}
857215570Sae
858215570Sae	/* whoops! we beat the close! */
859215570Sae	if (pp->sp_state & SS_CLOSING) {
860215570Sae		/* try and stop it from proceeding to bash the hardware */
861215570Sae		pp->sp_state &= ~SS_CLOSING;
862215570Sae	}
863215570Sae
864215672Sae	/*
865215672Sae	 * Wait for DCD if necessary
866215570Sae	 */
867215570Sae	if (!(tp->t_state & TS_CARR_ON)
868215570Sae	    && !IS_CALLOUT(mynor)
869215570Sae	    && !(tp->t_cflag & CLOCAL)
870215570Sae	    && !(flag & O_NONBLOCK)) {
871215570Sae		++pp->sp_wopeners;
872215570Sae		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
873215570Sae		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
874215570Sae		--pp->sp_wopeners;
875215570Sae		if (error != 0)
876215570Sae			goto out;
877215570Sae		goto open_top;
878215570Sae	}
879215570Sae
880215671Sae	error = (*linesw[tp->t_line].l_open)(dev, tp);
881215570Sae	si_disc_optim(tp, &tp->t_termios, pp);
882215570Sae	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
883215671Sae		pp->sp_active_out = TRUE;
884215671Sae
885215570Sae	pp->sp_state |= SS_OPEN;	/* made it! */
886215570Sae
887215570Saeout:
888215570Sae	splx(oldspl);
889215570Sae
890215570Sae	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
891215570Sae
892215671Sae	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
893215671Sae		sihardclose(pp);
894215671Sae
895215570Sae	return(error);
896215570Sae}
897215570Sae
898215570Saestatic	int
899215570Saesiclose(dev, flag, mode, p)
900215570Sae	dev_t dev;
901215570Sae	int flag, mode;
902215570Sae	struct proc *p;
903215570Sae{
904215570Sae	register struct si_port *pp;
905215570Sae	register struct tty *tp;
906215570Sae	int oldspl;
907215570Sae	int error = 0;
908215570Sae	int mynor = minor(dev);
909215570Sae
910215570Sae	if (IS_SPECIAL(mynor))
911215570Sae		return(0);
912215570Sae
913215570Sae	oldspl = spltty();
914215570Sae
915215570Sae	pp = MINOR2PP(mynor);
916215570Sae	tp = pp->sp_tty;
917215570Sae
918215570Sae	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
919215570Sae		dev, flag, mode, p, pp->sp_state));
920215570Sae
921215570Sae	/* did we sleep and loose a race? */
922215570Sae	if (pp->sp_state & SS_CLOSING) {
923215570Sae		/* error = ESOMETING? */
924215570Sae		goto out;
925215570Sae	}
926215570Sae
927215570Sae	/* begin race detection.. */
928215570Sae	pp->sp_state |= SS_CLOSING;
929215570Sae
930215671Sae	si_write_enable(pp, 0);		/* block writes for ttywait() */
931215570Sae
932223158Sae	/* THIS MAY SLEEP IN TTYWAIT!!! */
933215570Sae	(*linesw[tp->t_line].l_close)(tp, flag);
934215570Sae
935215570Sae	si_write_enable(pp, 1);
936215570Sae
937215570Sae	/* did we sleep and somebody started another open? */
938215570Sae	if (!(pp->sp_state & SS_CLOSING)) {
939215570Sae		/* error = ESOMETING? */
940215570Sae		goto out;
941215570Sae	}
942215570Sae	/* ok. we are now still on the right track.. nuke the hardware */
943215570Sae
944215570Sae	if (pp->sp_state & SS_LSTART) {
945215570Sae		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
946215570Sae		pp->sp_state &= ~SS_LSTART;
947215570Sae	}
948215570Sae
949215570Sae	sistop(tp, FREAD | FWRITE);
950215570Sae
951215570Sae	sihardclose(pp);
952215570Sae	ttyclose(tp);
953215570Sae	pp->sp_state &= ~SS_OPEN;
954215570Sae
955215570Saeout:
956215570Sae	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
957215570Sae	splx(oldspl);
958215570Sae	return(error);
959215570Sae}
960215570Sae
961215570Saestatic void
962215570Saesihardclose(pp)
963215570Sae	struct si_port *pp;
964215570Sae{
965215570Sae	int oldspl;
966215570Sae	struct tty *tp;
967215570Sae	volatile struct si_channel *ccbp;
968215570Sae
969215570Sae	oldspl = spltty();
970215570Sae
971215570Sae	tp = pp->sp_tty;
972215570Sae	ccbp = pp->sp_ccb;			/* Find control block */
973215570Sae	if (tp->t_cflag & HUPCL
974215570Sae	    || !pp->sp_active_out
975215672Sae	       && !(ccbp->hi_ip & IP_DCD)
976215672Sae	       && !(pp->sp_iin.c_cflag && CLOCAL)
977215570Sae	    || !(tp->t_state & TS_ISOPEN)) {
978215570Sae
979215570Sae		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
980215570Sae		(void) si_command(pp, FCLOSE, SI_NOWAIT);
981215570Sae
982215570Sae		if (pp->sp_dtr_wait != 0) {
983215570Sae			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
984215570Sae			pp->sp_state |= SS_DTR_OFF;
985215570Sae		}
986215570Sae
987215570Sae	}
988215570Sae	pp->sp_active_out = FALSE;
989215570Sae	wakeup((caddr_t)&pp->sp_active_out);
990215570Sae	wakeup(TSA_CARR_ON(tp));
991215570Sae
992215570Sae	splx(oldspl);
993215570Sae}
994215570Sae
995215570Sae
996215570Sae/*
997215570Sae * called at splsoftclock()...
998215570Sae */
999215570Saestatic void
1000215570Saesidtrwakeup(chan)
1001215570Sae	void *chan;
1002215570Sae{
1003215570Sae	struct si_port *pp;
1004215570Sae	int oldspl;
1005215570Sae
1006215570Sae	oldspl = spltty();
1007215570Sae
1008215570Sae	pp = (struct si_port *)chan;
1009215570Sae	pp->sp_state &= ~SS_DTR_OFF;
1010215570Sae	wakeup(&pp->sp_dtr_wait);
1011215570Sae
1012215570Sae	splx(oldspl);
1013179629Smarcel}
1014179629Smarcel
1015178180Smarcel/*
1016178180Smarcel * User level stuff - read and write
1017178180Smarcel */
1018179629Smarcelstatic	int
1019178180Smarcelsiread(dev, uio, flag)
1020179629Smarcel	register dev_t dev;
1021179629Smarcel	struct uio *uio;
1022178180Smarcel	int flag;
1023178180Smarcel{
1024179629Smarcel	register struct tty *tp;
1025179629Smarcel	int mynor = minor(dev);
1026208777Smarius
1027179629Smarcel	if (IS_SPECIAL(mynor)) {
1028179629Smarcel		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
1029178180Smarcel		return(ENODEV);
1030179629Smarcel	}
1031178180Smarcel	tp = MINOR2TP(mynor);
1032178180Smarcel	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
1033178180Smarcel		"siread(%x,%x,%x)\n", dev, uio, flag));
1034179629Smarcel	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1035179629Smarcel}
1036178180Smarcel
1037179629Smarcel
1038179629Smarcelstatic	int
1039179629Smarcelsiwrite(dev, uio, flag)
1040178180Smarcel	dev_t dev;
1041178180Smarcel	struct uio *uio;
1042179629Smarcel	int flag;
1043178180Smarcel{
1044179629Smarcel	register struct si_port *pp;
1045179629Smarcel	register struct tty *tp;
1046208777Smarius	int error = 0;
1047179629Smarcel	int mynor = minor(dev);
1048179629Smarcel	int oldspl;
1049179629Smarcel
1050179629Smarcel	if (IS_SPECIAL(mynor)) {
1051185038Smarcel		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
1052185038Smarcel		return(ENODEV);
1053208777Smarius	}
1054179629Smarcel	pp = MINOR2PP(mynor);
1055179629Smarcel	tp = pp->sp_tty;
1056179629Smarcel	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
1057179629Smarcel
1058179629Smarcel	oldspl = spltty();
1059179629Smarcel	/*
1060179629Smarcel	 * If writes are currently blocked, wait on the "real" tty
1061179629Smarcel	 */
1062179629Smarcel	while (pp->sp_state & SS_BLOCKWRITE) {
1063179629Smarcel		pp->sp_state |= SS_WAITWRITE;
1064179629Smarcel		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
1065179629Smarcel		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
1066179629Smarcel				     "siwrite", 0))
1067179629Smarcel			goto out;
1068179629Smarcel	}
1069179629Smarcel
1070179629Smarcel	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1071179629Smarcelout:
1072185038Smarcel	splx(oldspl);
1073185038Smarcel	return (error);
1074185038Smarcel}
1075185038Smarcel
1076185038Smarcel
1077185038Smarcelstatic	struct tty *
1078185038Smarcelsidevtotty(dev_t dev)
1079185038Smarcel{
1080185038Smarcel	struct si_port *pp;
1081185038Smarcel	int mynor = minor(dev);
1082179629Smarcel	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
1083185038Smarcel
1084185038Smarcel	if (IS_SPECIAL(mynor))
1085185038Smarcel		return(NULL);
1086185038Smarcel	if (SI_PORT(mynor) >= sc->sc_nport)
1087179629Smarcel		return(NULL);
1088179629Smarcel	pp = MINOR2PP(mynor);
1089179629Smarcel	return (pp->sp_tty);
1090208777Smarius}
1091179629Smarcel
1092208777Smariusstatic	int
1093208777Smariussiioctl(dev, cmd, data, flag, p)
1094208777Smarius	dev_t dev;
1095208777Smarius	int cmd;
1096208777Smarius	caddr_t data;
1097208777Smarius	int flag;
1098208777Smarius	struct proc *p;
1099208777Smarius{
1100208777Smarius	struct si_port *pp;
1101208777Smarius	register struct tty *tp;
1102208777Smarius	int error;
1103208777Smarius	int mynor = minor(dev);
1104208777Smarius	int oldspl;
1105208777Smarius	int blocked = 0;
1106208777Smarius#if defined(COMPAT_43)
1107208777Smarius	int oldcmd;
1108208777Smarius	struct termios term;
1109208777Smarius#endif
1110208777Smarius
1111208777Smarius	if (IS_SI_IOCTL(cmd))
1112208777Smarius		return(si_Sioctl(dev, cmd, data, flag, p));
1113208777Smarius
1114208777Smarius	pp = MINOR2PP(mynor);
1115208777Smarius	tp = pp->sp_tty;
1116208777Smarius
1117208777Smarius	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
1118208777Smarius		dev, cmd, data, flag));
1119208777Smarius	if (IS_STATE(mynor)) {
1120208777Smarius		struct termios *ct;
1121208777Smarius
1122208777Smarius		switch (mynor & SI_STATE_MASK) {
1123208777Smarius		case SI_INIT_STATE_MASK:
1124208777Smarius			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1125208777Smarius			break;
1126208777Smarius		case SI_LOCK_STATE_MASK:
1127208777Smarius			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1128208777Smarius			break;
1129208777Smarius		default:
1130208777Smarius			return (ENODEV);
1131208777Smarius		}
1132208777Smarius		switch (cmd) {
1133208777Smarius		case TIOCSETA:
1134179629Smarcel			error = suser(p->p_ucred, &p->p_acflag);
1135179629Smarcel			if (error != 0)
1136179629Smarcel				return (error);
1137185454Smarcel			*ct = *(struct termios *)data;
1138179629Smarcel			return (0);
1139208777Smarius		case TIOCGETA:
1140208777Smarius			*(struct termios *)data = *ct;
1141208777Smarius			return (0);
1142179629Smarcel		case TIOCGETD:
1143179629Smarcel			*(int *)data = TTYDISC;
1144179629Smarcel			return (0);
1145208777Smarius		case TIOCGWINSZ:
1146179629Smarcel			bzero(data, sizeof(struct winsize));
1147212554Spjd			return (0);
1148212554Spjd		default:
1149208173Snwhitehorn			return (ENOTTY);
1150179629Smarcel		}
1151212554Spjd	}
1152179629Smarcel	/*
1153179629Smarcel	 * Do the old-style ioctl compat routines...
1154179629Smarcel	 */
1155179629Smarcel#if defined(COMPAT_43)
1156179629Smarcel	term = tp->t_termios;
1157179629Smarcel	oldcmd = cmd;
1158179629Smarcel	error = ttsetcompat(tp, &cmd, data, &term);
1159179629Smarcel	if (error != 0)
1160208777Smarius		return (error);
1161208777Smarius	if (cmd != oldcmd)
1162208777Smarius		data = (caddr_t)&term;
1163208777Smarius#endif
1164208777Smarius	/*
1165208777Smarius	 * Do the initial / lock state business
1166208777Smarius	 */
1167208777Smarius	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1168208777Smarius		int     cc;
1169208777Smarius		struct termios *dt = (struct termios *)data;
1170208777Smarius		struct termios *lt = mynor & SI_CALLOUT_MASK
1171216619Sae				     ? &pp->sp_lout : &pp->sp_lin;
1172216619Sae
1173212554Spjd		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1174208777Smarius			| (dt->c_iflag & ~lt->c_iflag);
1175208777Smarius		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1176208777Smarius			| (dt->c_oflag & ~lt->c_oflag);
1177208777Smarius		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1178208777Smarius			| (dt->c_cflag & ~lt->c_cflag);
1179208777Smarius		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1180208777Smarius			| (dt->c_lflag & ~lt->c_lflag);
1181208777Smarius		for (cc = 0; cc < NCCS; ++cc)
1182208777Smarius			if (lt->c_cc[cc] != 0)
1183208777Smarius				dt->c_cc[cc] = tp->t_cc[cc];
1184212554Spjd		if (lt->c_ispeed != 0)
1185212554Spjd			dt->c_ispeed = tp->t_ispeed;
1186208777Smarius		if (lt->c_ospeed != 0)
1187179629Smarcel			dt->c_ospeed = tp->t_ospeed;
1188212554Spjd	}
1189179629Smarcel
1190179629Smarcel	/*
1191179629Smarcel	 * Block user-level writes to give the ttywait()
1192179629Smarcel	 * a chance to completely drain for commands
1193179629Smarcel	 * that require the port to be in a quiescent state.
1194179629Smarcel	 */
1195179629Smarcel	switch (cmd) {
1196212554Spjd	case TIOCSETAW: case TIOCSETAF:
1197179629Smarcel	case TIOCDRAIN: case TIOCSETP:
1198179629Smarcel		blocked++;	/* block writes for ttywait() and siparam() */
1199212708Spjd		si_write_enable(pp, 0);
1200212708Spjd	}
1201179629Smarcel
1202212554Spjd	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1203179629Smarcel	if (error >= 0)
1204179629Smarcel		goto out;
1205179629Smarcel
1206179629Smarcel	oldspl = spltty();
1207179629Smarcel
1208179629Smarcel	error = ttioctl(tp, cmd, data, flag);
1209208777Smarius	si_disc_optim(tp, &tp->t_termios, pp);
1210208777Smarius	if (error >= 0)
1211208777Smarius		goto outspl;
1212208777Smarius
1213223364Sae	switch (cmd) {
1214223364Sae	case TIOCSBRK:
1215223364Sae		si_command(pp, SBREAK, SI_NOWAIT);
1216208777Smarius		break;
1217223364Sae	case TIOCCBRK:
1218208777Smarius		si_command(pp, EBREAK, SI_NOWAIT);
1219179629Smarcel		break;
1220179629Smarcel	case TIOCSDTR:
1221179629Smarcel		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1222185454Smarcel		break;
1223185454Smarcel	case TIOCCDTR:
1224208777Smarius		(void) si_modem(pp, SET, 0);
1225208777Smarius		break;
1226185454Smarcel	case TIOCMSET:
1227185454Smarcel		(void) si_modem(pp, SET, *(int *)data);
1228185454Smarcel		break;
1229213097Sae	case TIOCMBIS:
1230213097Sae		(void) si_modem(pp, BIS, *(int *)data);
1231213097Sae		break;
1232213097Sae	case TIOCMBIC:
1233213097Sae		(void) si_modem(pp, BIC, *(int *)data);
1234213097Sae		break;
1235213097Sae	case TIOCMGET:
1236213097Sae		*(int *)data = si_modem(pp, GET, 0);
1237213097Sae		break;
1238213097Sae	case TIOCMSDTRWAIT:
1239213097Sae		/* must be root since the wait applies to following logins */
1240213097Sae		error = suser(p->p_ucred, &p->p_acflag);
1241213097Sae		if (error != 0) {
1242213097Sae			goto outspl;
1243213097Sae		}
1244213097Sae		pp->sp_dtr_wait = *(int *)data * hz / 100;
1245213097Sae		break;
1246213097Sae	case TIOCMGDTRWAIT:
1247185454Smarcel		*(int *)data = pp->sp_dtr_wait * 100 / hz;
1248185454Smarcel		break;
1249185454Smarcel
1250185454Smarcel	default:
1251185495Smarcel		error = ENOTTY;
1252185454Smarcel	}
1253212554Spjd	error = 0;
1254212554Spjdoutspl:
1255212554Spjd	splx(oldspl);
1256212554Spjdout:
1257193673Smarcel	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
1258193673Smarcel	if (blocked)
1259193673Smarcel		si_write_enable(pp, 1);
1260193673Smarcel	return(error);
1261193673Smarcel}
1262193673Smarcel
1263193673Smarcel/*
1264193673Smarcel * Handle the Specialix ioctls. All MUST be called via the CONTROL device
1265185454Smarcel */
1266185454Smarcelstatic int
1267185454Smarcelsi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
1268185454Smarcel{
1269185454Smarcel	struct si_softc *xsc;
1270185454Smarcel	register struct si_port *xpp;
1271185495Smarcel	volatile struct si_reg *regp;
1272185495Smarcel	struct si_tcsi *dp;
1273179629Smarcel	struct si_pstat *sps;
1274185454Smarcel	int *ip, error = 0;
1275213097Sae	int oldspl;
1276185495Smarcel	int card, port;
1277185495Smarcel	int mynor = minor(dev);
1278185495Smarcel
1279185495Smarcel	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
1280185495Smarcel		dev, cmd, data, flag));
1281179629Smarcel
1282#if 1
1283	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
1284	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
1285	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
1286#endif
1287
1288	if (!IS_CONTROLDEV(mynor)) {
1289		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
1290		return(ENODEV);
1291	}
1292
1293	oldspl = spltty();	/* better safe than sorry */
1294
1295	ip = (int *)data;
1296
1297#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
1298
1299	switch (cmd) {
1300	case TCSIPORTS:
1301		*ip = si_Nports;
1302		goto out;
1303	case TCSIMODULES:
1304		*ip = si_Nmodules;
1305		goto out;
1306	case TCSISDBG_ALL:
1307		SUCHECK;
1308		si_debug = *ip;
1309		goto out;
1310	case TCSIGDBG_ALL:
1311		*ip = si_debug;
1312		goto out;
1313	default:
1314		/*
1315		 * Check that a controller for this port exists
1316		 */
1317
1318		/* may also be a struct si_pstat, a superset of si_tcsi */
1319
1320		dp = (struct si_tcsi *)data;
1321		sps = (struct si_pstat *)data;
1322		card = dp->tc_card;
1323		xsc = &si_softc[card];	/* check.. */
1324		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
1325			error = ENOENT;
1326			goto out;
1327		}
1328		/*
1329		 * And check that a port exists
1330		 */
1331		port = dp->tc_port;
1332		if (port < 0 || port >= xsc->sc_nport) {
1333			error = ENOENT;
1334			goto out;
1335		}
1336		xpp = xsc->sc_ports + port;
1337		regp = (struct si_reg *)xsc->sc_maddr;
1338	}
1339
1340	switch (cmd) {
1341	case TCSIDEBUG:
1342#ifdef	SI_DEBUG
1343		SUCHECK;
1344		if (xpp->sp_debug)
1345			xpp->sp_debug = 0;
1346		else {
1347			xpp->sp_debug = DBG_ALL;
1348			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
1349				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
1350		}
1351		break;
1352#else
1353		error = ENODEV;
1354		goto out;
1355#endif
1356	case TCSISDBG_LEVEL:
1357	case TCSIGDBG_LEVEL:
1358#ifdef	SI_DEBUG
1359		if (cmd == TCSIGDBG_LEVEL) {
1360			dp->tc_dbglvl = xpp->sp_debug;
1361		} else {
1362			SUCHECK;
1363			xpp->sp_debug = dp->tc_dbglvl;
1364		}
1365		break;
1366#else
1367		error = ENODEV;
1368		goto out;
1369#endif
1370	case TCSIGRXIT:
1371		dp->tc_int = regp->rx_int_count;
1372		break;
1373	case TCSIRXIT:
1374		SUCHECK;
1375		regp->rx_int_count = dp->tc_int;
1376		break;
1377	case TCSIGIT:
1378		dp->tc_int = regp->int_count;
1379		break;
1380	case TCSIIT:
1381		SUCHECK;
1382		regp->int_count = dp->tc_int;
1383		break;
1384	case TCSISTATE:
1385		dp->tc_int = xpp->sp_ccb->hi_ip;
1386		break;
1387	/* these next three use a different structure */
1388	case TCSI_PORT:
1389		SUCHECK;
1390		sps->tc_siport = *xpp;
1391		break;
1392	case TCSI_CCB:
1393		SUCHECK;
1394		sps->tc_ccb = *xpp->sp_ccb;
1395		break;
1396	case TCSI_TTY:
1397		SUCHECK;
1398		sps->tc_tty = *xpp->sp_tty;
1399		break;
1400	default:
1401		error = EINVAL;
1402		goto out;
1403	}
1404out:
1405	splx(oldspl);
1406	return(error);		/* success */
1407}
1408
1409/*
1410 *	siparam()	: Configure line params
1411 *	called at spltty();
1412 *	this may sleep, does not flush, nor wait for drain, nor block writes
1413 *	caller must arrange this if it's important..
1414 */
1415static int
1416siparam(tp, t)
1417	register struct tty *tp;
1418	register struct termios *t;
1419{
1420	register struct si_port *pp = TP2PP(tp);
1421	volatile struct si_channel *ccbp;
1422	int oldspl, cflag, iflag, oflag, lflag;
1423	int error = 0;		/* shutup gcc */
1424	int ispeed = 0;		/* shutup gcc */
1425	int ospeed = 0;		/* shutup gcc */
1426	BYTE val;
1427
1428	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
1429	cflag = t->c_cflag;
1430	iflag = t->c_iflag;
1431	oflag = t->c_oflag;
1432	lflag = t->c_lflag;
1433	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
1434		oflag, cflag, iflag, lflag));
1435
1436
1437	/* if not hung up.. */
1438	if (t->c_ospeed != 0) {
1439		/* translate baud rate to firmware values */
1440		ospeed = ttspeedtab(t->c_ospeed, bdrates);
1441		ispeed = t->c_ispeed ?
1442			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
1443
1444		/* enforce legit baud rate */
1445		if (ospeed < 0 || ispeed < 0)
1446			return (EINVAL);
1447	}
1448
1449
1450	oldspl = spltty();
1451
1452	ccbp = pp->sp_ccb;
1453
1454	/* ========== set hi_break ========== */
1455	val = 0;
1456	if (iflag & IGNBRK)		/* Breaks */
1457		val |= BR_IGN;
1458	if (iflag & BRKINT)		/* Interrupt on break? */
1459		val |= BR_INT;
1460	if (iflag & PARMRK)		/* Parity mark? */
1461		val |= BR_PARMRK;
1462	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
1463		val |= BR_PARIGN;
1464	ccbp->hi_break = val;
1465
1466	/* ========== set hi_csr ========== */
1467	/* if not hung up.. */
1468	if (t->c_ospeed != 0) {
1469		/* Set I/O speeds */
1470		 val = (ispeed << 4) | ospeed;
1471	}
1472	ccbp->hi_csr = val;
1473
1474	/* ========== set hi_mr2 ========== */
1475	val = 0;
1476	if (cflag & CSTOPB)				/* Stop bits */
1477		val |= MR2_2_STOP;
1478	else
1479		val |= MR2_1_STOP;
1480	/*
1481	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1482	 * a DCE, hence the reverse sense of RTS and CTS
1483	 */
1484	/* Output Flow - RTS must be raised before data can be sent */
1485	if (cflag & CCTS_OFLOW)
1486		val |= MR2_RTSCONT;
1487
1488	ccbp->hi_mr1 = val;
1489
1490	/* ========== set hi_mr1 ========== */
1491	val = 0;
1492	if (!(cflag & PARENB))				/* Parity */
1493		val |= MR1_NONE;
1494	else
1495		val |= MR1_WITH;
1496	if (cflag & PARODD)
1497		val |= MR1_ODD;
1498
1499	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1500		val |= MR1_8_BITS;
1501	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1502		val |= MR1_7_BITS;
1503	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1504		val |= MR1_6_BITS;
1505	} else {					/* Must be 5 */
1506		val |= MR1_5_BITS;
1507	}
1508	/*
1509	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1510	 * a DCE, hence the reverse sense of RTS and CTS
1511	 */
1512	/* Input Flow - CTS is raised when port is ready to receive data */
1513	if (cflag & CRTS_IFLOW)
1514		val |= MR1_CTSCONT;
1515
1516	ccbp->hi_mr1 = val;
1517
1518	/* ========== set hi_mask ========== */
1519	val = 0xff;
1520	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1521		val &= 0xFF;
1522	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1523		val &= 0x7F;
1524	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1525		val &= 0x3F;
1526	} else {					/* Must be 5 */
1527		val &= 0x1F;
1528	}
1529	if (iflag & ISTRIP)
1530		val &= 0x7F;
1531
1532	ccbp->hi_mask = val;
1533
1534	/* ========== set hi_prtcl ========== */
1535	val = 0;
1536				/* Monitor DCD etc. if a modem */
1537	if (!(cflag & CLOCAL))
1538		val |= SP_DCEN;
1539	if (iflag & IXANY)
1540		val |= SP_TANY;
1541	if (iflag & IXON)
1542		val |= SP_TXEN;
1543	if (iflag & IXOFF)
1544		val |= SP_RXEN;
1545	if (iflag & INPCK)
1546		val |= SP_PAEN;
1547
1548	ccbp->hi_prtcl = val;
1549
1550
1551	/* ========== set hi_{rx|tx}{on|off} ========== */
1552	/* XXX: the card TOTALLY shields us from the flow control... */
1553	ccbp->hi_txon = t->c_cc[VSTART];
1554	ccbp->hi_txoff = t->c_cc[VSTOP];
1555
1556	ccbp->hi_rxon = t->c_cc[VSTART];
1557	ccbp->hi_rxoff = t->c_cc[VSTOP];
1558
1559	/* ========== send settings to the card ========== */
1560	/* potential sleep here */
1561	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
1562		si_command(pp, LOPEN, SI_WAIT);		/* open it */
1563	else
1564		si_command(pp, CONFIG, SI_WAIT);	/* change params */
1565
1566	/* ========== set DTR etc ========== */
1567	/* Hangup if ospeed == 0 */
1568	if (t->c_ospeed == 0) {
1569		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
1570	} else {
1571		/*
1572		 * If the previous speed was 0, may need to re-enable
1573	 	 * the modem signals
1574	 	 */
1575		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1576	}
1577
1578	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
1579		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
1580
1581	splx(oldspl);
1582	return(error);
1583}
1584
1585/*
1586 * Enable or Disable the writes to this channel...
1587 * "state" ->  enabled = 1; disabled = 0;
1588 */
1589static void
1590si_write_enable(pp, state)
1591	register struct si_port *pp;
1592	int state;
1593{
1594	int oldspl;
1595
1596	oldspl = spltty();
1597
1598	if (state) {
1599		pp->sp_state &= ~SS_BLOCKWRITE;
1600		if (pp->sp_state & SS_WAITWRITE) {
1601			pp->sp_state &= ~SS_WAITWRITE;
1602			/* thunder away! */
1603			wakeup((caddr_t)pp);
1604		}
1605	} else {
1606		pp->sp_state |= SS_BLOCKWRITE;
1607	}
1608
1609	splx(oldspl);
1610}
1611
1612/*
1613 * Set/Get state of modem control lines.
1614 * Due to DCE-like behaviour of the adapter, some signals need translation:
1615 *	TIOCM_DTR	DSR
1616 *	TIOCM_RTS	CTS
1617 */
1618static int
1619si_modem(pp, cmd, bits)
1620	struct si_port *pp;
1621	enum si_mctl cmd;
1622	int bits;
1623{
1624	volatile struct si_channel *ccbp;
1625	int x;
1626
1627	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
1628	ccbp = pp->sp_ccb;		/* Find channel address */
1629	switch (cmd) {
1630	case GET:
1631		x = ccbp->hi_ip;
1632		bits = TIOCM_LE;
1633		if (x & IP_DCD)		bits |= TIOCM_CAR;
1634		if (x & IP_DTR)		bits |= TIOCM_DTR;
1635		if (x & IP_RTS)		bits |= TIOCM_RTS;
1636		if (x & IP_RI)		bits |= TIOCM_RI;
1637		return(bits);
1638	case SET:
1639		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
1640		/* fall through */
1641	case BIS:
1642		x = 0;
1643		if (bits & TIOCM_DTR)
1644			x |= OP_DSR;
1645		if (bits & TIOCM_RTS)
1646			x |= OP_CTS;
1647		ccbp->hi_op |= x;
1648		break;
1649	case BIC:
1650		if (bits & TIOCM_DTR)
1651			ccbp->hi_op &= ~OP_DSR;
1652		if (bits & TIOCM_RTS)
1653			ccbp->hi_op &= ~OP_CTS;
1654	}
1655	return 0;
1656}
1657
1658/*
1659 * Handle change of modem state
1660 */
1661static void
1662si_modem_state(pp, tp, hi_ip)
1663	register struct si_port *pp;
1664	register struct tty *tp;
1665	register int hi_ip;
1666{
1667							/* if a modem dev */
1668	if (hi_ip & IP_DCD) {
1669		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
1670			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
1671				tp->t_line));
1672			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
1673		}
1674	} else {
1675		if (pp->sp_last_hi_ip & IP_DCD) {
1676			DPRINT((pp, DBG_INTR, "modem carr off\n"));
1677			if ((*linesw[tp->t_line].l_modem)(tp, 0))
1678				(void) si_modem(pp, SET, 0);
1679		}
1680	}
1681	pp->sp_last_hi_ip = hi_ip;
1682
1683}
1684
1685/*
1686 * Poller to catch missed interrupts.
1687 *
1688 * Note that the SYSV Specialix drivers poll at 100 times per second to get
1689 * better response.  We could really use a "periodic" version timeout(). :-)
1690 */
1691#ifdef POLL
1692static void
1693si_poll(void *nothing)
1694{
1695	register struct si_softc *sc;
1696	register int i;
1697	volatile struct si_reg *regp;
1698	register struct si_port *pp;
1699	int lost, oldspl, port;
1700
1701	DPRINT((0, DBG_POLL, "si_poll()\n"));
1702	oldspl = spltty();
1703	if (in_intr)
1704		goto out;
1705	lost = 0;
1706	for (i=0; i<NSI; i++) {
1707		sc = &si_softc[i];
1708		if (sc->sc_type == SIEMPTY)
1709			continue;
1710		regp = (struct si_reg *)sc->sc_maddr;
1711		/*
1712		 * See if there has been a pending interrupt for 2 seconds
1713		 * or so. The test <int_scounter >= 200) won't correspond
1714		 * to 2 seconds if int_count gets changed.
1715		 */
1716		if (regp->int_pending != 0) {
1717			if (regp->int_scounter >= 200 &&
1718			    regp->initstat == 1) {
1719				printf("si%d: lost intr\n", i);
1720				lost++;
1721			}
1722		} else {
1723			regp->int_scounter = 0;
1724		}
1725
1726		/*
1727		 * gripe about no input flow control..
1728		 */
1729		pp = sc->sc_ports;
1730		for (port = 0; port < sc->sc_nport; pp++, port++) {
1731			if (pp->sp_delta_overflows > 0) {
1732				printf("si%d: %d tty level buffer overflows\n",
1733					i, pp->sp_delta_overflows);
1734				pp->sp_delta_overflows = 0;
1735			}
1736		}
1737	}
1738	if (lost)
1739		siintr(-1);	/* call intr with fake vector */
1740out:
1741	splx(oldspl);
1742
1743	timeout(si_poll, (caddr_t)0L, si_pollrate);
1744}
1745#endif	/* ifdef POLL */
1746
1747/*
1748 * The interrupt handler polls ALL ports on ALL adapters each time
1749 * it is called.
1750 */
1751
1752static BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
1753
1754void
1755siintr(int unit)
1756{
1757	register struct si_softc *sc;
1758
1759	register struct si_port *pp;
1760	volatile struct si_channel *ccbp;
1761	register struct tty *tp;
1762	volatile caddr_t maddr;
1763	BYTE op, ip;
1764	int x, card, port, n, i, isopen;
1765	volatile BYTE *z;
1766	BYTE c;
1767
1768	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
1769	if (in_intr) {
1770		if (unit < 0)	/* should never happen */
1771			return;
1772		printf("si%d: Warning interrupt handler re-entered\n",
1773			unit);
1774		return;
1775	}
1776	in_intr = 1;
1777
1778	/*
1779	 * When we get an int we poll all the channels and do ALL pending
1780	 * work, not just the first one we find. This allows all cards to
1781	 * share the same vector.
1782	 */
1783	for (card=0; card < NSI; card++) {
1784		sc = &si_softc[card];
1785		if (sc->sc_type == SIEMPTY)
1786			continue;
1787
1788		/*
1789		 * First, clear the interrupt
1790		 */
1791		switch(sc->sc_type) {
1792		case SIHOST :
1793			maddr = sc->sc_maddr;
1794			((volatile struct si_reg *)maddr)->int_pending = 0;
1795							/* flag nothing pending */
1796			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
1797			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
1798			break;
1799		case SIHOST2:
1800			maddr = sc->sc_maddr;
1801			((volatile struct si_reg *)maddr)->int_pending = 0;
1802			*(maddr+SIPLIRQCLR) = 0x00;
1803			*(maddr+SIPLIRQCLR) = 0x10;
1804			break;
1805		case SIEISA:
1806#if NEISA > 0
1807			maddr = sc->sc_maddr;
1808			((volatile struct si_reg *)maddr)->int_pending = 0;
1809			(void)inb(sc->sc_eisa_iobase+3);
1810			break;
1811#endif	/* fall through if not EISA kernel */
1812		case SIEMPTY:
1813		default:
1814			continue;
1815		}
1816		((volatile struct si_reg *)maddr)->int_scounter = 0;
1817
1818		/*
1819		 * check each port
1820		 */
1821		for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) {
1822			ccbp = pp->sp_ccb;
1823			tp = pp->sp_tty;
1824
1825
1826			/*
1827			 * See if a command has completed ?
1828			 */
1829			if (ccbp->hi_stat != pp->sp_pend) {
1830				DPRINT((pp, DBG_INTR,
1831					"siintr hi_stat = 0x%x, pend = %d\n",
1832					ccbp->hi_stat, pp->sp_pend));
1833				switch(pp->sp_pend) {
1834				case LOPEN:
1835				case MPEND:
1836				case MOPEN:
1837				case CONFIG:
1838					pp->sp_pend = ccbp->hi_stat;
1839						/* sleeping in si_command */
1840					wakeup(&pp->sp_state);
1841					break;
1842				default:
1843					pp->sp_pend = ccbp->hi_stat;
1844				}
1845	 		}
1846
1847			/*
1848			 * Continue on if it's closed
1849			 */
1850			if (ccbp->hi_stat == IDLE_CLOSE) {
1851				continue;
1852			}
1853
1854			/*
1855			 * Do modem state change if not a local device
1856			 */
1857			si_modem_state(pp, tp, ccbp->hi_ip);
1858
1859			/*
1860			 * Check to see if there's we should 'receive'
1861			 * characters.
1862			 */
1863			if (tp->t_state & TS_CONNECTED &&
1864			    tp->t_state & TS_ISOPEN)
1865				isopen = 1;
1866			else
1867				isopen = 0;
1868
1869			/*
1870			 * Do break processing
1871			 */
1872			if (ccbp->hi_state & ST_BREAK) {
1873				if (isopen) {
1874				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
1875				}
1876				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
1877				DPRINT((pp, DBG_INTR, "si_intr break\n"));
1878			}
1879
1880			/*
1881			 * Do RX stuff - if not open then dump any characters.
1882			 * XXX: This is VERY messy and needs to be cleaned up.
1883			 *
1884			 * XXX: can we leave data in the host adapter buffer
1885			 * when the clists are full?  That may be dangerous
1886			 * if the user cannot get an interrupt signal through.
1887			 */
1888
1889	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
1890
1891			if (!isopen) {
1892				ccbp->hi_rxopos = ccbp->hi_rxipos;
1893				goto end_rx;
1894			}
1895
1896			/*
1897			 * If the tty input buffers are blocked, stop emptying
1898			 * the incoming buffers and let the auto flow control
1899			 * assert..
1900			 */
1901			if (tp->t_state & TS_TBLOCK) {
1902				goto end_rx;
1903			}
1904
1905			/*
1906			 * Process read characters if not skipped above
1907			 */
1908			op = ccbp->hi_rxopos;
1909			ip = ccbp->hi_rxipos;
1910			c = ip - op;
1911			if (c == 0) {
1912				goto end_rx;
1913			}
1914
1915			n = c & 0xff;
1916			if (n > 250)
1917				n = 250;
1918
1919			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1920						n, op, ip));
1921
1922			/*
1923			 * Suck characters out of host card buffer into the
1924			 * "input staging buffer" - so that we dont leave the
1925			 * host card in limbo while we're possibly echoing
1926			 * characters and possibly flushing input inside the
1927			 * ldisc l_rint() routine.
1928			 */
1929			if (n <= SI_BUFFERSIZE - op) {
1930
1931				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
1932				z = ccbp->hi_rxbuf + op;
1933				bcopy((caddr_t)z, si_rxbuf, n);
1934
1935				op += n;
1936			} else {
1937				x = SI_BUFFERSIZE - op;
1938
1939				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
1940				z = ccbp->hi_rxbuf + op;
1941				bcopy((caddr_t)z, si_rxbuf, x);
1942
1943				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
1944				z = ccbp->hi_rxbuf;
1945				bcopy((caddr_t)z, si_rxbuf+x, n-x);
1946
1947				op += n;
1948			}
1949
1950			/* clear collected characters from buffer */
1951			ccbp->hi_rxopos = op;
1952
1953			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1954						n, op, ip));
1955
1956			/*
1957			 * at this point...
1958			 * n = number of chars placed in si_rxbuf
1959			 */
1960
1961			/*
1962			 * Avoid the grotesquely inefficient lineswitch
1963			 * routine (ttyinput) in "raw" mode. It usually
1964			 * takes about 450 instructions (that's without
1965			 * canonical processing or echo!). slinput is
1966			 * reasonably fast (usually 40 instructions
1967			 * plus call overhead).
1968			 */
1969			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1970
1971				/* block if the driver supports it */
1972				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
1973				    && (tp->t_cflag & CRTS_IFLOW
1974					|| tp->t_iflag & IXOFF)
1975				    && !(tp->t_state & TS_TBLOCK))
1976					ttyblock(tp);
1977
1978				tk_nin += n;
1979				tk_rawcc += n;
1980				tp->t_rawcc += n;
1981
1982				pp->sp_delta_overflows +=
1983				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
1984
1985				ttwakeup(tp);
1986				if (tp->t_state & TS_TTSTOP
1987				    && (tp->t_iflag & IXANY
1988					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1989					tp->t_state &= ~TS_TTSTOP;
1990					tp->t_lflag &= ~FLUSHO;
1991					si_start(tp);
1992				}
1993			} else {
1994				/*
1995				 * It'd be nice to not have to go through the
1996				 * function call overhead for each char here.
1997				 * It'd be nice to block input it, saving a
1998				 * loop here and the call/return overhead.
1999				 */
2000				for(x = 0; x < n; x++) {
2001					i = si_rxbuf[x];
2002					if ((*linesw[tp->t_line].l_rint)(i, tp)
2003					     == -1) {
2004						pp->sp_delta_overflows++;
2005					}
2006					/*
2007					 * doesn't seem to be much point doing
2008					 * this here.. this driver has no
2009					 * softtty processing! ??
2010					 */
2011					if (pp->sp_hotchar && i == pp->sp_hotchar) {
2012						setsofttty();
2013					}
2014				}
2015			}
2016			goto more_rx;	/* try for more until RXbuf is empty */
2017
2018	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
2019
2020			/*
2021			 * Do TX stuff
2022			 */
2023			(*linesw[tp->t_line].l_start)(tp);
2024
2025		} /* end of for (all ports on this controller) */
2026	} /* end of for (all controllers) */
2027
2028	in_intr = 0;
2029	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
2030}
2031
2032/*
2033 * Nudge the transmitter...
2034 *
2035 * XXX: I inherited some funny code here.  It implies the host card only
2036 * interrupts when the transmit buffer reaches the low-water-mark, and does
2037 * not interrupt when it's actually hits empty.  In some cases, we have
2038 * processes waiting for complete drain, and we need to simulate an interrupt
2039 * about when we think the buffer is going to be empty (and retry if not).
2040 * I really am not certain about this...  I *need* the hardware manuals.
2041 */
2042static void
2043si_start(tp)
2044	register struct tty *tp;
2045{
2046	struct si_port *pp;
2047	volatile struct si_channel *ccbp;
2048	register struct clist *qp;
2049	register char *dptr;
2050	BYTE ipos;
2051	int nchar;
2052	int oldspl, count, n, amount, buffer_full;
2053	int do_exitproc;
2054
2055	oldspl = spltty();
2056
2057	qp = &tp->t_outq;
2058	pp = TP2PP(tp);
2059
2060	DPRINT((pp, DBG_ENTRY|DBG_START,
2061		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
2062		tp, tp->t_state, pp->sp_state, qp->c_cc));
2063
2064	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
2065		goto out;
2066
2067	do_exitproc = 0;
2068	buffer_full = 0;
2069	ccbp = pp->sp_ccb;
2070
2071	/*
2072	 * Handle the case where ttywait() is called on process exit
2073	 * this may be BSDI specific, I dont know...
2074	 */
2075	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
2076	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
2077		do_exitproc++;
2078	}
2079
2080	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
2081	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
2082
2083	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
2084
2085	while ((nchar = qp->c_cc) > 0) {
2086		if ((BYTE)count >= 255) {
2087			buffer_full++;
2088			break;
2089		}
2090		amount = min(nchar, (255 - (BYTE)count));
2091		ipos = (unsigned int)ccbp->hi_txipos;
2092		/* will it fit in one lump? */
2093		if ((SI_BUFFERSIZE - ipos) >= amount) {
2094			n = q_to_b(&tp->t_outq,
2095				(char *)&ccbp->hi_txbuf[ipos], amount);
2096		} else {
2097			n = q_to_b(&tp->t_outq,
2098				(char *)&ccbp->hi_txbuf[ipos],
2099				SI_BUFFERSIZE-ipos);
2100			if (n == SI_BUFFERSIZE-ipos) {
2101				n += q_to_b(&tp->t_outq,
2102					(char *)&ccbp->hi_txbuf[0],
2103					amount - (SI_BUFFERSIZE-ipos));
2104			}
2105		}
2106		ccbp->hi_txipos += n;
2107		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
2108	}
2109
2110	if (count != 0 && nchar == 0) {
2111		tp->t_state |= TS_BUSY;
2112	} else {
2113		tp->t_state &= ~TS_BUSY;
2114	}
2115
2116	/* wakeup time? */
2117	ttwwakeup(tp);
2118
2119	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
2120		(BYTE)count, nchar, tp->t_state));
2121
2122	if ((tp->t_state & TS_BUSY) || do_exitproc)
2123	{
2124		int time;
2125
2126		if (do_exitproc != 0) {
2127			time = hz / 10;
2128		} else {
2129			time = ttspeedtab(tp->t_ospeed, chartimes);
2130
2131			if (time > 0) {
2132				if (time < nchar)
2133					time = nchar / time;
2134				else
2135					time = 2;
2136			} else {
2137				DPRINT((pp, DBG_START,
2138					"bad char time value! %d\n", time));
2139				time = hz/10;
2140			}
2141		}
2142
2143		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
2144			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
2145		} else {
2146			pp->sp_state |= SS_LSTART;
2147		}
2148		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
2149		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
2150	}
2151
2152out:
2153	splx(oldspl);
2154	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
2155}
2156
2157/*
2158 * Note: called at splsoftclock from the timeout code
2159 * This has to deal with two things...  cause wakeups while waiting for
2160 * tty drains on last process exit, and call l_start at about the right
2161 * time for protocols like ppp.
2162 */
2163static void
2164si_lstart(pp)
2165	register struct si_port *pp;
2166{
2167	register struct tty *tp;
2168	int oldspl;
2169
2170	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
2171		pp, pp->sp_state));
2172
2173	oldspl = spltty();
2174
2175	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
2176		splx(oldspl);
2177		return;
2178	}
2179	pp->sp_state &= ~SS_LSTART;
2180	pp->sp_state |= SS_INLSTART;
2181
2182	tp = pp->sp_tty;
2183
2184	/* deal with the process exit case */
2185	ttwwakeup(tp);
2186
2187	/* nudge protocols - eg: ppp */
2188	(*linesw[tp->t_line].l_start)(tp);
2189
2190	pp->sp_state &= ~SS_INLSTART;
2191	splx(oldspl);
2192}
2193
2194/*
2195 * Stop output on a line. called at spltty();
2196 */
2197void
2198sistop(tp, rw)
2199	register struct tty *tp;
2200	int rw;
2201{
2202	volatile struct si_channel *ccbp;
2203	struct si_port *pp;
2204
2205	pp = TP2PP(tp);
2206	ccbp = pp->sp_ccb;
2207
2208	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
2209
2210	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
2211	if (rw & FWRITE) {
2212		/* what level are we meant to be flushing anyway? */
2213		if (tp->t_state & TS_BUSY) {
2214			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
2215			tp->t_state &= ~TS_BUSY;
2216			ttwwakeup(tp);	/* Bruce???? */
2217		}
2218	}
2219#if 1	/* XXX: this doesn't work right yet.. */
2220	/* XXX: this may have been failing because we used to call l_rint()
2221	 * while we were looping based on these two counters. Now, we collect
2222	 * the data and then loop stuffing it into l_rint(), making this
2223	 * useless.  Should we cause this to blow away the staging buffer?
2224	 */
2225	if (rw & FREAD) {
2226		ccbp->hi_rxopos = ccbp->hi_rxipos;
2227	}
2228#endif
2229}
2230
2231/*
2232 * Issue a command to the Z280 host card CPU.
2233 */
2234
2235static void
2236si_command(pp, cmd, waitflag)
2237	struct si_port *pp;		/* port control block (local) */
2238	int cmd;
2239	int waitflag;
2240{
2241	int oldspl;
2242	volatile struct si_channel *ccbp = pp->sp_ccb;
2243	int x;
2244
2245	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
2246		pp, cmd, waitflag, ccbp->hi_stat));
2247
2248	oldspl = spltty();		/* Keep others out */
2249
2250	/* wait until it's finished what it was doing.. */
2251	while((x = ccbp->hi_stat) != IDLE_OPEN &&
2252			x != IDLE_CLOSE &&
2253			x != cmd) {
2254		if (in_intr) {			/* Prevent sleep in intr */
2255			DPRINT((pp, DBG_PARAM,
2256				"cmd intr collision - completing %d\trequested %d\n",
2257				x, cmd));
2258			splx(oldspl);
2259			return;
2260		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2261				"sicmd1", 1)) {
2262			splx(oldspl);
2263			return;
2264		}
2265	}
2266	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
2267
2268	/* if there was a pending command, cause a state-change wakeup */
2269	if (pp->sp_pend != IDLE_OPEN) {
2270		switch(pp->sp_pend) {
2271		case LOPEN:
2272		case MPEND:
2273		case MOPEN:
2274		case CONFIG:
2275			wakeup(&pp->sp_state);
2276			break;
2277		default:
2278			break;
2279		}
2280	}
2281
2282	pp->sp_pend = cmd;		/* New command pending */
2283	ccbp->hi_stat = cmd;		/* Post it */
2284
2285	if (waitflag) {
2286		if (in_intr) {		/* If in interrupt handler */
2287			DPRINT((pp, DBG_PARAM,
2288				"attempt to sleep in si_intr - cmd req %d\n",
2289				cmd));
2290			splx(oldspl);
2291			return;
2292		} else while(ccbp->hi_stat != IDLE_OPEN) {
2293			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2294			    "sicmd2", 0))
2295				break;
2296		}
2297	}
2298	splx(oldspl);
2299}
2300
2301static void
2302si_disc_optim(tp, t, pp)
2303	struct tty	*tp;
2304	struct termios	*t;
2305	struct si_port	*pp;
2306{
2307	/*
2308	 * XXX can skip a lot more cases if Smarts.  Maybe
2309	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
2310	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2311	 */
2312	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2313	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2314	    && (!(t->c_iflag & PARMRK)
2315		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2316	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2317	    && linesw[tp->t_line].l_rint == ttyinput)
2318		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2319	else
2320		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2321
2322	/*
2323	 * Prepare to reduce input latency for packet
2324	 * discplines with a end of packet character.
2325	 */
2326	if (tp->t_line == SLIPDISC)
2327		pp->sp_hotchar = 0xc0;
2328	else if (tp->t_line == PPPDISC)
2329		pp->sp_hotchar = 0x7e;
2330	else
2331		pp->sp_hotchar = 0;
2332
2333	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
2334		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
2335		pp->sp_hotchar));
2336}
2337
2338
2339#ifdef	SI_DEBUG
2340
2341static void
2342#ifdef __STDC__
2343si_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
2344#else
2345si_dprintf(pp, flags, fmt, va_alist)
2346	struct si_port *pp;
2347	int flags;
2348	char *fmt;
2349#endif
2350{
2351	va_list ap;
2352
2353	if ((pp == NULL && (si_debug&flags)) ||
2354	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
2355	    	if (pp != NULL)
2356	    		printf("%ci%d(%d): ", 's',
2357	    			(int)SI_CARD(pp->sp_tty->t_dev),
2358	    			(int)SI_PORT(pp->sp_tty->t_dev));
2359		va_start(ap, fmt);
2360		vprintf(fmt, ap);
2361		va_end(ap);
2362	}
2363}
2364
2365static char *
2366si_mctl2str(cmd)
2367	enum si_mctl cmd;
2368{
2369	switch (cmd) {
2370	case GET:	return("GET");
2371	case SET:	return("SET");
2372	case BIS:	return("BIS");
2373	case BIC:	return("BIC");
2374	}
2375	return("BAD");
2376}
2377
2378#endif	/* DEBUG */
2379
2380
2381
2382static si_devsw_installed = 0;
2383
2384static void 	si_drvinit(void *unused)
2385{
2386	dev_t dev;
2387
2388	if( ! si_devsw_installed ) {
2389		dev = makedev(CDEV_MAJOR, 0);
2390		cdevsw_add(&dev,&si_cdevsw, NULL);
2391		si_devsw_installed = 1;
2392    	}
2393}
2394
2395SYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
2396
2397