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