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