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