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