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