si.c revision 13630
182498Sroberto/*
282498Sroberto * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
382498Sroberto *
482498Sroberto * Copyright (C) 1990, 1992 Specialix International,
582498Sroberto * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
682498Sroberto * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com>
782498Sroberto *
8285612Sdelphij * Originally derived from:	SunOS 4.x version
982498Sroberto * Ported from BSDI version to FreeBSD by Peter Wemm.
10285612Sdelphij *
1182498Sroberto * Redistribution and use in source and binary forms, with or without
12132451Sroberto * modification, are permitted provided that the following conditions
1382498Sroberto * are met:
1482498Sroberto * 1. Redistributions of source code must retain the above copyright
1582498Sroberto *    notices, this list of conditions and the following disclaimer.
1682498Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1782498Sroberto *    notices, this list of conditions and the following disclaimer in the
18132451Sroberto *    documentation and/or other materials provided with the distribution.
1982498Sroberto * 3. All advertising materials mentioning features or use of this software
20285612Sdelphij *    must display the following acknowledgement:
21285612Sdelphij *	This product includes software developed by Andy Rutter of
22285612Sdelphij *	Advanced Methods and Tools Ltd. based on original information
23285612Sdelphij *	from Specialix International.
2482498Sroberto * 4. Neither the name of Advanced Methods and Tools, nor Specialix
25316722Sdelphij *    International may be used to endorse or promote products derived from
26132451Sroberto *    this software without specific prior written permission.
27316722Sdelphij *
28132451Sroberto * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
29132451Sroberto * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30316722Sdelphij * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
31132451Sroberto * NO EVENT SHALL THE AUTHORS BE LIABLE.
32132451Sroberto *
33316722Sdelphij *	$Id: si.c,v 1.35 1996/01/16 18:13:18 phk Exp $
34132451Sroberto */
35310419Sdelphij
36132451Sroberto#ifndef lint
3782498Srobertostatic char si_copyright1[] =  "@(#) (C) Specialix International, 1990,1992",
3882498Sroberto            si_copyright2[] =  "@(#) (C) Andy Rutter 1993",
3982498Sroberto            si_copyright3[] =  "@(#) (C) Peter Wemm 1995";
4082498Sroberto#endif	/* not lint */
4182498Sroberto
42285612Sdelphij#include <sys/param.h>
43285612Sdelphij#include <sys/systm.h>
44285612Sdelphij#include <sys/ioctl.h>
45285612Sdelphij#include <sys/tty.h>
46285612Sdelphij#include <sys/ttydefaults.h>
47285612Sdelphij#include <sys/proc.h>
48285612Sdelphij#include <sys/conf.h>
49285612Sdelphij#include <sys/file.h>
50285612Sdelphij#include <sys/uio.h>
51285612Sdelphij#include <sys/dkstat.h>
52285612Sdelphij#include <sys/kernel.h>
53285612Sdelphij#include <sys/syslog.h>
54285612Sdelphij#include <sys/malloc.h>
55285612Sdelphij#include <sys/devconf.h>
56285612Sdelphij#ifdef DEVFS
57285612Sdelphij#include <sys/devfsext.h>
58285612Sdelphij#endif /*DEVFS*/
59285612Sdelphij
60285612Sdelphij#include <machine/clock.h>
61285612Sdelphij
62285612Sdelphij#include <vm/vm.h>
63285612Sdelphij#include <vm/vm_param.h>
64285612Sdelphij#include <vm/pmap.h>
65285612Sdelphij
66285612Sdelphij#include <i386/isa/icu.h>
67285612Sdelphij#include <i386/isa/isa.h>
68285612Sdelphij#include <i386/isa/isa_device.h>
69132451Sroberto
7082498Sroberto#include <i386/isa/sireg.h>
71132451Sroberto#include <machine/si.h>
72132451Sroberto#include <machine/stdarg.h>
73132451Sroberto
7482498Sroberto#include "si.h"
75132451Sroberto
76132451Sroberto/*
77132451Sroberto * This device driver is designed to interface the Specialix International
78285612Sdelphij * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine.
79132451Sroberto *
80132451Sroberto * The controller is interfaced to the host via dual port ram
81132451Sroberto * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15.
82132451Sroberto */
83132451Sroberto
84132451Sroberto#define	POLL		/* turn on poller to generate buffer empty interrupt */
85132451Sroberto#undef	FASTPOLL	/* turn on 100Hz poller, (XXX: NOTYET!) */
86132451Sroberto#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */
87132451Sroberto#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
88132451Sroberto
89132451Srobertoenum si_mctl { GET, SET, BIS, BIC };
90132451Sroberto
91132451Srobertostatic void si_command __P((struct si_port *, int, int));
92132451Srobertostatic int si_modem __P((struct si_port *, enum si_mctl, int));
93132451Srobertostatic void si_write_enable __P((struct si_port *, int));
94132451Srobertostatic int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));
95132451Srobertostatic void si_start __P((struct tty *));
9682498Srobertostatic void si_lstart __P((struct si_port *));
97132451Srobertostatic void si_disc_optim __P((struct tty *tp, struct termios *t,
98132451Sroberto					struct si_port *pp));
99132451Srobertostatic void sihardclose __P((struct si_port *pp));
100132451Srobertostatic void sidtrwakeup __P((void *chan));
101132451Sroberto
102132451Srobertostatic int	siparam __P((struct tty *, struct termios *));
103132451Sroberto
104132451Srobertostatic	void	si_registerdev __P((struct isa_device *id));
105132451Srobertostatic	int	siprobe __P((struct isa_device *id));
106132451Srobertostatic	int	siattach __P((struct isa_device *id));
107132451Srobertostatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
108132451Sroberto
109132451Srobertostruct isa_driver sidriver =
110132451Sroberto	{ siprobe, siattach, "si" };
111132451Sroberto
112132451Sroberto
113132451Srobertostatic	d_open_t	siopen;
114132451Srobertostatic	d_close_t	siclose;
115132451Srobertostatic	d_read_t	siread;
116132451Srobertostatic	d_write_t	siwrite;
117285612Sdelphijstatic	d_ioctl_t	siioctl;
118285612Sdelphijstatic	d_stop_t	sistop;
119285612Sdelphijstatic	d_devtotty_t	sidevtotty;
120285612Sdelphij
121285612Sdelphij#define CDEV_MAJOR 68
122285612Sdelphijstatic struct cdevsw si_cdevsw =
123285612Sdelphij	{ siopen,	siclose,	siread,		siwrite,	/*68*/
124285612Sdelphij	  siioctl,	sistop,		noreset,	sidevtotty,/* si */
125285612Sdelphij	  ttselect,	nommap,		NULL,	"si",	NULL,	-1 };
126285612Sdelphij
127285612Sdelphij
128285612Sdelphij#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
129285612Sdelphij
130285612Sdelphijstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
131285612Sdelphij				...));
132285612Sdelphijstatic	char	*si_mctl2str __P((enum si_mctl cmd));
133285612Sdelphij
134285612Sdelphij#define	DPRINT(x)	si_dprintf x
135285612Sdelphij
136285612Sdelphij#else
137285612Sdelphij#define	DPRINT(x)	/* void */
138285612Sdelphij#endif
13982498Sroberto
14082498Srobertostatic int si_Nports;
141132451Srobertostatic int si_Nmodules;
14282498Srobertostatic int si_debug = 0;	/* data, not bss, so it's patchable */
143132451Sroberto
144132451Srobertostatic struct tty *si_tty;
145132451Sroberto
146281230Sdelphij/* where the firmware lives; defined in si_code.c */
147132451Srobertoextern int si_dsize;
14882498Srobertoextern unsigned char si_download[];
14982498Sroberto
150132451Srobertostruct si_softc {
15182498Sroberto	int 		sc_type;	/* adapter type */
152132451Sroberto	char 		*sc_typename;	/* adapter type string */
153285612Sdelphij
154285612Sdelphij	struct si_port	*sc_ports;	/* port structures for this card */
155285612Sdelphij
156285612Sdelphij	caddr_t		sc_paddr;	/* physical addr of iomem */
157285612Sdelphij	caddr_t		sc_maddr;	/* kvaddr of iomem */
15882498Sroberto	int		sc_nport;	/* # ports on this card */
15982498Sroberto	int		sc_irq;		/* copy of attach irq */
160132451Sroberto	int		sc_eisa_iobase;	/* EISA io port address */
16182498Sroberto	int		sc_eisa_irqbits;
162285612Sdelphij	struct kern_devconf sc_kdc;
163285612Sdelphij#ifdef	DEVFS
164285612Sdelphij	struct {
165132451Sroberto		void	*ttyd;
166132451Sroberto		void	*cuaa;
167285612Sdelphij		void	*ttyl;
168285612Sdelphij		void	*ttyi;
169285612Sdelphij	} devfs_token[32]; /* what is the max per card? */
170285612Sdelphij	void	*control_token;
17182498Sroberto#endif
17282498Sroberto};
173132451Srobertostatic struct si_softc si_softc[NSI];		/* up to 4 elements */
17482498Sroberto
175132451Sroberto#ifndef B2000	/* not standard, but the hardware knows it. */
176132451Sroberto# define B2000 2000
177132451Sroberto#endif
178132451Srobertostatic struct speedtab bdrates[] = {
179132451Sroberto	B75,	CLK75,		/* 0x0 */
180132451Sroberto	B110,	CLK110,		/* 0x1 */
18182498Sroberto	B150,	CLK150,		/* 0x3 */
18282498Sroberto	B300,	CLK300,		/* 0x4 */
18382498Sroberto	B600,	CLK600,		/* 0x5 */
18482498Sroberto	B1200,	CLK1200,	/* 0x6 */
185285612Sdelphij	B2000,	CLK2000,	/* 0x7 */
186285612Sdelphij	B2400,	CLK2400,	/* 0x8 */
187285612Sdelphij	B4800,	CLK4800,	/* 0x9 */
188285612Sdelphij	B9600,	CLK9600,	/* 0xb */
189285612Sdelphij	B19200,	CLK19200,	/* 0xc */
190285612Sdelphij	B38400, CLK38400,	/* 0x2 (out of order!) */
191285612Sdelphij	B57600, CLK57600,	/* 0xd */
192285612Sdelphij	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
193285612Sdelphij	-1,	-1
194285612Sdelphij};
195285612Sdelphij
196285612Sdelphij
197285612Sdelphij/* populated with approx character/sec rates - translated at card
198285612Sdelphij * initialisation time to chars per tick of the clock */
199285612Sdelphijstatic int done_chartimes = 0;
200316722Sdelphijstatic struct speedtab chartimes[] = {
201285612Sdelphij	B75,	8,
202285612Sdelphij	B110,	11,
203285612Sdelphij	B150,	15,
204285612Sdelphij	B300,	30,
205285612Sdelphij	B600,	60,
206285612Sdelphij	B1200,	120,
207285612Sdelphij	B2000,	200,
208285612Sdelphij	B2400,	240,
209289997Sglebius	B4800,	480,
21082498Sroberto	B9600,	960,
211132451Sroberto	B19200,	1920,
212132451Sroberto	B38400, 3840,
213132451Sroberto	B57600, 5760,
214132451Sroberto	B115200, 11520,
215132451Sroberto	-1,	-1
216132451Sroberto};
21782498Srobertostatic volatile int in_intr = 0;	/* Inside interrupt handler? */
21882498Sroberto
21982498Srobertostatic int si_default_rate =	TTYDEF_SPEED;
22082498Srobertostatic int si_default_iflag =	0;
22182498Srobertostatic int si_default_oflag =	0;
22282498Srobertostatic int si_default_lflag =	0;
22382498Sroberto#ifdef SI_DEF_HWFLOW
22482498Srobertostatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;
225132451Sroberto#else
226285612Sdelphijstatic int si_default_cflag =	TTYDEF_CFLAG;
22782498Sroberto#endif
228132451Sroberto
22982498Sroberto#ifdef POLL
230285612Sdelphij#define	POLL_INTERVAL	(hz/2)
231285612Sdelphijstatic int init_finished = 0;
232132451Srobertostatic int fastpoll = 0;
233132451Srobertostatic void si_poll __P((void *));
234132451Sroberto#endif
23582498Sroberto
23682498Sroberto/*
237310419Sdelphij * Array of adapter types and the corresponding RAM size. The order of
238132451Sroberto * entries here MUST match the ordinal of the adapter type.
239132451Sroberto */
240132451Srobertostatic char *si_type[] = {
241132451Sroberto	"EMPTY",
24282498Sroberto	"SIHOST",
243182007Sroberto	"SI2",				/* MCA */
244182007Sroberto	"SIHOST2",
245182007Sroberto	"SIEISA",
24682498Sroberto};
24782498Sroberto
24882498Sroberto
24982498Srobertostatic struct kern_devconf si_kdc[NSI] = { {
250132451Sroberto	0, 0, 0,		/* filled in by dev_attach */
251285612Sdelphij	"si", 0, { MDDT_ISA, 0, "tty" },
252132451Sroberto	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
253285612Sdelphij	&kdc_isa0,		/* parent */
254285612Sdelphij	0,			/* parent data */
255132451Sroberto	DC_UNCONFIGURED,	/* state */
256132451Sroberto	"Specialix SI/XIO Host adapter",
257132451Sroberto	DC_CLS_SERIAL,		/* class */
258132451Sroberto} };
259182007Sroberto
260132451Srobertostatic void
261285612Sdelphijsi_registerdev(id)
262132451Sroberto	struct isa_device *id;
263285612Sdelphij{
264132451Sroberto	if (id->id_unit != 0) {
265132451Sroberto		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */
266132451Sroberto	}
267132451Sroberto	si_kdc[id->id_unit].kdc_unit = id->id_unit;
268132451Sroberto	si_kdc[id->id_unit].kdc_isa = id;
269132451Sroberto	si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED;
270310419Sdelphij	dev_attach(&si_kdc[id->id_unit]);
271330567Sgordon}
272330567Sgordon
273330567Sgordon/* Look for a valid board at the given mem addr */
274330567Sgordonstatic int
275330567Sgordonsiprobe(id)
276310419Sdelphij	struct isa_device *id;
277330567Sgordon{
278310419Sdelphij	struct si_softc *sc;
279310419Sdelphij	int type;
280310419Sdelphij	u_int i, ramsize;
281132451Sroberto	volatile BYTE was, *ux;
28282498Sroberto	volatile unsigned char *maddr;
28382498Sroberto	unsigned char *paddr;
284294569Sdelphij
28582498Sroberto	si_registerdev(id);
28682498Sroberto
287285612Sdelphij	maddr = id->id_maddr;		/* virtual address... */
288132451Sroberto	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
289285612Sdelphij
290285612Sdelphij	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
29182498Sroberto		id->id_unit, id->id_maddr, paddr));
29282498Sroberto
29382498Sroberto	/*
29482498Sroberto	 * this is a lie, but it's easier than trying to handle caching
29582498Sroberto	 * and ram conflicts in the >1M and <16M region.
29682498Sroberto	 */
29782498Sroberto	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
298182007Sroberto	    (caddr_t)paddr >= (caddr_t)IOM_END) {
299182007Sroberto		printf("si%d: iomem (%lx) out of range\n",
300285612Sdelphij			id->id_unit, (long)paddr);
301182007Sroberto		return(0);
30282498Sroberto	}
30382498Sroberto
30482498Sroberto	if (id->id_unit >= NSI) {
30582498Sroberto		/* THIS IS IMPOSSIBLE */
30682498Sroberto		return(0);
30782498Sroberto	}
308182007Sroberto
30982498Sroberto	if (((u_int)paddr & 0x7fff) != 0) {
31082498Sroberto		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
31182498Sroberto			"si%d: iomem (%x) not on 32k boundary\n",
31282498Sroberto			id->id_unit, paddr));
31382498Sroberto		return(0);
314310419Sdelphij	}
315132451Sroberto
31682498Sroberto
317132451Sroberto	for (i=0; i < NSI; i++) {
318132451Sroberto		if ((sc = &si_softc[i]) == NULL)
319132451Sroberto			continue;
320285612Sdelphij		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
321182007Sroberto			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
322132451Sroberto				"si%d: iomem (%x) already configured to si%d\n",
32382498Sroberto				id->id_unit, sc->sc_paddr, i));
324182007Sroberto			return(0);
325285612Sdelphij		}
326182007Sroberto	}
32782498Sroberto
32882498Sroberto#if NEISA > 0
32982498Sroberto	if (id->id_iobase > 0x0fff) {	/* EISA card */
330132451Sroberto		int irq, port;
33182498Sroberto		unsigned long base;
332285612Sdelphij		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,
333285612Sdelphij			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };
33482498Sroberto
33582498Sroberto		port = id->id_iobase;
33682498Sroberto		base = (inb(port+1) << 24) | (inb(port) << 16);
33782498Sroberto		irq  = ((inb(port+2) >> 4) & 0xf);
33882498Sroberto
33982498Sroberto		id->id_irq = eisa_irqs[irq];
340285612Sdelphij
341285612Sdelphij		DPRINT((0, DBG_AUTOBOOT,
342285612Sdelphij		    "si%d: EISA base %x, irq %x, id_irq %x, port %x\n",
343285612Sdelphij		    id->id_unit, base, irq, id->id_irq, port));
34482498Sroberto
34582498Sroberto		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)
34682498Sroberto			goto bad_irq;
34782498Sroberto
34882498Sroberto		id->id_iobase &= 0xf000;
34982498Sroberto		id->id_iosize  = 0x0fff;
35082498Sroberto
35182498Sroberto		type = EISA;
35282498Sroberto		outb(p+2, (BYTE)irq << 4);
35382498Sroberto
35482498Sroberto		sc->sc_eisa_iobase = p;
35582498Sroberto		sc->sc_eisa_irqbits = irq << 4;
356182007Sroberto		ramsize = SIEISA_RAMSIZE;
357285612Sdelphij		goto got_card;
35882498Sroberto	}
35982498Sroberto#endif
36082498Sroberto
361132451Sroberto	/* Is there anything out there? (0x17 is just an arbitrary number) */
36282498Sroberto	*maddr = 0x17;
36382498Sroberto	if (*maddr != 0x17) {
36482498Sroberto		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
36582498Sroberto			"si%d: 0x17 check fail at phys 0x%x\n",
366285612Sdelphij			id->id_unit, paddr));
367182007Srobertofail:
36882498Sroberto		return(0);
369285612Sdelphij	}
37082498Sroberto	/*
37182498Sroberto	 * OK, now to see if whatever responded is really an SI card.
37282498Sroberto	 * Try for a MK II first (SIHOST2)
37382498Sroberto	 */
37482498Sroberto	for (i=SIPLSIG; i<SIPLSIG+8; i++)
37582498Sroberto		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
376132451Sroberto			goto try_mk1;
377132451Sroberto
37882498Sroberto	/* It must be an SIHOST2 */
379132451Sroberto	*(maddr + SIPLRESET) = 0;
380132451Sroberto	*(maddr + SIPLIRQCLR) = 0;
381132451Sroberto	*(maddr + SIPLIRQSET) = 0x10;
382132451Sroberto	type = SIHOST2;
38382498Sroberto	ramsize = SIHOST2_RAMSIZE;
38482498Sroberto	goto got_card;
385132451Sroberto
386132451Sroberto	/*
387132451Sroberto	 * Its not a MK II, so try for a MK I (SIHOST)
388132451Sroberto	 */
389182007Srobertotry_mk1:
390132451Sroberto	*(maddr+SIRESET) = 0x0;		/* reset the card */
391132451Sroberto	*(maddr+SIINTCL) = 0x0;		/* clear int */
392310419Sdelphij	*(maddr+SIRAM) = 0x17;
393310419Sdelphij	if (*(maddr+SIRAM) != (BYTE)0x17)
394310419Sdelphij		goto fail;
395310419Sdelphij	*(maddr+0x7ff8) = 0x17;
396310419Sdelphij	if (*(maddr+0x7ff8) != (BYTE)0x17) {
397289997Sglebius		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
398132451Sroberto			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
399285612Sdelphij			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
400285612Sdelphij		goto fail;
401310419Sdelphij	}
402132451Sroberto
403285612Sdelphij	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */
404285612Sdelphij	type = SIHOST;
405285612Sdelphij	ramsize = SIHOST_RAMSIZE;
406182007Sroberto
40782498Srobertogot_card:
40882498Sroberto	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
40982498Sroberto		id->id_unit, type));
41082498Sroberto	/* Try the acid test */
41182498Sroberto	ux = (BYTE *)(maddr + SIRAM);
41282498Sroberto	for (i=0; i<ramsize; i++, ux++)
41382498Sroberto		*ux = (BYTE)(i&0xff);
41482498Sroberto	ux = (BYTE *)(maddr + SIRAM);
41582498Sroberto	for (i=0; i<ramsize; i++, ux++) {
41682498Sroberto		if ((was = *ux) != (BYTE)(i&0xff)) {
41782498Sroberto			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
418132451Sroberto				"si%d: match fail at phys 0x%x, was %x should be %x\n",
41982498Sroberto				id->id_unit, paddr+i, was, i&0xff));
420285612Sdelphij			goto fail;
421285612Sdelphij		}
422285612Sdelphij	}
423285612Sdelphij
424285612Sdelphij	/* clear out the RAM */
42582498Sroberto	ux = (BYTE *)(maddr + SIRAM);
426132451Sroberto	for (i=0; i<ramsize; i++)
42782498Sroberto		*ux++ = 0;
42882498Sroberto	ux = (BYTE *)(maddr + SIRAM);
42982498Sroberto	for (i=0; i<ramsize; i++) {
43082498Sroberto		if ((was = *ux++) != 0) {
43182498Sroberto			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
432132451Sroberto				"si%d: clear fail at phys 0x%x, was %x\n",
433132451Sroberto				id->id_unit, paddr+i, was));
434132451Sroberto			goto fail;
435132451Sroberto		}
436285612Sdelphij	}
437289997Sglebius
438132451Sroberto	/*
439132451Sroberto	 * Success, we've found a valid board, now fill in
440132451Sroberto	 * the adapter structure.
441132451Sroberto	 */
442132451Sroberto	switch (type) {
443132451Sroberto	case SIHOST2:
444132451Sroberto		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
445132451Srobertobad_irq:
446132451Sroberto			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
447182007Sroberto				"si%d: bad IRQ value - %d\n",
448132451Sroberto				id->id_unit, id->id_irq));
449285612Sdelphij			return(0);
450132451Sroberto		}
45182498Sroberto		id->id_msize = SIHOST2_MEMSIZE;
45282498Sroberto		break;
45382498Sroberto	case SIHOST:
454132451Sroberto		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {
455132451Sroberto			goto bad_irq;
456132451Sroberto		}
457132451Sroberto		id->id_msize = SIHOST_MEMSIZE;
458132451Sroberto		break;
459132451Sroberto	case SIEISA:
460132451Sroberto		id->id_msize = SIEISA_MEMSIZE;
46182498Sroberto		break;
46282498Sroberto	case SI2:		/* MCA */
463182007Sroberto	default:
464289997Sglebius		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
465289997Sglebius		return(0);
466289997Sglebius	}
467289997Sglebius	si_softc[id->id_unit].sc_type = type;
468289997Sglebius	si_softc[id->id_unit].sc_typename = si_type[type];
469132451Sroberto	return(-1);	/* -1 == found */
470132451Sroberto}
471132451Sroberto
472132451Sroberto/*
473285612Sdelphij * Attach the device.  Initialize the card.
474285612Sdelphij */
475132451Srobertostatic int
476285612Sdelphijsiattach(id)
477132451Sroberto	struct isa_device *id;
478285612Sdelphij{
479132451Sroberto	int unit = id->id_unit;
480132451Sroberto	struct si_softc *sc = &si_softc[unit];
481132451Sroberto	struct si_port *pp;
482132451Sroberto	volatile struct si_channel *ccbp;
483132451Sroberto	volatile struct si_reg *regp;
484182007Sroberto	volatile caddr_t maddr;
485285612Sdelphij	struct si_module *modp;
486132451Sroberto	struct tty *tp;
487132451Sroberto	struct speedtab *spt;
488132451Sroberto	int nmodule, nport, x, y;
489289997Sglebius	int uart_type;
490293650Sglebius#ifdef DEVFS
491289997Sglebius	char	name[32];
492293650Sglebius#endif
493289997Sglebius
494289997Sglebius	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
495289997Sglebius
496289997Sglebius	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
497289997Sglebius	sc->sc_maddr = id->id_maddr;
498289997Sglebius	sc->sc_irq = id->id_irq;
499289997Sglebius
500289997Sglebius	sc->sc_ports = NULL;			/* mark as uninitialised */
501132451Sroberto
502132451Sroberto	maddr = sc->sc_maddr;
503132451Sroberto
504281230Sdelphij	/*
505281230Sdelphij	 * OK, now lets download the firmware and try and boot the CPU..
506281230Sdelphij	 */
507281230Sdelphij
508281230Sdelphij	DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
509281230Sdelphij		id->id_unit, si_dsize));
510132451Sroberto	bcopy(si_download, maddr, si_dsize);
51182498Sroberto
51282498Sroberto	switch (sc->sc_type) {
51382498Sroberto	case SIEISA:
514132451Sroberto#if NEISA > 0
515132451Sroberto		/* modify the Z280 firmware to tell it that it's on an EISA */
516132451Sroberto		*(maddr+0x42) = 1;
517132451Sroberto		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);
518132451Sroberto		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */
519132451Sroberto		break;
520182007Sroberto#endif	/* fall-through if not EISA */
521132451Sroberto	case SI2:
52282498Sroberto		/*
523132451Sroberto		 * must get around to converting the code for
524132451Sroberto		 * these one day, if FreeBSD ever supports it.
525132451Sroberto		 */
526285612Sdelphij		return 0;
527285612Sdelphij	case SIHOST:
528285612Sdelphij		*(maddr+SIRESET_CL) = 0;
529285612Sdelphij		*(maddr+SIINTCL_CL) = 0;
530285612Sdelphij		break;
531285612Sdelphij	case SIHOST2:
532132451Sroberto		*(maddr+SIPLRESET) = 0x10;
533285612Sdelphij		switch (sc->sc_irq) {
534182007Sroberto		case IRQ11:
535182007Sroberto			*(maddr+SIPLIRQ11) = 0x10;
536182007Sroberto			break;
537285612Sdelphij		case IRQ12:
538285612Sdelphij			*(maddr+SIPLIRQ12) = 0x10;
539285612Sdelphij			break;
540285612Sdelphij		case IRQ15:
541285612Sdelphij			*(maddr+SIPLIRQ15) = 0x10;
542289997Sglebius			break;
543285612Sdelphij		}
544132451Sroberto		*(maddr+SIPLIRQCLR) = 0x10;
545132451Sroberto		break;
546285612Sdelphij	}
547132451Sroberto
548132451Sroberto	DELAY(1000000);			/* wait around for a second */
549132451Sroberto
55082498Sroberto	regp = (struct si_reg *)maddr;
551132451Sroberto	y = 0;
552132451Sroberto					/* wait max of 5 sec for init OK */
553132451Sroberto	while (regp->initstat == 0 && y++ < 10) {
554182007Sroberto		DELAY(500000);
555132451Sroberto	}
556285612Sdelphij	switch (regp->initstat) {
557285612Sdelphij	case 0:
558285612Sdelphij		printf("si%d: startup timeout - aborting\n", unit);
559132451Sroberto		sc->sc_type = SIEMPTY;
560285612Sdelphij		return 0;
561285612Sdelphij	case 1:
562182007Sroberto			/* set throttle to 125 intr per second */
563281230Sdelphij		regp->int_count = 25000;
564132451Sroberto			/* rx intr max of 25 timer per second */
565132451Sroberto		regp->rx_int_count = 4;
56682498Sroberto		regp->int_pending = 0;		/* no intr pending */
567285612Sdelphij		regp->int_scounter = 0;	/* reset counter */
568285612Sdelphij		break;
569285612Sdelphij	case 0xff:
570285612Sdelphij		/*
571132451Sroberto		 * No modules found, so give up on this one.
572132451Sroberto		 */
573285612Sdelphij		printf("si%d: %s - no ports found\n", unit,
574285612Sdelphij			si_type[sc->sc_type]);
575285612Sdelphij		return 0;
576285612Sdelphij	default:
577285612Sdelphij		printf("si%d: Z280 version error - initstat %x\n",
578285612Sdelphij			unit, regp->initstat);
579132451Sroberto		return 0;
580132451Sroberto	}
581182007Sroberto
582132451Sroberto	/*
583182007Sroberto	 * First time around the ports just count them in order
584285612Sdelphij	 * to allocate some memory.
585285612Sdelphij	 */
586285612Sdelphij	nport = 0;
587182007Sroberto	modp = (struct si_module *)(maddr + 0x80);
588182007Sroberto	for (;;) {
589285612Sdelphij		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
590285612Sdelphij		switch (modp->sm_type & (~MMASK)) {
591182007Sroberto		case M232:
592285612Sdelphij		case M422:
593285612Sdelphij			DPRINT((0, DBG_DOWNLOAD,
594285612Sdelphij				"si%d: Found 232/422 module, %d ports\n",
595285612Sdelphij				unit, (int)(modp->sm_type & MMASK)));
596285612Sdelphij
597285612Sdelphij			/* this is a firmware issue */
598285612Sdelphij			if (si_Nports == SI_MAXPORTPERCARD) {
599285612Sdelphij				printf("si%d: extra ports ignored\n", unit);
600285612Sdelphij				continue;
601132451Sroberto			}
602132451Sroberto
603132451Sroberto			x = modp->sm_type & MMASK;
604182007Sroberto			nport += x;
605182007Sroberto			si_Nports += x;
606132451Sroberto			si_Nmodules++;
607132451Sroberto			break;
608132451Sroberto		default:
609132451Sroberto			printf("si%d: unknown module type %d\n",
610182007Sroberto				unit, modp->sm_type);
611132451Sroberto			break;
612132451Sroberto		}
613182007Sroberto		if (modp->sm_next == 0)
614132451Sroberto			break;
615132451Sroberto		modp = (struct si_module *)
616132451Sroberto			(maddr + (unsigned)(modp->sm_next & 0x7fff));
617285612Sdelphij	}
618285612Sdelphij	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
619285612Sdelphij		M_DEVBUF, M_NOWAIT);
620132451Sroberto	if (sc->sc_ports == 0) {
621285612Sdelphijmem_fail:
622285612Sdelphij		printf("si%d: fail to malloc memory for port structs\n",
623285612Sdelphij			unit);
624285612Sdelphij		return 0;
625285612Sdelphij	}
626285612Sdelphij	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
627132451Sroberto	sc->sc_nport = nport;
628132451Sroberto
629285612Sdelphij	/*
630285612Sdelphij	 * allocate tty structures for ports
631132451Sroberto	 */
632132451Sroberto	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
633132451Sroberto	if (tp == 0)
634285612Sdelphij		goto mem_fail;
635285612Sdelphij	bzero(tp, sizeof(*tp) * nport);
636285612Sdelphij	si_tty = tp;
637285612Sdelphij
638285612Sdelphij	/* mark the device state as attached */
639285612Sdelphij	si_kdc[unit].kdc_state = DC_BUSY;
640285612Sdelphij
641132451Sroberto	/*
642285612Sdelphij	 * Scan round the ports again, this time initialising.
64382498Sroberto	 */
64482498Sroberto	pp = sc->sc_ports;
64582498Sroberto	nmodule = 0;
646132451Sroberto	modp = (struct si_module *)(maddr + 0x80);
647132451Sroberto	uart_type = 0;
648132451Sroberto	for (;;) {
649132451Sroberto		switch (modp->sm_type & (~MMASK)) {
650132451Sroberto		case M232:
65182498Sroberto		case M422:
652132451Sroberto			nmodule++;
653132451Sroberto			nport = (modp->sm_type & MMASK);
654132451Sroberto			ccbp = (struct si_channel *)((char *)modp+0x100);
655285612Sdelphij			if (uart_type == 0)
656132451Sroberto				uart_type = ccbp->type;
657285612Sdelphij			for (x = 0; x < nport; x++, pp++, ccbp++) {
658285612Sdelphij				pp->sp_ccb = ccbp;	/* save the address */
659285612Sdelphij				pp->sp_tty = tp++;
660132451Sroberto				pp->sp_pend = IDLE_CLOSE;
661132451Sroberto				pp->sp_state = 0;	/* internal flag */
662132451Sroberto				pp->sp_dtr_wait = 3 * hz;
663132451Sroberto				pp->sp_iin.c_iflag = si_default_iflag;
664132451Sroberto				pp->sp_iin.c_oflag = si_default_oflag;
665132451Sroberto				pp->sp_iin.c_cflag = si_default_cflag;
666132451Sroberto				pp->sp_iin.c_lflag = si_default_lflag;
667285612Sdelphij				termioschars(&pp->sp_iin);
668285612Sdelphij				pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
669285612Sdelphij					si_default_rate;
670132451Sroberto				pp->sp_iout = pp->sp_iin;
671285612Sdelphij			}
672285612Sdelphij			break;
673132451Sroberto		default:
674285612Sdelphij			break;
675285612Sdelphij		}
676285612Sdelphij		if (modp->sm_next == 0) {
677132451Sroberto			printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n",
678132451Sroberto				unit,
679182007Sroberto				sc->sc_typename,
680132451Sroberto				sc->sc_nport,
681132451Sroberto				nmodule,
682132451Sroberto				uart_type);
683132451Sroberto			break;
684132451Sroberto		}
685132451Sroberto		modp = (struct si_module *)
686285612Sdelphij			(maddr + (unsigned)(modp->sm_next & 0x7fff));
687285612Sdelphij	}
688285612Sdelphij	if (done_chartimes == 0) {
689132451Sroberto		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
690132451Sroberto			if ((spt->sp_code /= hz) == 0)
69182498Sroberto				spt->sp_code = 1;
692182007Sroberto		}
693285612Sdelphij		done_chartimes = 1;
694285612Sdelphij	}
695285612Sdelphij
696285612Sdelphij#ifdef DEVFS
697132451Sroberto/*	path	name	devsw		minor	type   uid gid perm*/
698132451Sroberto	for ( x = 0; x < sc->sc_nport; x++ ) {
699132451Sroberto		y = x + 1;	/* For sync with the manuals that start at 1 */
700285612Sdelphij		sc->devfs_token[x].ttyd = devfs_add_devswf(
70182498Sroberto			&si_cdevsw, x,
70282498Sroberto			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
70382498Sroberto		sc->devfs_token[x].cuaa = devfs_add_devswf(
704285612Sdelphij			&si_cdevsw, x + 128,
705285612Sdelphij			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
706285612Sdelphij		sc->devfs_token[x].ttyi = devfs_add_devswf(
707285612Sdelphij			&si_cdevsw, x + 0x10000,
708285612Sdelphij			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
709285612Sdelphij		sc->devfs_token[x].ttyl = devfs_add_devswf(
710132451Sroberto			&si_cdevsw, x + 0x20000,
71182498Sroberto			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
712132451Sroberto	}
71382498Sroberto	sc->control_token = devfs_add_devsw("/", "si_control",
714132451Sroberto						&si_cdevsw, 0x40000,
715285612Sdelphij						DV_CHR, 0, 0, 0600);
716132451Sroberto#endif
717132451Sroberto	return (1);
718132451Sroberto}
719132451Sroberto
720132451Srobertostatic	int
72182498Srobertosiopen(dev, flag, mode, p)
722285612Sdelphij	dev_t dev;
723285612Sdelphij	int flag, mode;
724132451Sroberto	struct proc *p;
725132451Sroberto{
726285612Sdelphij	int oldspl, error;
727285612Sdelphij	int card, port;
72882498Sroberto	register struct si_softc *sc;
729132451Sroberto	register struct tty *tp;
730132451Sroberto	volatile struct si_channel *ccbp;
731132451Sroberto	struct si_port *pp;
732285612Sdelphij	int mynor = minor(dev);
733182007Sroberto
734285612Sdelphij	/* quickly let in /dev/si_control */
735285612Sdelphij	if (IS_CONTROLDEV(mynor)) {
736132451Sroberto		if (error = suser(p->p_ucred, &p->p_acflag))
737285612Sdelphij			return(error);
73882498Sroberto		return(0);
73982498Sroberto	}
74082498Sroberto
741132451Sroberto	card = SI_CARD(mynor);
742132451Sroberto	if (card >= NSI)
743132451Sroberto		return (ENXIO);
744132451Sroberto	sc = &si_softc[card];
745132451Sroberto
746132451Sroberto	if (sc->sc_type == SIEMPTY) {
747132451Sroberto		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
748132451Sroberto			card, sc->sc_typename));
74982498Sroberto		return(ENXIO);
750132451Sroberto	}
751132451Sroberto
752132451Sroberto	port = SI_PORT(mynor);
753285612Sdelphij	if (port >= sc->sc_nport) {
754132451Sroberto		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
755132451Sroberto			card, sc->sc_nport));
756132451Sroberto		return(ENXIO);
757132451Sroberto	}
758132451Sroberto
759132451Sroberto#ifdef	POLL
760285612Sdelphij	/*
761285612Sdelphij	 * We've now got a device, so start the poller.
762132451Sroberto	 */
763132451Sroberto	if (init_finished == 0) {
764285612Sdelphij		timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
765285612Sdelphij		init_finished = 1;
766132451Sroberto	}
767132451Sroberto#endif
768132451Sroberto
769132451Sroberto	/* initial/lock device */
770285612Sdelphij	if (IS_STATE(mynor)) {
771182007Sroberto		return(0);
772285612Sdelphij	}
773285612Sdelphij
774132451Sroberto	pp = sc->sc_ports + port;
775285612Sdelphij	tp = pp->sp_tty;			/* the "real" tty */
77682498Sroberto	ccbp = pp->sp_ccb;			/* Find control block */
77782498Sroberto	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
77882498Sroberto		dev, flag, mode, p));
779285612Sdelphij
780285612Sdelphij	oldspl = spltty();			/* Keep others out */
781285612Sdelphij	error = 0;
782285612Sdelphij
783285612Sdelphijopen_top:
784285612Sdelphij	while (pp->sp_state & SS_DTR_OFF) {
785285612Sdelphij		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
78682498Sroberto		if (error != 0)
787132451Sroberto			goto out;
788132451Sroberto	}
789132451Sroberto
790285612Sdelphij	if (tp->t_state & TS_ISOPEN) {
791132451Sroberto		/*
792132451Sroberto		 * The device is open, so everything has been initialised.
793132451Sroberto		 * handle conflicts.
794132451Sroberto		 */
795132451Sroberto		if (IS_CALLOUT(mynor)) {
796132451Sroberto			if (!pp->sp_active_out) {
797285612Sdelphij				error = EBUSY;
798285612Sdelphij				goto out;
799132451Sroberto			}
800132451Sroberto		} else {
801285612Sdelphij			if (pp->sp_active_out) {
802285612Sdelphij				if (flag & O_NONBLOCK) {
803132451Sroberto					error = EBUSY;
804132451Sroberto					goto out;
805132451Sroberto				}
806132451Sroberto				error = tsleep(&pp->sp_active_out,
807285612Sdelphij						TTIPRI|PCATCH, "sibi", 0);
808182007Sroberto				if (error != 0)
809285612Sdelphij					goto out;
810285612Sdelphij				goto open_top;
811132451Sroberto			}
812285612Sdelphij		}
813132451Sroberto		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
81482498Sroberto			DPRINT((pp, DBG_OPEN|DBG_FAIL,
815132451Sroberto				"already open and EXCLUSIVE set\n"));
816132451Sroberto			error = EBUSY;
817132451Sroberto			goto out;
818132451Sroberto		}
819132451Sroberto	} else {
820132451Sroberto		/*
821132451Sroberto		 * The device isn't open, so there are no conflicts.
822132451Sroberto		 * Initialize it. Avoid sleep... :-)
82382498Sroberto		 */
824285612Sdelphij		DPRINT((pp, DBG_OPEN, "first open\n"));
825285612Sdelphij		tp->t_oproc = si_start;
826285612Sdelphij		tp->t_param = siparam;
82782498Sroberto		tp->t_dev = dev;
828132451Sroberto		tp->t_termios = mynor & SI_CALLOUT_MASK
829132451Sroberto				? pp->sp_iout : pp->sp_iin;
830132451Sroberto
831132451Sroberto		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
83282498Sroberto
833132451Sroberto		++pp->sp_wopeners;	/* in case of sleep in siparam */
834132451Sroberto
83582498Sroberto		error = siparam(tp, &tp->t_termios);
836285612Sdelphij
837310419Sdelphij		--pp->sp_wopeners;
838310419Sdelphij		if (error != 0)
839285612Sdelphij			goto out;
840276072Sdelphij		/* XXX: we should goto_top if siparam slept */
841276072Sdelphij
842276072Sdelphij		ttsetwater(tp);
843285612Sdelphij
844276072Sdelphij		/* set initial DCD state */
845132451Sroberto		pp->sp_last_hi_ip = ccbp->hi_ip;
846276072Sdelphij		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
847310419Sdelphij			(*linesw[tp->t_line].l_modem)(tp, 1);
848276072Sdelphij		}
849276072Sdelphij	}
850276072Sdelphij
851276072Sdelphij	/* whoops! we beat the close! */
852276072Sdelphij	if (pp->sp_state & SS_CLOSING) {
853276072Sdelphij		/* try and stop it from proceeding to bash the hardware */
854276072Sdelphij		pp->sp_state &= ~SS_CLOSING;
855276072Sdelphij	}
856132451Sroberto
857132451Sroberto	/*
858132451Sroberto	 * Wait for DCD if necessary
859132451Sroberto	 */
86082498Sroberto	if (!(tp->t_state & TS_CARR_ON)
86182498Sroberto	    && !IS_CALLOUT(mynor)
862132451Sroberto	    && !(tp->t_cflag & CLOCAL)
863132451Sroberto	    && !(flag & O_NONBLOCK)) {
864132451Sroberto		++pp->sp_wopeners;
86582498Sroberto		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
866132451Sroberto		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
867285612Sdelphij		--pp->sp_wopeners;
868285612Sdelphij		if (error != 0)
869285612Sdelphij			goto out;
870132451Sroberto		goto open_top;
871132451Sroberto	}
872285612Sdelphij
873182007Sroberto	error = (*linesw[tp->t_line].l_open)(dev, tp);
874285612Sdelphij	si_disc_optim(tp, &tp->t_termios, pp);
875285612Sdelphij	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
876285612Sdelphij		pp->sp_active_out = TRUE;
877132451Sroberto
878285612Sdelphij	pp->sp_state |= SS_OPEN;	/* made it! */
87982498Sroberto
88082498Srobertoout:
88182498Sroberto	splx(oldspl);
882132451Sroberto
883132451Sroberto	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
884132451Sroberto
885132451Sroberto	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
886132451Sroberto		sihardclose(pp);
887132451Sroberto
888132451Sroberto	return(error);
889132451Sroberto}
89082498Sroberto
891132451Srobertostatic	int
89282498Srobertosiclose(dev, flag, mode, p)
893132451Sroberto	dev_t dev;
894285612Sdelphij	int flag, mode;
895285612Sdelphij	struct proc *p;
896285612Sdelphij{
897132451Sroberto	register struct si_port *pp;
898132451Sroberto	register struct tty *tp;
899285612Sdelphij	int oldspl;
900132451Sroberto	int error = 0;
901132451Sroberto	int mynor = minor(dev);
90282498Sroberto
903285612Sdelphij	if (IS_SPECIAL(mynor))
904285612Sdelphij		return(0);
905285612Sdelphij
906285612Sdelphij	oldspl = spltty();
907285612Sdelphij
908285612Sdelphij	pp = MINOR2PP(mynor);
909285612Sdelphij	tp = pp->sp_tty;
910285612Sdelphij
911285612Sdelphij	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
912285612Sdelphij		dev, flag, mode, p, pp->sp_state));
913285612Sdelphij
914132451Sroberto	/* did we sleep and loose a race? */
915132451Sroberto	if (pp->sp_state & SS_CLOSING) {
91682498Sroberto		/* error = ESOMETING? */
917285612Sdelphij		goto out;
918285612Sdelphij	}
919285612Sdelphij
920132451Sroberto	/* begin race detection.. */
921132451Sroberto	pp->sp_state |= SS_CLOSING;
922132451Sroberto
923132451Sroberto	si_write_enable(pp, 0);		/* block writes for ttywait() */
924132451Sroberto
925132451Sroberto	/* THIS MAY SLEEP IN TTYWAIT!!! */
926132451Sroberto	(*linesw[tp->t_line].l_close)(tp, flag);
927132451Sroberto
928132451Sroberto	si_write_enable(pp, 1);
929132451Sroberto
930132451Sroberto	/* did we sleep and somebody started another open? */
931182007Sroberto	if (!(pp->sp_state & SS_CLOSING)) {
932285612Sdelphij		/* error = ESOMETING? */
933132451Sroberto		goto out;
934132451Sroberto	}
935132451Sroberto	/* ok. we are now still on the right track.. nuke the hardware */
936132451Sroberto
937285612Sdelphij	if (pp->sp_state & SS_LSTART) {
93882498Sroberto		untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
939182007Sroberto		pp->sp_state &= ~SS_LSTART;
940182007Sroberto	}
941182007Sroberto
942182007Sroberto	sistop(tp, FREAD | FWRITE);
943182007Sroberto
944182007Sroberto	sihardclose(pp);
945182007Sroberto	ttyclose(tp);
946182007Sroberto	pp->sp_state &= ~SS_OPEN;
947182007Sroberto
94882498Srobertoout:
949182007Sroberto	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
950285612Sdelphij	splx(oldspl);
951182007Sroberto	return(error);
952182007Sroberto}
953182007Sroberto
954182007Srobertostatic void
955182007Srobertosihardclose(pp)
956182007Sroberto	struct si_port *pp;
957182007Sroberto{
958182007Sroberto	int oldspl;
959182007Sroberto	struct tty *tp;
960182007Sroberto	volatile struct si_channel *ccbp;
961285612Sdelphij
962285612Sdelphij	oldspl = spltty();
963182007Sroberto
964285612Sdelphij	tp = pp->sp_tty;
965182007Sroberto	ccbp = pp->sp_ccb;			/* Find control block */
966182007Sroberto	if (tp->t_cflag & HUPCL
967285612Sdelphij	    || !pp->sp_active_out
968285612Sdelphij	       && !(ccbp->hi_ip & IP_DCD)
969285612Sdelphij	       && !(pp->sp_iin.c_cflag && CLOCAL)
970285612Sdelphij	    || !(tp->t_state & TS_ISOPEN)) {
971182007Sroberto
972182007Sroberto		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
973182007Sroberto		(void) si_command(pp, FCLOSE, SI_NOWAIT);
974285612Sdelphij
975182007Sroberto		if (pp->sp_dtr_wait != 0) {
976182007Sroberto			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
97782498Sroberto			pp->sp_state |= SS_DTR_OFF;
978285612Sdelphij		}
979285612Sdelphij
980285612Sdelphij	}
981285612Sdelphij	pp->sp_active_out = FALSE;
98282498Sroberto	wakeup((caddr_t)&pp->sp_active_out);
983285612Sdelphij	wakeup(TSA_CARR_ON(tp));
984132451Sroberto
985285612Sdelphij	splx(oldspl);
986285612Sdelphij}
987285612Sdelphij
988132451Sroberto
989285612Sdelphij/*
990285612Sdelphij * called at splsoftclock()...
991285612Sdelphij */
992132451Srobertostatic void
993132451Srobertosidtrwakeup(chan)
994285612Sdelphij	void *chan;
995285612Sdelphij{
996285612Sdelphij	struct si_port *pp;
997285612Sdelphij	int oldspl;
998132451Sroberto
999285612Sdelphij	oldspl = spltty();
1000285612Sdelphij
1001285612Sdelphij	pp = (struct si_port *)chan;
1002285612Sdelphij	pp->sp_state &= ~SS_DTR_OFF;
1003285612Sdelphij	wakeup(&pp->sp_dtr_wait);
1004285612Sdelphij
1005285612Sdelphij	splx(oldspl);
1006285612Sdelphij}
1007132451Sroberto
1008182007Sroberto/*
1009285612Sdelphij * User level stuff - read and write
1010285612Sdelphij */
1011285612Sdelphijstatic	int
1012285612Sdelphijsiread(dev, uio, flag)
1013132451Sroberto	register dev_t dev;
1014285612Sdelphij	struct uio *uio;
101582498Sroberto	int flag;
101682498Sroberto{
101782498Sroberto	register struct tty *tp;
1018132451Sroberto	int mynor = minor(dev);
1019132451Sroberto
1020132451Sroberto	if (IS_SPECIAL(mynor)) {
1021285612Sdelphij		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
1022285612Sdelphij		return(ENODEV);
102382498Sroberto	}
1024182007Sroberto	tp = MINOR2TP(mynor);
1025132451Sroberto	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
1026132451Sroberto		"siread(%x,%x,%x)\n", dev, uio, flag));
1027132451Sroberto	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1028285612Sdelphij}
1029132451Sroberto
1030132451Sroberto
1031132451Srobertostatic	int
103282498Srobertosiwrite(dev, uio, flag)
1033132451Sroberto	dev_t dev;
1034132451Sroberto	struct uio *uio;
1035132451Sroberto	int flag;
1036132451Sroberto{
1037285612Sdelphij	register struct si_port *pp;
1038285612Sdelphij	register struct tty *tp;
1039285612Sdelphij	int error = 0;
1040285612Sdelphij	int mynor = minor(dev);
1041285612Sdelphij	int oldspl;
1042285612Sdelphij
1043132451Sroberto	if (IS_SPECIAL(mynor)) {
1044132451Sroberto		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
1045132451Sroberto		return(ENODEV);
1046182007Sroberto	}
1047285612Sdelphij	pp = MINOR2PP(mynor);
1048132451Sroberto	tp = pp->sp_tty;
1049132451Sroberto	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
1050132451Sroberto
1051132451Sroberto	oldspl = spltty();
105282498Sroberto	/*
1053132451Sroberto	 * If writes are currently blocked, wait on the "real" tty
1054132451Sroberto	 */
1055132451Sroberto	while (pp->sp_state & SS_BLOCKWRITE) {
1056285612Sdelphij		pp->sp_state |= SS_WAITWRITE;
1057132451Sroberto		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
1058285612Sdelphij		if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
1059285612Sdelphij				     "siwrite", 0))
1060285612Sdelphij			goto out;
1061285612Sdelphij	}
1062182007Sroberto
1063285612Sdelphij	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1064285612Sdelphijout:
1065132451Sroberto	splx(oldspl);
1066285612Sdelphij	return (error);
106782498Sroberto}
1068132451Sroberto
106982498Sroberto
107082498Srobertostatic	struct tty *
107182498Srobertosidevtotty(dev_t dev)
107282498Sroberto{
107382498Sroberto	struct si_port *pp;
107482498Sroberto	int mynor = minor(dev);
107582498Sroberto	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
1076132451Sroberto
1077132451Sroberto	if (IS_SPECIAL(mynor))
107882498Sroberto		return(NULL);
1079132451Sroberto	if (SI_PORT(mynor) >= sc->sc_nport)
1080285612Sdelphij		return(NULL);
1081285612Sdelphij	pp = MINOR2PP(mynor);
1082285612Sdelphij	return (pp->sp_tty);
1083285612Sdelphij}
1084285612Sdelphij
1085285612Sdelphijstatic	int
1086285612Sdelphijsiioctl(dev, cmd, data, flag, p)
1087285612Sdelphij	dev_t dev;
108882498Sroberto	int cmd;
1089132451Sroberto	caddr_t data;
109082498Sroberto	int flag;
1091285612Sdelphij	struct proc *p;
1092132451Sroberto{
1093285612Sdelphij	struct si_port *pp;
1094132451Sroberto	register struct tty *tp;
1095132451Sroberto	int error;
1096132451Sroberto	int mynor = minor(dev);
109782498Sroberto	int oldspl;
109882498Sroberto	int blocked = 0;
1099285612Sdelphij#if defined(COMPAT_43)
1100285612Sdelphij	int oldcmd;
1101285612Sdelphij	struct termios term;
1102132451Sroberto#endif
1103132451Sroberto
1104132451Sroberto	if (IS_SI_IOCTL(cmd))
1105132451Sroberto		return(si_Sioctl(dev, cmd, data, flag, p));
1106182007Sroberto
1107285612Sdelphij	pp = MINOR2PP(mynor);
1108132451Sroberto	tp = pp->sp_tty;
1109132451Sroberto
1110132451Sroberto	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n",
1111132451Sroberto		dev, cmd, data, flag));
1112285612Sdelphij	if (IS_STATE(mynor)) {
1113132451Sroberto		struct termios *ct;
111482498Sroberto
111582498Sroberto		switch (mynor & SI_STATE_MASK) {
111682498Sroberto		case SI_INIT_STATE_MASK:
1117132451Sroberto			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1118132451Sroberto			break;
111982498Sroberto		case SI_LOCK_STATE_MASK:
1120132451Sroberto			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
1121132451Sroberto			break;
1122132451Sroberto		default:
1123285612Sdelphij			return (ENODEV);
1124285612Sdelphij		}
1125285612Sdelphij		switch (cmd) {
1126285612Sdelphij		case TIOCSETA:
1127285612Sdelphij			error = suser(p->p_ucred, &p->p_acflag);
1128285612Sdelphij			if (error != 0)
1129285612Sdelphij				return (error);
1130132451Sroberto			*ct = *(struct termios *)data;
113182498Sroberto			return (0);
1132285612Sdelphij		case TIOCGETA:
1133285612Sdelphij			*(struct termios *)data = *ct;
1134132451Sroberto			return (0);
1135182007Sroberto		case TIOCGETD:
1136132451Sroberto			*(int *)data = TTYDISC;
113782498Sroberto			return (0);
113882498Sroberto		case TIOCGWINSZ:
1139132451Sroberto			bzero(data, sizeof(struct winsize));
1140132451Sroberto			return (0);
1141182007Sroberto		default:
114282498Sroberto			return (ENOTTY);
1143285612Sdelphij		}
114482498Sroberto	}
1145285612Sdelphij	/*
1146182007Sroberto	 * Do the old-style ioctl compat routines...
1147182007Sroberto	 */
1148182007Sroberto#if defined(COMPAT_43)
114982498Sroberto	term = tp->t_termios;
1150132451Sroberto	oldcmd = cmd;
1151132451Sroberto	error = ttsetcompat(tp, &cmd, data, &term);
115282498Sroberto	if (error != 0)
1153132451Sroberto		return (error);
1154132451Sroberto	if (cmd != oldcmd)
1155132451Sroberto		data = (caddr_t)&term;
1156132451Sroberto#endif
1157132451Sroberto	/*
1158182007Sroberto	 * Do the initial / lock state business
1159285612Sdelphij	 */
1160132451Sroberto	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1161132451Sroberto		int     cc;
1162132451Sroberto		struct termios *dt = (struct termios *)data;
1163285612Sdelphij		struct termios *lt = mynor & SI_CALLOUT_MASK
1164285612Sdelphij				     ? &pp->sp_lout : &pp->sp_lin;
1165132451Sroberto
1166132451Sroberto		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1167285612Sdelphij			| (dt->c_iflag & ~lt->c_iflag);
1168285612Sdelphij		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1169285612Sdelphij			| (dt->c_oflag & ~lt->c_oflag);
1170285612Sdelphij		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1171285612Sdelphij			| (dt->c_cflag & ~lt->c_cflag);
1172285612Sdelphij		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1173285612Sdelphij			| (dt->c_lflag & ~lt->c_lflag);
1174285612Sdelphij		for (cc = 0; cc < NCCS; ++cc)
1175285612Sdelphij			if (lt->c_cc[cc] != 0)
1176285612Sdelphij				dt->c_cc[cc] = tp->t_cc[cc];
1177285612Sdelphij		if (lt->c_ispeed != 0)
1178285612Sdelphij			dt->c_ispeed = tp->t_ispeed;
1179285612Sdelphij		if (lt->c_ospeed != 0)
1180285612Sdelphij			dt->c_ospeed = tp->t_ospeed;
1181285612Sdelphij	}
1182285612Sdelphij
1183285612Sdelphij	/*
1184285612Sdelphij	 * Block user-level writes to give the ttywait()
1185285612Sdelphij	 * a chance to completely drain for commands
1186285612Sdelphij	 * that require the port to be in a quiescent state.
1187132451Sroberto	 */
1188289997Sglebius	switch (cmd) {
1189289997Sglebius	case TIOCSETAW: case TIOCSETAF:
1190182007Sroberto	case TIOCDRAIN: case TIOCSETP:
119182498Sroberto		blocked++;	/* block writes for ttywait() and siparam() */
119282498Sroberto		si_write_enable(pp, 0);
1193182007Sroberto	}
1194182007Sroberto
1195285612Sdelphij	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1196285612Sdelphij	if (error >= 0)
1197285612Sdelphij		goto out;
1198285612Sdelphij
1199182007Sroberto	oldspl = spltty();
1200285612Sdelphij
1201285612Sdelphij	error = ttioctl(tp, cmd, data, flag);
1202285612Sdelphij	si_disc_optim(tp, &tp->t_termios, pp);
1203132451Sroberto	if (error >= 0)
1204285612Sdelphij		goto outspl;
1205132451Sroberto
1206182007Sroberto	switch (cmd) {
1207285612Sdelphij	case TIOCSBRK:
1208285612Sdelphij		si_command(pp, SBREAK, SI_NOWAIT);
1209285612Sdelphij		break;
1210285612Sdelphij	case TIOCCBRK:
1211285612Sdelphij		si_command(pp, EBREAK, SI_NOWAIT);
1212285612Sdelphij		break;
1213285612Sdelphij	case TIOCSDTR:
1214285612Sdelphij		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1215132451Sroberto		break;
1216182007Sroberto	case TIOCCDTR:
1217182007Sroberto		(void) si_modem(pp, SET, 0);
1218285612Sdelphij		break;
1219285612Sdelphij	case TIOCMSET:
1220285612Sdelphij		(void) si_modem(pp, SET, *(int *)data);
1221182007Sroberto		break;
1222285612Sdelphij	case TIOCMBIS:
1223182007Sroberto		(void) si_modem(pp, BIS, *(int *)data);
1224182007Sroberto		break;
1225182007Sroberto	case TIOCMBIC:
1226182007Sroberto		(void) si_modem(pp, BIC, *(int *)data);
1227182007Sroberto		break;
1228285612Sdelphij	case TIOCMGET:
1229182007Sroberto		*(int *)data = si_modem(pp, GET, 0);
1230182007Sroberto		break;
1231285612Sdelphij	case TIOCMSDTRWAIT:
1232285612Sdelphij		/* must be root since the wait applies to following logins */
1233285612Sdelphij		error = suser(p->p_ucred, &p->p_acflag);
1234285612Sdelphij		if (error != 0) {
1235285612Sdelphij			goto outspl;
1236182007Sroberto		}
1237182007Sroberto		pp->sp_dtr_wait = *(int *)data * hz / 100;
1238182007Sroberto		break;
1239285612Sdelphij	case TIOCMGDTRWAIT:
124082498Sroberto		*(int *)data = pp->sp_dtr_wait * 100 / hz;
124182498Sroberto		break;
124282498Sroberto
1243132451Sroberto	default:
124482498Sroberto		error = ENOTTY;
1245132451Sroberto	}
1246285612Sdelphij	error = 0;
1247285612Sdelphijoutspl:
1248285612Sdelphij	splx(oldspl);
1249182007Srobertoout:
1250285612Sdelphij	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
1251182007Sroberto	if (blocked)
1252182007Sroberto		si_write_enable(pp, 1);
125382498Sroberto	return(error);
125482498Sroberto}
125582498Sroberto
1256132451Sroberto/*
125782498Sroberto * Handle the Specialix ioctls. All MUST be called via the CONTROL device
1258132451Sroberto */
1259182007Srobertostatic int
1260285612Sdelphijsi_Sioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
1261182007Sroberto{
1262182007Sroberto	struct si_softc *xsc;
1263132451Sroberto	register struct si_port *xpp;
1264132451Sroberto	volatile struct si_reg *regp;
126582498Sroberto	struct si_tcsi *dp;
1266132451Sroberto	struct si_pstat *sps;
126782498Sroberto	int *ip, error = 0;
1268132451Sroberto	int oldspl;
1269285612Sdelphij	int card, port;
1270285612Sdelphij	int mynor = minor(dev);
1271285612Sdelphij
1272182007Sroberto	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%x,%x,%x)\n",
1273285612Sdelphij		dev, cmd, data, flag));
1274182007Sroberto
1275182007Sroberto#if 1
127682498Sroberto	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
127782498Sroberto	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
127882498Sroberto	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
1279132451Sroberto#endif
128082498Sroberto
1281132451Sroberto	if (!IS_CONTROLDEV(mynor)) {
1282182007Sroberto		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
1283285612Sdelphij		return(ENODEV);
1284182007Sroberto	}
1285182007Sroberto
1286132451Sroberto	oldspl = spltty();	/* better safe than sorry */
1287132451Sroberto
1288132451Sroberto	ip = (int *)data;
1289132451Sroberto
1290132451Sroberto#define SUCHECK if (error = suser(p->p_ucred, &p->p_acflag)) goto out
1291132451Sroberto
1292285612Sdelphij	switch (cmd) {
1293285612Sdelphij	case TCSIPORTS:
1294285612Sdelphij		*ip = si_Nports;
1295182007Sroberto		goto out;
1296285612Sdelphij	case TCSIMODULES:
1297182007Sroberto		*ip = si_Nmodules;
1298182007Sroberto		goto out;
129982498Sroberto	case TCSISDBG_ALL:
130082498Sroberto		SUCHECK;
130182498Sroberto		si_debug = *ip;
1302132451Sroberto		goto out;
130382498Sroberto	case TCSIGDBG_ALL:
1304132451Sroberto		*ip = si_debug;
1305182007Sroberto		goto out;
1306285612Sdelphij	default:
1307182007Sroberto		/*
1308182007Sroberto		 * Check that a controller for this port exists
1309132451Sroberto		 */
1310132451Sroberto
1311132451Sroberto		/* may also be a struct si_pstat, a superset of si_tcsi */
1312132451Sroberto
1313132451Sroberto		dp = (struct si_tcsi *)data;
1314132451Sroberto		sps = (struct si_pstat *)data;
1315132451Sroberto		card = dp->tc_card;
1316132451Sroberto		xsc = &si_softc[card];	/* check.. */
1317132451Sroberto		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
1318132451Sroberto			error = ENOENT;
1319132451Sroberto			goto out;
1320285612Sdelphij		}
1321285612Sdelphij		/*
1322285612Sdelphij		 * And check that a port exists
1323285612Sdelphij		 */
1324132451Sroberto		port = dp->tc_port;
1325132451Sroberto		if (port < 0 || port >= xsc->sc_nport) {
1326132451Sroberto			error = ENOENT;
1327132451Sroberto			goto out;
1328132451Sroberto		}
1329132451Sroberto		xpp = xsc->sc_ports + port;
1330132451Sroberto		regp = (struct si_reg *)xsc->sc_maddr;
1331285612Sdelphij	}
1332132451Sroberto
1333132451Sroberto	switch (cmd) {
1334132451Sroberto	case TCSIDEBUG:
1335132451Sroberto#ifdef	SI_DEBUG
1336132451Sroberto		SUCHECK;
1337132451Sroberto		if (xpp->sp_debug)
1338132451Sroberto			xpp->sp_debug = 0;
1339281230Sdelphij		else {
1340281230Sdelphij			xpp->sp_debug = DBG_ALL;
1341281230Sdelphij			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
1342281230Sdelphij				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
1343182007Sroberto		}
134482498Sroberto		break;
134582498Sroberto#else
1346285612Sdelphij		error = ENODEV;
1347132451Sroberto		goto out;
1348285612Sdelphij#endif
1349285612Sdelphij	case TCSISDBG_LEVEL:
1350281230Sdelphij	case TCSIGDBG_LEVEL:
1351281230Sdelphij#ifdef	SI_DEBUG
1352285612Sdelphij		if (cmd == TCSIGDBG_LEVEL) {
1353281230Sdelphij			dp->tc_dbglvl = xpp->sp_debug;
1354281230Sdelphij		} else {
135582498Sroberto			SUCHECK;
135682498Sroberto			xpp->sp_debug = dp->tc_dbglvl;
135782498Sroberto		}
1358132451Sroberto		break;
1359132451Sroberto#else
1360132451Sroberto		error = ENODEV;
1361132451Sroberto		goto out;
1362132451Sroberto#endif
136382498Sroberto	case TCSIGRXIT:
1364132451Sroberto		dp->tc_int = regp->rx_int_count;
1365285612Sdelphij		break;
1366285612Sdelphij	case TCSIRXIT:
1367285612Sdelphij		SUCHECK;
1368285612Sdelphij		regp->rx_int_count = dp->tc_int;
1369285612Sdelphij		break;
137082498Sroberto	case TCSIGIT:
1371132451Sroberto		dp->tc_int = regp->int_count;
1372285612Sdelphij		break;
137382498Sroberto	case TCSIIT:
137482498Sroberto		SUCHECK;
137582498Sroberto		regp->int_count = dp->tc_int;
1376285612Sdelphij		break;
1377285612Sdelphij	case TCSISTATE:
1378182007Sroberto		dp->tc_int = xpp->sp_ccb->hi_ip;
137982498Sroberto		break;
1380285612Sdelphij	/* these next three use a different structure */
1381285612Sdelphij	case TCSI_PORT:
138282498Sroberto		SUCHECK;
138382498Sroberto		sps->tc_siport = *xpp;
138482498Sroberto		break;
1385285612Sdelphij	case TCSI_CCB:
1386285612Sdelphij		SUCHECK;
138782498Sroberto		sps->tc_ccb = *xpp->sp_ccb;
138882498Sroberto		break;
138982498Sroberto	case TCSI_TTY:
1390182007Sroberto		SUCHECK;
139182498Sroberto		sps->tc_tty = *xpp->sp_tty;
139282498Sroberto		break;
139382498Sroberto	default:
1394182007Sroberto		error = EINVAL;
1395182007Sroberto		goto out;
1396132451Sroberto	}
1397182007Srobertoout:
1398285612Sdelphij	splx(oldspl);
1399285612Sdelphij	return(error);		/* success */
1400285612Sdelphij}
1401285612Sdelphij
1402285612Sdelphij/*
1403285612Sdelphij *	siparam()	: Configure line params
1404285612Sdelphij *	called at spltty();
1405285612Sdelphij *	this may sleep, does not flush, nor wait for drain, nor block writes
1406132451Sroberto *	caller must arrange this if it's important..
1407285612Sdelphij */
1408182007Srobertostatic int
1409182007Srobertosiparam(tp, t)
1410132451Sroberto	register struct tty *tp;
1411285612Sdelphij	register struct termios *t;
1412285612Sdelphij{
141382498Sroberto	register struct si_port *pp = TP2PP(tp);
141482498Sroberto	volatile struct si_channel *ccbp;
141582498Sroberto	int oldspl, cflag, iflag, oflag, lflag;
1416132451Sroberto	int error = 0;		/* shutup gcc */
141782498Sroberto	int ispeed = 0;		/* shutup gcc */
1418285612Sdelphij	int ospeed = 0;		/* shutup gcc */
1419132451Sroberto	BYTE val;
1420132451Sroberto
1421132451Sroberto	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
1422285612Sdelphij	cflag = t->c_cflag;
1423285612Sdelphij	iflag = t->c_iflag;
1424132451Sroberto	oflag = t->c_oflag;
1425132451Sroberto	lflag = t->c_lflag;
1426132451Sroberto	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
1427132451Sroberto		oflag, cflag, iflag, lflag));
1428285612Sdelphij
142982498Sroberto
1430132451Sroberto	/* if not hung up.. */
1431132451Sroberto	if (t->c_ospeed != 0) {
1432132451Sroberto		/* translate baud rate to firmware values */
1433132451Sroberto		ospeed = ttspeedtab(t->c_ospeed, bdrates);
1434132451Sroberto		ispeed = t->c_ispeed ?
1435132451Sroberto			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
143682498Sroberto
1437132451Sroberto		/* enforce legit baud rate */
1438310419Sdelphij		if (ospeed < 0 || ispeed < 0)
1439182007Sroberto			return (EINVAL);
1440182007Sroberto	}
1441132451Sroberto
1442132451Sroberto
1443132451Sroberto	oldspl = spltty();
1444132451Sroberto
144582498Sroberto	ccbp = pp->sp_ccb;
144682498Sroberto
1447285612Sdelphij	/* ========== set hi_break ========== */
1448285612Sdelphij	val = 0;
1449285612Sdelphij	if (iflag & IGNBRK)		/* Breaks */
1450285612Sdelphij		val |= BR_IGN;
145182498Sroberto	if (iflag & BRKINT)		/* Interrupt on break? */
1452132451Sroberto		val |= BR_INT;
1453132451Sroberto	if (iflag & PARMRK)		/* Parity mark? */
145482498Sroberto		val |= BR_PARMRK;
145582498Sroberto	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
1456285612Sdelphij		val |= BR_PARIGN;
1457285612Sdelphij	ccbp->hi_break = val;
1458285612Sdelphij
1459285612Sdelphij	/* ========== set hi_csr ========== */
146082498Sroberto	/* if not hung up.. */
1461132451Sroberto	if (t->c_ospeed != 0) {
1462182007Sroberto		/* Set I/O speeds */
1463182007Sroberto		 val = (ispeed << 4) | ospeed;
1464285612Sdelphij	}
1465285612Sdelphij	ccbp->hi_csr = val;
1466285612Sdelphij
1467285612Sdelphij	/* ========== set hi_mr2 ========== */
1468285612Sdelphij	val = 0;
1469285612Sdelphij	if (cflag & CSTOPB)				/* Stop bits */
1470285612Sdelphij		val |= MR2_2_STOP;
1471132451Sroberto	else
1472285612Sdelphij		val |= MR2_1_STOP;
1473285612Sdelphij	/*
1474132451Sroberto	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1475182007Sroberto	 * a DCE, hence the reverse sense of RTS and CTS
1476132451Sroberto	 */
1477285612Sdelphij	/* Output Flow - RTS must be raised before data can be sent */
1478285612Sdelphij	if (cflag & CCTS_OFLOW)
1479285612Sdelphij		val |= MR2_RTSCONT;
1480285612Sdelphij
1481285612Sdelphij	ccbp->hi_mr1 = val;
1482132451Sroberto
1483132451Sroberto	/* ========== set hi_mr1 ========== */
1484281230Sdelphij	val = 0;
1485281230Sdelphij	if (!(cflag & PARENB))				/* Parity */
1486281230Sdelphij		val |= MR1_NONE;
1487285612Sdelphij	else
1488132451Sroberto		val |= MR1_WITH;
1489132451Sroberto	if (cflag & PARODD)
1490281230Sdelphij		val |= MR1_ODD;
1491281230Sdelphij
1492281230Sdelphij	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1493281230Sdelphij		val |= MR1_8_BITS;
1494132451Sroberto	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1495132451Sroberto		val |= MR1_7_BITS;
1496182007Sroberto	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1497182007Sroberto		val |= MR1_6_BITS;
1498182007Sroberto	} else {					/* Must be 5 */
1499285612Sdelphij		val |= MR1_5_BITS;
1500182007Sroberto	}
1501285612Sdelphij	/*
1502285612Sdelphij	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
1503182007Sroberto	 * a DCE, hence the reverse sense of RTS and CTS
1504182007Sroberto	 */
1505182007Sroberto	/* Input Flow - CTS is raised when port is ready to receive data */
1506285612Sdelphij	if (cflag & CRTS_IFLOW)
1507182007Sroberto		val |= MR1_CTSCONT;
1508182007Sroberto
1509182007Sroberto	ccbp->hi_mr1 = val;
1510182007Sroberto
1511182007Sroberto	/* ========== set hi_mask ========== */
1512182007Sroberto	val = 0xff;
1513182007Sroberto	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
1514285612Sdelphij		val &= 0xFF;
1515285612Sdelphij	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
1516285612Sdelphij		val &= 0x7F;
1517182007Sroberto	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
1518285612Sdelphij		val &= 0x3F;
1519285612Sdelphij	} else {					/* Must be 5 */
1520285612Sdelphij		val &= 0x1F;
1521182007Sroberto	}
1522182007Sroberto	if (iflag & ISTRIP)
1523182007Sroberto		val &= 0x7F;
1524285612Sdelphij
1525285612Sdelphij	ccbp->hi_mask = val;
1526285612Sdelphij
1527285612Sdelphij	/* ========== set hi_prtcl ========== */
1528285612Sdelphij	val = 0;
1529285612Sdelphij				/* Monitor DCD etc. if a modem */
1530285612Sdelphij	if (!(cflag & CLOCAL))
1531285612Sdelphij		val |= SP_DCEN;
1532182007Sroberto	if (iflag & IXANY)
1533182007Sroberto		val |= SP_TANY;
1534182007Sroberto	if (iflag & IXON)
1535132451Sroberto		val |= SP_TXEN;
1536132451Sroberto	if (iflag & IXOFF)
1537132451Sroberto		val |= SP_RXEN;
1538132451Sroberto	if (iflag & INPCK)
1539182007Sroberto		val |= SP_PAEN;
1540285612Sdelphij
1541132451Sroberto	ccbp->hi_prtcl = val;
1542182007Sroberto
1543182007Sroberto
1544182007Sroberto	/* ========== set hi_{rx|tx}{on|off} ========== */
1545132451Sroberto	/* XXX: the card TOTALLY shields us from the flow control... */
1546182007Sroberto	ccbp->hi_txon = t->c_cc[VSTART];
1547182007Sroberto	ccbp->hi_txoff = t->c_cc[VSTOP];
1548285612Sdelphij
1549132451Sroberto	ccbp->hi_rxon = t->c_cc[VSTART];
1550310419Sdelphij	ccbp->hi_rxoff = t->c_cc[VSTOP];
1551310419Sdelphij
1552281230Sdelphij	/* ========== send settings to the card ========== */
1553310419Sdelphij	/* potential sleep here */
1554310419Sdelphij	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
1555310419Sdelphij		si_command(pp, LOPEN, SI_WAIT);		/* open it */
1556310419Sdelphij	else
1557182007Sroberto		si_command(pp, CONFIG, SI_WAIT);	/* change params */
1558310419Sdelphij
1559310419Sdelphij	/* ========== set DTR etc ========== */
1560182007Sroberto	/* Hangup if ospeed == 0 */
1561285612Sdelphij	if (t->c_ospeed == 0) {
1562182007Sroberto		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
1563182007Sroberto	} else {
1564132451Sroberto		/*
1565132451Sroberto		 * If the previous speed was 0, may need to re-enable
1566132451Sroberto	 	 * the modem signals
1567132451Sroberto	 	 */
1568281230Sdelphij		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
1569281230Sdelphij	}
1570132451Sroberto
1571281230Sdelphij	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
1572132451Sroberto		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
1573285612Sdelphij
1574132451Sroberto	splx(oldspl);
1575132451Sroberto	return(error);
1576132451Sroberto}
1577132451Sroberto
1578281230Sdelphij/*
1579281230Sdelphij * Enable or Disable the writes to this channel...
1580281230Sdelphij * "state" ->  enabled = 1; disabled = 0;
1581281230Sdelphij */
1582132451Srobertostatic void
1583132451Srobertosi_write_enable(pp, state)
1584132451Sroberto	register struct si_port *pp;
1585310419Sdelphij	int state;
1586132451Sroberto{
1587132451Sroberto	int oldspl;
1588285612Sdelphij
1589132451Sroberto	oldspl = spltty();
1590132451Sroberto
1591132451Sroberto	if (state) {
1592132451Sroberto		pp->sp_state &= ~SS_BLOCKWRITE;
1593281230Sdelphij		if (pp->sp_state & SS_WAITWRITE) {
1594132451Sroberto			pp->sp_state &= ~SS_WAITWRITE;
1595285612Sdelphij			/* thunder away! */
1596132451Sroberto			wakeup((caddr_t)pp);
1597132451Sroberto		}
159882498Sroberto	} else {
159982498Sroberto		pp->sp_state |= SS_BLOCKWRITE;
160082498Sroberto	}
1601132451Sroberto
160282498Sroberto	splx(oldspl);
1603285612Sdelphij}
1604132451Sroberto
1605132451Sroberto/*
1606132451Sroberto * Set/Get state of modem control lines.
1607281230Sdelphij * Due to DCE-like behaviour of the adapter, some signals need translation:
1608281230Sdelphij *	TIOCM_DTR	DSR
1609281230Sdelphij *	TIOCM_RTS	CTS
1610285612Sdelphij */
1611132451Srobertostatic int
1612285612Sdelphijsi_modem(pp, cmd, bits)
1613310419Sdelphij	struct si_port *pp;
1614285612Sdelphij	enum si_mctl cmd;
1615132451Sroberto	int bits;
1616285612Sdelphij{
1617132451Sroberto	volatile struct si_channel *ccbp;
1618132451Sroberto	int x;
1619132451Sroberto
1620132451Sroberto	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
1621132451Sroberto	ccbp = pp->sp_ccb;		/* Find channel address */
1622132451Sroberto	switch (cmd) {
1623182007Sroberto	case GET:
1624132451Sroberto		x = ccbp->hi_ip;
1625310419Sdelphij		bits = TIOCM_LE;
1626310419Sdelphij		if (x & IP_DCD)		bits |= TIOCM_CAR;
1627310419Sdelphij		if (x & IP_DTR)		bits |= TIOCM_DTR;
1628310419Sdelphij		if (x & IP_RTS)		bits |= TIOCM_RTS;
1629310419Sdelphij		if (x & IP_RI)		bits |= TIOCM_RI;
1630289997Sglebius		return(bits);
1631285612Sdelphij	case SET:
1632285612Sdelphij		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
1633310419Sdelphij		/* fall through */
1634132451Sroberto	case BIS:
1635132451Sroberto		x = 0;
163682498Sroberto		if (bits & TIOCM_DTR)
1637132451Sroberto			x |= OP_DSR;
1638132451Sroberto		if (bits & TIOCM_RTS)
1639132451Sroberto			x |= OP_CTS;
1640132451Sroberto		ccbp->hi_op |= x;
1641132451Sroberto		break;
1642132451Sroberto	case BIC:
1643285612Sdelphij		if (bits & TIOCM_DTR)
1644285612Sdelphij			ccbp->hi_op &= ~OP_DSR;
1645285612Sdelphij		if (bits & TIOCM_RTS)
1646285612Sdelphij			ccbp->hi_op &= ~OP_CTS;
1647285612Sdelphij	}
1648285612Sdelphij	return 0;
1649132451Sroberto}
1650132451Sroberto
1651132451Sroberto/*
1652132451Sroberto * Handle change of modem state
1653132451Sroberto */
1654132451Srobertostatic void
1655285612Sdelphijsi_modem_state(pp, tp, hi_ip)
1656285612Sdelphij	register struct si_port *pp;
1657285612Sdelphij	register struct tty *tp;
1658132451Sroberto	register int hi_ip;
165982498Sroberto{
1660285612Sdelphij							/* if a modem dev */
1661285612Sdelphij	if (hi_ip & IP_DCD) {
1662285612Sdelphij		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
1663285612Sdelphij			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
166482498Sroberto				tp->t_line));
1665285612Sdelphij			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
1666132451Sroberto		}
1667285612Sdelphij	} else {
1668285612Sdelphij		if (pp->sp_last_hi_ip & IP_DCD) {
1669285612Sdelphij			DPRINT((pp, DBG_INTR, "modem carr off\n"));
1670285612Sdelphij			if ((*linesw[tp->t_line].l_modem)(tp, 0))
1671285612Sdelphij				(void) si_modem(pp, SET, 0);
1672285612Sdelphij		}
1673285612Sdelphij	}
1674285612Sdelphij	pp->sp_last_hi_ip = hi_ip;
1675132451Sroberto
1676132451Sroberto}
1677285612Sdelphij
1678285612Sdelphij/*
1679285612Sdelphij * Poller to catch missed interrupts.
1680285612Sdelphij *
1681285612Sdelphij * Note that the SYSV Specialix drivers poll at 100 times per second to get
1682132451Sroberto * better response.  We could really use a "periodic" version timeout(). :-)
1683285612Sdelphij */
1684132451Sroberto#ifdef POLL
1685132451Srobertostatic void
1686285612Sdelphijsi_poll(void *nothing)
1687285612Sdelphij{
1688285612Sdelphij	register struct si_softc *sc;
1689285612Sdelphij	register int i;
1690285612Sdelphij	volatile struct si_reg *regp;
1691132451Sroberto	register struct si_port *pp;
169282498Sroberto	int lost, oldspl, port;
1693132451Sroberto
1694132451Sroberto	DPRINT((0, DBG_POLL, "si_poll()\n"));
1695132451Sroberto	oldspl = spltty();
1696132451Sroberto	if (in_intr)
1697132451Sroberto		goto out;
1698132451Sroberto	lost = 0;
1699132451Sroberto	for (i=0; i<NSI; i++) {
1700132451Sroberto		sc = &si_softc[i];
1701132451Sroberto		if (sc->sc_type == SIEMPTY)
1702285612Sdelphij			continue;
1703281230Sdelphij		regp = (struct si_reg *)sc->sc_maddr;
1704281230Sdelphij		/*
1705281230Sdelphij		 * See if there has been a pending interrupt for 2 seconds
1706132451Sroberto		 * or so. The test <int_scounter >= 200) won't correspond
1707132451Sroberto		 * to 2 seconds if int_count gets changed.
1708132451Sroberto		 */
1709132451Sroberto		if (regp->int_pending != 0) {
1710132451Sroberto			if (regp->int_scounter >= 200 &&
1711285612Sdelphij			    regp->initstat == 1) {
1712132451Sroberto				printf("si%d: lost intr\n", i);
1713132451Sroberto				lost++;
1714132451Sroberto			}
1715132451Sroberto		} else {
1716132451Sroberto			regp->int_scounter = 0;
1717132451Sroberto		}
1718285612Sdelphij
1719132451Sroberto		/*
1720132451Sroberto		 * gripe about no input flow control..
1721132451Sroberto		 */
1722281230Sdelphij		pp = sc->sc_ports;
1723281230Sdelphij		for (port = 0; port < sc->sc_nport; pp++, port++) {
1724285612Sdelphij			if (pp->sp_delta_overflows > 0) {
1725281230Sdelphij				printf("si%d: %d tty level buffer overflows\n",
1726281230Sdelphij					i, pp->sp_delta_overflows);
1727285612Sdelphij				pp->sp_delta_overflows = 0;
1728182007Sroberto			}
1729182007Sroberto		}
1730182007Sroberto	}
1731285612Sdelphij	if (lost)
1732285612Sdelphij		siintr(-1);	/* call intr with fake vector */
1733285612Sdelphijout:
1734132451Sroberto	splx(oldspl);
1735285612Sdelphij
1736132451Sroberto	timeout(si_poll, (caddr_t)0L, POLL_INTERVAL);
1737132451Sroberto}
1738132451Sroberto#endif	/* ifdef POLL */
1739132451Sroberto
1740281230Sdelphij/*
1741281230Sdelphij * The interrupt handler polls ALL ports on ALL adapters each time
1742132451Sroberto * it is called.
1743132451Sroberto */
174482498Sroberto
174582498Srobertostatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
174682498Sroberto
174782498Srobertovoid
1748132451Srobertosiintr(int unit)
1749132451Sroberto{
1750285612Sdelphij	register struct si_softc *sc;
1751285612Sdelphij
1752285612Sdelphij	register struct si_port *pp;
1753285612Sdelphij	volatile struct si_channel *ccbp;
1754281230Sdelphij	register struct tty *tp;
1755281230Sdelphij	volatile caddr_t maddr;
175682498Sroberto	BYTE op, ip;
1757285612Sdelphij	int x, card, port, n, i, isopen;
1758132451Sroberto	volatile BYTE *z;
1759132451Sroberto	BYTE c;
1760285612Sdelphij
1761285612Sdelphij	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "siintr(%d)\n", unit));
1762132451Sroberto	if (in_intr) {
176382498Sroberto		if (unit < 0)	/* should never happen */
1764285612Sdelphij			return;
1765285612Sdelphij		printf("si%d: Warning interrupt handler re-entered\n",
176682498Sroberto			unit);
176782498Sroberto		return;
1768285612Sdelphij	}
1769285612Sdelphij	in_intr = 1;
177082498Sroberto
1771285612Sdelphij	/*
1772285612Sdelphij	 * When we get an int we poll all the channels and do ALL pending
1773285612Sdelphij	 * work, not just the first one we find. This allows all cards to
1774285612Sdelphij	 * share the same vector.
1775285612Sdelphij	 */
1776285612Sdelphij	for (card=0; card < NSI; card++) {
1777285612Sdelphij		sc = &si_softc[card];
1778285612Sdelphij		if (sc->sc_type == SIEMPTY)
1779285612Sdelphij			continue;
1780285612Sdelphij
1781285612Sdelphij		/*
1782285612Sdelphij		 * First, clear the interrupt
1783132451Sroberto		 */
1784132451Sroberto		switch(sc->sc_type) {
1785132451Sroberto		case SIHOST :
1786132451Sroberto			maddr = sc->sc_maddr;
1787132451Sroberto			((volatile struct si_reg *)maddr)->int_pending = 0;
1788285612Sdelphij							/* flag nothing pending */
1789285612Sdelphij			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
1790285612Sdelphij			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
1791285612Sdelphij			break;
1792285612Sdelphij		case SIHOST2:
1793285612Sdelphij			maddr = sc->sc_maddr;
1794285612Sdelphij			((volatile struct si_reg *)maddr)->int_pending = 0;
1795285612Sdelphij			*(maddr+SIPLIRQCLR) = 0x00;
1796285612Sdelphij			*(maddr+SIPLIRQCLR) = 0x10;
1797285612Sdelphij			break;
1798285612Sdelphij		case SIEISA:
1799285612Sdelphij#if NEISA > 0
1800285612Sdelphij			maddr = sc->sc_maddr;
1801132451Sroberto			((volatile struct si_reg *)maddr)->int_pending = 0;
1802132451Sroberto			(void)inb(sc->sc_eisa_iobase+3);
1803132451Sroberto			break;
1804132451Sroberto#endif	/* fall through if not EISA kernel */
1805285612Sdelphij		case SIEMPTY:
1806285612Sdelphij		default:
1807285612Sdelphij			continue;
1808285612Sdelphij		}
1809285612Sdelphij		((volatile struct si_reg *)maddr)->int_scounter = 0;
1810289997Sglebius
1811285612Sdelphij		/*
1812285612Sdelphij		 * check each port
1813285612Sdelphij		 */
1814285612Sdelphij		for (pp=sc->sc_ports,port=0; port < sc->sc_nport; pp++,port++) {
1815132451Sroberto			ccbp = pp->sp_ccb;
1816132451Sroberto			tp = pp->sp_tty;
1817132451Sroberto
1818132451Sroberto
1819132451Sroberto			/*
1820132451Sroberto			 * See if a command has completed ?
1821132451Sroberto			 */
1822132451Sroberto			if (ccbp->hi_stat != pp->sp_pend) {
1823132451Sroberto				DPRINT((pp, DBG_INTR,
1824132451Sroberto					"siintr hi_stat = 0x%x, pend = %d\n",
1825132451Sroberto					ccbp->hi_stat, pp->sp_pend));
1826132451Sroberto				switch(pp->sp_pend) {
1827132451Sroberto				case LOPEN:
1828132451Sroberto				case MPEND:
1829285612Sdelphij				case MOPEN:
1830132451Sroberto				case CONFIG:
1831285612Sdelphij					pp->sp_pend = ccbp->hi_stat;
1832285612Sdelphij						/* sleeping in si_command */
1833285612Sdelphij					wakeup(&pp->sp_state);
1834132451Sroberto					break;
1835132451Sroberto				default:
1836132451Sroberto					pp->sp_pend = ccbp->hi_stat;
1837132451Sroberto				}
1838132451Sroberto	 		}
1839132451Sroberto
1840310419Sdelphij			/*
1841285612Sdelphij			 * Continue on if it's closed
1842132451Sroberto			 */
1843285612Sdelphij			if (ccbp->hi_stat == IDLE_CLOSE) {
1844132451Sroberto				continue;
1845285612Sdelphij			}
1846132451Sroberto
1847285612Sdelphij			/*
1848285612Sdelphij			 * Do modem state change if not a local device
184982498Sroberto			 */
1850182007Sroberto			si_modem_state(pp, tp, ccbp->hi_ip);
1851310419Sdelphij
1852310419Sdelphij			/*
185382498Sroberto			 * Check to see if there's we should 'receive'
1854132451Sroberto			 * characters.
1855132451Sroberto			 */
1856132451Sroberto			if (tp->t_state & TS_CONNECTED &&
185782498Sroberto			    tp->t_state & TS_ISOPEN)
1858132451Sroberto				isopen = 1;
1859132451Sroberto			else
1860132451Sroberto				isopen = 0;
1861132451Sroberto
1862132451Sroberto			/*
1863310419Sdelphij			 * Do break processing
1864310419Sdelphij			 */
1865310419Sdelphij			if (ccbp->hi_state & ST_BREAK) {
1866310419Sdelphij				if (isopen) {
1867289997Sglebius				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
1868132451Sroberto				}
1869285612Sdelphij				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
187082498Sroberto				DPRINT((pp, DBG_INTR, "si_intr break\n"));
187182498Sroberto			}
187282498Sroberto
1873132451Sroberto			/*
1874132451Sroberto			 * Do RX stuff - if not open then dump any characters.
1875182007Sroberto			 * XXX: This is VERY messy and needs to be cleaned up.
1876182007Sroberto			 *
187782498Sroberto			 * XXX: can we leave data in the host adapter buffer
1878285612Sdelphij			 * when the clists are full?  That may be dangerous
1879182007Sroberto			 * if the user cannot get an interrupt signal through.
1880182007Sroberto			 */
1881182007Sroberto
1882182007Sroberto	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
1883310419Sdelphij
1884310419Sdelphij			if (!isopen) {
1885310419Sdelphij				ccbp->hi_rxopos = ccbp->hi_rxipos;
1886182007Sroberto				goto end_rx;
1887310419Sdelphij			}
1888289997Sglebius
1889182007Sroberto			/*
1890285612Sdelphij			 * Process read characters if not skipped above
189182498Sroberto			 */
189282498Sroberto			c = ccbp->hi_rxipos - ccbp->hi_rxopos;
189382498Sroberto			if (c == 0) {
1894285612Sdelphij				goto end_rx;
1895285612Sdelphij			}
189682498Sroberto
1897285612Sdelphij			op = ccbp->hi_rxopos;
1898285612Sdelphij			ip = ccbp->hi_rxipos;
1899285612Sdelphij			n = c & 0xff;
1900285612Sdelphij
1901285612Sdelphij			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1902285612Sdelphij						n, op, ip));
1903285612Sdelphij
1904285612Sdelphij			/*
1905285612Sdelphij			 * Suck characters out of host card buffer into the
1906285612Sdelphij			 * "input staging buffer" - so that we dont leave the
1907285612Sdelphij			 * host card in limbo while we're possibly echoing
190882498Sroberto			 * characters and possibly flushing input inside the
1909285612Sdelphij			 * ldisc l_rint() routine.
1910285612Sdelphij			 */
1911285612Sdelphij			if (n <= SI_BUFFERSIZE - op) {
1912285612Sdelphij
1913285612Sdelphij				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
1914285612Sdelphij				z = ccbp->hi_rxbuf + op;
1915285612Sdelphij				bcopy((caddr_t)z, si_rxbuf, n);
1916285612Sdelphij
1917285612Sdelphij				op += n;
1918285612Sdelphij			} else {
1919285612Sdelphij				x = SI_BUFFERSIZE - op;
1920285612Sdelphij
1921285612Sdelphij				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
1922285612Sdelphij				z = ccbp->hi_rxbuf + op;
1923285612Sdelphij				bcopy((caddr_t)z, si_rxbuf, x);
1924285612Sdelphij
1925285612Sdelphij				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n-x));
1926285612Sdelphij				z = ccbp->hi_rxbuf;
1927285612Sdelphij				bcopy((caddr_t)z, si_rxbuf+x, n-x);
1928285612Sdelphij
1929285612Sdelphij				op += n;
1930285612Sdelphij			}
1931285612Sdelphij
1932285612Sdelphij			/* clear collected characters from buffer */
1933285612Sdelphij			ccbp->hi_rxopos = op;
1934310419Sdelphij
1935310419Sdelphij			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1936310419Sdelphij						n, op, ip));
1937310419Sdelphij
1938289997Sglebius			/*
1939285612Sdelphij			 * at this point...
1940285612Sdelphij			 * n = number of chars placed in si_rxbuf
1941285612Sdelphij			 */
1942285612Sdelphij
1943285612Sdelphij			/*
1944285612Sdelphij			 * Avoid the grotesquely inefficient lineswitch
1945132451Sroberto			 * routine (ttyinput) in "raw" mode. It usually
1946285612Sdelphij			 * takes about 450 instructions (that's without
1947310419Sdelphij			 * canonical processing or echo!). slinput is
194882498Sroberto			 * reasonably fast (usually 40 instructions
194982498Sroberto			 * plus call overhead).
1950285612Sdelphij			 */
1951285612Sdelphij			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1952285612Sdelphij
1953285612Sdelphij				/* block if the driver supports it */
1954285612Sdelphij				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
1955285612Sdelphij				    && (tp->t_cflag & CRTS_IFLOW
1956285612Sdelphij					|| tp->t_iflag & IXOFF)
1957285612Sdelphij				    && !(tp->t_state & TS_TBLOCK))
1958285612Sdelphij					ttyblock(tp);
1959285612Sdelphij
1960285612Sdelphij				tk_nin += n;
1961285612Sdelphij				tk_rawcc += n;
1962285612Sdelphij				tp->t_rawcc += n;
1963285612Sdelphij
1964285612Sdelphij				pp->sp_delta_overflows +=
1965285612Sdelphij				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
1966285612Sdelphij
1967285612Sdelphij				ttwakeup(tp);
196882498Sroberto				if (tp->t_state & TS_TTSTOP
1969285612Sdelphij				    && (tp->t_iflag & IXANY
1970285612Sdelphij					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1971285612Sdelphij					tp->t_state &= ~TS_TTSTOP;
1972285612Sdelphij					tp->t_lflag &= ~FLUSHO;
1973285612Sdelphij					si_start(tp);
1974285612Sdelphij				}
1975285612Sdelphij			} else {
1976285612Sdelphij				/*
1977285612Sdelphij				 * It'd be nice to not have to go through the
1978285612Sdelphij				 * function call overhead for each char here.
1979285612Sdelphij				 * It'd be nice to block input it, saving a
1980285612Sdelphij				 * loop here and the call/return overhead.
198182498Sroberto				 */
1982132451Sroberto				for(x = 0; x < n; x++) {
1983132451Sroberto					i = si_rxbuf[x];
1984132451Sroberto					if ((*linesw[tp->t_line].l_rint)(i, tp)
198582498Sroberto					     == -1) {
1986132451Sroberto						pp->sp_delta_overflows++;
1987132451Sroberto					}
1988132451Sroberto					/*
198982498Sroberto					 * doesn't seem to be much point doing
199082498Sroberto					 * this here.. this driver has no
1991132451Sroberto					 * softtty processing! ??
1992132451Sroberto					 */
1993132451Sroberto					if (pp->sp_hotchar && i == pp->sp_hotchar) {
1994132451Sroberto						setsofttty();
1995132451Sroberto					}
1996132451Sroberto				}
199782498Sroberto			}
1998132451Sroberto			goto more_rx;	/* try for more until RXbuf is empty */
1999132451Sroberto
2000285612Sdelphij	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
2001285612Sdelphij
2002285612Sdelphij			/*
2003132451Sroberto			 * Do TX stuff
2004132451Sroberto			 */
2005132451Sroberto			(*linesw[tp->t_line].l_start)(tp);
2006132451Sroberto
2007285612Sdelphij		} /* end of for (all ports on this controller) */
2008132451Sroberto	} /* end of for (all controllers) */
2009132451Sroberto
2010132451Sroberto	in_intr = 0;
2011132451Sroberto	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end siintr(%d)\n", unit));
2012132451Sroberto}
2013132451Sroberto
2014132451Sroberto/*
2015132451Sroberto * Nudge the transmitter...
2016132451Sroberto *
2017285612Sdelphij * XXX: I inherited some funny code here.  It implies the host card only
2018285612Sdelphij * interrupts when the transmit buffer reaches the low-water-mark, and does
2019132451Sroberto * not interrupt when it's actually hits empty.  In some cases, we have
2020285612Sdelphij * processes waiting for complete drain, and we need to simulate an interrupt
2021285612Sdelphij * about when we think the buffer is going to be empty (and retry if not).
2022285612Sdelphij * I really am not certain about this...  I *need* the hardware manuals.
2023316722Sdelphij */
2024285612Sdelphijstatic void
2025132451Srobertosi_start(tp)
2026132451Sroberto	register struct tty *tp;
2027285612Sdelphij{
2028285612Sdelphij	struct si_port *pp;
2029285612Sdelphij	volatile struct si_channel *ccbp;
2030132451Sroberto	register struct clist *qp;
203182498Sroberto	register char *dptr;
2032132451Sroberto	BYTE ipos;
2033285612Sdelphij	int nchar;
2034132451Sroberto	int oldspl, count, n, amount, buffer_full;
2035285612Sdelphij	int do_exitproc;
2036285612Sdelphij
2037285612Sdelphij	oldspl = spltty();
203882498Sroberto
2039285612Sdelphij	qp = &tp->t_outq;
2040289997Sglebius	pp = TP2PP(tp);
2041285612Sdelphij
2042289997Sglebius	DPRINT((pp, DBG_ENTRY|DBG_START,
2043285612Sdelphij		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
2044285612Sdelphij		tp, tp->t_state, pp->sp_state, qp->c_cc));
2045285612Sdelphij
2046182007Sroberto	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
2047285612Sdelphij		goto out;
2048285612Sdelphij
2049285612Sdelphij	do_exitproc = 0;
2050285612Sdelphij	buffer_full = 0;
2051285612Sdelphij	ccbp = pp->sp_ccb;
2052285612Sdelphij
2053285612Sdelphij	/*
2054285612Sdelphij	 * Handle the case where ttywait() is called on process exit
2055285612Sdelphij	 * this may be BSDI specific, I dont know...
2056285612Sdelphij	 */
2057285612Sdelphij	if (tp->t_session != NULL && tp->t_session->s_leader != NULL &&
2058285612Sdelphij	    (tp->t_session->s_leader->p_flag & P_WEXIT)) {
2059285612Sdelphij		do_exitproc++;
2060285612Sdelphij	}
2061285612Sdelphij
2062285612Sdelphij	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
2063285612Sdelphij	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
2064285612Sdelphij
2065285612Sdelphij	dptr = (char *)ccbp->hi_txbuf;	/* data buffer */
2066285612Sdelphij
2067285612Sdelphij	while ((nchar = qp->c_cc) > 0) {
2068285612Sdelphij		if ((BYTE)count >= 255) {
2069285612Sdelphij			buffer_full++;
2070285612Sdelphij			break;
2071285612Sdelphij		}
2072285612Sdelphij		amount = min(nchar, (255 - (BYTE)count));
2073132451Sroberto		ipos = (unsigned int)ccbp->hi_txipos;
2074132451Sroberto		/* will it fit in one lump? */
2075132451Sroberto		if ((SI_BUFFERSIZE - ipos) >= amount) {
2076132451Sroberto			n = q_to_b(&tp->t_outq,
2077132451Sroberto				(char *)&ccbp->hi_txbuf[ipos], amount);
2078285612Sdelphij		} else {
2079285612Sdelphij			n = q_to_b(&tp->t_outq,
2080132451Sroberto				(char *)&ccbp->hi_txbuf[ipos],
2081285612Sdelphij				SI_BUFFERSIZE-ipos);
2082132451Sroberto			if (n == SI_BUFFERSIZE-ipos) {
2083132451Sroberto				n += q_to_b(&tp->t_outq,
2084132451Sroberto					(char *)&ccbp->hi_txbuf[0],
2085132451Sroberto					amount - (SI_BUFFERSIZE-ipos));
2086132451Sroberto			}
2087310419Sdelphij		}
2088132451Sroberto		ccbp->hi_txipos += n;
2089132451Sroberto		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
2090132451Sroberto	}
2091132451Sroberto
2092132451Sroberto	if (count != 0 && nchar == 0) {
2093132451Sroberto		tp->t_state |= TS_BUSY;
2094132451Sroberto	} else {
2095310419Sdelphij		tp->t_state &= ~TS_BUSY;
2096330567Sgordon	}
2097330567Sgordon
2098330567Sgordon	/* wakeup time? */
2099330567Sgordon	ttwwakeup(tp);
2100330567Sgordon
2101310419Sdelphij	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
2102330567Sgordon		(BYTE)count, nchar, tp->t_state));
2103310419Sdelphij
2104310419Sdelphij	if ((tp->t_state & TS_BUSY) || do_exitproc)
2105310419Sdelphij	{
2106132451Sroberto		int time;
2107285612Sdelphij
2108132451Sroberto		if (do_exitproc != 0) {
2109132451Sroberto			time = hz / 10;
2110132451Sroberto		} else {
2111132451Sroberto			time = ttspeedtab(tp->t_ospeed, chartimes);
2112132451Sroberto
2113132451Sroberto			if (time > 0) {
2114132451Sroberto				if (time < nchar)
2115132451Sroberto					time = nchar / time;
2116132451Sroberto				else
2117132451Sroberto					time = 2;
2118132451Sroberto			} else {
2119285612Sdelphij				printf("si%d: bad char time value!!\n",
2120285612Sdelphij					(int)SI_CARD(tp->t_dev));
2121285612Sdelphij				goto out;
2122285612Sdelphij			}
2123285612Sdelphij		}
2124285612Sdelphij
2125285612Sdelphij		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
2126285612Sdelphij			untimeout((timeout_func_t)si_lstart, (caddr_t)pp);
2127285612Sdelphij		} else {
2128132451Sroberto			pp->sp_state |= SS_LSTART;
2129285612Sdelphij		}
2130285612Sdelphij		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
2131285612Sdelphij		timeout((timeout_func_t)si_lstart, (caddr_t)pp, time);
2132285612Sdelphij	}
2133285612Sdelphij
2134285612Sdelphijout:
2135285612Sdelphij	splx(oldspl);
2136285612Sdelphij	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
2137285612Sdelphij}
2138132451Sroberto
2139132451Sroberto/*
2140132451Sroberto * Note: called at splsoftclock from the timeout code
2141132451Sroberto * This has to deal with two things...  cause wakeups while waiting for
2142132451Sroberto * tty drains on last process exit, and call l_start at about the right
2143285612Sdelphij * time for protocols like ppp.
2144132451Sroberto */
2145285612Sdelphijstatic void
2146285612Sdelphijsi_lstart(pp)
2147285612Sdelphij	register struct si_port *pp;
2148285612Sdelphij{
2149285612Sdelphij	register struct tty *tp;
2150285612Sdelphij	int oldspl;
2151132451Sroberto
2152132451Sroberto	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
2153132451Sroberto		pp, pp->sp_state));
2154132451Sroberto
2155132451Sroberto	oldspl = spltty();
2156132451Sroberto
2157132451Sroberto	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
2158132451Sroberto		splx(oldspl);
2159132451Sroberto		return;
2160132451Sroberto	}
2161132451Sroberto	pp->sp_state &= ~SS_LSTART;
2162285612Sdelphij	pp->sp_state |= SS_INLSTART;
2163132451Sroberto
2164132451Sroberto	tp = pp->sp_tty;
2165132451Sroberto
2166132451Sroberto	/* deal with the process exit case */
2167132451Sroberto	ttwwakeup(tp);
2168132451Sroberto
2169132451Sroberto	/* nudge protocols - eg: ppp */
2170132451Sroberto	(*linesw[tp->t_line].l_start)(tp);
2171132451Sroberto
2172132451Sroberto	pp->sp_state &= ~SS_INLSTART;
2173310419Sdelphij	splx(oldspl);
2174132451Sroberto}
2175132451Sroberto
2176310419Sdelphij/*
2177132451Sroberto * Stop output on a line. called at spltty();
2178132451Sroberto */
2179132451Srobertovoid
2180132451Srobertosistop(tp, rw)
2181285612Sdelphij	register struct tty *tp;
2182285612Sdelphij	int rw;
2183132451Sroberto{
2184285612Sdelphij	volatile struct si_channel *ccbp;
2185182007Sroberto	struct si_port *pp;
2186310419Sdelphij
2187285612Sdelphij	pp = TP2PP(tp);
2188132451Sroberto	ccbp = pp->sp_ccb;
2189132451Sroberto
2190132451Sroberto	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
2191132451Sroberto
2192285612Sdelphij	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
2193132451Sroberto	if (rw & FWRITE) {
2194132451Sroberto		/* what level are we meant to be flushing anyway? */
2195132451Sroberto		if (tp->t_state & TS_BUSY) {
2196132451Sroberto			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
2197310419Sdelphij			tp->t_state &= ~TS_BUSY;
2198310419Sdelphij			ttwwakeup(tp);	/* Bruce???? */
2199285612Sdelphij		}
2200285612Sdelphij	}
2201310419Sdelphij#if 1	/* XXX: this doesn't work right yet.. */
2202132451Sroberto	/* XXX: this may have been failing because we used to call l_rint()
2203132451Sroberto	 * while we were looping based on these two counters. Now, we collect
2204132451Sroberto	 * the data and then loop stuffing it into l_rint(), making this
2205132451Sroberto	 * useless.  Should we cause this to blow away the staging buffer?
2206132451Sroberto	 */
2207285612Sdelphij	if (rw & FREAD) {
2208132451Sroberto		ccbp->hi_rxopos = ccbp->hi_rxipos;
2209132451Sroberto	}
2210285612Sdelphij#endif
2211132451Sroberto}
2212132451Sroberto
2213132451Sroberto/*
2214132451Sroberto * Issue a command to the Z280 host card CPU.
2215132451Sroberto */
2216182007Sroberto
2217132451Srobertostatic void
2218310419Sdelphijsi_command(pp, cmd, waitflag)
2219310419Sdelphij	struct si_port *pp;		/* port control block (local) */
2220310419Sdelphij	int cmd;
2221310419Sdelphij	int waitflag;
2222310419Sdelphij{
2223289997Sglebius	int oldspl;
2224132451Sroberto	volatile struct si_channel *ccbp = pp->sp_ccb;
2225285612Sdelphij	int x;
2226310419Sdelphij
2227132451Sroberto	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
2228132451Sroberto		pp, cmd, waitflag, ccbp->hi_stat));
2229132451Sroberto
2230132451Sroberto	oldspl = spltty();		/* Keep others out */
2231132451Sroberto
2232132451Sroberto	/* wait until it's finished what it was doing.. */
2233132451Sroberto	while((x = ccbp->hi_stat) != IDLE_OPEN &&
2234132451Sroberto			x != IDLE_CLOSE &&
2235132451Sroberto			x != cmd) {
2236285612Sdelphij		if (in_intr) {			/* Prevent sleep in intr */
2237182007Sroberto			DPRINT((pp, DBG_PARAM,
2238132451Sroberto				"cmd intr collision - completing %d\trequested %d\n",
2239132451Sroberto				x, cmd));
2240132451Sroberto			splx(oldspl);
2241132451Sroberto			return;
2242132451Sroberto		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2243132451Sroberto				"sicmd1", 1)) {
2244132451Sroberto			splx(oldspl);
2245132451Sroberto			return;
2246132451Sroberto		}
2247132451Sroberto	}
2248310419Sdelphij	/* it should now be in IDLE_OPEN, IDLE_CLOSE, or "cmd" */
2249132451Sroberto
2250132451Sroberto	/* if there was a pending command, cause a state-change wakeup */
2251132451Sroberto	if (pp->sp_pend != IDLE_OPEN) {
2252289997Sglebius		switch(pp->sp_pend) {
2253310419Sdelphij		case LOPEN:
2254310419Sdelphij		case MPEND:
2255132451Sroberto		case MOPEN:
2256132451Sroberto		case CONFIG:
2257132451Sroberto			wakeup(&pp->sp_state);
2258132451Sroberto			break;
2259132451Sroberto		default:
2260285612Sdelphij			break;
2261285612Sdelphij		}
2262182007Sroberto	}
2263132451Sroberto
2264310419Sdelphij	pp->sp_pend = cmd;		/* New command pending */
2265310419Sdelphij	ccbp->hi_stat = cmd;		/* Post it */
2266310419Sdelphij
2267132451Sroberto	if (waitflag) {
2268132451Sroberto		if (in_intr) {		/* If in interrupt handler */
2269132451Sroberto			DPRINT((pp, DBG_PARAM,
2270132451Sroberto				"attempt to sleep in si_intr - cmd req %d\n",
2271289997Sglebius				cmd));
2272289997Sglebius			splx(oldspl);
2273289997Sglebius			return;
2274289997Sglebius		} else while(ccbp->hi_stat != IDLE_OPEN) {
2275285612Sdelphij			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
2276132451Sroberto			    "sicmd2", 0))
2277182007Sroberto				break;
2278132451Sroberto		}
2279132451Sroberto	}
2280132451Sroberto	splx(oldspl);
2281132451Sroberto}
2282132451Sroberto
2283132451Srobertostatic void
2284132451Srobertosi_disc_optim(tp, t, pp)
2285132451Sroberto	struct tty	*tp;
2286289997Sglebius	struct termios	*t;
2287310419Sdelphij	struct si_port	*pp;
2288132451Sroberto{
2289310419Sdelphij	/*
2290310419Sdelphij	 * XXX can skip a lot more cases if Smarts.  Maybe
2291132451Sroberto	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
2292310419Sdelphij	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2293132451Sroberto	 */
2294310419Sdelphij	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2295285612Sdelphij	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2296285612Sdelphij	    && (!(t->c_iflag & PARMRK)
2297285612Sdelphij		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2298285612Sdelphij	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2299132451Sroberto	    && linesw[tp->t_line].l_rint == ttyinput)
2300132451Sroberto		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2301285612Sdelphij	else
2302285612Sdelphij		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2303132451Sroberto
2304289997Sglebius	/*
2305289997Sglebius	 * Prepare to reduce input latency for packet
2306285612Sdelphij	 * discplines with a end of packet character.
2307132451Sroberto	 */
2308132451Sroberto	if (tp->t_line == SLIPDISC)
2309182007Sroberto		pp->sp_hotchar = 0xc0;
2310132451Sroberto	else if (tp->t_line == PPPDISC)
2311289997Sglebius		pp->sp_hotchar = 0x7e;
2312289997Sglebius	else
2313289997Sglebius		pp->sp_hotchar = 0;
2314281230Sdelphij
2315281230Sdelphij	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
2316281230Sdelphij		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
2317281230Sdelphij		pp->sp_hotchar));
2318281230Sdelphij}
2319281230Sdelphij
2320285612Sdelphij
2321289997Sglebius#ifdef	SI_DEBUG
2322289997Sglebius
2323132451Srobertostatic void
2324132451Sroberto#ifdef __STDC__
2325132451Srobertosi_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
2326132451Sroberto#else
2327132451Srobertosi_dprintf(pp, flags, fmt, va_alist)
2328182007Sroberto	struct si_port *pp;
2329281230Sdelphij	int flags;
2330132451Sroberto	char *fmt;
2331310419Sdelphij#endif
2332310419Sdelphij{
2333310419Sdelphij	va_list ap;
2334310419Sdelphij
2335310419Sdelphij	if ((pp == NULL && (si_debug&flags)) ||
2336289997Sglebius	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
2337289997Sglebius	    	if (pp != NULL)
2338285612Sdelphij	    		printf("%ci%d(%d): ", 's',
2339310419Sdelphij	    			(int)SI_CARD(pp->sp_tty->t_dev),
2340132451Sroberto	    			(int)SI_PORT(pp->sp_tty->t_dev));
2341132451Sroberto		va_start(ap, fmt);
2342132451Sroberto		vprintf(fmt, ap);
2343132451Sroberto		va_end(ap);
2344132451Sroberto	}
2345132451Sroberto}
2346132451Sroberto
2347132451Srobertostatic char *
2348132451Srobertosi_mctl2str(cmd)
2349285612Sdelphij	enum si_mctl cmd;
2350285612Sdelphij{
2351132451Sroberto	switch (cmd) {
2352132451Sroberto	case GET:	return("GET");
2353132451Sroberto	case SET:	return("SET");
2354132451Sroberto	case BIS:	return("BIS");
2355132451Sroberto	case BIC:	return("BIC");
2356132451Sroberto	}
2357132451Sroberto	return("BAD");
2358132451Sroberto}
2359132451Sroberto
2360132451Sroberto#endif	/* DEBUG */
2361132451Sroberto
2362132451Sroberto
2363132451Sroberto
2364285612Sdelphijstatic si_devsw_installed = 0;
2365132451Sroberto
2366310419Sdelphijstatic void 	si_drvinit(void *unused)
2367310419Sdelphij{
2368310419Sdelphij	dev_t dev;
2369132451Sroberto
2370132451Sroberto	if( ! si_devsw_installed ) {
2371132451Sroberto		dev = makedev(CDEV_MAJOR, 0);
2372132451Sroberto		cdevsw_add(&dev,&si_cdevsw, NULL);
2373132451Sroberto		si_devsw_installed = 1;
2374132451Sroberto    	}
2375285612Sdelphij}
2376182007Sroberto
2377132451SrobertoSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
2378285612Sdelphij
2379285612Sdelphij