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