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