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