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