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