cy.c revision 11671
1/*-
2 * cyclades cyclom-y serial driver
3 *	Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
4 *
5 * Copyright (c) 1993 Andrew Herbert.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name Andrew Herbert may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 *	$Id: cy.c,v 1.15 1995/10/11 02:41:13 davidg Exp $
31 */
32
33#include "cy.h"
34#if NCY > 0
35/*
36 * TODO:
37 * Check that cy16's work.
38 * Implement BREAK.
39 * Fix overflows when closing line.
40 * Atomic COR change.
41 * Don't report individual ports in devconf; busy flag for board should be
42 * union of the current individual busy flags.
43 * Consoles.
44 */
45
46/*
47 * Temporary compile-time configuration options.
48 */
49#define	RxFifoThreshold	(CD1400_RX_FIFO_SIZE / 2)
50			/* Number of chars in the receiver FIFO before an
51			 * an interrupt is generated.  Should depend on
52			 * line speed.  Needs to be about 6 on a 486DX33
53			 * for 4 active ports at 115200 bps.  Why doesn't
54			 * 10 work?
55			 */
56#define	PollMode	/* Use polling-based irq service routine, not the
57			 * hardware svcack lines.  Must be defined for
58			 * Cyclom-16Y boards.  Less efficient for Cyclom-8Ys,
59			 * and stops 4 * 115200 bps from working.
60			 */
61#undef	Smarts		/* Enable slightly more CD1400 intelligence.  Mainly
62			 * the output CR/LF processing, plus we can avoid a
63			 * few checks usually done in ttyinput().
64			 *
65			 * XXX not fully implemented, and not particularly
66			 * worthwhile.
67			 */
68#undef	CyDebug		/* Include debugging code (not very expensive). */
69
70/* These will go away. */
71#undef	SOFT_CTS_OFLOW
72#define	SOFT_HOTCHAR
73
74#include <sys/param.h>
75#include <sys/systm.h>
76#include <sys/reboot.h>
77#include <sys/ioctl.h>
78#include <sys/tty.h>
79#include <sys/proc.h>
80#include <sys/user.h>
81#include <sys/conf.h>
82#include <sys/dkstat.h>
83#include <sys/file.h>
84#include <sys/uio.h>
85#include <sys/kernel.h>
86#include <sys/malloc.h>
87#include <sys/syslog.h>
88#include <sys/devconf.h>
89
90#include <machine/clock.h>
91
92#include <i386/isa/icu.h>	/* XXX just to get at `imen' */
93#include <i386/isa/isa.h>
94#include <i386/isa/isa_device.h>
95#include <i386/isa/cyreg.h>
96#include <i386/isa/ic/cd1400.h>
97
98/*
99 * Dictionary so that I can name everything *sio* or *com* to compare with
100 * sio.c.  There is also lots of ugly formatting and unnecessary ifdefs to
101 * simplify the comparision.  These will go away.
102 */
103#define	LSR_BI		CD1400_RDSR_BREAK
104#define	LSR_FE		CD1400_RDSR_FE
105#define	LSR_OE		CD1400_RDSR_OE
106#define	LSR_PE		CD1400_RDSR_PE
107#define	MCR_DTR		CD1400_MSVR2_DTR
108#define	MCR_RTS		CD1400_MSVR1_RTS
109#define	MSR_CTS		CD1400_MSVR2_CTS
110#define	MSR_DCD		CD1400_MSVR2_CD
111#define	MSR_DSR		CD1400_MSVR2_DSR
112#define	MSR_RI		CD1400_MSVR2_RI
113#define	NSIO		(NCY * CY_MAX_PORTS)
114#define	comconsole	cyconsole
115#define	comdefaultrate	cydefaultrate
116#define	com_events	cy_events
117#define	comhardclose	cyhardclose
118#define	commajor	cymajor
119#define	commctl		cymctl
120#define	comparam	cyparam
121#define	comspeed	cyspeed
122#define	comstart	cystart
123#define	comwakeup	cywakeup
124#define	kdc_sio		kdc_cy
125#define	nsio_tty	ncy_tty
126#define	p_com_addr	p_cy_addr
127#define	sioattach	cyattach
128#define	sioclose	cyclose
129#define	siodevtotty	cydevtotty
130#define	siodriver	cydriver
131#define	siodtrwakeup	cydtrwakeup
132#define	sioioctl	cyioctl
133#define	siointr		cyintr
134#define	siointr1	cyintr1
135#define	siointrts	cyintrts
136#define	sioopen		cyopen
137#define	siopoll		cypoll
138#define	sioprobe	cyprobe
139#define	sioread		cyread
140#define	sioregisterdev	cyregisterdev
141#define	siosettimeout	cysettimeout
142#define	siostop		cystop
143#define	siowrite	cywrite
144#define	sio_timeout	cy_timeout
145#define	sio_timeouts_until_log	cy_timeouts_until_log
146#define	sio_tty		cy_tty
147
148#define	CY_MAX_PORTS		(CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)
149
150/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
151#define	CD1400_xIVR_CHAN_SHIFT	3
152#define	CD1400_xIVR_CHAN	0x0F	/* XXX reduce to pack Cyclom-8Ys */
153
154#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
155#define	RB_I_HIGH_WATER	(TTYHOG - 2 * RS_IBUFSIZE)
156#define	RS_IBUFSIZE	256
157
158#define	CALLOUT_MASK		0x80
159#define	CONTROL_MASK		0x60
160#define	CONTROL_INIT_STATE	0x20
161#define	CONTROL_LOCK_STATE	0x40
162#define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
163#define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
164#define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)
165
166/*
167 * Input buffer watermarks.
168 * The external device is asked to stop sending when the buffer exactly reaches
169 * high water, or when the high level requests it.
170 * The high level is notified immediately (rather than at a later clock tick)
171 * when this watermark is reached.
172 * The buffer size is chosen so the watermark should almost never be reached.
173 * The low watermark is invisibly 0 since the buffer is always emptied all at
174 * once.
175 */
176#define	RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
177
178/*
179 * com state bits.
180 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
181 * than the other bits so that they can be tested as a group without masking
182 * off the low bits.
183 *
184 * The following com and tty flags correspond closely:
185 *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and
186 *				   siostop())
187 *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart())
188 *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam())
189 *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam())
190 * TS_FLUSH is not used.
191 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
192 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
193 */
194#define	CS_BUSY		0x80	/* output in progress */
195#define	CS_TTGO		0x40	/* output not stopped by XOFF */
196#define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */
197#define	CS_CHECKMSR	1	/* check of MSR scheduled */
198#define	CS_CTS_OFLOW	2	/* use CTS output flow control */
199#define	CS_DTR_OFF	0x10	/* DTR held off */
200#define	CS_ODONE	4	/* output completed */
201#define	CS_RTS_IFLOW	8	/* use RTS input flow control */
202
203static	char const * const	error_desc[] = {
204#define	CE_OVERRUN			0
205	"silo overflow",
206#define	CE_INTERRUPT_BUF_OVERFLOW	1
207	"interrupt-level buffer overflow",
208#define	CE_TTY_BUF_OVERFLOW		2
209	"tty-level buffer overflow",
210};
211
212#define	CE_NTYPES			3
213#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
214
215/* types.  XXX - should be elsewhere */
216typedef u_char	bool_t;		/* boolean */
217typedef u_char volatile *cy_addr;
218
219/* queue of linear buffers */
220struct lbq {
221	u_char	*l_head;	/* next char to process */
222	u_char	*l_tail;	/* one past the last char to process */
223	struct lbq *l_next;	/* next in queue */
224	bool_t	l_queued;	/* nonzero if queued */
225};
226
227/* com device structure */
228struct com_s {
229	u_char	state;		/* miscellaneous flag bits */
230	bool_t  active_out;	/* nonzero if the callout device is open */
231#if 0
232	u_char	cfcr_image;	/* copy of value written to CFCR */
233	u_char	ftl;		/* current rx fifo trigger level */
234	u_char	ftl_init;	/* ftl_max for next open() */
235	u_char	ftl_max;	/* maximum ftl for curent open() */
236	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
237	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
238#endif
239	u_char	mcr_image;	/* copy of value written to MCR */
240#if 0
241#ifdef COM_MULTIPORT
242	bool_t	multiport;	/* is this unit part of a multiport device? */
243#endif /* COM_MULTIPORT */
244	bool_t	no_irq;		/* nonzero if irq is not attached */
245	bool_t	poll;		/* nonzero if polling is required */
246	bool_t	poll_output;	/* nonzero if polling for output is required */
247#endif
248	int	unit;		/* unit	number */
249	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
250#if 0
251	u_int	tx_fifo_size;
252#endif
253	u_int	wopeners;	/* # processes waiting for DCD in open() */
254
255	/*
256	 * The high level of the driver never reads status registers directly
257	 * because there would be too many side effects to handle conveniently.
258	 * Instead, it reads copies of the registers stored here by the
259	 * interrupt handler.
260	 */
261	u_char	last_modem_status;	/* last MSR read by intr handler */
262	u_char	prev_modem_status;	/* last MSR handled by high level */
263
264	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
265	u_char	*ibuf;		/* start of input buffer */
266	u_char	*ibufend;	/* end of input buffer */
267	u_char	*ihighwater;	/* threshold in input buffer */
268	u_char	*iptr;		/* next free spot in input buffer */
269
270	struct lbq	obufq;	/* head of queue of output buffers */
271	struct lbq	obufs[2];	/* output buffers */
272
273	cy_addr	cy_iobase;	/* base address of this port's cyclom */
274	cy_addr	iobase;		/* base address of this port's cd1400 */
275
276	struct tty	*tp;	/* cross reference */
277
278	/* Initial state. */
279	struct termios	it_in;	/* should be in struct tty */
280	struct termios	it_out;
281
282	/* Lock state. */
283	struct termios	lt_in;	/* should be in struct tty */
284	struct termios	lt_out;
285
286	bool_t	do_timestamp;
287	struct timeval	timestamp;
288
289	u_long	bytes_in;	/* statistics */
290	u_long	bytes_out;
291	u_int	delta_error_counts[CE_NTYPES];
292	u_long	error_counts[CE_NTYPES];
293
294	u_int	recv_exception;	/* exception chars received */
295	u_int	mdm;		/* modem signal changes */
296#ifdef CyDebug
297	u_int	start_count;	/* no. of calls to comstart() */
298	u_int	start_real;	/* no. of calls that did something */
299#endif
300	u_char	channel_control;/* CD1400 CCR control command shadow */
301	u_char	cor[3];		/* CD1400 COR1-3 shadows */
302	u_char	intr_enable;	/* CD1400 SRER shadow */
303
304	/*
305	 * Ping-pong input buffers.  The extra factor of 2 in the sizes is
306	 * to allow for an error byte for each input byte.
307	 */
308#define	CE_INPUT_OFFSET		RS_IBUFSIZE
309	u_char	ibuf1[2 * RS_IBUFSIZE];
310	u_char	ibuf2[2 * RS_IBUFSIZE];
311
312	/*
313	 * Data area for output buffers.  Someday we should build the output
314	 * buffer queue without copying data.
315	 */
316	u_char	obuf1[256];
317	u_char	obuf2[256];
318
319	struct kern_devconf kdc;
320};
321
322/*
323 * XXX public functions in drivers should be declared in headers produced
324 * by `config', not here.
325 */
326
327/* Interrupt handling entry points. */
328void	siointr		__P((int unit));
329void	siointrts	__P((int unit));
330void	siopoll		__P((void));
331
332/* Device switch entry points. */
333int	sioopen		__P((dev_t dev, int oflags, int devtype,
334			     struct proc *p));
335int	sioclose	__P((dev_t dev, int fflag, int devtype,
336			     struct proc *p));
337int	sioread		__P((dev_t dev, struct uio *uio, int ioflag));
338int	siowrite	__P((dev_t dev, struct uio *uio, int ioflag));
339int	sioioctl	__P((dev_t dev, int cmd, caddr_t data,
340			     int fflag, struct proc *p));
341void	siostop		__P((struct tty *tp, int rw));
342#define	sioreset	noreset
343struct tty *siodevtotty	__P((dev_t dev));
344#define	siommap		nommap
345#define	siostrategy	nostrategy
346
347static	int	sioattach	__P((struct isa_device *dev));
348static	void	cd1400_channel_cmd __P((cy_addr iobase, int cmd));
349static	timeout_t siodtrwakeup;
350static	void	comhardclose	__P((struct com_s *com));
351static	void	siointr1	__P((struct com_s *com));
352static	int	commctl		__P((struct com_s *com, int bits, int how));
353static	int	comparam	__P((struct tty *tp, struct termios *t));
354static	int	sioprobe	__P((struct isa_device *dev));
355static	void	sioregisterdev	__P((struct isa_device *id));
356static	void	siosettimeout	__P((void));
357static	int	comspeed	__P((speed_t speed, int *prescaler_io));
358static	void	comstart	__P((struct tty *tp));
359static	timeout_t comwakeup;
360static	void	disc_optim	__P((struct tty	*tp, struct termios *t,
361				     struct com_s *com));
362
363#ifdef CyDebug
364void	cystatus	__P((int unit));
365#endif
366
367/* table and macro for fast conversion from a unit number to its com struct */
368static	struct com_s	*p_com_addr[NSIO];
369#define	com_addr(unit)	(p_com_addr[unit])
370
371static  struct timeval	intr_timestamp;
372
373struct isa_driver	siodriver = {
374	sioprobe, sioattach, "cy"
375};
376
377static	int	comconsole = -1;
378static	speed_t	comdefaultrate = TTYDEF_SPEED;
379static	u_int	com_events;	/* input chars + weighted output completions */
380static	int	commajor;
381static	int	sio_timeout;
382static	int	sio_timeouts_until_log;
383#if 0 /* XXX */
384static struct tty	*sio_tty[NSIO];
385#else
386static struct tty	sio_tty[NSIO];
387static	int	nsio_tty = NSIO;
388#endif
389
390#ifdef KGDB
391#include <machine/remote-sl.h>
392
393extern	int	kgdb_dev;
394extern	int	kgdb_rate;
395extern	int	kgdb_debug_init;
396#endif
397
398#ifdef CyDebug
399static	u_int	cd_inbs;
400static	u_int	cy_inbs;
401static	u_int	cd_outbs;
402static	u_int	cy_outbs;
403static	u_int	cy_svrr_probes;
404static	u_int	cy_timeouts;
405#endif
406
407static	int	cy_nr_cd1400s[NCY];
408#undef	RxFifoThreshold
409static	int	volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
410
411static struct kern_devconf kdc_sio[NCY] = { {
412	0, 0, 0,		/* filled in by dev_attach */
413	"cyc", 0, { MDDT_ISA, 0, "tty" },
414	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
415	&kdc_isa0,		/* parent */
416	0,			/* parentdata */
417	DC_UNCONFIGURED,	/* state */
418	"Cyclades multiport board",
419	DC_CLS_MISC		/* just an ordinary device */
420} };
421
422static void
423sioregisterdev(id)
424	struct isa_device *id;
425{
426	int	unit;
427
428	unit = id->id_unit;
429	if (unit != 0)
430		kdc_sio[unit] = kdc_sio[0];
431	kdc_sio[unit].kdc_unit = unit;
432	kdc_sio[unit].kdc_isa = id;
433	dev_attach(&kdc_sio[unit]);
434}
435
436static int
437sioprobe(dev)
438	struct isa_device	*dev;
439{
440	int	cyu;
441	u_char	firmware_version;
442	cy_addr	iobase;
443	int	unit;
444
445	iobase = (cy_addr)dev->id_maddr;
446	unit = dev->id_unit;
447	if ((u_int)unit >= NCY)
448		return (0);
449	cy_nr_cd1400s[unit] = 0;
450	sioregisterdev(dev);
451
452	/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
453	cy_inb(iobase, CY16_RESET);	/* XXX? */
454	DELAY(500);	/* wait for the board to get its act together */
455
456	/* this is needed to get the board out of reset */
457	cy_outb(iobase, CY_CLEAR_INTR, 0);
458	DELAY(500);
459
460	for (cyu = 0; cyu < CY_MAX_CD1400s;
461	    ++cyu, iobase += CY_CD1400_MEMSIZE) {
462		int	i;
463
464		/* wait for chip to become ready for new command */
465		for (i = 0; i < 10; i++) {
466			DELAY(50);
467			if (!cd_inb(iobase, CD1400_CCR))
468				break;
469		}
470
471		/* clear the GFRCR register */
472		cd_outb(iobase, CD1400_GFRCR, 0);
473
474		/* issue a reset command */
475		cd_outb(iobase, CD1400_CCR,
476			CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
477
478		/* wait for the CD1400 to initialize itself */
479		for (i = 0; i < 200; i++) {
480			DELAY(50);
481
482			/* retrieve firmware version */
483			firmware_version = cd_inb(iobase, CD1400_GFRCR);
484			if ((firmware_version & 0xf0) == 0x40)
485				break;
486		}
487
488		/*
489		 * Anything in the 0x40-0x4F range is fine.
490		 * If one CD1400 is bad then we don't support higher
491		 * numbered good ones on this board.
492		 */
493		if ((firmware_version & 0xf0) != 0x40)
494			break;
495		++cy_nr_cd1400s[unit];
496	}
497	return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);
498}
499
500static int
501sioattach(isdp)
502	struct isa_device	*isdp;
503{
504	int	cyu;
505	cy_addr	cy_iobase;
506	cy_addr	iobase;
507	int	ncyu;
508	int	unit;
509
510	unit = isdp->id_unit;
511	if ((u_int)unit >= NCY)
512		return (0);
513	ncyu = cy_nr_cd1400s[unit];
514	if (ncyu == 0)
515		return (0);
516	isdp->id_ri_flags |= RI_FAST;
517
518	cy_iobase = (cy_addr)isdp->id_maddr;
519	unit *= CY_MAX_PORTS;
520	for (cyu = 0, iobase = cy_iobase; cyu < ncyu;
521	     ++cyu, iobase += CY_CD1400_MEMSIZE) {
522		int	cdu;
523
524		/* Set up a receive timeout period of than 1+ ms. */
525		cd_outb(iobase, CD1400_PPR,
526			howmany(CY_CLOCK / CD1400_PPR_PRESCALER, 1000));
527
528		for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
529			struct com_s	*com;
530			int		s;
531
532	com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
533	if (com == NULL)
534		break;
535	bzero(com, sizeof *com);
536	com->unit = unit;
537	com->dtr_wait = 3 * hz;
538	com->iptr = com->ibuf = com->ibuf1;
539	com->ibufend = com->ibuf1 + RS_IBUFSIZE;
540	com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
541	com->obufs[0].l_head = com->obuf1;
542	com->obufs[1].l_head = com->obuf2;
543
544			com->cy_iobase = cy_iobase;
545	com->iobase = iobase;
546
547	/*
548	 * We don't use all the flags from <sys/ttydefaults.h> since they
549	 * are only relevant for logins.  It's important to have echo off
550	 * initially so that the line doesn't start blathering before the
551	 * echo flag can be turned off.
552	 */
553	com->it_in.c_iflag = 0;
554	com->it_in.c_oflag = 0;
555	com->it_in.c_cflag = TTYDEF_CFLAG;
556	com->it_in.c_lflag = 0;
557	if (unit == comconsole) {
558		com->it_in.c_iflag = TTYDEF_IFLAG;
559		com->it_in.c_oflag = TTYDEF_OFLAG;
560		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
561		com->it_in.c_lflag = TTYDEF_LFLAG;
562		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
563	}
564	termioschars(&com->it_in);
565	com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
566	com->it_out = com->it_in;
567
568			com->kdc = kdc_sio[0];
569			com->kdc.kdc_name = "cy";
570			com->kdc.kdc_unit = unit;
571			com->kdc.kdc_isa = isdp;
572			com->kdc.kdc_parent = &kdc_sio[isdp->id_unit];
573			com->kdc.kdc_state = DC_IDLE;
574			com->kdc.kdc_description =
575			  "Serial port: Cirrus Logic CD1400";
576			com->kdc.kdc_class = DC_CLS_SERIAL;
577			dev_attach(&com->kdc);
578
579	s = spltty();
580	com_addr(unit) = com;
581	splx(s);
582		}
583	}
584	kdc_sio[isdp->id_unit].kdc_state = DC_BUSY;	/* XXX */
585
586	/* ensure an edge for the next interrupt */
587	cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
588
589	return (1);
590}
591
592int
593sioopen(dev, flag, mode, p)
594	dev_t		dev;
595	int		flag;
596	int		mode;
597	struct proc	*p;
598{
599	struct com_s	*com;
600	int		error;
601	cy_addr		iobase;
602	int		mynor;
603	int		s;
604	struct tty	*tp;
605	int		unit;
606
607	mynor = minor(dev);
608	unit = MINOR_TO_UNIT(mynor);
609	if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
610		return (ENXIO);
611	if (mynor & CONTROL_MASK)
612		return (0);
613#if 0 /* XXX */
614	tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
615#else
616	tp = com->tp = &sio_tty[unit];
617#endif
618	s = spltty();
619	/*
620	 * We jump to this label after all non-interrupted sleeps to pick
621	 * up any changes of the device state.
622	 */
623open_top:
624	while (com->state & CS_DTR_OFF) {
625		error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0);
626		if (error != 0)
627			goto out;
628	}
629	com->kdc.kdc_state = DC_BUSY;
630	if (tp->t_state & TS_ISOPEN) {
631		/*
632		 * The device is open, so everything has been initialized.
633		 * Handle conflicts.
634		 */
635		if (mynor & CALLOUT_MASK) {
636			if (!com->active_out) {
637				error = EBUSY;
638				goto out;
639			}
640		} else {
641			if (com->active_out) {
642				if (flag & O_NONBLOCK) {
643					error = EBUSY;
644					goto out;
645				}
646				error =	tsleep(&com->active_out,
647					       TTIPRI | PCATCH, "cybi", 0);
648				if (error != 0)
649					goto out;
650				goto open_top;
651			}
652		}
653		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
654			error = EBUSY;
655			goto out;
656		}
657	} else {
658		/*
659		 * The device isn't open, so there are no conflicts.
660		 * Initialize it.  Initialization is done twice in many
661		 * cases: to preempt sleeping callin opens if we are
662		 * callout, and to complete a callin open after DCD rises.
663		 */
664		tp->t_oproc = comstart;
665		tp->t_param = comparam;
666		tp->t_dev = dev;
667		tp->t_termios = mynor & CALLOUT_MASK
668				? com->it_out : com->it_in;
669#if 0
670		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
671		com->ftl_max = com->ftl_init;
672		com->poll = com->no_irq;
673		com->poll_output = com->loses_outints;
674#endif
675		++com->wopeners;
676		iobase = com->iobase;
677
678		/* reset this channel */
679		cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
680		cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET);
681
682		/*
683		 * Resetting disables the transmitter and receiver as well as
684		 * flushing the fifos so some of our cached state becomes
685		 * invalid.  The documentation suggests that all registers
686		 * for the current channel are reset to defaults, but
687		 * apparently none are.  We wouldn't want DTR cleared.
688		 */
689		com->channel_control = 0;
690
691		/* Encode per-board unit in LIVR for access in intr routines. */
692		cd_outb(iobase, CD1400_LIVR,
693			(unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
694
695		/*
696		 * raise dtr and generally set things up correctly.  this
697		 * has the side-effect of selecting the appropriate cd1400
698		 * channel, to help us with subsequent channel control stuff
699		 */
700		error = comparam(tp, &tp->t_termios);
701		--com->wopeners;
702		if (error != 0)
703			goto out;
704		/*
705		 * XXX we should goto open_top if comparam() slept.
706		 */
707		ttsetwater(tp);
708#if 0
709		if (com->hasfifo) {
710			/*
711			 * (Re)enable and drain fifos.
712			 *
713			 * Certain SMC chips cause problems if the fifos
714			 * are enabled while input is ready.  Turn off the
715			 * fifo if necessary to clear the input.  We test
716			 * the input ready bit after enabling the fifos
717			 * since we've already enabled them in comparam()
718			 * and to handle races between enabling and fresh
719			 * input.
720			 */
721			while (TRUE) {
722				outb(iobase + com_fifo,
723				     FIFO_RCV_RST | FIFO_XMT_RST
724				     | FIFO_ENABLE | com->ftl);
725				DELAY(100);
726				if (!(inb(com->line_status_port) & LSR_RXRDY))
727					break;
728				outb(iobase + com_fifo, 0);
729				DELAY(100);
730				(void) inb(com->data_port);
731			}
732		}
733
734		disable_intr();
735		(void) inb(com->line_status_port);
736		(void) inb(com->data_port);
737		com->prev_modem_status = com->last_modem_status
738		    = inb(com->modem_status_port);
739		outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
740				       | IER_EMSC);
741		enable_intr();
742#else /* !0 */
743		/* XXX raise RTS too */
744		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
745		disable_intr();
746		com->prev_modem_status = com->last_modem_status
747		    = cd_inb(iobase, CD1400_MSVR2);
748		cd_outb(iobase, CD1400_SRER,
749			com->intr_enable
750			    = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
751		enable_intr();
752#endif /* 0 */
753		/*
754		 * Handle initial DCD.  Callout devices get a fake initial
755		 * DCD (trapdoor DCD).  If we are callout, then any sleeping
756		 * callin opens get woken up and resume sleeping on "cybi"
757		 * instead of "cydcd".
758		 */
759		/*
760		 * XXX `mynor & CALLOUT_MASK' should be
761		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
762		 * TRAPDOOR_CARRIER is the default initial state for callout
763		 * devices and SOFT_CARRIER is like CLOCAL except it hides
764		 * the true carrier.
765		 */
766		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
767			(*linesw[tp->t_line].l_modem)(tp, 1);
768	}
769	/*
770	 * Wait for DCD if necessary.
771	 */
772	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
773	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
774		++com->wopeners;
775		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0);
776		--com->wopeners;
777		if (error != 0)
778			goto out;
779		goto open_top;
780	}
781	error =	(*linesw[tp->t_line].l_open)(dev, tp);
782	disc_optim(tp, &tp->t_termios, com);
783	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
784		com->active_out = TRUE;
785	siosettimeout();
786out:
787	splx(s);
788	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
789		comhardclose(com);
790	return (error);
791}
792
793int
794sioclose(dev, flag, mode, p)
795	dev_t		dev;
796	int		flag;
797	int		mode;
798	struct proc	*p;
799{
800	struct com_s	*com;
801	int		mynor;
802	int		s;
803	struct tty	*tp;
804
805	mynor = minor(dev);
806	if (mynor & CONTROL_MASK)
807		return (0);
808	com = com_addr(MINOR_TO_UNIT(mynor));
809	tp = com->tp;
810	s = spltty();
811	(*linesw[tp->t_line].l_close)(tp, flag);
812	disc_optim(tp, &tp->t_termios, com);
813	siostop(tp, FREAD | FWRITE);
814	comhardclose(com);
815	ttyclose(tp);
816	siosettimeout();
817	splx(s);
818#ifdef broken /* session holds a ref to the tty; can't deallocate */
819	ttyfree(tp);
820	com->tp = sio_tty[unit] = NULL;
821#endif
822	return (0);
823}
824
825static void
826comhardclose(com)
827	struct com_s	*com;
828{
829	cy_addr		iobase;
830	int		s;
831	struct tty	*tp;
832	int		unit;
833
834	unit = com->unit;
835	iobase = com->iobase;
836	s = spltty();
837#if 0
838	com->poll = FALSE;
839	com->poll_output = FALSE;
840#endif
841	com->do_timestamp = 0;
842	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
843#if 0
844	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
845#endif
846
847#ifdef KGDB
848	/* do not disable interrupts or hang up if debugging */
849	if (kgdb_dev != makedev(commajor, unit))
850#endif
851	{
852#if 0
853		outb(iobase + com_ier, 0);
854#else
855		disable_intr();
856		cd_outb(iobase, CD1400_SRER, com->intr_enable = 0);
857		enable_intr();
858#endif
859		tp = com->tp;
860		if (tp->t_cflag & HUPCL
861		    /*
862		     * XXX we will miss any carrier drop between here and the
863		     * next open.  Perhaps we should watch DCD even when the
864		     * port is closed; it is not sufficient to check it at
865		     * the next open because it might go up and down while
866		     * we're not watching.
867		     */
868		    || !com->active_out
869		       && !(com->prev_modem_status & MSR_DCD)
870		       && !(com->it_in.c_cflag & CLOCAL)
871		    || !(tp->t_state & TS_ISOPEN)) {
872			(void)commctl(com, TIOCM_DTR, DMBIC);
873
874			/* Disable receiver (leave transmitter enabled). */
875			com->channel_control = CD1400_CCR_CMDCHANCTL
876					       | CD1400_CCR_XMTEN
877					       | CD1400_CCR_RCVDIS;
878			cd1400_channel_cmd(iobase, com->channel_control);
879
880			if (com->dtr_wait != 0) {
881				timeout(siodtrwakeup, com, com->dtr_wait);
882				com->state |= CS_DTR_OFF;
883			}
884		}
885	}
886	com->active_out = FALSE;
887	wakeup(&com->active_out);
888	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */
889	if (!(com->state & CS_DTR_OFF) && unit != comconsole)
890		com->kdc.kdc_state = DC_IDLE;
891	splx(s);
892}
893
894int
895sioread(dev, uio, flag)
896	dev_t		dev;
897	struct uio	*uio;
898	int		flag;
899{
900	int		mynor;
901	struct tty	*tp;
902
903	mynor = minor(dev);
904	if (mynor & CONTROL_MASK)
905		return (ENODEV);
906	tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
907	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
908}
909
910int
911siowrite(dev, uio, flag)
912	dev_t		dev;
913	struct uio	*uio;
914	int		flag;
915{
916	int		mynor;
917	struct tty	*tp;
918	int		unit;
919
920	mynor = minor(dev);
921	if (mynor & CONTROL_MASK)
922		return (ENODEV);
923
924	unit = MINOR_TO_UNIT(mynor);
925	tp = com_addr(unit)->tp;
926	/*
927	 * (XXX) We disallow virtual consoles if the physical console is
928	 * a serial port.  This is in case there is a display attached that
929	 * is not the console.  In that situation we don't need/want the X
930	 * server taking over the console.
931	 */
932	if (constty != NULL && unit == comconsole)
933		constty = NULL;
934#ifdef Smarts
935	/* XXX duplicate ttwrite(), but without so much output processing on
936	 * CR & LF chars.  Hardly worth the effort, given that high-throughput
937	 * sessions are raw anyhow.
938	 */
939#else
940	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
941#endif
942}
943
944static void
945siodtrwakeup(chan)
946	void	*chan;
947{
948	struct com_s	*com;
949
950	com = (struct com_s *)chan;
951	com->state &= ~CS_DTR_OFF;
952	if (com->unit != comconsole)
953		com->kdc.kdc_state = DC_IDLE;
954	wakeup(&com->dtr_wait);
955}
956
957/* Interrupt routine for timekeeping purposes */
958void
959siointrts(unit)
960	int	unit;
961{
962	/*
963	 * XXX microtime() reenables CPU interrupts.  We can't afford to
964	 * be interrupted and don't want to slow down microtime(), so lock
965	 * out interrupts in another way.
966	 */
967	outb(IO_ICU1 + 1, 0xff);
968	microtime(&intr_timestamp);
969	disable_intr();
970	outb(IO_ICU1 + 1, imen);
971
972	siointr(unit);
973}
974
975void
976siointr(unit)
977	int	unit;
978{
979	int	baseu;
980	cy_addr	cy_iobase;
981	int	cyu;
982	cy_addr	iobase;
983	u_char	status;
984
985	baseu = unit * CY_MAX_PORTS;
986	cy_iobase = com_addr(baseu)->cy_iobase;
987
988	/* check each CD1400 in turn */
989	for (cyu = 0, iobase = cy_iobase; cyu < cy_nr_cd1400s[unit];
990	     ++cyu, iobase += CY_CD1400_MEMSIZE) {
991		/* poll to see if it has any work */
992		status = cd_inb(iobase, CD1400_SVRR);
993		if (status == 0)
994			continue;
995#ifdef CyDebug
996		++cy_svrr_probes;
997#endif
998		/* service requests as appropriate, giving priority to RX */
999		if (status & CD1400_SVRR_RXRDY) {
1000			struct com_s	*com;
1001			u_int		count;
1002			u_char		*ioptr;
1003			u_char		line_status;
1004			u_char		recv_data;
1005			u_char		serv_type;
1006#ifdef PollMode
1007			u_char		save_car;
1008			u_char		save_rir;
1009#endif
1010
1011#ifdef PollMode
1012			save_rir = cd_inb(iobase, CD1400_RIR);
1013			save_car = cd_inb(iobase, CD1400_CAR);
1014
1015			/* enter rx service */
1016			cd_outb(iobase, CD1400_CAR, save_rir);
1017
1018			serv_type = cd_inb(iobase, CD1400_RIVR);
1019			com = com_addr(baseu
1020				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1021					  & CD1400_xIVR_CHAN));
1022#else
1023			/* ack receive service */
1024			serv_type = cy_inb(iobase, CY8_SVCACKR);
1025
1026			com = com_addr(baseu +
1027				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1028					  & CD1400_xIVR_CHAN));
1029#endif
1030
1031	if (com->do_timestamp)
1032		/* XXX a little bloat here... */
1033		com->timestamp = intr_timestamp;
1034
1035		if (serv_type & CD1400_RIVR_EXCEPTION) {
1036			++com->recv_exception;
1037			line_status = cd_inb(iobase, CD1400_RDSR);
1038			/* break/unnattached error bits or real input? */
1039			recv_data = cd_inb(iobase, CD1400_RDSR);
1040#ifndef SOFT_HOTCHAR
1041			if (line_status & CD1400_RDSR_SPECIAL
1042			    && com->hotchar != 0)
1043				setsofttty();
1044#endif
1045#if 1 /* XXX "intelligent" PFO error handling would break O error handling */
1046			if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {
1047				/*
1048				  Don't store PE if IGNPAR and BI if IGNBRK,
1049				  this hack allows "raw" tty optimization
1050				  works even if IGN* is set.
1051				*/
1052				if (   com->tp == NULL
1053				    || !(com->tp->t_state & TS_ISOPEN)
1054				    || (line_status & (LSR_PE|LSR_FE))
1055				    &&  (com->tp->t_iflag & IGNPAR)
1056				    || (line_status & LSR_BI)
1057				    &&  (com->tp->t_iflag & IGNBRK))
1058					goto cont;
1059				if (   (line_status & (LSR_PE|LSR_FE))
1060				    && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)
1061				    && ((line_status & LSR_FE)
1062				    ||  (line_status & LSR_PE)
1063				    &&  (com->tp->t_iflag & INPCK)))
1064					recv_data = 0;
1065			}
1066#endif /* 1 */
1067			++com->bytes_in;
1068#ifdef SOFT_HOTCHAR
1069			if (com->hotchar != 0 && recv_data == com->hotchar)
1070				setsofttty();
1071#endif
1072			ioptr = com->iptr;
1073			if (ioptr >= com->ibufend)
1074				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1075			else {
1076				++com_events;
1077				ioptr[0] = recv_data;
1078				ioptr[CE_INPUT_OFFSET] = line_status;
1079				com->iptr = ++ioptr;
1080				if (ioptr == com->ihighwater
1081				    && com->state & CS_RTS_IFLOW)
1082#if 0
1083					outb(com->modem_ctl_port,
1084					     com->mcr_image &= ~MCR_RTS);
1085#else
1086					cd_outb(iobase, CD1400_MSVR1,
1087						com->mcr_image &= ~MCR_RTS);
1088#endif
1089				if (line_status & LSR_OE)
1090					CE_RECORD(com, CE_OVERRUN);
1091			}
1092			goto cont;
1093		} else {
1094			int	ifree;
1095
1096			count = cd_inb(iobase, CD1400_RDCR);
1097			com->bytes_in += count;
1098			ioptr = com->iptr;
1099			ifree = com->ibufend - ioptr;
1100			if (count > ifree) {
1101				count -= ifree;
1102				com_events += ifree;
1103				while (ifree-- != 0) {
1104					recv_data = cd_inb(iobase, CD1400_RDSR);
1105#ifdef SOFT_HOTCHAR
1106					if (com->hotchar != 0
1107					    && recv_data == com->hotchar)
1108						setsofttty();
1109#endif
1110					ioptr[0] = recv_data;
1111					ioptr[CE_INPUT_OFFSET] = 0;
1112					++ioptr;
1113				}
1114				com->delta_error_counts
1115				    [CE_INTERRUPT_BUF_OVERFLOW] += count;
1116				do {
1117					recv_data = cd_inb(iobase, CD1400_RDSR);
1118#ifdef SOFT_HOTCHAR
1119					if (com->hotchar != 0
1120					    && recv_data == com->hotchar)
1121						setsofttty();
1122#endif
1123				} while (--count != 0);
1124			} else {
1125				if (ioptr <= com->ihighwater
1126				    && ioptr + count > com->ihighwater
1127				    && com->state & CS_RTS_IFLOW)
1128#if 0
1129					outb(com->modem_ctl_port,
1130					     com->mcr_image &= ~MCR_RTS);
1131#else
1132					cd_outb(iobase, CD1400_MSVR1,
1133						com->mcr_image &= ~MCR_RTS);
1134#endif
1135				com_events += count;
1136				do {
1137					recv_data = cd_inb(iobase, CD1400_RDSR);
1138#ifdef SOFT_HOTCHAR
1139					if (com->hotchar != 0
1140					    && recv_data == com->hotchar)
1141						setsofttty();
1142#endif
1143					ioptr[0] = recv_data;
1144					ioptr[CE_INPUT_OFFSET] = 0;
1145					++ioptr;
1146				} while (--count != 0);
1147			}
1148			com->iptr = ioptr;
1149		}
1150cont:
1151
1152			/* terminate service context */
1153#ifdef PollMode
1154			cd_outb(iobase, CD1400_RIR,
1155				save_rir
1156				& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
1157			cd_outb(iobase, CD1400_CAR, save_car);
1158#else
1159			cd_outb(iobase, CD1400_EOSRR, 0);
1160#endif
1161		}
1162		if (status & CD1400_SVRR_MDMCH) {
1163			struct com_s	*com;
1164			u_char	modem_status;
1165#ifdef PollMode
1166			u_char	save_car;
1167			u_char	save_mir;
1168#else
1169			u_char	vector;
1170#endif
1171
1172#ifdef PollMode
1173			save_mir = cd_inb(iobase, CD1400_MIR);
1174			save_car = cd_inb(iobase, CD1400_CAR);
1175
1176			/* enter modem service */
1177			cd_outb(iobase, CD1400_CAR, save_mir);
1178
1179			com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
1180				       + (save_mir & CD1400_MIR_CHAN));
1181#else
1182			/* ack modem service */
1183			vector = cy_inb(iobase, CY8_SVCACKM);
1184
1185			com = com_addr(baseu
1186				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1187					  & CD1400_xIVR_CHAN));
1188#endif
1189			++com->mdm;
1190			modem_status = cd_inb(iobase, CD1400_MSVR2);
1191		if (modem_status != com->last_modem_status) {
1192			/*
1193			 * Schedule high level to handle DCD changes.  Note
1194			 * that we don't use the delta bits anywhere.  Some
1195			 * UARTs mess them up, and it's easy to remember the
1196			 * previous bits and calculate the delta.
1197			 */
1198			com->last_modem_status = modem_status;
1199			if (!(com->state & CS_CHECKMSR)) {
1200				com_events += LOTS_OF_EVENTS;
1201				com->state |= CS_CHECKMSR;
1202				setsofttty();
1203			}
1204
1205#ifdef SOFT_CTS_OFLOW
1206			/* handle CTS change immediately for crisp flow ctl */
1207			if (com->state & CS_CTS_OFLOW) {
1208				if (modem_status & MSR_CTS) {
1209					com->state |= CS_ODEVREADY;
1210					if (com->state >= (CS_BUSY | CS_TTGO
1211							   | CS_ODEVREADY)
1212					    && !(com->intr_enable
1213						 & CD1400_SRER_TXRDY))
1214						cd_outb(iobase, CD1400_SRER,
1215							com->intr_enable
1216							|= CD1400_SRER_TXRDY);
1217				} else {
1218					com->state &= ~CS_ODEVREADY;
1219					if (com->intr_enable & CD1400_SRER_TXRDY)
1220						cd_outb(iobase, CD1400_SRER,
1221							com->intr_enable
1222							&= ~CD1400_SRER_TXRDY);
1223				}
1224			}
1225#endif
1226		}
1227
1228			/* terminate service context */
1229#ifdef PollMode
1230			cd_outb(iobase, CD1400_MIR,
1231				save_mir
1232				& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
1233			cd_outb(iobase, CD1400_CAR, save_car);
1234#else
1235			cd_outb(iobase, CD1400_EOSRR, 0);
1236#endif
1237		}
1238		if (status & CD1400_SVRR_TXRDY) {
1239			struct com_s	*com;
1240#ifdef PollMode
1241			u_char	save_car;
1242			u_char	save_tir;
1243#else
1244			u_char	vector;
1245#endif
1246
1247#ifdef PollMode
1248			save_tir = cd_inb(iobase, CD1400_TIR);
1249			save_car = cd_inb(iobase, CD1400_CAR);
1250
1251			/* enter tx service */
1252			cd_outb(iobase, CD1400_CAR, save_tir);
1253			com = com_addr(baseu
1254				       + cyu * CD1400_NO_OF_CHANNELS
1255				       + (save_tir & CD1400_TIR_CHAN));
1256#else
1257			/* ack transmit service */
1258			vector = cy_inb(iobase, CY8_SVCACKT);
1259
1260			com = com_addr(baseu
1261				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1262					  & CD1400_xIVR_CHAN));
1263#endif
1264
1265		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1266			u_char	*ioptr;
1267			u_int	ocount;
1268
1269			ioptr = com->obufq.l_head;
1270				ocount = com->obufq.l_tail - ioptr;
1271				if (ocount > CD1400_TX_FIFO_SIZE)
1272					ocount = CD1400_TX_FIFO_SIZE;
1273				com->bytes_out += ocount;
1274				do
1275					cd_outb(iobase, CD1400_TDR, *ioptr++);
1276				while (--ocount != 0);
1277			com->obufq.l_head = ioptr;
1278			if (ioptr >= com->obufq.l_tail) {
1279				struct lbq	*qp;
1280
1281				qp = com->obufq.l_next;
1282				qp->l_queued = FALSE;
1283				qp = qp->l_next;
1284				if (qp != NULL) {
1285					com->obufq.l_head = qp->l_head;
1286					com->obufq.l_tail = qp->l_tail;
1287					com->obufq.l_next = qp;
1288				} else {
1289					/* output just completed */
1290					com->state &= ~CS_BUSY;
1291					cd_outb(iobase, CD1400_SRER,
1292						com->intr_enable
1293						&= ~CD1400_SRER_TXRDY);
1294				}
1295				if (!(com->state & CS_ODONE)) {
1296					com_events += LOTS_OF_EVENTS;
1297					com->state |= CS_ODONE;
1298					setsofttty();	/* handle at high level ASAP */
1299				}
1300			}
1301		}
1302
1303			/* terminate service context */
1304#ifdef PollMode
1305			cd_outb(iobase, CD1400_TIR,
1306				save_tir
1307				& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
1308			cd_outb(iobase, CD1400_CAR, save_car);
1309#else
1310			cd_outb(iobase, CD1400_EOSRR, 0);
1311#endif
1312		}
1313	}
1314
1315	/* ensure an edge for the next interrupt */
1316	cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
1317
1318	schedsofttty();
1319}
1320
1321static void
1322siointr1(com)
1323	struct com_s	*com;
1324{
1325}
1326
1327int
1328sioioctl(dev, cmd, data, flag, p)
1329	dev_t		dev;
1330	int		cmd;
1331	caddr_t		data;
1332	int		flag;
1333	struct proc	*p;
1334{
1335	struct com_s	*com;
1336	int		error;
1337	cy_addr		iobase;
1338	int		mynor;
1339	int		s;
1340	struct tty	*tp;
1341#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1342	int		oldcmd;
1343	struct termios	term;
1344#endif
1345
1346	mynor = minor(dev);
1347	com = com_addr(MINOR_TO_UNIT(mynor));
1348	iobase = com->iobase;
1349	if (mynor & CONTROL_MASK) {
1350		struct termios	*ct;
1351
1352		switch (mynor & CONTROL_MASK) {
1353		case CONTROL_INIT_STATE:
1354			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1355			break;
1356		case CONTROL_LOCK_STATE:
1357			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1358			break;
1359		default:
1360			return (ENODEV);	/* /dev/nodev */
1361		}
1362		switch (cmd) {
1363		case TIOCSETA:
1364			error = suser(p->p_ucred, &p->p_acflag);
1365			if (error != 0)
1366				return (error);
1367			*ct = *(struct termios *)data;
1368			return (0);
1369		case TIOCGETA:
1370			*(struct termios *)data = *ct;
1371			return (0);
1372		case TIOCGETD:
1373			*(int *)data = TTYDISC;
1374			return (0);
1375		case TIOCGWINSZ:
1376			bzero(data, sizeof(struct winsize));
1377			return (0);
1378		default:
1379			return (ENOTTY);
1380		}
1381	}
1382	tp = com->tp;
1383#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1384	term = tp->t_termios;
1385	oldcmd = cmd;
1386	error = ttsetcompat(tp, &cmd, data, &term);
1387	if (error != 0)
1388		return (error);
1389	if (cmd != oldcmd)
1390		data = (caddr_t)&term;
1391#endif
1392	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1393		int	cc;
1394		struct termios *dt = (struct termios *)data;
1395		struct termios *lt = mynor & CALLOUT_MASK
1396				     ? &com->lt_out : &com->lt_in;
1397
1398		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1399			      | (dt->c_iflag & ~lt->c_iflag);
1400		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1401			      | (dt->c_oflag & ~lt->c_oflag);
1402		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1403			      | (dt->c_cflag & ~lt->c_cflag);
1404		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1405			      | (dt->c_lflag & ~lt->c_lflag);
1406		for (cc = 0; cc < NCCS; ++cc)
1407			if (lt->c_cc[cc] != 0)
1408				dt->c_cc[cc] = tp->t_cc[cc];
1409		if (lt->c_ispeed != 0)
1410			dt->c_ispeed = tp->t_ispeed;
1411		if (lt->c_ospeed != 0)
1412			dt->c_ospeed = tp->t_ospeed;
1413	}
1414	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1415	if (error >= 0)
1416		return (error);
1417	s = spltty();
1418	error = ttioctl(tp, cmd, data, flag);
1419	disc_optim(tp, &tp->t_termios, com);
1420	if (error >= 0) {
1421		splx(s);
1422		return (error);
1423	}
1424	cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
1425	switch (cmd) {
1426#if 0
1427	case TIOCSBRK:
1428		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1429		break;
1430	case TIOCCBRK:
1431		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1432		break;
1433#endif /* 0 */
1434	case TIOCSDTR:
1435		(void)commctl(com, TIOCM_DTR, DMBIS);
1436		break;
1437	case TIOCCDTR:
1438		(void)commctl(com, TIOCM_DTR, DMBIC);
1439		break;
1440	case TIOCMSET:
1441		(void)commctl(com, *(int *)data, DMSET);
1442		break;
1443	case TIOCMBIS:
1444		(void)commctl(com, *(int *)data, DMBIS);
1445		break;
1446	case TIOCMBIC:
1447		(void)commctl(com, *(int *)data, DMBIC);
1448		break;
1449	case TIOCMGET:
1450		*(int *)data = commctl(com, 0, DMGET);
1451		break;
1452	case TIOCMSDTRWAIT:
1453		/* must be root since the wait applies to following logins */
1454		error = suser(p->p_ucred, &p->p_acflag);
1455		if (error != 0) {
1456			splx(s);
1457			return (error);
1458		}
1459		com->dtr_wait = *(int *)data * hz / 100;
1460		break;
1461	case TIOCMGDTRWAIT:
1462		*(int *)data = com->dtr_wait * 100 / hz;
1463		break;
1464	case TIOCTIMESTAMP:
1465		com->do_timestamp = TRUE;
1466		*(struct timeval *)data = com->timestamp;
1467		break;
1468	default:
1469		splx(s);
1470		return (ENOTTY);
1471	}
1472	splx(s);
1473	return (0);
1474}
1475
1476void
1477siopoll()
1478{
1479	int		unit;
1480
1481#ifdef CyDebug
1482	++cy_timeouts;
1483#endif
1484	if (com_events == 0)
1485		return;
1486repeat:
1487	for (unit = 0; unit < NSIO; ++unit) {
1488		u_char		*buf;
1489		struct com_s	*com;
1490		u_char		*ibuf;
1491		cy_addr		iobase;
1492		int		incc;
1493		struct tty	*tp;
1494
1495		com = com_addr(unit);
1496		if (com == NULL)
1497			continue;
1498		tp = com->tp;
1499		if (tp == NULL) {
1500			/*
1501			 * XXX forget any events related to closed devices
1502			 * (actually never opened devices) so that we don't
1503			 * loop.
1504			 */
1505			disable_intr();
1506			incc = com->iptr - com->ibuf;
1507			com->iptr = com->ibuf;
1508			if (com->state & CS_CHECKMSR) {
1509				incc += LOTS_OF_EVENTS;
1510				com->state &= ~CS_CHECKMSR;
1511			}
1512			com_events -= incc;
1513			enable_intr();
1514			if (incc != 0)
1515				log(LOG_DEBUG,
1516				    "sio%d: %d events for device with no tp\n",
1517				    unit, incc);
1518			continue;
1519		}
1520
1521		/* switch the role of the low-level input buffers */
1522		if (com->iptr == (ibuf = com->ibuf)) {
1523			buf = NULL;     /* not used, but compiler can't tell */
1524			incc = 0;
1525		} else {
1526			buf = ibuf;
1527			disable_intr();
1528			incc = com->iptr - buf;
1529			com_events -= incc;
1530			if (ibuf == com->ibuf1)
1531				ibuf = com->ibuf2;
1532			else
1533				ibuf = com->ibuf1;
1534			com->ibufend = ibuf + RS_IBUFSIZE;
1535			com->ihighwater = ibuf + RS_IHIGHWATER;
1536			com->iptr = ibuf;
1537
1538			/*
1539			 * There is now room for another low-level buffer full
1540			 * of input, so enable RTS if it is now disabled and
1541			 * there is room in the high-level buffer.
1542			 */
1543			/*
1544			 * XXX this used not to look at CS_RTS_IFLOW.  The
1545			 * change is to allow full control of MCR_RTS via
1546			 * ioctls after turning CS_RTS_IFLOW off.  Check
1547			 * for races.  We shouldn't allow the ioctls while
1548			 * CS_RTS_IFLOW is on.
1549			 */
1550			if ((com->state & CS_RTS_IFLOW)
1551			    && !(com->mcr_image & MCR_RTS)
1552			    && !(tp->t_state & TS_TBLOCK))
1553#if 0
1554				outb(com->modem_ctl_port,
1555				     com->mcr_image |= MCR_RTS);
1556#else
1557				iobase = com->iobase,
1558				cd_outb(iobase, CD1400_CAR,
1559					unit & CD1400_CAR_CHAN),
1560				cd_outb(iobase, CD1400_MSVR1,
1561					com->mcr_image |= MCR_RTS);
1562#endif
1563			enable_intr();
1564			com->ibuf = ibuf;
1565		}
1566
1567		if (com->state & CS_CHECKMSR) {
1568			u_char	delta_modem_status;
1569
1570			disable_intr();
1571			delta_modem_status = com->last_modem_status
1572					     ^ com->prev_modem_status;
1573			com->prev_modem_status = com->last_modem_status;
1574			com_events -= LOTS_OF_EVENTS;
1575			com->state &= ~CS_CHECKMSR;
1576			enable_intr();
1577			if (delta_modem_status & MSR_DCD)
1578				(*linesw[tp->t_line].l_modem)
1579					(tp, com->prev_modem_status & MSR_DCD);
1580		}
1581		if (com->state & CS_ODONE) {
1582			disable_intr();
1583			com_events -= LOTS_OF_EVENTS;
1584			com->state &= ~CS_ODONE;
1585			if (!(com->state & CS_BUSY))
1586				com->tp->t_state &= ~TS_BUSY;
1587			enable_intr();
1588			(*linesw[tp->t_line].l_start)(tp);
1589		}
1590		if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
1591			continue;
1592		/*
1593		 * Avoid the grotesquely inefficient lineswitch routine
1594		 * (ttyinput) in "raw" mode.  It usually takes about 450
1595		 * instructions (that's without canonical processing or echo!).
1596		 * slinput is reasonably fast (usually 40 instructions plus
1597		 * call overhead).
1598		 */
1599		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1600			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
1601			    && (com->state & CS_RTS_IFLOW
1602				|| tp->t_iflag & IXOFF)
1603			    && !(tp->t_state & TS_TBLOCK))
1604				ttyblock(tp);
1605			tk_nin += incc;
1606			tk_rawcc += incc;
1607			tp->t_rawcc += incc;
1608			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1609				+= b_to_q((char *)buf, incc, &tp->t_rawq);
1610			ttwakeup(tp);
1611			if (tp->t_state & TS_TTSTOP
1612			    && (tp->t_iflag & IXANY
1613				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1614				tp->t_state &= ~TS_TTSTOP;
1615				tp->t_lflag &= ~FLUSHO;
1616				comstart(tp);
1617			}
1618		} else {
1619			do {
1620				u_char	line_status;
1621				int	recv_data;
1622
1623				line_status = (u_char) buf[CE_INPUT_OFFSET];
1624				recv_data = (u_char) *buf++;
1625				if (line_status
1626				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1627					if (line_status & LSR_BI)
1628						recv_data |= TTY_BI;
1629					if (line_status & LSR_FE)
1630						recv_data |= TTY_FE;
1631					if (line_status & LSR_OE)
1632						recv_data |= TTY_OE;
1633					if (line_status & LSR_PE)
1634						recv_data |= TTY_PE;
1635				}
1636				(*linesw[tp->t_line].l_rint)(recv_data, tp);
1637			} while (--incc > 0);
1638		}
1639		if (com_events == 0)
1640			break;
1641	}
1642	if (com_events >= LOTS_OF_EVENTS)
1643		goto repeat;
1644}
1645
1646static int
1647comparam(tp, t)
1648	struct tty	*tp;
1649	struct termios	*t;
1650{
1651	int		bits;
1652	int		cflag;
1653	struct com_s	*com;
1654	u_char		cor_change;
1655	int		idivisor;
1656	int		iflag;
1657	cy_addr		iobase;
1658	int		iprescaler;
1659	int		itimeout;
1660	int		odivisor;
1661	int		oprescaler;
1662	u_char		opt;
1663	int		s;
1664	int		unit;
1665
1666	/* do historical conversions */
1667	if (t->c_ispeed == 0)
1668		t->c_ispeed = t->c_ospeed;
1669
1670	/* check requested parameters */
1671	idivisor = comspeed(t->c_ispeed, &iprescaler);
1672	if (idivisor < 0)
1673		return (EINVAL);
1674	odivisor = comspeed(t->c_ospeed, &oprescaler);
1675	if (odivisor < 0)
1676		return (EINVAL);
1677
1678	/* parameters are OK, convert them to the com struct and the device */
1679	unit = DEV_TO_UNIT(tp->t_dev);
1680	com = com_addr(unit);
1681	iobase = com->iobase;
1682	s = spltty();
1683	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
1684	if (odivisor == 0)
1685		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
1686	else
1687		(void)commctl(com, TIOCM_DTR, DMBIS);
1688
1689	cd_outb(iobase, CD1400_RBPR, idivisor);
1690	cd_outb(iobase, CD1400_RCOR, iprescaler);
1691	cd_outb(iobase, CD1400_TBPR, odivisor);
1692	cd_outb(iobase, CD1400_TCOR, oprescaler);
1693
1694	/*
1695	 * channel control
1696	 *	receiver enable
1697	 *	transmitter enable (always set)
1698	 */
1699	cflag = t->c_cflag;
1700	opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
1701	      | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
1702	if (opt != com->channel_control) {
1703		com->channel_control = opt;
1704		cd1400_channel_cmd(iobase, opt);
1705	}
1706
1707#ifdef Smarts
1708	/* set special chars */
1709	/* XXX if one is _POSIX_VDISABLE, can't use some others */
1710	if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
1711		cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]);
1712	if (t->c_cc[VSTART] != _POSIX_VDISABLE)
1713		cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]);
1714	if (t->c_cc[VINTR] != _POSIX_VDISABLE)
1715		cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]);
1716	if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
1717		cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);
1718#endif
1719
1720	/*
1721	 * set channel option register 1 -
1722	 *	parity mode
1723	 *	stop bits
1724	 *	char length
1725	 */
1726	opt = 0;
1727	/* parity */
1728	if (cflag & PARENB) {
1729		if (cflag & PARODD)
1730			opt |= CD1400_COR1_PARODD;
1731		opt |= CD1400_COR1_PARNORMAL;
1732	}
1733	iflag = t->c_iflag;
1734	if (!(iflag & INPCK))
1735		opt |= CD1400_COR1_NOINPCK;
1736	bits = 1 + 1;
1737	/* stop bits */
1738	if (cflag & CSTOPB) {
1739		++bits;
1740		opt |= CD1400_COR1_STOP2;
1741	}
1742	/* char length */
1743	switch (cflag & CSIZE) {
1744	case CS5:
1745		bits += 5;
1746		opt |= CD1400_COR1_CS5;
1747		break;
1748	case CS6:
1749		bits += 6;
1750		opt |= CD1400_COR1_CS6;
1751		break;
1752	case CS7:
1753		bits += 7;
1754		opt |= CD1400_COR1_CS7;
1755		break;
1756	default:
1757		bits += 8;
1758		opt |= CD1400_COR1_CS8;
1759		break;
1760	}
1761	cor_change = 0;
1762	if (opt != com->cor[0]) {
1763		cor_change |= CD1400_CCR_COR1;
1764		cd_outb(iobase, CD1400_COR1, com->cor[0] = opt);
1765	}
1766
1767	/*
1768	 * Set receive time-out period, normally to max(one char time, 5 ms).
1769	 */
1770	if (t->c_ispeed == 0)
1771		itimeout = cd_inb(iobase, CD1400_RTPR);
1772	else {
1773		itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
1774#ifdef SOFT_HOTCHAR
1775#define	MIN_RTP		1
1776#else
1777#define	MIN_RTP		5
1778#endif
1779		if (itimeout < MIN_RTP)
1780			itimeout = MIN_RTP;
1781	}
1782	if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
1783	    && t->c_cc[VTIME] * 10 > itimeout)
1784		itimeout = t->c_cc[VTIME] * 10;
1785	if (itimeout > 255)
1786		itimeout = 255;
1787	cd_outb(iobase, CD1400_RTPR, itimeout);
1788
1789	/*
1790	 * set channel option register 2 -
1791	 *	flow control
1792	 */
1793	opt = 0;
1794#ifdef Smarts
1795	if (iflag & IXANY)
1796		opt |= CD1400_COR2_IXANY;
1797	if (iflag & IXOFF)
1798		opt |= CD1400_COR2_IXOFF;
1799#endif
1800#ifndef SOFT_CTS_OFLOW
1801	if (cflag & CCTS_OFLOW)
1802		opt |= CD1400_COR2_CCTS_OFLOW;
1803#endif
1804	if (opt != com->cor[1]) {
1805		cor_change |= CD1400_CCR_COR2;
1806		cd_outb(iobase, CD1400_COR2, com->cor[1] = opt);
1807	}
1808
1809	/*
1810	 * set channel option register 3 -
1811	 *	receiver FIFO interrupt threshold
1812	 *	flow control
1813	 */
1814	opt = RxFifoThreshold;
1815#ifdef Smarts
1816	if (t->c_lflag & ICANON)
1817		opt |= CD1400_COR3_SCD34;	/* detect INTR & SUSP chars */
1818	if (iflag & IXOFF)
1819		/* detect and transparently handle START and STOP chars */
1820		opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
1821#endif
1822	if (opt != com->cor[2]) {
1823		cor_change |= CD1400_CCR_COR3;
1824		cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
1825	}
1826
1827	/* notify the CD1400 if COR1-3 have changed */
1828	if (cor_change)
1829		cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change);
1830
1831	/*
1832	 * set channel option register 4 -
1833	 *	CR/NL processing
1834	 *	break processing
1835	 *	received exception processing
1836	 */
1837	opt = 0;
1838	if (iflag & IGNCR)
1839		opt |= CD1400_COR4_IGNCR;
1840#ifdef Smarts
1841	/*
1842	 * we need a new ttyinput() for this, as we don't want to
1843	 * have ICRNL && INLCR being done in both layers, or to have
1844	 * synchronisation problems
1845	 */
1846	if (iflag & ICRNL)
1847		opt |= CD1400_COR4_ICRNL;
1848	if (iflag & INLCR)
1849		opt |= CD1400_COR4_INLCR;
1850#endif
1851	if (iflag & IGNBRK)
1852		opt |= CD1400_COR4_IGNBRK;
1853	if (!(iflag & BRKINT))
1854		opt |= CD1400_COR4_NOBRKINT;
1855#if 0
1856	/* XXX using this "intelligence" breaks reporting of overruns. */
1857	if (iflag & IGNPAR)
1858		opt |= CD1400_COR4_PFO_DISCARD;
1859	else {
1860		if (iflag & PARMRK)
1861			opt |= CD1400_COR4_PFO_ESC;
1862		else
1863			opt |= CD1400_COR4_PFO_NUL;
1864	}
1865#else
1866	opt |= CD1400_COR4_PFO_EXCEPTION;
1867#endif
1868	cd_outb(iobase, CD1400_COR4, opt);
1869
1870	/*
1871	 * set channel option register 5 -
1872	 */
1873	opt = 0;
1874	if (iflag & ISTRIP)
1875		opt |= CD1400_COR5_ISTRIP;
1876	if (t->c_iflag & IEXTEN)
1877		/* enable LNEXT (e.g. ctrl-v quoting) handling */
1878		opt |= CD1400_COR5_LNEXT;
1879#ifdef Smarts
1880	if (t->c_oflag & ONLCR)
1881		opt |= CD1400_COR5_ONLCR;
1882	if (t->c_oflag & OCRNL)
1883		opt |= CD1400_COR5_OCRNL;
1884#endif
1885	cd_outb(iobase, CD1400_COR5, opt);
1886
1887	/*
1888	 * XXX we probably alway want to track carrier changes, so that
1889	 * TS_CARR_ON gives the true carrier.  If we don't track them,
1890	 * then we should set TS_CARR_ON when CLOCAL drops.
1891	 */
1892	/*
1893	 * set modem change option register 1
1894	 *	generate modem interrupts on which 1 -> 0 input transitions
1895	 *	also controls auto-DTR output flow-control, which we don't use
1896	 */
1897	opt = cflag & CLOCAL ? 0 : CD1400_MCOR1_CDzd;
1898#ifdef SOFT_CTS_OFLOW
1899	if (cflag & CCTS_OFLOW)
1900		opt |= CD1400_MCOR1_CTSzd;
1901#endif
1902	cd_outb(iobase, CD1400_MCOR1, opt);
1903
1904	/*
1905	 * set modem change option register 2
1906	 *	generate modem interrupts on specific 0 -> 1 input transitions
1907	 */
1908	opt = cflag & CLOCAL ? 0 : CD1400_MCOR2_CDod;
1909#ifdef SOFT_CTS_OFLOW
1910	if (cflag & CCTS_OFLOW)
1911		opt |= CD1400_MCOR2_CTSod;
1912#endif
1913	cd_outb(iobase, CD1400_MCOR2, opt);
1914
1915	/*
1916	 * XXX should have done this long ago, but there is too much state
1917	 * to change all atomically.
1918	 */
1919	disable_intr();
1920
1921	com->state &= ~CS_TTGO;
1922	if (!(tp->t_state & TS_TTSTOP))
1923		com->state |= CS_TTGO;
1924	if (cflag & CRTS_IFLOW)
1925		com->state |= CS_RTS_IFLOW;	/* XXX - secondary changes? */
1926	else
1927		com->state &= ~CS_RTS_IFLOW;
1928
1929	/*
1930	 * Set up state to handle output flow control.
1931	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
1932	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
1933	 */
1934	com->state |= CS_ODEVREADY;
1935#ifdef SOFT_CTS_OFLOW
1936	com->state &= ~CS_CTS_OFLOW;
1937	if (cflag & CCTS_OFLOW) {
1938		com->state |= CS_CTS_OFLOW;
1939		if (!(com->last_modem_status & MSR_CTS))
1940			com->state &= ~CS_ODEVREADY;
1941	}
1942#endif
1943	/* XXX shouldn't call functions while intrs are disabled. */
1944	disc_optim(tp, t, com);
1945#if 0
1946	/*
1947	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
1948	 * unconditionally, but that defeated the careful discarding of
1949	 * stale input in sioopen().
1950	 */
1951	if (com->state >= (CS_BUSY | CS_TTGO))
1952		siointr1(com);
1953#endif
1954	if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1955		if (!(com->intr_enable & CD1400_SRER_TXRDY))
1956			cd_outb(iobase, CD1400_SRER,
1957				com->intr_enable |= CD1400_SRER_TXRDY);
1958	} else {
1959		if (com->intr_enable & CD1400_SRER_TXRDY)
1960			cd_outb(iobase, CD1400_SRER,
1961				com->intr_enable &= ~CD1400_SRER_TXRDY);
1962	}
1963
1964	enable_intr();
1965	splx(s);
1966	return (0);
1967}
1968
1969static void
1970comstart(tp)
1971	struct tty	*tp;
1972{
1973	struct com_s	*com;
1974	cy_addr		iobase;
1975	int		s;
1976#ifdef CyDebug
1977	bool_t		started;
1978#endif
1979	int		unit;
1980
1981	unit = DEV_TO_UNIT(tp->t_dev);
1982	com = com_addr(unit);
1983	iobase = com->iobase;
1984	s = spltty();
1985
1986#ifdef CyDebug
1987	++com->start_count;
1988	started = FALSE;
1989#endif
1990
1991	disable_intr();
1992	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
1993	if (tp->t_state & TS_TTSTOP) {
1994		com->state &= ~CS_TTGO;
1995		if (com->intr_enable & CD1400_SRER_TXRDY)
1996			cd_outb(iobase, CD1400_SRER,
1997				com->intr_enable &= ~CD1400_SRER_TXRDY);
1998	} else {
1999		com->state |= CS_TTGO;
2000		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
2001		    && !(com->intr_enable & CD1400_SRER_TXRDY))
2002			cd_outb(iobase, CD1400_SRER,
2003				com->intr_enable |= CD1400_SRER_TXRDY);
2004	}
2005	if (tp->t_state & TS_TBLOCK) {
2006		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2007#if 0
2008			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2009#else
2010			cd_outb(iobase, CD1400_MSVR1,
2011				com->mcr_image &= ~MCR_RTS);
2012#endif
2013	} else {
2014		/*
2015		 * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off.  Set it
2016		 * appropriately in comparam() if RTS-flow is being changed.
2017		 * Check for races.
2018		 */
2019		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
2020#if 0
2021			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2022#else
2023			cd_outb(iobase, CD1400_MSVR1,
2024				com->mcr_image |= MCR_RTS);
2025#endif
2026	}
2027	enable_intr();
2028	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2029		splx(s);
2030		return;
2031	}
2032	if (tp->t_outq.c_cc != 0) {
2033		struct lbq	*qp;
2034		struct lbq	*next;
2035
2036		if (!com->obufs[0].l_queued) {
2037#ifdef CyDebug
2038			started = TRUE;
2039#endif
2040			com->obufs[0].l_tail
2041			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2042						  sizeof com->obuf1);
2043			com->obufs[0].l_next = NULL;
2044			com->obufs[0].l_queued = TRUE;
2045			disable_intr();
2046			if (com->state & CS_BUSY) {
2047				qp = com->obufq.l_next;
2048				while ((next = qp->l_next) != NULL)
2049					qp = next;
2050				qp->l_next = &com->obufs[0];
2051			} else {
2052				com->obufq.l_head = com->obufs[0].l_head;
2053				com->obufq.l_tail = com->obufs[0].l_tail;
2054				com->obufq.l_next = &com->obufs[0];
2055				com->state |= CS_BUSY;
2056				if (com->state >= (CS_BUSY | CS_TTGO
2057						   | CS_ODEVREADY))
2058					cd_outb(iobase, CD1400_SRER,
2059						com->intr_enable
2060						|= CD1400_SRER_TXRDY);
2061			}
2062			enable_intr();
2063		}
2064		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2065#ifdef CyDebug
2066			started = TRUE;
2067#endif
2068			com->obufs[1].l_tail
2069			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2070						  sizeof com->obuf2);
2071			com->obufs[1].l_next = NULL;
2072			com->obufs[1].l_queued = TRUE;
2073			disable_intr();
2074			if (com->state & CS_BUSY) {
2075				qp = com->obufq.l_next;
2076				while ((next = qp->l_next) != NULL)
2077					qp = next;
2078				qp->l_next = &com->obufs[1];
2079			} else {
2080				com->obufq.l_head = com->obufs[1].l_head;
2081				com->obufq.l_tail = com->obufs[1].l_tail;
2082				com->obufq.l_next = &com->obufs[1];
2083				com->state |= CS_BUSY;
2084				if (com->state >= (CS_BUSY | CS_TTGO
2085						   | CS_ODEVREADY))
2086					cd_outb(iobase, CD1400_SRER,
2087						com->intr_enable
2088						|= CD1400_SRER_TXRDY);
2089			}
2090			enable_intr();
2091		}
2092		tp->t_state |= TS_BUSY;
2093	}
2094#ifdef CyDebug
2095	if (started)
2096		++com->start_real;
2097#endif
2098#if 0
2099	disable_intr();
2100	if (com->state >= (CS_BUSY | CS_TTGO)) {
2101		siointr1(com);	/* fake interrupt to start output */
2102	enable_intr();
2103#endif
2104	ttwwakeup(tp);
2105	splx(s);
2106}
2107
2108void
2109siostop(tp, rw)
2110	struct tty	*tp;
2111	int		rw;
2112{
2113	struct com_s	*com;
2114
2115	com = com_addr(DEV_TO_UNIT(tp->t_dev));
2116	disable_intr();
2117	if (rw & FWRITE) {
2118		com->obufs[0].l_queued = FALSE;
2119		com->obufs[1].l_queued = FALSE;
2120		if (com->state & CS_ODONE)
2121			com_events -= LOTS_OF_EVENTS;
2122		com->state &= ~(CS_ODONE | CS_BUSY);
2123		com->tp->t_state &= ~TS_BUSY;
2124	}
2125	if (rw & FREAD) {
2126		com_events -= (com->iptr - com->ibuf);
2127		com->iptr = com->ibuf;
2128	}
2129	enable_intr();
2130	comstart(tp);
2131
2132	/* XXX should clear h/w fifos too. */
2133}
2134
2135struct tty *
2136siodevtotty(dev)
2137	dev_t	dev;
2138{
2139	int	mynor;
2140	int	unit;
2141
2142	mynor = minor(dev);
2143	if (mynor & CONTROL_MASK)
2144		return (NULL);
2145	unit = MINOR_TO_UNIT(mynor);
2146	if ((u_int) unit >= NSIO)
2147		return (NULL);
2148	return (&sio_tty[unit]);
2149}
2150
2151static int
2152commctl(com, bits, how)
2153	struct com_s	*com;
2154	int		bits;
2155	int		how;
2156{
2157	cy_addr	iobase;
2158	int	mcr;
2159	int	msr;
2160
2161	if (how == DMGET) {
2162		if (com->channel_control & CD1400_CCR_RCVEN)
2163			bits |= TIOCM_LE;
2164		mcr = com->mcr_image;
2165		if (mcr & MCR_DTR)
2166			bits |= TIOCM_DTR;
2167		if (mcr & MCR_RTS)
2168			/* XXX wired on for Cyclom-8Ys */
2169			bits |= TIOCM_RTS;
2170		msr = com->prev_modem_status;
2171		if (msr & MSR_CTS)
2172			bits |= TIOCM_CTS;
2173		if (msr & MSR_DCD)
2174			bits |= TIOCM_CD;
2175		if (msr & MSR_DSR)
2176			bits |= TIOCM_DSR;
2177		if (msr & MSR_RI)
2178			/* XXX not connected except for Cyclom-16Y? */
2179			bits |= TIOCM_RI;
2180		return (bits);
2181	}
2182	iobase = com->iobase;
2183	mcr = 0;
2184	if (bits & TIOCM_DTR)
2185		mcr |= MCR_DTR;
2186	if (bits & TIOCM_RTS)
2187		mcr |= MCR_RTS;
2188	disable_intr();
2189	switch (how) {
2190	case DMSET:
2191		com->mcr_image = mcr;
2192		cd_outb(iobase, CD1400_MSVR1, mcr);
2193		cd_outb(iobase, CD1400_MSVR2, mcr);
2194		break;
2195	case DMBIS:
2196		com->mcr_image = mcr = com->mcr_image | mcr;
2197		cd_outb(iobase, CD1400_MSVR1, mcr);
2198		cd_outb(iobase, CD1400_MSVR2, mcr);
2199		break;
2200	case DMBIC:
2201		com->mcr_image = mcr = com->mcr_image & ~mcr;
2202		cd_outb(iobase, CD1400_MSVR1, mcr);
2203		cd_outb(iobase, CD1400_MSVR2, mcr);
2204		break;
2205	}
2206	enable_intr();
2207	return (0);
2208}
2209
2210static void
2211siosettimeout()
2212{
2213	struct com_s	*com;
2214	bool_t		someopen;
2215	int		unit;
2216
2217	/*
2218	 * Set our timeout period to 1 second if no polled devices are open.
2219	 * Otherwise set it to max(1/200, 1/hz).
2220	 * Enable timeouts iff some device is open.
2221	 */
2222	untimeout(comwakeup, (void *)NULL);
2223	sio_timeout = hz;
2224	someopen = FALSE;
2225	for (unit = 0; unit < NSIO; ++unit) {
2226		com = com_addr(unit);
2227		if (com != NULL && com->tp != NULL
2228		    && com->tp->t_state & TS_ISOPEN) {
2229			someopen = TRUE;
2230#if 0
2231			if (com->poll || com->poll_output) {
2232				sio_timeout = hz > 200 ? hz / 200 : 1;
2233				break;
2234			}
2235#endif
2236		}
2237	}
2238	if (someopen) {
2239		sio_timeouts_until_log = hz / sio_timeout;
2240		timeout(comwakeup, (void *)NULL, sio_timeout);
2241	} else {
2242		/* Flush error messages, if any. */
2243		sio_timeouts_until_log = 1;
2244		comwakeup((void *)NULL);
2245		untimeout(comwakeup, (void *)NULL);
2246	}
2247}
2248
2249static void
2250comwakeup(chan)
2251	void	*chan;
2252{
2253	struct com_s	*com;
2254	int		unit;
2255
2256	timeout(comwakeup, (void *)NULL, sio_timeout);
2257
2258#if 0
2259	/*
2260	 * Recover from lost output interrupts.
2261	 * Poll any lines that don't use interrupts.
2262	 */
2263	for (unit = 0; unit < NSIO; ++unit) {
2264		com = com_addr(unit);
2265		if (com != NULL
2266		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2267			disable_intr();
2268			siointr1(com);
2269			enable_intr();
2270		}
2271	}
2272#endif
2273
2274	/*
2275	 * Check for and log errors, but not too often.
2276	 */
2277	if (--sio_timeouts_until_log > 0)
2278		return;
2279	sio_timeouts_until_log = hz / sio_timeout;
2280	for (unit = 0; unit < NSIO; ++unit) {
2281		int	errnum;
2282
2283		com = com_addr(unit);
2284		if (com == NULL)
2285			continue;
2286		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2287			u_int	delta;
2288			u_long	total;
2289
2290			disable_intr();
2291			delta = com->delta_error_counts[errnum];
2292			com->delta_error_counts[errnum] = 0;
2293			enable_intr();
2294			if (delta == 0)
2295				continue;
2296			total = com->error_counts[errnum] += delta;
2297			log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
2298			    unit, delta, error_desc[errnum],
2299			    delta == 1 ? "" : "s", total);
2300#if 0
2301			/*
2302			 * XXX if we resurrect this then we should move
2303			 * the dropping of the ftl to somewhere with less
2304			 * latency.
2305			 */
2306			if (errnum == CE_OVERRUN && com->hasfifo
2307			    && com->ftl > FIFO_TRIGGER_1) {
2308				static	u_char	ftl_in_bytes[] =
2309					{ 1, 4, 8, 14, };
2310
2311				com->ftl_init = FIFO_TRIGGER_8;
2312#define	FIFO_TRIGGER_DELTA	FIFO_TRIGGER_4
2313				com->ftl_max =
2314				com->ftl -= FIFO_TRIGGER_DELTA;
2315				outb(com->iobase + com_fifo,
2316				     FIFO_ENABLE | com->ftl);
2317				log(LOG_DEBUG,
2318				    "sio%d: reduced fifo trigger level to %d\n",
2319				    unit,
2320				    ftl_in_bytes[com->ftl
2321						 / FIFO_TRIGGER_DELTA]);
2322			}
2323#endif
2324		}
2325	}
2326}
2327
2328static void
2329disc_optim(tp, t, com)
2330	struct tty	*tp;
2331	struct termios	*t;
2332	struct com_s	*com;
2333{
2334#ifndef SOFT_HOTCHAR
2335	cy_addr	iobase;
2336	u_char	opt;
2337#endif
2338
2339	/*
2340	 * XXX can skip a lot more cases if Smarts.  Maybe
2341	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
2342	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2343	 */
2344	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2345	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2346	    && (!(t->c_iflag & PARMRK)
2347		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2348	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2349	    && linesw[tp->t_line].l_rint == ttyinput)
2350		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2351	else
2352		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2353	/*
2354	 * Prepare to reduce input latency for packet
2355	 * discplines with a end of packet character.
2356	 */
2357	if (tp->t_line == SLIPDISC)
2358		com->hotchar = 0xc0;
2359	else if (tp->t_line == PPPDISC)
2360		com->hotchar = 0x7e;
2361	else
2362		com->hotchar = 0;
2363#ifndef SOFT_HOTCHAR
2364	iobase = com->iobase;
2365	cd_outb(iobase, CD1400_CAR, com->unit & CD1400_CAR_CHAN);
2366	opt = com->cor[2] & ~CD1400_COR3_SCD34;
2367	if (com->hotchar != 0) {
2368		cd_outb(iobase, CD1400_SCHR3, com->hotchar);
2369		cd_outb(iobase, CD1400_SCHR4, com->hotchar);
2370		opt |= CD1400_COR3_SCD34;
2371	}
2372	if (opt != com->cor[2]) {
2373		cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
2374		cd1400_channel_cmd(com->iobase,
2375				   CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
2376	}
2377#endif
2378}
2379
2380#ifdef Smarts
2381/* standard line discipline input routine */
2382int
2383cyinput(c, tp)
2384	int		c;
2385	struct tty	*tp;
2386{
2387	/* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
2388	 * bits, as they are done by the CD1400.  Hardly worth the effort,
2389	 * given that high-throughput sessions are raw anyhow.
2390	 */
2391}
2392#endif /* Smarts */
2393
2394static int
2395comspeed(speed, prescaler_io)
2396	speed_t	speed;
2397	int	*prescaler_io;
2398{
2399	int	actual;
2400	int	error;
2401	int	divider;
2402	int	prescaler;
2403	int	prescaler_unit;
2404
2405	if (speed == 0)
2406		return (0);
2407	if (speed < 0 || speed > 150000)
2408		return (-1);
2409
2410	/* determine which prescaler to use */
2411	for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
2412		prescaler_unit--, prescaler >>= 2) {
2413		if (CY_CLOCK / prescaler / speed > 63)
2414			break;
2415	}
2416
2417	divider = (CY_CLOCK / prescaler * 2 / speed + 1) / 2; /* round off */
2418	if (divider > 255)
2419		divider = 255;
2420	actual = CY_CLOCK/prescaler/divider;
2421	error = ((actual - speed) * 2000 / speed + 1) / 2;	/* percentage */
2422
2423	/* 3.0% max error tolerance */
2424	if (error < -30 || error > 30)
2425		return (-1);
2426
2427#if 0
2428	printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
2429	printf("divider = %d (%x)\n", divider, divider);
2430	printf("actual = %d\n", actual);
2431	printf("error = %d\n", error);
2432#endif
2433
2434	*prescaler_io = prescaler_unit;
2435	return (divider);
2436}
2437
2438static void
2439cd1400_channel_cmd(iobase, cmd)
2440	cy_addr	iobase;
2441	int	cmd;
2442{
2443	/* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
2444	   as the card is probed every round?  Replaced delaycount with 8k.
2445	   Either delaycount has to be implemented in FreeBSD or more sensible
2446	   way of doing these should be implemented.  DELAY isn't enough here.
2447	   */
2448	u_int	maxwait = 5 * 8 * 1024;	/* approx. 5 ms */
2449
2450	/* wait for processing of previous command to complete */
2451	while (cd_inb(iobase, CD1400_CCR) && maxwait--)
2452		;
2453
2454	if (!maxwait)
2455		log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
2456		    5 * 8 * 1024);
2457
2458	cd_outb(iobase, CD1400_CCR, cmd);
2459}
2460
2461#ifdef CyDebug
2462/* useful in ddb */
2463void
2464cystatus(unit)
2465	int	unit;
2466{
2467	struct com_s	*com;
2468	cy_addr		iobase;
2469	u_int		ocount;
2470	struct tty	*tp;
2471
2472	com = com_addr(unit);
2473	printf("info for channel %d\n", unit);
2474	printf("------------------\n");
2475	printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
2476	printf("calls to upper layer:\t\t%d\n", cy_timeouts);
2477	if (com == NULL)
2478		return;
2479	iobase = com->iobase;
2480	printf("\n");
2481	printf("cd1400 base address:\\tt%p\n", iobase);
2482	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
2483	printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
2484	printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
2485	       com->cor[0], com->cor[1], com->cor[2]);
2486	printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
2487	       cd_inb(iobase, CD1400_SRER), com->intr_enable);
2488	printf("service request register:\t0x%02x\n",
2489	       cd_inb(iobase, CD1400_SVRR));
2490	printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
2491	       cd_inb(iobase, CD1400_MSVR2), com->prev_modem_status);
2492	printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
2493	       cd_inb(iobase, CD1400_RIR), cd_inb(iobase, CD1400_TIR),
2494	       cd_inb(iobase, CD1400_MIR));
2495	printf("\n");
2496	printf("com state:\t\t\t0x%02x\n", com->state);
2497	printf("calls to comstart():\t\t%d (%d useful)\n",
2498	       com->start_count, com->start_real);
2499	printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
2500	ocount = 0;
2501	if (com->obufs[0].l_queued)
2502		ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
2503	if (com->obufs[1].l_queued)
2504		ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
2505	printf("tx buffer chars:\t\t%u\n", ocount);
2506	printf("received chars:\t\t\t%d\n", com->bytes_in);
2507	printf("received exceptions:\t\t%d\n", com->recv_exception);
2508	printf("modem signal deltas:\t\t%d\n", com->mdm);
2509	printf("transmitted chars:\t\t%d\n", com->bytes_out);
2510	printf("\n");
2511	tp = com->tp;
2512	if (tp != NULL) {
2513		printf("tty state:\t\t\t0x%08x\n", tp->t_state);
2514		printf("upper layer queue lengths:\t%d raw, %d canon, %d output\n",
2515		       tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
2516	} else
2517		printf("tty state:\t\t\tclosed\n");
2518}
2519#endif /* CyDebug */
2520
2521#endif /* NCY > 0 */
2522