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