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