si.c revision 12080
1/*
2 * Device driver for Specialix range (SLXOS) of serial line multiplexors.
3 *
4 * Copyright (C) 1990, 1992 Specialix International,
5 * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
6 * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com>
7 *
8 * Originally derived from:	SunOS 4.x version
9 * Ported from BSDI version to FreeBSD by Peter Wemm.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notices, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notices, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by Andy Rutter of
22 *	Advanced Methods and Tools Ltd. based on original information
23 *	from Specialix International.
24 * 4. Neither the name of Advanced Methods and Tools, nor Specialix
25 *    International may be used to endorse or promote products derived from
26 *    this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
31 * NO EVENT SHALL THE AUTHORS BE LIABLE.
32 *
33 *	$Id: si.c,v 1.12 1995/11/04 13:23:40 bde Exp $
34 */
35
36#ifndef lint
37static char si_copyright1[] =  "@(#) (C) Specialix International, 1990,1992",
38            si_copyright2[] =  "@(#) (C) Andy Rutter 1993",
39            si_copyright3[] =  "@(#) (C) Peter Wemm 1995";
40#endif	/* not lint */
41
42#define	SI_DEBUG			/* turn driver debugging on */
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/ioctl.h>
47#include <sys/tty.h>
48#include <sys/ttydefaults.h>
49#include <sys/proc.h>
50#include <sys/user.h>
51#include <sys/conf.h>
52#include <sys/file.h>
53#include <sys/uio.h>
54#include <sys/dkstat.h>
55#include <sys/kernel.h>
56#include <sys/syslog.h>
57#include <sys/device.h>
58#include <sys/malloc.h>
59#include <sys/devconf.h>
60
61#include <machine/clock.h>
62
63#include <i386/isa/icu.h>
64#include <i386/isa/isa.h>
65#include <i386/isa/isa_device.h>
66
67#include <i386/isa/sireg.h>
68#include <machine/si.h>
69
70#include "si.h"
71
72/*
73 * This device driver is designed to interface the Specialix International
74 * range of serial multiplexor cards (SLXOS) to BSDI/386 on an ISA bus machine.
75 *
76 * The controller is interfaced to the host via dual port ram
77 * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
78 */
79
80#define	POLL		/* turn on poller to generate buffer empty interrupt */
81#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
82#define SI_I_HIGH_WATER	(TTYHOG - SLXOS_BUFFERSIZE)
83
84enum si_mctl { GET, SET, BIS, BIC };
85
86static void si_command __P((struct si_port *, int, int));
87static int si_modem __P((struct si_port *, enum si_mctl, int));
88static void si_write_enable __P((struct si_port *, int));
89static int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
90static void si_start __P((struct tty *));
91static void si_lstart __P((struct si_port *));
92static void si_disc_optim __P((struct tty *tp, struct termios *t,
93					struct si_port *pp));
94static void sihardclose __P((struct si_port *pp));
95static void sidtrwakeup __P((void *chan));
96
97int	siparam __P((struct tty *, struct termios *));
98
99extern	void	si_registerdev __P((struct isa_device *id));
100extern	int	siprobe __P((struct isa_device *id));
101extern	int	siattach __P((struct isa_device *id));
102static	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
103
104#ifdef SI_DEBUG
105static	void	si_dprintf __P((/* XXX should be varargs struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */));
106static	char	*si_mctl2str __P((enum si_mctl cmd));
107#define	DPRINT(x)	si_dprintf x
108#else
109#define	DPRINT(x)	/* void */
110#endif
111
112static int si_Nports;
113static int si_Nmodules;
114static int si_debug = 0;	/* data, not bss, so it's patchable */
115
116static struct tty *si_tty;
117
118/* where the firmware lives */
119extern int si_dsize;
120extern unsigned char si_download[];
121
122struct si_softc {
123	int 		sc_type;	/* adapter type */
124	char 		*sc_typename;	/* adapter type string */
125
126	struct si_port	*sc_ports;	/* port structures for this card */
127
128	caddr_t		sc_paddr;	/* physical addr of iomem */
129	caddr_t		sc_maddr;	/* kvaddr of iomem */
130	int		sc_nport;	/* # ports on this card */
131	int		sc_irq;		/* copy of attach irq */
132	int		sc_eisa_iobase;	/* EISA io port address */
133	int		sc_eisa_irqbits;
134	struct kern_devconf sc_kdc;
135};
136struct si_softc si_softc[NSI];		/* up to 4 elements */
137
138#ifndef B2000	/* not standard */
139# define B2000 2000
140#endif
141static struct speedtab bdrates[] = {
142	B75,	CLK75,		/* 0x0 */
143	B110,	CLK110,		/* 0x1 */
144	B150,	CLK150,		/* 0x3 */
145	B300,	CLK300,		/* 0x4 */
146	B600,	CLK600,		/* 0x5 */
147	B1200,	CLK1200,	/* 0x6 */
148	B2000,	CLK2000,	/* 0x7 */
149	B2400,	CLK2400,	/* 0x8 */
150	B4800,	CLK4800,	/* 0x9 */
151	B9600,	CLK9600,	/* 0xb */
152	B19200,	CLK19200,	/* 0xc */
153	B38400, CLK38400,	/* 0x2 (out of order!) */
154	B57600, CLK57600,	/* 0xd */
155	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
156	-1,	-1
157};
158
159
160/* populated with approx character/sec rates - translated at card
161 * initialisation time to chars per tick of the clock */
162static int done_chartimes = 0;
163static struct speedtab chartimes[] = {
164	B75,	8,
165	B110,	11,
166	B150,	15,
167	B300,	30,
168	B600,	60,
169	B1200,	120,
170	B2000,	200,
171	B2400,	240,
172	B4800,	480,
173	B9600,	960,
174	B19200,	1920,
175	B38400, 3840,
176	B57600, 5760,
177	B115200, 11520,
178	-1,	-1
179};
180static volatile int in_intr = 0;	/* Inside interrupt handler? */
181
182static int si_default_rate =	TTYDEF_SPEED;
183static int si_default_iflag =	0;
184static int si_default_oflag =	0;
185static int si_default_lflag =	0;
186#ifdef SI_DEF_HWFLOW
187static int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
188#else
189static int si_default_cflag =	TTYDEF_CFLAG;
190#endif
191
192#ifdef POLL
193#define	POLL_INTERVAL	(hz/2)
194static int init_finished = 0;
195static void si_poll __P((void *));
196#endif
197
198/*
199 * Array of adapter types and the corresponding RAM size. The order of
200 * entries here MUST match the ordinal of the adapter type.
201 */
202static char *si_type[] = {
203	"EMPTY",
204	"SIHOST",
205	"SI2",				/* MCA */
206	"SIHOST2",
207	"SIEISA",
208};
209
210
211static struct kern_devconf si_kdc[NSI] = { {
212	0, 0, 0,		/* filled in by dev_attach */
213	"si", 0, { MDDT_ISA, 0, "tty" },
214	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
215	&kdc_isa0,		/* parent */
216	0,			/* parent data */
217	DC_UNCONFIGURED,	/* state */
218	"Specialix SI/XIO Host adapter",
219	DC_CLS_SERIAL,		/* class */
220} };
221
222void
223si_registerdev(id)
224	struct isa_device *id;
225{
226	if (id->id_unit != 0) {
227		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
228	}
229	si_kdc[id->id_unit].kdc_unit = id->id_unit;
230	si_kdc[id->id_unit].kdc_isa = id;
231	dev_attach(&si_kdc[id->id_unit]);
232}
233
234/* Look for a valid board at the given mem addr */
235int
236siprobe(id)
237	struct isa_device *id;
238{
239	struct si_softc *sc;
240	int type;
241	u_int i, ramsize;
242	volatile BYTE was, *ux;
243	volatile unsigned char *maddr;
244	unsigned char *paddr;
245
246	si_registerdev(id);
247
248	maddr = id->id_maddr;		/* virtual address... */
249	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
250
251	DPRINT((0, DBG_AUTOBOOT, "SLXOS probe at virtual=0x%x physical=0x%x\n",
252		id->id_maddr, paddr));
253
254	/*
255	 * this is a lie, but it's easier than trying to handle caching
256	 * and ram conflicts in the >1M and <16M region.
257	 */
258	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
259	    (caddr_t)paddr >= (caddr_t)IOM_END) {
260		printf("si%d: iomem (%x) out of range\n",
261			id->id_unit, paddr);
262		return(0);
263	}
264
265	if (id->id_unit >= NSI) {
266		/* THIS IS IMPOSSIBLE */
267		return(0);
268	}
269
270	if (((u_int)paddr & 0x7fff) != 0) {
271		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
272			"si%d: iomem (%x) not on 32k boundary\n",
273			id->id_unit, paddr));
274		return(0);
275	}
276
277
278	for (i=0; i < NSI; i++) {
279		if ((sc = &si_softc[i]) == NULL)
280			continue;
281		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
282			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
283				"si%d: iomem (%x) already configured to si%d\n",
284				id->id_unit, sc->sc_paddr, i));
285			return(0);
286		}
287	}
288
289#if NEISA > 0
290	if (id->id_iobase > 0x0fff) {	/* EISA card */
291		int irq, port;
292		unsigned long base;
293		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
294			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
295
296		port = id->id_iobase;
297		base = (inb(port+1) << 24) | (inb(port) << 16);
298		irq  = ((inb(port+2) >> 4) & 0xf);
299
300		id->id_irq = eisa_irqs[irq];
301
302		DPRINT((0, DBG_AUTOBOOT,
303		    "SLXOS: si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
304		    id->id_unit, base, irq, id->id_irq, port));
305
306		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
307			goto bad_irq;
308
309		id->id_iobase &= 0xf000;
310		id->id_iosize  = 0x0fff;
311
312		type = EISA;
313		outb(p+2, (BYTE)irq << 4);
314
315		sc->sc_eisa_iobase = p;
316		sc->sc_eisa_irqbits = irq << 4;
317		ramsize = SIEISA_RAMSIZE;
318		goto got_card;
319	}
320#endif
321
322	/* Is there anything out there? (0x17 is just an arbitrary number) */
323	*maddr = 0x17;
324	if (*maddr != 0x17) {
325		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
326			"si%d: 0x17 check fail at phys 0x%x\n",
327			id->id_unit, paddr));
328fail:
329		return(0);
330	}
331	/*
332	 * OK, now to see if whatever responded is really an SI card.
333	 * Try for a MK II first (SIHOST2)
334	 */
335	for (i=SIPLSIG; i<SIPLSIG+8; i++)
336		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
337			goto try_mk1;
338
339	/* It must be an SIHOST2 */
340	*(maddr + SIPLRESET) = 0;
341	*(maddr + SIPLIRQCLR) = 0;
342	*(maddr + SIPLIRQSET) = 0x10;
343	type = SIHOST2;
344	ramsize = SIHOST2_RAMSIZE;
345	goto got_card;
346
347	/*
348	 * Its not a MK II, so try for a MK I (SIHOST)
349	 */
350try_mk1:
351	*(maddr+SIRESET) = 0x0;		/* reset the card */
352	*(maddr+SIINTCL) = 0x0;		/* clear int */
353	*(maddr+SIRAM) = 0x17;
354	if (*(maddr+SIRAM) != (BYTE)0x17)
355		goto fail;
356	*(maddr+0x7ff8) = 0x17;
357	if (*(maddr+0x7ff8) != (BYTE)0x17) {
358		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
359			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
360			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
361		goto fail;
362	}
363
364	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
365	type = SIHOST;
366	ramsize = SIHOST_RAMSIZE;
367
368got_card:
369	DPRINT((0, DBG_AUTOBOOT, "SLXOS: found type %d card, try memory test\n", type));
370	/* Try the acid test */
371	ux = (BYTE *)(maddr + SIRAM);
372	for (i=0; i<ramsize; i++, ux++)
373		*ux = (BYTE)(i&0xff);
374	ux = (BYTE *)(maddr + SIRAM);
375	for (i=0; i<ramsize; i++, ux++) {
376		if ((was = *ux) != (BYTE)(i&0xff)) {
377			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
378				"SLXOS si%d: match fail at phys 0x%x, was %x should be %x\n",
379				id->id_unit, paddr+i, was, i&0xff));
380			goto fail;
381		}
382	}
383
384	/* clear out the RAM */
385	ux = (BYTE *)(maddr + SIRAM);
386	for (i=0; i<ramsize; i++)
387		*ux++ = 0;
388	ux = (BYTE *)(maddr + SIRAM);
389	for (i=0; i<ramsize; i++) {
390		if ((was = *ux++) != 0) {
391			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
392				"SLXOS si%d: clear fail at phys 0x%x, was %x\n",
393				id->id_unit, paddr+i, was));
394			goto fail;
395		}
396	}
397
398	/*
399	 * Success, we've found a valid board, now fill in
400	 * the adapter structure.
401	 */
402	switch (type) {
403	case SIHOST2:
404		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
405bad_irq:
406			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
407				"si%d: bad IRQ value - %d\n",
408				id->id_unit, id->id_irq));
409			return(0);
410		}
411		id->id_msize = SIHOST2_MEMSIZE;
412		break;
413	case SIHOST:
414		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
415			goto bad_irq;
416		}
417		id->id_msize = SIHOST_MEMSIZE;
418		break;
419	case SIEISA:
420		id->id_msize = SIEISA_MEMSIZE;
421		break;
422	case SI2:		/* MCA */
423	default:
424		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
425		return(0);
426	}
427	si_softc[id->id_unit].sc_type = type;
428	si_softc[id->id_unit].sc_typename = si_type[type];
429	return(-1);	/* -1 == found */
430}
431
432/*
433 * Attach the device.  Initialize the card.
434 */
435int
436siattach(id)
437	struct isa_device *id;
438{
439	int unit = id->id_unit;
440	struct si_softc *sc = &si_softc[unit];
441	struct si_port *pp;
442	volatile struct si_channel *ccbp;
443	volatile struct si_reg *regp;
444	volatile caddr_t maddr;
445	struct si_module *modp;
446	struct tty *tp;
447	struct speedtab *spt;
448	int nmodule, nport, x, y;
449
450	DPRINT((0, DBG_AUTOBOOT, "SLXOS siattach\n"));
451
452	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
453	sc->sc_maddr = id->id_maddr;
454	sc->sc_irq = id->id_irq;
455
456	sc->sc_ports = NULL;			/* mark as uninitialised */
457
458	maddr = sc->sc_maddr;
459
460	/*
461	 * OK, now lets download the firmware and try and boot the CPU..
462	 */
463
464	DPRINT((0, DBG_DOWNLOAD, "SLXOS si_download: nbytes %d\n", si_dsize));
465	bcopy(si_download, maddr, si_dsize);
466
467	switch (sc->sc_type) {
468	case SIEISA:
469#if NEISA > 0
470		/* modify the Z280 firmware to tell it that it's on an EISA */
471		*(maddr+0x42) = 1;
472		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
473		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
474		break;
475#endif	/* fall-through if not EISA */
476	case SI2:
477		/* must get around to writing the code for
478		 * these one day */
479		return 0;
480	case SIHOST:
481		*(maddr+SIRESET_CL) = 0;
482		*(maddr+SIINTCL_CL) = 0;
483		break;
484	case SIHOST2:
485		*(maddr+SIPLRESET) = 0x10;
486		switch (sc->sc_irq) {
487		case IRQ11:
488			*(maddr+SIPLIRQ11) = 0x10;
489			break;
490		case IRQ12:
491			*(maddr+SIPLIRQ12) = 0x10;
492			break;
493		case IRQ15:
494			*(maddr+SIPLIRQ15) = 0x10;
495			break;
496		}
497		*(maddr+SIPLIRQCLR) = 0x10;
498		break;
499	}
500
501	DELAY(1000000);			/* wait around for a second */
502
503	regp = (struct si_reg *)maddr;
504	y = 0;
505					/* wait max of 5 sec for init OK */
506	while (regp->initstat == 0 && y++ < 10) {
507		DELAY(500000);
508	}
509	switch (regp->initstat) {
510	case 0:
511		printf("si%d: startup timeout - aborting\n", unit);
512		sc->sc_type = NULL;
513		return 0;
514	case 1:
515			/* set throttle to 100 intr per second */
516		regp->int_count = 25000;
517			/* rx intr max of 25 timer per second */
518		regp->rx_int_count = 4;
519		regp->int_pending = 0;		/* no intr pending */
520		regp->int_scounter = 0;	/* reset counter */
521		break;
522	case 0xff:
523		/*
524		 * No modules found, so give up on this one.
525		 */
526		printf("si%d: %s - no ports found\n", unit,
527			si_type[sc->sc_type]);
528		return 0;
529	default:
530		printf("si%d: Z280 version error - initstat %x\n",
531			unit, regp->initstat);
532		return 0;
533	}
534
535	/*
536	 * First time around the ports just count them in order
537	 * to allocate some memory.
538	 */
539	nport = 0;
540	modp = (struct si_module *)(maddr + 0x80);
541	for (;;) {
542		DPRINT((0, DBG_DOWNLOAD, "SLXOS si%d: ccb addr 0x%x\n", unit, modp));
543		switch (modp->sm_type & (~MMASK)) {
544		case M232:
545		case M422:
546			DPRINT((0, DBG_DOWNLOAD,
547				"SLXOS si%d: Found 232/422 module, %d ports\n",
548				unit, (int)(modp->sm_type & MMASK)));
549
550			/* this is a firmware issue */
551			if (si_Nports == SI_MAXPORTPERCARD) {
552				printf("si%d: extra ports ignored\n", unit);
553				continue;
554			}
555
556			x = modp->sm_type & MMASK;
557			nport += x;
558			si_Nports += x;
559			si_Nmodules++;
560			break;
561		default:
562			printf("si%d: unknown module type %d\n",
563				unit, modp->sm_type);
564			break;
565		}
566		if (modp->sm_next == 0)
567			break;
568		modp = (struct si_module *)
569			(maddr + (unsigned)(modp->sm_next & 0x7fff));
570	}
571	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
572		M_DEVBUF, M_NOWAIT);
573	if (sc->sc_ports == 0) {
574mem_fail:
575		printf("si%d: fail to malloc memory for port structs\n",
576			unit);
577		return 0;
578	}
579	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
580	sc->sc_nport = nport;
581
582	/*
583	 * allocate tty structures for ports
584	 */
585	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
586	if (tp == 0)
587		goto mem_fail;
588	bzero(tp, sizeof(*tp) * nport);
589	si_tty = tp;
590
591	/* mark the device state as attached */
592	si_kdc[unit].kdc_state = DC_BUSY;
593
594	/*
595	 * Scan round the ports again, this time initialising.
596	 */
597	pp = sc->sc_ports;
598	nmodule = 0;
599	modp = (struct si_module *)(maddr + 0x80);
600	for (;;) {
601		switch (modp->sm_type & (~MMASK)) {
602		case M232:
603		case M422:
604			nmodule++;
605			nport = (modp->sm_type & MMASK);
606			ccbp = (struct si_channel *)((char *)modp+0x100);
607			for (x = 0; x < nport; x++, pp++, ccbp++) {
608				pp->sp_ccb = ccbp;	/* save the address */
609				pp->sp_tty = tp++;
610				pp->sp_pend = IDLE_CLOSE;
611				pp->sp_flags = 0;
612				pp->sp_state = 0;	/* internal flag */
613				pp->sp_dtr_wait = 3 * hz;
614				pp->sp_iin.c_iflag = si_default_iflag;
615				pp->sp_iin.c_oflag = si_default_oflag;
616				pp->sp_iin.c_cflag = si_default_cflag;
617				pp->sp_iin.c_lflag = si_default_lflag;
618				termioschars(&pp->sp_iin);
619				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
620					si_default_rate;
621				pp->sp_iout = pp->sp_iin;
622			}
623			break;
624		default:
625			break;
626		}
627		if (modp->sm_next == 0) {
628			printf("si%d: card: %s, ports: %d, modules: %d\n",
629				unit,
630				sc->sc_typename,
631				sc->sc_nport,
632				nmodule);
633			break;
634		}
635		modp = (struct si_module *)
636			(maddr + (unsigned)(modp->sm_next & 0x7fff));
637	}
638	if (done_chartimes == 0) {
639		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
640			if ((spt->sp_code /= hz) == 0)
641				spt->sp_code = 1;
642		}
643		done_chartimes = 1;
644	}
645	return (1);
646}
647
648struct isa_driver sidriver =
649	{ siprobe, siattach, "si" };
650
651
652int
653siopen(dev, flag, mode, p)
654	dev_t dev;
655	int flag, mode;
656	struct proc *p;
657{
658	int oldspl, error;
659	int card, port;
660	register struct si_softc *sc;
661	register struct tty *tp;
662	volatile struct si_channel *ccbp;
663	struct si_port *pp;
664	int mynor = minor(dev);
665
666	/* quickly let in /dev/si_control */
667	if (IS_CONTROLDEV(mynor)) {
668		if (error = suser(p->p_ucred, &p->p_acflag))
669			return(error);
670		return(0);
671	}
672
673	card = SI_CARD(mynor);
674	if (card >= NSI)
675		return (ENXIO);
676	sc = &si_softc[card];
677
678	if (sc->sc_type == NULL) {
679		DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: type %s??\n",
680			card, sc->sc_typename));
681		return(ENXIO);
682	}
683
684	port = SI_PORT(mynor);
685	if (port >= sc->sc_nport) {
686		DPRINT((0, DBG_OPEN|DBG_FAIL, "SLXOS si%d: nports %d\n",
687			card, sc->sc_nport));
688		return(ENXIO);
689	}
690
691#ifdef	POLL
692	/*
693	 * We've now got a device, so start the poller.
694	 */
695	if (init_finished == 0) {
696		timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
697		init_finished = 1;
698	}
699#endif
700
701	/* initial/lock device */
702	if (IS_STATE(mynor)) {
703		return(0);
704	}
705
706	pp = sc->sc_ports + port;
707	tp = pp->sp_tty;			/* the "real" tty */
708	ccbp = pp->sp_ccb;			/* Find control block */
709	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
710		dev, flag, mode, p));
711
712	oldspl = spltty();			/* Keep others out */
713	error = 0;
714
715open_top:
716	while (pp->sp_state & SS_DTR_OFF) {
717		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
718		if (error != 0)
719			goto out;
720	}
721
722	if (tp->t_state & TS_ISOPEN) {
723		/*
724		 * The device is open, so everything has been initialised.
725		 * handle conflicts.
726		 */
727		if (IS_CALLOUT(mynor)) {
728			if (!pp->sp_active_out) {
729				error = EBUSY;
730				goto out;
731			}
732		} else {
733			if (pp->sp_active_out) {
734				if (flag & O_NONBLOCK) {
735					error = EBUSY;
736					goto out;
737				}
738				error = tsleep(&pp->sp_active_out,
739						TTIPRI|PCATCH, "sibi", 0);
740				if (error != 0)
741					goto out;
742				goto open_top;
743			}
744		}
745		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
746			DPRINT((pp, DBG_OPEN|DBG_FAIL,
747				"already open and EXCLUSIVE set\n"));
748			error = EBUSY;
749			goto out;
750		}
751	} else {
752		/*
753		 * The device isn't open, so there are no conflicts.
754		 * Initialize it. Avoid sleep... :-)
755		 */
756		DPRINT((pp, DBG_OPEN, "first open\n"));
757		tp->t_oproc = si_start;
758		tp->t_param = siparam;
759		tp->t_dev = dev;
760		tp->t_termios = mynor & SI_CALLOUT_MASK
761				? pp->sp_iout : pp->sp_iin;
762
763		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
764
765		++pp->sp_wopeners;	/* in case of sleep in siparam */
766
767		error = siparam(tp, &tp->t_termios);
768
769		--pp->sp_wopeners;
770		if (error != 0)
771			goto out;
772		/* XXX: we should goto_top if siparam slept */
773
774		ttsetwater(tp);
775
776		/* set initial DCD state */
777		pp->sp_last_hi_ip = ccbp->hi_ip;
778		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
779			(*linesw[tp->t_line].l_modem)(tp, 1);
780		}
781	}
782
783	/* whoops! we beat the close! */
784	if (pp->sp_state & SS_CLOSING) {
785		/* try and stop it from proceeding to bash the hardware */
786		pp->sp_state &= ~SS_CLOSING;
787	}
788
789	/*
790	 * Wait for DCD if necessary
791	 */
792	if (!(tp->t_state & TS_CARR_ON)
793	    && !IS_CALLOUT(mynor)
794	    && !(tp->t_cflag & CLOCAL)
795	    && !(flag & O_NONBLOCK)) {
796		++pp->sp_wopeners;
797		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
798		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
799		--pp->sp_wopeners;
800		if (error != 0)
801			goto out;
802		goto open_top;
803	}
804
805	error = (*linesw[tp->t_line].l_open)(dev, tp);
806	si_disc_optim(tp, &tp->t_termios, pp);
807	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
808		pp->sp_active_out = TRUE;
809
810	pp->sp_state |= SS_OPEN;	/* made it! */
811
812out:
813	splx(oldspl);
814
815	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
816
817	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
818		sihardclose(pp);
819
820	return(error);
821}
822
823int
824siclose(dev, flag, mode, p)
825	dev_t dev;
826	int flag, mode;
827	struct proc *p;
828{
829	register struct si_port *pp;
830	register struct tty *tp;
831	int oldspl;
832	int error = 0;
833	int mynor = minor(dev);
834
835	if (IS_SPECIAL(mynor))
836		return(0);
837
838	oldspl = spltty();
839
840	pp = MINOR2PP(mynor);
841	tp = pp->sp_tty;
842
843	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
844		dev, flag, mode, p, pp->sp_state));
845
846	/* did we sleep and loose a race? */
847	if (pp->sp_state & SS_CLOSING) {
848		/* error = ESOMETING? */
849		goto out;
850	}
851
852	/* begin race detection.. */
853	pp->sp_state |= SS_CLOSING;
854
855	si_write_enable(pp, 0);		/* block writes for ttywait() */
856
857	/* THIS MAY SLEEP IN TTYWAIT!!! */
858	(*linesw[tp->t_line].l_close)(tp, flag);
859
860	si_write_enable(pp, 1);
861
862	/* did we sleep and somebody started another open? */
863	if (!(pp->sp_state & SS_CLOSING)) {
864		/* error = ESOMETING? */
865		goto out;
866	}
867	/* ok. we are now still on the right track.. nuke the hardware */
868
869	if (pp->sp_state & SS_LSTART) {
870		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
871		pp->sp_state &= ~SS_LSTART;
872	}
873
874	sistop(tp, FREAD | FWRITE);
875
876	sihardclose(pp);
877	ttyclose(tp);
878	pp->sp_state &= ~SS_OPEN;
879
880out:
881	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
882	splx(oldspl);
883	return(error);
884}
885
886static void
887sihardclose(pp)
888	struct si_port *pp;
889{
890	int oldspl;
891	struct tty *tp;
892	volatile struct si_channel *ccbp;
893
894	oldspl = spltty();
895
896	tp = pp->sp_tty;
897	ccbp = pp->sp_ccb;			/* Find control block */
898	if (tp->t_cflag & HUPCL
899	    || !pp->sp_active_out
900	       && !(ccbp->hi_ip & IP_DCD)
901	       && !(pp->sp_iin.c_cflag && CLOCAL)
902	    || !(tp->t_state & TS_ISOPEN)) {
903
904		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
905		(void) si_command(pp, FCLOSE, SI_NOWAIT);
906
907		if (pp->sp_dtr_wait != 0) {
908			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
909			pp->sp_state |= SS_DTR_OFF;
910		}
911
912	}
913	pp->sp_active_out = FALSE;
914	wakeup((caddr_t)&pp->sp_active_out);
915	wakeup(TSA_CARR_ON(tp));
916
917	splx(oldspl);
918}
919
920
921/*
922 * called at splsoftclock()...
923 */
924static void
925sidtrwakeup(chan)
926	void *chan;
927{
928	struct si_port *pp;
929	int oldspl;
930
931	oldspl = spltty();
932
933	pp = (struct si_port *)chan;
934	pp->sp_state &= ~SS_DTR_OFF;
935	wakeup(&pp->sp_dtr_wait);
936
937	splx(oldspl);
938}
939
940/*
941 * User level stuff - read and write
942 */
943int
944siread(dev, uio, flag)
945	register dev_t dev;
946	struct uio *uio;
947	int flag;
948{
949	register struct tty *tp;
950	int mynor = minor(dev);
951
952	if (IS_SPECIAL(mynor)) {
953		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
954		return(ENODEV);
955	}
956	tp = MINOR2TP(mynor);
957	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
958		"siread(%x,%x,%x)\n", dev, uio, flag));
959	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
960}
961
962
963int
964siwrite(dev, uio, flag)
965	dev_t dev;
966	struct uio *uio;
967	int flag;
968{
969	register struct si_port *pp;
970	register struct tty *tp;
971	int error = 0;
972	int mynor = minor(dev);
973	int oldspl;
974
975	if (IS_SPECIAL(mynor)) {
976		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
977		return(ENODEV);
978	}
979	pp = MINOR2PP(mynor);
980	tp = pp->sp_tty;
981	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
982
983	oldspl = spltty();
984	/*
985	 * If writes are currently blocked, wait on the "real" tty
986	 */
987	while (pp->sp_state & SS_BLOCKWRITE) {
988		pp->sp_state |= SS_WAITWRITE;
989		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
990		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
991				     "siwrite", 0))
992			goto out;
993	}
994
995	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
996out:
997	splx(oldspl);
998	return (error);
999}
1000
1001
1002struct tty *
1003sidevtotty(dev_t dev)
1004{
1005	struct si_port *pp;
1006	int mynor = minor(dev);
1007	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
1008
1009	if (IS_SPECIAL(mynor))
1010		return(NULL);
1011	if (SI_PORT(mynor) >= sc->sc_nport)
1012		return(NULL);
1013	pp = MINOR2PP(mynor);
1014	return (pp->sp_tty);
1015}
1016
1017int
1018siioctl(dev, cmd, data, flag, p)
1019	dev_t dev;
1020	int cmd;
1021	caddr_t data;
1022	int flag;
1023	struct proc *p;
1024{
1025	struct si_port *pp;
1026	register struct tty *tp;
1027	int error;
1028	int mynor = minor(dev);
1029	int oldspl;
1030	int blocked = 0;
1031#if defined(COMPAT_43)
1032	int oldcmd;
1033	struct termios term;
1034#endif
1035
1036	if (IS_SI_IOCTL(cmd))
1037		return(si_Sioctl(dev, cmd, data, flag, p));
1038
1039	pp = MINOR2PP(mynor);
1040	tp = pp->sp_tty;
1041
1042	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
1043		dev, cmd, data, flag));
1044	if (IS_STATE(mynor)) {
1045		struct termios *ct;
1046
1047		switch (mynor & SI_STATE_MASK) {
1048		case SI_INIT_STATE_MASK:
1049			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1050			break;
1051		case SI_LOCK_STATE_MASK:
1052			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1053			break;
1054		default:
1055			return (ENODEV);
1056		}
1057		switch (cmd) {
1058		case TIOCSETA:
1059			error = suser(p->p_ucred, &p->p_acflag);
1060			if (error != 0)
1061				return (error);
1062			*ct = *(struct termios *)data;
1063			return (0);
1064		case TIOCGETA:
1065			*(struct termios *)data = *ct;
1066			return (0);
1067		case TIOCGETD:
1068			*(int *)data = TTYDISC;
1069			return (0);
1070		case TIOCGWINSZ:
1071			bzero(data, sizeof(struct winsize));
1072			return (0);
1073		default:
1074			return (ENOTTY);
1075		}
1076	}
1077	/*
1078	 * Do the old-style ioctl compat routines...
1079	 */
1080#if defined(COMPAT_43)
1081	term = tp->t_termios;
1082	oldcmd = cmd;
1083	error = ttsetcompat(tp, &cmd, data, &term);
1084	if (error != 0)
1085		return (error);
1086	if (cmd != oldcmd)
1087		data = (caddr_t)&term;
1088#endif
1089	/*
1090	 * Do the initial / lock state business
1091	 */
1092	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1093		int     cc;
1094		struct termios *dt = (struct termios *)data;
1095		struct termios *lt = mynor & SI_CALLOUT_MASK
1096				     ? &pp->sp_lout : &pp->sp_lin;
1097
1098		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1099			| (dt->c_iflag & ~lt->c_iflag);
1100		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1101			| (dt->c_oflag & ~lt->c_oflag);
1102		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1103			| (dt->c_cflag & ~lt->c_cflag);
1104		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1105			| (dt->c_lflag & ~lt->c_lflag);
1106		for (cc = 0; cc < NCCS; ++cc)
1107			if (lt->c_cc[cc] != 0)
1108				dt->c_cc[cc] = tp->t_cc[cc];
1109		if (lt->c_ispeed != 0)
1110			dt->c_ispeed = tp->t_ispeed;
1111		if (lt->c_ospeed != 0)
1112			dt->c_ospeed = tp->t_ospeed;
1113	}
1114
1115	/*
1116	 * Block user-level writes to give the ttywait()
1117	 * a chance to completely drain for commands
1118	 * that require the port to be in a quiescent state.
1119	 */
1120	switch (cmd) {
1121	case TIOCSETAW: case TIOCSETAF:
1122	case TIOCDRAIN: case TIOCSETP:
1123		blocked++;	/* block writes for ttywait() and siparam() */
1124		si_write_enable(pp, 0);
1125	}
1126
1127	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1128	if (error >= 0)
1129		goto out;
1130
1131	oldspl = spltty();
1132
1133	error = ttioctl(tp, cmd, data, flag);
1134	si_disc_optim(tp, &tp->t_termios, pp);
1135	if (error >= 0)
1136		goto outspl;
1137
1138	switch (cmd) {
1139	case TIOCSBRK:
1140		si_command(pp, SBREAK, SI_NOWAIT);
1141		break;
1142	case TIOCCBRK:
1143		si_command(pp, EBREAK, SI_NOWAIT);
1144		break;
1145	case TIOCSDTR:
1146		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1147		break;
1148	case TIOCCDTR:
1149		(void) si_modem(pp, SET, 0);
1150		break;
1151	case TIOCMSET:
1152		(void) si_modem(pp, SET, *(int *)data);
1153		break;
1154	case TIOCMBIS:
1155		(void) si_modem(pp, BIS, *(int *)data);
1156		break;
1157	case TIOCMBIC:
1158		(void) si_modem(pp, BIC, *(int *)data);
1159		break;
1160	case TIOCMGET:
1161		*(int *)data = si_modem(pp, GET, 0);
1162		break;
1163	case TIOCMSDTRWAIT:
1164		/* must be root since the wait applies to following logins */
1165		error = suser(p->p_ucred, &p->p_acflag);
1166		if (error != 0) {
1167			goto outspl;
1168		}
1169		pp->sp_dtr_wait = *(int *)data * hz / 100;
1170		break;
1171	case TIOCMGDTRWAIT:
1172		*(int *)data = pp->sp_dtr_wait * 100 / hz;
1173		break;
1174
1175	default:
1176		error = ENOTTY;
1177	}
1178	error = 0;
1179outspl:
1180	splx(oldspl);
1181out:
1182	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
1183	if (blocked)
1184		si_write_enable(pp, 1);
1185	return(error);
1186}
1187
1188/*
1189 * Handle the Specialix ioctls. All MUST be called via the CONTROL device
1190 */
1191static int
1192si_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
1193{
1194	struct si_softc *xsc;
1195	register struct si_port *xpp;
1196	volatile struct si_reg *regp;
1197	struct si_tcsi *dp;
1198	struct si_pstat *sps;
1199	int *ip, error = 0;
1200	int oldspl;
1201	int card, port;
1202	int mynor = minor(dev);
1203
1204	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
1205		dev, cmd, data, flag));
1206
1207#if 1
1208	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
1209	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
1210	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
1211#endif
1212
1213	if (!IS_CONTROLDEV(mynor)) {
1214		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
1215		return(ENODEV);
1216	}
1217
1218	oldspl = spltty();	/* better safe than sorry */
1219
1220	ip = (int *)data;
1221
1222#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
1223
1224	switch (cmd) {
1225	case TCSIPORTS:
1226		*ip = si_Nports;
1227		goto out;
1228	case TCSIMODULES:
1229		*ip = si_Nmodules;
1230		goto out;
1231	case TCSISDBG_ALL:
1232		SUCHECK;
1233		si_debug = *ip;
1234		goto out;
1235	case TCSIGDBG_ALL:
1236		*ip = si_debug;
1237		goto out;
1238	default:
1239		/*
1240		 * Check that a controller for this port exists
1241		 */
1242
1243		/* may also be a struct si_pstat, a superset of si_tcsi */
1244
1245		dp = (struct si_tcsi *)data;
1246		sps = (struct si_pstat *)data;
1247		card = dp->tc_card;
1248		xsc = &si_softc[card];	/* check.. */
1249		if (card < 0 || card >= NSI || xsc->sc_type == NULL) {
1250			error = ENOENT;
1251			goto out;
1252		}
1253		/*
1254		 * And check that a port exists
1255		 */
1256		port = dp->tc_port;
1257		if (port < 0 || port >= xsc->sc_nport) {
1258			error = ENOENT;
1259			goto out;
1260		}
1261		xpp = xsc->sc_ports + port;
1262		regp = (struct si_reg *)xsc->sc_maddr;
1263	}
1264
1265	switch (cmd) {
1266	case TCSIDEBUG:
1267#ifdef	SI_DEBUG
1268		SUCHECK;
1269		if (xpp->sp_debug)
1270			xpp->sp_debug = 0;
1271		else {
1272			xpp->sp_debug = DBG_ALL;
1273			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
1274				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
1275		}
1276		break;
1277#else
1278		error = ENODEV;
1279		goto out;
1280#endif
1281	case TCSISDBG_LEVEL:
1282	case TCSIGDBG_LEVEL:
1283#ifdef	SI_DEBUG
1284		if (cmd == TCSIGDBG_LEVEL) {
1285			dp->tc_dbglvl = xpp->sp_debug;
1286		} else {
1287			SUCHECK;
1288			xpp->sp_debug = dp->tc_dbglvl;
1289		}
1290		break;
1291#else
1292		error = ENODEV;
1293		goto out;
1294#endif
1295	case TCSIGRXIT:
1296		dp->tc_int = regp->rx_int_count;
1297		break;
1298	case TCSIRXIT:
1299		SUCHECK;
1300		regp->rx_int_count = dp->tc_int;
1301		break;
1302	case TCSIGIT:
1303		dp->tc_int = regp->int_count;
1304		break;
1305	case TCSIIT:
1306		SUCHECK;
1307		regp->int_count = dp->tc_int;
1308		break;
1309	case TCSISTATE:
1310		dp->tc_int = xpp->sp_ccb->hi_ip;
1311		break;
1312	/* these next three use a different structure */
1313	case TCSI_PORT:
1314		SUCHECK;
1315		sps->tc_siport = *xpp;
1316		break;
1317	case TCSI_CCB:
1318		SUCHECK;
1319		sps->tc_ccb = *xpp->sp_ccb;
1320		break;
1321	case TCSI_TTY:
1322		SUCHECK;
1323		sps->tc_tty = *xpp->sp_tty;
1324		break;
1325	default:
1326		error = EINVAL;
1327		goto out;
1328	}
1329out:
1330	splx(oldspl);
1331	return(error);		/* success */
1332}
1333
1334/*
1335 *	siparam()	: Configure line params
1336 *	called at spltty();
1337 *	this may sleep, does not flush, nor wait for drain, nor block writes
1338 *	caller must arrange this if it's important..
1339 */
1340int
1341siparam(tp, t)
1342	register struct tty *tp;
1343	register struct termios *t;
1344{
1345	register struct si_port *pp = TP2PP(tp);
1346	volatile struct si_channel *ccbp;
1347	int oldspl, cflag, iflag, oflag, lflag;
1348	int error = 0;		/* shutup gcc */
1349	int ispeed = 0;		/* shutup gcc */
1350	int ospeed = 0;		/* shutup gcc */
1351	BYTE val;
1352
1353	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
1354	cflag = t->c_cflag;
1355	iflag = t->c_iflag;
1356	oflag = t->c_oflag;
1357	lflag = t->c_lflag;
1358	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
1359		oflag, cflag, iflag, lflag));
1360
1361
1362	/* if not hung up.. */
1363	if (t->c_ospeed != 0) {
1364		/* translate baud rate to firmware values */
1365		ospeed = ttspeedtab(t->c_ospeed, bdrates);
1366		ispeed = t->c_ispeed ?
1367			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
1368
1369		/* enforce legit baud rate */
1370		if (ospeed < 0 || ispeed < 0)
1371			return (EINVAL);
1372	}
1373
1374
1375	oldspl = spltty();
1376
1377	ccbp = pp->sp_ccb;
1378
1379	/* ========== set hi_break ========== */
1380	val = 0;
1381	if (iflag & IGNBRK)		/* Breaks */
1382		val |= BR_IGN;
1383	if (iflag & BRKINT)		/* Interrupt on break? */
1384		val |= BR_INT;
1385	if (iflag & PARMRK)		/* Parity mark? */
1386		val |= BR_PARMRK;
1387	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
1388		val |= BR_PARIGN;
1389	ccbp->hi_break = val;
1390
1391	/* ========== set hi_csr ========== */
1392	/* if not hung up.. */
1393	if (t->c_ospeed != 0) {
1394		/* Set I/O speeds */
1395		 val = (ispeed << 4) | ospeed;
1396	}
1397	ccbp->hi_csr = val;
1398
1399	/* ========== set hi_mr2 ========== */
1400	val = 0;
1401	if (cflag & CSTOPB)				/* Stop bits */
1402		val |= MR2_2_STOP;
1403	else
1404		val |= MR2_1_STOP;
1405	/*
1406	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1407	 * a DCE, hence the reverse sense of RTS and CTS
1408	 */
1409	/* Output Flow - RTS must be raised before data can be sent */
1410	if (cflag & CCTS_OFLOW)
1411		val |= MR2_RTSCONT;
1412
1413	ccbp->hi_mr1 = val;
1414
1415	/* ========== set hi_mr1 ========== */
1416	val = 0;
1417	if (!(cflag & PARENB))				/* Parity */
1418		val |= MR1_NONE;
1419	else
1420		val |= MR1_WITH;
1421	if (cflag & PARODD)
1422		val |= MR1_ODD;
1423
1424	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1425		val |= MR1_8_BITS;
1426	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1427		val |= MR1_7_BITS;
1428	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1429		val |= MR1_6_BITS;
1430	} else {					/* Must be 5 */
1431		val |= MR1_5_BITS;
1432	}
1433	/*
1434	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1435	 * a DCE, hence the reverse sense of RTS and CTS
1436	 */
1437	/* Input Flow - CTS is raised when port is ready to receive data */
1438	if (cflag & CRTS_IFLOW)
1439		val |= MR1_CTSCONT;
1440
1441	ccbp->hi_mr1 = val;
1442
1443	/* ========== set hi_mask ========== */
1444	val = 0xff;
1445	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1446		val &= 0xFF;
1447	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1448		val &= 0x7F;
1449	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1450		val &= 0x3F;
1451	} else {					/* Must be 5 */
1452		val &= 0x1F;
1453	}
1454	if (iflag & ISTRIP)
1455		val &= 0x7F;
1456
1457	ccbp->hi_mask = val;
1458
1459	/* ========== set hi_prtcl ========== */
1460	val = 0;
1461				/* Monitor DCD etc. if a modem */
1462	if (!(cflag & CLOCAL))
1463		val |= SP_DCEN;
1464	if (iflag & IXANY)
1465		val |= SP_TANY;
1466	if (iflag & IXON)
1467		val |= SP_TXEN;
1468	if (iflag & IXOFF)
1469		val |= SP_RXEN;
1470	if (iflag & INPCK)
1471		val |= SP_PAEN;
1472
1473	ccbp->hi_prtcl = val;
1474
1475
1476	/* ========== set hi_{rx|tx}{on|off} ========== */
1477	/* XXX: the card TOTALLY shields us from the flow control... */
1478	ccbp->hi_txon = t->c_cc[VSTART];
1479	ccbp->hi_txoff = t->c_cc[VSTOP];
1480
1481	ccbp->hi_rxon = t->c_cc[VSTART];
1482	ccbp->hi_rxoff = t->c_cc[VSTOP];
1483
1484	/* ========== send settings to the card ========== */
1485	/* potential sleep here */
1486	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
1487		si_command(pp, LOPEN, SI_WAIT);		/* open it */
1488	else
1489		si_command(pp, CONFIG, SI_WAIT);	/* change params */
1490
1491	/* ========== set DTR etc ========== */
1492	/* Hangup if ospeed == 0 */
1493	if (t->c_ospeed == 0) {
1494		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
1495	} else {
1496		/*
1497		 * If the previous speed was 0, may need to re-enable
1498	 	 * the modem signals
1499	 	 */
1500		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1501	}
1502
1503	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
1504		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
1505
1506	splx(oldspl);
1507out:
1508	return(error);
1509}
1510
1511/*
1512 * Enable or Disable the writes to this channel...
1513 * "state" ->  enabled = 1; disabled = 0;
1514 */
1515static void
1516si_write_enable(pp, state)
1517	register struct si_port *pp;
1518	int state;
1519{
1520	int oldspl;
1521
1522	oldspl = spltty();
1523
1524	if (state) {
1525		pp->sp_state &= ~SS_BLOCKWRITE;
1526		if (pp->sp_state & SS_WAITWRITE) {
1527			pp->sp_state &= ~SS_WAITWRITE;
1528			/* thunder away! */
1529			wakeup((caddr_t)pp);
1530		}
1531	} else {
1532		pp->sp_state |= SS_BLOCKWRITE;
1533	}
1534
1535	splx(oldspl);
1536}
1537
1538/*
1539 * Set/Get state of modem control lines.
1540 * Due to DCE-like behaviour of the adapter, some signals need translation:
1541 *	TIOCM_DTR	DSR
1542 *	TIOCM_RTS	CTS
1543 */
1544static int
1545si_modem(pp, cmd, bits)
1546	struct si_port *pp;
1547	enum si_mctl cmd;
1548	int bits;
1549{
1550	volatile struct si_channel *ccbp;
1551	int x;
1552
1553	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
1554	ccbp = pp->sp_ccb;		/* Find channel address */
1555	switch (cmd) {
1556	case GET:
1557		x = ccbp->hi_ip;
1558		bits = TIOCM_LE;
1559		if (x & IP_DCD)		bits |= TIOCM_CAR;
1560		if (x & IP_DTR)		bits |= TIOCM_DTR;
1561		if (x & IP_RTS)		bits |= TIOCM_RTS;
1562		if (x & IP_RI)		bits |= TIOCM_RI;
1563		return(bits);
1564	case SET:
1565		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
1566		/* fall through */
1567	case BIS:
1568		x = 0;
1569		if (bits & TIOCM_DTR)
1570			x |= OP_DSR;
1571		if (bits & TIOCM_RTS)
1572			x |= OP_CTS;
1573		ccbp->hi_op |= x;
1574		break;
1575	case BIC:
1576		if (bits & TIOCM_DTR)
1577			ccbp->hi_op &= ~OP_DSR;
1578		if (bits & TIOCM_RTS)
1579			ccbp->hi_op &= ~OP_CTS;
1580	}
1581	return 0;
1582}
1583
1584/*
1585 * Handle change of modem state
1586 */
1587static void
1588si_modem_state(pp, tp, hi_ip)
1589	register struct si_port *pp;
1590	register struct tty *tp;
1591	register int hi_ip;
1592{
1593							/* if a modem dev */
1594	if (hi_ip & IP_DCD) {
1595		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
1596			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
1597				tp->t_line));
1598			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
1599		}
1600	} else {
1601		if (pp->sp_last_hi_ip & IP_DCD) {
1602			DPRINT((pp, DBG_INTR, "modem carr off\n"));
1603			if ((*linesw[tp->t_line].l_modem)(tp, 0))
1604				(void) si_modem(pp, SET, 0);
1605		}
1606	}
1607	pp->sp_last_hi_ip = hi_ip;
1608
1609}
1610
1611/*
1612 * Poller to catch missed interrupts.
1613 */
1614#ifdef POLL
1615static void
1616si_poll(void *nothing)
1617{
1618	register struct si_softc *sc;
1619	register int i;
1620	volatile struct si_reg *regp;
1621	int lost, oldspl;
1622
1623	DPRINT((0, DBG_POLL, "si_poll()\n"));
1624	oldspl = spltty();
1625	if (in_intr)
1626		goto out;
1627	lost = 0;
1628	for (i=0; i<NSI; i++) {
1629		sc = &si_softc[i];
1630		if (sc->sc_type == NULL)
1631			continue;
1632		regp = (struct si_reg *)sc->sc_maddr;
1633		/*
1634		 * See if there has been a pending interrupt for 2 seconds
1635		 * or so. The test <int_scounter >= 200) won't correspond
1636		 * to 2 seconds if int_count gets changed.
1637		 */
1638		if (regp->int_pending != 0) {
1639			if (regp->int_scounter >= 200 &&
1640			    regp->initstat == 1) {
1641				printf("SLXOS si%d: lost intr\n", i);
1642				lost++;
1643			}
1644		} else {
1645			regp->int_scounter = 0;
1646		}
1647
1648	}
1649	if (lost)
1650		siintr(-1);	/* call intr with fake vector */
1651out:
1652	splx(oldspl);
1653
1654	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
1655}
1656#endif	/* ifdef POLL */
1657
1658/*
1659 * The interrupt handler polls ALL ports on ALL adapters each time
1660 * it is called.
1661 */
1662
1663static BYTE rxbuf[SLXOS_BUFFERSIZE];	/* input staging area */
1664
1665void
1666siintr(int unit)
1667{
1668	register struct si_softc *sc;
1669
1670	register struct si_port *pp;
1671	volatile struct si_channel *ccbp;
1672	register struct tty *tp;
1673	volatile caddr_t maddr;
1674	BYTE op, ip;
1675	int x, card, port, n, i;
1676	volatile BYTE *z;
1677	BYTE c;
1678
1679	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
1680	if (in_intr) {
1681		if (unit < 0)	/* should never happen */
1682			return;
1683		printf("SLXOS si%d: Warning interrupt handler re-entered\n",
1684			unit);
1685		return;
1686	}
1687	in_intr = 1;
1688
1689	/*
1690	 * When we get an int we poll all the channels and do ALL pending
1691	 * work, not just the first one we find. This allows all cards to
1692	 * share the same vector.
1693	 */
1694	for (card=0; card < NSI; card++) {
1695		sc = &si_softc[card];
1696		if (sc->sc_type == NULL)
1697			continue;
1698		switch(sc->sc_type) {
1699		case SIHOST :
1700			maddr = sc->sc_maddr;
1701			((volatile struct si_reg *)maddr)->int_pending = 0;
1702							/* flag nothing pending */
1703			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
1704			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
1705			break;
1706		case SIHOST2:
1707			maddr = sc->sc_maddr;
1708			((volatile struct si_reg *)maddr)->int_pending = 0;
1709			*(maddr+SIPLIRQCLR) = 0x00;
1710			*(maddr+SIPLIRQCLR) = 0x10;
1711			break;
1712		case SIEISA:
1713#if NEISA > 0
1714			maddr = sc->sc_maddr;
1715			((volatile struct si_reg *)maddr)->int_pending = 0;
1716			(void)inb(sc->sc_eisa_iobase+3);
1717			break;
1718#endif	/* fall through if not EISA kernel */
1719		case SIEMPTY:
1720		default:
1721			continue;
1722		}
1723		((volatile struct si_reg *)maddr)->int_scounter = 0;
1724
1725		for (pp = sc->sc_ports, port=0;
1726		     port < sc->sc_nport;
1727		     pp++, port++) {
1728			ccbp = pp->sp_ccb;
1729			tp = pp->sp_tty;
1730
1731			/*
1732			 * See if a command has completed ?
1733			 */
1734			if (ccbp->hi_stat != pp->sp_pend) {
1735				DPRINT((pp, DBG_INTR,
1736					"siintr hi_stat = 0x%x, pend = %d\n",
1737					ccbp->hi_stat, pp->sp_pend));
1738				switch(pp->sp_pend) {
1739				case LOPEN:
1740				case MPEND:
1741				case MOPEN:
1742				case CONFIG:
1743					pp->sp_pend = ccbp->hi_stat;
1744						/* sleeping in si_command */
1745					wakeup(&pp->sp_state);
1746					break;
1747				default:
1748					pp->sp_pend = ccbp->hi_stat;
1749				}
1750	 		}
1751
1752			/*
1753			 * Continue on if it's closed
1754			 */
1755			if (ccbp->hi_stat == IDLE_CLOSE) {
1756				continue;
1757			}
1758
1759			/*
1760			 * Do modem state change if not a local device
1761			 */
1762			si_modem_state(pp, tp, ccbp->hi_ip);
1763
1764			/*
1765			 * Do break processing
1766			 */
1767			if (ccbp->hi_state & ST_BREAK) {
1768				if (tp->t_state & TS_CONNECTED &&
1769				    tp->t_state & TS_ISOPEN) {
1770					(*linesw[tp->t_line].l_rint)(TTY_BI, tp);
1771				}
1772				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
1773				DPRINT((pp, DBG_INTR, "si_intr break\n"));
1774			}
1775
1776			/*
1777			 * Do RX stuff - if not open then
1778			 * dump any characters.
1779			 */
1780
1781			if ((tp->t_state & TS_CONNECTED) == 0 ||
1782			    (tp->t_state & TS_ISOPEN) == 0) {
1783				ccbp->hi_rxopos = ccbp->hi_rxipos;
1784			} else {
1785				while ((c = ccbp->hi_rxipos - ccbp->hi_rxopos) != 0) {
1786
1787					op = ccbp->hi_rxopos;
1788					ip = ccbp->hi_rxipos;
1789					n = c & 0xff;
1790
1791					DPRINT((pp, DBG_INTR,
1792						"n = %d, op = %d, ip = %d\n",
1793						n, op, ip));
1794					if (n <= SLXOS_BUFFERSIZE - op) {
1795
1796						DPRINT((pp, DBG_INTR,
1797							"\tsingle copy\n"));
1798						z = ccbp->hi_rxbuf + op;
1799						bcopy((caddr_t)z, rxbuf, n);
1800
1801						op += n;
1802					} else {
1803						x = SLXOS_BUFFERSIZE - op;
1804
1805						DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
1806						z = ccbp->hi_rxbuf + op;
1807						bcopy((caddr_t)z, rxbuf, x);
1808
1809						DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
1810						z = ccbp->hi_rxbuf;
1811						bcopy((caddr_t)z, rxbuf+x, n-x);
1812
1813						op += n;
1814					}
1815
1816					ccbp->hi_rxopos = op;
1817
1818					DPRINT((pp, DBG_INTR,
1819						"n = %d, op = %d, ip = %d\n",
1820						n, op, ip));
1821
1822					/*
1823					 * at this point...
1824					 * n = number of chars placed in rxbuf
1825					 */
1826		/*
1827		 * Avoid the grotesquely inefficient lineswitch routine
1828		 * (ttyinput) in "raw" mode.  It usually takes about 450
1829		 * instructions (that's without canonical processing or echo!).
1830		 * slinput is reasonably fast (usually 40 instructions plus
1831		 * call overhead).
1832		 */
1833					if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1834
1835						/* block if the driver supports it */
1836						if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
1837						    && (tp->t_cflag & CRTS_IFLOW
1838							|| tp->t_iflag & IXOFF)
1839						    && !(tp->t_state & TS_TBLOCK))
1840							ttyblock(tp);
1841
1842						tk_nin += n;
1843						tk_rawcc += n;
1844						tp->t_rawcc += n;
1845
1846						b_to_q((char *)rxbuf, n, &tp->t_rawq);
1847						ttwakeup(tp);
1848						if (tp->t_state & TS_TTSTOP
1849						    && (tp->t_iflag & IXANY
1850							|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1851							tp->t_state &= ~TS_TTSTOP;
1852							tp->t_lflag &= ~FLUSHO;
1853							si_start(tp);
1854						}
1855					} else {
1856						for(x = 0; x < n; x++) {
1857							i = rxbuf[x];
1858							(*linesw[tp->t_line].l_rint)(rxbuf[x], tp);
1859							if (pp->sp_hotchar && i == pp->sp_hotchar) {
1860								setsofttty();
1861							}
1862						}
1863					}
1864
1865				} /* end of RX while */
1866			} /* end TS_CONNECTED */
1867
1868			/*
1869			 * Do TX stuff
1870			 */
1871			(*linesw[tp->t_line].l_start)(tp);
1872
1873		} /* end of for (all ports on this controller) */
1874	} /* end of for (all controllers) */
1875
1876	in_intr = 0;
1877	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
1878}
1879
1880/*
1881 * Nudge the transmitter...
1882 */
1883static void
1884si_start(tp)
1885	register struct tty *tp;
1886{
1887	struct si_port *pp;
1888	volatile struct si_channel *ccbp;
1889	register struct clist *qp;
1890	register char *dptr;
1891	BYTE ipos;
1892	int nchar;
1893	int oldspl, count, n, amount, buffer_full;
1894	int do_exitproc;
1895
1896	oldspl = spltty();
1897
1898	qp = &tp->t_outq;
1899	pp = TP2PP(tp);
1900
1901	DPRINT((pp, DBG_ENTRY|DBG_START,
1902		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
1903		tp, tp->t_state, pp->sp_state, qp->c_cc));
1904
1905	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
1906		goto out;
1907
1908	do_exitproc = 0;
1909	buffer_full = 0;
1910	ccbp = pp->sp_ccb;
1911
1912	/*
1913	 * Handle the case where ttywait() is called on process exit
1914	 * this may be BSDI specific, I dont know...
1915	 */
1916	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
1917	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
1918		do_exitproc++;
1919	}
1920
1921	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
1922	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
1923
1924	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
1925
1926	while ((nchar = qp->c_cc) > 0) {
1927		if ((BYTE)count >= 255) {
1928			buffer_full++;
1929			break;
1930		}
1931		amount = min(nchar, (255 - (BYTE)count));
1932		ipos = (unsigned int)ccbp->hi_txipos;
1933		/* will it fit in one lump? */
1934		if ((SLXOS_BUFFERSIZE - ipos) >= amount) {
1935			n = q_to_b(&tp->t_outq,
1936				(char *)&ccbp->hi_txbuf[ipos], amount);
1937		} else {
1938			n = q_to_b(&tp->t_outq,
1939				(char *)&ccbp->hi_txbuf[ipos],
1940				SLXOS_BUFFERSIZE-ipos);
1941			if (n == SLXOS_BUFFERSIZE-ipos) {
1942				n += q_to_b(&tp->t_outq,
1943					(char *)&ccbp->hi_txbuf[0],
1944					amount - (SLXOS_BUFFERSIZE-ipos));
1945			}
1946		}
1947		ccbp->hi_txipos += n;
1948		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
1949	}
1950
1951	if (count != 0 && nchar == 0) {
1952		tp->t_state |= TS_BUSY;
1953	} else {
1954		tp->t_state &= ~TS_BUSY;
1955	}
1956
1957	/* wakeup time? */
1958	ttwwakeup(tp);
1959
1960	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
1961		(BYTE)count, nchar, tp->t_state));
1962
1963	if ((tp->t_state & TS_BUSY) || do_exitproc)
1964	{
1965		int time;
1966
1967		if (do_exitproc != 0) {
1968			time = hz / 10;
1969		} else {
1970			time = ttspeedtab(tp->t_ospeed, chartimes);
1971
1972			if (time > 0) {
1973				if (time < nchar)
1974					time = nchar / time;
1975				else
1976					time = 2;
1977			} else {
1978				printf("SLXOS si%d: bad char time value!!\n",
1979					SI_CARD(tp->t_dev));
1980				goto out;
1981			}
1982		}
1983
1984		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
1985			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
1986		} else {
1987			pp->sp_state |= SS_LSTART;
1988		}
1989		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
1990		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
1991	}
1992
1993out:
1994	splx(oldspl);
1995	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
1996}
1997
1998/*
1999 * Note: called at splsoftclock from the timeout code
2000 * This has to deal with two things...  cause wakeups while waiting for
2001 * tty drains on last process exit, and call l_start at about the right
2002 * time for protocols like ppp.
2003 */
2004static void
2005si_lstart(pp)
2006	register struct si_port *pp;
2007{
2008	register struct tty *tp;
2009	int oldspl;
2010
2011	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
2012		pp, pp->sp_state));
2013
2014	oldspl = spltty();
2015
2016	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
2017		splx(oldspl);
2018		return;
2019	}
2020	pp->sp_state &= ~SS_LSTART;
2021	pp->sp_state |= SS_INLSTART;
2022
2023	tp = pp->sp_tty;
2024
2025	/* deal with the process exit case */
2026	ttwwakeup(tp);
2027
2028	/* nudge protocols */
2029	(*linesw[tp->t_line].l_start)(tp);
2030
2031	pp->sp_state &= ~SS_INLSTART;
2032	splx(oldspl);
2033}
2034
2035/*
2036 * Stop output on a line. called at spltty();
2037 */
2038void
2039sistop(tp, rw)
2040	register struct tty *tp;
2041	int rw;
2042{
2043	volatile struct si_channel *ccbp;
2044	struct si_port *pp;
2045
2046	pp = TP2PP(tp);
2047	ccbp = pp->sp_ccb;
2048
2049	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
2050
2051	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
2052	if (rw & FWRITE) {
2053		/* what level are we meant to be flushing anyway? */
2054		if (tp->t_state & TS_BUSY) {
2055			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
2056			tp->t_state &= ~TS_BUSY;
2057			ttwwakeup(tp);	/* Bruce???? */
2058		}
2059	}
2060#if 0	/* this doesn't work right yet.. */
2061	if (rw & FREAD) {
2062		ccbp->hi_rxopos = ccbp->hi_rxipos;
2063	}
2064#endif
2065}
2066
2067/*
2068 * Issue a command to the Z280 host card CPU.
2069 */
2070
2071static void
2072si_command(pp, cmd, waitflag)
2073	struct si_port *pp;		/* port control block (local) */
2074	int cmd;
2075	int waitflag;
2076{
2077	int oldspl;
2078	volatile struct si_channel *ccbp = pp->sp_ccb;
2079	int x;
2080
2081	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
2082		pp, cmd, waitflag, ccbp->hi_stat));
2083
2084	oldspl = spltty();		/* Keep others out */
2085
2086	/* wait until it's finished what it was doing.. */
2087	while((x = ccbp->hi_stat) != IDLE_OPEN &&
2088			x != IDLE_CLOSE &&
2089			x != cmd) {
2090		if (in_intr) {			/* Prevent sleep in intr */
2091			DPRINT((pp, DBG_PARAM,
2092				"cmd intr collision - completing %d\trequested %d\n",
2093				x, cmd));
2094			splx(oldspl);
2095			return;
2096		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2097				"sicmd1", 1)) {
2098			splx(oldspl);
2099			return;
2100		}
2101	}
2102	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
2103
2104	/* if there was a pending command, cause a state-change wakeup */
2105	if (pp->sp_pend != IDLE_OPEN) {
2106		switch(pp->sp_pend) {
2107		case LOPEN:
2108		case MPEND:
2109		case MOPEN:
2110		case CONFIG:
2111			wakeup(&pp->sp_state);
2112			break;
2113		default:
2114			break;
2115		}
2116	}
2117
2118	pp->sp_pend = cmd;		/* New command pending */
2119	ccbp->hi_stat = cmd;		/* Post it */
2120
2121	if (waitflag) {
2122		if (in_intr) {		/* If in interrupt handler */
2123			DPRINT((pp, DBG_PARAM,
2124				"attempt to sleep in si_intr - cmd req %d\n",
2125				cmd));
2126			splx(oldspl);
2127			return;
2128		} else while(ccbp->hi_stat != IDLE_OPEN) {
2129			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2130			    "sicmd2", 0))
2131				break;
2132		}
2133	}
2134	splx(oldspl);
2135}
2136
2137static void
2138si_disc_optim(tp, t, pp)
2139	struct tty	*tp;
2140	struct termios	*t;
2141	struct si_port	*pp;
2142{
2143	/*
2144	 * XXX can skip a lot more cases if Smarts.  Maybe
2145	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
2146	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2147	 */
2148	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2149	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2150	    && (!(t->c_iflag & PARMRK)
2151		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2152	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2153	    && linesw[tp->t_line].l_rint == ttyinput)
2154		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2155	else
2156		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2157
2158	/*
2159	 * Prepare to reduce input latency for packet
2160	 * discplines with a end of packet character.
2161	 */
2162	if (tp->t_line == SLIPDISC)
2163		pp->sp_hotchar = 0xc0;
2164	else if (tp->t_line == PPPDISC)
2165		pp->sp_hotchar = 0x7e;
2166	else
2167		pp->sp_hotchar = 0;
2168
2169	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
2170		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
2171		pp->sp_hotchar));
2172}
2173
2174
2175#ifdef	SI_DEBUG
2176static void
2177si_dprintf(pp, flags, str, a1, a2, a3, a4, a5, a6)
2178	struct si_port *pp;
2179	int flags;
2180	char *str;
2181	int a1, a2, a3, a4, a5, a6;
2182{
2183	if ((pp == NULL && (si_debug&flags)) ||
2184	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
2185	    	if (pp != NULL)
2186	    		printf("SLXOS %ci%d(%d): ", 's',
2187	    			SI_CARD(pp->sp_tty->t_dev),
2188	    			SI_PORT(pp->sp_tty->t_dev));
2189		printf(str, a1, a2, a3, a4, a5, a6);
2190	}
2191}
2192
2193static char *
2194si_mctl2str(cmd)
2195	enum si_mctl cmd;
2196{
2197	switch (cmd) {
2198	case GET:	return("GET");
2199	case SET:	return("SET");
2200	case BIS:	return("BIS");
2201	case BIC:	return("BIC");
2202	}
2203	return("BAD");
2204}
2205#endif
2206