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