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