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