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