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