sio.c revision 56793
1228753Smm/*-
2231200Smm * Copyright (c) 1991 The Regents of the University of California.
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm * 3. All advertising materials mentioning features or use of this software
14228753Smm *    must display the following acknowledgement:
15228753Smm *	This product includes software developed by the University of
16228753Smm *	California, Berkeley and its contributors.
17228753Smm * 4. Neither the name of the University nor the names of its contributors
18228753Smm *    may be used to endorse or promote products derived from this software
19228753Smm *    without specific prior written permission.
20228753Smm *
21228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24228753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31228753Smm * SUCH DAMAGE.
32228753Smm *
33228753Smm * $FreeBSD: head/sys/pc98/cbus/sio.c 56793 2000-01-29 04:47:22Z kato $
34228753Smm *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
35228753Smm *	from: i386/isa sio.c,v 1.234
36228753Smm */
37228753Smm
38228753Smm#include "opt_comconsole.h"
39228753Smm#include "opt_compat.h"
40228753Smm#include "opt_ddb.h"
41228753Smm#include "opt_sio.h"
42228753Smm#include "card.h"
43228753Smm#include "sio.h"
44228753Smm
45228753Smm/*
46228753Smm * Serial driver, based on 386BSD-0.1 com driver.
47228753Smm * Mostly rewritten to use pseudo-DMA.
48228753Smm * Works for National Semiconductor NS8250-NS16550AF UARTs.
49228753Smm * COM driver, based on HP dca driver.
50228753Smm *
51228753Smm * Changes for PC-Card integration:
52228753Smm *	- Added PC-Card driver table and handlers
53228753Smm */
54228753Smm/*===============================================================
55228753Smm * 386BSD(98),FreeBSD-1.1x(98) com driver.
56228753Smm * -----
57228753Smm * modified for PC9801 by M.Ishii
58228753Smm *			Kyoto University Microcomputer Club (KMC)
59228753Smm * Chou "TEFUTEFU" Hirotomi
60228753Smm *			Kyoto Univ.  the faculty of medicine
61228753Smm *===============================================================
62228753Smm * FreeBSD-2.0.1(98) sio driver.
63231200Smm * -----
64231200Smm * modified for pc98 Internal i8251 and MICRO CORE MC16550II
65231200Smm *			T.Koike(hfc01340@niftyserve.or.jp)
66231200Smm * implement kernel device configuration
67231200Smm *			aizu@orient.center.nitech.ac.jp
68231200Smm *
69231200Smm * Notes.
70228753Smm * -----
71228753Smm *  PC98 localization based on 386BSD(98) com driver. Using its PC98 local
72231200Smm *  functions.
73231200Smm *  This driver is under debugging,has bugs.
74231200Smm *
75231200Smm * 1) config
76231200Smm *  options COM_MULTIPORT  #if using MC16550II
77231200Smm *  device sio0 at nec? port 0x30  tty irq 4             #internal
78231200Smm *  device sio1 at nec? port 0xd2  tty irq 5 flags 0x101 #mc1
79231200Smm *  device sio2 at nec? port 0x8d2 tty flags 0x101       #mc2
80231200Smm *                         # ~~~~~iobase        ~~multi port flag
81228753Smm *                         #                   ~  master device is sio1
82228753Smm * 2) device
83228753Smm *  cd /dev; MAKEDEV ttyd0 ttyd1 ..
84228753Smm * 3) /etc/rc.serial
85228753Smm *  57600bps is too fast for sio0(internal8251)
86228753Smm *  my ex.
87228753Smm *    #set default speed 9600
88228753Smm *    modem()
89228753Smm *       :
90228753Smm *      stty </dev/ttyid$i crtscts 9600
91228753Smm *       :                 #       ~~~~ default speed(can change after init.)
92228753Smm *    modem 0 1 2
93228753Smm * 4) COMCONSOLE
94228753Smm *  not changed.
95228753Smm * 5) PC9861K,PIO9032B,B98_01
96228753Smm *  not tested.
97228753Smm */
98228753Smm/*
99228753Smm * modified for AIWA B98-01
100228753Smm * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp>  last update: 15 Sep.1995
101228753Smm *
102228753Smm * How to configure...
103228753Smm *   # options COM_MULTIPORT         # support for MICROCORE MC16550II
104228753Smm *      ... comment-out this line, which will conflict with B98_01.
105228753Smm *   options "B98_01"                # support for AIWA B98-01
106228753Smm *   device  sio1 at nec? port 0x00d1 tty irq ?
107228753Smm *   device  sio2 at nec? port 0x00d5 tty irq ?
108228753Smm *      ... you can leave these lines `irq ?', irq will be autodetected.
109228753Smm */
110228753Smm/*
111228753Smm * Modified by Y.Takahashi of Kogakuin University.
112231200Smm */
113231200Smm/*
114231200Smm * modified for 8251(FIFO) by Seigo TANIMURA <tanimura@FreeBSD.org>
115231200Smm */
116228753Smm
117231200Smm#ifdef PC98
118231200Smm#define COM_IF_INTERNAL		0x00
119228753Smm#define COM_IF_PC9861K_1	0x01
120231200Smm#define COM_IF_PC9861K_2	0x02
121228753Smm#define COM_IF_IND_SS_1		0x03
122231200Smm#define COM_IF_IND_SS_2		0x04
123231200Smm#define COM_IF_PIO9032B_1	0x05
124231200Smm#define COM_IF_PIO9032B_2	0x06
125231200Smm#define COM_IF_B98_01_1		0x07
126231200Smm#define COM_IF_B98_01_2		0x08
127231200Smm#define COM_IF_END1		COM_IF_B98_01_2
128231200Smm#define COM_IF_RSA98		0x10	/* same as COM_IF_NS16550 */
129228753Smm#define COM_IF_NS16550		0x11
130231200Smm#define COM_IF_SECOND_CCU	0x12	/* same as COM_IF_NS16550 */
131228753Smm#define COM_IF_MC16550II	0x13
132231200Smm#define COM_IF_MCRS98		0x14	/* same as COM_IF_MC16550II */
133231200Smm#define COM_IF_RSB3000		0x15
134231200Smm#define COM_IF_RSB384		0x16
135231200Smm#define COM_IF_MODEM_CARD	0x17	/* same as COM_IF_NS16550 */
136228753Smm#define COM_IF_RSA98III		0x18
137228753Smm#define COM_IF_ESP98		0x19
138228753Smm#define COM_IF_END2		COM_IF_ESP98
139228753Smm#endif /* PC98 */
140228753Smm
141228753Smm#include <sys/param.h>
142228753Smm#include <sys/systm.h>
143228753Smm#include <sys/reboot.h>
144228753Smm#include <sys/malloc.h>
145228753Smm#include <sys/tty.h>
146228753Smm#include <sys/proc.h>
147228753Smm#include <sys/module.h>
148228753Smm#include <sys/conf.h>
149228753Smm#include <sys/dkstat.h>
150228753Smm#include <sys/fcntl.h>
151228753Smm#include <sys/interrupt.h>
152231200Smm#include <sys/kernel.h>
153228753Smm#include <sys/syslog.h>
154231200Smm#include <sys/sysctl.h>
155228753Smm#include <sys/bus.h>
156231200Smm#include <machine/bus.h>
157231200Smm#include <sys/rman.h>
158231200Smm#include <sys/timepps.h>
159231200Smm
160231200Smm#ifdef PC98
161231200Smm#include <pc98/pc98/pc98.h>
162231200Smm#include <pc98/pc98/pc98_machdep.h>
163228753Smm#include <i386/isa/ic/i8251.h>
164231200Smm#else
165228753Smm#include <isa/isareg.h>
166231200Smm#endif
167231200Smm#include <isa/isavar.h>
168231200Smm#include <machine/lock.h>
169231200Smm
170228753Smm#include <machine/clock.h>
171228753Smm#include <machine/ipl.h>
172228753Smm#ifndef SMP
173228753Smm#include <machine/lock.h>
174228753Smm#endif
175228753Smm#include <machine/resource.h>
176228753Smm
177228753Smm#include <isa/sioreg.h>
178228753Smm
179228753Smm#ifdef COM_ESP
180228753Smm#include <i386/isa/ic/esp.h>
181228753Smm#endif
182228753Smm#include <i386/isa/ic/ns16550.h>
183228753Smm#ifdef PC98
184228753Smm#include <i386/isa/ic/rsa.h>
185228753Smm#endif
186228753Smm
187228753Smm#ifndef __i386__
188231200Smm#define disable_intr()
189231200Smm#define enable_intr()
190231200Smm#endif
191231200Smm
192231200Smm#ifdef SMP
193231200Smm#define disable_intr()	COM_DISABLE_INTR()
194231200Smm#define enable_intr()	COM_ENABLE_INTR()
195231200Smm#endif /* SMP */
196231200Smm
197231200Smm#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
198231200Smm
199231200Smm#define	CALLOUT_MASK		0x80
200231200Smm#define	CONTROL_MASK		0x60
201231200Smm#define	CONTROL_INIT_STATE	0x20
202231200Smm#define	CONTROL_LOCK_STATE	0x40
203231200Smm#define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
204231200Smm#define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
205231200Smm#define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)
206231200Smm
207231200Smm#ifdef COM_MULTIPORT
208231200Smm/* checks in flags for multiport and which is multiport "master chip"
209231200Smm * for a given card
210231200Smm */
211231200Smm#define	COM_ISMULTIPORT(flags)	((flags) & 0x01)
212231200Smm#define	COM_MPMASTER(flags)	(((flags) >> 8) & 0x0ff)
213231200Smm#define	COM_NOTAST4(flags)	((flags) & 0x04)
214231200Smm#endif /* COM_MULTIPORT */
215231200Smm
216231200Smm#define	COM_CONSOLE(flags)	((flags) & 0x10)
217231200Smm#define	COM_FORCECONSOLE(flags)	((flags) & 0x20)
218231200Smm#define	COM_LLCONSOLE(flags)	((flags) & 0x40)
219231200Smm#define	COM_DEBUGGER(flags)	((flags) & 0x80)
220231200Smm#define	COM_LOSESOUTINTS(flags)	((flags) & 0x08)
221231200Smm#define	COM_NOFIFO(flags)		((flags) & 0x02)
222231200Smm#define COM_ST16650A(flags)	((flags) & 0x20000)
223228753Smm#define COM_C_NOPROBE		(0x40000)
224228753Smm#define COM_NOPROBE(flags)	((flags) & COM_C_NOPROBE)
225228753Smm#define COM_C_IIR_TXRDYBUG	(0x80000)
226228753Smm#define COM_IIR_TXRDYBUG(flags)	((flags) & COM_C_IIR_TXRDYBUG)
227228753Smm#define	COM_FIFOSIZE(flags)	(((flags) & 0xff000000) >> 24)
228228753Smm
229228753Smm#ifdef PC98
230228753Smm#define	com_emr		com_msr	/* Extension mode register for RSB-2000/3000 */
231228753Smm#else
232228753Smm#define	com_scr		7	/* scratch register for 16450-16550 (R/W) */
233228753Smm#endif
234228753Smm
235228753Smm/*
236228753Smm * com state bits.
237228753Smm * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
238228753Smm * than the other bits so that they can be tested as a group without masking
239228753Smm * off the low bits.
240228753Smm *
241228753Smm * The following com and tty flags correspond closely:
242231200Smm *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and
243228753Smm *				   comstop())
244228753Smm *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart())
245231200Smm *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam())
246228753Smm *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam())
247228753Smm * TS_FLUSH is not used.
248228753Smm * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
249228753Smm * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
250228753Smm */
251228753Smm#define	CS_BUSY		0x80	/* output in progress */
252228753Smm#define	CS_TTGO		0x40	/* output not stopped by XOFF */
253228753Smm#define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */
254228753Smm#define	CS_CHECKMSR	1	/* check of MSR scheduled */
255228753Smm#define	CS_CTS_OFLOW	2	/* use CTS output flow control */
256228753Smm#define	CS_DTR_OFF	0x10	/* DTR held off */
257228753Smm#define	CS_ODONE	4	/* output completed */
258228753Smm#define	CS_RTS_IFLOW	8	/* use RTS input flow control */
259228753Smm#define	CSE_BUSYCHECK	1	/* siobusycheck() scheduled */
260228753Smm
261228753Smmstatic	char const * const	error_desc[] = {
262228753Smm#define	CE_OVERRUN			0
263228753Smm	"silo overflow",
264228753Smm#define	CE_INTERRUPT_BUF_OVERFLOW	1
265228753Smm	"interrupt-level buffer overflow",
266228753Smm#define	CE_TTY_BUF_OVERFLOW		2
267228753Smm	"tty-level buffer overflow",
268228753Smm};
269228753Smm
270228753Smm#define	CE_NTYPES			3
271228753Smm#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
272228753Smm
273228753Smm/* types.  XXX - should be elsewhere */
274228753Smmtypedef u_int	Port_t;		/* hardware port */
275228753Smmtypedef u_char	bool_t;		/* boolean */
276228753Smm
277228753Smm/* queue of linear buffers */
278228753Smmstruct lbq {
279228753Smm	u_char	*l_head;	/* next char to process */
280228753Smm	u_char	*l_tail;	/* one past the last char to process */
281228753Smm	struct lbq *l_next;	/* next in queue */
282228753Smm	bool_t	l_queued;	/* nonzero if queued */
283228753Smm};
284228753Smm
285228753Smm/* com device structure */
286228753Smmstruct com_s {
287228753Smm	u_int	flags;		/* Copy isa device flags */
288228753Smm	u_char	state;		/* miscellaneous flag bits */
289228753Smm	bool_t  active_out;	/* nonzero if the callout device is open */
290228753Smm	u_char	cfcr_image;	/* copy of value written to CFCR */
291228753Smm#ifdef COM_ESP
292228753Smm	bool_t	esp;		/* is this unit a hayes esp board? */
293228753Smm#endif
294228753Smm	u_char	extra_state;	/* more flag bits, separate for order trick */
295228753Smm	u_char	fifo_image;	/* copy of value written to FIFO */
296228753Smm	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
297228753Smm	bool_t	st16650a;	/* Is a Startech 16650A or RTS/CTS compat */
298228753Smm	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
299228753Smm	u_char	mcr_image;	/* copy of value written to MCR */
300228753Smm#ifdef COM_MULTIPORT
301228753Smm	bool_t	multiport;	/* is this unit part of a multiport device? */
302228753Smm#endif /* COM_MULTIPORT */
303228753Smm	bool_t	no_irq;		/* nonzero if irq is not attached */
304228753Smm	bool_t  gone;		/* hardware disappeared */
305228753Smm	bool_t	poll;		/* nonzero if polling is required */
306228753Smm	bool_t	poll_output;	/* nonzero if polling for output is required */
307228753Smm	int	unit;		/* unit	number */
308228753Smm	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
309228753Smm	u_int	tx_fifo_size;
310228753Smm	u_int	wopeners;	/* # processes waiting for DCD in open() */
311228753Smm
312228753Smm	/*
313228753Smm	 * The high level of the driver never reads status registers directly
314228753Smm	 * because there would be too many side effects to handle conveniently.
315228753Smm	 * Instead, it reads copies of the registers stored here by the
316228753Smm	 * interrupt handler.
317228753Smm	 */
318228753Smm	u_char	last_modem_status;	/* last MSR read by intr handler */
319228753Smm	u_char	prev_modem_status;	/* last MSR handled by high level */
320228753Smm
321228753Smm	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
322228753Smm	u_char	*ibuf;		/* start of input buffer */
323228753Smm	u_char	*ibufend;	/* end of input buffer */
324228753Smm	u_char	*ibufold;	/* old input buffer, to be freed */
325228753Smm	u_char	*ihighwater;	/* threshold in input buffer */
326228753Smm	u_char	*iptr;		/* next free spot in input buffer */
327228753Smm	int	ibufsize;	/* size of ibuf (not include error bytes) */
328228753Smm	int	ierroff;	/* offset of error bytes in ibuf */
329228753Smm
330228753Smm	struct lbq	obufq;	/* head of queue of output buffers */
331228753Smm	struct lbq	obufs[2];	/* output buffers */
332228753Smm
333228753Smm#ifdef PC98
334228753Smm	Port_t	cmd_port;
335228753Smm	Port_t	sts_port;
336228753Smm	Port_t	in_modem_port;
337228753Smm	Port_t	intr_ctrl_port;
338228753Smm	int	intr_enable;
339228753Smm	int	pc98_prev_modem_status;
340228753Smm	int	pc98_modem_delta;
341228753Smm	int	modem_car_chg_timer;
342228753Smm	int	pc98_prev_siocmd;
343228753Smm	int	pc98_prev_siomod;
344228753Smm	int	modem_checking;
345228753Smm	int	pc98_if_type;
346228753Smm
347228753Smm	bool_t	pc98_8251fifo;
348228753Smm	bool_t	pc98_8251fifo_enable;
349228753Smm#endif /* PC98 */
350228753Smm	Port_t	data_port;	/* i/o ports */
351228753Smm#ifdef COM_ESP
352228753Smm	Port_t	esp_port;
353228753Smm#endif
354228753Smm	Port_t	int_id_port;
355228753Smm	Port_t	iobase;
356228753Smm#ifdef PC98
357228753Smm	Port_t	rsabase;	/* iobase address of a I/O-DATA RSA board */
358228753Smm#endif
359228753Smm	Port_t	modem_ctl_port;
360228753Smm	Port_t	line_status_port;
361228753Smm	Port_t	modem_status_port;
362228753Smm	Port_t	intr_ctl_port;	/* Ports of IIR register */
363228753Smm
364228753Smm	struct tty	*tp;	/* cross reference */
365228753Smm
366228753Smm	/* Initial state. */
367231200Smm	struct termios	it_in;	/* should be in struct tty */
368231200Smm	struct termios	it_out;
369231200Smm
370231200Smm	/* Lock state. */
371231200Smm	struct termios	lt_in;	/* should be in struct tty */
372231200Smm	struct termios	lt_out;
373231200Smm
374231200Smm	bool_t	do_timestamp;
375231200Smm	bool_t	do_dcd_timestamp;
376231200Smm	struct timeval	timestamp;
377231200Smm	struct timeval	dcd_timestamp;
378231200Smm	struct	pps_state pps;
379231200Smm
380231200Smm	u_long	bytes_in;	/* statistics */
381231200Smm	u_long	bytes_out;
382231200Smm	u_int	delta_error_counts[CE_NTYPES];
383231200Smm	u_long	error_counts[CE_NTYPES];
384231200Smm
385231200Smm	struct resource *irqres;
386231200Smm	struct resource *ioportres;
387231200Smm	void *cookie;
388231200Smm
389231200Smm	/*
390231200Smm	 * Data area for output buffers.  Someday we should build the output
391231200Smm	 * buffer queue without copying data.
392231200Smm	 */
393231200Smm#ifdef PC98
394231200Smm	int	obufsize;
395231200Smm 	u_char	*obuf1;
396231200Smm 	u_char	*obuf2;
397231200Smm#else
398231200Smm	u_char	obuf1[256];
399231200Smm	u_char	obuf2[256];
400231200Smm#endif
401231200Smm};
402231200Smm
403231200Smm#ifdef COM_ESP
404231200Smmstatic	int	espattach	__P((struct com_s *com, Port_t esp_port));
405231200Smm#endif
406231200Smmstatic	int	sioattach	__P((device_t dev));
407231200Smmstatic	int	sio_isa_attach	__P((device_t dev));
408231200Smm
409231200Smmstatic	timeout_t siobusycheck;
410228753Smmstatic	timeout_t siodtrwakeup;
411228753Smmstatic	void	comhardclose	__P((struct com_s *com));
412228753Smmstatic	void	sioinput	__P((struct com_s *com));
413228753Smmstatic	void	siointr1	__P((struct com_s *com));
414228753Smmstatic	void	siointr		__P((void *arg));
415228753Smmstatic	int	commctl		__P((struct com_s *com, int bits, int how));
416228753Smmstatic	int	comparam	__P((struct tty *tp, struct termios *t));
417228753Smmstatic	swihand_t siopoll;
418228753Smmstatic	int	sioprobe	__P((device_t dev));
419228753Smmstatic	int	sio_isa_probe	__P((device_t dev));
420228753Smmstatic	void	siosettimeout	__P((void));
421228753Smmstatic	int	siosetwater	__P((struct com_s *com, speed_t speed));
422228753Smmstatic	void	comstart	__P((struct tty *tp));
423228753Smmstatic	void	comstop		__P((struct tty *tp, int rw));
424228753Smmstatic	timeout_t comwakeup;
425228753Smmstatic	void	disc_optim	__P((struct tty	*tp, struct termios *t,
426228753Smm				     struct com_s *com));
427228753Smm
428228753Smm#if NCARD > 0
429228753Smmstatic	int	sio_pccard_attach __P((device_t dev));
430228753Smmstatic	int	sio_pccard_detach __P((device_t dev));
431231200Smmstatic	int	sio_pccard_probe __P((device_t dev));
432231200Smm#endif /* NCARD > 0 */
433231200Smm
434231200Smmstatic char driver_name[] = "sio";
435231200Smm
436231200Smm/* table and macro for fast conversion from a unit number to its com struct */
437231200Smmstatic	devclass_t	sio_devclass;
438231200Smm#define	com_addr(unit)	((struct com_s *) \
439228753Smm			 devclass_get_softc(sio_devclass, unit))
440231200Smm
441231200Smmstatic device_method_t sio_isa_methods[] = {
442231200Smm	/* Device interface */
443231200Smm	DEVMETHOD(device_probe,		sio_isa_probe),
444231200Smm	DEVMETHOD(device_attach,	sio_isa_attach),
445231200Smm
446231200Smm	{ 0, 0 }
447231200Smm};
448231200Smm
449231200Smmstatic driver_t sio_isa_driver = {
450231200Smm	driver_name,
451231200Smm	sio_isa_methods,
452231200Smm	sizeof(struct com_s),
453231200Smm};
454231200Smm
455231200Smm#if NCARD > 0
456231200Smmstatic device_method_t sio_pccard_methods[] = {
457231200Smm	/* Device interface */
458231200Smm	DEVMETHOD(device_probe,		sio_pccard_probe),
459231200Smm	DEVMETHOD(device_attach,	sio_pccard_attach),
460231200Smm	DEVMETHOD(device_detach,	sio_pccard_detach),
461231200Smm
462231200Smm	{ 0, 0 }
463231200Smm};
464231200Smm
465231200Smmstatic driver_t sio_pccard_driver = {
466231200Smm	driver_name,
467231200Smm	sio_pccard_methods,
468231200Smm	sizeof(struct com_s),
469231200Smm};
470231200Smm#endif (NCARD > 0)
471231200Smm
472231200Smmstatic	d_open_t	sioopen;
473231200Smmstatic	d_close_t	sioclose;
474231200Smmstatic	d_read_t	sioread;
475231200Smmstatic	d_write_t	siowrite;
476231200Smmstatic	d_ioctl_t	sioioctl;
477231200Smm
478231200Smm#define	CDEV_MAJOR	28
479231200Smmstatic struct cdevsw sio_cdevsw = {
480231200Smm	/* open */	sioopen,
481231200Smm	/* close */	sioclose,
482231200Smm	/* read */	sioread,
483231200Smm	/* write */	siowrite,
484231200Smm	/* ioctl */	sioioctl,
485231200Smm	/* poll */	ttypoll,
486231200Smm	/* mmap */	nommap,
487231200Smm	/* strategy */	nostrategy,
488228753Smm	/* name */	driver_name,
489228753Smm	/* maj */	CDEV_MAJOR,
490228753Smm	/* dump */	nodump,
491228753Smm	/* psize */	nopsize,
492228753Smm	/* flags */	D_TTY,
493228753Smm	/* bmaj */	-1
494228753Smm};
495228753Smm
496228753Smmint	comconsole = -1;
497228753Smmstatic	volatile speed_t	comdefaultrate = CONSPEED;
498228753Smm#ifdef __alpha__
499228753Smmstatic	volatile speed_t	gdbdefaultrate = CONSPEED;
500228753Smm#endif
501228753Smmstatic	u_int	com_events;	/* input chars + weighted output completions */
502228753Smmstatic	Port_t	siocniobase;
503228753Smmstatic	int	siocnunit;
504228753Smmstatic	Port_t	siogdbiobase;
505228753Smmstatic	int	siogdbunit = -1;
506228753Smmstatic	bool_t	sio_registered;
507228753Smmstatic	int	sio_timeout;
508228753Smmstatic	int	sio_timeouts_until_log;
509228753Smmstatic	struct	callout_handle sio_timeout_handle
510228753Smm    = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
511228753Smmstatic	int	sio_numunits;
512228753Smm
513228753Smm#ifdef PC98
514228753Smmstruct	siodev	{
515228753Smm	short	if_type;
516228753Smm	short	irq;
517228753Smm	Port_t	cmd, sts, ctrl, mod;
518228753Smm};
519228753Smmstatic	int	sysclock;
520231200Smm
521231200Smm#define	COM_INT_DISABLE		{int previpri; previpri=spltty();
522231200Smm#define	COM_INT_ENABLE		splx(previpri);}
523231200Smm#define IEN_TxFLAG		IEN_Tx
524231200Smm
525231200Smm#define COM_CARRIER_DETECT_EMULATE	0
526231200Smm#define	PC98_CHECK_MODEM_INTERVAL	(hz/10)
527231200Smm#define DCD_OFF_TOLERANCE		2
528231200Smm#define DCD_ON_RECOGNITION		2
529231200Smm#define GET_IFTYPE(flags)		((flags >> 24) & 0x1f)
530231200Smm#define IS_8251(if_type)		(!(if_type & 0x10))
531231200Smm#define COM1_EXT_CLOCK			0x40000
532231200Smm
533228753Smmstatic	void	commint		__P((dev_t dev));
534228753Smmstatic	void	com_tiocm_set	__P((struct com_s *com, int msr));
535231200Smmstatic	void	com_tiocm_bis	__P((struct com_s *com, int msr));
536228753Smmstatic	void	com_tiocm_bic	__P((struct com_s *com, int msr));
537228753Smmstatic	int	com_tiocm_get	__P((struct com_s *com));
538228753Smmstatic	int	com_tiocm_get_delta	__P((struct com_s *com));
539231200Smmstatic	void	pc98_msrint_start	__P((dev_t dev));
540228753Smmstatic	void	com_cflag_and_speed_set	__P((struct com_s *com, int cflag, int speed));
541228753Smmstatic	int	pc98_ttspeedtab		__P((struct com_s *com, int speed));
542228753Smmstatic	int	pc98_get_modem_status	__P((struct com_s *com));
543228753Smmstatic	timeout_t	pc98_check_msr;
544228753Smmstatic	void	pc98_set_baud_rate	__P((struct com_s *com, int count));
545231200Smmstatic	void	pc98_i8251_reset	__P((struct com_s *com, int mode, int command));
546228753Smmstatic	void	pc98_disable_i8251_interrupt	__P((struct com_s *com, int mod));
547228753Smmstatic	void	pc98_enable_i8251_interrupt	__P((struct com_s *com, int mod));
548228753Smmstatic	int	pc98_check_i8251_interrupt	__P((struct com_s *com));
549228753Smmstatic	int	pc98_i8251_get_cmd	__P((struct com_s *com));
550228753Smmstatic	int	pc98_i8251_get_mod	__P((struct com_s *com));
551228753Smmstatic	void	pc98_i8251_set_cmd	__P((struct com_s *com, int x));
552228753Smmstatic	void	pc98_i8251_or_cmd	__P((struct com_s *com, int x));
553231200Smmstatic	void	pc98_i8251_clear_cmd	__P((struct com_s *com, int x));
554231200Smmstatic	void	pc98_i8251_clear_or_cmd	__P((struct com_s *com, int clr, int x));
555231200Smmstatic	int	pc98_check_if_type	__P((device_t dev, struct siodev *iod));
556231200Smmstatic	int	pc98_check_8251vfast	__P((void));
557231200Smmstatic	int	pc98_check_8251fifo	__P((void));
558231200Smmstatic	void	pc98_check_sysclock	__P((void));
559231200Smmstatic	int	pc98_set_ioport		__P((struct com_s *com));
560231200Smm
561231200Smm#define com_int_Tx_disable(com) \
562231200Smm		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP)
563231200Smm#define com_int_Tx_enable(com) \
564231200Smm		pc98_enable_i8251_interrupt(com,IEN_TxFLAG)
565231200Smm#define com_int_Rx_disable(com) \
566231200Smm		pc98_disable_i8251_interrupt(com,IEN_Rx)
567231200Smm#define com_int_Rx_enable(com) \
568231200Smm		pc98_enable_i8251_interrupt(com,IEN_Rx)
569231200Smm#define com_int_TxRx_disable(com) \
570231200Smm		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx)
571231200Smm#define com_int_TxRx_enable(com) \
572231200Smm		pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx)
573231200Smm#define com_send_break_on(com) \
574231200Smm		pc98_i8251_or_cmd(com,CMD8251_SBRK)
575231200Smm#define com_send_break_off(com) \
576231200Smm		pc98_i8251_clear_cmd(com,CMD8251_SBRK)
577231200Smm
578231200Smmstatic struct speedtab pc98speedtab[] = {	/* internal RS232C interface */
579231200Smm	{ 0,		0, },
580231200Smm	{ 50,		50, },
581231200Smm	{ 75,		75, },
582231200Smm	{ 150,		150, },
583231200Smm	{ 200,		200, },
584231200Smm	{ 300,		300, },
585231200Smm	{ 600,		600, },
586231200Smm	{ 1200,		1200, },
587231200Smm	{ 2400,		2400, },
588231200Smm	{ 4800,		4800, },
589231200Smm	{ 9600,		9600, },
590231200Smm	{ 19200,	19200, },
591231200Smm	{ 38400,	38400, },
592231200Smm	{ 51200,	51200, },
593231200Smm	{ 76800,	76800, },
594231200Smm	{ 20800,	20800, },
595231200Smm	{ 31200,	31200, },
596231200Smm	{ 41600,	41600, },
597231200Smm	{ 62400,	62400, },
598231200Smm	{ -1,		-1 }
599231200Smm};
600231200Smmstatic struct speedtab pc98fast_speedtab[] = {
601231200Smm	{ 9600,		0x80 | COMBRD(9600), },
602231200Smm	{ 19200,	0x80 | COMBRD(19200), },
603231200Smm	{ 38400,	0x80 | COMBRD(38400), },
604231200Smm	{ 57600,	0x80 | COMBRD(57600), },
605231200Smm	{ 115200,	0x80 | COMBRD(115200), },
606231200Smm	{ -1,		-1 }
607231200Smm};
608231200Smmstatic struct speedtab comspeedtab_pio9032b[] = {
609231200Smm	{ 300,		6, },
610231200Smm	{ 600,		5, },
611231200Smm	{ 1200,		4, },
612231200Smm	{ 2400,		3, },
613231200Smm	{ 4800,		2, },
614231200Smm	{ 9600,		1, },
615231200Smm	{ 19200,	0, },
616231200Smm	{ 38400,	7, },
617231200Smm	{ -1,		-1 }
618231200Smm};
619231200Smmstatic struct speedtab comspeedtab_b98_01[] = {
620231200Smm	{ 75,		11, },
621231200Smm	{ 150,		10, },
622231200Smm	{ 300,		9, },
623231200Smm	{ 600,		8, },
624231200Smm	{ 1200,		7, },
625231200Smm	{ 2400,		6, },
626231200Smm	{ 4800,		5, },
627231200Smm	{ 9600,		4, },
628231200Smm	{ 19200,	3, },
629231200Smm	{ 38400,	2, },
630231200Smm	{ 76800,	1, },
631231200Smm	{ 153600,	0, },
632231200Smm	{ -1,		-1 }
633231200Smm};
634231200Smmstatic struct speedtab comspeedtab_mc16550[] = {
635231200Smm	{ 300,		1536, },
636231200Smm	{ 600,		768, },
637231200Smm	{ 1200,		384, },
638231200Smm	{ 2400,		192, },
639231200Smm	{ 4800,		96, },
640231200Smm	{ 9600,		48, },
641231200Smm	{ 19200,	24, },
642231200Smm	{ 38400,	12, },
643231200Smm	{ 57600,	8, },
644231200Smm	{ 115200,	4, },
645231200Smm	{ 153600,	3, },
646231200Smm	{ 230400,	2, },
647231200Smm	{ 460800,	1, },
648231200Smm	{ -1,		-1 }
649231200Smm};
650231200Smmstatic struct speedtab comspeedtab_rsb384[] = {
651231200Smm	{ 300,		3840, },
652231200Smm	{ 600,		1920, },
653231200Smm	{ 1200,		960, },
654231200Smm	{ 2400,		480, },
655231200Smm	{ 4800,		240, },
656231200Smm	{ 9600,		120, },
657231200Smm	{ 19200,	60, },
658231200Smm	{ 38400,	30, },
659231200Smm	{ 57600,	20, },
660231200Smm	{ 115200,	10, },
661231200Smm	{ 128000,	9, },
662231200Smm	{ 144000,	8, },
663231200Smm	{ 192000,	6, },
664231200Smm	{ 230400,	5, },
665231200Smm	{ 288000,	4, },
666231200Smm	{ 384000,	3, },
667231200Smm	{ 576000,	2, },
668231200Smm	{ 1152000,	1, },
669228753Smm	{ -1,		-1 }
670228753Smm};
671228753Smmstatic  struct speedtab comspeedtab_rsa[] = {
672228753Smm        { 0,		0 },
673228753Smm	{ 50,		COMBRD_RSA(50) },
674228753Smm	{ 75,		COMBRD_RSA(75) },
675228753Smm	{ 110,		COMBRD_RSA(110) },
676228753Smm	{ 134,		COMBRD_RSA(134) },
677228753Smm	{ 150,		COMBRD_RSA(150) },
678228753Smm	{ 200,		COMBRD_RSA(200) },
679228753Smm	{ 300,		COMBRD_RSA(300) },
680228753Smm	{ 600,		COMBRD_RSA(600) },
681228753Smm	{ 1200,		COMBRD_RSA(1200) },
682228753Smm	{ 1800,		COMBRD_RSA(1800) },
683228753Smm	{ 2400,		COMBRD_RSA(2400) },
684228753Smm	{ 4800,		COMBRD_RSA(4800) },
685228753Smm	{ 9600,		COMBRD_RSA(9600) },
686228753Smm	{ 19200,	COMBRD_RSA(19200) },
687228753Smm	{ 38400,	COMBRD_RSA(38400) },
688231200Smm	{ 57600,	COMBRD_RSA(57600) },
689231200Smm	{ 115200,	COMBRD_RSA(115200) },
690231200Smm	{ 230400,	COMBRD_RSA(230400) },
691231200Smm	{ 460800,	COMBRD_RSA(460800) },
692231200Smm	{ 921600,	COMBRD_RSA(921600) },
693231200Smm	{ -1,           -1 }
694231200Smm};
695231200Smm#endif /* PC98 */
696231200Smm
697228753Smmstatic	struct speedtab comspeedtab[] = {
698228753Smm	{ 0,		0 },
699231200Smm	{ 50,		COMBRD(50) },
700231200Smm	{ 75,		COMBRD(75) },
701231200Smm	{ 110,		COMBRD(110) },
702231200Smm	{ 134,		COMBRD(134) },
703228753Smm	{ 150,		COMBRD(150) },
704231200Smm	{ 200,		COMBRD(200) },
705228753Smm	{ 300,		COMBRD(300) },
706228753Smm	{ 600,		COMBRD(600) },
707228753Smm	{ 1200,		COMBRD(1200) },
708228753Smm	{ 1800,		COMBRD(1800) },
709228753Smm	{ 2400,		COMBRD(2400) },
710228753Smm	{ 4800,		COMBRD(4800) },
711228753Smm	{ 9600,		COMBRD(9600) },
712228753Smm	{ 19200,	COMBRD(19200) },
713228753Smm	{ 38400,	COMBRD(38400) },
714228753Smm	{ 57600,	COMBRD(57600) },
715228753Smm	{ 115200,	COMBRD(115200) },
716228753Smm	{ -1,		-1 }
717231200Smm};
718231200Smm
719228753Smm#ifdef PC98
720228753Smmstruct {
721231200Smm	char	*name;
722228753Smm	short	port_table[7];
723228753Smm	short	irr_mask;
724228753Smm	struct speedtab	*speedtab;
725228753Smm	short	check_irq;
726228753Smm} if_8251_type[] = {
727228753Smm	/* COM_IF_INTERNAL */
728231200Smm	{ " (internal)", {0x30, 0x32, 0x32, 0x33, 0x35, -1, -1},
729228753Smm	     -1, pc98speedtab, 1 },
730228753Smm	/* COM_IF_PC9861K_1 */
731231200Smm	{ " (PC9861K)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, -1, -1},
732228753Smm	     3, NULL, 1 },
733231200Smm	/* COM_IF_PC9861K_2 */
734231200Smm	{ " (PC9861K)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, -1, -1},
735231200Smm	      3, NULL, 1 },
736231200Smm	/* COM_IF_IND_SS_1 */
737231200Smm	{ " (IND-SS)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb3, -1},
738231200Smm	     3, comspeedtab_mc16550, 1 },
739231200Smm	/* COM_IF_IND_SS_2 */
740231200Smm	{ " (IND-SS)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xbb, -1},
741231200Smm	     3, comspeedtab_mc16550, 1 },
742231200Smm	/* COM_IF_PIO9032B_1 */
743228753Smm	{ " (PIO9032B)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb8, -1},
744228753Smm	      7, comspeedtab_pio9032b, 1 },
745228753Smm	/* COM_IF_PIO9032B_2 */
746228753Smm	{ " (PIO9032B)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xba, -1},
747228753Smm	      7, comspeedtab_pio9032b, 1 },
748228753Smm	/* COM_IF_B98_01_1 */
749228753Smm	{ " (B98-01)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xd1, 0xd3},
750228753Smm	      7, comspeedtab_b98_01, 0 },
751228753Smm	/* COM_IF_B98_01_2 */
752228753Smm	{ " (B98-01)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xd5, 0xd7},
753228753Smm	     7, comspeedtab_b98_01, 0 },
754228753Smm};
755228753Smm#define	PC98SIO_data_port(type)		(if_8251_type[type].port_table[0])
756228753Smm#define	PC98SIO_cmd_port(type)		(if_8251_type[type].port_table[1])
757228753Smm#define	PC98SIO_sts_port(type)		(if_8251_type[type].port_table[2])
758228753Smm#define	PC98SIO_in_modem_port(type)	(if_8251_type[type].port_table[3])
759228753Smm#define	PC98SIO_intr_ctrl_port(type)	(if_8251_type[type].port_table[4])
760228753Smm#define	PC98SIO_baud_rate_port(type)	(if_8251_type[type].port_table[5])
761228753Smm#define	PC98SIO_func_port(type)		(if_8251_type[type].port_table[6])
762228753Smm
763228753Smm#define	I8251F_data		0x130
764228753Smm#define	I8251F_lsr		0x132
765228753Smm#define	I8251F_msr		0x134
766228753Smm#define	I8251F_iir		0x136
767228753Smm#define	I8251F_fcr		0x138
768228753Smm#define	I8251F_div		0x13a
769228753Smm
770228753Smm
771228753Smmstruct {
772228753Smm	char	*name;
773228753Smm	short	irr_read;
774228753Smm	short	irr_write;
775228753Smm	short	port_shift;
776228753Smm	short	io_size;
777228753Smm	struct speedtab	*speedtab;
778228753Smm} if_16550a_type[] = {
779228753Smm	/* COM_IF_RSA98 */
780228753Smm        { " (RSA-98)", -1, -1, 0, IO_COMSIZE, comspeedtab },
781228753Smm	/* COM_IF_NS16550 */
782228753Smm	{ "", -1, -1, 0, IO_COMSIZE, comspeedtab },
783228753Smm	/* COM_IF_SECOND_CCU */
784228753Smm	{ "", -1, -1, 0, IO_COMSIZE, comspeedtab },
785228753Smm	/* COM_IF_MC16550II */
786228753Smm	{ " (MC16550II)", -1, 0x1000, 8, 1, comspeedtab_mc16550 },
787228753Smm	/* COM_IF_MCRS98 */
788228753Smm	{ " (MC-RS98)", -1, 0x1000, 8, 1, comspeedtab_mc16550 },
789228753Smm	/* COM_IF_RSB3000 */
790228753Smm	{ " (RSB-3000)", 0xbf, -1, 1, 1, comspeedtab_rsb384 },
791228753Smm	/* COM_IF_RSB384 */
792228753Smm	{ " (RSB-384)", 0xbf, -1, 1, 1, comspeedtab_rsb384 },
793228753Smm	/* COM_IF_MODEM_CARD */
794228753Smm	{ "", -1, -1, 0, IO_COMSIZE, comspeedtab },
795228753Smm	/* COM_IF_RSA98III */
796228753Smm	{ " (RSA-98III)", -1, -1, 0, 16, comspeedtab_rsa },
797228753Smm	/* COM_IF_ESP98 */
798228753Smm	{ " (ESP98)", -1, -1, 1, 1, comspeedtab_mc16550 },
799228753Smm};
800228753Smm#endif /* PC98 */
801228753Smm
802228753Smm#ifdef COM_ESP
803228753Smm#ifdef PC98
804228753Smm
805228753Smm/* XXX configure this properly. */
806228753Smmstatic  Port_t  likely_com_ports[] = { 0, 0xb0, 0xb1, 0 };
807228753Smmstatic  Port_t  likely_esp_ports[] = { 0xc0d0, 0 };
808228753Smm
809228753Smm#define	ESP98_CMD1	(ESP_CMD1 * 0x100)
810228753Smm#define	ESP98_CMD2	(ESP_CMD2 * 0x100)
811228753Smm#define	ESP98_STATUS1	(ESP_STATUS1 * 0x100)
812228753Smm#define	ESP98_STATUS2	(ESP_STATUS2 * 0x100)
813228753Smm
814228753Smm#else /* PC98 */
815228753Smm
816228753Smm/* XXX configure this properly. */
817228753Smmstatic	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
818228753Smmstatic	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
819228753Smm
820228753Smm#endif /* PC98 */
821228753Smm#endif
822228753Smm
823228753Smm/*
824228753Smm * handle sysctl read/write requests for console speed
825228753Smm *
826228753Smm * In addition to setting comdefaultrate for I/O through /dev/console,
827228753Smm * also set the initial and lock values for the /dev/ttyXX device
828228753Smm * if there is one associated with the console.  Finally, if the /dev/tty
829228753Smm * device has already been open, change the speed on the open running port
830228753Smm * itself.
831228753Smm */
832228753Smm
833228753Smmstatic int
834228753Smmsysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS
835228753Smm{
836228753Smm	int error, s;
837228753Smm	speed_t newspeed;
838228753Smm	struct com_s *com;
839228753Smm	struct tty *tp;
840228753Smm
841228753Smm	newspeed = comdefaultrate;
842228753Smm
843228753Smm	error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
844228753Smm	if (error || !req->newptr)
845228753Smm		return (error);
846228753Smm
847228753Smm	comdefaultrate = newspeed;
848228753Smm
849228753Smm	if (comconsole < 0)		/* serial console not selected? */
850228753Smm		return (0);
851228753Smm
852228753Smm	com = com_addr(comconsole);
853228753Smm	if (!com)
854228753Smm		return (ENXIO);
855228753Smm
856228753Smm	/*
857228753Smm	 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
858228753Smm	 * (note, the lock rates really are boolean -- if non-zero, disallow
859228753Smm	 *  speed changes)
860228753Smm	 */
861228753Smm	com->it_in.c_ispeed  = com->it_in.c_ospeed =
862231200Smm	com->lt_in.c_ispeed  = com->lt_in.c_ospeed =
863231200Smm	com->it_out.c_ispeed = com->it_out.c_ospeed =
864231200Smm	com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate;
865231200Smm
866228753Smm	/*
867231200Smm	 * if we're open, change the running rate too
868228753Smm	 */
869228753Smm	tp = com->tp;
870228753Smm	if (tp && (tp->t_state & TS_ISOPEN)) {
871228753Smm		tp->t_termios.c_ispeed =
872228753Smm		tp->t_termios.c_ospeed = comdefaultrate;
873228753Smm		s = spltty();
874228753Smm		error = comparam(tp, &tp->t_termios);
875228753Smm		splx(s);
876228753Smm	}
877228753Smm	return error;
878228753Smm}
879228753Smm
880228753SmmSYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
881228753Smm	    0, 0, sysctl_machdep_comdefaultrate, "I", "");
882228753Smm
883228753Smm#define SET_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) | (bit))
884228753Smm#define CLR_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) & ~(bit))
885228753Smm
886228753Smm#if NCARD > 0
887228753Smmstatic int
888228753Smmsio_pccard_probe(dev)
889228753Smm	device_t	dev;
890228753Smm{
891228753Smm	/* Do not probe IRQ - pccard doesn't turn on the interrupt line */
892228753Smm	/* until bus_setup_intr */
893228753Smm	SET_FLAG(dev, COM_C_NOPROBE);
894228753Smm
895228753Smm	return (sioprobe(dev));
896228753Smm}
897228753Smm
898228753Smmstatic int
899228753Smmsio_pccard_attach(dev)
900228753Smm	device_t	dev;
901228753Smm{
902228753Smm	return (sioattach(dev));
903228753Smm}
904228753Smm
905228753Smm/*
906228753Smm *	sio_detach - unload the driver and clear the table.
907228753Smm *	XXX TODO:
908228753Smm *	This is usually called when the card is ejected, but
909228753Smm *	can be caused by a modunload of a controller driver.
910228753Smm *	The idea is to reset the driver's view of the device
911228753Smm *	and ensure that any driver entry points such as
912228753Smm *	read and write do not hang.
913228753Smm */
914228753Smmstatic int
915228753Smmsio_pccard_detach(dev)
916228753Smm	device_t	dev;
917228753Smm{
918228753Smm	struct com_s	*com;
919228753Smm
920228753Smm	com = (struct com_s *) device_get_softc(dev);
921228753Smm	if (!com) {
922228753Smm		device_printf(dev, "NULL com in siounload\n");
923228753Smm		return (0);
924228753Smm	}
925228753Smm	if (!com->iobase) {
926228753Smm		device_printf(dev, "already unloaded!\n");
927228753Smm		return (0);
928228753Smm	}
929228753Smm	com->gone = 1;
930228753Smm	if (com->irqres) {
931228753Smm		bus_teardown_intr(dev, com->irqres, com->cookie);
932228753Smm		bus_release_resource(dev, SYS_RES_IRQ, 0, com->irqres);
933228753Smm	}
934228753Smm	if (com->ioportres)
935228753Smm		bus_release_resource(dev, SYS_RES_IOPORT, 0, com->ioportres);
936228753Smm	if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
937228753Smm		device_printf(dev, "unload\n");
938228753Smm		com->tp->t_gen++;
939228753Smm		ttyclose(com->tp);
940228753Smm		ttwakeup(com->tp);
941228753Smm		ttwwakeup(com->tp);
942228753Smm		device_printf(dev, "Was busy, so crash likely\n");
943228753Smm	} else {
944228753Smm		if (com->ibuf != NULL)
945228753Smm			free(com->ibuf, M_DEVBUF);
946228753Smm		device_printf(dev, "unload, gone\n");
947228753Smm	}
948228753Smm	return (0);
949228753Smm}
950228753Smm#endif /* NCARD > 0 */
951228753Smm
952228753Smm
953228753Smmstatic struct isa_pnp_id sio_ids[] = {
954228753Smm	{0x0005d041, "Standard PC COM port"},	/* PNP0500 */
955228753Smm	{0x0105d041, "16550A-compatible COM port"},	/* PNP0501 */
956228753Smm	{0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
957228753Smm	{0x1005d041, "Generic IRDA-compatible device"},	/* PNP0510 */
958228753Smm	{0x1105d041, "Generic IRDA-compatible device"},	/* PNP0511 */
959228753Smm	/* Devices that do not have a compatid */
960228753Smm	{0x7602a904, NULL},	/* AEI0276 - 56K v.90 Fax Modem (LKT) */
961228753Smm	{0x00007905, NULL},	/* AKY0000 - 56K Plug&Play Modem */
962228753Smm	{0x01405407, NULL},	/* AZT4001 - AZT3000 PnP SOUND DEVICE, MODEM */
963228753Smm	{0x56039008, NULL},	/* BDP0356 - Best Data 56x2 */
964228753Smm	{0x36339008, NULL},	/* BDP3336 - Best Data Prods. 336F */
965228753Smm	{0x0014490a, NULL},	/* BRI1400 - Boca 33.6 PnP */
966228753Smm	{0x0015490a, NULL},	/* BRI1500 - Internal Fax Data */
967228753Smm	{0x0034490a, NULL},	/* BRI3400 - Internal ACF Modem */
968228753Smm	{0x00b4490a, NULL},	/* BRIB400 - Boca 56k PnP */
969228753Smm	{0x0030320d, NULL},	/* CIR3000 - Cirrus Logic V43 */
970231200Smm	{0x0100440e, NULL},	/* CRD0001 - Cardinal MVP288IV ? */
971231200Smm	{0x1200c31e, NULL},	/* GVC0012 - VF1128HV-R9 (win modem?) */
972231200Smm	{0x0303c31e, NULL},	/* GVC0303 - MaxTech 33.6 PnP D/F/V */
973231200Smm	{0x0505c31e, NULL},	/* GVC0505 - GVC 56k Faxmodem */
974228753Smm	{0x0050c31e, NULL},	/* GVC5000 - some GVC modem */
975231200Smm	{0x3800f91e, NULL},	/* GWY0038 - Telepath with v.90 */
976231200Smm	{0x9062f91e, NULL},	/* GWY6290 - Telepath with x2 Technology */
977231200Smm	{0x0000f435, NULL},	/* MOT0000 - Motorola ModemSURFR 33.6 Intern */
978231200Smm	{0x5015f435, NULL},	/* MOT1550 - Motorola ModemSURFR 56K Modem */
979231200Smm	{0xf015f435, NULL},	/* MOT15F0 - Motorola VoiceSURFR 56K Modem */
980231200Smm	{0x6045f435, NULL},	/* MOT4560 - Motorola ? */
981231200Smm	{0x61e7a338, NULL},	/* NECE761 - 33.6Modem */
982231200Smm	{0x39804f3f, NULL},	/* OZO8039 - Zoom 56k flex */
983231200Smm	{0x1000eb49, NULL},	/* ROK0010 - Rockwell ? */
984231200Smm	{0x5002734a, NULL},	/* RSS0250 - 5614Jx3(G) Internal Modem */
985228753Smm	{0xc100ad4d, NULL},	/* SMM00C1 - Leopard 56k PnP */
986	{0x9012b04e, NULL},	/* SUP1290 - Supra ? */
987	{0x1013b04e, NULL},	/* SUP1310 - SupraExpress 336i PnP */
988	{0x8013b04e, NULL},	/* SUP1380 - SupraExpress 288i PnP Voice */
989	{0x8113b04e, NULL},	/* SUP1381 - SupraExpress 336i PnP Voice */
990	{0x5016b04e, NULL},	/* SUP1650 - Supra 336i Sp Intl */
991	{0x7420b04e, NULL},	/* SUP2070 - Supra ? */
992	{0x8020b04e, NULL},	/* SUP2080 - Supra ? */
993	{0x8420b04e, NULL},	/* SUP2084 - SupraExpress 56i PnP */
994	{0x7121b04e, NULL},	/* SUP2171 - SupraExpress 56i Sp? */
995	{0x8024b04e, NULL},	/* SUP2480 - Supra ? */
996	{0x01007256, NULL},	/* USR0001 - U.S. Robotics Inc., Sportster W */
997	{0x02007256, NULL},	/* USR0002 - U.S. Robotics Inc. Sportster 33. */
998	{0x04007256, NULL},	/* USR0004 - USR Sportster 14.4k */
999	{0x06007256, NULL},	/* USR0006 - USR Sportster 33.6k */
1000	{0x11007256, NULL},	/* USR0011 - USR ? */
1001	{0x01017256, NULL},	/* USR0101 - USR ? */
1002	{0x30207256, NULL},	/* USR2030 - U.S.Robotics Inc. Sportster 560 */
1003	{0x50207256, NULL},	/* USR2050 - U.S.Robotics Inc. Sportster 33. */
1004	{0x70207256, NULL},	/* USR2070 - U.S.Robotics Inc. Sportster 560 */
1005	{0x30307256, NULL},	/* USR3030 - U.S. Robotics 56K FAX INT */
1006	{0x31307256, NULL},	/* USR3031 - U.S. Robotics 56K FAX INT */
1007	{0x70307256, NULL},	/* USR3070 - U.S. Robotics 56K Voice INT */
1008	{0x90307256, NULL},	/* USR3090 - USR ? */
1009	{0x90917256, NULL},	/* USR9190 - USR 56k Voice INT */
1010	{0x0300695c, NULL},	/* WCI0003 - Fax/Voice/Modem/Speakphone/Asvd */
1011	{0x61f7896a, NULL},	/* ZTIF761 - Zoom ComStar 33.6 */
1012#ifdef PC98
1013	{0x0100e4a5, "RSA-98III"},
1014#endif
1015	{0}
1016};
1017
1018
1019
1020static int
1021sio_isa_probe(dev)
1022	device_t	dev;
1023{
1024#ifdef PC98
1025	int	logical_id;
1026#endif
1027	/* Check isapnp ids */
1028	if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO)
1029		return (ENXIO);
1030#ifdef PC98
1031	logical_id = isa_get_logicalid(dev);
1032	if (logical_id == 0x0100e4a5)		/* RSA-98III */
1033		device_set_flags(dev, COM_IF_RSA98III << 24);
1034#endif
1035	return (sioprobe(dev));
1036}
1037
1038static int
1039sioprobe(dev)
1040	device_t	dev;
1041{
1042#if 0
1043	static bool_t	already_init;
1044	device_t	xdev;
1045#endif
1046	bool_t		failures[10];
1047	int		fn;
1048	device_t	idev;
1049	Port_t		iobase;
1050	intrmask_t	irqmap[4];
1051	intrmask_t	irqs;
1052	u_char		mcr_image;
1053	int		result;
1054	u_long		xirq;
1055	u_int		flags = device_get_flags(dev);
1056	int		rid;
1057	struct resource *port;
1058#ifdef PC98
1059	int		irqout=0;
1060	int		tmp;
1061	int		port_shift = 0;
1062	struct siodev	iod;
1063	Port_t		rsabase;
1064#endif
1065
1066	rid = 0;
1067#ifdef PC98
1068	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1069				  0, ~0, 1, RF_ACTIVE);		/* XXX */
1070#else
1071	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1072				  0, ~0, IO_COMSIZE, RF_ACTIVE);
1073#endif
1074	if (!port)
1075		return ENXIO;
1076
1077#if 0
1078	/*
1079	 * XXX this is broken - when we are first called, there are no
1080	 * previously configured IO ports.  We could hard code
1081	 * 0x3f8, 0x2f8, 0x3e8, 0x2e8 etc but that's probably worse.
1082	 * This code has been doing nothing since the conversion since
1083	 * "count" is zero the first time around.
1084	 */
1085	if (!already_init) {
1086		/*
1087		 * Turn off MCR_IENABLE for all likely serial ports.  An unused
1088		 * port with its MCR_IENABLE gate open will inhibit interrupts
1089		 * from any used port that shares the interrupt vector.
1090		 * XXX the gate enable is elsewhere for some multiports.
1091		 */
1092		device_t *devs;
1093		int count, i, xioport;
1094#ifdef PC98
1095		int xiftype;
1096#endif
1097
1098		devclass_get_devices(sio_devclass, &devs, &count);
1099#ifdef PC98
1100		for (i = 0; i < count; i++) {
1101			xdev = devs[i];
1102			xioport = bus_get_resource_start(xdev, SYS_RES_IOPORT, 0);
1103			xiftype = GET_IFTYPE(device_get_flags(xdev));
1104			if (device_is_enabled(xdev) && xioport > 0) {
1105			    if (IS_8251(xiftype))
1106				outb(xioport & 0xff00) | PC98SIO_cmd_port(xiftype & 0x0f), 0xf2);
1107			    else {
1108				if (xiftype == COM_IF_RSA98III)
1109				    xioport += 8;
1110				outb(xioport + (com_mcr << if_16550a_type[xiftype & 0x0f].port_shift), 0);
1111			    }
1112			}
1113		}
1114#else
1115		for (i = 0; i < count; i++) {
1116			xdev = devs[i];
1117			if (device_is_enabled(xdev) &&
1118			    bus_get_resource(xdev, SYS_RES_IOPORT, 0, &xioport,
1119					     NULL) == 0)
1120				outb(xioport + com_mcr, 0);
1121		}
1122#endif
1123		free(devs, M_TEMP);
1124		already_init = TRUE;
1125	}
1126#endif
1127
1128	if (COM_LLCONSOLE(flags)) {
1129		printf("sio%d: reserved for low-level i/o\n",
1130		       device_get_unit(dev));
1131		bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1132		return (ENXIO);
1133	}
1134
1135#ifdef PC98
1136	DELAY(10);
1137
1138	/*
1139	 * If the port is i8251 UART (internal, B98_01)
1140	 */
1141	if (pc98_check_if_type(dev, &iod) == -1)
1142		return ENXIO;
1143	if (iod.irq > 0)
1144		bus_set_resource(dev, SYS_RES_IRQ, 0, iod.irq, 1);
1145	if (IS_8251(iod.if_type)) {
1146		outb(iod.cmd, 0);
1147		DELAY(10);
1148		outb(iod.cmd, 0);
1149		DELAY(10);
1150		outb(iod.cmd, 0);
1151		DELAY(10);
1152		outb(iod.cmd, CMD8251_RESET);
1153		DELAY(1000);		/* for a while...*/
1154		outb(iod.cmd, 0xf2);	/* MODE (dummy) */
1155		DELAY(10);
1156		outb(iod.cmd, 0x01);	/* CMD (dummy) */
1157		DELAY(1000);		/* for a while...*/
1158		if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) {
1159		    result = ENXIO;
1160		}
1161		if (if_8251_type[iod.if_type & 0x0f].check_irq) {
1162		    COM_INT_DISABLE
1163		    tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx));
1164		    outb( iod.ctrl, tmp|IEN_TxEMP );
1165		    DELAY(10);
1166		    result = isa_irq_pending() ? 0 : ENXIO;
1167		    outb( iod.ctrl, tmp );
1168		    COM_INT_ENABLE
1169		} else {
1170		    /*
1171		     * B98_01 doesn't activate TxEMP interrupt line
1172		     * when being reset, so we can't check irq pending.
1173		     */
1174		    result = 0;
1175		}
1176		if (epson_machine_id==0x20) {	/* XXX */
1177		    result = 0;
1178		}
1179		bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1180		return result;
1181	}
1182#endif /* PC98 */
1183	/*
1184	 * If the device is on a multiport card and has an AST/4
1185	 * compatible interrupt control register, initialize this
1186	 * register and prepare to leave MCR_IENABLE clear in the mcr.
1187	 * Otherwise, prepare to set MCR_IENABLE in the mcr.
1188	 * Point idev to the device struct giving the correct id_irq.
1189	 * This is the struct for the master device if there is one.
1190	 */
1191	idev = dev;
1192	mcr_image = MCR_IENABLE;
1193#ifdef COM_MULTIPORT
1194	if (COM_ISMULTIPORT(flags) && !COM_NOTAST4(flags)) {
1195		Port_t xiobase;
1196		u_long io;
1197
1198		idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags));
1199		if (idev == NULL) {
1200			printf("sio%d: master device %d not configured\n",
1201			       device_get_unit(dev), COM_MPMASTER(flags));
1202			idev = dev;
1203		}
1204#ifndef PC98
1205		if (bus_get_resource(idev, SYS_RES_IOPORT, 0, &io, NULL) == 0) {
1206			xiobase = io;
1207			if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL))
1208				outb(xiobase + com_scr, 0x80);	/* no irq */
1209			else
1210				outb(xiobase + com_scr, 0);
1211		}
1212		mcr_image = 0;
1213#endif
1214	}
1215#endif /* COM_MULTIPORT */
1216	if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL) != 0)
1217		mcr_image = 0;
1218
1219	bzero(failures, sizeof failures);
1220	iobase = rman_get_start(port);
1221
1222#ifdef PC98
1223        if (iod.if_type == COM_IF_RSA98III) {
1224		mcr_image = 0;
1225
1226		rsabase = iobase & 0xfff0;
1227		if (rsabase != iobase)
1228			return(0);
1229		iobase += 8;
1230
1231		outb(rsabase + rsa_msr,   0x04);
1232		outb(rsabase + rsa_frr,   0x00);
1233		if ((inb(rsabase + rsa_srr) & 0x36) != 0x36)
1234			return (0);
1235		outb(rsabase + rsa_ier,   0x00);
1236		outb(rsabase + rsa_frr,   0x00);
1237		outb(rsabase + rsa_tivsr, 0x00);
1238		outb(rsabase + rsa_tcr,   0x00);
1239	}
1240
1241	tmp = if_16550a_type[iod.if_type & 0x0f].irr_write;
1242	if (tmp != -1) {
1243	    /* MC16550II */
1244	    switch (isa_get_irq(idev)) {
1245	    case 3: irqout = 4; break;
1246	    case 5: irqout = 5; break;
1247	    case 6: irqout = 6; break;
1248	    case 12: irqout = 7; break;
1249	    default:
1250		printf("sio%d: irq configuration error\n",
1251		       device_get_unit(dev));
1252		return (0);
1253	    }
1254	    outb((isa_get_port(dev) & 0x00ff) | tmp, irqout);
1255	}
1256	port_shift = if_16550a_type[iod.if_type & 0x0f].port_shift;
1257#endif
1258
1259	/*
1260	 * We don't want to get actual interrupts, just masked ones.
1261	 * Interrupts from this line should already be masked in the ICU,
1262	 * but mask them in the processor as well in case there are some
1263	 * (misconfigured) shared interrupts.
1264	 */
1265	disable_intr();
1266/* EXTRA DELAY? */
1267
1268	/*
1269	 * Initialize the speed and the word size and wait long enough to
1270	 * drain the maximum of 16 bytes of junk in device output queues.
1271	 * The speed is undefined after a master reset and must be set
1272	 * before relying on anything related to output.  There may be
1273	 * junk after a (very fast) soft reboot and (apparently) after
1274	 * master reset.
1275	 * XXX what about the UART bug avoided by waiting in comparam()?
1276	 * We don't want to to wait long enough to drain at 2 bps.
1277	 */
1278	if (iobase == siocniobase)
1279		DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
1280	else {
1281#ifdef PC98
1282		tmp = ttspeedtab(SIO_TEST_SPEED,
1283				 if_16550a_type[iod.if_type & 0x0f].speedtab);
1284		outb(iobase + (com_cfcr << port_shift), CFCR_DLAB|CFCR_8BITS);
1285		outb(iobase + (com_dlbl << port_shift), tmp & 0xff);
1286		outb(iobase + (com_dlbh << port_shift), (tmp >> 8) & 0xff);
1287		outb(iobase + (com_cfcr << port_shift), CFCR_8BITS);
1288#else
1289		outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
1290		outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
1291		outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
1292		outb(iobase + com_cfcr, CFCR_8BITS);
1293#endif
1294		DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
1295	}
1296
1297	/*
1298	 * Enable the interrupt gate and disable device interupts.  This
1299	 * should leave the device driving the interrupt line low and
1300	 * guarantee an edge trigger if an interrupt can be generated.
1301	 */
1302/* EXTRA DELAY? */
1303#ifdef PC98
1304	outb(iobase + (com_mcr << port_shift), mcr_image);
1305	outb(iobase + (com_ier << port_shift), 0);
1306#else
1307	outb(iobase + com_mcr, mcr_image);
1308	outb(iobase + com_ier, 0);
1309#endif
1310	DELAY(1000);		/* XXX */
1311	irqmap[0] = isa_irq_pending();
1312
1313	/*
1314	 * Attempt to set loopback mode so that we can send a null byte
1315	 * without annoying any external device.
1316	 */
1317/* EXTRA DELAY? */
1318#ifdef PC98
1319	outb(iobase + (com_mcr << port_shift), mcr_image | MCR_LOOPBACK);
1320#else
1321	outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
1322#endif
1323
1324	/*
1325	 * Attempt to generate an output interrupt.  On 8250's, setting
1326	 * IER_ETXRDY generates an interrupt independent of the current
1327	 * setting and independent of whether the THR is empty.  On 16450's,
1328	 * setting IER_ETXRDY generates an interrupt independent of the
1329	 * current setting.  On 16550A's, setting IER_ETXRDY only
1330	 * generates an interrupt when IER_ETXRDY is not already set.
1331	 */
1332#ifdef PC98
1333	outb(iobase + (com_ier << port_shift), IER_ETXRDY);
1334        if (iod.if_type == COM_IF_RSA98III)
1335		outb(rsabase + rsa_ier,   0x04);
1336#else
1337	outb(iobase + com_ier, IER_ETXRDY);
1338#endif /* PC98 */
1339
1340	/*
1341	 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
1342	 * an interrupt.  They'd better generate one for actually doing
1343	 * output.  Loopback may be broken on the same incompatibles but
1344	 * it's unlikely to do more than allow the null byte out.
1345	 */
1346#ifdef PC98
1347 	outb(iobase + (com_data << port_shift), 0);
1348#else
1349	outb(iobase + com_data, 0);
1350#endif
1351	DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
1352
1353	/*
1354	 * Turn off loopback mode so that the interrupt gate works again
1355	 * (MCR_IENABLE was hidden).  This should leave the device driving
1356	 * an interrupt line high.  It doesn't matter if the interrupt
1357	 * line oscillates while we are not looking at it, since interrupts
1358	 * are disabled.
1359	 */
1360/* EXTRA DELAY? */
1361#ifdef PC98
1362	outb(iobase + (com_mcr << port_shift), mcr_image);
1363#else
1364	outb(iobase + com_mcr, mcr_image);
1365#endif /* PC98 */
1366
1367	/*
1368	 * Some pcmcia cards have the "TXRDY bug", so we check everyone
1369	 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
1370	 */
1371	if (COM_NOPROBE(flags)) {
1372		/* Reading IIR register twice */
1373		for (fn = 0; fn < 2; fn ++) {
1374			DELAY(10000);
1375#ifdef PC98
1376			failures[6] = inb(iobase + (com_iir << port_shift));
1377#else
1378			failures[6] = inb(iobase + com_iir);
1379#endif
1380		}
1381		/* Check IIR_TXRDY clear ? */
1382		result = 0;
1383		if (failures[6] & IIR_TXRDY) {
1384			/* Nop, Double check with clearing IER */
1385#ifdef PC98
1386			outb(iobase + (com_ier << port_shift), 0);
1387			if (inb(iobase + (com_iir << port_shift))
1388			    & IIR_NOPEND) {
1389#else
1390			outb(iobase + com_ier, 0);
1391			if (inb(iobase + com_iir) & IIR_NOPEND) {
1392#endif
1393				/* Ok. we're familia this gang */
1394				SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
1395			} else {
1396				/* Unknown, Just omit this chip.. XXX */
1397				result = ENXIO;
1398			}
1399		} else {
1400			/* OK. this is well-known guys */
1401			CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
1402		}
1403#ifdef PC98
1404		outb(iobase + (com_cfcr << port_shift), CFCR_8BITS);
1405#else
1406		outb(iobase + com_cfcr, CFCR_8BITS);
1407#endif
1408		enable_intr();
1409		bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1410		return (iobase == siocniobase ? 0 : result);
1411	}
1412
1413	/*
1414	 * Check that
1415	 *	o the CFCR, IER and MCR in UART hold the values written to them
1416	 *	  (the values happen to be all distinct - this is good for
1417	 *	  avoiding false positive tests from bus echoes).
1418	 *	o an output interrupt is generated and its vector is correct.
1419	 *	o the interrupt goes away when the IIR in the UART is read.
1420	 */
1421/* EXTRA DELAY? */
1422#ifdef PC98
1423	failures[0] = inb(iobase + (com_cfcr << port_shift)) - CFCR_8BITS;
1424	failures[1] = inb(iobase + (com_ier << port_shift)) - IER_ETXRDY;
1425	failures[2] = inb(iobase + (com_mcr << port_shift)) - mcr_image;
1426#else
1427	failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
1428	failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
1429	failures[2] = inb(iobase + com_mcr) - mcr_image;
1430#endif
1431	DELAY(10000);		/* Some internal modems need this time */
1432	irqmap[1] = isa_irq_pending();
1433#ifdef PC98
1434	failures[4] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK)
1435	    - IIR_TXRDY;
1436        if (iod.if_type == COM_IF_RSA98III)
1437		inb(rsabase + rsa_srr);
1438#else
1439	failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
1440#endif
1441	DELAY(1000);		/* XXX */
1442	irqmap[2] = isa_irq_pending();
1443#ifdef PC98
1444	failures[6] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK)
1445	    - IIR_NOPEND;
1446        if (iod.if_type == COM_IF_RSA98III)
1447		inb(rsabase + rsa_srr);
1448#else
1449	failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
1450#endif
1451
1452	/*
1453	 * Turn off all device interrupts and check that they go off properly.
1454	 * Leave MCR_IENABLE alone.  For ports without a master port, it gates
1455	 * the OUT2 output of the UART to
1456	 * the ICU input.  Closing the gate would give a floating ICU input
1457	 * (unless there is another device driving it) and spurious interrupts.
1458	 * (On the system that this was first tested on, the input floats high
1459	 * and gives a (masked) interrupt as soon as the gate is closed.)
1460	 */
1461#ifdef PC98
1462	outb(iobase + (com_ier << port_shift), 0);
1463	outb(iobase + (com_cfcr << port_shift), CFCR_8BITS);
1464	failures[7] = inb(iobase + (com_ier << port_shift));
1465        if (iod.if_type == COM_IF_RSA98III)
1466		outb(rsabase + rsa_ier,   0x00);
1467#else
1468	outb(iobase + com_ier, 0);
1469	outb(iobase + com_cfcr, CFCR_8BITS);	/* dummy to avoid bus echo */
1470	failures[7] = inb(iobase + com_ier);
1471#endif
1472	DELAY(1000);		/* XXX */
1473	irqmap[3] = isa_irq_pending();
1474#ifdef PC98
1475	failures[9] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK)
1476	    - IIR_NOPEND;
1477        if (iod.if_type == COM_IF_RSA98III) {
1478		inb(rsabase + rsa_srr);
1479		outb(rsabase + rsa_frr, 0x00);
1480	}
1481#else
1482	failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
1483#endif
1484
1485	enable_intr();
1486
1487	irqs = irqmap[1] & ~irqmap[0];
1488	if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 &&
1489	    ((1 << xirq) & irqs) == 0)
1490		printf(
1491		"sio%d: configured irq %ld not in bitmap of probed irqs %#x\n",
1492		    device_get_unit(dev), xirq, irqs);
1493	if (bootverbose)
1494		printf("sio%d: irq maps: %#x %#x %#x %#x\n",
1495		    device_get_unit(dev),
1496		    irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
1497
1498	result = 0;
1499	for (fn = 0; fn < sizeof failures; ++fn)
1500		if (failures[fn]) {
1501#ifdef PC98
1502			outb(iobase + (com_mcr << port_shift), 0);
1503#else
1504			outb(iobase + com_mcr, 0);
1505#endif
1506			result = ENXIO;
1507			if (bootverbose) {
1508				printf("sio%d: probe failed test(s):",
1509				    device_get_unit(dev));
1510				for (fn = 0; fn < sizeof failures; ++fn)
1511					if (failures[fn])
1512						printf(" %d", fn);
1513				printf("\n");
1514			}
1515			break;
1516		}
1517	bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1518	return (iobase == siocniobase ? 0 : result);
1519}
1520
1521#ifdef COM_ESP
1522static int
1523espattach(com, esp_port)
1524	struct com_s		*com;
1525	Port_t			esp_port;
1526{
1527	u_char	dips;
1528	u_char	val;
1529
1530	/*
1531	 * Check the ESP-specific I/O port to see if we're an ESP
1532	 * card.  If not, return failure immediately.
1533	 */
1534	if ((inb(esp_port) & 0xf3) == 0) {
1535		printf(" port 0x%x is not an ESP board?\n", esp_port);
1536		return (0);
1537	}
1538
1539	/*
1540	 * We've got something that claims to be a Hayes ESP card.
1541	 * Let's hope so.
1542	 */
1543
1544	/* Get the dip-switch configuration */
1545#ifdef PC98
1546	outb(esp_port + ESP98_CMD1, ESP_GETDIPS);
1547	dips = inb(esp_port + ESP98_STATUS1);
1548#else
1549	outb(esp_port + ESP_CMD1, ESP_GETDIPS);
1550	dips = inb(esp_port + ESP_STATUS1);
1551#endif
1552
1553	/*
1554	 * Bits 0,1 of dips say which COM port we are.
1555	 */
1556#ifdef PC98
1557	if ((com->iobase & 0xff) == likely_com_ports[dips & 0x03])
1558#else
1559	if (com->iobase == likely_com_ports[dips & 0x03])
1560#endif
1561		printf(" : ESP");
1562	else {
1563		printf(" esp_port has com %d\n", dips & 0x03);
1564		return (0);
1565	}
1566
1567	/*
1568	 * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
1569	 */
1570#ifdef PC98
1571	outb(esp_port + ESP98_CMD1, ESP_GETTEST);
1572	val = inb(esp_port + ESP98_STATUS1);	/* clear reg 1 */
1573	val = inb(esp_port + ESP98_STATUS2);
1574#else
1575	outb(esp_port + ESP_CMD1, ESP_GETTEST);
1576	val = inb(esp_port + ESP_STATUS1);	/* clear reg 1 */
1577	val = inb(esp_port + ESP_STATUS2);
1578#endif
1579	if ((val & 0x70) < 0x20) {
1580		printf("-old (%o)", val & 0x70);
1581		return (0);
1582	}
1583
1584	/*
1585	 * Check for ability to emulate 16550:  bit 7 == 1
1586	 */
1587	if ((dips & 0x80) == 0) {
1588		printf(" slave");
1589		return (0);
1590	}
1591
1592	/*
1593	 * Okay, we seem to be a Hayes ESP card.  Whee.
1594	 */
1595	com->esp = TRUE;
1596	com->esp_port = esp_port;
1597	return (1);
1598}
1599#endif /* COM_ESP */
1600
1601static int
1602sio_isa_attach(dev)
1603	device_t	dev;
1604{
1605	return (sioattach(dev));
1606}
1607
1608static int
1609sioattach(dev)
1610	device_t	dev;
1611{
1612	struct com_s	*com;
1613#ifdef COM_ESP
1614	Port_t		*espp;
1615#endif
1616	Port_t		iobase;
1617	int		unit;
1618	u_int		flags;
1619	int		rid;
1620	struct resource *port;
1621	int		ret;
1622#ifdef PC98
1623	int		port_shift = 0;
1624	u_char		*obuf;
1625	u_long		obufsize;
1626#endif
1627
1628	rid = 0;
1629#ifdef PC98
1630	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1631				  0, ~0, 1, RF_ACTIVE);		/* XXX */
1632#else
1633	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1634				  0, ~0, IO_COMSIZE, RF_ACTIVE);
1635#endif
1636	if (!port)
1637		return ENXIO;
1638
1639	iobase = rman_get_start(port);
1640	unit = device_get_unit(dev);
1641	com = device_get_softc(dev);
1642	flags = device_get_flags(dev);
1643
1644	if (unit >= sio_numunits)
1645		sio_numunits = unit + 1;
1646
1647#ifdef PC98
1648	obufsize = 256;
1649	if (GET_IFTYPE(flags) == COM_IF_RSA98III) {
1650		iobase += 8;
1651		obufsize = 2048;
1652	}
1653	if ((obuf = malloc(obufsize * 2, M_DEVBUF, M_NOWAIT)) == NULL)
1654		return ENXIO;
1655	bzero(obuf, obufsize * 2);
1656#endif
1657
1658	/*
1659	 * sioprobe() has initialized the device registers as follows:
1660	 *	o cfcr = CFCR_8BITS.
1661	 *	  It is most important that CFCR_DLAB is off, so that the
1662	 *	  data port is not hidden when we enable interrupts.
1663	 *	o ier = 0.
1664	 *	  Interrupts are only enabled when the line is open.
1665	 *	o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
1666	 *	  interrupt control register or the config specifies no irq.
1667	 *	  Keeping MCR_DTR and MCR_RTS off might stop the external
1668	 *	  device from sending before we are ready.
1669	 */
1670	bzero(com, sizeof *com);
1671#ifdef PC98
1672	com->obufsize = obufsize;
1673	com->obuf1 = obuf;
1674	com->obuf2 = obuf + obufsize;
1675#endif
1676	com->unit = unit;
1677	com->ioportres = port;
1678	com->cfcr_image = CFCR_8BITS;
1679	com->dtr_wait = 3 * hz;
1680	com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
1681	com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL);
1682	com->tx_fifo_size = 1;
1683	com->obufs[0].l_head = com->obuf1;
1684	com->obufs[1].l_head = com->obuf2;
1685
1686	com->iobase = iobase;
1687#ifdef PC98
1688	com->pc98_if_type = GET_IFTYPE(flags);
1689
1690	if (pc98_set_ioport(com) == -1) {
1691	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
1692
1693	    com->data_port = iobase + (com_data << port_shift);
1694	    com->int_id_port = iobase + (com_iir << port_shift);
1695	    com->modem_ctl_port = iobase + (com_mcr << port_shift);
1696	    com->mcr_image = inb(com->modem_ctl_port);
1697	    com->line_status_port = iobase + (com_lsr << port_shift);
1698	    com->modem_status_port = iobase + (com_msr << port_shift);
1699	    com->intr_ctl_port = iobase + (com_ier << port_shift);
1700	}
1701	if (com->pc98_if_type == COM_IF_INTERNAL && pc98_check_8251fifo()) {
1702	    com->pc98_8251fifo = 1;
1703	    com->pc98_8251fifo_enable = 0;
1704	}
1705#else /* not PC98 */
1706	com->data_port = iobase + com_data;
1707	com->int_id_port = iobase + com_iir;
1708	com->modem_ctl_port = iobase + com_mcr;
1709	com->mcr_image = inb(com->modem_ctl_port);
1710	com->line_status_port = iobase + com_lsr;
1711	com->modem_status_port = iobase + com_msr;
1712	com->intr_ctl_port = iobase + com_ier;
1713#endif
1714
1715	/*
1716	 * We don't use all the flags from <sys/ttydefaults.h> since they
1717	 * are only relevant for logins.  It's important to have echo off
1718	 * initially so that the line doesn't start blathering before the
1719	 * echo flag can be turned off.
1720	 */
1721	com->it_in.c_iflag = 0;
1722	com->it_in.c_oflag = 0;
1723	com->it_in.c_cflag = TTYDEF_CFLAG;
1724	com->it_in.c_lflag = 0;
1725	if (unit == comconsole) {
1726#ifdef PC98
1727		if (IS_8251(com->pc98_if_type))
1728			DELAY(100000);
1729#endif
1730		com->it_in.c_iflag = TTYDEF_IFLAG;
1731		com->it_in.c_oflag = TTYDEF_OFLAG;
1732		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
1733		com->it_in.c_lflag = TTYDEF_LFLAG;
1734		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
1735		com->lt_out.c_ispeed = com->lt_out.c_ospeed =
1736		com->lt_in.c_ispeed = com->lt_in.c_ospeed =
1737		com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
1738	} else
1739		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
1740	if (siosetwater(com, com->it_in.c_ispeed) != 0) {
1741		enable_intr();
1742		free(com, M_DEVBUF);
1743		/*
1744		 * Leave i/o resources allocated if this is a `cn'-level
1745		 * console, so that other devices can't snarf them.
1746		 */
1747		if (iobase != siocniobase)
1748			bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1749		return (ENOMEM);
1750	}
1751	enable_intr();
1752	termioschars(&com->it_in);
1753	com->it_out = com->it_in;
1754
1755	/* attempt to determine UART type */
1756	printf("sio%d: type", unit);
1757
1758
1759#ifndef PC98
1760#ifdef COM_MULTIPORT
1761	if (!COM_ISMULTIPORT(flags) && !COM_IIR_TXRDYBUG(flags))
1762#else
1763	if (!COM_IIR_TXRDYBUG(flags))
1764#endif
1765	{
1766		u_char	scr;
1767		u_char	scr1;
1768		u_char	scr2;
1769
1770		scr = inb(iobase + com_scr);
1771		outb(iobase + com_scr, 0xa5);
1772		scr1 = inb(iobase + com_scr);
1773		outb(iobase + com_scr, 0x5a);
1774		scr2 = inb(iobase + com_scr);
1775		outb(iobase + com_scr, scr);
1776		if (scr1 != 0xa5 || scr2 != 0x5a) {
1777			printf(" 8250");
1778			goto determined_type;
1779		}
1780	}
1781#endif /* !PC98 */
1782#ifdef PC98
1783	if (IS_8251(com->pc98_if_type)) {
1784	    if (com->pc98_8251fifo && !COM_NOFIFO(flags))
1785		com->tx_fifo_size = 16;
1786	    com_int_TxRx_disable( com );
1787	    com_cflag_and_speed_set( com, com->it_in.c_cflag, comdefaultrate );
1788	    com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
1789	    com_send_break_off( com );
1790
1791	    if (com->pc98_if_type == COM_IF_INTERNAL) {
1792		printf(" (internal%s%s)",
1793		       com->pc98_8251fifo ? " fifo" : "",
1794		       PC98SIO_baud_rate_port(com->pc98_if_type) != -1 ?
1795		       " v-fast" : "");
1796	    } else {
1797		printf(" 8251%s", if_8251_type[com->pc98_if_type & 0x0f].name);
1798	    }
1799	} else {
1800	outb(iobase + (com_fifo << port_shift), FIFO_ENABLE | FIFO_RX_HIGH);
1801#else
1802	outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
1803#endif /* PC98 */
1804	DELAY(100);
1805	com->st16650a = 0;
1806	switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
1807	case FIFO_RX_LOW:
1808		printf(" 16450");
1809		break;
1810	case FIFO_RX_MEDL:
1811		printf(" 16450?");
1812		break;
1813	case FIFO_RX_MEDH:
1814		printf(" 16550?");
1815		break;
1816	case FIFO_RX_HIGH:
1817		if (COM_NOFIFO(flags)) {
1818			printf(" 16550A fifo disabled");
1819		} else {
1820			com->hasfifo = TRUE;
1821#ifdef PC98
1822			com->tx_fifo_size = 0;	/* XXX flag conflicts. */
1823			printf(" 16550A");
1824#else
1825			if (COM_ST16650A(flags)) {
1826				com->st16650a = 1;
1827				com->tx_fifo_size = 32;
1828				printf(" ST16650A");
1829			} else {
1830				com->tx_fifo_size = COM_FIFOSIZE(flags);
1831				printf(" 16550A");
1832			}
1833#endif
1834		}
1835#ifdef PC98
1836		if (com->pc98_if_type == COM_IF_RSA98III) {
1837			com->tx_fifo_size = 2048;
1838			com->rsabase = isa_get_port(dev);
1839			outb(com->rsabase + rsa_ier, 0x00);
1840			outb(com->rsabase + rsa_frr, 0x00);
1841		}
1842#endif
1843
1844#ifdef COM_ESP
1845#ifdef PC98
1846		if (com->pc98_if_type == COM_IF_ESP98)
1847#endif
1848		for (espp = likely_esp_ports; *espp != 0; espp++)
1849			if (espattach(com, *espp)) {
1850				com->tx_fifo_size = 1024;
1851				break;
1852			}
1853#endif
1854		if (!com->st16650a) {
1855			if (!com->tx_fifo_size)
1856				com->tx_fifo_size = 16;
1857			else
1858				printf(" lookalike with %d bytes FIFO",
1859				    com->tx_fifo_size);
1860		}
1861
1862		break;
1863	}
1864
1865#ifdef PC98
1866	if (com->pc98_if_type == COM_IF_RSB3000) {
1867	    /* Set RSB-2000/3000 Extended Buffer mode. */
1868	    u_char lcr;
1869	    lcr = inb(iobase + (com_cfcr << port_shift));
1870	    outb(iobase + (com_cfcr << port_shift), lcr | CFCR_DLAB);
1871	    outb(iobase + (com_emr << port_shift), EMR_EXBUFF | EMR_EFMODE);
1872	    outb(iobase + (com_cfcr << port_shift), lcr);
1873	}
1874#endif
1875
1876#ifdef COM_ESP
1877	if (com->esp) {
1878		/*
1879		 * Set 16550 compatibility mode.
1880		 * We don't use the ESP_MODE_SCALE bit to increase the
1881		 * fifo trigger levels because we can't handle large
1882		 * bursts of input.
1883		 * XXX flow control should be set in comparam(), not here.
1884		 */
1885#ifdef PC98
1886		outb(com->esp_port + ESP98_CMD1, ESP_SETMODE);
1887		outb(com->esp_port + ESP98_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1888#else
1889		outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1890		outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1891#endif
1892
1893		/* Set RTS/CTS flow control. */
1894#ifdef PC98
1895		outb(com->esp_port + ESP98_CMD1, ESP_SETFLOWTYPE);
1896		outb(com->esp_port + ESP98_CMD2, ESP_FLOW_RTS);
1897		outb(com->esp_port + ESP98_CMD2, ESP_FLOW_CTS);
1898#else
1899		outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1900		outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1901		outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1902#endif
1903
1904		/* Set flow-control levels. */
1905#ifdef PC98
1906		outb(com->esp_port + ESP98_CMD1, ESP_SETRXFLOW);
1907		outb(com->esp_port + ESP98_CMD2, HIBYTE(768));
1908		outb(com->esp_port + ESP98_CMD2, LOBYTE(768));
1909		outb(com->esp_port + ESP98_CMD2, HIBYTE(512));
1910		outb(com->esp_port + ESP98_CMD2, LOBYTE(512));
1911#else
1912		outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1913		outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1914		outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1915		outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1916		outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1917#endif
1918
1919#ifdef PC98
1920                /* Set UART clock prescaler. */
1921                outb(com->esp_port + ESP98_CMD1, ESP_SETCLOCK);
1922                outb(com->esp_port + ESP98_CMD2, 2);	/* 4 times */
1923#endif
1924	}
1925#endif /* COM_ESP */
1926#ifdef PC98
1927	printf("%s", if_16550a_type[com->pc98_if_type & 0x0f].name);
1928	outb(iobase + (com_fifo << port_shift), 0);
1929#else
1930	outb(iobase + com_fifo, 0);
1931determined_type: ;
1932#endif
1933
1934#ifdef COM_MULTIPORT
1935	if (COM_ISMULTIPORT(flags)) {
1936		device_t masterdev;
1937
1938		com->multiport = TRUE;
1939		printf(" (multiport");
1940		masterdev = devclass_get_device(sio_devclass,
1941		    COM_MPMASTER(flags));
1942		com->no_irq = bus_get_resource(masterdev, SYS_RES_IRQ, 0, NULL,
1943		    NULL);
1944		if (unit == COM_MPMASTER(flags))
1945			printf(" master");
1946		printf(")");
1947	 }
1948#endif /* COM_MULTIPORT */
1949#ifdef PC98
1950	}
1951#endif
1952	if (unit == comconsole)
1953		printf(", console");
1954	if (COM_IIR_TXRDYBUG(flags))
1955		printf(" with a bogus IIR_TXRDY register");
1956	printf("\n");
1957
1958	if (!sio_registered) {
1959		register_swi(SWI_TTY, siopoll);
1960		sio_registered = TRUE;
1961	}
1962	make_dev(&sio_cdevsw, unit,
1963	    UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit);
1964	make_dev(&sio_cdevsw, unit | CONTROL_INIT_STATE,
1965	    UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit);
1966	make_dev(&sio_cdevsw, unit | CONTROL_LOCK_STATE,
1967	    UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit);
1968	make_dev(&sio_cdevsw, unit | CALLOUT_MASK,
1969	    UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit);
1970	make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_INIT_STATE,
1971	    UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit);
1972	make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_LOCK_STATE,
1973	    UID_UUCP, GID_DIALER, 0660, "cuala%r", unit);
1974	com->flags = flags;
1975	com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
1976	pps_init(&com->pps);
1977
1978	rid = 0;
1979	com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1,
1980	    RF_ACTIVE);
1981	if (com->irqres) {
1982		ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
1983				     INTR_TYPE_TTY | INTR_TYPE_FAST,
1984				     siointr, com, &com->cookie);
1985		if (ret) {
1986			ret = BUS_SETUP_INTR(device_get_parent(dev), dev,
1987					     com->irqres, INTR_TYPE_TTY,
1988					     siointr, com, &com->cookie);
1989			if (ret == 0)
1990				device_printf(dev, "unable to activate interrupt in fast mode - using normal mode");
1991		}
1992		if (ret)
1993			device_printf(dev, "could not activate interrupt\n");
1994	}
1995
1996	return (0);
1997}
1998
1999static int
2000sioopen(dev, flag, mode, p)
2001	dev_t		dev;
2002	int		flag;
2003	int		mode;
2004	struct proc	*p;
2005{
2006	struct com_s	*com;
2007	int		error;
2008	Port_t		iobase;
2009	int		mynor;
2010	int		s;
2011	struct tty	*tp;
2012	int		unit;
2013#ifdef PC98
2014	int		port_shift = 0;
2015#endif
2016
2017	mynor = minor(dev);
2018	unit = MINOR_TO_UNIT(mynor);
2019	com = com_addr(unit);
2020	if (com == NULL)
2021		return (ENXIO);
2022	if (com->gone)
2023		return (ENXIO);
2024	if (mynor & CONTROL_MASK)
2025		return (0);
2026	tp = dev->si_tty = com->tp = ttymalloc(com->tp);
2027	s = spltty();
2028
2029#ifdef PC98
2030	if (!IS_8251(com->pc98_if_type))
2031	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
2032#endif
2033	/*
2034	 * We jump to this label after all non-interrupted sleeps to pick
2035	 * up any changes of the device state.
2036	 */
2037open_top:
2038	while (com->state & CS_DTR_OFF) {
2039		error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
2040		if (com_addr(unit) == NULL)
2041			return (ENXIO);
2042		if (error != 0 || com->gone)
2043			goto out;
2044	}
2045	if (tp->t_state & TS_ISOPEN) {
2046		/*
2047		 * The device is open, so everything has been initialized.
2048		 * Handle conflicts.
2049		 */
2050		if (mynor & CALLOUT_MASK) {
2051			if (!com->active_out) {
2052				error = EBUSY;
2053				goto out;
2054			}
2055		} else {
2056			if (com->active_out) {
2057				if (flag & O_NONBLOCK) {
2058					error = EBUSY;
2059					goto out;
2060				}
2061				error =	tsleep(&com->active_out,
2062					       TTIPRI | PCATCH, "siobi", 0);
2063				if (com_addr(unit) == NULL)
2064					return (ENXIO);
2065				if (error != 0 || com->gone)
2066					goto out;
2067				goto open_top;
2068			}
2069		}
2070		if (tp->t_state & TS_XCLUDE &&
2071		    suser(p)) {
2072			error = EBUSY;
2073			goto out;
2074		}
2075	} else {
2076		/*
2077		 * The device isn't open, so there are no conflicts.
2078		 * Initialize it.  Initialization is done twice in many
2079		 * cases: to preempt sleeping callin opens if we are
2080		 * callout, and to complete a callin open after DCD rises.
2081		 */
2082		tp->t_oproc = comstart;
2083		tp->t_param = comparam;
2084		tp->t_stop = comstop;
2085		tp->t_dev = dev;
2086		tp->t_termios = mynor & CALLOUT_MASK
2087				? com->it_out : com->it_in;
2088#ifdef PC98
2089		if (!IS_8251(com->pc98_if_type))
2090#endif
2091		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
2092		com->poll = com->no_irq;
2093		com->poll_output = com->loses_outints;
2094		++com->wopeners;
2095		error = comparam(tp, &tp->t_termios);
2096		--com->wopeners;
2097		if (error != 0)
2098			goto out;
2099#ifdef PC98
2100		if (IS_8251(com->pc98_if_type)) {
2101			com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS);
2102			pc98_msrint_start(dev);
2103			if (com->pc98_8251fifo) {
2104			    com->pc98_8251fifo_enable = 1;
2105			    outb(I8251F_fcr, CTRL8251F_ENABLE |
2106				 CTRL8251F_XMT_RST | CTRL8251F_RCV_RST);
2107			}
2108		}
2109#endif
2110		/*
2111		 * XXX we should goto open_top if comparam() slept.
2112		 */
2113		iobase = com->iobase;
2114		if (com->hasfifo) {
2115			/*
2116			 * (Re)enable and drain fifos.
2117			 *
2118			 * Certain SMC chips cause problems if the fifos
2119			 * are enabled while input is ready.  Turn off the
2120			 * fifo if necessary to clear the input.  We test
2121			 * the input ready bit after enabling the fifos
2122			 * since we've already enabled them in comparam()
2123			 * and to handle races between enabling and fresh
2124			 * input.
2125			 */
2126			while (TRUE) {
2127#ifdef PC98
2128 				outb(iobase + (com_fifo << port_shift),
2129 				     FIFO_RCV_RST | FIFO_XMT_RST
2130 				     | com->fifo_image);
2131				if (com->pc98_if_type == COM_IF_RSA98III)
2132				  outb(com->rsabase + rsa_frr , 0x00);
2133#else
2134				outb(iobase + com_fifo,
2135				     FIFO_RCV_RST | FIFO_XMT_RST
2136				     | com->fifo_image);
2137#endif
2138				/*
2139				 * XXX the delays are for superstitious
2140				 * historical reasons.  It must be less than
2141				 * the character time at the maximum
2142				 * supported speed (87 usec at 115200 bps
2143				 * 8N1).  Otherwise we might loop endlessly
2144				 * if data is streaming in.  We used to use
2145				 * delays of 100.  That usually worked
2146				 * because DELAY(100) used to usually delay
2147				 * for about 85 usec instead of 100.
2148				 */
2149				DELAY(50);
2150#ifndef PC98
2151				if (!(inb(com->line_status_port) & LSR_RXRDY))
2152#else
2153				if (com->pc98_if_type == COM_IF_RSA98III
2154				    ? !(inb(com->rsabase + rsa_srr) & 0x08)
2155				    : !(inb(com->line_status_port) & LSR_RXRDY))
2156#endif
2157					break;
2158#ifdef PC98
2159 				outb(iobase + (com_fifo << port_shift), 0);
2160#else
2161				outb(iobase + com_fifo, 0);
2162#endif
2163				DELAY(50);
2164				(void) inb(com->data_port);
2165			}
2166		}
2167
2168		disable_intr();
2169#ifdef PC98
2170		if (IS_8251(com->pc98_if_type)) {
2171		    com_tiocm_bis(com, TIOCM_LE);
2172		    com->pc98_prev_modem_status = pc98_get_modem_status(com);
2173		    com_int_Rx_enable(com);
2174		} else {
2175#endif
2176		(void) inb(com->line_status_port);
2177		(void) inb(com->data_port);
2178		com->prev_modem_status = com->last_modem_status
2179		    = inb(com->modem_status_port);
2180		if (COM_IIR_TXRDYBUG(com->flags)) {
2181			outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
2182						| IER_EMSC);
2183		} else {
2184			outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
2185						| IER_ERLS | IER_EMSC);
2186		}
2187#ifdef PC98
2188		if (com->pc98_if_type == COM_IF_RSA98III) {
2189			outb(com->rsabase + rsa_ier, 0x1d);
2190			outb(com->intr_ctl_port, IER_ERLS | IER_EMSC);
2191		}
2192#endif
2193#ifdef PC98
2194		}
2195#endif
2196		enable_intr();
2197		/*
2198		 * Handle initial DCD.  Callout devices get a fake initial
2199		 * DCD (trapdoor DCD).  If we are callout, then any sleeping
2200		 * callin opens get woken up and resume sleeping on "siobi"
2201		 * instead of "siodcd".
2202		 */
2203		/*
2204		 * XXX `mynor & CALLOUT_MASK' should be
2205		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
2206		 * TRAPDOOR_CARRIER is the default initial state for callout
2207		 * devices and SOFT_CARRIER is like CLOCAL except it hides
2208		 * the true carrier.
2209		 */
2210#ifdef PC98
2211		if ((IS_8251(com->pc98_if_type) &&
2212			(pc98_get_modem_status(com) & TIOCM_CAR)) ||
2213		    (!IS_8251(com->pc98_if_type) &&
2214			(com->prev_modem_status & MSR_DCD)) ||
2215		    mynor & CALLOUT_MASK)
2216#else
2217		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
2218#endif
2219			(*linesw[tp->t_line].l_modem)(tp, 1);
2220	}
2221	/*
2222	 * Wait for DCD if necessary.
2223	 */
2224	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
2225	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
2226		++com->wopeners;
2227		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
2228		if (com_addr(unit) == NULL)
2229			return (ENXIO);
2230		--com->wopeners;
2231		if (error != 0 || com->gone)
2232			goto out;
2233		goto open_top;
2234	}
2235	error =	(*linesw[tp->t_line].l_open)(dev, tp);
2236	disc_optim(tp, &tp->t_termios, com);
2237	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
2238		com->active_out = TRUE;
2239	siosettimeout();
2240out:
2241	splx(s);
2242	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
2243		comhardclose(com);
2244	return (error);
2245}
2246
2247static int
2248sioclose(dev, flag, mode, p)
2249	dev_t		dev;
2250	int		flag;
2251	int		mode;
2252	struct proc	*p;
2253{
2254	struct com_s	*com;
2255	int		mynor;
2256	int		s;
2257	struct tty	*tp;
2258
2259	mynor = minor(dev);
2260	if (mynor & CONTROL_MASK)
2261		return (0);
2262	com = com_addr(MINOR_TO_UNIT(mynor));
2263	tp = com->tp;
2264	s = spltty();
2265	(*linesw[tp->t_line].l_close)(tp, flag);
2266#ifdef PC98
2267	com->modem_checking = 0;
2268#endif
2269	disc_optim(tp, &tp->t_termios, com);
2270	comstop(tp, FREAD | FWRITE);
2271	comhardclose(com);
2272	ttyclose(tp);
2273	siosettimeout();
2274	splx(s);
2275	if (com->gone) {
2276		printf("sio%d: gone\n", com->unit);
2277		s = spltty();
2278		if (com->ibuf != NULL)
2279			free(com->ibuf, M_DEVBUF);
2280		bzero(tp, sizeof *tp);
2281		free(com, M_DEVBUF);
2282		splx(s);
2283	}
2284	return (0);
2285}
2286
2287static void
2288comhardclose(com)
2289	struct com_s	*com;
2290{
2291	Port_t		iobase;
2292	int		s;
2293	struct tty	*tp;
2294	int		unit;
2295#ifdef PC98
2296	int		port_shift = 0;
2297#endif
2298
2299	unit = com->unit;
2300	iobase = com->iobase;
2301	s = spltty();
2302	com->poll = FALSE;
2303	com->poll_output = FALSE;
2304	com->do_timestamp = FALSE;
2305	com->do_dcd_timestamp = FALSE;
2306	com->pps.ppsparam.mode = 0;
2307#ifdef PC98
2308	if (IS_8251(com->pc98_if_type))
2309	    com_send_break_off(com);
2310	else {
2311	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
2312	    outb(iobase + (com_cfcr << port_shift),
2313		 com->cfcr_image &= ~CFCR_SBREAK);
2314	}
2315#else
2316	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
2317#endif
2318	{
2319#ifdef PC98
2320		int tmp;
2321		if (IS_8251(com->pc98_if_type))
2322			com_int_TxRx_disable(com);
2323		else
2324			outb(iobase + (com_ier << port_shift), 0);
2325		if (com->pc98_if_type == COM_IF_RSA98III) {
2326			outb(com->rsabase + rsa_ier, 0x00);
2327		}
2328#else
2329		outb(iobase + com_ier, 0);
2330#endif
2331		tp = com->tp;
2332#ifdef PC98
2333		if (IS_8251(com->pc98_if_type))
2334			tmp = pc98_get_modem_status(com) & TIOCM_CAR;
2335		else
2336			tmp = com->prev_modem_status & MSR_DCD;
2337#endif
2338		if (tp->t_cflag & HUPCL
2339		    /*
2340		     * XXX we will miss any carrier drop between here and the
2341		     * next open.  Perhaps we should watch DCD even when the
2342		     * port is closed; it is not sufficient to check it at
2343		     * the next open because it might go up and down while
2344		     * we're not watching.
2345		     */
2346		    || (!com->active_out
2347#ifdef PC98
2348		       && !(tmp)
2349#else
2350		        && !(com->prev_modem_status & MSR_DCD)
2351#endif
2352		        && !(com->it_in.c_cflag & CLOCAL))
2353		    || !(tp->t_state & TS_ISOPEN)) {
2354#ifdef PC98
2355			if (IS_8251(com->pc98_if_type))
2356			    com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
2357			else
2358#endif
2359			(void)commctl(com, TIOCM_DTR, DMBIC);
2360			if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
2361				timeout(siodtrwakeup, com, com->dtr_wait);
2362				com->state |= CS_DTR_OFF;
2363			}
2364		}
2365#ifdef PC98
2366		else {
2367			if (IS_8251(com->pc98_if_type))
2368				com_tiocm_bic(com, TIOCM_LE );
2369		}
2370#endif
2371	}
2372#ifdef PC98
2373	if (com->pc98_8251fifo)	{
2374	    if (com->pc98_8251fifo_enable)
2375		outb(I8251F_fcr, CTRL8251F_XMT_RST | CTRL8251F_RCV_RST);
2376	    com->pc98_8251fifo_enable = 0;
2377	}
2378#endif
2379	if (com->hasfifo) {
2380		/*
2381		 * Disable fifos so that they are off after controlled
2382		 * reboots.  Some BIOSes fail to detect 16550s when the
2383		 * fifos are enabled.
2384		 */
2385#ifdef PC98
2386		outb(iobase + (com_fifo << port_shift), 0);
2387#else
2388		outb(iobase + com_fifo, 0);
2389#endif
2390	}
2391	com->active_out = FALSE;
2392	wakeup(&com->active_out);
2393	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */
2394	splx(s);
2395}
2396
2397static int
2398sioread(dev, uio, flag)
2399	dev_t		dev;
2400	struct uio	*uio;
2401	int		flag;
2402{
2403	int		mynor;
2404	struct com_s	*com;
2405
2406	mynor = minor(dev);
2407	if (mynor & CONTROL_MASK)
2408		return (ENODEV);
2409	com = com_addr(MINOR_TO_UNIT(mynor));
2410	if (com->gone)
2411		return (ENODEV);
2412	return ((*linesw[com->tp->t_line].l_read)(com->tp, uio, flag));
2413}
2414
2415static int
2416siowrite(dev, uio, flag)
2417	dev_t		dev;
2418	struct uio	*uio;
2419	int		flag;
2420{
2421	int		mynor;
2422	struct com_s	*com;
2423	int		unit;
2424
2425	mynor = minor(dev);
2426	if (mynor & CONTROL_MASK)
2427		return (ENODEV);
2428
2429	unit = MINOR_TO_UNIT(mynor);
2430	com = com_addr(unit);
2431	if (com->gone)
2432		return (ENODEV);
2433	/*
2434	 * (XXX) We disallow virtual consoles if the physical console is
2435	 * a serial port.  This is in case there is a display attached that
2436	 * is not the console.  In that situation we don't need/want the X
2437	 * server taking over the console.
2438	 */
2439	if (constty != NULL && unit == comconsole)
2440		constty = NULL;
2441	return ((*linesw[com->tp->t_line].l_write)(com->tp, uio, flag));
2442}
2443
2444static void
2445siobusycheck(chan)
2446	void	*chan;
2447{
2448	struct com_s	*com;
2449	int		s;
2450
2451	com = (struct com_s *)chan;
2452
2453	/*
2454	 * Clear TS_BUSY if low-level output is complete.
2455	 * spl locking is sufficient because siointr1() does not set CS_BUSY.
2456	 * If siointr1() clears CS_BUSY after we look at it, then we'll get
2457	 * called again.  Reading the line status port outside of siointr1()
2458	 * is safe because CS_BUSY is clear so there are no output interrupts
2459	 * to lose.
2460	 */
2461	s = spltty();
2462	if (com->state & CS_BUSY)
2463		com->extra_state &= ~CSE_BUSYCHECK;	/* False alarm. */
2464#ifdef	PC98
2465	else if ((IS_8251(com->pc98_if_type) &&
2466		  ((com->pc98_8251fifo_enable &&
2467		    (inb(I8251F_lsr) & (STS8251F_TxRDY | STS8251F_TxEMP))
2468		    == (STS8251F_TxRDY | STS8251F_TxEMP)) ||
2469		   (!com->pc98_8251fifo_enable &&
2470		    (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP))
2471		    == (STS8251_TxRDY | STS8251_TxEMP)))) ||
2472		 ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2473		  == (LSR_TSRE | LSR_TXRDY))) {
2474#else
2475	else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2476	    == (LSR_TSRE | LSR_TXRDY)) {
2477#endif
2478		com->tp->t_state &= ~TS_BUSY;
2479		ttwwakeup(com->tp);
2480		com->extra_state &= ~CSE_BUSYCHECK;
2481	} else
2482		timeout(siobusycheck, com, hz / 100);
2483	splx(s);
2484}
2485
2486static void
2487siodtrwakeup(chan)
2488	void	*chan;
2489{
2490	struct com_s	*com;
2491
2492	com = (struct com_s *)chan;
2493	com->state &= ~CS_DTR_OFF;
2494	wakeup(&com->dtr_wait);
2495}
2496
2497static void
2498sioinput(com)
2499	struct com_s	*com;
2500{
2501	u_char		*buf;
2502	int		incc;
2503	u_char		line_status;
2504	int		recv_data;
2505	struct tty	*tp;
2506
2507	buf = com->ibuf;
2508	tp = com->tp;
2509	if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) {
2510		com_events -= (com->iptr - com->ibuf);
2511		com->iptr = com->ibuf;
2512		return;
2513	}
2514	if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
2515		/*
2516		 * Avoid the grotesquely inefficient lineswitch routine
2517		 * (ttyinput) in "raw" mode.  It usually takes about 450
2518		 * instructions (that's without canonical processing or echo!).
2519		 * slinput is reasonably fast (usually 40 instructions plus
2520		 * call overhead).
2521		 */
2522		do {
2523			enable_intr();
2524			incc = com->iptr - buf;
2525			if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
2526			    && (com->state & CS_RTS_IFLOW
2527				|| tp->t_iflag & IXOFF)
2528			    && !(tp->t_state & TS_TBLOCK))
2529				ttyblock(tp);
2530			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
2531				+= b_to_q((char *)buf, incc, &tp->t_rawq);
2532			buf += incc;
2533			tk_nin += incc;
2534			tk_rawcc += incc;
2535			tp->t_rawcc += incc;
2536			ttwakeup(tp);
2537			if (tp->t_state & TS_TTSTOP
2538			    && (tp->t_iflag & IXANY
2539				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
2540				tp->t_state &= ~TS_TTSTOP;
2541				tp->t_lflag &= ~FLUSHO;
2542				comstart(tp);
2543			}
2544			disable_intr();
2545		} while (buf < com->iptr);
2546	} else {
2547		do {
2548			enable_intr();
2549			line_status = buf[com->ierroff];
2550			recv_data = *buf++;
2551			if (line_status
2552			    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
2553				if (line_status & LSR_BI)
2554					recv_data |= TTY_BI;
2555				if (line_status & LSR_FE)
2556					recv_data |= TTY_FE;
2557				if (line_status & LSR_OE)
2558					recv_data |= TTY_OE;
2559				if (line_status & LSR_PE)
2560					recv_data |= TTY_PE;
2561			}
2562			(*linesw[tp->t_line].l_rint)(recv_data, tp);
2563			disable_intr();
2564		} while (buf < com->iptr);
2565	}
2566	com_events -= (com->iptr - com->ibuf);
2567	com->iptr = com->ibuf;
2568
2569	/*
2570	 * There is now room for another low-level buffer full of input,
2571	 * so enable RTS if it is now disabled and there is room in the
2572	 * high-level buffer.
2573	 */
2574#ifdef PC98
2575	if (IS_8251(com->pc98_if_type)) {
2576		if ((com->state & CS_RTS_IFLOW) &&
2577		    !(com_tiocm_get(com) & TIOCM_RTS) &&
2578		    !(tp->t_state & TS_TBLOCK))
2579			com_tiocm_bis(com, TIOCM_RTS);
2580	} else {
2581		if ((com->state & CS_RTS_IFLOW) &&
2582		    !(com->mcr_image & MCR_RTS) &&
2583		    !(tp->t_state & TS_TBLOCK))
2584			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2585	}
2586#else
2587	if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
2588	    !(tp->t_state & TS_TBLOCK))
2589		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2590#endif
2591}
2592
2593void
2594siointr(arg)
2595	void		*arg;
2596{
2597#ifndef COM_MULTIPORT
2598	COM_LOCK();
2599	siointr1((struct com_s *) arg);
2600	COM_UNLOCK();
2601#else /* COM_MULTIPORT */
2602	bool_t		possibly_more_intrs;
2603	int		unit;
2604	struct com_s	*com;
2605#ifdef PC98
2606	u_char		rsa_buf_status;
2607#endif
2608
2609	/*
2610	 * Loop until there is no activity on any port.  This is necessary
2611	 * to get an interrupt edge more than to avoid another interrupt.
2612	 * If the IRQ signal is just an OR of the IRQ signals from several
2613	 * devices, then the edge from one may be lost because another is
2614	 * on.
2615	 */
2616	COM_LOCK();
2617	do {
2618		possibly_more_intrs = FALSE;
2619		for (unit = 0; unit < sio_numunits; ++unit) {
2620			com = com_addr(unit);
2621			/*
2622			 * XXX COM_LOCK();
2623			 * would it work here, or be counter-productive?
2624			 */
2625#ifdef PC98
2626			if (com != NULL
2627			    && !com->gone
2628			    && IS_8251(com->pc98_if_type)){
2629				siointr1(com);
2630			} else
2631#endif /* PC98 */
2632#ifdef PC98
2633			if (com != NULL
2634			    && !com->gone
2635			    && com->pc98_if_type == COM_IF_RSA98III) {
2636			  rsa_buf_status = inb(com->rsabase + rsa_srr) & 0xc9;
2637			  if ((rsa_buf_status & 0xc8)
2638			      || !(rsa_buf_status & 0x01)) {
2639			    siointr1(com);
2640			    if(rsa_buf_status
2641			       != (inb(com->rsabase + rsa_srr) & 0xc9))
2642			      possibly_more_intrs = TRUE;
2643			  }
2644			} else
2645#endif
2646			if (com != NULL
2647			    && !com->gone
2648			    && (inb(com->int_id_port) & IIR_IMASK)
2649			       != IIR_NOPEND) {
2650				siointr1(com);
2651				possibly_more_intrs = TRUE;
2652			}
2653			/* XXX COM_UNLOCK(); */
2654		}
2655	} while (possibly_more_intrs);
2656	COM_UNLOCK();
2657#endif /* COM_MULTIPORT */
2658}
2659
2660static void
2661siointr1(com)
2662	struct com_s	*com;
2663{
2664	u_char	line_status;
2665	u_char	modem_status;
2666	u_char	*ioptr;
2667	u_char	recv_data;
2668	u_char	int_ctl;
2669	u_char	int_ctl_new;
2670	struct	timecounter *tc;
2671	u_int	count;
2672
2673#ifdef PC98
2674	u_char	tmp=0;
2675	u_char	rsa_buf_status = 0;
2676	int	rsa_tx_fifo_size=0;
2677	recv_data=0;
2678#endif /* PC98 */
2679
2680	int_ctl = inb(com->intr_ctl_port);
2681	int_ctl_new = int_ctl;
2682
2683	while (!com->gone) {
2684#ifdef PC98
2685status_read:;
2686		if (IS_8251(com->pc98_if_type)) {
2687			if (com->pc98_8251fifo_enable)
2688				tmp = inb(I8251F_lsr);
2689			else
2690				tmp = inb(com->sts_port);
2691more_intr:
2692			line_status = 0;
2693			if (com->pc98_8251fifo_enable) {
2694			    if (tmp & STS8251F_TxRDY) line_status |= LSR_TXRDY;
2695			    if (tmp & STS8251F_RxRDY) line_status |= LSR_RXRDY;
2696			    if (tmp & STS8251F_TxEMP) line_status |= LSR_TSRE;
2697			    if (tmp & STS8251F_PE)    line_status |= LSR_PE;
2698			    if (tmp & STS8251F_OE)    line_status |= LSR_OE;
2699			    if (tmp & STS8251F_BD_SD) line_status |= LSR_BI;
2700			} else {
2701			    if (tmp & STS8251_TxRDY)  line_status |= LSR_TXRDY;
2702			    if (tmp & STS8251_RxRDY)  line_status |= LSR_RXRDY;
2703			    if (tmp & STS8251_TxEMP)  line_status |= LSR_TSRE;
2704			    if (tmp & STS8251_PE)     line_status |= LSR_PE;
2705			    if (tmp & STS8251_OE)     line_status |= LSR_OE;
2706			    if (tmp & STS8251_FE)     line_status |= LSR_FE;
2707			    if (tmp & STS8251_BD_SD)  line_status |= LSR_BI;
2708			}
2709		} else {
2710#endif /* PC98 */
2711		if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) {
2712			modem_status = inb(com->modem_status_port);
2713		        if ((modem_status ^ com->last_modem_status) & MSR_DCD) {
2714				tc = timecounter;
2715				count = tc->tc_get_timecount(tc);
2716				pps_event(&com->pps, tc, count,
2717				    (modem_status & MSR_DCD) ?
2718				    PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
2719			}
2720		}
2721		line_status = inb(com->line_status_port);
2722#ifdef PC98
2723		}
2724		if (com->pc98_if_type == COM_IF_RSA98III)
2725			rsa_buf_status = inb(com->rsabase + rsa_srr);
2726#endif /* PC98 */
2727
2728		/* input event? (check first to help avoid overruns) */
2729#ifndef PC98
2730		while (line_status & LSR_RCV_MASK) {
2731#else
2732		while ((line_status & LSR_RCV_MASK)
2733		       || (com->pc98_if_type == COM_IF_RSA98III
2734			   && (rsa_buf_status & 0x08))) {
2735#endif /* PC98 */
2736			/* break/unnattached error bits or real input? */
2737#ifdef PC98
2738			if (IS_8251(com->pc98_if_type)) {
2739				if (com->pc98_8251fifo_enable) {
2740				    recv_data = inb(I8251F_data);
2741				    if (tmp & (STS8251F_PE | STS8251F_OE |
2742					       STS8251F_BD_SD)) {
2743					pc98_i8251_or_cmd(com, CMD8251_ER);
2744					recv_data = 0;
2745				    }
2746				} else {
2747				    recv_data = inb(com->data_port);
2748				    if (tmp & (STS8251_PE | STS8251_OE |
2749					       STS8251_FE | STS8251_BD_SD)) {
2750					pc98_i8251_or_cmd(com, CMD8251_ER);
2751					recv_data = 0;
2752				    }
2753				}
2754			} else {
2755#endif /* PC98 */
2756#ifdef PC98
2757			if (com->pc98_if_type == COM_IF_RSA98III) {
2758				if (!(rsa_buf_status & 0x08))
2759					recv_data = 0;
2760				else
2761					recv_data = inb(com->data_port);
2762			} else
2763#endif
2764			if (!(line_status & LSR_RXRDY))
2765				recv_data = 0;
2766			else
2767				recv_data = inb(com->data_port);
2768#ifdef PC98
2769			}
2770#endif
2771			if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
2772				/*
2773				 * Don't store BI if IGNBRK or FE/PE if IGNPAR.
2774				 * Otherwise, push the work to a higher level
2775				 * (to handle PARMRK) if we're bypassing.
2776				 * Otherwise, convert BI/FE and PE+INPCK to 0.
2777				 *
2778				 * This makes bypassing work right in the
2779				 * usual "raw" case (IGNBRK set, and IGNPAR
2780				 * and INPCK clear).
2781				 *
2782				 * Note: BI together with FE/PE means just BI.
2783				 */
2784				if (line_status & LSR_BI) {
2785#if defined(DDB) && defined(BREAK_TO_DEBUGGER)
2786					if (com->unit == comconsole) {
2787						breakpoint();
2788						goto cont;
2789					}
2790#endif
2791					if (com->tp == NULL
2792					    || com->tp->t_iflag & IGNBRK)
2793						goto cont;
2794				} else {
2795					if (com->tp == NULL
2796					    || com->tp->t_iflag & IGNPAR)
2797						goto cont;
2798				}
2799				if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
2800				    && (line_status & (LSR_BI | LSR_FE)
2801					|| com->tp->t_iflag & INPCK))
2802					recv_data = 0;
2803			}
2804			++com->bytes_in;
2805			if (com->hotchar != 0 && recv_data == com->hotchar)
2806				setsofttty();
2807			ioptr = com->iptr;
2808			if (ioptr >= com->ibufend)
2809				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
2810			else {
2811				if (com->do_timestamp)
2812					microtime(&com->timestamp);
2813				++com_events;
2814				schedsofttty();
2815#if 0 /* for testing input latency vs efficiency */
2816if (com->iptr - com->ibuf == 8)
2817	setsofttty();
2818#endif
2819				ioptr[0] = recv_data;
2820				ioptr[com->ierroff] = line_status;
2821				com->iptr = ++ioptr;
2822				if (ioptr == com->ihighwater
2823				    && com->state & CS_RTS_IFLOW)
2824#ifdef PC98
2825					IS_8251(com->pc98_if_type) ?
2826						com_tiocm_bic(com, TIOCM_RTS) :
2827#endif
2828					outb(com->modem_ctl_port,
2829					     com->mcr_image &= ~MCR_RTS);
2830				if (line_status & LSR_OE)
2831					CE_RECORD(com, CE_OVERRUN);
2832			}
2833cont:
2834			/*
2835			 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
2836			 * jump from the top of the loop to here
2837			 */
2838#ifdef PC98
2839			if (IS_8251(com->pc98_if_type))
2840				goto status_read;
2841			else
2842#endif
2843			line_status = inb(com->line_status_port) & 0x7F;
2844#ifdef PC98
2845			if (com->pc98_if_type == COM_IF_RSA98III)
2846				rsa_buf_status = inb(com->rsabase + rsa_srr);
2847#endif /* PC98 */
2848		}
2849
2850		/* modem status change? (always check before doing output) */
2851#ifdef PC98
2852		if (!IS_8251(com->pc98_if_type)) {
2853#endif
2854		modem_status = inb(com->modem_status_port);
2855		if (modem_status != com->last_modem_status) {
2856			if (com->do_dcd_timestamp
2857			    && !(com->last_modem_status & MSR_DCD)
2858			    && modem_status & MSR_DCD)
2859				microtime(&com->dcd_timestamp);
2860
2861			/*
2862			 * Schedule high level to handle DCD changes.  Note
2863			 * that we don't use the delta bits anywhere.  Some
2864			 * UARTs mess them up, and it's easy to remember the
2865			 * previous bits and calculate the delta.
2866			 */
2867			com->last_modem_status = modem_status;
2868			if (!(com->state & CS_CHECKMSR)) {
2869				com_events += LOTS_OF_EVENTS;
2870				com->state |= CS_CHECKMSR;
2871				setsofttty();
2872			}
2873
2874			/* handle CTS change immediately for crisp flow ctl */
2875			if (com->state & CS_CTS_OFLOW) {
2876				if (modem_status & MSR_CTS)
2877					com->state |= CS_ODEVREADY;
2878				else
2879					com->state &= ~CS_ODEVREADY;
2880			}
2881		}
2882#ifdef PC98
2883		}
2884#endif
2885
2886		/* output queued and everything ready? */
2887#ifndef PC98
2888		if (line_status & LSR_TXRDY
2889		    && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2890#else
2891		if (((com->pc98_if_type == COM_IF_RSA98III)
2892		     ? (rsa_buf_status & 0x02)
2893		     : (line_status & LSR_TXRDY))
2894		    && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2895#endif
2896#ifdef PC98
2897			Port_t	tmp_data_port;
2898
2899			if (IS_8251(com->pc98_if_type) &&
2900			    com->pc98_8251fifo_enable)
2901				tmp_data_port = I8251F_data;
2902			else
2903				tmp_data_port = com->data_port;
2904#endif
2905
2906			ioptr = com->obufq.l_head;
2907			if (com->tx_fifo_size > 1) {
2908				u_int	ocount;
2909
2910				ocount = com->obufq.l_tail - ioptr;
2911#ifdef PC98
2912				if (com->pc98_if_type == COM_IF_RSA98III) {
2913				  rsa_buf_status = inb(com->rsabase + rsa_srr);
2914				  rsa_tx_fifo_size = 1024;
2915				  if (!(rsa_buf_status & 0x01))
2916				      rsa_tx_fifo_size = 2048;
2917				  if (ocount > rsa_tx_fifo_size)
2918				      ocount = rsa_tx_fifo_size;
2919				} else
2920#endif
2921				if (ocount > com->tx_fifo_size)
2922					ocount = com->tx_fifo_size;
2923				com->bytes_out += ocount;
2924				do
2925#ifdef PC98
2926					outb(tmp_data_port, *ioptr++);
2927#else
2928					outb(com->data_port, *ioptr++);
2929#endif
2930				while (--ocount != 0);
2931			} else {
2932#ifdef PC98
2933				outb(tmp_data_port, *ioptr++);
2934#else
2935				outb(com->data_port, *ioptr++);
2936#endif
2937				++com->bytes_out;
2938			}
2939#ifdef PC98
2940			if (IS_8251(com->pc98_if_type))
2941			    if (!(pc98_check_i8251_interrupt(com) & IEN_TxFLAG))
2942					com_int_Tx_enable(com);
2943#endif
2944			com->obufq.l_head = ioptr;
2945			if (COM_IIR_TXRDYBUG(com->flags)) {
2946				int_ctl_new = int_ctl | IER_ETXRDY;
2947			}
2948			if (ioptr >= com->obufq.l_tail) {
2949				struct lbq	*qp;
2950
2951				qp = com->obufq.l_next;
2952				qp->l_queued = FALSE;
2953				qp = qp->l_next;
2954				if (qp != NULL) {
2955					com->obufq.l_head = qp->l_head;
2956					com->obufq.l_tail = qp->l_tail;
2957					com->obufq.l_next = qp;
2958				} else {
2959					/* output just completed */
2960					if (COM_IIR_TXRDYBUG(com->flags)) {
2961						int_ctl_new = int_ctl & ~IER_ETXRDY;
2962					}
2963					com->state &= ~CS_BUSY;
2964#if defined(PC98)
2965					if (IS_8251(com->pc98_if_type))
2966					    if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2967						com_int_Tx_disable(com);
2968#endif
2969				}
2970				if (!(com->state & CS_ODONE)) {
2971					com_events += LOTS_OF_EVENTS;
2972					com->state |= CS_ODONE;
2973					setsofttty();	/* handle at high level ASAP */
2974				}
2975			}
2976			if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
2977#ifdef PC98
2978				if (com->pc98_if_type == COM_IF_RSA98III) {
2979				    int_ctl_new &= ~(IER_ETXRDY | IER_ERXRDY);
2980				    outb(com->intr_ctl_port, int_ctl_new);
2981				    outb(com->rsabase + rsa_ier, 0x1d);
2982				} else
2983#endif
2984				outb(com->intr_ctl_port, int_ctl_new);
2985			}
2986		}
2987#ifdef PC98
2988		else if (line_status & LSR_TXRDY) {
2989		    if (IS_8251(com->pc98_if_type))
2990			if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2991			    com_int_Tx_disable(com);
2992		}
2993		if (IS_8251(com->pc98_if_type)) {
2994		    if (com->pc98_8251fifo_enable) {
2995			if ((tmp = inb(I8251F_lsr)) & STS8251F_RxRDY)
2996			    goto more_intr;
2997		    } else {
2998			if ((tmp = inb(com->sts_port)) & STS8251_RxRDY)
2999			    goto more_intr;
3000		    }
3001		}
3002#endif
3003
3004		/* finished? */
3005#ifndef COM_MULTIPORT
3006#ifdef PC98
3007		if (IS_8251(com->pc98_if_type))
3008			return;
3009#endif
3010		if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
3011#endif /* COM_MULTIPORT */
3012			return;
3013	}
3014}
3015
3016static int
3017sioioctl(dev, cmd, data, flag, p)
3018	dev_t		dev;
3019	u_long		cmd;
3020	caddr_t		data;
3021	int		flag;
3022	struct proc	*p;
3023{
3024	struct com_s	*com;
3025	int		error;
3026	Port_t		iobase;
3027	int		mynor;
3028	int		s;
3029	struct tty	*tp;
3030#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
3031	u_long		oldcmd;
3032	struct termios	term;
3033#endif
3034
3035	mynor = minor(dev);
3036	com = com_addr(MINOR_TO_UNIT(mynor));
3037	if (com->gone)
3038		return (ENODEV);
3039	iobase = com->iobase;
3040	if (mynor & CONTROL_MASK) {
3041		struct termios	*ct;
3042
3043		switch (mynor & CONTROL_MASK) {
3044		case CONTROL_INIT_STATE:
3045			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
3046			break;
3047		case CONTROL_LOCK_STATE:
3048			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
3049			break;
3050		default:
3051			return (ENODEV);	/* /dev/nodev */
3052		}
3053		switch (cmd) {
3054		case TIOCSETA:
3055			error = suser(p);
3056			if (error != 0)
3057				return (error);
3058			*ct = *(struct termios *)data;
3059			return (0);
3060		case TIOCGETA:
3061			*(struct termios *)data = *ct;
3062			return (0);
3063		case TIOCGETD:
3064			*(int *)data = TTYDISC;
3065			return (0);
3066		case TIOCGWINSZ:
3067			bzero(data, sizeof(struct winsize));
3068			return (0);
3069		default:
3070			return (ENOTTY);
3071		}
3072	}
3073	tp = com->tp;
3074#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
3075	term = tp->t_termios;
3076	oldcmd = cmd;
3077	error = ttsetcompat(tp, &cmd, data, &term);
3078	if (error != 0)
3079		return (error);
3080	if (cmd != oldcmd)
3081		data = (caddr_t)&term;
3082#endif
3083	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
3084		int	cc;
3085		struct termios *dt = (struct termios *)data;
3086		struct termios *lt = mynor & CALLOUT_MASK
3087				     ? &com->lt_out : &com->lt_in;
3088
3089		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
3090			      | (dt->c_iflag & ~lt->c_iflag);
3091		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
3092			      | (dt->c_oflag & ~lt->c_oflag);
3093		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
3094			      | (dt->c_cflag & ~lt->c_cflag);
3095		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
3096			      | (dt->c_lflag & ~lt->c_lflag);
3097		for (cc = 0; cc < NCCS; ++cc)
3098			if (lt->c_cc[cc] != 0)
3099				dt->c_cc[cc] = tp->t_cc[cc];
3100		if (lt->c_ispeed != 0)
3101			dt->c_ispeed = tp->t_ispeed;
3102		if (lt->c_ospeed != 0)
3103			dt->c_ospeed = tp->t_ospeed;
3104	}
3105	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
3106	if (error != ENOIOCTL)
3107		return (error);
3108	s = spltty();
3109	error = ttioctl(tp, cmd, data, flag);
3110	disc_optim(tp, &tp->t_termios, com);
3111	if (error != ENOIOCTL) {
3112		splx(s);
3113		return (error);
3114	}
3115#ifdef PC98
3116	if (IS_8251(com->pc98_if_type)) {
3117	    switch (cmd) {
3118	    case TIOCSBRK:
3119		com_send_break_on( com );
3120		break;
3121	    case TIOCCBRK:
3122		com_send_break_off( com );
3123		break;
3124	    case TIOCSDTR:
3125		com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS );
3126		break;
3127	    case TIOCCDTR:
3128		com_tiocm_bic(com, TIOCM_DTR);
3129		break;
3130	/*
3131	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
3132	 * changes get undone on the next call to comparam().
3133	 */
3134	    case TIOCMSET:
3135		com_tiocm_set( com, *(int *)data );
3136		break;
3137	    case TIOCMBIS:
3138		com_tiocm_bis( com, *(int *)data );
3139		break;
3140	    case TIOCMBIC:
3141		com_tiocm_bic( com, *(int *)data );
3142		break;
3143	    case TIOCMGET:
3144		*(int *)data = com_tiocm_get(com);
3145		break;
3146	    case TIOCMSDTRWAIT:
3147		/* must be root since the wait applies to following logins */
3148		error = suser(p);
3149		if (error != 0) {
3150			splx(s);
3151			return (error);
3152		}
3153		com->dtr_wait = *(int *)data * hz / 100;
3154		break;
3155	    case TIOCMGDTRWAIT:
3156		*(int *)data = com->dtr_wait * 100 / hz;
3157		break;
3158	    case TIOCTIMESTAMP:
3159		com->do_timestamp = TRUE;
3160		*(struct timeval *)data = com->timestamp;
3161		break;
3162	    case TIOCDCDTIMESTAMP:
3163		com->do_dcd_timestamp = TRUE;
3164		*(struct timeval *)data = com->dcd_timestamp;
3165		break;
3166	    default:
3167		splx(s);
3168		return (ENOTTY);
3169	    }
3170	} else {
3171	    int port_shift;
3172	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
3173#endif
3174	switch (cmd) {
3175	case TIOCSBRK:
3176#ifdef PC98
3177		outb(iobase + (com_cfcr << port_shift),
3178		     com->cfcr_image |= CFCR_SBREAK);
3179#else
3180		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
3181#endif
3182		break;
3183	case TIOCCBRK:
3184#ifdef PC98
3185		outb(iobase + (com_cfcr << port_shift),
3186		     com->cfcr_image &= ~CFCR_SBREAK);
3187#else
3188		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
3189#endif
3190		break;
3191	case TIOCSDTR:
3192		(void)commctl(com, TIOCM_DTR, DMBIS);
3193		break;
3194	case TIOCCDTR:
3195		(void)commctl(com, TIOCM_DTR, DMBIC);
3196		break;
3197	/*
3198	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
3199	 * changes get undone on the next call to comparam().
3200	 */
3201	case TIOCMSET:
3202		(void)commctl(com, *(int *)data, DMSET);
3203		break;
3204	case TIOCMBIS:
3205		(void)commctl(com, *(int *)data, DMBIS);
3206		break;
3207	case TIOCMBIC:
3208		(void)commctl(com, *(int *)data, DMBIC);
3209		break;
3210	case TIOCMGET:
3211		*(int *)data = commctl(com, 0, DMGET);
3212		break;
3213	case TIOCMSDTRWAIT:
3214		/* must be root since the wait applies to following logins */
3215		error = suser(p);
3216		if (error != 0) {
3217			splx(s);
3218			return (error);
3219		}
3220		com->dtr_wait = *(int *)data * hz / 100;
3221		break;
3222	case TIOCMGDTRWAIT:
3223		*(int *)data = com->dtr_wait * 100 / hz;
3224		break;
3225	case TIOCTIMESTAMP:
3226		com->do_timestamp = TRUE;
3227		*(struct timeval *)data = com->timestamp;
3228		break;
3229	case TIOCDCDTIMESTAMP:
3230		com->do_dcd_timestamp = TRUE;
3231		*(struct timeval *)data = com->dcd_timestamp;
3232		break;
3233	default:
3234		splx(s);
3235		error = pps_ioctl(cmd, data, &com->pps);
3236		if (error == ENODEV)
3237			error = ENOTTY;
3238		return (error);
3239	}
3240#ifdef PC98
3241	}
3242#endif
3243	splx(s);
3244	return (0);
3245}
3246
3247static void
3248siopoll()
3249{
3250	int		unit;
3251
3252	if (com_events == 0)
3253		return;
3254repeat:
3255	for (unit = 0; unit < sio_numunits; ++unit) {
3256		struct com_s	*com;
3257		int		incc;
3258		struct tty	*tp;
3259
3260		com = com_addr(unit);
3261		if (com == NULL)
3262			continue;
3263		tp = com->tp;
3264		if (tp == NULL || com->gone) {
3265			/*
3266			 * Discard any events related to never-opened or
3267			 * going-away devices.
3268			 */
3269			disable_intr();
3270			incc = com->iptr - com->ibuf;
3271			com->iptr = com->ibuf;
3272			if (com->state & CS_CHECKMSR) {
3273				incc += LOTS_OF_EVENTS;
3274				com->state &= ~CS_CHECKMSR;
3275			}
3276			com_events -= incc;
3277			enable_intr();
3278			continue;
3279		}
3280		if (com->iptr != com->ibuf) {
3281			disable_intr();
3282			sioinput(com);
3283			enable_intr();
3284		}
3285		if (com->state & CS_CHECKMSR) {
3286			u_char	delta_modem_status;
3287
3288#ifdef PC98
3289			if (!IS_8251(com->pc98_if_type)) {
3290#endif
3291			disable_intr();
3292			delta_modem_status = com->last_modem_status
3293					     ^ com->prev_modem_status;
3294			com->prev_modem_status = com->last_modem_status;
3295			com_events -= LOTS_OF_EVENTS;
3296			com->state &= ~CS_CHECKMSR;
3297			enable_intr();
3298			if (delta_modem_status & MSR_DCD)
3299				(*linesw[tp->t_line].l_modem)
3300					(tp, com->prev_modem_status & MSR_DCD);
3301#ifdef PC98
3302			}
3303#endif
3304		}
3305		if (com->state & CS_ODONE) {
3306			disable_intr();
3307			com_events -= LOTS_OF_EVENTS;
3308			com->state &= ~CS_ODONE;
3309			enable_intr();
3310			if (!(com->state & CS_BUSY)
3311			    && !(com->extra_state & CSE_BUSYCHECK)) {
3312				timeout(siobusycheck, com, hz / 100);
3313				com->extra_state |= CSE_BUSYCHECK;
3314			}
3315			(*linesw[tp->t_line].l_start)(tp);
3316		}
3317		if (com_events == 0)
3318			break;
3319	}
3320	if (com_events >= LOTS_OF_EVENTS)
3321		goto repeat;
3322}
3323
3324static int
3325comparam(tp, t)
3326	struct tty	*tp;
3327	struct termios	*t;
3328{
3329	u_int		cfcr;
3330	int		cflag;
3331	struct com_s	*com;
3332	int		divisor;
3333	u_char		dlbh;
3334	u_char		dlbl;
3335	Port_t		iobase;
3336	int		s;
3337	int		unit;
3338#ifdef PC98
3339	int		port_shift = 0;
3340	u_char		param = 0;
3341#endif
3342
3343#ifdef PC98
3344	cfcr = 0;
3345	unit = DEV_TO_UNIT(tp->t_dev);
3346	com = com_addr(unit);
3347	iobase = com->iobase;
3348	if (IS_8251(com->pc98_if_type)) {
3349	    divisor = pc98_ttspeedtab(com, t->c_ospeed);
3350	} else {
3351	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
3352
3353	    /* do historical conversions */
3354	    if (t->c_ispeed == 0)
3355		t->c_ispeed = t->c_ospeed;
3356
3357	    /* check requested parameters */
3358	    divisor = ttspeedtab(t->c_ospeed,
3359			if_16550a_type[com->pc98_if_type & 0x0f].speedtab);
3360	}
3361#else
3362	/* do historical conversions */
3363	if (t->c_ispeed == 0)
3364		t->c_ispeed = t->c_ospeed;
3365
3366	/* check requested parameters */
3367	divisor = ttspeedtab(t->c_ospeed, comspeedtab);
3368#endif
3369	if (divisor < 0 || (divisor > 0 && t->c_ispeed != t->c_ospeed))
3370		return (EINVAL);
3371
3372	/* parameters are OK, convert them to the com struct and the device */
3373#ifndef PC98
3374	unit = DEV_TO_UNIT(tp->t_dev);
3375	com = com_addr(unit);
3376	iobase = com->iobase;
3377#endif
3378	s = spltty();
3379#ifdef PC98
3380	if (IS_8251(com->pc98_if_type)) {
3381		if (divisor == 0)
3382			com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
3383		else
3384			com_tiocm_bis( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
3385	} else {
3386#endif
3387	if (divisor == 0)
3388		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
3389	else
3390		(void)commctl(com, TIOCM_DTR, DMBIS);
3391#ifdef PC98
3392	}
3393#endif
3394	cflag = t->c_cflag;
3395#ifdef PC98
3396	if (!IS_8251(com->pc98_if_type)) {
3397#endif
3398	switch (cflag & CSIZE) {
3399	case CS5:
3400		cfcr = CFCR_5BITS;
3401		break;
3402	case CS6:
3403		cfcr = CFCR_6BITS;
3404		break;
3405	case CS7:
3406		cfcr = CFCR_7BITS;
3407		break;
3408	default:
3409		cfcr = CFCR_8BITS;
3410		break;
3411	}
3412	if (cflag & PARENB) {
3413		cfcr |= CFCR_PENAB;
3414		if (!(cflag & PARODD))
3415			cfcr |= CFCR_PEVEN;
3416	}
3417	if (cflag & CSTOPB)
3418		cfcr |= CFCR_STOPB;
3419
3420	if (com->hasfifo && divisor != 0) {
3421		/*
3422		 * Use a fifo trigger level low enough so that the input
3423		 * latency from the fifo is less than about 16 msec and
3424		 * the total latency is less than about 30 msec.  These
3425		 * latencies are reasonable for humans.  Serial comms
3426		 * protocols shouldn't expect anything better since modem
3427		 * latencies are larger.
3428		 */
3429		com->fifo_image = t->c_ospeed <= 4800
3430				  ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
3431#ifdef COM_ESP
3432		/*
3433		 * The Hayes ESP card needs the fifo DMA mode bit set
3434		 * in compatibility mode.  If not, it will interrupt
3435		 * for each character received.
3436		 */
3437		if (com->esp)
3438			com->fifo_image |= FIFO_DMA_MODE;
3439#endif
3440#ifdef PC98
3441		outb(iobase + (com_fifo << port_shift), com->fifo_image);
3442#else
3443		outb(iobase + com_fifo, com->fifo_image);
3444#endif
3445	}
3446#ifdef PC98
3447	}
3448#endif
3449
3450	/*
3451	 * This returns with interrupts disabled so that we can complete
3452	 * the speed change atomically.  Keeping interrupts disabled is
3453	 * especially important while com_data is hidden.
3454	 */
3455	(void) siosetwater(com, t->c_ispeed);
3456
3457#ifdef PC98
3458	if (IS_8251(com->pc98_if_type))
3459	    com_cflag_and_speed_set(com, cflag, t->c_ospeed);
3460	else {
3461#endif
3462	if (divisor != 0) {
3463#ifdef PC98
3464		outb(iobase + (com_cfcr << port_shift), cfcr | CFCR_DLAB);
3465#else
3466		outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
3467#endif
3468		/*
3469		 * Only set the divisor registers if they would change,
3470		 * since on some 16550 incompatibles (UMC8669F), setting
3471		 * them while input is arriving them loses sync until
3472		 * data stops arriving.
3473		 */
3474		dlbl = divisor & 0xFF;
3475#ifdef PC98
3476		if (inb(iobase + (com_dlbl << port_shift)) != dlbl)
3477			outb(iobase + (com_dlbl << port_shift), dlbl);
3478		dlbh = (u_int) divisor >> 8;
3479		if (inb(iobase + (com_dlbh << port_shift)) != dlbh)
3480			outb(iobase + (com_dlbh << port_shift), dlbh);
3481#else
3482		if (inb(iobase + com_dlbl) != dlbl)
3483			outb(iobase + com_dlbl, dlbl);
3484		dlbh = (u_int) divisor >> 8;
3485		if (inb(iobase + com_dlbh) != dlbh)
3486			outb(iobase + com_dlbh, dlbh);
3487#endif
3488	}
3489
3490
3491#ifdef PC98
3492	}
3493	outb(iobase + (com_cfcr << port_shift), com->cfcr_image = cfcr);
3494#else
3495	outb(iobase + com_cfcr, com->cfcr_image = cfcr);
3496#endif
3497
3498	if (!(tp->t_state & TS_TTSTOP))
3499		com->state |= CS_TTGO;
3500
3501	if (cflag & CRTS_IFLOW) {
3502		if (com->st16650a) {
3503			outb(iobase + com_cfcr, 0xbf);
3504			outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40);
3505		}
3506		com->state |= CS_RTS_IFLOW;
3507		/*
3508		 * If CS_RTS_IFLOW just changed from off to on, the change
3509		 * needs to be propagated to MCR_RTS.  This isn't urgent,
3510		 * so do it later by calling comstart() instead of repeating
3511		 * a lot of code from comstart() here.
3512		 */
3513	} else if (com->state & CS_RTS_IFLOW) {
3514		com->state &= ~CS_RTS_IFLOW;
3515		/*
3516		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
3517		 * on here, since comstart() won't do it later.
3518		 */
3519#ifdef PC98
3520		if (IS_8251(com->pc98_if_type))
3521			com_tiocm_bis(com, TIOCM_RTS);
3522		else
3523#endif
3524		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
3525		if (com->st16650a) {
3526			outb(iobase + com_cfcr, 0xbf);
3527			outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40);
3528		}
3529	}
3530
3531
3532	/*
3533	 * Set up state to handle output flow control.
3534	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
3535	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
3536	 */
3537	com->state |= CS_ODEVREADY;
3538	com->state &= ~CS_CTS_OFLOW;
3539#ifdef PC98
3540	if (com->pc98_if_type == COM_IF_RSA98III) {
3541		param = inb(com->rsabase + rsa_msr);
3542		outb(com->rsabase + rsa_msr, param & 0x14);
3543	}
3544#endif
3545	if (cflag & CCTS_OFLOW) {
3546		com->state |= CS_CTS_OFLOW;
3547#ifdef PC98
3548		if (IS_8251(com->pc98_if_type)) {
3549			if (!(pc98_get_modem_status(com) & TIOCM_CTS))
3550				com->state &= ~CS_ODEVREADY;
3551		} else {
3552#endif
3553#ifdef PC98
3554		if (com->pc98_if_type == COM_IF_RSA98III) {
3555			/* Set automatic flow control mode */
3556			outb(com->rsabase + rsa_msr, param | 0x08);
3557		} else
3558#endif
3559		if (!(com->last_modem_status & MSR_CTS))
3560			com->state &= ~CS_ODEVREADY;
3561		if (com->st16650a) {
3562			outb(iobase + com_cfcr, 0xbf);
3563			outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80);
3564		}
3565#ifdef PC98
3566		}
3567#endif
3568	} else {
3569		if (com->st16650a) {
3570			outb(iobase + com_cfcr, 0xbf);
3571			outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80);
3572		}
3573	}
3574
3575
3576#ifdef PC98
3577	outb(iobase + (com_cfcr << port_shift), com->cfcr_image);
3578#else
3579	outb(iobase + com_cfcr, com->cfcr_image);
3580#endif
3581
3582
3583	/* XXX shouldn't call functions while intrs are disabled. */
3584	disc_optim(tp, t, com);
3585	/*
3586	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
3587	 * unconditionally, but that defeated the careful discarding of
3588	 * stale input in sioopen().
3589	 */
3590	if (com->state >= (CS_BUSY | CS_TTGO))
3591		siointr1(com);
3592
3593	enable_intr();
3594	splx(s);
3595	comstart(tp);
3596	if (com->ibufold != NULL) {
3597		free(com->ibufold, M_DEVBUF);
3598		com->ibufold = NULL;
3599	}
3600	return (0);
3601}
3602
3603static int
3604siosetwater(com, speed)
3605	struct com_s	*com;
3606	speed_t		speed;
3607{
3608	int		cp4ticks;
3609	u_char		*ibuf;
3610	int		ibufsize;
3611	struct tty	*tp;
3612
3613	/*
3614	 * Make the buffer size large enough to handle a softtty interrupt
3615	 * latency of about 2 ticks without loss of throughput or data
3616	 * (about 3 ticks if input flow control is not used or not honoured,
3617	 * but a bit less for CS5-CS7 modes).
3618	 */
3619	cp4ticks = speed / 10 / hz * 4;
3620	for (ibufsize = 128; ibufsize < cp4ticks;)
3621		ibufsize <<= 1;
3622#ifdef PC98
3623	if (com->pc98_if_type == COM_IF_RSA98III)
3624		ibufsize = 2048;
3625#endif
3626	if (ibufsize == com->ibufsize) {
3627		disable_intr();
3628		return (0);
3629	}
3630
3631	/*
3632	 * Allocate input buffer.  The extra factor of 2 in the size is
3633	 * to allow for an error byte for each input byte.
3634	 */
3635	ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
3636	if (ibuf == NULL) {
3637		disable_intr();
3638		return (ENOMEM);
3639	}
3640
3641	/* Initialize non-critical variables. */
3642	com->ibufold = com->ibuf;
3643	com->ibufsize = ibufsize;
3644	tp = com->tp;
3645	if (tp != NULL) {
3646		tp->t_ififosize = 2 * ibufsize;
3647		tp->t_ispeedwat = (speed_t)-1;
3648		tp->t_ospeedwat = (speed_t)-1;
3649	}
3650
3651	/*
3652	 * Read current input buffer, if any.  Continue with interrupts
3653	 * disabled.
3654	 */
3655	disable_intr();
3656	if (com->iptr != com->ibuf)
3657		sioinput(com);
3658
3659	/*-
3660	 * Initialize critical variables, including input buffer watermarks.
3661	 * The external device is asked to stop sending when the buffer
3662	 * exactly reaches high water, or when the high level requests it.
3663	 * The high level is notified immediately (rather than at a later
3664	 * clock tick) when this watermark is reached.
3665	 * The buffer size is chosen so the watermark should almost never
3666	 * be reached.
3667	 * The low watermark is invisibly 0 since the buffer is always
3668	 * emptied all at once.
3669	 */
3670	com->iptr = com->ibuf = ibuf;
3671	com->ibufend = ibuf + ibufsize;
3672	com->ierroff = ibufsize;
3673	com->ihighwater = ibuf + 3 * ibufsize / 4;
3674	return (0);
3675}
3676
3677static void
3678comstart(tp)
3679	struct tty	*tp;
3680{
3681	struct com_s	*com;
3682	int		s;
3683	int		unit;
3684
3685	unit = DEV_TO_UNIT(tp->t_dev);
3686	com = com_addr(unit);
3687	s = spltty();
3688	disable_intr();
3689	if (tp->t_state & TS_TTSTOP)
3690		com->state &= ~CS_TTGO;
3691	else
3692		com->state |= CS_TTGO;
3693	if (tp->t_state & TS_TBLOCK) {
3694#ifdef PC98
3695		if (IS_8251(com->pc98_if_type)) {
3696		    if ((com_tiocm_get(com) & TIOCM_RTS) &&
3697			(com->state & CS_RTS_IFLOW))
3698			com_tiocm_bic(com, TIOCM_RTS);
3699		} else {
3700		    if ((com->mcr_image & MCR_RTS) &&
3701			(com->state & CS_RTS_IFLOW))
3702			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
3703		}
3704#else
3705		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
3706			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
3707#endif
3708	} else {
3709#ifdef PC98
3710		if (IS_8251(com->pc98_if_type)) {
3711		    if (!(com_tiocm_get(com) & TIOCM_RTS) &&
3712			com->iptr < com->ihighwater &&
3713			com->state & CS_RTS_IFLOW)
3714			com_tiocm_bis(com, TIOCM_RTS);
3715		} else {
3716		    if (!(com->mcr_image & MCR_RTS) &&
3717			com->iptr < com->ihighwater &&
3718			com->state & CS_RTS_IFLOW)
3719			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
3720		}
3721#else
3722		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
3723		    && com->state & CS_RTS_IFLOW)
3724			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
3725#endif
3726	}
3727	enable_intr();
3728	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
3729		ttwwakeup(tp);
3730#ifdef PC98
3731/*		if(IS_8251(com->pc98_if_type))
3732			com_int_Tx_enable(com); */
3733#endif
3734		splx(s);
3735		return;
3736	}
3737	if (tp->t_outq.c_cc != 0) {
3738		struct lbq	*qp;
3739		struct lbq	*next;
3740
3741		if (!com->obufs[0].l_queued) {
3742			com->obufs[0].l_tail
3743			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
3744#ifndef PC98
3745						  sizeof com->obuf1);
3746#else
3747						  com->obufsize);
3748#endif
3749			com->obufs[0].l_next = NULL;
3750			com->obufs[0].l_queued = TRUE;
3751			disable_intr();
3752			if (com->state & CS_BUSY) {
3753				qp = com->obufq.l_next;
3754				while ((next = qp->l_next) != NULL)
3755					qp = next;
3756				qp->l_next = &com->obufs[0];
3757			} else {
3758				com->obufq.l_head = com->obufs[0].l_head;
3759				com->obufq.l_tail = com->obufs[0].l_tail;
3760				com->obufq.l_next = &com->obufs[0];
3761				com->state |= CS_BUSY;
3762			}
3763			enable_intr();
3764		}
3765		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
3766			com->obufs[1].l_tail
3767			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
3768#ifndef PC98
3769						  sizeof com->obuf2);
3770#else
3771						  com->obufsize);
3772#endif
3773			com->obufs[1].l_next = NULL;
3774			com->obufs[1].l_queued = TRUE;
3775			disable_intr();
3776			if (com->state & CS_BUSY) {
3777				qp = com->obufq.l_next;
3778				while ((next = qp->l_next) != NULL)
3779					qp = next;
3780				qp->l_next = &com->obufs[1];
3781			} else {
3782				com->obufq.l_head = com->obufs[1].l_head;
3783				com->obufq.l_tail = com->obufs[1].l_tail;
3784				com->obufq.l_next = &com->obufs[1];
3785				com->state |= CS_BUSY;
3786			}
3787			enable_intr();
3788		}
3789		tp->t_state |= TS_BUSY;
3790	}
3791	disable_intr();
3792	if (com->state >= (CS_BUSY | CS_TTGO))
3793		siointr1(com);	/* fake interrupt to start output */
3794	enable_intr();
3795#ifdef PC98
3796/*		if(IS_8251(com->pc98_if_type))
3797			com_int_Tx_enable(com); */
3798#endif
3799	ttwwakeup(tp);
3800	splx(s);
3801}
3802
3803static void
3804comstop(tp, rw)
3805	struct tty	*tp;
3806	int		rw;
3807{
3808	struct com_s	*com;
3809#ifdef PC98
3810	int		port_shift = 0;
3811	int		rsa98_tmp  = 0;
3812#endif
3813
3814	com = com_addr(DEV_TO_UNIT(tp->t_dev));
3815	if (com->gone)
3816		return;
3817#ifdef PC98
3818	if (!IS_8251(com->pc98_if_type))
3819	    port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift;
3820#endif
3821	disable_intr();
3822	if (rw & FWRITE) {
3823		if (com->hasfifo)
3824#ifdef COM_ESP
3825		    /* XXX avoid h/w bug. */
3826		    if (!com->esp)
3827#endif
3828#ifdef PC98
3829			outb(com->iobase + (com_fifo << port_shift),
3830			     FIFO_XMT_RST | com->fifo_image);
3831			if (com->pc98_if_type == COM_IF_RSA98III)
3832			    for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++)
3833				outb(com->iobase + (com_fifo << port_shift),
3834				     FIFO_XMT_RST | com->fifo_image);
3835#else
3836			outb(com->iobase + com_fifo,
3837			     FIFO_XMT_RST | com->fifo_image);
3838#endif
3839		com->obufs[0].l_queued = FALSE;
3840		com->obufs[1].l_queued = FALSE;
3841		if (com->state & CS_ODONE)
3842			com_events -= LOTS_OF_EVENTS;
3843		com->state &= ~(CS_ODONE | CS_BUSY);
3844		com->tp->t_state &= ~TS_BUSY;
3845	}
3846	if (rw & FREAD) {
3847		if (com->hasfifo)
3848#ifdef COM_ESP
3849		    /* XXX avoid h/w bug. */
3850		    if (!com->esp)
3851#endif
3852#ifdef PC98
3853			if (com->pc98_if_type == COM_IF_RSA98III) {
3854			    for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++)
3855				inb(com->data_port);
3856			}
3857			outb(com->iobase + (com_fifo << port_shift),
3858			     FIFO_RCV_RST | com->fifo_image);
3859#else
3860			outb(com->iobase + com_fifo,
3861			     FIFO_RCV_RST | com->fifo_image);
3862#endif
3863		com_events -= (com->iptr - com->ibuf);
3864		com->iptr = com->ibuf;
3865	}
3866	enable_intr();
3867	comstart(tp);
3868}
3869
3870static int
3871commctl(com, bits, how)
3872	struct com_s	*com;
3873	int		bits;
3874	int		how;
3875{
3876	int	mcr;
3877	int	msr;
3878
3879	if (how == DMGET) {
3880		bits = TIOCM_LE;	/* XXX - always enabled while open */
3881		mcr = com->mcr_image;
3882		if (mcr & MCR_DTR)
3883			bits |= TIOCM_DTR;
3884		if (mcr & MCR_RTS)
3885			bits |= TIOCM_RTS;
3886		msr = com->prev_modem_status;
3887		if (msr & MSR_CTS)
3888			bits |= TIOCM_CTS;
3889		if (msr & MSR_DCD)
3890			bits |= TIOCM_CD;
3891		if (msr & MSR_DSR)
3892			bits |= TIOCM_DSR;
3893		/*
3894		 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
3895		 * more volatile by reading the modem status a lot.  Perhaps
3896		 * we should latch both bits until the status is read here.
3897		 */
3898		if (msr & (MSR_RI | MSR_TERI))
3899			bits |= TIOCM_RI;
3900		return (bits);
3901	}
3902	mcr = 0;
3903	if (bits & TIOCM_DTR)
3904		mcr |= MCR_DTR;
3905	if (bits & TIOCM_RTS)
3906		mcr |= MCR_RTS;
3907	if (com->gone)
3908		return(0);
3909	disable_intr();
3910	switch (how) {
3911	case DMSET:
3912		outb(com->modem_ctl_port,
3913		     com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
3914		break;
3915	case DMBIS:
3916		outb(com->modem_ctl_port, com->mcr_image |= mcr);
3917		break;
3918	case DMBIC:
3919		outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
3920		break;
3921	}
3922	enable_intr();
3923	return (0);
3924}
3925
3926static void
3927siosettimeout()
3928{
3929	struct com_s	*com;
3930	bool_t		someopen;
3931	int		unit;
3932
3933	/*
3934	 * Set our timeout period to 1 second if no polled devices are open.
3935	 * Otherwise set it to max(1/200, 1/hz).
3936	 * Enable timeouts iff some device is open.
3937	 */
3938	untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
3939	sio_timeout = hz;
3940	someopen = FALSE;
3941	for (unit = 0; unit < sio_numunits; ++unit) {
3942		com = com_addr(unit);
3943		if (com != NULL && com->tp != NULL
3944		    && com->tp->t_state & TS_ISOPEN && !com->gone) {
3945			someopen = TRUE;
3946			if (com->poll || com->poll_output) {
3947				sio_timeout = hz > 200 ? hz / 200 : 1;
3948				break;
3949			}
3950		}
3951	}
3952	if (someopen) {
3953		sio_timeouts_until_log = hz / sio_timeout;
3954		sio_timeout_handle = timeout(comwakeup, (void *)NULL,
3955					     sio_timeout);
3956	} else {
3957		/* Flush error messages, if any. */
3958		sio_timeouts_until_log = 1;
3959		comwakeup((void *)NULL);
3960		untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
3961	}
3962}
3963
3964static void
3965comwakeup(chan)
3966	void	*chan;
3967{
3968	struct com_s	*com;
3969	int		unit;
3970
3971	sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
3972
3973	/*
3974	 * Recover from lost output interrupts.
3975	 * Poll any lines that don't use interrupts.
3976	 */
3977	for (unit = 0; unit < sio_numunits; ++unit) {
3978		com = com_addr(unit);
3979		if (com != NULL && !com->gone
3980		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
3981			disable_intr();
3982			siointr1(com);
3983			enable_intr();
3984		}
3985	}
3986
3987	/*
3988	 * Check for and log errors, but not too often.
3989	 */
3990	if (--sio_timeouts_until_log > 0)
3991		return;
3992	sio_timeouts_until_log = hz / sio_timeout;
3993	for (unit = 0; unit < sio_numunits; ++unit) {
3994		int	errnum;
3995
3996		com = com_addr(unit);
3997		if (com == NULL)
3998			continue;
3999		if (com->gone)
4000			continue;
4001		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
4002			u_int	delta;
4003			u_long	total;
4004
4005			disable_intr();
4006			delta = com->delta_error_counts[errnum];
4007			com->delta_error_counts[errnum] = 0;
4008			enable_intr();
4009			if (delta == 0)
4010				continue;
4011			total = com->error_counts[errnum] += delta;
4012			log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
4013			    unit, delta, error_desc[errnum],
4014			    delta == 1 ? "" : "s", total);
4015		}
4016	}
4017}
4018
4019#ifdef PC98
4020/* commint is called when modem control line changes */
4021static void
4022commint(dev_t dev)
4023{
4024	register struct tty *tp;
4025	int	stat,delta;
4026	struct com_s *com;
4027	int	mynor,unit;
4028
4029	mynor = minor(dev);
4030	unit = MINOR_TO_UNIT(mynor);
4031	com = com_addr(unit);
4032	tp = com->tp;
4033
4034	stat = com_tiocm_get(com);
4035	delta = com_tiocm_get_delta(com);
4036
4037	if (com->state & CS_CTS_OFLOW) {
4038		if (stat & TIOCM_CTS)
4039			com->state |= CS_ODEVREADY;
4040		else
4041			com->state &= ~CS_ODEVREADY;
4042	}
4043	if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) {
4044	    if (stat & TIOCM_CAR )
4045		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
4046	    else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
4047		/* negate DTR, RTS */
4048		com_tiocm_bic(com, (tp->t_cflag & HUPCL) ?
4049				TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE );
4050		/* disable IENABLE */
4051		com_int_TxRx_disable( com );
4052	    }
4053	}
4054}
4055#endif
4056
4057static void
4058disc_optim(tp, t, com)
4059	struct tty	*tp;
4060	struct termios	*t;
4061	struct com_s	*com;
4062{
4063	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
4064	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
4065	    && (!(t->c_iflag & PARMRK)
4066		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
4067	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
4068	    && linesw[tp->t_line].l_rint == ttyinput)
4069		tp->t_state |= TS_CAN_BYPASS_L_RINT;
4070	else
4071		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
4072	com->hotchar = linesw[tp->t_line].l_hotchar;
4073}
4074
4075/*
4076 * Following are all routines needed for SIO to act as console
4077 */
4078#include <sys/cons.h>
4079
4080struct siocnstate {
4081	u_char	dlbl;
4082	u_char	dlbh;
4083	u_char	ier;
4084	u_char	cfcr;
4085	u_char	mcr;
4086};
4087
4088static speed_t siocngetspeed __P((Port_t, struct speedtab *));
4089static void siocnclose	__P((struct siocnstate *sp, Port_t iobase));
4090static void siocnopen	__P((struct siocnstate *sp, Port_t iobase, int speed));
4091static void siocntxwait	__P((Port_t iobase));
4092
4093static cn_probe_t siocnprobe;
4094static cn_init_t siocninit;
4095static cn_checkc_t siocncheckc;
4096static cn_getc_t siocngetc;
4097static cn_putc_t siocnputc;
4098
4099#ifdef __i386__
4100CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc,
4101	    siocnputc, NULL);
4102#endif
4103
4104/* To get the GDB related variables */
4105#if DDB > 0
4106#include <ddb/ddb.h>
4107#endif
4108
4109static void
4110siocntxwait(iobase)
4111	Port_t	iobase;
4112{
4113	int	timo;
4114
4115	/*
4116	 * Wait for any pending transmission to finish.  Required to avoid
4117	 * the UART lockup bug when the speed is changed, and for normal
4118	 * transmits.
4119	 */
4120	timo = 100000;
4121	while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
4122	       != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
4123		;
4124}
4125
4126/*
4127 * Read the serial port specified and try to figure out what speed
4128 * it's currently running at.  We're assuming the serial port has
4129 * been initialized and is basicly idle.  This routine is only intended
4130 * to be run at system startup.
4131 *
4132 * If the value read from the serial port doesn't make sense, return 0.
4133 */
4134
4135static speed_t
4136siocngetspeed(iobase, table)
4137	Port_t iobase;
4138	struct speedtab *table;
4139{
4140	int	code;
4141	u_char	dlbh;
4142	u_char	dlbl;
4143	u_char  cfcr;
4144
4145	cfcr = inb(iobase + com_cfcr);
4146	outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
4147
4148	dlbl = inb(iobase + com_dlbl);
4149	dlbh = inb(iobase + com_dlbh);
4150
4151	outb(iobase + com_cfcr, cfcr);
4152
4153	code = dlbh << 8 | dlbl;
4154
4155	for (; table->sp_speed != -1; table++)
4156		if (table->sp_code == code)
4157			return (table->sp_speed);
4158
4159	return 0;	/* didn't match anything sane */
4160}
4161
4162static void
4163siocnopen(sp, iobase, speed)
4164	struct siocnstate	*sp;
4165	Port_t			iobase;
4166	int			speed;
4167{
4168	int	divisor;
4169	u_char	dlbh;
4170	u_char	dlbl;
4171
4172	/*
4173	 * Save all the device control registers except the fifo register
4174	 * and set our default ones (cs8 -parenb speed=comdefaultrate).
4175	 * We can't save the fifo register since it is read-only.
4176	 */
4177	sp->ier = inb(iobase + com_ier);
4178	outb(iobase + com_ier, 0);	/* spltty() doesn't stop siointr() */
4179	siocntxwait(iobase);
4180	sp->cfcr = inb(iobase + com_cfcr);
4181	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
4182	sp->dlbl = inb(iobase + com_dlbl);
4183	sp->dlbh = inb(iobase + com_dlbh);
4184	/*
4185	 * Only set the divisor registers if they would change, since on
4186	 * some 16550 incompatibles (Startech), setting them clears the
4187	 * data input register.  This also reduces the effects of the
4188	 * UMC8669F bug.
4189	 */
4190	divisor = ttspeedtab(speed, comspeedtab);
4191	dlbl = divisor & 0xFF;
4192	if (sp->dlbl != dlbl)
4193		outb(iobase + com_dlbl, dlbl);
4194	dlbh = (u_int) divisor >> 8;
4195	if (sp->dlbh != dlbh)
4196		outb(iobase + com_dlbh, dlbh);
4197	outb(iobase + com_cfcr, CFCR_8BITS);
4198	sp->mcr = inb(iobase + com_mcr);
4199	/*
4200	 * We don't want interrupts, but must be careful not to "disable"
4201	 * them by clearing the MCR_IENABLE bit, since that might cause
4202	 * an interrupt by floating the IRQ line.
4203	 */
4204	outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
4205}
4206
4207static void
4208siocnclose(sp, iobase)
4209	struct siocnstate	*sp;
4210	Port_t			iobase;
4211{
4212	/*
4213	 * Restore the device control registers.
4214	 */
4215	siocntxwait(iobase);
4216	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
4217	if (sp->dlbl != inb(iobase + com_dlbl))
4218		outb(iobase + com_dlbl, sp->dlbl);
4219	if (sp->dlbh != inb(iobase + com_dlbh))
4220		outb(iobase + com_dlbh, sp->dlbh);
4221	outb(iobase + com_cfcr, sp->cfcr);
4222	/*
4223	 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
4224	 */
4225	outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
4226	outb(iobase + com_ier, sp->ier);
4227}
4228
4229static void
4230siocnprobe(cp)
4231	struct consdev	*cp;
4232{
4233	speed_t			boot_speed;
4234	u_char			cfcr;
4235	int			s, unit;
4236	struct siocnstate	sp;
4237
4238	/*
4239	 * Find our first enabled console, if any.  If it is a high-level
4240	 * console device, then initialize it and return successfully.
4241	 * If it is a low-level console device, then initialize it and
4242	 * return unsuccessfully.  It must be initialized in both cases
4243	 * for early use by console drivers and debuggers.  Initializing
4244	 * the hardware is not necessary in all cases, since the i/o
4245	 * routines initialize it on the fly, but it is necessary if
4246	 * input might arrive while the hardware is switched back to an
4247	 * uninitialized state.  We can't handle multiple console devices
4248	 * yet because our low-level routines don't take a device arg.
4249	 * We trust the user to set the console flags properly so that we
4250	 * don't need to probe.
4251	 */
4252	cp->cn_pri = CN_DEAD;
4253
4254	for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
4255		int flags;
4256		int disabled;
4257		if (resource_int_value("sio", unit, "disabled", &disabled) == 0) {
4258			if (disabled)
4259				continue;
4260		}
4261		if (resource_int_value("sio", unit, "flags", &flags))
4262			continue;
4263		if (COM_CONSOLE(flags) || COM_DEBUGGER(flags)) {
4264			int port;
4265			Port_t iobase;
4266
4267			if (resource_int_value("sio", unit, "port", &port))
4268				continue;
4269			iobase = port;
4270			s = spltty();
4271			if (boothowto & RB_SERIAL) {
4272				boot_speed = siocngetspeed(iobase, comspeedtab);
4273				if (boot_speed)
4274					comdefaultrate = boot_speed;
4275			}
4276
4277			/*
4278			 * Initialize the divisor latch.  We can't rely on
4279			 * siocnopen() to do this the first time, since it
4280			 * avoids writing to the latch if the latch appears
4281			 * to have the correct value.  Also, if we didn't
4282			 * just read the speed from the hardware, then we
4283			 * need to set the speed in hardware so that
4284			 * switching it later is null.
4285			 */
4286			cfcr = inb(iobase + com_cfcr);
4287			outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
4288			outb(iobase + com_dlbl,
4289			     COMBRD(comdefaultrate) & 0xff);
4290			outb(iobase + com_dlbh,
4291			     (u_int) COMBRD(comdefaultrate) >> 8);
4292			outb(iobase + com_cfcr, cfcr);
4293
4294			siocnopen(&sp, iobase, comdefaultrate);
4295
4296			splx(s);
4297			if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) {
4298				cp->cn_dev = makedev(CDEV_MAJOR, unit);
4299				cp->cn_pri = COM_FORCECONSOLE(flags)
4300					     || boothowto & RB_SERIAL
4301					     ? CN_REMOTE : CN_NORMAL;
4302				siocniobase = iobase;
4303				siocnunit = unit;
4304			}
4305			if (COM_DEBUGGER(flags)) {
4306				printf("sio%d: gdb debugging port\n", unit);
4307				siogdbiobase = iobase;
4308				siogdbunit = unit;
4309#if DDB > 0
4310				gdbdev = makedev(CDEV_MAJOR, unit);
4311				gdb_getc = siocngetc;
4312				gdb_putc = siocnputc;
4313#endif
4314			}
4315		}
4316	}
4317#ifdef	__i386__
4318#if DDB > 0
4319	/*
4320	 * XXX Ugly Compatability.
4321	 * If no gdb port has been specified, set it to be the console
4322	 * as some configuration files don't specify the gdb port.
4323	 */
4324	if (gdbdev == NODEV && (boothowto & RB_GDB)) {
4325		printf("Warning: no GDB port specified. Defaulting to sio%d.\n",
4326			siocnunit);
4327		printf("Set flag 0x80 on desired GDB port in your\n");
4328		printf("configuration file (currently sio only).\n");
4329		siogdbiobase = siocniobase;
4330		siogdbunit = siocnunit;
4331		gdbdev = makedev(CDEV_MAJOR, siocnunit);
4332		gdb_getc = siocngetc;
4333		gdb_putc = siocnputc;
4334	}
4335#endif
4336#endif
4337}
4338
4339#ifdef __alpha__
4340
4341CONS_DRIVER(sio, NULL, NULL, NULL, siocngetc, siocncheckc, siocnputc, NULL);
4342
4343int
4344siocnattach(port, speed)
4345	int port;
4346	int speed;
4347{
4348	int			s;
4349	u_char			cfcr;
4350	struct siocnstate	sp;
4351
4352	siocniobase = port;
4353	comdefaultrate = speed;
4354	sio_consdev.cn_pri = CN_NORMAL;
4355	sio_consdev.cn_dev = makedev(CDEV_MAJOR, 0);
4356
4357	s = spltty();
4358
4359	/*
4360	 * Initialize the divisor latch.  We can't rely on
4361	 * siocnopen() to do this the first time, since it
4362	 * avoids writing to the latch if the latch appears
4363	 * to have the correct value.  Also, if we didn't
4364	 * just read the speed from the hardware, then we
4365	 * need to set the speed in hardware so that
4366	 * switching it later is null.
4367	 */
4368	cfcr = inb(siocniobase + com_cfcr);
4369	outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
4370	outb(siocniobase + com_dlbl,
4371	     COMBRD(comdefaultrate) & 0xff);
4372	outb(siocniobase + com_dlbh,
4373	     (u_int) COMBRD(comdefaultrate) >> 8);
4374	outb(siocniobase + com_cfcr, cfcr);
4375
4376	siocnopen(&sp, siocniobase, comdefaultrate);
4377	splx(s);
4378
4379	cn_tab = &sio_consdev;
4380	return 0;
4381}
4382
4383int
4384siogdbattach(port, speed)
4385	int port;
4386	int speed;
4387{
4388	int			s;
4389	u_char			cfcr;
4390	struct siocnstate	sp;
4391
4392	siogdbiobase = port;
4393	gdbdefaultrate = speed;
4394
4395	s = spltty();
4396
4397	/*
4398	 * Initialize the divisor latch.  We can't rely on
4399	 * siocnopen() to do this the first time, since it
4400	 * avoids writing to the latch if the latch appears
4401	 * to have the correct value.  Also, if we didn't
4402	 * just read the speed from the hardware, then we
4403	 * need to set the speed in hardware so that
4404	 * switching it later is null.
4405	 */
4406	cfcr = inb(siogdbiobase + com_cfcr);
4407	outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr);
4408	outb(siogdbiobase + com_dlbl,
4409	     COMBRD(gdbdefaultrate) & 0xff);
4410	outb(siogdbiobase + com_dlbh,
4411	     (u_int) COMBRD(gdbdefaultrate) >> 8);
4412	outb(siogdbiobase + com_cfcr, cfcr);
4413
4414	siocnopen(&sp, siogdbiobase, gdbdefaultrate);
4415	splx(s);
4416
4417	return 0;
4418}
4419
4420#endif
4421
4422static void
4423siocninit(cp)
4424	struct consdev	*cp;
4425{
4426	comconsole = DEV_TO_UNIT(cp->cn_dev);
4427}
4428
4429static int
4430siocncheckc(dev)
4431	dev_t	dev;
4432{
4433	int	c;
4434	Port_t	iobase;
4435	int	s;
4436	struct siocnstate	sp;
4437
4438	if (minor(dev) == siogdbunit)
4439		iobase = siogdbiobase;
4440	else
4441		iobase = siocniobase;
4442	s = spltty();
4443	siocnopen(&sp, iobase, comdefaultrate);
4444	if (inb(iobase + com_lsr) & LSR_RXRDY)
4445		c = inb(iobase + com_data);
4446	else
4447		c = -1;
4448	siocnclose(&sp, iobase);
4449	splx(s);
4450	return (c);
4451}
4452
4453
4454int
4455siocngetc(dev)
4456	dev_t	dev;
4457{
4458	int	c;
4459	Port_t	iobase;
4460	int	s;
4461	struct siocnstate	sp;
4462
4463	if (minor(dev) == siogdbunit)
4464		iobase = siogdbiobase;
4465	else
4466		iobase = siocniobase;
4467	s = spltty();
4468	siocnopen(&sp, iobase, comdefaultrate);
4469	while (!(inb(iobase + com_lsr) & LSR_RXRDY))
4470		;
4471	c = inb(iobase + com_data);
4472	siocnclose(&sp, iobase);
4473	splx(s);
4474	return (c);
4475}
4476
4477void
4478siocnputc(dev, c)
4479	dev_t	dev;
4480	int	c;
4481{
4482	int	s;
4483	struct siocnstate	sp;
4484	Port_t	iobase;
4485
4486	if (minor(dev) == siogdbunit)
4487		iobase = siogdbiobase;
4488	else
4489		iobase = siocniobase;
4490	s = spltty();
4491	siocnopen(&sp, iobase, comdefaultrate);
4492	siocntxwait(iobase);
4493	outb(iobase + com_data, c);
4494	siocnclose(&sp, iobase);
4495	splx(s);
4496}
4497
4498#ifdef __alpha__
4499int
4500siogdbgetc()
4501{
4502	int	c;
4503	Port_t	iobase;
4504	int	s;
4505	struct siocnstate	sp;
4506
4507	iobase = siogdbiobase;
4508	s = spltty();
4509	siocnopen(&sp, iobase, gdbdefaultrate);
4510	while (!(inb(iobase + com_lsr) & LSR_RXRDY))
4511		;
4512	c = inb(iobase + com_data);
4513	siocnclose(&sp, iobase);
4514	splx(s);
4515	return (c);
4516}
4517
4518void
4519siogdbputc(c)
4520	int	c;
4521{
4522	int	s;
4523	struct siocnstate	sp;
4524
4525	s = spltty();
4526	siocnopen(&sp, siogdbiobase, gdbdefaultrate);
4527	siocntxwait(siogdbiobase);
4528	outb(siogdbiobase + com_data, c);
4529	siocnclose(&sp, siogdbiobase);
4530	splx(s);
4531}
4532#endif
4533
4534DRIVER_MODULE(sio, isa, sio_isa_driver, sio_devclass, 0, 0);
4535#if NCARD > 0
4536DRIVER_MODULE(sio, pccard, sio_pccard_driver, sio_devclass, 0, 0);
4537#endif
4538
4539#ifdef PC98
4540/*
4541 *  pc98 local function
4542 */
4543
4544static void
4545com_tiocm_set(struct com_s *com, int msr)
4546{
4547	int	s;
4548	int	tmp = 0;
4549	int	mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS;
4550
4551	s=spltty();
4552	com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) )
4553	   | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
4554	tmp |= (CMD8251_TxEN|CMD8251_RxEN);
4555	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
4556	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
4557	pc98_i8251_clear_or_cmd( com, mask, tmp );
4558	splx(s);
4559}
4560
4561static void
4562com_tiocm_bis(struct com_s *com, int msr)
4563{
4564	int	s;
4565	int	tmp = 0;
4566
4567	s=spltty();
4568	com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
4569	tmp |= CMD8251_TxEN|CMD8251_RxEN;
4570	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
4571	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
4572
4573	pc98_i8251_or_cmd( com, tmp );
4574	splx(s);
4575}
4576
4577static void
4578com_tiocm_bic(struct com_s *com, int msr)
4579{
4580	int	s;
4581	int	tmp = msr;
4582
4583	s=spltty();
4584	com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
4585	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
4586	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
4587
4588	pc98_i8251_clear_cmd( com, tmp );
4589	splx(s);
4590}
4591
4592static int
4593com_tiocm_get(struct com_s *com)
4594{
4595	return( com->pc98_prev_modem_status );
4596}
4597
4598static int
4599com_tiocm_get_delta(struct com_s *com)
4600{
4601	int	tmp;
4602
4603	tmp = com->pc98_modem_delta;
4604	com->pc98_modem_delta = 0;
4605	return( tmp );
4606}
4607
4608/* convert to TIOCM_?? ( ioctl.h ) */
4609static int
4610pc98_get_modem_status(struct com_s *com)
4611{
4612	register int	msr;
4613
4614	msr = com->pc98_prev_modem_status
4615			& ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
4616	if (com->pc98_8251fifo_enable) {
4617		int	stat2;
4618
4619		stat2 = inb(I8251F_msr);
4620		if ( stat2 & CICSCDF_CD ) msr |= TIOCM_CAR;
4621		if ( stat2 & CICSCDF_CI ) msr |= TIOCM_RI;
4622		if ( stat2 & CICSCDF_DR ) msr |= TIOCM_DSR;
4623		if ( stat2 & CICSCDF_CS ) msr |= TIOCM_CTS;
4624#if COM_CARRIER_DETECT_EMULATE
4625		if ( msr & (TIOCM_DSR|TIOCM_CTS) ) {
4626			msr |= TIOCM_CAR;
4627		}
4628#endif
4629	} else {
4630		int	stat, stat2;
4631
4632		stat  = inb(com->sts_port);
4633		stat2 = inb(com->in_modem_port);
4634		if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR;
4635		if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI;
4636		if (   stat & STS8251_DSR ) msr |= TIOCM_DSR;
4637		if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS;
4638#if COM_CARRIER_DETECT_EMULATE
4639		if ( msr & (TIOCM_DSR|TIOCM_CTS) ) {
4640			msr |= TIOCM_CAR;
4641		}
4642#endif
4643	}
4644	return(msr);
4645}
4646
4647static void
4648pc98_check_msr(void* chan)
4649{
4650	int	msr, delta;
4651	int	s;
4652	register struct tty *tp;
4653	struct	com_s *com;
4654	int	mynor;
4655	int	unit;
4656	dev_t	dev;
4657
4658	dev=(dev_t)chan;
4659	mynor = minor(dev);
4660	unit = MINOR_TO_UNIT(mynor);
4661	com = com_addr(unit);
4662	tp = com->tp;
4663
4664	s = spltty();
4665	msr = pc98_get_modem_status(com);
4666	/* make change flag */
4667	delta = msr ^ com->pc98_prev_modem_status;
4668	if ( delta & TIOCM_CAR ) {
4669	    if ( com->modem_car_chg_timer ) {
4670		if ( -- com->modem_car_chg_timer )
4671		    msr ^= TIOCM_CAR;
4672	    } else {
4673		if ((com->modem_car_chg_timer = (msr & TIOCM_CAR) ?
4674		     DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE) != 0)
4675		    msr ^= TIOCM_CAR;
4676	    }
4677	} else
4678	    com->modem_car_chg_timer = 0;
4679	delta = ( msr ^ com->pc98_prev_modem_status ) &
4680			(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
4681	com->pc98_prev_modem_status = msr;
4682	delta = ( com->pc98_modem_delta |= delta );
4683	splx(s);
4684	if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) {
4685		if ( delta ) {
4686			commint(dev);
4687		}
4688		timeout(pc98_check_msr, (caddr_t)dev,
4689					PC98_CHECK_MODEM_INTERVAL);
4690	} else {
4691		com->modem_checking = 0;
4692	}
4693}
4694
4695static void
4696pc98_msrint_start(dev_t dev)
4697{
4698	struct	com_s *com;
4699	int	mynor;
4700	int	unit;
4701	int	s = spltty();
4702
4703	mynor = minor(dev);
4704	unit = MINOR_TO_UNIT(mynor);
4705	com = com_addr(unit);
4706	/* modem control line check routine envoke interval is 1/10 sec */
4707	if ( com->modem_checking == 0 ) {
4708		com->pc98_prev_modem_status = pc98_get_modem_status(com);
4709		com->pc98_modem_delta = 0;
4710		timeout(pc98_check_msr, (caddr_t)dev,
4711					PC98_CHECK_MODEM_INTERVAL);
4712		com->modem_checking = 1;
4713	}
4714	splx(s);
4715}
4716
4717static void
4718pc98_disable_i8251_interrupt(struct com_s *com, int mod)
4719{
4720	/* disable interrupt */
4721	register int	tmp;
4722
4723	mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
4724	COM_INT_DISABLE
4725	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
4726	outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp );
4727	COM_INT_ENABLE
4728}
4729
4730static void
4731pc98_enable_i8251_interrupt(struct com_s *com, int mod)
4732{
4733	register int	tmp;
4734
4735	COM_INT_DISABLE
4736	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
4737	outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp );
4738	COM_INT_ENABLE
4739}
4740
4741static int
4742pc98_check_i8251_interrupt(struct com_s *com)
4743{
4744	return ( com->intr_enable & 0x07 );
4745}
4746
4747static void
4748pc98_i8251_clear_cmd(struct com_s *com, int x)
4749{
4750	int	tmp;
4751
4752	COM_INT_DISABLE
4753	tmp = com->pc98_prev_siocmd & ~(x);
4754	if (com->pc98_8251fifo_enable)
4755	    outb(I8251F_fcr, 0);
4756	outb(com->cmd_port, tmp);
4757	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4758	if (com->pc98_8251fifo_enable)
4759	    outb(I8251F_fcr, CTRL8251F_ENABLE);
4760	COM_INT_ENABLE
4761}
4762
4763static void
4764pc98_i8251_or_cmd(struct com_s *com, int x)
4765{
4766	int	tmp;
4767
4768	COM_INT_DISABLE
4769	if (com->pc98_8251fifo_enable)
4770	    outb(I8251F_fcr, 0);
4771	tmp = com->pc98_prev_siocmd | (x);
4772	outb(com->cmd_port, tmp);
4773	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4774	if (com->pc98_8251fifo_enable)
4775	    outb(I8251F_fcr, CTRL8251F_ENABLE);
4776	COM_INT_ENABLE
4777}
4778
4779static void
4780pc98_i8251_set_cmd(struct com_s *com, int x)
4781{
4782	int	tmp;
4783
4784	COM_INT_DISABLE
4785	if (com->pc98_8251fifo_enable)
4786	    outb(I8251F_fcr, 0);
4787	tmp = (x);
4788	outb(com->cmd_port, tmp);
4789	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4790	if (com->pc98_8251fifo_enable)
4791	    outb(I8251F_fcr, CTRL8251F_ENABLE);
4792	COM_INT_ENABLE
4793}
4794
4795static void
4796pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x)
4797{
4798	int	tmp;
4799	COM_INT_DISABLE
4800	if (com->pc98_8251fifo_enable)
4801	    outb(I8251F_fcr, 0);
4802	tmp = com->pc98_prev_siocmd & ~(clr);
4803	tmp |= (x);
4804	outb(com->cmd_port, tmp);
4805	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4806	if (com->pc98_8251fifo_enable)
4807	    outb(I8251F_fcr, CTRL8251F_ENABLE);
4808	COM_INT_ENABLE
4809}
4810
4811static int
4812pc98_i8251_get_cmd(struct com_s *com)
4813{
4814	return com->pc98_prev_siocmd;
4815}
4816
4817static int
4818pc98_i8251_get_mod(struct com_s *com)
4819{
4820	return com->pc98_prev_siomod;
4821}
4822
4823static void
4824pc98_i8251_reset(struct com_s *com, int mode, int command)
4825{
4826	if (com->pc98_8251fifo_enable)
4827	    outb(I8251F_fcr, 0);
4828	outb(com->cmd_port, 0);	/* dummy */
4829	DELAY(2);
4830	outb(com->cmd_port, 0);	/* dummy */
4831	DELAY(2);
4832	outb(com->cmd_port, 0);	/* dummy */
4833	DELAY(2);
4834	outb(com->cmd_port, CMD8251_RESET);	/* internal reset */
4835	DELAY(2);
4836	outb(com->cmd_port, mode );	/* mode register */
4837	com->pc98_prev_siomod = mode;
4838	DELAY(2);
4839	pc98_i8251_set_cmd( com, (command|CMD8251_ER) );
4840	DELAY(10);
4841	if (com->pc98_8251fifo_enable)
4842	    outb(I8251F_fcr, CTRL8251F_ENABLE |
4843		 CTRL8251F_XMT_RST | CTRL8251F_RCV_RST);
4844}
4845
4846static void
4847pc98_check_sysclock(void)
4848{
4849	/* get system clock from port */
4850	if ( pc98_machine_type & M_8M ) {
4851	/* 8 MHz system & H98 */
4852		sysclock = 8;
4853	} else {
4854	/* 5 MHz system */
4855		sysclock = 5;
4856	}
4857}
4858
4859static void
4860com_cflag_and_speed_set( struct com_s *com, int cflag, int speed)
4861{
4862	int	cfcr=0, count;
4863	int	previnterrupt;
4864
4865	count = pc98_ttspeedtab( com, speed );
4866	if ( count < 0 ) return;
4867
4868	previnterrupt = pc98_check_i8251_interrupt(com);
4869	pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx );
4870
4871	switch ( cflag&CSIZE ) {
4872	  case CS5:
4873		cfcr = MOD8251_5BITS; break;
4874	  case CS6:
4875		cfcr = MOD8251_6BITS; break;
4876	  case CS7:
4877		cfcr = MOD8251_7BITS; break;
4878	  case CS8:
4879		cfcr = MOD8251_8BITS; break;
4880	}
4881	if ( cflag&PARENB ) {
4882	    if ( cflag&PARODD )
4883		cfcr |= MOD8251_PODD;
4884	    else
4885		cfcr |= MOD8251_PEVEN;
4886	} else
4887		cfcr |= MOD8251_PDISAB;
4888
4889	if ( cflag&CSTOPB )
4890		cfcr |= MOD8251_STOP2;
4891	else
4892		cfcr |= MOD8251_STOP1;
4893
4894	if ( count & 0x10000 )
4895		cfcr |= MOD8251_CLKX1;
4896	else
4897		cfcr |= MOD8251_CLKX16;
4898
4899	if (epson_machine_id != 0x20) {	/* XXX */
4900		int	tmp;
4901		while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP))
4902			;
4903	}
4904	/* set baud rate from ospeed */
4905	pc98_set_baud_rate( com, count );
4906
4907	if ( cfcr != pc98_i8251_get_mod(com) )
4908		pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) );
4909
4910	pc98_enable_i8251_interrupt( com, previnterrupt );
4911}
4912
4913static int
4914pc98_ttspeedtab(struct com_s *com, int speed)
4915{
4916	int	if_type, effect_sp, count = -1, mod;
4917
4918	if_type = com->pc98_if_type & 0x0f;
4919
4920	switch (com->pc98_if_type) {
4921	case COM_IF_INTERNAL:
4922	    if (PC98SIO_baud_rate_port(if_type) != -1) {
4923		count = ttspeedtab(speed, if_8251_type[if_type].speedtab);
4924		if (count > 0) {
4925		    count |= COM1_EXT_CLOCK;
4926		    break;
4927		}
4928	    }
4929
4930	    /* for *1CLK asynchronous! mode, TEFUTEFU */
4931	    mod = (sysclock == 5) ? 2457600 : 1996800;
4932	    effect_sp = ttspeedtab( speed, pc98speedtab );
4933	    if ( effect_sp < 0 )	/* XXX */
4934		effect_sp = ttspeedtab( (speed - 1), pc98speedtab );
4935	    if ( effect_sp <= 0 )
4936		return effect_sp;
4937	    if ( effect_sp == speed )
4938		mod /= 16;
4939	    if ( mod % effect_sp )
4940		return(-1);
4941	    count = mod / effect_sp;
4942	    if ( count > 65535 )
4943		return(-1);
4944	    if ( effect_sp != speed )
4945		count |= 0x10000;
4946	    break;
4947	case COM_IF_PC9861K_1:
4948	case COM_IF_PC9861K_2:
4949	    count = 1;
4950	    break;
4951	case COM_IF_IND_SS_1:
4952	case COM_IF_IND_SS_2:
4953	case COM_IF_PIO9032B_1:
4954	case COM_IF_PIO9032B_2:
4955	    if ( speed == 0 ) return 0;
4956	    count = ttspeedtab( speed, if_8251_type[if_type].speedtab );
4957	    break;
4958	case COM_IF_B98_01_1:
4959	case COM_IF_B98_01_2:
4960	    if ( speed == 0 ) return 0;
4961	    count = ttspeedtab( speed, if_8251_type[if_type].speedtab );
4962#ifdef B98_01_OLD
4963	    if (count == 0 || count == 1) {
4964		count += 4;
4965		count |= 0x20000;  /* x1 mode for 76800 and 153600 */
4966	    }
4967#endif
4968	    break;
4969	}
4970
4971	return count;
4972}
4973
4974static void
4975pc98_set_baud_rate( struct com_s *com, int count )
4976{
4977	int	if_type, io, s;
4978
4979	if_type = com->pc98_if_type & 0x0f;
4980	io = com->iobase & 0xff00;
4981
4982	switch (com->pc98_if_type) {
4983	case COM_IF_INTERNAL:
4984	    if (PC98SIO_baud_rate_port(if_type) != -1) {
4985		if (count & COM1_EXT_CLOCK) {
4986		    outb((Port_t)PC98SIO_baud_rate_port(if_type), count & 0xff);
4987		    break;
4988		} else {
4989		    outb((Port_t)PC98SIO_baud_rate_port(if_type), 0x09);
4990		}
4991	    }
4992
4993	    if ( count < 0 ) {
4994		printf( "[ Illegal count : %d ]", count );
4995		return;
4996	    } else if ( count == 0 )
4997		return;
4998	    /* set i8253 */
4999	    s = splclock();
5000	    if (count != 3)
5001		outb( 0x77, 0xb6 );
5002	    else
5003		outb( 0x77, 0xb4 );
5004	    outb( 0x5f, 0);
5005	    outb( 0x75, count & 0xff );
5006	    outb( 0x5f, 0);
5007	    outb( 0x75, (count >> 8) & 0xff );
5008	    splx(s);
5009	    break;
5010	case COM_IF_IND_SS_1:
5011	case COM_IF_IND_SS_2:
5012	    outb(io | PC98SIO_intr_ctrl_port(if_type), 0);
5013	    outb(io | PC98SIO_baud_rate_port(if_type), 0);
5014	    outb(io | PC98SIO_baud_rate_port(if_type), 0xc0);
5015	    outb(io | PC98SIO_baud_rate_port(if_type), (count >> 8) | 0x80);
5016	    outb(io | PC98SIO_baud_rate_port(if_type), count & 0xff);
5017	    break;
5018	case COM_IF_PIO9032B_1:
5019	case COM_IF_PIO9032B_2:
5020	    outb(io | PC98SIO_baud_rate_port(if_type), count);
5021	    break;
5022	case COM_IF_B98_01_1:
5023	case COM_IF_B98_01_2:
5024	    outb(io | PC98SIO_baud_rate_port(if_type), count & 0x0f);
5025#ifdef B98_01_OLD
5026	    /*
5027	     * Some old B98_01 board should be controlled
5028	     * in different way, but this hasn't been tested yet.
5029	     */
5030	    outb(io | PC98SIO_func_port(if_type),
5031		 (count & 0x20000) ? 0xf0 : 0xf2);
5032#endif
5033	    break;
5034	}
5035}
5036static int
5037pc98_check_if_type(device_t dev, struct siodev *iod)
5038{
5039	int	irr, io, if_type, tmp;
5040	static  short	irq_tab[2][8] = {
5041		{  3,  5,  6,  9, 10, 12, 13, -1},
5042		{  3, 10, 12, 13,  5,  6,  9, -1}
5043	};
5044
5045	iod->if_type = if_type = GET_IFTYPE(device_get_flags(dev));
5046	if ((if_type < 0 || if_type > COM_IF_END1) &&
5047	    (if_type < 0x10 || if_type > COM_IF_END2))
5048	    return(-1);
5049	if_type &= 0x0f;
5050	iod->irq = 0;
5051	io = isa_get_port(dev) & 0xff00;
5052
5053	if (IS_8251(iod->if_type)) {
5054	    if (PC98SIO_func_port(if_type) != -1) {
5055		outb(io | PC98SIO_func_port(if_type), 0xf2);
5056		tmp = ttspeedtab(9600, if_8251_type[if_type].speedtab);
5057		if (tmp != -1 && PC98SIO_baud_rate_port(if_type) != -1)
5058		    outb(io | PC98SIO_baud_rate_port(if_type), tmp);
5059	    }
5060
5061	    iod->cmd  = io | PC98SIO_cmd_port(if_type);
5062	    iod->sts  = io | PC98SIO_sts_port(if_type);
5063	    iod->mod  = io | PC98SIO_in_modem_port(if_type);
5064	    iod->ctrl = io | PC98SIO_intr_ctrl_port(if_type);
5065
5066	    if (iod->if_type == COM_IF_INTERNAL) {
5067		iod->irq = 4;
5068
5069		if (pc98_check_8251vfast()) {
5070			PC98SIO_baud_rate_port(if_type) = I8251F_div;
5071			if_8251_type[if_type].speedtab = pc98fast_speedtab;
5072		}
5073	    } else {
5074		tmp = inb( iod->mod ) & if_8251_type[if_type].irr_mask;
5075		if ((isa_get_port(dev) & 0xff) == IO_COM2)
5076		    iod->irq = irq_tab[0][tmp];
5077		else
5078		    iod->irq = irq_tab[1][tmp];
5079	    }
5080	} else {
5081	    irr = if_16550a_type[if_type].irr_read;
5082#ifdef COM_MULTIPORT
5083	    if (!COM_ISMULTIPORT(device_get_flags(dev)) ||
5084		    device_get_unit(dev) == COM_MPMASTER(device_get_flags(dev)))
5085#endif
5086	    if (irr != -1) {
5087		tmp = inb(io | irr);
5088		if (isa_get_port(dev) & 0x01)	/* XXX depend on RSB-384 */
5089		    iod->irq = irq_tab[1][tmp >> 3];
5090		else
5091		    iod->irq = irq_tab[0][tmp & 0x07];
5092	    }
5093	}
5094	if ( iod->irq == -1 ) return -1;
5095
5096	return 0;
5097}
5098static int
5099pc98_set_ioport(struct com_s *com)
5100{
5101	int	if_type = com->pc98_if_type & 0x0f;
5102	int	io = com->iobase & 0xff00;
5103
5104	if (IS_8251(com->pc98_if_type)) {
5105	    pc98_check_sysclock();
5106	    com->data_port	= io | PC98SIO_data_port(if_type);
5107	    com->cmd_port	= io | PC98SIO_cmd_port(if_type);
5108	    com->sts_port	= io | PC98SIO_sts_port(if_type);
5109	    com->in_modem_port	= io | PC98SIO_in_modem_port(if_type);
5110	    com->intr_ctrl_port	= io | PC98SIO_intr_ctrl_port(if_type);
5111
5112	    return 0;
5113	}
5114
5115	return -1;
5116}
5117static int
5118pc98_check_8251vfast(void)
5119{
5120    int	i;
5121
5122    outb(I8251F_div, 0x8c);
5123    DELAY(10);
5124    for (i = 0; i < 100; i++) {
5125	if ((inb(I8251F_div) & 0x80) != 0) {
5126	    i = 0;
5127	    break;
5128	}
5129	DELAY(1);
5130    }
5131    outb(I8251F_div, 0);
5132    DELAY(10);
5133    for (; i < 100; i++) {
5134	if ((inb(I8251F_div) & 0x80) == 0)
5135	    return 1;
5136	DELAY(1);
5137    }
5138
5139    return 0;
5140}
5141static int
5142pc98_check_8251fifo(void)
5143{
5144    u_char	tmp1, tmp2;
5145
5146    tmp1 = inb(I8251F_iir);
5147    DELAY(10);
5148    tmp2 = inb(I8251F_iir);
5149    if (((tmp1 ^ tmp2) & 0x40) != 0 && ((tmp1 | tmp2) & 0x20) == 0)
5150	return 1;
5151
5152    return 0;
5153}
5154#endif /* PC98 defined */
5155