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