cy.c revision 32726
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.59 1997/12/28 06:23:03 bde 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			com->bytes_in += count;
1126			ioptr = com->iptr;
1127			ifree = com->ibufend - ioptr;
1128			if (count > ifree) {
1129				count -= ifree;
1130				com_events += ifree;
1131				if (ifree != 0) {
1132					if (com->do_timestamp)
1133						microtime(&com->timestamp);
1134					do {
1135						recv_data = cd_inb(iobase,
1136								   CD1400_RDSR,
1137								   cy_align);
1138#ifdef SOFT_HOTCHAR
1139						if (com->hotchar != 0
1140						    && recv_data
1141						       == com->hotchar)
1142							setsofttty();
1143#endif
1144						ioptr[0] = recv_data;
1145						ioptr[CE_INPUT_OFFSET] = 0;
1146						++ioptr;
1147					} while (--ifree != 0);
1148				}
1149				com->delta_error_counts
1150				    [CE_INTERRUPT_BUF_OVERFLOW] += count;
1151				do {
1152					recv_data = cd_inb(iobase, CD1400_RDSR,
1153							   cy_align);
1154#ifdef SOFT_HOTCHAR
1155					if (com->hotchar != 0
1156					    && recv_data == com->hotchar)
1157						setsofttty();
1158#endif
1159				} while (--count != 0);
1160			} else {
1161				if (com->do_timestamp)
1162					microtime(&com->timestamp);
1163				if (ioptr <= com->ihighwater
1164				    && ioptr + count > com->ihighwater
1165				    && com->state & CS_RTS_IFLOW)
1166#if 0
1167					outb(com->modem_ctl_port,
1168					     com->mcr_image &= ~MCR_RTS);
1169#else
1170					cd_outb(iobase, CD1400_MSVR1, cy_align,
1171						com->mcr_image &= ~MCR_RTS);
1172#endif
1173				com_events += count;
1174				do {
1175					recv_data = cd_inb(iobase, CD1400_RDSR,
1176							   cy_align);
1177#ifdef SOFT_HOTCHAR
1178					if (com->hotchar != 0
1179					    && recv_data == com->hotchar)
1180						setsofttty();
1181#endif
1182					ioptr[0] = recv_data;
1183					ioptr[CE_INPUT_OFFSET] = 0;
1184					++ioptr;
1185				} while (--count != 0);
1186			}
1187			com->iptr = ioptr;
1188		}
1189cont:
1190
1191			/* terminate service context */
1192#ifdef PollMode
1193			cd_outb(iobase, CD1400_RIR, cy_align,
1194				save_rir
1195				& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
1196			cd_outb(iobase, CD1400_CAR, cy_align, save_car);
1197#else
1198			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1199#endif
1200		}
1201		if (status & CD1400_SVRR_MDMCH) {
1202			struct com_s	*com;
1203			u_char	modem_status;
1204#ifdef PollMode
1205			u_char	save_car;
1206			u_char	save_mir;
1207#else
1208			u_char	vector;
1209#endif
1210
1211#ifdef PollMode
1212			save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
1213			save_car = cd_inb(iobase, CD1400_CAR, cy_align);
1214
1215			/* enter modem service */
1216			cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
1217
1218			com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
1219				       + (save_mir & CD1400_MIR_CHAN));
1220#else
1221			/* ack modem service */
1222			vector = cy_inb(iobase, CY8_SVCACKM);
1223
1224			com = com_addr(baseu
1225				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1226					  & CD1400_xIVR_CHAN));
1227#endif
1228			++com->mdm;
1229			modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
1230		if (modem_status != com->last_modem_status) {
1231			if (com->do_dcd_timestamp
1232			    && !(com->last_modem_status & MSR_DCD)
1233			    && modem_status & MSR_DCD)
1234				microtime(&com->dcd_timestamp);
1235
1236			/*
1237			 * Schedule high level to handle DCD changes.  Note
1238			 * that we don't use the delta bits anywhere.  Some
1239			 * UARTs mess them up, and it's easy to remember the
1240			 * previous bits and calculate the delta.
1241			 */
1242			com->last_modem_status = modem_status;
1243			if (!(com->state & CS_CHECKMSR)) {
1244				com_events += LOTS_OF_EVENTS;
1245				com->state |= CS_CHECKMSR;
1246				setsofttty();
1247			}
1248
1249#ifdef SOFT_CTS_OFLOW
1250			/* handle CTS change immediately for crisp flow ctl */
1251			if (com->state & CS_CTS_OFLOW) {
1252				if (modem_status & MSR_CTS) {
1253					com->state |= CS_ODEVREADY;
1254					if (com->state >= (CS_BUSY | CS_TTGO
1255							   | CS_ODEVREADY)
1256					    && !(com->intr_enable
1257						 & CD1400_SRER_TXRDY))
1258						cd_outb(iobase, CD1400_SRER,
1259							cy_align,
1260							com->intr_enable
1261							|= CD1400_SRER_TXRDY);
1262				} else {
1263					com->state &= ~CS_ODEVREADY;
1264					if (com->intr_enable
1265					    & CD1400_SRER_TXRDY)
1266						cd_outb(iobase, CD1400_SRER,
1267							cy_align,
1268							com->intr_enable
1269							&= ~CD1400_SRER_TXRDY);
1270				}
1271			}
1272#endif
1273		}
1274
1275			/* terminate service context */
1276#ifdef PollMode
1277			cd_outb(iobase, CD1400_MIR, cy_align,
1278				save_mir
1279				& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
1280			cd_outb(iobase, CD1400_CAR, cy_align, save_car);
1281#else
1282			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1283#endif
1284		}
1285		if (status & CD1400_SVRR_TXRDY) {
1286			struct com_s	*com;
1287#ifdef PollMode
1288			u_char	save_car;
1289			u_char	save_tir;
1290#else
1291			u_char	vector;
1292#endif
1293
1294#ifdef PollMode
1295			save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
1296			save_car = cd_inb(iobase, CD1400_CAR, cy_align);
1297
1298			/* enter tx service */
1299			cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
1300			com = com_addr(baseu
1301				       + cyu * CD1400_NO_OF_CHANNELS
1302				       + (save_tir & CD1400_TIR_CHAN));
1303#else
1304			/* ack transmit service */
1305			vector = cy_inb(iobase, CY8_SVCACKT);
1306
1307			com = com_addr(baseu
1308				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1309					  & CD1400_xIVR_CHAN));
1310#endif
1311
1312		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1313			u_char	*ioptr;
1314			u_int	ocount;
1315
1316			ioptr = com->obufq.l_head;
1317				ocount = com->obufq.l_tail - ioptr;
1318				if (ocount > CD1400_TX_FIFO_SIZE)
1319					ocount = CD1400_TX_FIFO_SIZE;
1320				com->bytes_out += ocount;
1321				do
1322					cd_outb(iobase, CD1400_TDR, cy_align,
1323						*ioptr++);
1324				while (--ocount != 0);
1325			com->obufq.l_head = ioptr;
1326			if (ioptr >= com->obufq.l_tail) {
1327				struct lbq	*qp;
1328
1329				qp = com->obufq.l_next;
1330				qp->l_queued = FALSE;
1331				qp = qp->l_next;
1332				if (qp != NULL) {
1333					com->obufq.l_head = qp->l_head;
1334					com->obufq.l_tail = qp->l_tail;
1335					com->obufq.l_next = qp;
1336				} else {
1337					/* output just completed */
1338					com->state &= ~CS_BUSY;
1339					cd_outb(iobase, CD1400_SRER, cy_align,
1340						com->intr_enable
1341						&= ~CD1400_SRER_TXRDY);
1342				}
1343				if (!(com->state & CS_ODONE)) {
1344					com_events += LOTS_OF_EVENTS;
1345					com->state |= CS_ODONE;
1346
1347					/* handle at high level ASAP */
1348					setsofttty();
1349				}
1350			}
1351		}
1352
1353			/* terminate service context */
1354#ifdef PollMode
1355			cd_outb(iobase, CD1400_TIR, cy_align,
1356				save_tir
1357				& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
1358			cd_outb(iobase, CD1400_CAR, cy_align, save_car);
1359#else
1360			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1361#endif
1362		}
1363	}
1364
1365	/* ensure an edge for the next interrupt */
1366	cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
1367
1368	schedsofttty();
1369
1370	COM_UNLOCK();
1371}
1372
1373#if 0
1374static void
1375siointr1(com)
1376	struct com_s	*com;
1377{
1378}
1379#endif
1380
1381static int
1382sioioctl(dev, cmd, data, flag, p)
1383	dev_t		dev;
1384	int		cmd;
1385	caddr_t		data;
1386	int		flag;
1387	struct proc	*p;
1388{
1389	struct com_s	*com;
1390	int		error;
1391	cy_addr		iobase;
1392	int		mynor;
1393	int		s;
1394	struct tty	*tp;
1395#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1396	int		oldcmd;
1397	struct termios	term;
1398#endif
1399
1400	mynor = minor(dev);
1401	com = com_addr(MINOR_TO_UNIT(mynor));
1402	iobase = com->iobase;
1403	if (mynor & CONTROL_MASK) {
1404		struct termios	*ct;
1405
1406		switch (mynor & CONTROL_MASK) {
1407		case CONTROL_INIT_STATE:
1408			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1409			break;
1410		case CONTROL_LOCK_STATE:
1411			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1412			break;
1413		default:
1414			return (ENODEV);	/* /dev/nodev */
1415		}
1416		switch (cmd) {
1417		case TIOCSETA:
1418			error = suser(p->p_ucred, &p->p_acflag);
1419			if (error != 0)
1420				return (error);
1421			*ct = *(struct termios *)data;
1422			return (0);
1423		case TIOCGETA:
1424			*(struct termios *)data = *ct;
1425			return (0);
1426		case TIOCGETD:
1427			*(int *)data = TTYDISC;
1428			return (0);
1429		case TIOCGWINSZ:
1430			bzero(data, sizeof(struct winsize));
1431			return (0);
1432		default:
1433			return (ENOTTY);
1434		}
1435	}
1436	tp = com->tp;
1437#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1438	term = tp->t_termios;
1439	oldcmd = cmd;
1440	error = ttsetcompat(tp, &cmd, data, &term);
1441	if (error != 0)
1442		return (error);
1443	if (cmd != oldcmd)
1444		data = (caddr_t)&term;
1445#endif
1446	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1447		int	cc;
1448		struct termios *dt = (struct termios *)data;
1449		struct termios *lt = mynor & CALLOUT_MASK
1450				     ? &com->lt_out : &com->lt_in;
1451
1452		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1453			      | (dt->c_iflag & ~lt->c_iflag);
1454		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1455			      | (dt->c_oflag & ~lt->c_oflag);
1456		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1457			      | (dt->c_cflag & ~lt->c_cflag);
1458		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1459			      | (dt->c_lflag & ~lt->c_lflag);
1460		for (cc = 0; cc < NCCS; ++cc)
1461			if (lt->c_cc[cc] != 0)
1462				dt->c_cc[cc] = tp->t_cc[cc];
1463		if (lt->c_ispeed != 0)
1464			dt->c_ispeed = tp->t_ispeed;
1465		if (lt->c_ospeed != 0)
1466			dt->c_ospeed = tp->t_ospeed;
1467	}
1468	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1469	if (error != ENOIOCTL)
1470		return (error);
1471	s = spltty();
1472	error = ttioctl(tp, cmd, data, flag);
1473	disc_optim(tp, &tp->t_termios, com);
1474	if (error != ENOIOCTL) {
1475		splx(s);
1476		return (error);
1477	}
1478	cd_outb(iobase, CD1400_CAR, com->cy_align,
1479		MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
1480	switch (cmd) {
1481#if 0
1482	case TIOCSBRK:
1483		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1484		break;
1485	case TIOCCBRK:
1486		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1487		break;
1488#endif /* 0 */
1489	case TIOCSDTR:
1490		(void)commctl(com, TIOCM_DTR, DMBIS);
1491		break;
1492	case TIOCCDTR:
1493		(void)commctl(com, TIOCM_DTR, DMBIC);
1494		break;
1495	/*
1496	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
1497	 * changes get undone on the next call to comparam().
1498	 */
1499	case TIOCMSET:
1500		(void)commctl(com, *(int *)data, DMSET);
1501		break;
1502	case TIOCMBIS:
1503		(void)commctl(com, *(int *)data, DMBIS);
1504		break;
1505	case TIOCMBIC:
1506		(void)commctl(com, *(int *)data, DMBIC);
1507		break;
1508	case TIOCMGET:
1509		*(int *)data = commctl(com, 0, DMGET);
1510		break;
1511	case TIOCMSDTRWAIT:
1512		/* must be root since the wait applies to following logins */
1513		error = suser(p->p_ucred, &p->p_acflag);
1514		if (error != 0) {
1515			splx(s);
1516			return (error);
1517		}
1518		com->dtr_wait = *(int *)data * hz / 100;
1519		break;
1520	case TIOCMGDTRWAIT:
1521		*(int *)data = com->dtr_wait * 100 / hz;
1522		break;
1523	case TIOCTIMESTAMP:
1524		com->do_timestamp = TRUE;
1525		*(struct timeval *)data = com->timestamp;
1526		break;
1527	case TIOCDCDTIMESTAMP:
1528		com->do_dcd_timestamp = TRUE;
1529		*(struct timeval *)data = com->dcd_timestamp;
1530		break;
1531	default:
1532		splx(s);
1533		return (ENOTTY);
1534	}
1535	splx(s);
1536	return (0);
1537}
1538
1539void
1540siopoll()
1541{
1542	int		unit;
1543
1544#ifdef CyDebug
1545	++cy_timeouts;
1546#endif
1547	if (com_events == 0)
1548		return;
1549repeat:
1550	for (unit = 0; unit < NSIO; ++unit) {
1551		u_char		*buf;
1552		struct com_s	*com;
1553		u_char		*ibuf;
1554		cy_addr		iobase;
1555		int		incc;
1556		struct tty	*tp;
1557
1558		com = com_addr(unit);
1559		if (com == NULL)
1560			continue;
1561		tp = com->tp;
1562		if (tp == NULL) {
1563			/*
1564			 * XXX forget any events related to closed devices
1565			 * (actually never opened devices) so that we don't
1566			 * loop.
1567			 */
1568			disable_intr();
1569			incc = com->iptr - com->ibuf;
1570			com->iptr = com->ibuf;
1571			if (com->state & CS_CHECKMSR) {
1572				incc += LOTS_OF_EVENTS;
1573				com->state &= ~CS_CHECKMSR;
1574			}
1575			com_events -= incc;
1576			enable_intr();
1577			if (incc != 0)
1578				log(LOG_DEBUG,
1579				    "sio%d: %d events for device with no tp\n",
1580				    unit, incc);
1581			continue;
1582		}
1583
1584		/* switch the role of the low-level input buffers */
1585		if (com->iptr == (ibuf = com->ibuf)) {
1586			buf = NULL;     /* not used, but compiler can't tell */
1587			incc = 0;
1588		} else {
1589			buf = ibuf;
1590			disable_intr();
1591			incc = com->iptr - buf;
1592			com_events -= incc;
1593			if (ibuf == com->ibuf1)
1594				ibuf = com->ibuf2;
1595			else
1596				ibuf = com->ibuf1;
1597			com->ibufend = ibuf + RS_IBUFSIZE;
1598			com->ihighwater = ibuf + RS_IHIGHWATER;
1599			com->iptr = ibuf;
1600
1601			/*
1602			 * There is now room for another low-level buffer full
1603			 * of input, so enable RTS if it is now disabled and
1604			 * there is room in the high-level buffer.
1605			 */
1606			if ((com->state & CS_RTS_IFLOW)
1607			    && !(com->mcr_image & MCR_RTS)
1608			    && !(tp->t_state & TS_TBLOCK))
1609#if 0
1610				outb(com->modem_ctl_port,
1611				     com->mcr_image |= MCR_RTS);
1612#else
1613				iobase = com->iobase,
1614				cd_outb(iobase, CD1400_CAR, com->cy_align,
1615					unit & CD1400_CAR_CHAN),
1616				cd_outb(iobase, CD1400_MSVR1, com->cy_align,
1617					com->mcr_image |= MCR_RTS);
1618#endif
1619			enable_intr();
1620			com->ibuf = ibuf;
1621		}
1622
1623		if (com->state & CS_CHECKMSR) {
1624			u_char	delta_modem_status;
1625
1626			disable_intr();
1627			delta_modem_status = com->last_modem_status
1628					     ^ com->prev_modem_status;
1629			com->prev_modem_status = com->last_modem_status;
1630			com_events -= LOTS_OF_EVENTS;
1631			com->state &= ~CS_CHECKMSR;
1632			enable_intr();
1633			if (delta_modem_status & MSR_DCD)
1634				(*linesw[tp->t_line].l_modem)
1635					(tp, com->prev_modem_status & MSR_DCD);
1636		}
1637		if (com->state & CS_ODONE) {
1638			disable_intr();
1639			com_events -= LOTS_OF_EVENTS;
1640			com->state &= ~CS_ODONE;
1641			if (!(com->state & CS_BUSY))
1642				com->tp->t_state &= ~TS_BUSY;
1643			enable_intr();
1644			(*linesw[tp->t_line].l_start)(tp);
1645		}
1646		if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
1647			continue;
1648		/*
1649		 * Avoid the grotesquely inefficient lineswitch routine
1650		 * (ttyinput) in "raw" mode.  It usually takes about 450
1651		 * instructions (that's without canonical processing or echo!).
1652		 * slinput is reasonably fast (usually 40 instructions plus
1653		 * call overhead).
1654		 */
1655		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1656			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
1657			    && (com->state & CS_RTS_IFLOW
1658				|| tp->t_iflag & IXOFF)
1659			    && !(tp->t_state & TS_TBLOCK))
1660				ttyblock(tp);
1661			tk_nin += incc;
1662			tk_rawcc += incc;
1663			tp->t_rawcc += incc;
1664			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1665				+= b_to_q((char *)buf, incc, &tp->t_rawq);
1666			ttwakeup(tp);
1667			if (tp->t_state & TS_TTSTOP
1668			    && (tp->t_iflag & IXANY
1669				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1670				tp->t_state &= ~TS_TTSTOP;
1671				tp->t_lflag &= ~FLUSHO;
1672				comstart(tp);
1673			}
1674		} else {
1675			do {
1676				u_char	line_status;
1677				int	recv_data;
1678
1679				line_status = (u_char) buf[CE_INPUT_OFFSET];
1680				recv_data = (u_char) *buf++;
1681				if (line_status
1682				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1683					if (line_status & LSR_BI)
1684						recv_data |= TTY_BI;
1685					if (line_status & LSR_FE)
1686						recv_data |= TTY_FE;
1687					if (line_status & LSR_OE)
1688						recv_data |= TTY_OE;
1689					if (line_status & LSR_PE)
1690						recv_data |= TTY_PE;
1691				}
1692				(*linesw[tp->t_line].l_rint)(recv_data, tp);
1693			} while (--incc > 0);
1694		}
1695		if (com_events == 0)
1696			break;
1697	}
1698	if (com_events >= LOTS_OF_EVENTS)
1699		goto repeat;
1700}
1701
1702static int
1703comparam(tp, t)
1704	struct tty	*tp;
1705	struct termios	*t;
1706{
1707	int		bits;
1708	int		cflag;
1709	struct com_s	*com;
1710	u_char		cor_change;
1711	int		idivisor;
1712	int		iflag;
1713	cy_addr		iobase;
1714	int		iprescaler;
1715	int		itimeout;
1716	int		odivisor;
1717	int		oprescaler;
1718	u_char		opt;
1719	int		s;
1720	int		unit;
1721
1722	/* do historical conversions */
1723	if (t->c_ispeed == 0)
1724		t->c_ispeed = t->c_ospeed;
1725
1726	/* check requested parameters */
1727	idivisor = comspeed(t->c_ispeed, &iprescaler);
1728	if (idivisor < 0)
1729		return (EINVAL);
1730	odivisor = comspeed(t->c_ospeed, &oprescaler);
1731	if (odivisor < 0)
1732		return (EINVAL);
1733
1734	/* parameters are OK, convert them to the com struct and the device */
1735	unit = DEV_TO_UNIT(tp->t_dev);
1736	com = com_addr(unit);
1737	iobase = com->iobase;
1738	s = spltty();
1739	cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
1740	if (odivisor == 0)
1741		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
1742	else
1743		(void)commctl(com, TIOCM_DTR, DMBIS);
1744
1745	if (idivisor != 0) {
1746		cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor);
1747		cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler);
1748	}
1749	if (odivisor != 0) {
1750		cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor);
1751		cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler);
1752	}
1753
1754	/*
1755	 * channel control
1756	 *	receiver enable
1757	 *	transmitter enable (always set)
1758	 */
1759	cflag = t->c_cflag;
1760	opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
1761	      | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
1762	if (opt != com->channel_control) {
1763		com->channel_control = opt;
1764		cd1400_channel_cmd(iobase, opt, com->cy_align);
1765	}
1766
1767#ifdef Smarts
1768	/* set special chars */
1769	/* XXX if one is _POSIX_VDISABLE, can't use some others */
1770	if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
1771		cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]);
1772	if (t->c_cc[VSTART] != _POSIX_VDISABLE)
1773		cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]);
1774	if (t->c_cc[VINTR] != _POSIX_VDISABLE)
1775		cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]);
1776	if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
1777		cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]);
1778#endif
1779
1780	/*
1781	 * set channel option register 1 -
1782	 *	parity mode
1783	 *	stop bits
1784	 *	char length
1785	 */
1786	opt = 0;
1787	/* parity */
1788	if (cflag & PARENB) {
1789		if (cflag & PARODD)
1790			opt |= CD1400_COR1_PARODD;
1791		opt |= CD1400_COR1_PARNORMAL;
1792	}
1793	iflag = t->c_iflag;
1794	if (!(iflag & INPCK))
1795		opt |= CD1400_COR1_NOINPCK;
1796	bits = 1 + 1;
1797	/* stop bits */
1798	if (cflag & CSTOPB) {
1799		++bits;
1800		opt |= CD1400_COR1_STOP2;
1801	}
1802	/* char length */
1803	switch (cflag & CSIZE) {
1804	case CS5:
1805		bits += 5;
1806		opt |= CD1400_COR1_CS5;
1807		break;
1808	case CS6:
1809		bits += 6;
1810		opt |= CD1400_COR1_CS6;
1811		break;
1812	case CS7:
1813		bits += 7;
1814		opt |= CD1400_COR1_CS7;
1815		break;
1816	default:
1817		bits += 8;
1818		opt |= CD1400_COR1_CS8;
1819		break;
1820	}
1821	cor_change = 0;
1822	if (opt != com->cor[0]) {
1823		cor_change |= CD1400_CCR_COR1;
1824		cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt);
1825	}
1826
1827	/*
1828	 * Set receive time-out period, normally to max(one char time, 5 ms).
1829	 */
1830	if (t->c_ispeed == 0)
1831		itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align);
1832	else {
1833		itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
1834#ifdef SOFT_HOTCHAR
1835#define	MIN_RTP		1
1836#else
1837#define	MIN_RTP		5
1838#endif
1839		if (itimeout < MIN_RTP)
1840			itimeout = MIN_RTP;
1841	}
1842	if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
1843	    && t->c_cc[VTIME] * 10 > itimeout)
1844		itimeout = t->c_cc[VTIME] * 10;
1845	if (itimeout > 255)
1846		itimeout = 255;
1847	cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout);
1848
1849	/*
1850	 * set channel option register 2 -
1851	 *	flow control
1852	 */
1853	opt = 0;
1854#ifdef Smarts
1855	if (iflag & IXANY)
1856		opt |= CD1400_COR2_IXANY;
1857	if (iflag & IXOFF)
1858		opt |= CD1400_COR2_IXOFF;
1859#endif
1860#ifndef SOFT_CTS_OFLOW
1861	if (cflag & CCTS_OFLOW)
1862		opt |= CD1400_COR2_CCTS_OFLOW;
1863#endif
1864	if (opt != com->cor[1]) {
1865		cor_change |= CD1400_CCR_COR2;
1866		cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt);
1867	}
1868
1869	/*
1870	 * set channel option register 3 -
1871	 *	receiver FIFO interrupt threshold
1872	 *	flow control
1873	 */
1874	opt = RxFifoThreshold;
1875#ifdef Smarts
1876	if (t->c_lflag & ICANON)
1877		opt |= CD1400_COR3_SCD34;	/* detect INTR & SUSP chars */
1878	if (iflag & IXOFF)
1879		/* detect and transparently handle START and STOP chars */
1880		opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
1881#endif
1882	if (opt != com->cor[2]) {
1883		cor_change |= CD1400_CCR_COR3;
1884		cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
1885	}
1886
1887	/* notify the CD1400 if COR1-3 have changed */
1888	if (cor_change)
1889		cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change,
1890				   com->cy_align);
1891
1892	/*
1893	 * set channel option register 4 -
1894	 *	CR/NL processing
1895	 *	break processing
1896	 *	received exception processing
1897	 */
1898	opt = 0;
1899	if (iflag & IGNCR)
1900		opt |= CD1400_COR4_IGNCR;
1901#ifdef Smarts
1902	/*
1903	 * we need a new ttyinput() for this, as we don't want to
1904	 * have ICRNL && INLCR being done in both layers, or to have
1905	 * synchronisation problems
1906	 */
1907	if (iflag & ICRNL)
1908		opt |= CD1400_COR4_ICRNL;
1909	if (iflag & INLCR)
1910		opt |= CD1400_COR4_INLCR;
1911#endif
1912	if (iflag & IGNBRK)
1913		opt |= CD1400_COR4_IGNBRK;
1914	if (!(iflag & BRKINT))
1915		opt |= CD1400_COR4_NOBRKINT;
1916#if 0
1917	/* XXX using this "intelligence" breaks reporting of overruns. */
1918	if (iflag & IGNPAR)
1919		opt |= CD1400_COR4_PFO_DISCARD;
1920	else {
1921		if (iflag & PARMRK)
1922			opt |= CD1400_COR4_PFO_ESC;
1923		else
1924			opt |= CD1400_COR4_PFO_NUL;
1925	}
1926#else
1927	opt |= CD1400_COR4_PFO_EXCEPTION;
1928#endif
1929	cd_outb(iobase, CD1400_COR4, com->cy_align, opt);
1930
1931	/*
1932	 * set channel option register 5 -
1933	 */
1934	opt = 0;
1935	if (iflag & ISTRIP)
1936		opt |= CD1400_COR5_ISTRIP;
1937	if (t->c_iflag & IEXTEN)
1938		/* enable LNEXT (e.g. ctrl-v quoting) handling */
1939		opt |= CD1400_COR5_LNEXT;
1940#ifdef Smarts
1941	if (t->c_oflag & ONLCR)
1942		opt |= CD1400_COR5_ONLCR;
1943	if (t->c_oflag & OCRNL)
1944		opt |= CD1400_COR5_OCRNL;
1945#endif
1946	cd_outb(iobase, CD1400_COR5, com->cy_align, opt);
1947
1948	/*
1949	 * We always generate modem status change interrupts for CD changes.
1950	 * Among other things, this is necessary to track TS_CARR_ON for
1951	 * pstat to print even when the driver doesn't care.  CD changes
1952	 * should be rare so interrupts for them are not worth extra code to
1953	 * avoid.  We avoid interrupts for other modem status changes (except
1954	 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is
1955	 * simplest and best.
1956	 */
1957
1958	/*
1959	 * set modem change option register 1
1960	 *	generate modem interrupts on which 1 -> 0 input transitions
1961	 *	also controls auto-DTR output flow-control, which we don't use
1962	 */
1963	opt = CD1400_MCOR1_CDzd;
1964#ifdef SOFT_CTS_OFLOW
1965	if (cflag & CCTS_OFLOW)
1966		opt |= CD1400_MCOR1_CTSzd;
1967#endif
1968	cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt);
1969
1970	/*
1971	 * set modem change option register 2
1972	 *	generate modem interrupts on specific 0 -> 1 input transitions
1973	 */
1974	opt = CD1400_MCOR2_CDod;
1975#ifdef SOFT_CTS_OFLOW
1976	if (cflag & CCTS_OFLOW)
1977		opt |= CD1400_MCOR2_CTSod;
1978#endif
1979	cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt);
1980
1981	/*
1982	 * XXX should have done this long ago, but there is too much state
1983	 * to change all atomically.
1984	 */
1985	disable_intr();
1986
1987	com->state &= ~CS_TTGO;
1988	if (!(tp->t_state & TS_TTSTOP))
1989		com->state |= CS_TTGO;
1990	if (cflag & CRTS_IFLOW) {
1991		com->state |= CS_RTS_IFLOW;
1992		/*
1993		 * If CS_RTS_IFLOW just changed from off to on, the change
1994		 * needs to be propagated to MCR_RTS.  This isn't urgent,
1995		 * so do it later by calling comstart() instead of repeating
1996		 * a lot of code from comstart() here.
1997		 */
1998	} else if (com->state & CS_RTS_IFLOW) {
1999		com->state &= ~CS_RTS_IFLOW;
2000		/*
2001		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
2002		 * on here, since comstart() won't do it later.
2003		 */
2004#if 0
2005		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2006#else
2007		cd_outb(iobase, CD1400_MSVR1, com->cy_align,
2008			com->mcr_image |= MCR_RTS);
2009#endif
2010	}
2011
2012	/*
2013	 * Set up state to handle output flow control.
2014	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2015	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2016	 */
2017	com->state |= CS_ODEVREADY;
2018#ifdef SOFT_CTS_OFLOW
2019	com->state &= ~CS_CTS_OFLOW;
2020	if (cflag & CCTS_OFLOW) {
2021		com->state |= CS_CTS_OFLOW;
2022		if (!(com->last_modem_status & MSR_CTS))
2023			com->state &= ~CS_ODEVREADY;
2024	}
2025#endif
2026	/* XXX shouldn't call functions while intrs are disabled. */
2027	disc_optim(tp, t, com);
2028#if 0
2029	/*
2030	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
2031	 * unconditionally, but that defeated the careful discarding of
2032	 * stale input in sioopen().
2033	 */
2034	if (com->state >= (CS_BUSY | CS_TTGO))
2035		siointr1(com);
2036#endif
2037	if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2038		if (!(com->intr_enable & CD1400_SRER_TXRDY))
2039			cd_outb(iobase, CD1400_SRER, com->cy_align,
2040				com->intr_enable |= CD1400_SRER_TXRDY);
2041	} else {
2042		if (com->intr_enable & CD1400_SRER_TXRDY)
2043			cd_outb(iobase, CD1400_SRER, com->cy_align,
2044				com->intr_enable &= ~CD1400_SRER_TXRDY);
2045	}
2046
2047	enable_intr();
2048	splx(s);
2049	comstart(tp);
2050	return (0);
2051}
2052
2053static void
2054comstart(tp)
2055	struct tty	*tp;
2056{
2057	struct com_s	*com;
2058	cy_addr		iobase;
2059	int		s;
2060#ifdef CyDebug
2061	bool_t		started;
2062#endif
2063	int		unit;
2064
2065	unit = DEV_TO_UNIT(tp->t_dev);
2066	com = com_addr(unit);
2067	iobase = com->iobase;
2068	s = spltty();
2069
2070#ifdef CyDebug
2071	++com->start_count;
2072	started = FALSE;
2073#endif
2074
2075	disable_intr();
2076	cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
2077	if (tp->t_state & TS_TTSTOP) {
2078		com->state &= ~CS_TTGO;
2079		if (com->intr_enable & CD1400_SRER_TXRDY)
2080			cd_outb(iobase, CD1400_SRER, com->cy_align,
2081				com->intr_enable &= ~CD1400_SRER_TXRDY);
2082	} else {
2083		com->state |= CS_TTGO;
2084		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
2085		    && !(com->intr_enable & CD1400_SRER_TXRDY))
2086			cd_outb(iobase, CD1400_SRER, com->cy_align,
2087				com->intr_enable |= CD1400_SRER_TXRDY);
2088	}
2089	if (tp->t_state & TS_TBLOCK) {
2090		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2091#if 0
2092			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2093#else
2094			cd_outb(iobase, CD1400_MSVR1, com->cy_align,
2095				com->mcr_image &= ~MCR_RTS);
2096#endif
2097	} else {
2098		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2099		    && com->state & CS_RTS_IFLOW)
2100#if 0
2101			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2102#else
2103			cd_outb(iobase, CD1400_MSVR1, com->cy_align,
2104				com->mcr_image |= MCR_RTS);
2105#endif
2106	}
2107	enable_intr();
2108	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2109		ttwwakeup(tp);
2110		splx(s);
2111		return;
2112	}
2113	if (tp->t_outq.c_cc != 0) {
2114		struct lbq	*qp;
2115		struct lbq	*next;
2116
2117		if (!com->obufs[0].l_queued) {
2118#ifdef CyDebug
2119			started = TRUE;
2120#endif
2121			com->obufs[0].l_tail
2122			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2123						  sizeof com->obuf1);
2124			com->obufs[0].l_next = NULL;
2125			com->obufs[0].l_queued = TRUE;
2126			disable_intr();
2127			if (com->state & CS_BUSY) {
2128				qp = com->obufq.l_next;
2129				while ((next = qp->l_next) != NULL)
2130					qp = next;
2131				qp->l_next = &com->obufs[0];
2132			} else {
2133				com->obufq.l_head = com->obufs[0].l_head;
2134				com->obufq.l_tail = com->obufs[0].l_tail;
2135				com->obufq.l_next = &com->obufs[0];
2136				com->state |= CS_BUSY;
2137				if (com->state >= (CS_BUSY | CS_TTGO
2138						   | CS_ODEVREADY))
2139					cd_outb(iobase, CD1400_SRER,
2140						com->cy_align,
2141						com->intr_enable
2142						|= CD1400_SRER_TXRDY);
2143			}
2144			enable_intr();
2145		}
2146		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2147#ifdef CyDebug
2148			started = TRUE;
2149#endif
2150			com->obufs[1].l_tail
2151			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2152						  sizeof com->obuf2);
2153			com->obufs[1].l_next = NULL;
2154			com->obufs[1].l_queued = TRUE;
2155			disable_intr();
2156			if (com->state & CS_BUSY) {
2157				qp = com->obufq.l_next;
2158				while ((next = qp->l_next) != NULL)
2159					qp = next;
2160				qp->l_next = &com->obufs[1];
2161			} else {
2162				com->obufq.l_head = com->obufs[1].l_head;
2163				com->obufq.l_tail = com->obufs[1].l_tail;
2164				com->obufq.l_next = &com->obufs[1];
2165				com->state |= CS_BUSY;
2166				if (com->state >= (CS_BUSY | CS_TTGO
2167						   | CS_ODEVREADY))
2168					cd_outb(iobase, CD1400_SRER,
2169						com->cy_align,
2170						com->intr_enable
2171						|= CD1400_SRER_TXRDY);
2172			}
2173			enable_intr();
2174		}
2175		tp->t_state |= TS_BUSY;
2176	}
2177#ifdef CyDebug
2178	if (started)
2179		++com->start_real;
2180#endif
2181#if 0
2182	disable_intr();
2183	if (com->state >= (CS_BUSY | CS_TTGO))
2184		siointr1(com);	/* fake interrupt to start output */
2185	enable_intr();
2186#endif
2187	ttwwakeup(tp);
2188	splx(s);
2189}
2190
2191static void
2192siostop(tp, rw)
2193	struct tty	*tp;
2194	int		rw;
2195{
2196	struct com_s	*com;
2197
2198	com = com_addr(DEV_TO_UNIT(tp->t_dev));
2199	disable_intr();
2200	if (rw & FWRITE) {
2201		com->obufs[0].l_queued = FALSE;
2202		com->obufs[1].l_queued = FALSE;
2203		if (com->state & CS_ODONE)
2204			com_events -= LOTS_OF_EVENTS;
2205		com->state &= ~(CS_ODONE | CS_BUSY);
2206		com->tp->t_state &= ~TS_BUSY;
2207	}
2208	if (rw & FREAD) {
2209		com_events -= (com->iptr - com->ibuf);
2210		com->iptr = com->ibuf;
2211	}
2212	enable_intr();
2213	comstart(tp);
2214
2215	/* XXX should clear h/w fifos too. */
2216}
2217
2218static struct tty *
2219siodevtotty(dev)
2220	dev_t	dev;
2221{
2222	int	mynor;
2223	int	unit;
2224
2225	mynor = minor(dev);
2226	if (mynor & CONTROL_MASK)
2227		return (NULL);
2228	unit = MINOR_TO_UNIT(mynor);
2229	if ((u_int) unit >= NSIO)
2230		return (NULL);
2231	return (&sio_tty[unit]);
2232}
2233
2234static int
2235commctl(com, bits, how)
2236	struct com_s	*com;
2237	int		bits;
2238	int		how;
2239{
2240	cy_addr	iobase;
2241	int	mcr;
2242	int	msr;
2243
2244	iobase = com->iobase;
2245	if (how == DMGET) {
2246		if (com->channel_control & CD1400_CCR_RCVEN)
2247			bits |= TIOCM_LE;
2248		mcr = com->mcr_image;
2249		if (mcr & MCR_DTR)
2250			bits |= TIOCM_DTR;
2251		if (mcr & MCR_RTS)
2252			/* XXX wired on for Cyclom-8Ys */
2253			bits |= TIOCM_RTS;
2254
2255		/*
2256		 * We must read the modem status from the hardware because
2257		 * we don't generate modem status change interrupts for all
2258		 * changes, so com->prev_modem_status is not guaranteed to
2259		 * be up to date.  This is safe, unlike for sio, because
2260		 * reading the status register doesn't clear pending modem
2261		 * status change interrupts.
2262		 */
2263		msr = cd_inb(iobase, CD1400_MSVR2, com->cy_align);
2264
2265		if (msr & MSR_CTS)
2266			bits |= TIOCM_CTS;
2267		if (msr & MSR_DCD)
2268			bits |= TIOCM_CD;
2269		if (msr & MSR_DSR)
2270			bits |= TIOCM_DSR;
2271		if (msr & MSR_RI)
2272			/* XXX not connected except for Cyclom-16Y? */
2273			bits |= TIOCM_RI;
2274		return (bits);
2275	}
2276	mcr = 0;
2277	if (bits & TIOCM_DTR)
2278		mcr |= MCR_DTR;
2279	if (bits & TIOCM_RTS)
2280		mcr |= MCR_RTS;
2281	disable_intr();
2282	switch (how) {
2283	case DMSET:
2284		com->mcr_image = mcr;
2285		cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
2286		cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
2287		break;
2288	case DMBIS:
2289		com->mcr_image = mcr = com->mcr_image | mcr;
2290		cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
2291		cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
2292		break;
2293	case DMBIC:
2294		com->mcr_image = mcr = com->mcr_image & ~mcr;
2295		cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
2296		cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
2297		break;
2298	}
2299	enable_intr();
2300	return (0);
2301}
2302
2303static void
2304siosettimeout()
2305{
2306	struct com_s	*com;
2307	bool_t		someopen;
2308	int		unit;
2309
2310	/*
2311	 * Set our timeout period to 1 second if no polled devices are open.
2312	 * Otherwise set it to max(1/200, 1/hz).
2313	 * Enable timeouts iff some device is open.
2314	 */
2315	untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2316	sio_timeout = hz;
2317	someopen = FALSE;
2318	for (unit = 0; unit < NSIO; ++unit) {
2319		com = com_addr(unit);
2320		if (com != NULL && com->tp != NULL
2321		    && com->tp->t_state & TS_ISOPEN) {
2322			someopen = TRUE;
2323#if 0
2324			if (com->poll || com->poll_output) {
2325				sio_timeout = hz > 200 ? hz / 200 : 1;
2326				break;
2327			}
2328#endif
2329		}
2330	}
2331	if (someopen) {
2332		sio_timeouts_until_log = hz / sio_timeout;
2333		sio_timeout_handle = timeout(comwakeup, (void *)NULL,
2334					     sio_timeout);
2335	} else {
2336		/* Flush error messages, if any. */
2337		sio_timeouts_until_log = 1;
2338		comwakeup((void *)NULL);
2339		untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2340	}
2341}
2342
2343static void
2344comwakeup(chan)
2345	void	*chan;
2346{
2347	struct com_s	*com;
2348	int		unit;
2349
2350	sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
2351
2352#if 0
2353	/*
2354	 * Recover from lost output interrupts.
2355	 * Poll any lines that don't use interrupts.
2356	 */
2357	for (unit = 0; unit < NSIO; ++unit) {
2358		com = com_addr(unit);
2359		if (com != NULL
2360		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2361			disable_intr();
2362			siointr1(com);
2363			enable_intr();
2364		}
2365	}
2366#endif
2367
2368	/*
2369	 * Check for and log errors, but not too often.
2370	 */
2371	if (--sio_timeouts_until_log > 0)
2372		return;
2373	sio_timeouts_until_log = hz / sio_timeout;
2374	for (unit = 0; unit < NSIO; ++unit) {
2375		int	errnum;
2376
2377		com = com_addr(unit);
2378		if (com == NULL)
2379			continue;
2380		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2381			u_int	delta;
2382			u_long	total;
2383
2384			disable_intr();
2385			delta = com->delta_error_counts[errnum];
2386			com->delta_error_counts[errnum] = 0;
2387			enable_intr();
2388			if (delta == 0)
2389				continue;
2390			total = com->error_counts[errnum] += delta;
2391			log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
2392			    unit, delta, error_desc[errnum],
2393			    delta == 1 ? "" : "s", total);
2394		}
2395	}
2396}
2397
2398static void
2399disc_optim(tp, t, com)
2400	struct tty	*tp;
2401	struct termios	*t;
2402	struct com_s	*com;
2403{
2404#ifndef SOFT_HOTCHAR
2405	cy_addr	iobase;
2406	u_char	opt;
2407#endif
2408
2409	/*
2410	 * XXX can skip a lot more cases if Smarts.  Maybe
2411	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
2412	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2413	 */
2414	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2415	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2416	    && (!(t->c_iflag & PARMRK)
2417		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2418	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2419	    && linesw[tp->t_line].l_rint == ttyinput)
2420		tp->t_state |= TS_CAN_BYPASS_L_RINT;
2421	else
2422		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2423	/*
2424	 * Prepare to reduce input latency for packet
2425	 * discplines with a end of packet character.
2426	 */
2427	if (tp->t_line == SLIPDISC)
2428		com->hotchar = 0xc0;
2429	else if (tp->t_line == PPPDISC)
2430		com->hotchar = 0x7e;
2431	else
2432		com->hotchar = 0;
2433#ifndef SOFT_HOTCHAR
2434	iobase = com->iobase;
2435	cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN);
2436	opt = com->cor[2] & ~CD1400_COR3_SCD34;
2437	if (com->hotchar != 0) {
2438		cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar);
2439		cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar);
2440		opt |= CD1400_COR3_SCD34;
2441	}
2442	if (opt != com->cor[2]) {
2443		cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
2444		cd1400_channel_cmd(com->iobase,
2445				   CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3,
2446				   com->cy_align);
2447	}
2448#endif
2449}
2450
2451#ifdef Smarts
2452/* standard line discipline input routine */
2453int
2454cyinput(c, tp)
2455	int		c;
2456	struct tty	*tp;
2457{
2458	/* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
2459	 * bits, as they are done by the CD1400.  Hardly worth the effort,
2460	 * given that high-throughput sessions are raw anyhow.
2461	 */
2462}
2463#endif /* Smarts */
2464
2465static int
2466comspeed(speed, prescaler_io)
2467	speed_t	speed;
2468	int	*prescaler_io;
2469{
2470	int	actual;
2471	int	error;
2472	int	divider;
2473	int	prescaler;
2474	int	prescaler_unit;
2475
2476	if (speed == 0)
2477		return (0);
2478	if (speed < 0 || speed > 150000)
2479		return (-1);
2480
2481	/* determine which prescaler to use */
2482	for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
2483		prescaler_unit--, prescaler >>= 2) {
2484		if (CY_CLOCK / prescaler / speed > 63)
2485			break;
2486	}
2487
2488	divider = (CY_CLOCK / prescaler * 2 / speed + 1) / 2; /* round off */
2489	if (divider > 255)
2490		divider = 255;
2491	actual = CY_CLOCK/prescaler/divider;
2492	error = ((actual - speed) * 2000 / speed + 1) / 2;	/* percentage */
2493
2494	/* 3.0% max error tolerance */
2495	if (error < -30 || error > 30)
2496		return (-1);
2497
2498#if 0
2499	printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
2500	printf("divider = %d (%x)\n", divider, divider);
2501	printf("actual = %d\n", actual);
2502	printf("error = %d\n", error);
2503#endif
2504
2505	*prescaler_io = prescaler_unit;
2506	return (divider);
2507}
2508
2509static void
2510cd1400_channel_cmd(iobase, cmd, cy_align)
2511	cy_addr	iobase;
2512	int	cmd;
2513	int	cy_align;
2514{
2515	/* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
2516	   as the card is probed every round?  Replaced delaycount with 8k.
2517	   Either delaycount has to be implemented in FreeBSD or more sensible
2518	   way of doing these should be implemented.  DELAY isn't enough here.
2519	   */
2520	u_int	maxwait = 5 * 8 * 1024;	/* approx. 5 ms */
2521
2522	/* wait for processing of previous command to complete */
2523	while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--)
2524		;
2525
2526	if (!maxwait)
2527		log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
2528		    5 * 8 * 1024);
2529
2530	cd_outb(iobase, CD1400_CCR, cy_align, cmd);
2531}
2532
2533#ifdef CyDebug
2534/* useful in ddb */
2535void
2536cystatus(unit)
2537	int	unit;
2538{
2539	struct com_s	*com;
2540	cy_addr		iobase;
2541	u_int		ocount;
2542	struct tty	*tp;
2543
2544	com = com_addr(unit);
2545	printf("info for channel %d\n", unit);
2546	printf("------------------\n");
2547	printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
2548	printf("calls to upper layer:\t\t%d\n", cy_timeouts);
2549	if (com == NULL)
2550		return;
2551	iobase = com->iobase;
2552	printf("\n");
2553	printf("cd1400 base address:\\tt%p\n", iobase);
2554	cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
2555	printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
2556	printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
2557	       com->cor[0], com->cor[1], com->cor[2]);
2558	printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
2559	       cd_inb(iobase, CD1400_SRER, com->cy_align), com->intr_enable);
2560	printf("service request register:\t0x%02x\n",
2561	       cd_inb(iobase, CD1400_SVRR, com->cy_align));
2562	printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
2563	       cd_inb(iobase, CD1400_MSVR2, com->cy_align),
2564	       com->prev_modem_status);
2565	printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
2566	       cd_inb(iobase, CD1400_RIR, com->cy_align),
2567	       cd_inb(iobase, CD1400_TIR, com->cy_align),
2568	       cd_inb(iobase, CD1400_MIR, com->cy_align));
2569	printf("\n");
2570	printf("com state:\t\t\t0x%02x\n", com->state);
2571	printf("calls to comstart():\t\t%d (%d useful)\n",
2572	       com->start_count, com->start_real);
2573	printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
2574	ocount = 0;
2575	if (com->obufs[0].l_queued)
2576		ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
2577	if (com->obufs[1].l_queued)
2578		ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
2579	printf("tx buffer chars:\t\t%u\n", ocount);
2580	printf("received chars:\t\t\t%d\n", com->bytes_in);
2581	printf("received exceptions:\t\t%d\n", com->recv_exception);
2582	printf("modem signal deltas:\t\t%d\n", com->mdm);
2583	printf("transmitted chars:\t\t%d\n", com->bytes_out);
2584	printf("\n");
2585	tp = com->tp;
2586	if (tp != NULL) {
2587		printf("tty state:\t\t\t0x%08x\n", tp->t_state);
2588		printf(
2589		"upper layer queue lengths:\t%d raw, %d canon, %d output\n",
2590		       tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
2591	} else
2592		printf("tty state:\t\t\tclosed\n");
2593}
2594#endif /* CyDebug */
2595