sio.c revision 25026
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
34 *	$Id: sio.c,v 1.21 1997/04/05 15:04:32 kato Exp $
35 */
36
37#include "opt_comconsole.h"
38#include "opt_ddb.h"
39#include "opt_sio.h"
40#include "sio.h"
41
42/*
43 * Serial driver, based on 386BSD-0.1 com driver.
44 * Mostly rewritten to use pseudo-DMA.
45 * Works for National Semiconductor NS8250-NS16550AF UARTs.
46 * COM driver, based on HP dca driver.
47 *
48 * Changes for PC-Card integration:
49 *	- Added PC-Card driver table and handlers
50 */
51/*===============================================================
52 * 386BSD(98),FreeBSD-1.1x(98) com driver.
53 * -----
54 * modified for PC9801 by M.Ishii
55 *			Kyoto University Microcomputer Club (KMC)
56 * Chou "TEFUTEFU" Hirotomi
57 *			Kyoto Univ.  the faculty of medicine
58 *===============================================================
59 * FreeBSD-2.0.1(98) sio driver.
60 * -----
61 * modified for pc98 Internal i8251 and MICRO CORE MC16550II
62 *			T.Koike(hfc01340@niftyserve.or.jp)
63 * implement kernel device configuration
64 *			aizu@orient.center.nitech.ac.jp
65 *
66 * Notes.
67 * -----
68 *  PC98 localization based on 386BSD(98) com driver. Using its PC98 local
69 *  functions.
70 *  This driver is under debugging,has bugs.
71 *
72 * 1) config
73 *  options COM_MULTIPORT  #if using MC16550II
74 *  device sio0 at nec? port 0x30  tty irq 4 vector siointr #internal
75 *  device sio1 at nec? port 0xd2  tty irq 5 flags 0x101 vector siointr #mc1
76 *  device sio2 at nec? port 0x8d2 tty flags 0x101 vector siointr       #mc2
77 *                         # ~~~~~iobase        ~~multi port flag
78 *                         #                   ~  master device is sio1
79 * 2) device
80 *  cd /dev; MAKEDEV ttyd0 ttyd1 ..
81 * 3) /etc/rc.serial
82 *  57600bps is too fast for sio0(internal8251)
83 *  my ex.
84 *    #set default speed 9600
85 *    modem()
86 *       :
87 *      stty </dev/ttyid$i crtscts 9600
88 *       :                 #       ~~~~ default speed(can change after init.)
89 *    modem 0 1 2
90 * 4) COMCONSOLE
91 *  not changed.
92 * 5) PC9861K,PIO9032B,B98_01
93 *  not tested.
94 */
95/*
96 * modified for AIWA B98-01
97 * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp>  last update: 15 Sep.1995
98 *
99 * How to configure...
100 *   # options COM_MULTIPORT         # support for MICROCORE MC16550II
101 *      ... comment-out this line, which will conflict with B98_01.
102 *   options "B98_01"                # support for AIWA B98-01
103 *   device  sio1 at nec? port 0x00d1 tty irq ? vector siointr
104 *   device  sio2 at nec? port 0x00d5 tty irq ? vector siointr
105 *      ... you can leave these lines `irq ?', irq will be autodetected.
106 */
107#ifdef PC98
108#define	MC16550		0
109#define COM_IF_INTERNAL	1
110#if 0
111#define COM_IF_PC9861K	2
112#define COM_IF_PIO9032B	3
113#endif
114#ifdef	B98_01
115#undef  COM_MULTIPORT	/* COM_MULTIPORT will conflict with B98_01 */
116#define COM_IF_B98_01	4
117#endif /* B98_01 */
118#endif /* PC98 */
119
120#include <sys/param.h>
121#include <sys/systm.h>
122#include <sys/reboot.h>
123#include <sys/tty.h>
124#include <sys/proc.h>
125#include <sys/conf.h>
126#include <sys/dkstat.h>
127#include <sys/fcntl.h>
128#include <sys/uio.h>
129#include <sys/kernel.h>
130#include <sys/malloc.h>
131#include <sys/syslog.h>
132#ifdef DEVFS
133#include <sys/devfsext.h>
134#endif
135
136#include <machine/clock.h>
137
138#ifdef PC98
139#include <pc98/pc98/pc98.h>
140#include <pc98/pc98/pc98_machdep.h>
141#include <i386/isa/icu.h>
142#include <i386/isa/isa_device.h>
143#include <pc98/pc98/sioreg.h>
144#include <i386/isa/ic/i8251.h>
145#else
146#include <i386/isa/isa.h>
147#include <i386/isa/isa_device.h>
148#include <i386/isa/sioreg.h>
149#endif
150
151#ifdef COM_ESP
152#include <i386/isa/ic/esp.h>
153#endif
154#include <i386/isa/ic/ns16550.h>
155
156#include "crd.h"
157#if NCRD > 0
158#include <pccard/card.h>
159#include <pccard/driver.h>
160#include <pccard/slot.h>
161#endif
162
163#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
164#define	RB_I_HIGH_WATER	(TTYHOG - 2 * RS_IBUFSIZE)
165#define	RS_IBUFSIZE	256
166
167#define	CALLOUT_MASK		0x80
168#define	CONTROL_MASK		0x60
169#define	CONTROL_INIT_STATE	0x20
170#define	CONTROL_LOCK_STATE	0x40
171#define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
172#define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
173#define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)
174
175#ifdef COM_MULTIPORT
176/* checks in flags for multiport and which is multiport "master chip"
177 * for a given card
178 */
179#define	COM_ISMULTIPORT(dev)	((dev)->id_flags & 0x01)
180#define	COM_MPMASTER(dev)	(((dev)->id_flags >> 8) & 0x0ff)
181#define	COM_NOTAST4(dev)	((dev)->id_flags & 0x04)
182#endif /* COM_MULTIPORT */
183
184#define	COM_CONSOLE(dev)	((dev)->id_flags & 0x10)
185#define	COM_FORCECONSOLE(dev)	((dev)->id_flags & 0x20)
186#define	COM_LLCONSOLE(dev)	((dev)->id_flags & 0x40)
187#define	COM_LOSESOUTINTS(dev)	((dev)->id_flags & 0x08)
188#define	COM_NOFIFO(dev)		((dev)->id_flags & 0x02)
189#define	COM_VERBOSE(dev)	((dev)->id_flags & 0x80)
190
191#ifndef PC98
192#define	com_scr		7	/* scratch register for 16450-16550 (R/W) */
193#endif /* !PC98 */
194
195/*
196 * Input buffer watermarks.
197 * The external device is asked to stop sending when the buffer exactly reaches
198 * high water, or when the high level requests it.
199 * The high level is notified immediately (rather than at a later clock tick)
200 * when this watermark is reached.
201 * The buffer size is chosen so the watermark should almost never be reached.
202 * The low watermark is invisibly 0 since the buffer is always emptied all at
203 * once.
204 */
205#define	RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
206
207/*
208 * com state bits.
209 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
210 * than the other bits so that they can be tested as a group without masking
211 * off the low bits.
212 *
213 * The following com and tty flags correspond closely:
214 *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and
215 *				   siostop())
216 *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart())
217 *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam())
218 *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam())
219 * TS_FLUSH is not used.
220 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
221 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
222 */
223#define	CS_BUSY		0x80	/* output in progress */
224#define	CS_TTGO		0x40	/* output not stopped by XOFF */
225#define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */
226#define	CS_CHECKMSR	1	/* check of MSR scheduled */
227#define	CS_CTS_OFLOW	2	/* use CTS output flow control */
228#define	CS_DTR_OFF	0x10	/* DTR held off */
229#define	CS_ODONE	4	/* output completed */
230#define	CS_RTS_IFLOW	8	/* use RTS input flow control */
231#define	CSE_BUSYCHECK	1	/* siobusycheck() scheduled */
232
233static	char const * const	error_desc[] = {
234#define	CE_OVERRUN			0
235	"silo overflow",
236#define	CE_INTERRUPT_BUF_OVERFLOW	1
237	"interrupt-level buffer overflow",
238#define	CE_TTY_BUF_OVERFLOW		2
239	"tty-level buffer overflow",
240};
241
242#define	CE_NTYPES			3
243#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
244
245/* types.  XXX - should be elsewhere */
246typedef u_int	Port_t;		/* hardware port */
247typedef u_char	bool_t;		/* boolean */
248
249/* queue of linear buffers */
250struct lbq {
251	u_char	*l_head;	/* next char to process */
252	u_char	*l_tail;	/* one past the last char to process */
253	struct lbq *l_next;	/* next in queue */
254	bool_t	l_queued;	/* nonzero if queued */
255};
256
257/* com device structure */
258struct com_s {
259	u_char	state;		/* miscellaneous flag bits */
260	bool_t  active_out;	/* nonzero if the callout device is open */
261	u_char	cfcr_image;	/* copy of value written to CFCR */
262#ifdef COM_ESP
263	bool_t	esp;		/* is this unit a hayes esp board? */
264#endif
265	u_char	extra_state;	/* more flag bits, separate for order trick */
266	u_char	fifo_image;	/* copy of value written to FIFO */
267	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
268	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
269	u_char	mcr_image;	/* copy of value written to MCR */
270#ifdef COM_MULTIPORT
271	bool_t	multiport;	/* is this unit part of a multiport device? */
272#endif /* COM_MULTIPORT */
273	bool_t	no_irq;		/* nonzero if irq is not attached */
274	bool_t  gone;		/* hardware disappeared */
275	bool_t	poll;		/* nonzero if polling is required */
276	bool_t	poll_output;	/* nonzero if polling for output is required */
277	int	unit;		/* unit	number */
278	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
279	u_int	tx_fifo_size;
280	u_int	wopeners;	/* # processes waiting for DCD in open() */
281
282	/*
283	 * The high level of the driver never reads status registers directly
284	 * because there would be too many side effects to handle conveniently.
285	 * Instead, it reads copies of the registers stored here by the
286	 * interrupt handler.
287	 */
288	u_char	last_modem_status;	/* last MSR read by intr handler */
289	u_char	prev_modem_status;	/* last MSR handled by high level */
290
291	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
292	u_char	*ibuf;		/* start of input buffer */
293	u_char	*ibufend;	/* end of input buffer */
294	u_char	*ihighwater;	/* threshold in input buffer */
295	u_char	*iptr;		/* next free spot in input buffer */
296
297	struct lbq	obufq;	/* head of queue of output buffers */
298	struct lbq	obufs[2];	/* output buffers */
299
300#ifdef PC98
301	Port_t	cmd_port;
302	Port_t	sts_port;
303	Port_t	in_modem_port;
304	Port_t	intr_ctrl_port;
305	int	intr_enable;
306	int	pc98_prev_modem_status;
307	int	pc98_modem_delta;
308	int	modem_car_chg_timer;
309	int	pc98_prev_siocmd;
310	int	pc98_prev_siomod;
311	int	modem_checking;
312	int	pc98_if_type;
313#endif /* PC98 */
314	Port_t	data_port;	/* i/o ports */
315#ifdef COM_ESP
316	Port_t	esp_port;
317#endif
318	Port_t	int_id_port;
319	Port_t	iobase;
320	Port_t	modem_ctl_port;
321	Port_t	line_status_port;
322	Port_t	modem_status_port;
323
324	struct tty	*tp;	/* cross reference */
325
326	/* Initial state. */
327	struct termios	it_in;	/* should be in struct tty */
328	struct termios	it_out;
329
330	/* Lock state. */
331	struct termios	lt_in;	/* should be in struct tty */
332	struct termios	lt_out;
333
334	bool_t	do_timestamp;
335	bool_t	do_dcd_timestamp;
336	struct timeval	timestamp;
337	struct timeval	dcd_timestamp;
338
339	u_long	bytes_in;	/* statistics */
340	u_long	bytes_out;
341	u_int	delta_error_counts[CE_NTYPES];
342	u_long	error_counts[CE_NTYPES];
343
344	/*
345	 * Ping-pong input buffers.  The extra factor of 2 in the sizes is
346	 * to allow for an error byte for each input byte.
347	 */
348#define	CE_INPUT_OFFSET		RS_IBUFSIZE
349	u_char	ibuf1[2 * RS_IBUFSIZE];
350	u_char	ibuf2[2 * RS_IBUFSIZE];
351
352	/*
353	 * Data area for output buffers.  Someday we should build the output
354	 * buffer queue without copying data.
355	 */
356	u_char	obuf1[256];
357	u_char	obuf2[256];
358#ifdef DEVFS
359	void	*devfs_token_ttyd;
360	void	*devfs_token_ttyl;
361	void	*devfs_token_ttyi;
362	void	*devfs_token_cuaa;
363	void	*devfs_token_cual;
364	void	*devfs_token_cuai;
365#endif
366};
367
368/*
369 * XXX public functions in drivers should be declared in headers produced
370 * by `config', not here.
371 */
372
373/* Interrupt handling entry point. */
374void	siopoll		__P((void));
375
376/* Device switch entry points. */
377#define	sioreset	noreset
378#define	siommap		nommap
379#define	siostrategy	nostrategy
380
381#ifdef COM_ESP
382static	int	espattach	__P((struct isa_device *isdp, struct com_s *com,
383				     Port_t esp_port));
384#endif
385static	int	sioattach	__P((struct isa_device *dev));
386static	timeout_t siobusycheck;
387static	timeout_t siodtrwakeup;
388static	void	comhardclose	__P((struct com_s *com));
389static	void	siointr1	__P((struct com_s *com));
390static	int	commctl		__P((struct com_s *com, int bits, int how));
391static	int	comparam	__P((struct tty *tp, struct termios *t));
392static	int	sioprobe	__P((struct isa_device *dev));
393static	void	siosettimeout	__P((void));
394static	void	comstart	__P((struct tty *tp));
395static	timeout_t comwakeup;
396static	int	tiocm_xxx2mcr	__P((int tiocm_xxx));
397static	void	disc_optim	__P((struct tty	*tp, struct termios *t,
398				     struct com_s *com));
399
400#ifdef DSI_SOFT_MODEM
401static  int 	LoadSoftModem   __P((int unit,int base_io, u_long size, u_char *ptr));
402#endif /* DSI_SOFT_MODEM */
403
404static char driver_name[] = "sio";
405
406/* table and macro for fast conversion from a unit number to its com struct */
407static	struct com_s	*p_com_addr[NSIO];
408#define	com_addr(unit)	(p_com_addr[unit])
409
410struct isa_driver	siodriver = {
411	sioprobe, sioattach, driver_name
412};
413
414static	d_open_t	sioopen;
415static	d_close_t	sioclose;
416static	d_read_t	sioread;
417static	d_write_t	siowrite;
418static	d_ioctl_t	sioioctl;
419static	d_stop_t	siostop;
420static	d_devtotty_t	siodevtotty;
421
422#define CDEV_MAJOR 28
423static struct cdevsw sio_cdevsw = {
424	sioopen,	sioclose,	sioread,	siowrite,
425	sioioctl,	siostop,	noreset,	siodevtotty,
426	ttselect,	nommap,		NULL,		driver_name,
427	NULL,		-1,
428};
429
430static	int	comconsole = -1;
431static	volatile speed_t	comdefaultrate = CONSPEED;
432static	u_int	com_events;	/* input chars + weighted output completions */
433static	Port_t	siocniobase;
434static	int	sio_timeout;
435static	int	sio_timeouts_until_log;
436#if 0 /* XXX */
437static struct tty	*sio_tty[NSIO];
438#else
439static struct tty	sio_tty[NSIO];
440#endif
441static	const int	nsio_tty = NSIO;
442
443#ifdef PC98
444struct	siodev	{
445	short	if_type;
446	short	irq;
447	Port_t	cmd, sts, ctrl, mod;
448	};
449static	int	sysclock;
450static	short	port_table[5][3] = {
451			{0x30, 0xb1, 0xb9},
452			{0x32, 0xb3, 0xbb},
453			{0x32, 0xb3, 0xbb},
454			{0x33, 0xb0, 0xb2},
455			{0x35, 0xb0, 0xb2}
456		};
457#define	PC98SIO_data_port(ch)		port_table[0][ch]
458#define	PC98SIO_cmd_port(ch)		port_table[1][ch]
459#define	PC98SIO_sts_port(ch)		port_table[2][ch]
460#define	PC98SIO_in_modem_port(ch)	port_table[3][ch]
461#define	PC98SIO_intr_ctrl_port(ch)	port_table[4][ch]
462#ifdef COM_IF_PIO9032B
463#define   IO_COM_PIO9032B_2	0x0b8
464#define   IO_COM_PIO9032B_3	0x0ba
465#endif /* COM_IF_PIO9032B */
466#ifdef COM_IF_B98_01
467#define	  IO_COM_B98_01_2	0x0d1
468#define	  IO_COM_B98_01_3	0x0d5
469#endif /* COM_IF_B98_01 */
470#define	COM_INT_DISABLE		{int previpri; previpri=spltty();
471#define	COM_INT_ENABLE		splx(previpri);}
472#define IEN_TxFLAG		IEN_Tx
473
474#define COM_CARRIER_DETECT_EMULATE	0
475#define	PC98_CHECK_MODEM_INTERVAL	(hz/10)
476#define DCD_OFF_TOLERANCE		2
477#define DCD_ON_RECOGNITION		2
478#define	IS_8251(type)		(type != MC16550)
479#define	IS_PC98IN(adr)		(adr == 0x30)
480
481static	void	commint		__P((dev_t dev));
482static	void	com_tiocm_set	__P((struct com_s *com, int msr));
483static	void	com_tiocm_bis	__P((struct com_s *com, int msr));
484static	void	com_tiocm_bic	__P((struct com_s *com, int msr));
485static	int	com_tiocm_get	__P((struct com_s *com));
486static	int	com_tiocm_get_delta	__P((struct com_s *com));
487static	void	pc98_msrint_start	__P((dev_t dev));
488static	void	com_cflag_and_speed_set	__P((struct com_s *com, int cflag, int speed));
489static	int	pc98_ttspeedtab		__P((struct com_s *com, int speed));
490static	int	pc98_get_modem_status	__P((struct com_s *com));
491static	timeout_t	pc98_check_msr;
492static	void	pc98_set_baud_rate	__P((struct com_s *com, int count));
493static	void	pc98_i8251_reset	__P((struct com_s *com, int mode, int command));
494static	void	pc98_disable_i8251_interrupt	__P((struct com_s *com, int mod));
495static	void	pc98_enable_i8251_interrupt	__P((struct com_s *com, int mod));
496static	int	pc98_check_i8251_interrupt	__P((struct com_s *com));
497static	int	pc98_i8251_get_cmd	__P((struct com_s *com));
498static	int	pc98_i8251_get_mod	__P((struct com_s *com));
499static	void	pc98_i8251_set_cmd	__P((struct com_s *com, int x));
500static	void	pc98_i8251_or_cmd	__P((struct com_s *com, int x));
501static	void	pc98_i8251_clear_cmd	__P((struct com_s *com, int x));
502static	void	pc98_i8251_clear_or_cmd	__P((struct com_s *com, int clr, int x));
503static	int	pc98_check_if_type	__P((int iobase, struct siodev *iod));
504static	void	pc98_check_sysclock	__P((void));
505static	int	pc98_set_ioport		__P((struct com_s *com, int io_base));
506
507#define com_int_Tx_disable(com) \
508		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP)
509#define com_int_Tx_enable(com) \
510		pc98_enable_i8251_interrupt(com,IEN_TxFLAG)
511#define com_int_Rx_disable(com) \
512		pc98_disable_i8251_interrupt(com,IEN_Rx)
513#define com_int_Rx_enable(com) \
514		pc98_enable_i8251_interrupt(com,IEN_Rx)
515#define com_int_TxRx_disable(com) \
516		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx)
517#define com_int_TxRx_enable(com) \
518		pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx)
519#define com_send_break_on(com) \
520		pc98_i8251_or_cmd(com,CMD8251_SBRK)
521#define com_send_break_off(com) \
522		pc98_i8251_clear_cmd(com,CMD8251_SBRK)
523
524struct speedtab pc98speedtab[] = {	/* internal RS232C interface */
525	0,	0,
526	50,	50,
527	75,	75,
528	150,	150,
529	200,	200,
530	300,	300,
531	600,	600,
532	1200,	1200,
533	2400,	2400,
534	4800,	4800,
535	9600,	9600,
536	19200,	19200,
537	38400,	38400,
538	76800,	76800,
539	20800,	20800,
540	41600,	41600,
541	15600,	15600,
542	31200,	31200,
543	62400,	62400,
544	-1,	-1
545};
546#ifdef COM_IF_PIO9032B
547struct speedtab comspeedtab_pio9032b[] = {
548	300,	6,
549	600,	5,
550	1200,	4,
551	2400,	3,
552	4800,	2,
553	9600,	1,
554	19200,	0,
555	38400,	7,
556	-1,	-1
557};
558#endif
559
560#ifdef COM_IF_B98_01
561struct speedtab comspeedtab_b98_01[] = {
562	0,	0,
563	75,	15,
564	150,	14,
565	300,	13,
566	600,	12,
567	1200,	11,
568	2400,	10,
569	4800,	9,
570	9600,	8,
571	19200,	7,
572	38400,	6,
573	76800,	5,
574	153600,	4,
575	-1,	-1
576};
577#endif
578#endif /* PC98 */
579
580static	struct speedtab comspeedtab[] = {
581	{ 0,		0 },
582	{ 50,		COMBRD(50) },
583	{ 75,		COMBRD(75) },
584	{ 110,		COMBRD(110) },
585	{ 134,		COMBRD(134) },
586	{ 150,		COMBRD(150) },
587	{ 200,		COMBRD(200) },
588	{ 300,		COMBRD(300) },
589	{ 600,		COMBRD(600) },
590	{ 1200,		COMBRD(1200) },
591	{ 1800,		COMBRD(1800) },
592	{ 2400,		COMBRD(2400) },
593	{ 4800,		COMBRD(4800) },
594	{ 9600,		COMBRD(9600) },
595	{ 19200,	COMBRD(19200) },
596	{ 38400,	COMBRD(38400) },
597	{ 57600,	COMBRD(57600) },
598	{ 115200,	COMBRD(115200) },
599	{ -1,		-1 }
600};
601
602#ifdef COM_ESP
603/* XXX configure this properly. */
604static	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
605static	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
606#endif
607
608#if NCRD > 0
609/*
610 *	PC-Card (PCMCIA) specific code.
611 */
612static int card_intr(struct pccard_dev *);	/* Interrupt handler */
613static void siounload(struct pccard_dev *);	/* Disable driver */
614static void siosuspend(struct pccard_dev *);	/* Suspend driver */
615static int sioinit(struct pccard_dev *, int);	/* init device */
616
617static struct pccard_drv sio_info = {
618	driver_name,
619	card_intr,
620	siounload,
621	siosuspend,
622	sioinit,
623	0,			/* Attributes - presently unused */
624	&tty_imask		/* Interrupt mask for device */
625				/* XXX - Should this also include net_imask? */
626};
627
628/*
629 *	Called when a power down is requested. Shuts down the
630 *	device and configures the device as unavailable (but
631 *	still loaded...). A resume is done by calling
632 *	sioinit with first=0. This is called when the user suspends
633 *	the system, or the APM code suspends the system.
634 */
635static void
636siosuspend(struct pccard_dev *dp)
637{
638	printf("sio%d: suspending\n", dp->isahd.id_unit);
639}
640
641/*
642 *	Initialize the device - called from Slot manager.
643 *	If first is set, then check for the device's existence
644 *	before initializing it.  Once initialized, the device table may
645 *	be set up.
646 */
647int
648sioinit(struct pccard_dev *dp, int first)
649{
650
651	/* validate unit number. */
652	if (first) {
653		if (dp->isahd.id_unit >= NSIO)
654			return(ENODEV);
655		/* Make sure it isn't already probed. */
656		if (com_addr(dp->isahd.id_unit))
657			return(EBUSY);
658		/*
659		 * Probe the device. If a value is returned, the
660		 * device was found at the location.
661		 */
662		if (sioprobe(&dp->isahd)==0)
663			return(ENXIO);
664		if (sioattach(&dp->isahd)==0)
665			return(ENXIO);
666	}
667	/*
668	 * XXX TODO:
669	 * If it was initialized before, the device structure
670	 * should also be initialized.  We should
671	 * reset (and possibly restart) the hardware, but
672	 * I am not sure of the best way to do this...
673	 */
674	return(0);
675}
676
677/*
678 *	siounload - unload the driver and clear the table.
679 *	XXX TODO:
680 *	This is usually called when the card is ejected, but
681 *	can be caused by a modunload of a controller driver.
682 *	The idea is to reset the driver's view of the device
683 *	and ensure that any driver entry points such as
684 *	read and write do not hang.
685 */
686static void
687siounload(struct pccard_dev *dp)
688{
689	struct com_s	*com;
690
691	com = com_addr(dp->isahd.id_unit);
692	if (!com->iobase) {
693		printf("sio%d already unloaded!\n",dp->isahd.id_unit);
694		return;
695	}
696	if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
697		com->gone = 1;
698		printf("sio%d: unload\n", dp->isahd.id_unit);
699		com->tp->t_gen++;
700		ttyclose(com->tp);
701		ttwakeup(com->tp);
702		ttwwakeup(com->tp);
703	} else {
704		com_addr(com->unit) = NULL;
705		bzero(com, sizeof *com);
706		free(com,M_TTYS);
707		printf("sio%d: unload,gone\n", dp->isahd.id_unit);
708	}
709}
710
711/*
712 *	card_intr - Shared interrupt called from
713 *	front end of PC-Card handler.
714 */
715static int
716card_intr(struct pccard_dev *dp)
717{
718	struct com_s	*com;
719	com = com_addr(dp->isahd.id_unit);
720	if (com && !com_addr(dp->isahd.id_unit)->gone)
721		siointr1(com_addr(dp->isahd.id_unit));
722	return(1);
723}
724#endif /* NCRD > 0 */
725
726static int
727sioprobe(dev)
728	struct isa_device	*dev;
729{
730	static bool_t	already_init;
731	bool_t		failures[10];
732	int		fn;
733	struct isa_device	*idev;
734	Port_t		iobase;
735	u_char		mcr_image;
736	int		result;
737#ifdef PC98
738	struct isa_device	*xdev;
739	int		irqout=0;
740	int		ret = 0;
741	int		tmp;
742	struct		siodev	iod;
743#else
744	struct isa_device	*xdev;
745#endif
746
747	if (!already_init) {
748		/*
749		 * Turn off MCR_IENABLE for all likely serial ports.  An unused
750		 * port with its MCR_IENABLE gate open will inhibit interrupts
751		 * from any used port that shares the interrupt vector.
752		 * XXX the gate enable is elsewhere for some multiports.
753		 */
754		for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++)
755			if (xdev->id_driver == &siodriver && xdev->id_enabled)
756#ifdef PC98
757				if (IS_PC98IN(xdev->id_iobase))
758					outb(xdev->id_iobase + 2, 0xf2);
759				else
760#endif
761				outb(xdev->id_iobase + com_mcr, 0);
762#if NCRD > 0
763		/*
764		 * If PC-Card probe required, then register driver with
765		 * slot manager.
766		 */
767		pccard_add_driver(&sio_info);
768#endif
769		already_init = TRUE;
770	}
771
772#ifdef PC98
773	/*
774	 * If the port is i8251 UART (internal, B98_01)
775	 */
776	if(pc98_check_if_type(dev->id_iobase, &iod) == -1)
777		return 0;
778	if(IS_8251(iod.if_type)){
779		if ( iod.irq > 0 )
780			dev->id_irq = (1 << iod.irq);
781		outb(iod.cmd, 0);
782		DELAY(10);
783		outb(iod.cmd, 0);
784		DELAY(10);
785		outb(iod.cmd, 0);
786		DELAY(10);
787		outb(iod.cmd, CMD8251_RESET);
788		DELAY(1000);		/* for a while...*/
789		outb(iod.cmd, 0xf2);	/* MODE (dummy) */
790		DELAY(10);
791		outb(iod.cmd, 0x01);	/* CMD (dummy) */
792		DELAY(1000);		/* for a while...*/
793		if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) {
794			ret = 0;
795		}
796		switch (iod.if_type) {
797		case COM_IF_INTERNAL:
798			COM_INT_DISABLE
799			tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx));
800			outb( iod.ctrl, tmp|IEN_TxEMP );
801			ret = isa_irq_pending(dev) ? 4 : 0;
802			outb( iod.ctrl, tmp );
803			COM_INT_ENABLE
804			break;
805#ifdef COM_IF_B98_01
806		case COM_IF_B98_01:
807			/* B98_01 doesn't activate TxEMP interrupt line
808			   when being reset, so we can't check irq pending.*/
809			ret = 4;
810			break;
811#endif
812		}
813		if (epson_machine_id==0x20) {	/* XXX */
814			ret = 4;
815		}
816		return ret;
817	}
818#endif /* PC98 */
819	/*
820	 * If the device is on a multiport card and has an AST/4
821	 * compatible interrupt control register, initialize this
822	 * register and prepare to leave MCR_IENABLE clear in the mcr.
823	 * Otherwise, prepare to set MCR_IENABLE in the mcr.
824	 * Point idev to the device struct giving the correct id_irq.
825	 * This is the struct for the master device if there is one.
826	 */
827	idev = dev;
828	mcr_image = MCR_IENABLE;
829#ifdef COM_MULTIPORT
830	if (COM_ISMULTIPORT(dev)) {
831		idev = find_isadev(isa_devtab_tty, &siodriver,
832				   COM_MPMASTER(dev));
833		if (idev == NULL) {
834			printf("sio%d: master device %d not configured\n",
835			       dev->id_unit, COM_MPMASTER(dev));
836			return (0);
837		}
838#ifndef PC98
839		if (!COM_NOTAST4(dev)) {
840			outb(idev->id_iobase + com_scr,
841			     idev->id_irq ? 0x80 : 0);
842			mcr_image = 0;
843		}
844#endif /* !PC98 */
845	}
846#endif /* COM_MULTIPORT */
847	if (idev->id_irq == 0)
848		mcr_image = 0;
849
850#ifdef PC98
851	switch(idev->id_irq){
852		case IRQ3: irqout = 4; break;
853		case IRQ5: irqout = 5; break;
854		case IRQ6: irqout = 6; break;
855		case IRQ12: irqout = 7; break;
856		default:
857			printf("sio%d: irq configuration error\n",dev->id_unit);
858			return (0);
859	}
860	outb(dev->id_iobase+0x1000, irqout);
861#endif
862	bzero(failures, sizeof failures);
863	iobase = dev->id_iobase;
864
865	if (COM_LLCONSOLE(dev)) {
866		printf("sio%d: reserved for low-level i/o\n", dev->id_unit);
867		return (0);
868	}
869
870	/*
871	 * We don't want to get actual interrupts, just masked ones.
872	 * Interrupts from this line should already be masked in the ICU,
873	 * but mask them in the processor as well in case there are some
874	 * (misconfigured) shared interrupts.
875	 */
876	disable_intr();
877/* EXTRA DELAY? */
878
879	/*
880	 * Initialize the speed and the word size and wait long enough to
881	 * drain the maximum of 16 bytes of junk in device output queues.
882	 * The speed is undefined after a master reset and must be set
883	 * before relying on anything related to output.  There may be
884	 * junk after a (very fast) soft reboot and (apparently) after
885	 * master reset.
886	 * XXX what about the UART bug avoided by waiting in comparam()?
887	 * We don't want to to wait long enough to drain at 2 bps.
888	 */
889	if (iobase == siocniobase)
890		DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
891	else {
892		outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
893		outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
894		outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
895		outb(iobase + com_cfcr, CFCR_8BITS);
896		DELAY((16 + 1) * 1000000 / (9600 / 10));
897	}
898
899	/*
900	 * Enable the interrupt gate and disable device interupts.  This
901	 * should leave the device driving the interrupt line low and
902	 * guarantee an edge trigger if an interrupt can be generated.
903	 */
904/* EXTRA DELAY? */
905	outb(iobase + com_mcr, mcr_image);
906	outb(iobase + com_ier, 0);
907
908	/*
909	 * Attempt to set loopback mode so that we can send a null byte
910	 * without annoying any external device.
911	 */
912/* EXTRA DELAY? */
913	outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
914
915	/*
916	 * Attempt to generate an output interrupt.  On 8250's, setting
917	 * IER_ETXRDY generates an interrupt independent of the current
918	 * setting and independent of whether the THR is empty.  On 16450's,
919	 * setting IER_ETXRDY generates an interrupt independent of the
920	 * current setting.  On 16550A's, setting IER_ETXRDY only
921	 * generates an interrupt when IER_ETXRDY is not already set.
922	 */
923	outb(iobase + com_ier, IER_ETXRDY);
924
925	/*
926	 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
927	 * an interrupt.  They'd better generate one for actually doing
928	 * output.  Loopback may be broken on the same incompatibles but
929	 * it's unlikely to do more than allow the null byte out.
930	 */
931	outb(iobase + com_data, 0);
932	DELAY((1 + 2) * 1000000 / (9600 / 10));
933
934	/*
935	 * Turn off loopback mode so that the interrupt gate works again
936	 * (MCR_IENABLE was hidden).  This should leave the device driving
937	 * an interrupt line high.  It doesn't matter if the interrupt
938	 * line oscillates while we are not looking at it, since interrupts
939	 * are disabled.
940	 */
941/* EXTRA DELAY? */
942	outb(iobase + com_mcr, mcr_image);
943
944	/*
945	 * Check that
946	 *	o the CFCR, IER and MCR in UART hold the values written to them
947	 *	  (the values happen to be all distinct - this is good for
948	 *	  avoiding false positive tests from bus echoes).
949	 *	o an output interrupt is generated and its vector is correct.
950	 *	o the interrupt goes away when the IIR in the UART is read.
951	 */
952/* EXTRA DELAY? */
953	failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
954	failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
955	failures[2] = inb(iobase + com_mcr) - mcr_image;
956	DELAY(10000);		/* Some internal modems need this time */
957	if (idev->id_irq != 0)
958		failures[3] = isa_irq_pending(idev) ? 0 : 1;
959	failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
960	DELAY(1000);		/* XXX */
961	if (idev->id_irq != 0)
962		failures[5] = isa_irq_pending(idev) ? 1	: 0;
963	failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
964
965	/*
966	 * Turn off all device interrupts and check that they go off properly.
967	 * Leave MCR_IENABLE alone.  For ports without a master port, it gates
968	 * the OUT2 output of the UART to
969	 * the ICU input.  Closing the gate would give a floating ICU input
970	 * (unless there is another device driving at) and spurious interrupts.
971	 * (On the system that this was first tested on, the input floats high
972	 * and gives a (masked) interrupt as soon as the gate is closed.)
973	 */
974	outb(iobase + com_ier, 0);
975	outb(iobase + com_cfcr, CFCR_8BITS);	/* dummy to avoid bus echo */
976	failures[7] = inb(iobase + com_ier);
977	DELAY(1000);		/* XXX */
978	if (idev->id_irq != 0)
979		failures[8] = isa_irq_pending(idev) ? 1	: 0;
980	failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
981
982	enable_intr();
983
984	result = IO_COMSIZE;
985	for (fn = 0; fn < sizeof failures; ++fn)
986		if (failures[fn]) {
987			outb(iobase + com_mcr, 0);
988			result = 0;
989			if (COM_VERBOSE(dev))
990				printf("sio%d: probe test %d failed\n",
991				       dev->id_unit, fn);
992		}
993	return (result);
994}
995
996#ifdef COM_ESP
997static int
998espattach(isdp, com, esp_port)
999	struct isa_device	*isdp;
1000	struct com_s		*com;
1001	Port_t			esp_port;
1002{
1003	u_char	dips;
1004	u_char	val;
1005
1006	/*
1007	 * Check the ESP-specific I/O port to see if we're an ESP
1008	 * card.  If not, return failure immediately.
1009	 */
1010	if ((inb(esp_port) & 0xf3) == 0) {
1011		printf(" port 0x%x is not an ESP board?\n", esp_port);
1012		return (0);
1013	}
1014
1015	/*
1016	 * We've got something that claims to be a Hayes ESP card.
1017	 * Let's hope so.
1018	 */
1019
1020	/* Get the dip-switch configuration */
1021	outb(esp_port + ESP_CMD1, ESP_GETDIPS);
1022	dips = inb(esp_port + ESP_STATUS1);
1023
1024	/*
1025	 * Bits 0,1 of dips say which COM port we are.
1026	 */
1027	if (com->iobase == likely_com_ports[dips & 0x03])
1028		printf(" : ESP");
1029	else {
1030		printf(" esp_port has com %d\n", dips & 0x03);
1031		return (0);
1032	}
1033
1034	/*
1035	 * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
1036	 */
1037	outb(esp_port + ESP_CMD1, ESP_GETTEST);
1038	val = inb(esp_port + ESP_STATUS1);	/* clear reg 1 */
1039	val = inb(esp_port + ESP_STATUS2);
1040	if ((val & 0x70) < 0x20) {
1041		printf("-old (%o)", val & 0x70);
1042		return (0);
1043	}
1044
1045	/*
1046	 * Check for ability to emulate 16550:  bit 7 == 1
1047	 */
1048	if ((dips & 0x80) == 0) {
1049		printf(" slave");
1050		return (0);
1051	}
1052
1053	/*
1054	 * Okay, we seem to be a Hayes ESP card.  Whee.
1055	 */
1056	com->esp = TRUE;
1057	com->esp_port = esp_port;
1058	return (1);
1059}
1060#endif /* COM_ESP */
1061
1062static int
1063sioattach(isdp)
1064	struct isa_device	*isdp;
1065{
1066	struct com_s	*com;
1067	dev_t		dev;
1068#ifdef COM_ESP
1069	Port_t		*espp;
1070#endif
1071	Port_t		iobase;
1072	int		s;
1073	int		unit;
1074
1075	isdp->id_ri_flags |= RI_FAST;
1076	iobase = isdp->id_iobase;
1077	unit = isdp->id_unit;
1078	com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
1079	if (com == NULL)
1080		return (0);
1081
1082	/*
1083	 * sioprobe() has initialized the device registers as follows:
1084	 *	o cfcr = CFCR_8BITS.
1085	 *	  It is most important that CFCR_DLAB is off, so that the
1086	 *	  data port is not hidden when we enable interrupts.
1087	 *	o ier = 0.
1088	 *	  Interrupts are only enabled when the line is open.
1089	 *	o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
1090	 *	  interrupt control register or the config specifies no irq.
1091	 *	  Keeping MCR_DTR and MCR_RTS off might stop the external
1092	 *	  device from sending before we are ready.
1093	 */
1094	bzero(com, sizeof *com);
1095	com->unit = unit;
1096	com->cfcr_image = CFCR_8BITS;
1097	com->dtr_wait = 3 * hz;
1098	com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
1099	com->no_irq = isdp->id_irq == 0;
1100	com->tx_fifo_size = 1;
1101	com->iptr = com->ibuf = com->ibuf1;
1102	com->ibufend = com->ibuf1 + RS_IBUFSIZE;
1103	com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
1104	com->obufs[0].l_head = com->obuf1;
1105	com->obufs[1].l_head = com->obuf2;
1106
1107	com->iobase = iobase;
1108#ifdef PC98
1109	if(pc98_set_ioport(com, iobase) == -1)
1110		if((iobase & 0x0f0) == 0xd0) {
1111			com->pc98_if_type = MC16550;
1112			com->data_port = iobase + com_data;
1113			com->int_id_port = iobase + com_iir;
1114			com->modem_ctl_port = iobase + com_mcr;
1115			com->mcr_image = inb(com->modem_ctl_port);
1116			com->line_status_port = iobase + com_lsr;
1117			com->modem_status_port = iobase + com_msr;
1118		}
1119#else /* not PC98 */
1120	com->data_port = iobase + com_data;
1121	com->int_id_port = iobase + com_iir;
1122	com->modem_ctl_port = iobase + com_mcr;
1123	com->mcr_image = inb(com->modem_ctl_port);
1124	com->line_status_port = iobase + com_lsr;
1125	com->modem_status_port = iobase + com_msr;
1126#endif
1127
1128	/*
1129	 * We don't use all the flags from <sys/ttydefaults.h> since they
1130	 * are only relevant for logins.  It's important to have echo off
1131	 * initially so that the line doesn't start blathering before the
1132	 * echo flag can be turned off.
1133	 */
1134	com->it_in.c_iflag = 0;
1135	com->it_in.c_oflag = 0;
1136	com->it_in.c_cflag = TTYDEF_CFLAG;
1137	com->it_in.c_lflag = 0;
1138	if (unit == comconsole) {
1139#ifdef PC98
1140		if(IS_8251(com->pc98_if_type))
1141			DELAY(100000);
1142#endif
1143		com->it_in.c_iflag = TTYDEF_IFLAG;
1144		com->it_in.c_oflag = TTYDEF_OFLAG;
1145		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
1146		com->it_in.c_lflag = TTYDEF_LFLAG;
1147		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
1148		com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
1149	} else
1150		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
1151	termioschars(&com->it_in);
1152	com->it_out = com->it_in;
1153
1154	/* attempt to determine UART type */
1155	printf("sio%d: type", unit);
1156
1157#ifdef DSI_SOFT_MODEM
1158	if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) {
1159	    printf(" Digicom Systems, Inc. SoftModem");
1160	goto determined_type;
1161	}
1162#endif /* DSI_SOFT_MODEM */
1163
1164#ifndef PC98
1165#ifdef COM_MULTIPORT
1166	if (!COM_ISMULTIPORT(isdp))
1167#endif
1168	{
1169		u_char	scr;
1170		u_char	scr1;
1171		u_char	scr2;
1172
1173		scr = inb(iobase + com_scr);
1174		outb(iobase + com_scr, 0xa5);
1175		scr1 = inb(iobase + com_scr);
1176		outb(iobase + com_scr, 0x5a);
1177		scr2 = inb(iobase + com_scr);
1178		outb(iobase + com_scr, scr);
1179		if (scr1 != 0xa5 || scr2 != 0x5a) {
1180			printf(" 8250");
1181			goto determined_type;
1182		}
1183	}
1184#endif /* !PC98 */
1185#ifdef PC98
1186	if(IS_8251(com->pc98_if_type)){
1187		com_int_TxRx_disable( com );
1188		com_cflag_and_speed_set( com, com->it_in.c_cflag,
1189						comdefaultrate );
1190		com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
1191		com_send_break_off( com );
1192		switch(com->pc98_if_type){
1193		case COM_IF_INTERNAL:
1194			printf(" 8251 (internal)");
1195			break;
1196#ifdef COM_IF_PC9861K
1197		case COM_IF_PC9861K:
1198			printf(" 8251 (PC9861K)");
1199			break;
1200#endif
1201#ifdef COM_IF_PIO9032B
1202		case COM_IF_PIO9032B:
1203			printf(" 8251 (PIO9032B)");
1204			break;
1205#endif
1206#ifdef COM_IF_B98_01
1207		case COM_IF_B98_01:
1208			printf(" 8251 (B98_01)");
1209			break;
1210#endif
1211		}
1212	} else {
1213#endif /* PC98 */
1214	outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
1215	DELAY(100);
1216	switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
1217	case FIFO_RX_LOW:
1218		printf(" 16450");
1219		break;
1220	case FIFO_RX_MEDL:
1221		printf(" 16450?");
1222		break;
1223	case FIFO_RX_MEDH:
1224		printf(" 16550?");
1225		break;
1226	case FIFO_RX_HIGH:
1227		printf(" 16550A");
1228		if (COM_NOFIFO(isdp)) {
1229			printf(" fifo disabled");
1230		} else {
1231			com->hasfifo = TRUE;
1232			com->tx_fifo_size = 16;
1233#ifdef COM_ESP
1234			for (espp = likely_esp_ports; *espp != 0; espp++)
1235				if (espattach(isdp, com, *espp)) {
1236					com->tx_fifo_size = 1024;
1237					break;
1238				}
1239#endif
1240		}
1241#if 0
1242		/*
1243		 * Check for the Startech ST16C650 chip.
1244		 * it has a shadow register under the com_iir,
1245		 * which can only be accessed when cfcr == 0xff
1246		 */
1247		{
1248		u_char i, j;
1249
1250		i = inb(iobase + com_iir);
1251		outb(iobase + com_cfcr, 0xff);
1252		outb(iobase + com_iir, 0x0);
1253		outb(iobase + com_cfcr, CFCR_8BITS);
1254		j = inb(iobase + com_iir);
1255		outb(iobase + com_iir, i);
1256		if (i != j) {
1257			printf(" 16550A");
1258		} else {
1259			com->tx_fifo_size = 32;
1260			printf(" 16650");
1261		}
1262		if (!com->tx_fifo_size)
1263			printf(" fifo disabled");
1264		}
1265#endif
1266		break;
1267	}
1268#ifdef COM_ESP
1269	if (com->esp) {
1270		/*
1271		 * Set 16550 compatibility mode.
1272		 * We don't use the ESP_MODE_SCALE bit to increase the
1273		 * fifo trigger levels because we can't handle large
1274		 * bursts of input.
1275		 * XXX flow control should be set in comparam(), not here.
1276		 */
1277		outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1278		outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1279
1280		/* Set RTS/CTS flow control. */
1281		outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1282		outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1283		outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1284
1285		/* Set flow-control levels. */
1286		outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1287		outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1288		outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1289		outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1290		outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1291	}
1292#endif /* COM_ESP */
1293	outb(iobase + com_fifo, 0);
1294determined_type: ;
1295
1296#ifdef COM_MULTIPORT
1297	if (COM_ISMULTIPORT(isdp)) {
1298		com->multiport = TRUE;
1299		printf(" (multiport");
1300		if (unit == COM_MPMASTER(isdp))
1301			printf(" master");
1302		printf(")");
1303		com->no_irq = find_isadev(isa_devtab_tty, &siodriver,
1304					  COM_MPMASTER(isdp))->id_irq == 0;
1305	 }
1306#endif /* COM_MULTIPORT */
1307#ifdef PC98
1308	}
1309#endif
1310	printf("\n");
1311
1312	s = spltty();
1313	com_addr(unit) = com;
1314	splx(s);
1315
1316	dev = makedev(CDEV_MAJOR, 0);
1317	cdevsw_add(&dev, &sio_cdevsw, NULL);
1318#ifdef DEVFS
1319	com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
1320		unit, DV_CHR,
1321		UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
1322	com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
1323		unit | CONTROL_INIT_STATE, DV_CHR,
1324		UID_ROOT, GID_WHEEL, 0600, "ttyid%n", unit);
1325	com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
1326		unit | CONTROL_LOCK_STATE, DV_CHR,
1327		UID_ROOT, GID_WHEEL, 0600, "ttyld%n", unit);
1328	com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
1329		unit | CALLOUT_MASK, DV_CHR,
1330		UID_UUCP, GID_DIALER, 0660, "cuaa%n", unit);
1331	com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
1332		unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
1333		UID_UUCP, GID_DIALER, 0660, "cuaia%n", unit);
1334	com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
1335		unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
1336		UID_UUCP, GID_DIALER, 0660, "cuala%n", unit);
1337#endif
1338	return (1);
1339}
1340
1341static int
1342sioopen(dev, flag, mode, p)
1343	dev_t		dev;
1344	int		flag;
1345	int		mode;
1346	struct proc	*p;
1347{
1348	struct com_s	*com;
1349	int		error;
1350	Port_t		iobase;
1351	int		mynor;
1352	int		s;
1353	struct tty	*tp;
1354	int		unit;
1355
1356	mynor = minor(dev);
1357	unit = MINOR_TO_UNIT(mynor);
1358	if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
1359		return (ENXIO);
1360	if (com->gone)
1361		return (ENXIO);
1362	if (mynor & CONTROL_MASK)
1363		return (0);
1364#if 0 /* XXX */
1365	tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
1366#else
1367	tp = com->tp = &sio_tty[unit];
1368#endif
1369	s = spltty();
1370	/*
1371	 * We jump to this label after all non-interrupted sleeps to pick
1372	 * up any changes of the device state.
1373	 */
1374open_top:
1375	while (com->state & CS_DTR_OFF) {
1376		error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
1377		if (com_addr(unit) == NULL)
1378			return (ENXIO);
1379		if (error != 0 || com->gone)
1380			goto out;
1381	}
1382	if (tp->t_state & TS_ISOPEN) {
1383		/*
1384		 * The device is open, so everything has been initialized.
1385		 * Handle conflicts.
1386		 */
1387		if (mynor & CALLOUT_MASK) {
1388			if (!com->active_out) {
1389				error = EBUSY;
1390				goto out;
1391			}
1392		} else {
1393			if (com->active_out) {
1394				if (flag & O_NONBLOCK) {
1395					error = EBUSY;
1396					goto out;
1397				}
1398				error =	tsleep(&com->active_out,
1399					       TTIPRI | PCATCH, "siobi", 0);
1400				if (com_addr(unit) == NULL)
1401					return (ENXIO);
1402				if (error != 0 || com->gone)
1403					goto out;
1404				goto open_top;
1405			}
1406		}
1407		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
1408			error = EBUSY;
1409			goto out;
1410		}
1411	} else {
1412		/*
1413		 * The device isn't open, so there are no conflicts.
1414		 * Initialize it.  Initialization is done twice in many
1415		 * cases: to preempt sleeping callin opens if we are
1416		 * callout, and to complete a callin open after DCD rises.
1417		 */
1418		tp->t_oproc = comstart;
1419		tp->t_param = comparam;
1420		tp->t_dev = dev;
1421		tp->t_termios = mynor & CALLOUT_MASK
1422				? com->it_out : com->it_in;
1423#ifdef PC98
1424		if(!IS_8251(com->pc98_if_type))
1425#endif
1426		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
1427		com->poll = com->no_irq;
1428		com->poll_output = com->loses_outints;
1429		++com->wopeners;
1430		error = comparam(tp, &tp->t_termios);
1431		--com->wopeners;
1432		if (error != 0)
1433			goto out;
1434#ifdef PC98
1435		if(IS_8251(com->pc98_if_type)){
1436			com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS);
1437			pc98_msrint_start(dev);
1438		}
1439#endif
1440		/*
1441		 * XXX we should goto open_top if comparam() slept.
1442		 */
1443		ttsetwater(tp);
1444		iobase = com->iobase;
1445		if (com->hasfifo) {
1446			/*
1447			 * (Re)enable and drain fifos.
1448			 *
1449			 * Certain SMC chips cause problems if the fifos
1450			 * are enabled while input is ready.  Turn off the
1451			 * fifo if necessary to clear the input.  We test
1452			 * the input ready bit after enabling the fifos
1453			 * since we've already enabled them in comparam()
1454			 * and to handle races between enabling and fresh
1455			 * input.
1456			 */
1457			while (TRUE) {
1458				outb(iobase + com_fifo,
1459				     FIFO_RCV_RST | FIFO_XMT_RST
1460				     | com->fifo_image);
1461				/*
1462				 * XXX the delays are for superstitious
1463				 * historical reasons.  It must be less than
1464				 * the character time at the maximum
1465				 * supported speed (87 usec at 115200 bps
1466				 * 8N1).  Otherwise we might loop endlessly
1467				 * if data is streaming in.  We used to use
1468				 * delays of 100.  That usually worked
1469				 * because DELAY(100) used to usually delay
1470				 * for about 85 usec instead of 100.
1471				 */
1472				DELAY(50);
1473				if (!(inb(com->line_status_port) & LSR_RXRDY))
1474					break;
1475				outb(iobase + com_fifo, 0);
1476				DELAY(50);
1477				(void) inb(com->data_port);
1478			}
1479		}
1480
1481		disable_intr();
1482#ifdef PC98
1483		if(IS_8251(com->pc98_if_type)){
1484			com_tiocm_bis(com, TIOCM_LE);
1485			com->pc98_prev_modem_status =
1486				pc98_get_modem_status(com);
1487			com_int_Rx_enable(com);
1488		} else {
1489#endif
1490		(void) inb(com->line_status_port);
1491		(void) inb(com->data_port);
1492		com->prev_modem_status = com->last_modem_status
1493		    = inb(com->modem_status_port);
1494		outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
1495				       | IER_EMSC);
1496#ifdef PC98
1497		}
1498#endif
1499		enable_intr();
1500		/*
1501		 * Handle initial DCD.  Callout devices get a fake initial
1502		 * DCD (trapdoor DCD).  If we are callout, then any sleeping
1503		 * callin opens get woken up and resume sleeping on "siobi"
1504		 * instead of "siodcd".
1505		 */
1506		/*
1507		 * XXX `mynor & CALLOUT_MASK' should be
1508		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
1509		 * TRAPDOOR_CARRIER is the default initial state for callout
1510		 * devices and SOFT_CARRIER is like CLOCAL except it hides
1511		 * the true carrier.
1512		 */
1513#ifdef PC98
1514		if ((IS_8251(com->pc98_if_type) &&
1515			(pc98_get_modem_status(com) & TIOCM_CAR)) ||
1516		    (!IS_8251(com->pc98_if_type) &&
1517			(com->prev_modem_status & MSR_DCD)) ||
1518		    mynor & CALLOUT_MASK)
1519#else
1520		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
1521#endif
1522			(*linesw[tp->t_line].l_modem)(tp, 1);
1523	}
1524	/*
1525	 * Wait for DCD if necessary.
1526	 */
1527	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1528	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1529		++com->wopeners;
1530		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
1531		if (com_addr(unit) == NULL)
1532			return (ENXIO);
1533		--com->wopeners;
1534		if (error != 0 || com->gone)
1535			goto out;
1536		goto open_top;
1537	}
1538	error =	(*linesw[tp->t_line].l_open)(dev, tp);
1539	disc_optim(tp, &tp->t_termios, com);
1540	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1541		com->active_out = TRUE;
1542	siosettimeout();
1543out:
1544	splx(s);
1545	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
1546		comhardclose(com);
1547	return (error);
1548}
1549
1550static int
1551sioclose(dev, flag, mode, p)
1552	dev_t		dev;
1553	int		flag;
1554	int		mode;
1555	struct proc	*p;
1556{
1557	struct com_s	*com;
1558	int		mynor;
1559	int		s;
1560	struct tty	*tp;
1561
1562	mynor = minor(dev);
1563	if (mynor & CONTROL_MASK)
1564		return (0);
1565	com = com_addr(MINOR_TO_UNIT(mynor));
1566	tp = com->tp;
1567	s = spltty();
1568	(*linesw[tp->t_line].l_close)(tp, flag);
1569#ifdef PC98
1570	com->modem_checking = 0;
1571#endif
1572	disc_optim(tp, &tp->t_termios, com);
1573	siostop(tp, FREAD | FWRITE);
1574	comhardclose(com);
1575	ttyclose(tp);
1576	siosettimeout();
1577	splx(s);
1578	if (com->gone) {
1579		printf("sio%d: gone\n", com->unit);
1580		s = spltty();
1581		com_addr(com->unit) = 0;
1582		bzero(tp,sizeof *tp);
1583		bzero(com,sizeof *com);
1584		free(com,M_TTYS);
1585		splx(s);
1586	}
1587	return (0);
1588}
1589
1590static void
1591comhardclose(com)
1592	struct com_s	*com;
1593{
1594	Port_t		iobase;
1595	int		s;
1596	struct tty	*tp;
1597	int		unit;
1598
1599	unit = com->unit;
1600	iobase = com->iobase;
1601	s = spltty();
1602	com->poll = FALSE;
1603	com->poll_output = FALSE;
1604	com->do_timestamp = FALSE;
1605	com->do_dcd_timestamp = FALSE;
1606#ifdef PC98
1607	if(IS_8251(com->pc98_if_type))
1608		com_send_break_off(com);
1609	else
1610#endif
1611	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1612	{
1613#ifdef PC98
1614		int tmp;
1615		if(IS_8251(com->pc98_if_type))
1616			com_int_TxRx_disable(com);
1617		else
1618#endif
1619		outb(iobase + com_ier, 0);
1620		tp = com->tp;
1621#ifdef PC98
1622		if(IS_8251(com->pc98_if_type))
1623			tmp = pc98_get_modem_status(com) & TIOCM_CAR;
1624		else
1625			tmp = com->prev_modem_status & MSR_DCD;
1626#endif
1627		if (tp->t_cflag & HUPCL
1628		    /*
1629		     * XXX we will miss any carrier drop between here and the
1630		     * next open.  Perhaps we should watch DCD even when the
1631		     * port is closed; it is not sufficient to check it at
1632		     * the next open because it might go up and down while
1633		     * we're not watching.
1634		     */
1635		    || !com->active_out
1636#ifdef PC98
1637		       && !(tmp)
1638#else
1639		       && !(com->prev_modem_status & MSR_DCD)
1640#endif
1641		       && !(com->it_in.c_cflag & CLOCAL)
1642		    || !(tp->t_state & TS_ISOPEN)) {
1643#ifdef PC98
1644			if(IS_8251(com->pc98_if_type))
1645				com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
1646			else
1647#endif
1648			(void)commctl(com, TIOCM_DTR, DMBIC);
1649			if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
1650				timeout(siodtrwakeup, com, com->dtr_wait);
1651				com->state |= CS_DTR_OFF;
1652			}
1653		}
1654#ifdef PC98
1655		else {
1656			if(IS_8251(com->pc98_if_type))
1657				com_tiocm_bic(com, TIOCM_LE );
1658		}
1659#endif
1660	}
1661	if (com->hasfifo) {
1662		/*
1663		 * Disable fifos so that they are off after controlled
1664		 * reboots.  Some BIOSes fail to detect 16550s when the
1665		 * fifos are enabled.
1666		 */
1667		outb(iobase + com_fifo, 0);
1668	}
1669	com->active_out = FALSE;
1670	wakeup(&com->active_out);
1671	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */
1672	splx(s);
1673}
1674
1675static int
1676sioread(dev, uio, flag)
1677	dev_t		dev;
1678	struct uio	*uio;
1679	int		flag;
1680{
1681	int		mynor;
1682	int		unit;
1683	struct tty	*tp;
1684
1685	mynor = minor(dev);
1686	if (mynor & CONTROL_MASK)
1687		return (ENODEV);
1688	unit = MINOR_TO_UNIT(mynor);
1689	if (com_addr(unit)->gone)
1690		return (ENODEV);
1691	tp = com_addr(unit)->tp;
1692	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1693}
1694
1695static int
1696siowrite(dev, uio, flag)
1697	dev_t		dev;
1698	struct uio	*uio;
1699	int		flag;
1700{
1701	int		mynor;
1702	struct tty	*tp;
1703	int		unit;
1704
1705	mynor = minor(dev);
1706	if (mynor & CONTROL_MASK)
1707		return (ENODEV);
1708
1709	unit = MINOR_TO_UNIT(mynor);
1710	if (com_addr(unit)->gone)
1711		return (ENODEV);
1712	tp = com_addr(unit)->tp;
1713	/*
1714	 * (XXX) We disallow virtual consoles if the physical console is
1715	 * a serial port.  This is in case there is a display attached that
1716	 * is not the console.  In that situation we don't need/want the X
1717	 * server taking over the console.
1718	 */
1719	if (constty != NULL && unit == comconsole)
1720		constty = NULL;
1721	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
1722}
1723
1724static void
1725siobusycheck(chan)
1726	void	*chan;
1727{
1728	struct com_s	*com;
1729	int		s;
1730
1731	com = (struct com_s *)chan;
1732
1733	/*
1734	 * Clear TS_BUSY if low-level output is complete.
1735	 * spl locking is sufficient because siointr1() does not set CS_BUSY.
1736	 * If siointr1() clears CS_BUSY after we look at it, then we'll get
1737	 * called again.  Reading the line status port outside of siointr1()
1738	 * is safe because CS_BUSY is clear so there are no output interrupts
1739	 * to lose.
1740	 */
1741	s = spltty();
1742	if (com->state & CS_BUSY)
1743		com->extra_state &= ~CSE_BUSYCHECK;	/* False alarm. */
1744#ifdef	PC98
1745	else if (IS_8251(com->pc98_if_type) &&
1746		 (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP))
1747		 == (STS8251_TxRDY | STS8251_TxEMP) ||
1748		 (inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1749		 == (LSR_TSRE | LSR_TXRDY)) {
1750#else
1751	else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1752	    == (LSR_TSRE | LSR_TXRDY)) {
1753#endif
1754		com->tp->t_state &= ~TS_BUSY;
1755		ttwwakeup(com->tp);
1756		com->extra_state &= ~CSE_BUSYCHECK;
1757	} else
1758		timeout(siobusycheck, com, hz / 100);
1759	splx(s);
1760}
1761
1762static void
1763siodtrwakeup(chan)
1764	void	*chan;
1765{
1766	struct com_s	*com;
1767
1768	com = (struct com_s *)chan;
1769	com->state &= ~CS_DTR_OFF;
1770	wakeup(&com->dtr_wait);
1771}
1772
1773void
1774siointr(unit)
1775	int	unit;
1776{
1777#ifndef COM_MULTIPORT
1778	siointr1(com_addr(unit));
1779#else /* COM_MULTIPORT */
1780	struct com_s    *com;
1781	bool_t		possibly_more_intrs;
1782
1783	/*
1784	 * Loop until there is no activity on any port.  This is necessary
1785	 * to get an interrupt edge more than to avoid another interrupt.
1786	 * If the IRQ signal is just an OR of the IRQ signals from several
1787	 * devices, then the edge from one may be lost because another is
1788	 * on.
1789	 */
1790	do {
1791		possibly_more_intrs = FALSE;
1792		for (unit = 0; unit < NSIO; ++unit) {
1793			com = com_addr(unit);
1794#ifdef PC98
1795			if (com != NULL
1796			    && !com->gone
1797			    && IS_8251(com->pc98_if_type)){
1798				siointr1(com);
1799			} else
1800#endif /* PC98 */
1801			if (com != NULL
1802			    && !com->gone
1803			    && (inb(com->int_id_port) & IIR_IMASK)
1804			       != IIR_NOPEND) {
1805				siointr1(com);
1806				possibly_more_intrs = TRUE;
1807			}
1808		}
1809	} while (possibly_more_intrs);
1810#endif /* COM_MULTIPORT */
1811}
1812
1813static void
1814siointr1(com)
1815	struct com_s	*com;
1816{
1817	u_char	line_status;
1818	u_char	modem_status;
1819	u_char	*ioptr;
1820	u_char	recv_data;
1821#ifdef PC98
1822	u_char	tmp=0;
1823recv_data=0;
1824#endif /* PC98 */
1825
1826	while (TRUE) {
1827#ifdef PC98
1828status_read:;
1829		if (IS_8251(com->pc98_if_type)) {
1830			tmp = inb(com->sts_port);
1831more_intr:
1832			line_status = 0;
1833			if (tmp & STS8251_TxRDY) line_status |= LSR_TXRDY;
1834			if (tmp & STS8251_RxRDY) line_status |= LSR_RXRDY;
1835			if (tmp & STS8251_TxEMP) line_status |= LSR_TSRE;
1836			if (tmp & STS8251_PE)    line_status |= LSR_PE;
1837			if (tmp & STS8251_OE)    line_status |= LSR_OE;
1838			if (tmp & STS8251_FE)    line_status |= LSR_FE;
1839			if (tmp & STS8251_BD_SD) line_status |= LSR_BI;
1840		} else
1841#endif /* PC98 */
1842		line_status = inb(com->line_status_port);
1843
1844		/* input event? (check first to help avoid overruns) */
1845		while (line_status & LSR_RCV_MASK) {
1846			/* break/unnattached error bits or real input? */
1847#ifdef PC98
1848			if(IS_8251(com->pc98_if_type)){
1849				recv_data = inb(com->data_port);
1850				if(tmp & 0x78){
1851					pc98_i8251_or_cmd(com,CMD8251_ER);
1852					recv_data = 0;
1853				}
1854			} else {
1855#endif /* PC98 */
1856			if (!(line_status & LSR_RXRDY))
1857				recv_data = 0;
1858			else
1859				recv_data = inb(com->data_port);
1860#ifdef PC98
1861			}
1862#endif
1863			if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
1864				/*
1865				 * Don't store BI if IGNBRK or FE/PE if IGNPAR.
1866				 * Otherwise, push the work to a higher level
1867				 * (to handle PARMRK) if we're bypassing.
1868				 * Otherwise, convert BI/FE and PE+INPCK to 0.
1869				 *
1870				 * This makes bypassing work right in the
1871				 * usual "raw" case (IGNBRK set, and IGNPAR
1872				 * and INPCK clear).
1873				 *
1874				 * Note: BI together with FE/PE means just BI.
1875				 */
1876				if (line_status & LSR_BI) {
1877#if defined(DDB) && defined(BREAK_TO_DEBUGGER)
1878					if (com->unit == comconsole) {
1879						breakpoint();
1880						goto cont;
1881					}
1882#endif
1883					if (com->tp == NULL
1884					    || com->tp->t_iflag & IGNBRK)
1885						goto cont;
1886				} else {
1887					if (com->tp == NULL
1888					    || com->tp->t_iflag & IGNPAR)
1889						goto cont;
1890				}
1891				if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1892				    && (line_status & (LSR_BI | LSR_FE)
1893					|| com->tp->t_iflag & INPCK))
1894					recv_data = 0;
1895			}
1896
1897			++com->bytes_in;
1898			if (com->hotchar != 0 && recv_data == com->hotchar)
1899				setsofttty();
1900			ioptr = com->iptr;
1901			if (ioptr >= com->ibufend)
1902				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1903			else {
1904				if (com->do_timestamp)
1905					microtime(&com->timestamp);
1906				++com_events;
1907				schedsofttty();
1908#if 0 /* for testing input latency vs efficiency */
1909if (com->iptr - com->ibuf == 8)
1910	setsofttty();
1911#endif
1912				ioptr[0] = recv_data;
1913				ioptr[CE_INPUT_OFFSET] = line_status;
1914				com->iptr = ++ioptr;
1915				if (ioptr == com->ihighwater
1916				    && com->state & CS_RTS_IFLOW)
1917#ifdef PC98
1918					if(IS_8251(com->pc98_if_type))
1919						com_tiocm_bic(com, TIOCM_RTS);
1920					else
1921#endif
1922					outb(com->modem_ctl_port,
1923					     com->mcr_image &= ~MCR_RTS);
1924				if (line_status & LSR_OE)
1925					CE_RECORD(com, CE_OVERRUN);
1926			}
1927cont:
1928			/*
1929			 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1930			 * jump from the top of the loop to here
1931			 */
1932#ifdef PC98
1933			if(IS_8251(com->pc98_if_type))
1934				goto status_read;
1935			else
1936#endif
1937			line_status = inb(com->line_status_port) & 0x7F;
1938		}
1939
1940		/* modem status change? (always check before doing output) */
1941#ifdef PC98
1942		if(!IS_8251(com->pc98_if_type)){
1943#endif
1944		modem_status = inb(com->modem_status_port);
1945		if (modem_status != com->last_modem_status) {
1946			if (com->do_dcd_timestamp
1947			    && !(com->last_modem_status & MSR_DCD)
1948			    && modem_status & MSR_DCD)
1949				microtime(&com->dcd_timestamp);
1950
1951			/*
1952			 * Schedule high level to handle DCD changes.  Note
1953			 * that we don't use the delta bits anywhere.  Some
1954			 * UARTs mess them up, and it's easy to remember the
1955			 * previous bits and calculate the delta.
1956			 */
1957			com->last_modem_status = modem_status;
1958			if (!(com->state & CS_CHECKMSR)) {
1959				com_events += LOTS_OF_EVENTS;
1960				com->state |= CS_CHECKMSR;
1961				setsofttty();
1962			}
1963
1964			/* handle CTS change immediately for crisp flow ctl */
1965			if (com->state & CS_CTS_OFLOW) {
1966				if (modem_status & MSR_CTS)
1967					com->state |= CS_ODEVREADY;
1968				else
1969					com->state &= ~CS_ODEVREADY;
1970			}
1971		}
1972#ifdef PC98
1973		}
1974#endif
1975
1976		/* output queued and everything ready? */
1977		if (line_status & LSR_TXRDY
1978		    && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1979			ioptr = com->obufq.l_head;
1980			if (com->tx_fifo_size > 1) {
1981				u_int	ocount;
1982
1983				ocount = com->obufq.l_tail - ioptr;
1984				if (ocount > com->tx_fifo_size)
1985					ocount = com->tx_fifo_size;
1986				com->bytes_out += ocount;
1987				do
1988					outb(com->data_port, *ioptr++);
1989				while (--ocount != 0);
1990			} else {
1991				outb(com->data_port, *ioptr++);
1992				++com->bytes_out;
1993			}
1994#ifdef PC98
1995			if(IS_8251(com->pc98_if_type))
1996				if ( !(pc98_check_i8251_interrupt(com) & IEN_TxFLAG) )
1997					com_int_Tx_enable(com);
1998#endif
1999			com->obufq.l_head = ioptr;
2000			if (ioptr >= com->obufq.l_tail) {
2001				struct lbq	*qp;
2002
2003				qp = com->obufq.l_next;
2004				qp->l_queued = FALSE;
2005				qp = qp->l_next;
2006				if (qp != NULL) {
2007					com->obufq.l_head = qp->l_head;
2008					com->obufq.l_tail = qp->l_tail;
2009					com->obufq.l_next = qp;
2010				} else {
2011					/* output just completed */
2012					com->state &= ~CS_BUSY;
2013#if defined(PC98)
2014					if(IS_8251(com->pc98_if_type))
2015						if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2016							com_int_Tx_disable(com);
2017#endif
2018				}
2019				if (!(com->state & CS_ODONE)) {
2020					com_events += LOTS_OF_EVENTS;
2021					com->state |= CS_ODONE;
2022					setsofttty();	/* handle at high level ASAP */
2023				}
2024			}
2025		}
2026#ifdef PC98
2027		else if (line_status & LSR_TXRDY) {
2028			if(IS_8251(com->pc98_if_type))
2029				if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2030					com_int_Tx_disable(com);
2031		}
2032		if(IS_8251(com->pc98_if_type))
2033			if ((tmp = inb(com->sts_port)) & STS8251_RxRDY)
2034				goto more_intr;
2035#endif
2036
2037		/* finished? */
2038#ifndef COM_MULTIPORT
2039#ifdef PC98
2040		if(IS_8251(com->pc98_if_type))
2041			return;
2042#endif
2043		if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
2044#endif /* COM_MULTIPORT */
2045			return;
2046	}
2047}
2048
2049static int
2050sioioctl(dev, cmd, data, flag, p)
2051	dev_t		dev;
2052	int		cmd;
2053	caddr_t		data;
2054	int		flag;
2055	struct proc	*p;
2056{
2057	struct com_s	*com;
2058	int		error;
2059	Port_t		iobase;
2060	int		mynor;
2061	int		s;
2062	struct tty	*tp;
2063#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2064	int		oldcmd;
2065	struct termios	term;
2066#endif
2067
2068	mynor = minor(dev);
2069	com = com_addr(MINOR_TO_UNIT(mynor));
2070	if (com->gone)
2071		return (ENODEV);
2072	iobase = com->iobase;
2073	if (mynor & CONTROL_MASK) {
2074		struct termios	*ct;
2075
2076		switch (mynor & CONTROL_MASK) {
2077		case CONTROL_INIT_STATE:
2078			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
2079			break;
2080		case CONTROL_LOCK_STATE:
2081			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
2082			break;
2083		default:
2084			return (ENODEV);	/* /dev/nodev */
2085		}
2086		switch (cmd) {
2087		case TIOCSETA:
2088			error = suser(p->p_ucred, &p->p_acflag);
2089			if (error != 0)
2090				return (error);
2091			*ct = *(struct termios *)data;
2092			return (0);
2093		case TIOCGETA:
2094			*(struct termios *)data = *ct;
2095			return (0);
2096		case TIOCGETD:
2097			*(int *)data = TTYDISC;
2098			return (0);
2099		case TIOCGWINSZ:
2100			bzero(data, sizeof(struct winsize));
2101			return (0);
2102#ifdef DSI_SOFT_MODEM
2103		/*
2104		 * Download micro-code to Digicom modem.
2105		 */
2106		case TIOCDSIMICROCODE:
2107			{
2108			u_long l;
2109			u_char *p,*pi;
2110
2111			pi = (u_char*)(*(caddr_t*)data);
2112			error = copyin(pi,&l,sizeof l);
2113			if(error)
2114				{return error;};
2115			pi += sizeof l;
2116
2117			p = malloc(l,M_TEMP,M_NOWAIT);
2118			if(!p)
2119				{return ENOBUFS;}
2120			error = copyin(pi,p,l);
2121			if(error)
2122				{free(p,M_TEMP); return error;};
2123			if(error = LoadSoftModem(
2124			    MINOR_TO_UNIT(mynor),iobase,l,p))
2125				{free(p,M_TEMP); return error;}
2126			free(p,M_TEMP);
2127			return(0);
2128			}
2129#endif /* DSI_SOFT_MODEM */
2130		default:
2131			return (ENOTTY);
2132		}
2133	}
2134	tp = com->tp;
2135#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2136	term = tp->t_termios;
2137	oldcmd = cmd;
2138	error = ttsetcompat(tp, &cmd, data, &term);
2139	if (error != 0)
2140		return (error);
2141	if (cmd != oldcmd)
2142		data = (caddr_t)&term;
2143#endif
2144	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
2145		int	cc;
2146		struct termios *dt = (struct termios *)data;
2147		struct termios *lt = mynor & CALLOUT_MASK
2148				     ? &com->lt_out : &com->lt_in;
2149
2150		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
2151			      | (dt->c_iflag & ~lt->c_iflag);
2152		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
2153			      | (dt->c_oflag & ~lt->c_oflag);
2154		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
2155			      | (dt->c_cflag & ~lt->c_cflag);
2156		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
2157			      | (dt->c_lflag & ~lt->c_lflag);
2158		for (cc = 0; cc < NCCS; ++cc)
2159			if (lt->c_cc[cc] != 0)
2160				dt->c_cc[cc] = tp->t_cc[cc];
2161		if (lt->c_ispeed != 0)
2162			dt->c_ispeed = tp->t_ispeed;
2163		if (lt->c_ospeed != 0)
2164			dt->c_ospeed = tp->t_ospeed;
2165	}
2166	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2167	if (error >= 0)
2168		return (error);
2169	s = spltty();
2170	error = ttioctl(tp, cmd, data, flag);
2171	disc_optim(tp, &tp->t_termios, com);
2172	if (error >= 0) {
2173		splx(s);
2174		return (error);
2175	}
2176#ifdef PC98
2177	if(IS_8251(com->pc98_if_type)){
2178	switch (cmd) {
2179	case TIOCSBRK:
2180		com_send_break_on( com );
2181		break;
2182	case TIOCCBRK:
2183		com_send_break_off( com );
2184		break;
2185	case TIOCSDTR:
2186		com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS );
2187		break;
2188	case TIOCCDTR:
2189		com_tiocm_bic(com, TIOCM_DTR);
2190		break;
2191	/*
2192	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
2193	 * changes get undone on the next call to comparam().
2194	 */
2195	case TIOCMSET:
2196		com_tiocm_set( com, *(int *)data );
2197		break;
2198	case TIOCMBIS:
2199		com_tiocm_bis( com, *(int *)data );
2200		break;
2201	case TIOCMBIC:
2202		com_tiocm_bic( com, *(int *)data );
2203		break;
2204	case TIOCMGET:
2205		*(int *)data = com_tiocm_get(com);
2206		break;
2207	case TIOCMSDTRWAIT:
2208		/* must be root since the wait applies to following logins */
2209		error = suser(p->p_ucred, &p->p_acflag);
2210		if (error != 0) {
2211			splx(s);
2212			return (error);
2213		}
2214		com->dtr_wait = *(int *)data * hz / 100;
2215		break;
2216	case TIOCMGDTRWAIT:
2217		*(int *)data = com->dtr_wait * 100 / hz;
2218		break;
2219	case TIOCTIMESTAMP:
2220		com->do_timestamp = TRUE;
2221		*(struct timeval *)data = com->timestamp;
2222		break;
2223	case TIOCDCDTIMESTAMP:
2224		com->do_dcd_timestamp = TRUE;
2225		*(struct timeval *)data = com->dcd_timestamp;
2226		break;
2227	default:
2228		splx(s);
2229		return (ENOTTY);
2230	}
2231	} else {
2232#endif
2233	switch (cmd) {
2234	case TIOCSBRK:
2235		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
2236		break;
2237	case TIOCCBRK:
2238		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
2239		break;
2240	case TIOCSDTR:
2241		(void)commctl(com, TIOCM_DTR, DMBIS);
2242		break;
2243	case TIOCCDTR:
2244		(void)commctl(com, TIOCM_DTR, DMBIC);
2245		break;
2246	case TIOCMSET:
2247		(void)commctl(com, *(int *)data, DMSET);
2248		break;
2249	case TIOCMBIS:
2250		(void)commctl(com, *(int *)data, DMBIS);
2251		break;
2252	case TIOCMBIC:
2253		(void)commctl(com, *(int *)data, DMBIC);
2254		break;
2255	case TIOCMGET:
2256		*(int *)data = commctl(com, 0, DMGET);
2257		break;
2258	case TIOCMSDTRWAIT:
2259		/* must be root since the wait applies to following logins */
2260		error = suser(p->p_ucred, &p->p_acflag);
2261		if (error != 0) {
2262			splx(s);
2263			return (error);
2264		}
2265		com->dtr_wait = *(int *)data * hz / 100;
2266		break;
2267	case TIOCMGDTRWAIT:
2268		*(int *)data = com->dtr_wait * 100 / hz;
2269		break;
2270	case TIOCTIMESTAMP:
2271		com->do_timestamp = TRUE;
2272		*(struct timeval *)data = com->timestamp;
2273		break;
2274	default:
2275		splx(s);
2276		return (ENOTTY);
2277	}
2278#ifdef PC98
2279	}
2280#endif
2281	splx(s);
2282	return (0);
2283}
2284
2285void
2286siopoll()
2287{
2288	int		unit;
2289
2290	if (com_events == 0)
2291		return;
2292repeat:
2293	for (unit = 0; unit < NSIO; ++unit) {
2294		u_char		*buf;
2295		struct com_s	*com;
2296		u_char		*ibuf;
2297		int		incc;
2298		struct tty	*tp;
2299#ifdef PC98
2300		int		tmp;
2301#endif
2302
2303		com = com_addr(unit);
2304		if (com == NULL)
2305			continue;
2306		if (com->gone)
2307			continue;
2308		tp = com->tp;
2309		if (tp == NULL) {
2310			/*
2311			 * XXX forget any events related to closed devices
2312			 * (actually never opened devices) so that we don't
2313			 * loop.
2314			 */
2315			disable_intr();
2316			incc = com->iptr - com->ibuf;
2317			com->iptr = com->ibuf;
2318			if (com->state & CS_CHECKMSR) {
2319				incc += LOTS_OF_EVENTS;
2320				com->state &= ~CS_CHECKMSR;
2321			}
2322			com_events -= incc;
2323			enable_intr();
2324			if (incc != 0)
2325				log(LOG_DEBUG,
2326				    "sio%d: %d events for device with no tp\n",
2327				    unit, incc);
2328			continue;
2329		}
2330
2331		/* switch the role of the low-level input buffers */
2332		if (com->iptr == (ibuf = com->ibuf)) {
2333			buf = NULL;     /* not used, but compiler can't tell */
2334			incc = 0;
2335		} else {
2336			buf = ibuf;
2337			disable_intr();
2338			incc = com->iptr - buf;
2339			com_events -= incc;
2340			if (ibuf == com->ibuf1)
2341				ibuf = com->ibuf2;
2342			else
2343				ibuf = com->ibuf1;
2344			com->ibufend = ibuf + RS_IBUFSIZE;
2345			com->ihighwater = ibuf + RS_IHIGHWATER;
2346			com->iptr = ibuf;
2347
2348			/*
2349			 * There is now room for another low-level buffer full
2350			 * of input, so enable RTS if it is now disabled and
2351			 * there is room in the high-level buffer.
2352			 */
2353#ifdef PC98
2354			if(IS_8251(com->pc98_if_type))
2355				tmp = com_tiocm_get(com) & TIOCM_RTS;
2356			else
2357				tmp = com->mcr_image & MCR_RTS;
2358#endif
2359			if ((com->state & CS_RTS_IFLOW)
2360#ifdef PC98
2361			    && !(tmp)
2362#else
2363			    && !(com->mcr_image & MCR_RTS)
2364#endif
2365			    && !(tp->t_state & TS_TBLOCK))
2366#ifdef PC98
2367				if(IS_8251(com->pc98_if_type))
2368					com_tiocm_bis(com, TIOCM_RTS);
2369				else
2370#endif
2371				outb(com->modem_ctl_port,
2372				     com->mcr_image |= MCR_RTS);
2373			enable_intr();
2374			com->ibuf = ibuf;
2375		}
2376
2377		if (com->state & CS_CHECKMSR) {
2378			u_char	delta_modem_status;
2379
2380#ifdef PC98
2381			if(!IS_8251(com->pc98_if_type)){
2382#endif
2383			disable_intr();
2384			delta_modem_status = com->last_modem_status
2385					     ^ com->prev_modem_status;
2386			com->prev_modem_status = com->last_modem_status;
2387			com_events -= LOTS_OF_EVENTS;
2388			com->state &= ~CS_CHECKMSR;
2389			enable_intr();
2390			if (delta_modem_status & MSR_DCD)
2391				(*linesw[tp->t_line].l_modem)
2392					(tp, com->prev_modem_status & MSR_DCD);
2393#ifdef PC98
2394			}
2395#endif
2396		}
2397		if (com->state & CS_ODONE) {
2398			disable_intr();
2399			com_events -= LOTS_OF_EVENTS;
2400			com->state &= ~CS_ODONE;
2401			enable_intr();
2402			if (!(com->state & CS_BUSY)
2403			    && !(com->extra_state & CSE_BUSYCHECK)) {
2404				timeout(siobusycheck, com, hz / 100);
2405				com->extra_state |= CSE_BUSYCHECK;
2406			}
2407			(*linesw[tp->t_line].l_start)(tp);
2408		}
2409		if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
2410		    !(tp->t_cflag & CREAD))
2411			continue;
2412		/*
2413		 * Avoid the grotesquely inefficient lineswitch routine
2414		 * (ttyinput) in "raw" mode.  It usually takes about 450
2415		 * instructions (that's without canonical processing or echo!).
2416		 * slinput is reasonably fast (usually 40 instructions plus
2417		 * call overhead).
2418		 */
2419		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
2420			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
2421			    && (com->state & CS_RTS_IFLOW
2422				|| tp->t_iflag & IXOFF)
2423			    && !(tp->t_state & TS_TBLOCK))
2424				ttyblock(tp);
2425			tk_nin += incc;
2426			tk_rawcc += incc;
2427			tp->t_rawcc += incc;
2428			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
2429				+= b_to_q((char *)buf, incc, &tp->t_rawq);
2430			ttwakeup(tp);
2431			if (tp->t_state & TS_TTSTOP
2432			    && (tp->t_iflag & IXANY
2433				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
2434				tp->t_state &= ~TS_TTSTOP;
2435				tp->t_lflag &= ~FLUSHO;
2436				comstart(tp);
2437			}
2438		} else {
2439			do {
2440				u_char	line_status;
2441				int	recv_data;
2442
2443				line_status = (u_char) buf[CE_INPUT_OFFSET];
2444				recv_data = (u_char) *buf++;
2445				if (line_status
2446				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
2447					if (line_status & LSR_BI)
2448						recv_data |= TTY_BI;
2449					if (line_status & LSR_FE)
2450						recv_data |= TTY_FE;
2451					if (line_status & LSR_OE)
2452						recv_data |= TTY_OE;
2453					if (line_status & LSR_PE)
2454						recv_data |= TTY_PE;
2455				}
2456				(*linesw[tp->t_line].l_rint)(recv_data, tp);
2457			} while (--incc > 0);
2458		}
2459		if (com_events == 0)
2460			break;
2461	}
2462	if (com_events >= LOTS_OF_EVENTS)
2463		goto repeat;
2464}
2465
2466static int
2467comparam(tp, t)
2468	struct tty	*tp;
2469	struct termios	*t;
2470{
2471	u_int		cfcr;
2472	int		cflag;
2473	struct com_s	*com;
2474	int		divisor;
2475	u_char		dlbh;
2476	u_char		dlbl;
2477	int		error;
2478	Port_t		iobase;
2479	int		s;
2480	int		unit;
2481	int		txtimeout;
2482#ifdef PC98
2483	Port_t		tmp_port;
2484	int		tmp_flg;
2485#endif
2486
2487#ifdef PC98
2488	cfcr = 0;
2489	unit = DEV_TO_UNIT(tp->t_dev);
2490	com = com_addr(unit);
2491	iobase = com->iobase;
2492	if(IS_8251(com->pc98_if_type)) {
2493		divisor = pc98_ttspeedtab(com, t->c_ospeed);
2494	} else
2495#endif
2496	/* do historical conversions */
2497	if (t->c_ispeed == 0)
2498		t->c_ispeed = t->c_ospeed;
2499
2500	/* check requested parameters */
2501	divisor = ttspeedtab(t->c_ospeed, comspeedtab);
2502	if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
2503		return (EINVAL);
2504
2505	/* parameters are OK, convert them to the com struct and the device */
2506#ifndef PC98
2507	unit = DEV_TO_UNIT(tp->t_dev);
2508	com = com_addr(unit);
2509	iobase = com->iobase;
2510#endif
2511	s = spltty();
2512#ifdef PC98
2513	if(IS_8251(com->pc98_if_type)){
2514		if(divisor == 0){
2515			com_int_TxRx_disable( com );
2516			com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
2517		}
2518	} else {
2519#endif
2520	if (divisor == 0)
2521		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
2522	else
2523		(void)commctl(com, TIOCM_DTR, DMBIS);
2524#ifdef PC98
2525	}
2526#endif
2527	cflag = t->c_cflag;
2528#ifdef PC98
2529	if(!IS_8251(com->pc98_if_type)){
2530#endif
2531	switch (cflag & CSIZE) {
2532	case CS5:
2533		cfcr = CFCR_5BITS;
2534		break;
2535	case CS6:
2536		cfcr = CFCR_6BITS;
2537		break;
2538	case CS7:
2539		cfcr = CFCR_7BITS;
2540		break;
2541	default:
2542		cfcr = CFCR_8BITS;
2543		break;
2544	}
2545	if (cflag & PARENB) {
2546		cfcr |= CFCR_PENAB;
2547		if (!(cflag & PARODD))
2548			cfcr |= CFCR_PEVEN;
2549	}
2550	if (cflag & CSTOPB)
2551		cfcr |= CFCR_STOPB;
2552
2553	if (com->hasfifo && divisor != 0) {
2554		/*
2555		 * Use a fifo trigger level low enough so that the input
2556		 * latency from the fifo is less than about 16 msec and
2557		 * the total latency is less than about 30 msec.  These
2558		 * latencies are reasonable for humans.  Serial comms
2559		 * protocols shouldn't expect anything better since modem
2560		 * latencies are larger.
2561		 */
2562		com->fifo_image = t->c_ospeed <= 4800
2563				  ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
2564#ifdef COM_ESP
2565		/*
2566		 * The Hayes ESP card needs the fifo DMA mode bit set
2567		 * in compatibility mode.  If not, it will interrupt
2568		 * for each character received.
2569		 */
2570		if (com->esp)
2571			com->fifo_image |= FIFO_DMA_MODE;
2572#endif
2573		outb(iobase + com_fifo, com->fifo_image);
2574	}
2575
2576	/*
2577	 * Some UARTs lock up if the divisor latch registers are selected
2578	 * while the UART is doing output (they refuse to transmit anything
2579	 * more until given a hard reset).  Fix this by stopping filling
2580	 * the device buffers and waiting for them to drain.  Reading the
2581	 * line status port outside of siointr1() might lose some receiver
2582	 * error bits, but that is acceptable here.
2583	 */
2584#ifdef PC98
2585	}
2586#endif
2587	disable_intr();
2588retry:
2589	com->state &= ~CS_TTGO;
2590	txtimeout = tp->t_timeout;
2591	enable_intr();
2592#ifdef PC98
2593	if(IS_8251(com->pc98_if_type)){
2594		tmp_port = com->sts_port;
2595		tmp_flg = (STS8251_TxRDY|STS8251_TxEMP);
2596	} else {
2597		tmp_port = com->line_status_port;
2598		tmp_flg = (LSR_TSRE|LSR_TXRDY);
2599	}
2600	while ((inb(tmp_port) & tmp_flg) != tmp_flg) {
2601#else
2602	while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2603	       != (LSR_TSRE | LSR_TXRDY)) {
2604#endif
2605		tp->t_state |= TS_SO_OCOMPLETE;
2606		error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
2607				 "siotx", hz / 100);
2608		if (   txtimeout != 0
2609		    && (!error || error	== EAGAIN)
2610		    && (txtimeout -= hz	/ 100) <= 0
2611		   )
2612			error = EIO;
2613		if (com->gone)
2614			error = ENODEV;
2615		if (error != 0 && error != EAGAIN) {
2616			if (!(tp->t_state & TS_TTSTOP)) {
2617				disable_intr();
2618				com->state |= CS_TTGO;
2619				enable_intr();
2620			}
2621			splx(s);
2622			return (error);
2623		}
2624	}
2625
2626	disable_intr();		/* very important while com_data is hidden */
2627
2628	/*
2629	 * XXX - clearing CS_TTGO is not sufficient to stop further output,
2630	 * because siopoll() calls comstart() which usually sets it again
2631	 * because TS_TTSTOP is clear.  Setting TS_TTSTOP would not be
2632	 * sufficient, for similar reasons.
2633	 */
2634#ifdef PC98
2635	if ((inb(tmp_port) & tmp_flg) != tmp_flg)
2636#else
2637	if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2638	    != (LSR_TSRE | LSR_TXRDY))
2639#endif
2640		goto retry;
2641
2642#ifdef PC98
2643	if(!IS_8251(com->pc98_if_type)){
2644#endif
2645	if (divisor != 0) {
2646		outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
2647		/*
2648		 * Only set the divisor registers if they would change,
2649		 * since on some 16550 incompatibles (UMC8669F), setting
2650		 * them while input is arriving them loses sync until
2651		 * data stops arriving.
2652		 */
2653		dlbl = divisor & 0xFF;
2654		if (inb(iobase + com_dlbl) != dlbl)
2655			outb(iobase + com_dlbl, dlbl);
2656		dlbh = (u_int) divisor >> 8;
2657		if (inb(iobase + com_dlbh) != dlbh)
2658			outb(iobase + com_dlbh, dlbh);
2659	}
2660	outb(iobase + com_cfcr, com->cfcr_image = cfcr);
2661#ifdef PC98
2662	} else
2663		com_cflag_and_speed_set(com, cflag, t->c_ospeed);
2664#endif
2665	if (!(tp->t_state & TS_TTSTOP))
2666		com->state |= CS_TTGO;
2667	if (cflag & CRTS_IFLOW) {
2668		com->state |= CS_RTS_IFLOW;
2669		/*
2670		 * If CS_RTS_IFLOW just changed from off to on, the change
2671		 * needs to be propagated to MCR_RTS.  This isn't urgent,
2672		 * so do it later by calling comstart() instead of repeating
2673		 * a lot of code from comstart() here.
2674		 */
2675	} else if (com->state & CS_RTS_IFLOW) {
2676		com->state &= ~CS_RTS_IFLOW;
2677		/*
2678		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
2679		 * on here, since comstart() won't do it later.
2680		 */
2681#ifdef PC98
2682		if(IS_8251(com->pc98_if_type))
2683			com_tiocm_bis(com, TIOCM_RTS);
2684		else
2685#endif
2686		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2687	}
2688
2689	/*
2690	 * Set up state to handle output flow control.
2691	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2692	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2693	 */
2694	com->state |= CS_ODEVREADY;
2695	com->state &= ~CS_CTS_OFLOW;
2696	if (cflag & CCTS_OFLOW) {
2697		com->state |= CS_CTS_OFLOW;
2698#ifdef PC98
2699		if(IS_8251(com->pc98_if_type)){
2700			if (!(pc98_get_modem_status(com) & TIOCM_CTS))
2701				com->state &= ~CS_ODEVREADY;
2702		} else {
2703#endif
2704		if (!(com->last_modem_status & MSR_CTS))
2705			com->state &= ~CS_ODEVREADY;
2706#ifdef PC98
2707		}
2708#endif
2709	}
2710	/* XXX shouldn't call functions while intrs are disabled. */
2711	disc_optim(tp, t, com);
2712	/*
2713	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
2714	 * unconditionally, but that defeated the careful discarding of
2715	 * stale input in sioopen().
2716	 */
2717	if (com->state >= (CS_BUSY | CS_TTGO))
2718		siointr1(com);
2719
2720	enable_intr();
2721	splx(s);
2722	comstart(tp);
2723	return (0);
2724}
2725
2726static void
2727comstart(tp)
2728	struct tty	*tp;
2729{
2730	struct com_s	*com;
2731	int		s;
2732	int		unit;
2733#ifdef PC98
2734	int		tmp;
2735#endif
2736
2737	unit = DEV_TO_UNIT(tp->t_dev);
2738	com = com_addr(unit);
2739	s = spltty();
2740	disable_intr();
2741	if (tp->t_state & TS_TTSTOP)
2742		com->state &= ~CS_TTGO;
2743	else
2744		com->state |= CS_TTGO;
2745	if (tp->t_state & TS_TBLOCK) {
2746#ifdef PC98
2747		if(IS_8251(com->pc98_if_type))
2748			tmp = com_tiocm_get(com) & TIOCM_RTS;
2749		else
2750			tmp = com->mcr_image & MCR_RTS;
2751		if (tmp && (com->state & CS_RTS_IFLOW))
2752#else
2753		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2754#endif
2755#ifdef PC98
2756			if(IS_8251(com->pc98_if_type))
2757				com_tiocm_bic(com, TIOCM_RTS);
2758			else
2759#endif
2760			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2761	} else {
2762#ifdef PC98
2763		if(IS_8251(com->pc98_if_type))
2764			tmp = com_tiocm_get(com) & TIOCM_RTS;
2765		else
2766			tmp = com->mcr_image & MCR_RTS;
2767		if (!(tmp) && com->iptr < com->ihighwater
2768			&& com->state & CS_RTS_IFLOW)
2769#else
2770		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2771		    && com->state & CS_RTS_IFLOW)
2772#endif
2773#ifdef PC98
2774			if(IS_8251(com->pc98_if_type))
2775				com_tiocm_bis(com, TIOCM_RTS);
2776			else
2777#endif
2778			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2779	}
2780	enable_intr();
2781	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2782#ifdef PC98
2783/*		if(IS_8251(com->pc98_if_type))
2784			com_int_Tx_enable(com); */
2785#endif
2786		splx(s);
2787		return;
2788	}
2789	if (tp->t_outq.c_cc != 0) {
2790		struct lbq	*qp;
2791		struct lbq	*next;
2792
2793		if (!com->obufs[0].l_queued) {
2794			com->obufs[0].l_tail
2795			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2796						  sizeof com->obuf1);
2797			com->obufs[0].l_next = NULL;
2798			com->obufs[0].l_queued = TRUE;
2799			disable_intr();
2800			if (com->state & CS_BUSY) {
2801				qp = com->obufq.l_next;
2802				while ((next = qp->l_next) != NULL)
2803					qp = next;
2804				qp->l_next = &com->obufs[0];
2805			} else {
2806				com->obufq.l_head = com->obufs[0].l_head;
2807				com->obufq.l_tail = com->obufs[0].l_tail;
2808				com->obufq.l_next = &com->obufs[0];
2809				com->state |= CS_BUSY;
2810			}
2811			enable_intr();
2812		}
2813		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2814			com->obufs[1].l_tail
2815			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2816						  sizeof com->obuf2);
2817			com->obufs[1].l_next = NULL;
2818			com->obufs[1].l_queued = TRUE;
2819			disable_intr();
2820			if (com->state & CS_BUSY) {
2821				qp = com->obufq.l_next;
2822				while ((next = qp->l_next) != NULL)
2823					qp = next;
2824				qp->l_next = &com->obufs[1];
2825			} else {
2826				com->obufq.l_head = com->obufs[1].l_head;
2827				com->obufq.l_tail = com->obufs[1].l_tail;
2828				com->obufq.l_next = &com->obufs[1];
2829				com->state |= CS_BUSY;
2830			}
2831			enable_intr();
2832		}
2833		tp->t_state |= TS_BUSY;
2834	}
2835	disable_intr();
2836	if (com->state >= (CS_BUSY | CS_TTGO))
2837		siointr1(com);	/* fake interrupt to start output */
2838	enable_intr();
2839#ifdef PC98
2840/*		if(IS_8251(com->pc98_if_type))
2841			com_int_Tx_enable(com); */
2842#endif
2843	ttwwakeup(tp);
2844	splx(s);
2845}
2846
2847static void
2848siostop(tp, rw)
2849	struct tty	*tp;
2850	int		rw;
2851{
2852	struct com_s	*com;
2853
2854	com = com_addr(DEV_TO_UNIT(tp->t_dev));
2855	if (com->gone)
2856		return;
2857	disable_intr();
2858	if (rw & FWRITE) {
2859		if (com->hasfifo)
2860#ifdef COM_ESP
2861		    /* XXX avoid h/w bug. */
2862		    if (!com->esp)
2863#endif
2864			/* XXX does this flush everything? */
2865			outb(com->iobase + com_fifo,
2866			     FIFO_XMT_RST | com->fifo_image);
2867		com->obufs[0].l_queued = FALSE;
2868		com->obufs[1].l_queued = FALSE;
2869		if (com->state & CS_ODONE)
2870			com_events -= LOTS_OF_EVENTS;
2871		com->state &= ~(CS_ODONE | CS_BUSY);
2872		com->tp->t_state &= ~TS_BUSY;
2873	}
2874	if (rw & FREAD) {
2875		if (com->hasfifo)
2876#ifdef COM_ESP
2877		    /* XXX avoid h/w bug. */
2878		    if (!com->esp)
2879#endif
2880			/* XXX does this flush everything? */
2881			outb(com->iobase + com_fifo,
2882			     FIFO_RCV_RST | com->fifo_image);
2883		com_events -= (com->iptr - com->ibuf);
2884		com->iptr = com->ibuf;
2885	}
2886	enable_intr();
2887	comstart(tp);
2888}
2889
2890static struct tty *
2891siodevtotty(dev)
2892	dev_t	dev;
2893{
2894	int	mynor;
2895	int	unit;
2896
2897	mynor = minor(dev);
2898	if (mynor & CONTROL_MASK)
2899		return (NULL);
2900	unit = MINOR_TO_UNIT(mynor);
2901	if ((u_int) unit >= NSIO)
2902		return (NULL);
2903	return (&sio_tty[unit]);
2904}
2905
2906static int
2907commctl(com, bits, how)
2908	struct com_s	*com;
2909	int		bits;
2910	int		how;
2911{
2912	int	mcr;
2913	int	msr;
2914
2915	if (how == DMGET) {
2916		bits = TIOCM_LE;	/* XXX - always enabled while open */
2917		mcr = com->mcr_image;
2918		if (mcr & MCR_DTR)
2919			bits |= TIOCM_DTR;
2920		if (mcr & MCR_RTS)
2921			bits |= TIOCM_RTS;
2922		msr = com->prev_modem_status;
2923		if (msr & MSR_CTS)
2924			bits |= TIOCM_CTS;
2925		if (msr & MSR_DCD)
2926			bits |= TIOCM_CD;
2927		if (msr & MSR_DSR)
2928			bits |= TIOCM_DSR;
2929		/*
2930		 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
2931		 * more volatile by reading the modem status a lot.  Perhaps
2932		 * we should latch both bits until the status is read here.
2933		 */
2934		if (msr & (MSR_RI | MSR_TERI))
2935			bits |= TIOCM_RI;
2936		return (bits);
2937	}
2938	mcr = 0;
2939	if (bits & TIOCM_DTR)
2940		mcr |= MCR_DTR;
2941	if (bits & TIOCM_RTS)
2942		mcr |= MCR_RTS;
2943	if (com->gone)
2944		return(0);
2945	disable_intr();
2946	switch (how) {
2947	case DMSET:
2948		outb(com->modem_ctl_port,
2949		     com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
2950		break;
2951	case DMBIS:
2952		outb(com->modem_ctl_port, com->mcr_image |= mcr);
2953		break;
2954	case DMBIC:
2955		outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
2956		break;
2957	}
2958	enable_intr();
2959	return (0);
2960}
2961
2962static void
2963siosettimeout()
2964{
2965	struct com_s	*com;
2966	bool_t		someopen;
2967	int		unit;
2968
2969	/*
2970	 * Set our timeout period to 1 second if no polled devices are open.
2971	 * Otherwise set it to max(1/200, 1/hz).
2972	 * Enable timeouts iff some device is open.
2973	 */
2974	untimeout(comwakeup, (void *)NULL);
2975	sio_timeout = hz;
2976	someopen = FALSE;
2977	for (unit = 0; unit < NSIO; ++unit) {
2978		com = com_addr(unit);
2979		if (com != NULL && com->tp != NULL
2980		    && com->tp->t_state & TS_ISOPEN && !com->gone) {
2981			someopen = TRUE;
2982			if (com->poll || com->poll_output) {
2983				sio_timeout = hz > 200 ? hz / 200 : 1;
2984				break;
2985			}
2986		}
2987	}
2988	if (someopen) {
2989		sio_timeouts_until_log = hz / sio_timeout;
2990		timeout(comwakeup, (void *)NULL, sio_timeout);
2991	} else {
2992		/* Flush error messages, if any. */
2993		sio_timeouts_until_log = 1;
2994		comwakeup((void *)NULL);
2995		untimeout(comwakeup, (void *)NULL);
2996	}
2997}
2998
2999static void
3000comwakeup(chan)
3001	void	*chan;
3002{
3003	struct com_s	*com;
3004	int		unit;
3005
3006	timeout(comwakeup, (void *)NULL, sio_timeout);
3007
3008	/*
3009	 * Recover from lost output interrupts.
3010	 * Poll any lines that don't use interrupts.
3011	 */
3012	for (unit = 0; unit < NSIO; ++unit) {
3013		com = com_addr(unit);
3014		if (com != NULL && !com->gone
3015		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
3016			disable_intr();
3017			siointr1(com);
3018			enable_intr();
3019		}
3020	}
3021
3022	/*
3023	 * Check for and log errors, but not too often.
3024	 */
3025	if (--sio_timeouts_until_log > 0)
3026		return;
3027	sio_timeouts_until_log = hz / sio_timeout;
3028	for (unit = 0; unit < NSIO; ++unit) {
3029		int	errnum;
3030
3031		com = com_addr(unit);
3032		if (com == NULL)
3033			continue;
3034		if (com->gone)
3035			continue;
3036		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
3037			u_int	delta;
3038			u_long	total;
3039
3040			disable_intr();
3041			delta = com->delta_error_counts[errnum];
3042			com->delta_error_counts[errnum] = 0;
3043			enable_intr();
3044			if (delta == 0)
3045				continue;
3046			total = com->error_counts[errnum] += delta;
3047			log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
3048			    unit, delta, error_desc[errnum],
3049			    delta == 1 ? "" : "s", total);
3050		}
3051	}
3052}
3053
3054#ifdef PC98
3055/* commint is called when modem control line changes */
3056static void
3057commint(dev_t dev)
3058{
3059	register struct tty *tp;
3060	int	stat,delta;
3061	struct com_s *com;
3062	int	mynor,unit;
3063
3064	mynor = minor(dev);
3065	unit = MINOR_TO_UNIT(mynor);
3066	com = com_addr(unit);
3067	tp = com->tp;
3068
3069	stat = com_tiocm_get(com);
3070	delta = com_tiocm_get_delta(com);
3071
3072	if (com->state & CS_CTS_OFLOW) {
3073		if (stat & TIOCM_CTS)
3074			com->state |= CS_ODEVREADY;
3075		else
3076			com->state &= ~CS_ODEVREADY;
3077	}
3078	if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) {
3079	    if (stat & TIOCM_CAR )
3080		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
3081	    else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
3082		/* negate DTR, RTS */
3083		com_tiocm_bic(com, (tp->t_cflag & HUPCL) ?
3084				TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE );
3085		/* disable IENABLE */
3086		com_int_TxRx_disable( com );
3087	    }
3088	}
3089}
3090#endif
3091
3092static void
3093disc_optim(tp, t, com)
3094	struct tty	*tp;
3095	struct termios	*t;
3096	struct com_s	*com;
3097{
3098	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
3099	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
3100	    && (!(t->c_iflag & PARMRK)
3101		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
3102	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
3103	    && linesw[tp->t_line].l_rint == ttyinput)
3104		tp->t_state |= TS_CAN_BYPASS_L_RINT;
3105	else
3106		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
3107	/*
3108	 * Prepare to reduce input latency for packet
3109	 * discplines with a end of packet character.
3110	 */
3111	if (tp->t_line == SLIPDISC)
3112		com->hotchar = 0xc0;
3113	else if (tp->t_line == PPPDISC)
3114		com->hotchar = 0x7e;
3115	else
3116		com->hotchar = 0;
3117}
3118
3119/*
3120 * Following are all routines needed for SIO to act as console
3121 */
3122#include <machine/cons.h>
3123
3124struct siocnstate {
3125	u_char	dlbl;
3126	u_char	dlbh;
3127	u_char	ier;
3128	u_char	cfcr;
3129	u_char	mcr;
3130};
3131
3132static void siocnclose	__P((struct siocnstate *sp));
3133static void siocnopen	__P((struct siocnstate *sp));
3134static void siocntxwait	__P((void));
3135
3136static void
3137siocntxwait()
3138{
3139	int	timo;
3140
3141	/*
3142	 * Wait for any pending transmission to finish.  Required to avoid
3143	 * the UART lockup bug when the speed is changed, and for normal
3144	 * transmits.
3145	 */
3146	timo = 100000;
3147	while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
3148	       != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
3149		;
3150}
3151
3152static void
3153siocnopen(sp)
3154	struct siocnstate	*sp;
3155{
3156	int	divisor;
3157	u_char	dlbh;
3158	u_char	dlbl;
3159	Port_t	iobase;
3160
3161	/*
3162	 * Save all the device control registers except the fifo register
3163	 * and set our default ones (cs8 -parenb speed=comdefaultrate).
3164	 * We can't save the fifo register since it is read-only.
3165	 */
3166	iobase = siocniobase;
3167	sp->ier = inb(iobase + com_ier);
3168	outb(iobase + com_ier, 0);	/* spltty() doesn't stop siointr() */
3169	siocntxwait();
3170	sp->cfcr = inb(iobase + com_cfcr);
3171	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3172	sp->dlbl = inb(iobase + com_dlbl);
3173	sp->dlbh = inb(iobase + com_dlbh);
3174	/*
3175	 * Only set the divisor registers if they would change, since on
3176	 * some 16550 incompatibles (Startech), setting them clears the
3177	 * data input register.  This also reduces the effects of the
3178	 * UMC8669F bug.
3179	 */
3180	divisor = ttspeedtab(comdefaultrate, comspeedtab);
3181	dlbl = divisor & 0xFF;
3182	if (sp->dlbl != dlbl)
3183		outb(iobase + com_dlbl, dlbl);
3184	dlbh = (u_int) divisor >> 8;
3185	if (sp->dlbh != dlbh)
3186		outb(iobase + com_dlbh, dlbh);
3187	outb(iobase + com_cfcr, CFCR_8BITS);
3188	sp->mcr = inb(iobase + com_mcr);
3189	/*
3190	 * We don't want interrupts, but must be careful not to "disable"
3191	 * them by clearing the MCR_IENABLE bit, since that might cause
3192	 * an interrupt by floating the IRQ line.
3193	 */
3194	outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
3195}
3196
3197static void
3198siocnclose(sp)
3199	struct siocnstate	*sp;
3200{
3201	Port_t	iobase;
3202
3203	/*
3204	 * Restore the device control registers.
3205	 */
3206	siocntxwait();
3207	iobase = siocniobase;
3208	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3209	if (sp->dlbl != inb(iobase + com_dlbl))
3210		outb(iobase + com_dlbl, sp->dlbl);
3211	if (sp->dlbh != inb(iobase + com_dlbh))
3212		outb(iobase + com_dlbh, sp->dlbh);
3213	outb(iobase + com_cfcr, sp->cfcr);
3214	/*
3215	 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
3216	 */
3217	outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
3218	outb(iobase + com_ier, sp->ier);
3219}
3220
3221void
3222siocnprobe(cp)
3223	struct consdev	*cp;
3224{
3225	struct isa_device	*dvp;
3226	int	s;
3227	struct siocnstate	sp;
3228
3229	/*
3230	 * Find our first enabled console, if any.  If it is a high-level
3231	 * console device, then initialize it and return successfully.
3232	 * If it is a low-level console device, then initialize it and
3233	 * return unsuccessfully.  It must be initialized in both cases
3234	 * for early use by console drivers and debuggers.  Initializing
3235	 * the hardware is not necessary in all cases, since the i/o
3236	 * routines initialize it on the fly, but it is necessary if
3237	 * input might arrive while the hardware is switched back to an
3238	 * uninitialized state.  We can't handle multiple console devices
3239	 * yet because our low-level routines don't take a device arg.
3240	 * We trust the user to set the console flags properly so that we
3241	 * don't need to probe.
3242	 */
3243	cp->cn_pri = CN_DEAD;
3244	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
3245		if (dvp->id_driver == &siodriver && dvp->id_enabled
3246		    && COM_CONSOLE(dvp)) {
3247			siocniobase = dvp->id_iobase;
3248			s = spltty();
3249			siocnopen(&sp);
3250			splx(s);
3251			if (!COM_LLCONSOLE(dvp)) {
3252				cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit);
3253				cp->cn_pri = COM_FORCECONSOLE(dvp)
3254					     || boothowto & RB_SERIAL
3255					     ? CN_REMOTE : CN_NORMAL;
3256			}
3257			break;
3258		}
3259}
3260
3261void
3262siocninit(cp)
3263	struct consdev	*cp;
3264{
3265	comconsole = DEV_TO_UNIT(cp->cn_dev);
3266}
3267
3268int
3269siocncheckc(dev)
3270	dev_t	dev;
3271{
3272	int	c;
3273	Port_t	iobase;
3274	int	s;
3275	struct siocnstate	sp;
3276
3277	iobase = siocniobase;
3278	s = spltty();
3279	siocnopen(&sp);
3280	if (inb(iobase + com_lsr) & LSR_RXRDY)
3281		c = inb(iobase + com_data);
3282	else
3283		c = -1;
3284	siocnclose(&sp);
3285	splx(s);
3286	return (c);
3287}
3288
3289
3290int
3291siocngetc(dev)
3292	dev_t	dev;
3293{
3294	int	c;
3295	Port_t	iobase;
3296	int	s;
3297	struct siocnstate	sp;
3298
3299	iobase = siocniobase;
3300	s = spltty();
3301	siocnopen(&sp);
3302	while (!(inb(iobase + com_lsr) & LSR_RXRDY))
3303		;
3304	c = inb(iobase + com_data);
3305	siocnclose(&sp);
3306	splx(s);
3307	return (c);
3308}
3309
3310void
3311siocnputc(dev, c)
3312	dev_t	dev;
3313	int	c;
3314{
3315	int	s;
3316	struct siocnstate	sp;
3317
3318	s = spltty();
3319	siocnopen(&sp);
3320	siocntxwait();
3321	outb(siocniobase + com_data, c);
3322	siocnclose(&sp);
3323	splx(s);
3324}
3325
3326#ifdef DSI_SOFT_MODEM
3327/*
3328 * The magic code to download microcode to a "Connection 14.4+Fax"
3329 * modem from Digicom Systems Inc.  Very magic.
3330 */
3331
3332#define DSI_ERROR(str) { ptr = str; goto error; }
3333static int
3334LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr)
3335{
3336    int int_c,int_k;
3337    int data_0188, data_0187;
3338
3339    /*
3340     * First see if it is a DSI SoftModem
3341     */
3342    if(!((inb(base_io+7) ^ inb(base_io+7) & 0x80)))
3343	return ENODEV;
3344
3345    data_0188 = inb(base_io+4);
3346    data_0187 = inb(base_io+3);
3347    outb(base_io+3,0x80);
3348    outb(base_io+4,0x0C);
3349    outb(base_io+0,0x31);
3350    outb(base_io+1,0x8C);
3351    outb(base_io+7,0x10);
3352    outb(base_io+7,0x19);
3353
3354    if(0x18 != (inb(base_io+7) & 0x1A))
3355	DSI_ERROR("dsp bus not granted");
3356
3357    if(0x01 != (inb(base_io+7) & 0x01)) {
3358	outb(base_io+7,0x18);
3359	outb(base_io+7,0x19);
3360	if(0x01 != (inb(base_io+7) & 0x01))
3361	    DSI_ERROR("program mem not granted");
3362    }
3363
3364    int_c = 0;
3365
3366    while(1) {
3367	if(int_c >= 7 || size <= 0x1800)
3368	    break;
3369
3370	for(int_k = 0 ; int_k < 0x800; int_k++) {
3371	    outb(base_io+0,*ptr++);
3372	    outb(base_io+1,*ptr++);
3373	    outb(base_io+2,*ptr++);
3374	}
3375
3376	size -= 0x1800;
3377	int_c++;
3378    }
3379
3380    if(size > 0x1800) {
3381 	outb(base_io+7,0x18);
3382 	outb(base_io+7,0x19);
3383	if(0x00 != (inb(base_io+7) & 0x01))
3384	    DSI_ERROR("program data not granted");
3385
3386	for(int_k = 0 ; int_k < 0x800; int_k++) {
3387	    outb(base_io+1,*ptr++);
3388	    outb(base_io+2,0);
3389	    outb(base_io+1,*ptr++);
3390	    outb(base_io+2,*ptr++);
3391	}
3392
3393	size -= 0x1800;
3394
3395	while(size > 0x1800) {
3396	    for(int_k = 0 ; int_k < 0xC00; int_k++) {
3397		outb(base_io+1,*ptr++);
3398		outb(base_io+2,*ptr++);
3399	    }
3400	    size -= 0x1800;
3401	}
3402
3403	if(size < 0x1800) {
3404	    for(int_k=0;int_k<size/2;int_k++) {
3405		outb(base_io+1,*ptr++);
3406		outb(base_io+2,*ptr++);
3407	    }
3408	}
3409
3410    } else if (size > 0) {
3411	if(int_c == 7) {
3412	    outb(base_io+7,0x18);
3413	    outb(base_io+7,0x19);
3414	    if(0x00 != (inb(base_io+7) & 0x01))
3415		DSI_ERROR("program data not granted");
3416	    for(int_k = 0 ; int_k < size/3; int_k++) {
3417		outb(base_io+1,*ptr++);
3418		outb(base_io+2,0);
3419		outb(base_io+1,*ptr++);
3420		outb(base_io+2,*ptr++);
3421	    }
3422	} else {
3423	    for(int_k = 0 ; int_k < size/3; int_k++) {
3424		outb(base_io+0,*ptr++);
3425		outb(base_io+1,*ptr++);
3426		outb(base_io+2,*ptr++);
3427	    }
3428	}
3429    }
3430    outb(base_io+7,0x11);
3431    outb(base_io+7,3);
3432
3433    outb(base_io+4,data_0188 & 0xfb);
3434
3435    outb(base_io+3,data_0187);
3436
3437    return 0;
3438error:
3439    printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr);
3440    outb(base_io+7,0x00); \
3441    outb(base_io+3,data_0187); \
3442    outb(base_io+4,data_0188);  \
3443    return EIO;
3444}
3445#endif /* DSI_SOFT_MODEM */
3446#ifdef PC98
3447/*
3448 *  pc98 local function
3449 */
3450
3451static void
3452com_tiocm_set(struct com_s *com, int msr)
3453{
3454	int	s;
3455	int	tmp = 0;
3456	int	mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS;
3457
3458	s=spltty();
3459	com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) )
3460	   | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3461	tmp |= (CMD8251_TxEN|CMD8251_RxEN);
3462	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3463	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3464	pc98_i8251_clear_or_cmd( com, mask, tmp );
3465	splx(s);
3466}
3467
3468static void
3469com_tiocm_bis(struct com_s *com, int msr)
3470{
3471	int	s;
3472	int	tmp = 0;
3473
3474	s=spltty();
3475	com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3476	tmp |= CMD8251_TxEN|CMD8251_RxEN;
3477	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3478	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3479
3480	pc98_i8251_or_cmd( com, tmp );
3481	splx(s);
3482}
3483
3484static void
3485com_tiocm_bic(struct com_s *com, int msr)
3486{
3487	int	s;
3488	int	tmp = msr;
3489
3490	s=spltty();
3491	com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3492	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3493	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3494
3495	pc98_i8251_clear_cmd( com, tmp );
3496	splx(s);
3497}
3498
3499static int
3500com_tiocm_get(struct com_s *com)
3501{
3502	return( com->pc98_prev_modem_status );
3503}
3504
3505static int
3506com_tiocm_get_delta(struct com_s *com)
3507{
3508	int	tmp;
3509
3510	tmp = com->pc98_modem_delta;
3511	com->pc98_modem_delta = 0;
3512	return( tmp );
3513}
3514
3515/* convert to TIOCM_?? ( ioctl.h ) */
3516static int
3517pc98_get_modem_status(struct com_s *com)
3518{
3519	int	stat, stat2;
3520	register int	msr;
3521
3522	stat  = inb(com->sts_port);
3523	stat2 = inb(com->in_modem_port);
3524	msr = com->pc98_prev_modem_status
3525			& ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3526	if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR;
3527	if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI;
3528	if (   stat & STS8251_DSR ) msr |= TIOCM_DSR;
3529	if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS;
3530#if COM_CARRIER_DETECT_EMULATE
3531	if ( msr & (TIOCM_DSR|TIOCM_CTS) ) {
3532		msr |= TIOCM_CAR;
3533	}
3534#endif
3535	return(msr);
3536}
3537
3538static void
3539pc98_check_msr(void* chan)
3540{
3541	int	msr, delta;
3542	int	s;
3543	register struct tty *tp;
3544	struct	com_s *com;
3545	int	mynor;
3546	int	unit;
3547	dev_t	dev;
3548
3549	dev=(dev_t)chan;
3550	mynor = minor(dev);
3551	unit = MINOR_TO_UNIT(mynor);
3552	com = com_addr(unit);
3553	tp = com->tp;
3554
3555	s = spltty();
3556	msr = pc98_get_modem_status(com);
3557	/* make change flag */
3558	delta = msr ^ com->pc98_prev_modem_status;
3559	if ( delta & TIOCM_CAR ) {
3560	    if ( com->modem_car_chg_timer ) {
3561		if ( -- com->modem_car_chg_timer )
3562		    msr ^= TIOCM_CAR;
3563	    } else {
3564		if ( com->modem_car_chg_timer = ( msr & TIOCM_CAR ) ?
3565			     DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE )
3566		    msr ^= TIOCM_CAR;
3567	    }
3568	} else
3569	    com->modem_car_chg_timer = 0;
3570	delta = ( msr ^ com->pc98_prev_modem_status ) &
3571			(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3572	com->pc98_prev_modem_status = msr;
3573	delta = ( com->pc98_modem_delta |= delta );
3574	splx(s);
3575	if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) {
3576		if ( delta ) {
3577			commint(dev);
3578		}
3579		timeout(pc98_check_msr, (caddr_t)dev,
3580					PC98_CHECK_MODEM_INTERVAL);
3581	} else {
3582		com->modem_checking = 0;
3583	}
3584}
3585
3586static void
3587pc98_msrint_start(dev_t dev)
3588{
3589	struct	com_s *com;
3590	int	mynor;
3591	int	unit;
3592	int	s = spltty();
3593
3594	mynor = minor(dev);
3595	unit = MINOR_TO_UNIT(mynor);
3596	com = com_addr(unit);
3597	/* modem control line check routine envoke interval is 1/10 sec */
3598	if ( com->modem_checking == 0 ) {
3599		com->pc98_prev_modem_status = pc98_get_modem_status(com);
3600		com->pc98_modem_delta = 0;
3601		timeout(pc98_check_msr, (caddr_t)dev,
3602					PC98_CHECK_MODEM_INTERVAL);
3603		com->modem_checking = 1;
3604	}
3605	splx(s);
3606}
3607
3608static void
3609pc98_disable_i8251_interrupt(struct com_s *com, int mod)
3610{
3611	/* disable interrupt */
3612	register int	tmp;
3613
3614	mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3615	COM_INT_DISABLE
3616	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3617	outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp );
3618	COM_INT_ENABLE
3619}
3620
3621static void
3622pc98_enable_i8251_interrupt(struct com_s *com, int mod)
3623{
3624	register int	tmp;
3625
3626	COM_INT_DISABLE
3627	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3628	outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp );
3629	COM_INT_ENABLE
3630}
3631
3632static int
3633pc98_check_i8251_interrupt(struct com_s *com)
3634{
3635	return ( com->intr_enable & 0x07 );
3636}
3637
3638static void
3639pc98_i8251_clear_cmd(struct com_s *com, int x)
3640{
3641	int	tmp;
3642
3643	COM_INT_DISABLE
3644	tmp = com->pc98_prev_siocmd & ~(x);
3645	outb(com->cmd_port, tmp);
3646	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3647	COM_INT_ENABLE
3648}
3649
3650static void
3651pc98_i8251_or_cmd(struct com_s *com, int x)
3652{
3653	int	tmp;
3654
3655	COM_INT_DISABLE
3656	tmp = com->pc98_prev_siocmd | (x);
3657	outb(com->cmd_port, tmp);
3658	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3659	COM_INT_ENABLE
3660}
3661
3662static void
3663pc98_i8251_set_cmd(struct com_s *com, int x)
3664{
3665	int	tmp;
3666
3667	COM_INT_DISABLE
3668	tmp = (x);
3669	outb(com->cmd_port, tmp);
3670	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3671	COM_INT_ENABLE
3672}
3673
3674static void
3675pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x)
3676{
3677	int	tmp;
3678	COM_INT_DISABLE
3679	tmp = com->pc98_prev_siocmd & ~(clr);
3680	tmp |= (x);
3681	outb(com->cmd_port, tmp);
3682	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3683	COM_INT_ENABLE
3684}
3685
3686static int
3687pc98_i8251_get_cmd(struct com_s *com)
3688{
3689	return com->pc98_prev_siocmd;
3690}
3691
3692static int
3693pc98_i8251_get_mod(struct com_s *com)
3694{
3695	return com->pc98_prev_siomod;
3696}
3697
3698static void
3699pc98_i8251_reset(struct com_s *com, int mode, int command)
3700{
3701	outb(com->cmd_port, 0);	/* dummy */
3702	DELAY(2);
3703	outb(com->cmd_port, 0);	/* dummy */
3704	DELAY(2);
3705	outb(com->cmd_port, 0);	/* dummy */
3706	DELAY(2);
3707	outb(com->cmd_port, CMD8251_RESET);	/* internal reset */
3708	DELAY(2);
3709	outb(com->cmd_port, mode );	/* mode register */
3710	com->pc98_prev_siomod = mode;
3711	DELAY(2);
3712	pc98_i8251_set_cmd( com, (command|CMD8251_ER) );
3713}
3714
3715static void
3716pc98_check_sysclock(void)
3717{
3718	/* get system clock from port */
3719	if ( pc98_machine_type & M_8M ) {
3720	/* 8 MHz system & H98 */
3721		sysclock = 8;
3722	} else {
3723	/* 5 MHz system */
3724		sysclock = 5;
3725	}
3726}
3727
3728static void
3729com_cflag_and_speed_set( struct com_s *com, int cflag, int speed)
3730{
3731	int	cfcr=0, count;
3732	int	previnterrupt;
3733
3734	count = pc98_ttspeedtab( com, speed );
3735	if ( count < 0 ) return;
3736
3737	previnterrupt = pc98_check_i8251_interrupt(com);
3738	pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx );
3739
3740	switch ( cflag&CSIZE ) {
3741	  case CS5:
3742		cfcr = MOD8251_5BITS; break;
3743	  case CS6:
3744		cfcr = MOD8251_6BITS; break;
3745	  case CS7:
3746		cfcr = MOD8251_7BITS; break;
3747	  case CS8:
3748		cfcr = MOD8251_8BITS; break;
3749	}
3750	if ( cflag&PARENB ) {
3751	    if ( cflag&PARODD )
3752		cfcr |= MOD8251_PODD;
3753	    else
3754		cfcr |= MOD8251_PEVEN;
3755	} else
3756		cfcr |= MOD8251_PDISAB;
3757
3758	if ( cflag&CSTOPB )
3759		cfcr |= MOD8251_STOP2;
3760	else
3761		cfcr |= MOD8251_STOP1;
3762
3763	if ( count & 0x10000 )
3764		cfcr |= MOD8251_CLKX1;
3765	else
3766		cfcr |= MOD8251_CLKX16;
3767
3768	if (epson_machine_id != 0x20) {	/* XXX */
3769	{
3770		int	tmp;
3771		while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP))
3772			;
3773	}
3774	}
3775	/* set baud rate from ospeed */
3776	pc98_set_baud_rate( com, count );
3777
3778	if ( cfcr != pc98_i8251_get_mod(com) )
3779		pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) );
3780
3781	pc98_enable_i8251_interrupt( com, previnterrupt );
3782}
3783
3784static int
3785pc98_ttspeedtab(struct com_s *com, int speed)
3786{
3787	int	effect_sp, count=-1, mod;
3788
3789	switch ( com->pc98_if_type ) {
3790	    case COM_IF_INTERNAL:
3791		/* for *1CLK asynchronous! mode		, TEFUTEFU */
3792		effect_sp = ttspeedtab( speed, pc98speedtab );
3793		if ( effect_sp < 0 )
3794			effect_sp = ttspeedtab( (speed-1), pc98speedtab );
3795		if ( effect_sp <= 0 )
3796			return effect_sp;
3797		mod = (sysclock == 5 ? 2457600 : 1996800);
3798		if ( effect_sp == speed )
3799			mod /= 16;
3800		count = mod / effect_sp;
3801		if ( count > 65535 )
3802			return(-1);
3803		if ( effect_sp >= 2400 )
3804			if ( !(sysclock != 5 &&
3805				(effect_sp == 19200 || effect_sp == 38400)) )
3806				if ( ( mod % effect_sp ) != 0 )
3807					return(-1);
3808		if ( effect_sp != speed )
3809			count |= 0x10000;
3810		break;
3811#ifdef COM_IF_PC9861K
3812	    case COM_IF_PC9861K:
3813		effect_sp = speed;
3814		count = 1;
3815		break;
3816#endif
3817#ifdef COM_IF_PIO9032B
3818	    case COM_IF_PIO9032B:
3819		if ( speed == 0 ) return 0;
3820		count = ttspeedtab( speed, comspeedtab_pio9032b );
3821		if ( count < 0 ) return count;
3822		effect_sp = speed;
3823		break;
3824#endif
3825#ifdef COM_IF_B98_01
3826	    case COM_IF_B98_01:
3827		effect_sp=speed;
3828		count = ttspeedtab( speed, comspeedtab_b98_01 );
3829		if ( count <= 3 )
3830			return -1;         /* invalid speed/count */
3831		if ( count <= 5 )
3832			count |= 0x10000;  /* x1 mode for 76800 and 153600 */
3833		else
3834			count -= 4;        /* x16 mode for slower */
3835		break;
3836#endif
3837	}
3838	return count;
3839}
3840
3841static void
3842pc98_set_baud_rate( struct com_s *com, int count)
3843{
3844	int	s;
3845
3846	switch ( com->pc98_if_type ) {
3847	    case COM_IF_INTERNAL:
3848		if ( count < 0 ) {
3849			printf( "[ Illegal count : %d ]", count );
3850			return;
3851		} else if ( count == 0)
3852			return;
3853		/* set i8253 */
3854		s = splclock();
3855		outb( 0x77, 0xb6 );
3856		outb( 0x5f, 0);
3857		outb( 0x75, count & 0xff );
3858		outb( 0x5f, 0);
3859		outb( 0x75, (count >> 8) & 0xff );
3860		splx(s);
3861		break;
3862#if 0
3863#ifdef COM_IF_PC9861K
3864	    case COM_IF_PC9861K:
3865		break;
3866		/* ext. RS232C board: speed is determined by DIP switch */
3867#endif
3868#endif /* 0 */
3869#ifdef COM_IF_PIO9032B
3870	    case COM_IF_PIO9032B:
3871		outb( com_addr[unit], count & 0x07 );
3872		break;
3873#endif
3874#ifdef COM_IF_B98_01
3875	    case COM_IF_B98_01:
3876		outb( com->iobase,     count & 0x0f );
3877#ifdef B98_01_OLD
3878		/* some old board should be controlled in different way,
3879		   but this hasn't been tested yet.*/
3880		outb( com->iobase+2, ( count & 0x10000 ) ? 0xf0 : 0xf2 );
3881#endif
3882		break;
3883#endif
3884	}
3885}
3886static int
3887pc98_check_if_type( int iobase, struct siodev *iod)
3888{
3889	int	irr = 0, tmp = 0;
3890	int	ret = 0;
3891	static  short	irq_tab[2][8] = {
3892		{  3,  5,  6,  9, 10, 12, 13, -1},
3893		{  3, 10, 12, 13,  5,  6,  9, -1}
3894	};
3895	iod->irq = 0;
3896	switch ( iobase & 0xff ) {
3897		case IO_COM1:
3898			iod->if_type = COM_IF_INTERNAL;
3899			ret = 0; iod->irq = 4; break;
3900#ifdef COM_IF_PC9861K
3901		case IO_COM2:
3902			iod->if_type = COM_IF_PC9861K;
3903			ret = 1; irr = 0; tmp = 3; break;
3904		case IO_COM3:
3905			iod->if_type = COM_IF_PC9861K;
3906			ret = 2; irr = 1; tmp = 3; break;
3907#endif
3908#ifdef COM_IF_PIO9032B
3909	    case IO_COM_PIO9032B_2:
3910			iod->if_type = COM_IF_PIO9032B;
3911			ret = 1; irr = 0; tmp = 7; break;
3912	    case IO_COM_PIO9032B_3:
3913			iod->if_type = COM_IF_PIO9032B;
3914			ret = 2; irr = 1; tmp = 7; break;
3915#endif
3916#ifdef COM_IF_B98_01
3917	    case IO_COM_B98_01_2:
3918			iod->if_type = COM_IF_B98_01;
3919			ret = 1; irr = 0; tmp = 7;
3920			outb(iobase + 2, 0xf2);
3921			outb(iobase,     4);
3922			break;
3923	    case IO_COM_B98_01_3:
3924			iod->if_type = COM_IF_B98_01;
3925			ret = 2; irr = 1; tmp = 7;
3926			outb(iobase + 2, 0xf2);
3927			outb(iobase    , 4);
3928			break;
3929#endif
3930	    default:
3931			if((iobase & 0x0f0) == 0xd0){
3932				iod->if_type = MC16550;
3933				return 0;
3934			}
3935			return -1;
3936	}
3937
3938	iod->cmd  = ( iobase & 0xff00 )|PC98SIO_cmd_port(ret);
3939	iod->sts  = ( iobase & 0xff00 )|PC98SIO_sts_port(ret);
3940	iod->mod  = ( iobase & 0xff00 )|PC98SIO_in_modem_port(ret);
3941	iod->ctrl = ( iobase & 0xff00 )|PC98SIO_intr_ctrl_port(ret);
3942
3943	if ( iod->irq == 0 ) {
3944		tmp &= inb( iod->mod );
3945		iod->irq = irq_tab[irr][tmp];
3946		if ( iod->irq == -1 ) return -1;
3947	}
3948	return 0;
3949}
3950static int
3951pc98_set_ioport( struct com_s *com, int io_base )
3952{
3953	int	a, io, type;
3954
3955	switch ( io_base & 0xff ) {
3956	    case IO_COM1: a = 0; io = 0; type = COM_IF_INTERNAL;
3957					 pc98_check_sysclock(); break;
3958#ifdef COM_IF_PC9861K
3959	    case IO_COM2: a = 1; io = 0; type = COM_IF_PC9861K; break;
3960	    case IO_COM3: a = 2; io = 0; type = COM_IF_PC9861K; break;
3961#endif /* COM_IF_PC9861K */
3962#ifdef COM_IF_PIO9032B
3963			/* PIO9032B : I/O address is changeable */
3964	    case IO_COM_PIO9032B_2:
3965			a = 1; io = io_base & 0xff00;
3966			type = COM_IF_PIO9032B; break;
3967	    case IO_COM_PIO9032B_3:
3968			a = 2; io = io_base & 0xff00;
3969			type = COM_IF_PIO9032B; break;
3970#endif /* COM_IF_PIO9032B */
3971#ifdef COM_IF_B98_01
3972	    case IO_COM_B98_01_2:
3973			a = 1; io = 0; type = COM_IF_B98_01; break;
3974	    case IO_COM_B98_01_3:
3975			a = 2; io = 0; type = COM_IF_B98_01; break;
3976#endif /* COM_IF_B98_01*/
3977	    default:	/* i/o address not match */
3978		return -1;
3979	}
3980
3981	com->pc98_if_type	= type;
3982	com->data_port		= io | PC98SIO_data_port(a);
3983	com->cmd_port		= io | PC98SIO_cmd_port(a);
3984	com->sts_port		= io | PC98SIO_sts_port(a);
3985	com->in_modem_port	= io | PC98SIO_in_modem_port(a);
3986	com->intr_ctrl_port	= io | PC98SIO_intr_ctrl_port(a);
3987	return 0;
3988}
3989#endif /* PC98 defined */
3990