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