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