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