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