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