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