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