sio.c revision 36762
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1991 The Regents of the University of California.
31541Srgrimes * All rights reserved.
45455Sdg *
55455Sdg * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
331541Srgrimes *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
341541Srgrimes *	$Id: sio.c,v 1.59 1998/06/05 08:31:01 kato Exp $
351541Srgrimes */
367164Sdg
371541Srgrimes#include "opt_comconsole.h"
381541Srgrimes#include "opt_compat.h"
391541Srgrimes#include "opt_ddb.h"
401549Srgrimes#include "opt_devfs.h"
411541Srgrimes#include "opt_sio.h"
421541Srgrimes#include "sio.h"
431541Srgrimes#include "pnp.h"
441541Srgrimes
451541Srgrimes#ifndef EXTRA_SIO
461541Srgrimes#if NPNP > 0
475455Sdg#define EXTRA_SIO 2
485455Sdg#else
496621Sdg#define EXTRA_SIO 0
506621Sdg#endif
511541Srgrimes#endif
521541Srgrimes
531541Srgrimes#define NSIOTOT (NSIO + EXTRA_SIO)
541541Srgrimes
553055Sdg/*
565455Sdg * Serial driver, based on 386BSD-0.1 com driver.
575455Sdg * Mostly rewritten to use pseudo-DMA.
581541Srgrimes * Works for National Semiconductor NS8250-NS16550AF UARTs.
591541Srgrimes * COM driver, based on HP dca driver.
603055Sdg *
611541Srgrimes * Changes for PC-Card integration:
621541Srgrimes *	- Added PC-Card driver table and handlers
631541Srgrimes */
641541Srgrimes/*===============================================================
651541Srgrimes * 386BSD(98),FreeBSD-1.1x(98) com driver.
661541Srgrimes * -----
675455Sdg * modified for PC9801 by M.Ishii
681541Srgrimes *			Kyoto University Microcomputer Club (KMC)
691541Srgrimes * Chou "TEFUTEFU" Hirotomi
705455Sdg *			Kyoto Univ.  the faculty of medicine
715455Sdg *===============================================================
725455Sdg * FreeBSD-2.0.1(98) sio driver.
731541Srgrimes * -----
741541Srgrimes * modified for pc98 Internal i8251 and MICRO CORE MC16550II
751541Srgrimes *			T.Koike(hfc01340@niftyserve.or.jp)
761541Srgrimes * implement kernel device configuration
771541Srgrimes *			aizu@orient.center.nitech.ac.jp
781541Srgrimes *
791541Srgrimes * Notes.
801541Srgrimes * -----
811541Srgrimes *  PC98 localization based on 386BSD(98) com driver. Using its PC98 local
821541Srgrimes *  functions.
831541Srgrimes *  This driver is under debugging,has bugs.
841541Srgrimes *
851541Srgrimes * 1) config
865455Sdg *  options COM_MULTIPORT  #if using MC16550II
875455Sdg *  device sio0 at nec? port 0x30  tty irq 4 vector siointr #internal
881541Srgrimes *  device sio1 at nec? port 0xd2  tty irq 5 flags 0x101 vector siointr #mc1
891541Srgrimes *  device sio2 at nec? port 0x8d2 tty flags 0x101 vector siointr       #mc2
901541Srgrimes *                         # ~~~~~iobase        ~~multi port flag
911541Srgrimes *                         #                   ~  master device is sio1
921541Srgrimes * 2) device
935839Sdg *  cd /dev; MAKEDEV ttyd0 ttyd1 ..
941541Srgrimes * 3) /etc/rc.serial
951541Srgrimes *  57600bps is too fast for sio0(internal8251)
961541Srgrimes *  my ex.
971541Srgrimes *    #set default speed 9600
981541Srgrimes *    modem()
991541Srgrimes *       :
1001541Srgrimes *      stty </dev/ttyid$i crtscts 9600
1011541Srgrimes *       :                 #       ~~~~ default speed(can change after init.)
1021541Srgrimes *    modem 0 1 2
1031541Srgrimes * 4) COMCONSOLE
1041541Srgrimes *  not changed.
1051549Srgrimes * 5) PC9861K,PIO9032B,B98_01
1061541Srgrimes *  not tested.
1071541Srgrimes */
1081541Srgrimes/*
1091541Srgrimes * modified for AIWA B98-01
1101541Srgrimes * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp>  last update: 15 Sep.1995
1111541Srgrimes *
1121541Srgrimes * How to configure...
1131541Srgrimes *   # options COM_MULTIPORT         # support for MICROCORE MC16550II
1141541Srgrimes *      ... comment-out this line, which will conflict with B98_01.
1155455Sdg *   options "B98_01"                # support for AIWA B98-01
1161541Srgrimes *   device  sio1 at nec? port 0x00d1 tty irq ? vector siointr
1171541Srgrimes *   device  sio2 at nec? port 0x00d5 tty irq ? vector siointr
1181541Srgrimes *      ... you can leave these lines `irq ?', irq will be autodetected.
1195455Sdg */
1201541Srgrimes#ifdef PC98
1215455Sdg#define	MC16550		0
1225455Sdg#define COM_IF_INTERNAL	1
1235455Sdg#if 0
1241541Srgrimes#define COM_IF_PC9861K	2
1255455Sdg#define COM_IF_PIO9032B	3
1265455Sdg#endif
1275455Sdg#ifdef	B98_01
1285455Sdg#undef  COM_MULTIPORT	/* COM_MULTIPORT will conflict with B98_01 */
1295455Sdg#define COM_IF_B98_01	4
1301541Srgrimes#endif /* B98_01 */
1315455Sdg#endif /* PC98 */
1325455Sdg
1335455Sdg#include <sys/param.h>
1346621Sdg#include <sys/systm.h>
1355455Sdg#include <sys/reboot.h>
1365455Sdg#include <sys/malloc.h>
1376621Sdg#include <sys/tty.h>
1385839Sdg#include <sys/proc.h>
1395839Sdg#include <sys/conf.h>
1406621Sdg#include <sys/dkstat.h>
1415839Sdg#include <sys/fcntl.h>
1426621Sdg#include <sys/kernel.h>
1435839Sdg#include <sys/syslog.h>
1445455Sdg#include <sys/sysctl.h>
1455455Sdg#ifdef DEVFS
1461541Srgrimes#include <sys/devfsext.h>
1475455Sdg#endif
1485455Sdg
1491541Srgrimes#include <machine/clock.h>
1501541Srgrimes
1515455Sdg#ifdef PC98
1525455Sdg#include <pc98/pc98/pc98.h>
1531541Srgrimes#include <pc98/pc98/pc98_machdep.h>
1541541Srgrimes#include <i386/isa/icu.h>
1555455Sdg#include <i386/isa/isa_device.h>
1561541Srgrimes#include <pc98/pc98/sioreg.h>
1575455Sdg#include <i386/isa/ic/i8251.h>
1585455Sdg#else
1595455Sdg#include <i386/isa/isa.h>
1605455Sdg#include <i386/isa/isa_device.h>
1615455Sdg#include <i386/isa/sioreg.h>
1625455Sdg#endif
1635455Sdg#include <i386/isa/intr_machdep.h>
1645455Sdg
1655455Sdg#ifdef COM_ESP
1665455Sdg#include <i386/isa/ic/esp.h>
1675455Sdg#endif
1685455Sdg#include <i386/isa/ic/ns16550.h>
1695455Sdg
1705455Sdg#include "card.h"
1711541Srgrimes#if NCARD > 0
1725455Sdg#include <pccard/cardinfo.h>
1735455Sdg#include <pccard/slot.h>
1745455Sdg#endif
1755455Sdg
1761541Srgrimes#if NPNP > 0
1775455Sdg#include <i386/isa/pnp.h>
1785455Sdg#endif
1795455Sdg
1805455Sdg#ifdef SMP
1815455Sdg#define disable_intr()	COM_DISABLE_INTR()
1825455Sdg#define enable_intr()	COM_ENABLE_INTR()
1835455Sdg#endif /* SMP */
1845455Sdg
1855455Sdg#define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
1866621Sdg#define	RB_I_HIGH_WATER	(TTYHOG - 2 * RS_IBUFSIZE)
1876621Sdg#define	RS_IBUFSIZE	256
1886621Sdg
1895455Sdg#define	CALLOUT_MASK		0x80
1906621Sdg#define	CONTROL_MASK		0x60
1915455Sdg#define	CONTROL_INIT_STATE	0x20
1925455Sdg#define	CONTROL_LOCK_STATE	0x40
1935455Sdg#define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
1945455Sdg#define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
1956621Sdg#define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)
1966621Sdg
1975455Sdg#ifdef COM_MULTIPORT
1981541Srgrimes/* checks in flags for multiport and which is multiport "master chip"
1995455Sdg * for a given card
2005455Sdg */
2015455Sdg#define	COM_ISMULTIPORT(dev)	((dev)->id_flags & 0x01)
2025455Sdg#define	COM_MPMASTER(dev)	(((dev)->id_flags >> 8) & 0x0ff)
2035455Sdg#define	COM_NOTAST4(dev)	((dev)->id_flags & 0x04)
2045455Sdg#endif /* COM_MULTIPORT */
2055455Sdg
2065455Sdg#define	COM_CONSOLE(dev)	((dev)->id_flags & 0x10)
2075455Sdg#define	COM_FORCECONSOLE(dev)	((dev)->id_flags & 0x20)
2085839Sdg#define	COM_LLCONSOLE(dev)	((dev)->id_flags & 0x40)
2095839Sdg#define	COM_LOSESOUTINTS(dev)	((dev)->id_flags & 0x08)
2105455Sdg#define	COM_NOFIFO(dev)		((dev)->id_flags & 0x02)
2115455Sdg#define COM_ST16650A(dev)	((dev)->id_flags & 0x20000)
2121541Srgrimes#define COM_C_NOPROBE     (0x40000)
2136621Sdg#define COM_NOPROBE(dev)  ((dev)->id_flags & COM_C_NOPROBE)
2141541Srgrimes#define COM_C_IIR_TXRDYBUG    (0x80000)
2155455Sdg#define COM_IIR_TXRDYBUG(dev) ((dev)->id_flags & COM_C_IIR_TXRDYBUG)
2161541Srgrimes#define	COM_FIFOSIZE(dev)	(((dev)->id_flags & 0xff000000) >> 24)
2175455Sdg
2185455Sdg#ifndef PC98
2191541Srgrimes#define	com_scr		7	/* scratch register for 16450-16550 (R/W) */
2201541Srgrimes#endif /* !PC98 */
2211541Srgrimes
2225839Sdg/*
2235455Sdg * Input buffer watermarks.
2245455Sdg * The external device is asked to stop sending when the buffer exactly reaches
2255455Sdg * high water, or when the high level requests it.
2265455Sdg * The high level is notified immediately (rather than at a later clock tick)
2275455Sdg * when this watermark is reached.
2281541Srgrimes * The buffer size is chosen so the watermark should almost never be reached.
2291541Srgrimes * The low watermark is invisibly 0 since the buffer is always emptied all at
2305455Sdg * once.
2315455Sdg */
2321541Srgrimes#define	RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
2335455Sdg
2345455Sdg/*
2355455Sdg * com state bits.
2365455Sdg * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
2375455Sdg * than the other bits so that they can be tested as a group without masking
2385455Sdg * off the low bits.
2395455Sdg *
2405455Sdg * The following com and tty flags correspond closely:
2415455Sdg *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and
2425455Sdg *				   siostop())
2436621Sdg *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart())
2445455Sdg *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam())
2451541Srgrimes *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam())
2461541Srgrimes * TS_FLUSH is not used.
2475455Sdg * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
2485455Sdg * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
2491541Srgrimes */
2505455Sdg#define	CS_BUSY		0x80	/* output in progress */
2515455Sdg#define	CS_TTGO		0x40	/* output not stopped by XOFF */
2525455Sdg#define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */
2535455Sdg#define	CS_CHECKMSR	1	/* check of MSR scheduled */
2545455Sdg#define	CS_CTS_OFLOW	2	/* use CTS output flow control */
2555839Sdg#define	CS_DTR_OFF	0x10	/* DTR held off */
2565455Sdg#define	CS_ODONE	4	/* output completed */
2575455Sdg#define	CS_RTS_IFLOW	8	/* use RTS input flow control */
2581541Srgrimes#define	CSE_BUSYCHECK	1	/* siobusycheck() scheduled */
2591541Srgrimes
2601541Srgrimesstatic	char const * const	error_desc[] = {
2611541Srgrimes#define	CE_OVERRUN			0
2621541Srgrimes	"silo overflow",
2631541Srgrimes#define	CE_INTERRUPT_BUF_OVERFLOW	1
2641541Srgrimes	"interrupt-level buffer overflow",
2651541Srgrimes#define	CE_TTY_BUF_OVERFLOW		2
2661541Srgrimes	"tty-level buffer overflow",
2671541Srgrimes};
2681541Srgrimes
2691541Srgrimes#define	CE_NTYPES			3
2701541Srgrimes#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
2711541Srgrimes
2721541Srgrimes/* types.  XXX - should be elsewhere */
2731541Srgrimestypedef u_int	Port_t;		/* hardware port */
2741541Srgrimestypedef u_char	bool_t;		/* boolean */
2751541Srgrimes
2761541Srgrimes/* queue of linear buffers */
2771541Srgrimesstruct lbq {
2781541Srgrimes	u_char	*l_head;	/* next char to process */
2795455Sdg	u_char	*l_tail;	/* one past the last char to process */
2801541Srgrimes	struct lbq *l_next;	/* next in queue */
2811541Srgrimes	bool_t	l_queued;	/* nonzero if queued */
2821541Srgrimes};
2831541Srgrimes
2845455Sdg/* com device structure */
2851541Srgrimesstruct com_s {
2861541Srgrimes	u_int	id_flags;	/* Copy isa device falgas */
2871541Srgrimes	u_char	state;		/* miscellaneous flag bits */
2881541Srgrimes	bool_t  active_out;	/* nonzero if the callout device is open */
2891541Srgrimes	u_char	cfcr_image;	/* copy of value written to CFCR */
2901541Srgrimes#ifdef COM_ESP
2911541Srgrimes	bool_t	esp;		/* is this unit a hayes esp board? */
2921541Srgrimes#endif
2931541Srgrimes	u_char	extra_state;	/* more flag bits, separate for order trick */
2945455Sdg	u_char	fifo_image;	/* copy of value written to FIFO */
2951541Srgrimes	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
2965455Sdg	bool_t	st16650a;	/* Is a Startech 16650A or RTS/CTS compat */
2975455Sdg	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
2985455Sdg	u_char	mcr_image;	/* copy of value written to MCR */
2995455Sdg#ifdef COM_MULTIPORT
3005455Sdg	bool_t	multiport;	/* is this unit part of a multiport device? */
3015455Sdg#endif /* COM_MULTIPORT */
3025455Sdg	bool_t	no_irq;		/* nonzero if irq is not attached */
3035455Sdg	bool_t  gone;		/* hardware disappeared */
3045455Sdg	bool_t	poll;		/* nonzero if polling is required */
3055455Sdg	bool_t	poll_output;	/* nonzero if polling for output is required */
3065455Sdg	int	unit;		/* unit	number */
3075455Sdg	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
3085455Sdg	u_int	tx_fifo_size;
3095455Sdg	u_int	wopeners;	/* # processes waiting for DCD in open() */
3105455Sdg
3111541Srgrimes	/*
3125142Sdg	 * The high level of the driver never reads status registers directly
3131541Srgrimes	 * because there would be too many side effects to handle conveniently.
3141541Srgrimes	 * Instead, it reads copies of the registers stored here by the
3155455Sdg	 * interrupt handler.
3165455Sdg	 */
3171541Srgrimes	u_char	last_modem_status;	/* last MSR read by intr handler */
3185455Sdg	u_char	prev_modem_status;	/* last MSR handled by high level */
3195455Sdg
3205455Sdg	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
3215455Sdg	u_char	*ibuf;		/* start of input buffer */
3225455Sdg	u_char	*ibufend;	/* end of input buffer */
3235455Sdg	u_char	*ihighwater;	/* threshold in input buffer */
3245455Sdg	u_char	*iptr;		/* next free spot in input buffer */
3251541Srgrimes
3265455Sdg	struct lbq	obufq;	/* head of queue of output buffers */
3275455Sdg	struct lbq	obufs[2];	/* output buffers */
3285455Sdg
3295455Sdg#ifdef PC98
3305455Sdg	Port_t	cmd_port;
3315455Sdg	Port_t	sts_port;
3325455Sdg	Port_t	in_modem_port;
3335455Sdg	Port_t	intr_ctrl_port;
3345455Sdg	int	intr_enable;
3355455Sdg	int	pc98_prev_modem_status;
3365455Sdg	int	pc98_modem_delta;
3375455Sdg	int	modem_car_chg_timer;
3381541Srgrimes	int	pc98_prev_siocmd;
3391541Srgrimes	int	pc98_prev_siomod;
3405455Sdg	int	modem_checking;
3415455Sdg	int	pc98_if_type;
3425455Sdg#endif /* PC98 */
3431541Srgrimes	Port_t	data_port;	/* i/o ports */
3445455Sdg#ifdef COM_ESP
3455455Sdg	Port_t	esp_port;
3465455Sdg#endif
3471541Srgrimes	Port_t	int_id_port;
3486621Sdg	Port_t	iobase;
3495455Sdg	Port_t	modem_ctl_port;
3501541Srgrimes	Port_t	line_status_port;
3511541Srgrimes	Port_t	modem_status_port;
3521541Srgrimes	Port_t	intr_ctl_port;	/* Ports of IIR register */
3531541Srgrimes
3541541Srgrimes	struct tty	*tp;	/* cross reference */
3551541Srgrimes
3561541Srgrimes	/* Initial state. */
3571541Srgrimes	struct termios	it_in;	/* should be in struct tty */
3581541Srgrimes	struct termios	it_out;
3591541Srgrimes
3601541Srgrimes	/* Lock state. */
3611541Srgrimes	struct termios	lt_in;	/* should be in struct tty */
3621541Srgrimes	struct termios	lt_out;
3631541Srgrimes
3641541Srgrimes	bool_t	do_timestamp;
3651541Srgrimes	bool_t	do_dcd_timestamp;
3661541Srgrimes	struct timeval	timestamp;
3671541Srgrimes	struct timeval	dcd_timestamp;
3681541Srgrimes
3691541Srgrimes	u_long	bytes_in;	/* statistics */
3701541Srgrimes	u_long	bytes_out;
3711541Srgrimes	u_int	delta_error_counts[CE_NTYPES];
3721541Srgrimes	u_long	error_counts[CE_NTYPES];
3735455Sdg
3746621Sdg	/*
3751541Srgrimes	 * Ping-pong input buffers.  The extra factor of 2 in the sizes is
3761541Srgrimes	 * to allow for an error byte for each input byte.
3771541Srgrimes	 */
3781541Srgrimes#define	CE_INPUT_OFFSET		RS_IBUFSIZE
3791541Srgrimes	u_char	ibuf1[2 * RS_IBUFSIZE];
3801541Srgrimes	u_char	ibuf2[2 * RS_IBUFSIZE];
3811541Srgrimes
3821541Srgrimes	/*
3831541Srgrimes	 * Data area for output buffers.  Someday we should build the output
3841541Srgrimes	 * buffer queue without copying data.
3851541Srgrimes	 */
3861541Srgrimes	u_char	obuf1[256];
3871541Srgrimes	u_char	obuf2[256];
3885455Sdg#ifdef DEVFS
3891541Srgrimes	void	*devfs_token_ttyd;
3901541Srgrimes	void	*devfs_token_ttyl;
3911541Srgrimes	void	*devfs_token_ttyi;
3921541Srgrimes	void	*devfs_token_cuaa;
3931541Srgrimes	void	*devfs_token_cual;
3941541Srgrimes	void	*devfs_token_cuai;
3951541Srgrimes#endif
3961541Srgrimes};
3971541Srgrimes
3981541Srgrimes/*
3991541Srgrimes * XXX public functions in drivers should be declared in headers produced
4001541Srgrimes * by `config', not here.
4011541Srgrimes */
4021541Srgrimes
4035455Sdg/* Interrupt handling entry point. */
4041541Srgrimesvoid	siopoll		__P((void));
4051541Srgrimes
4065455Sdg/* Device switch entry points. */
4075455Sdg#define	sioreset	noreset
4085455Sdg#define	siommap		nommap
4095455Sdg#define	siostrategy	nostrategy
4101541Srgrimes
4115455Sdg#ifdef COM_ESP
4125455Sdgstatic	int	espattach	__P((struct isa_device *isdp, struct com_s *com,
4135455Sdg				     Port_t esp_port));
4141541Srgrimes#endif
4151541Srgrimesstatic	int	sioattach	__P((struct isa_device *dev));
4161541Srgrimesstatic	timeout_t siobusycheck;
4171541Srgrimesstatic	timeout_t siodtrwakeup;
4181541Srgrimesstatic	void	comhardclose	__P((struct com_s *com));
4195455Sdgstatic	void	siointr1	__P((struct com_s *com));
4205455Sdgstatic	int	commctl		__P((struct com_s *com, int bits, int how));
4215839Sdgstatic	int	comparam	__P((struct tty *tp, struct termios *t));
4221541Srgrimesstatic	int	sioprobe	__P((struct isa_device *dev));
4231541Srgrimesstatic	void	siosettimeout	__P((void));
4241541Srgrimesstatic	void	comstart	__P((struct tty *tp));
4255455Sdgstatic	timeout_t comwakeup;
4261541Srgrimesstatic	void	disc_optim	__P((struct tty	*tp, struct termios *t,
4275455Sdg				     struct com_s *com));
4285455Sdg
4295455Sdg#ifdef DSI_SOFT_MODEM
4305455Sdgstatic  int 	LoadSoftModem   __P((int unit,int base_io, u_long size, u_char *ptr));
4311541Srgrimes#endif /* DSI_SOFT_MODEM */
4321541Srgrimes
4335455Sdgstatic char driver_name[] = "sio";
4345455Sdg
4351541Srgrimes/* table and macro for fast conversion from a unit number to its com struct */
4361541Srgrimesstatic	struct com_s	*p_com_addr[NSIOTOT];
4375455Sdg#define	com_addr(unit)	(p_com_addr[unit])
4385455Sdg
4395455Sdgstruct isa_driver	siodriver = {
4401541Srgrimes	sioprobe, sioattach, driver_name
4415455Sdg};
4421541Srgrimes
4435455Sdgstatic	d_open_t	sioopen;
4441541Srgrimesstatic	d_close_t	sioclose;
4451541Srgrimesstatic	d_read_t	sioread;
4461541Srgrimesstatic	d_write_t	siowrite;
4471541Srgrimesstatic	d_ioctl_t	sioioctl;
4481541Srgrimesstatic	d_stop_t	siostop;
4491541Srgrimesstatic	d_devtotty_t	siodevtotty;
4501541Srgrimes
4515455Sdg#define CDEV_MAJOR 28
4525455Sdgstatic struct cdevsw sio_cdevsw = {
4531541Srgrimes	sioopen,	sioclose,	sioread,	siowrite,
4545455Sdg	sioioctl,	siostop,	noreset,	siodevtotty,
4555455Sdg	ttpoll,		nommap,		NULL,		driver_name,
4561541Srgrimes	NULL,		-1,
4575455Sdg};
4581541Srgrimes
4591541Srgrimesstatic	int	comconsole = -1;
4601541Srgrimesstatic	volatile speed_t	comdefaultrate = CONSPEED;
4611541Srgrimesstatic	u_int	com_events;	/* input chars + weighted output completions */
4621541Srgrimesstatic	Port_t	siocniobase;
4631541Srgrimesstatic	int	sio_timeout;
4641541Srgrimesstatic	int	sio_timeouts_until_log;
4651541Srgrimesstatic	struct	callout_handle sio_timeout_handle
4661541Srgrimes    = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
4671541Srgrimes#if 0 /* XXX */
4681541Srgrimesstatic struct tty	*sio_tty[NSIOTOT];
4695455Sdg#else
4701541Srgrimesstatic struct tty	sio_tty[NSIOTOT];
4711541Srgrimes#endif
4721541Srgrimesstatic	const int	nsio_tty = NSIOTOT;
4731541Srgrimes
4741541Srgrimes#ifdef PC98
4751541Srgrimesstruct	siodev	{
4761541Srgrimes	short	if_type;
4771541Srgrimes	short	irq;
4781541Srgrimes	Port_t	cmd, sts, ctrl, mod;
4791541Srgrimes	};
4801541Srgrimesstatic	int	sysclock;
4811541Srgrimesstatic	short	port_table[5][3] = {
4821541Srgrimes			{0x30, 0xb1, 0xb9},
4831541Srgrimes			{0x32, 0xb3, 0xbb},
4841541Srgrimes			{0x32, 0xb3, 0xbb},
4851541Srgrimes			{0x33, 0xb0, 0xb2},
4861541Srgrimes			{0x35, 0xb0, 0xb2}
4871541Srgrimes		};
4881541Srgrimes#define	PC98SIO_data_port(ch)		port_table[0][ch]
4891541Srgrimes#define	PC98SIO_cmd_port(ch)		port_table[1][ch]
4905455Sdg#define	PC98SIO_sts_port(ch)		port_table[2][ch]
4911541Srgrimes#define	PC98SIO_in_modem_port(ch)	port_table[3][ch]
4921541Srgrimes#define	PC98SIO_intr_ctrl_port(ch)	port_table[4][ch]
4935839Sdg#ifdef COM_IF_PIO9032B
4945455Sdg#define   IO_COM_PIO9032B_2	0x0b8
4955455Sdg#define   IO_COM_PIO9032B_3	0x0ba
4961541Srgrimes#endif /* COM_IF_PIO9032B */
4971541Srgrimes#ifdef COM_IF_B98_01
4981541Srgrimes#define	  IO_COM_B98_01_2	0x0d1
4991541Srgrimes#define	  IO_COM_B98_01_3	0x0d5
5005455Sdg#endif /* COM_IF_B98_01 */
5011541Srgrimes#define	COM_INT_DISABLE		{int previpri; previpri=spltty();
5021541Srgrimes#define	COM_INT_ENABLE		splx(previpri);}
5036837Sdg#define IEN_TxFLAG		IEN_Tx
5046837Sdg
5056837Sdg#define COM_CARRIER_DETECT_EMULATE	0
5066837Sdg#define	PC98_CHECK_MODEM_INTERVAL	(hz/10)
5076837Sdg#define DCD_OFF_TOLERANCE		2
5086837Sdg#define DCD_ON_RECOGNITION		2
5091541Srgrimes#define	IS_8251(type)		(type != MC16550)
5107090Sbde#define	IS_PC98IN(adr)		(adr == 0x30)
5116837Sdg
5127164Sdgstatic	void	commint		__P((dev_t dev));
5137164Sdgstatic	void	com_tiocm_set	__P((struct com_s *com, int msr));
5147164Sdgstatic	void	com_tiocm_bis	__P((struct com_s *com, int msr));
5156837Sdgstatic	void	com_tiocm_bic	__P((struct com_s *com, int msr));
5166837Sdgstatic	int	com_tiocm_get	__P((struct com_s *com));
5176837Sdgstatic	int	com_tiocm_get_delta	__P((struct com_s *com));
5186837Sdgstatic	void	pc98_msrint_start	__P((dev_t dev));
5196837Sdgstatic	void	com_cflag_and_speed_set	__P((struct com_s *com, int cflag, int speed));
5206837Sdgstatic	int	pc98_ttspeedtab		__P((struct com_s *com, int speed));
5216837Sdgstatic	int	pc98_get_modem_status	__P((struct com_s *com));
5221541Srgrimesstatic	timeout_t	pc98_check_msr;
5236837Sdgstatic	void	pc98_set_baud_rate	__P((struct com_s *com, int count));
5246837Sdgstatic	void	pc98_i8251_reset	__P((struct com_s *com, int mode, int command));
5256837Sdgstatic	void	pc98_disable_i8251_interrupt	__P((struct com_s *com, int mod));
5266837Sdgstatic	void	pc98_enable_i8251_interrupt	__P((struct com_s *com, int mod));
5276837Sdgstatic	int	pc98_check_i8251_interrupt	__P((struct com_s *com));
5286837Sdgstatic	int	pc98_i8251_get_cmd	__P((struct com_s *com));
5296837Sdgstatic	int	pc98_i8251_get_mod	__P((struct com_s *com));
5306837Sdgstatic	void	pc98_i8251_set_cmd	__P((struct com_s *com, int x));
5317090Sbdestatic	void	pc98_i8251_or_cmd	__P((struct com_s *com, int x));
5327164Sdgstatic	void	pc98_i8251_clear_cmd	__P((struct com_s *com, int x));
5336837Sdgstatic	void	pc98_i8251_clear_or_cmd	__P((struct com_s *com, int clr, int x));
5346837Sdgstatic	int	pc98_check_if_type	__P((int iobase, struct siodev *iod));
5356837Sdgstatic	void	pc98_check_sysclock	__P((void));
5361541Srgrimesstatic	int	pc98_set_ioport		__P((struct com_s *com, int io_base));
5376837Sdg
5385455Sdg#define com_int_Tx_disable(com) \
5395839Sdg		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP)
5401541Srgrimes#define com_int_Tx_enable(com) \
5411541Srgrimes		pc98_enable_i8251_interrupt(com,IEN_TxFLAG)
5425455Sdg#define com_int_Rx_disable(com) \
5431541Srgrimes		pc98_disable_i8251_interrupt(com,IEN_Rx)
5441541Srgrimes#define com_int_Rx_enable(com) \
5451541Srgrimes		pc98_enable_i8251_interrupt(com,IEN_Rx)
5465455Sdg#define com_int_TxRx_disable(com) \
5475455Sdg		pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx)
5485455Sdg#define com_int_TxRx_enable(com) \
5495455Sdg		pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx)
5505455Sdg#define com_send_break_on(com) \
5511541Srgrimes		pc98_i8251_or_cmd(com,CMD8251_SBRK)
5525455Sdg#define com_send_break_off(com) \
5535839Sdg		pc98_i8251_clear_cmd(com,CMD8251_SBRK)
5541541Srgrimes
5551541Srgrimesstruct speedtab pc98speedtab[] = {	/* internal RS232C interface */
5565455Sdg	0,	0,
5571541Srgrimes	50,	50,
5581541Srgrimes	75,	75,
5595839Sdg	150,	150,
5605455Sdg	200,	200,
5611541Srgrimes	300,	300,
5621541Srgrimes	600,	600,
5635455Sdg	1200,	1200,
5645455Sdg	2400,	2400,
5655455Sdg	4800,	4800,
5665455Sdg	9600,	9600,
5675455Sdg	19200,	19200,
5681541Srgrimes	38400,	38400,
5695455Sdg	76800,	76800,
5705455Sdg	20800,	20800,
5715455Sdg	41600,	41600,
5725455Sdg	15600,	15600,
5735455Sdg	31200,	31200,
5745455Sdg	62400,	62400,
5751541Srgrimes	-1,	-1
5765455Sdg};
5771541Srgrimes#ifdef COM_IF_PIO9032B
5785455Sdgstruct speedtab comspeedtab_pio9032b[] = {
5795455Sdg	300,	6,
5805455Sdg	600,	5,
5815455Sdg	1200,	4,
5825455Sdg	2400,	3,
5835455Sdg	4800,	2,
5845455Sdg	9600,	1,
5855455Sdg	19200,	0,
5865455Sdg	38400,	7,
5871541Srgrimes	-1,	-1
5881541Srgrimes};
5895839Sdg#endif
5905455Sdg
5911541Srgrimes#ifdef COM_IF_B98_01
5926837Sdgstruct speedtab comspeedtab_b98_01[] = {
5936837Sdg	0,	0,
5946837Sdg	75,	15,
5955455Sdg	150,	14,
5965455Sdg	300,	13,
5975455Sdg	600,	12,
5985455Sdg	1200,	11,
5995455Sdg	2400,	10,
6005455Sdg	4800,	9,
6015839Sdg	9600,	8,
6025839Sdg	19200,	7,
6035455Sdg	38400,	6,
6045455Sdg	76800,	5,
6055455Sdg	153600,	4,
6065455Sdg	-1,	-1
6075455Sdg};
6085455Sdg#endif
6095455Sdg#endif /* PC98 */
6105455Sdg
6111541Srgrimesstatic	struct speedtab comspeedtab[] = {
6125455Sdg	{ 0,		0 },
6135455Sdg	{ 50,		COMBRD(50) },
6145455Sdg	{ 75,		COMBRD(75) },
6155455Sdg	{ 110,		COMBRD(110) },
6161541Srgrimes	{ 134,		COMBRD(134) },
6171541Srgrimes	{ 150,		COMBRD(150) },
6181541Srgrimes	{ 200,		COMBRD(200) },
6191541Srgrimes	{ 300,		COMBRD(300) },
6201937Sdg	{ 600,		COMBRD(600) },
6211541Srgrimes	{ 1200,		COMBRD(1200) },
6225455Sdg	{ 1800,		COMBRD(1800) },
6231541Srgrimes	{ 2400,		COMBRD(2400) },
6241541Srgrimes	{ 4800,		COMBRD(4800) },
6251541Srgrimes	{ 9600,		COMBRD(9600) },
6261541Srgrimes	{ 19200,	COMBRD(19200) },
6275455Sdg	{ 38400,	COMBRD(38400) },
6286621Sdg	{ 57600,	COMBRD(57600) },
6295455Sdg	{ 115200,	COMBRD(115200) },
6301541Srgrimes	{ -1,		-1 }
6311541Srgrimes};
6325455Sdg
6331541Srgrimes#ifdef COM_ESP
6341541Srgrimes/* XXX configure this properly. */
6351541Srgrimesstatic	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
6361541Srgrimesstatic	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
6371541Srgrimes#endif
6381541Srgrimes
6391541Srgrimes/*
6401541Srgrimes * handle sysctl read/write requests for console speed
6411541Srgrimes *
6421541Srgrimes * In addition to setting comdefaultrate for I/O through /dev/console,
6431541Srgrimes * also set the initial and lock values for the /dev/ttyXX device
6441541Srgrimes * if there is one associated with the console.  Finally, if the /dev/tty
6451541Srgrimes * device has already been open, change the speed on the open running port
6461541Srgrimes * itself.
6475455Sdg */
6481541Srgrimes
6491541Srgrimesstatic int
6501541Srgrimessysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS
6511541Srgrimes{
6521541Srgrimes	int error, s;
6531541Srgrimes	speed_t newspeed;
6545455Sdg	struct com_s *com;
6551541Srgrimes	struct tty *tp;
6565455Sdg
6575455Sdg	newspeed = comdefaultrate;
6581541Srgrimes
6591541Srgrimes	error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
6601541Srgrimes	if (error || !req->newptr)
6611541Srgrimes		return (error);
662
663	comdefaultrate = newspeed;
664
665	if (comconsole < 0)		/* serial console not selected? */
666		return (0);
667
668	com = com_addr(comconsole);
669	if (!com)
670		return (ENXIO);
671
672	/*
673	 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
674	 * (note, the lock rates really are boolean -- if non-zero, disallow
675	 *  speed changes)
676	 */
677	com->it_in.c_ispeed  = com->it_in.c_ospeed =
678	com->lt_in.c_ispeed  = com->lt_in.c_ospeed =
679	com->it_out.c_ispeed = com->it_out.c_ospeed =
680	com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate;
681
682	/*
683	 * if we're open, change the running rate too
684	 */
685	tp = com->tp;
686	if (tp && (tp->t_state & TS_ISOPEN)) {
687		tp->t_termios.c_ispeed =
688		tp->t_termios.c_ospeed = comdefaultrate;
689		s = spltty();
690		error = comparam(tp, &tp->t_termios);
691		splx(s);
692	}
693	return error;
694}
695
696SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
697	    0, 0, sysctl_machdep_comdefaultrate, "I", "");
698
699#if NCARD > 0
700/*
701 *	PC-Card (PCMCIA) specific code.
702 */
703static int	sioinit		__P((struct pccard_devinfo *));
704static void	siounload	__P((struct pccard_devinfo *));
705static int	card_intr	__P((struct pccard_devinfo *));
706
707static struct pccard_device sio_info = {
708	driver_name,
709	sioinit,
710	siounload,
711	card_intr,
712	0,			/* Attributes - presently unused */
713	&tty_imask		/* Interrupt mask for device */
714				/* XXX - Should this also include net_imask? */
715};
716
717DATA_SET(pccarddrv_set, sio_info);
718
719/*
720 *	Initialize the device - called from Slot manager.
721 */
722int
723sioinit(struct pccard_devinfo *devi)
724{
725
726	/* validate unit number. */
727	if (devi->isahd.id_unit >= (NSIOTOT))
728		return(ENODEV);
729	/* Make sure it isn't already probed. */
730	if (com_addr(devi->isahd.id_unit))
731		return(EBUSY);
732
733	/* It's already probed as serial by Upper */
734	devi->isahd.id_flags |= COM_C_NOPROBE;
735
736	/*
737	 * Probe the device. If a value is returned, the
738	 * device was found at the location.
739	 */
740	if (sioprobe(&devi->isahd) == 0)
741		return(ENXIO);
742	if (sioattach(&devi->isahd) == 0)
743		return(ENXIO);
744
745	return(0);
746}
747
748/*
749 *	siounload - unload the driver and clear the table.
750 *	XXX TODO:
751 *	This is usually called when the card is ejected, but
752 *	can be caused by a modunload of a controller driver.
753 *	The idea is to reset the driver's view of the device
754 *	and ensure that any driver entry points such as
755 *	read and write do not hang.
756 */
757static void
758siounload(struct pccard_devinfo *devi)
759{
760	struct com_s	*com;
761
762	com = com_addr(devi->isahd.id_unit);
763	if (!com->iobase) {
764		printf("sio%d already unloaded!\n",devi->isahd.id_unit);
765		return;
766	}
767	if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
768		com->gone = 1;
769		printf("sio%d: unload\n", devi->isahd.id_unit);
770		com->tp->t_gen++;
771		ttyclose(com->tp);
772		ttwakeup(com->tp);
773		ttwwakeup(com->tp);
774	} else {
775		com_addr(com->unit) = NULL;
776		bzero(com, sizeof *com);
777		free(com,M_TTYS);
778		printf("sio%d: unload,gone\n", devi->isahd.id_unit);
779	}
780}
781
782/*
783 *	card_intr - Shared interrupt called from
784 *	front end of PC-Card handler.
785 */
786static int
787card_intr(struct pccard_devinfo *devi)
788{
789	struct com_s	*com;
790
791	COM_LOCK();
792	com = com_addr(devi->isahd.id_unit);
793	if (com && !com->gone)
794		siointr1(com_addr(devi->isahd.id_unit));
795	COM_UNLOCK();
796	return(1);
797}
798#endif /* NCARD > 0 */
799
800static int
801sioprobe(dev)
802	struct isa_device	*dev;
803{
804	static bool_t	already_init;
805	bool_t		failures[10];
806	int		fn;
807	struct isa_device	*idev;
808	Port_t		iobase;
809	intrmask_t	irqmap[4];
810	intrmask_t	irqs;
811	u_char		mcr_image;
812	int		result;
813	struct isa_device	*xdev;
814#ifdef PC98
815	int		irqout=0;
816	int		ret = 0;
817	int		tmp;
818	struct		siodev	iod;
819#endif
820
821	if (!already_init) {
822		/*
823		 * Turn off MCR_IENABLE for all likely serial ports.  An unused
824		 * port with its MCR_IENABLE gate open will inhibit interrupts
825		 * from any used port that shares the interrupt vector.
826		 * XXX the gate enable is elsewhere for some multiports.
827		 */
828		for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++)
829			if (xdev->id_driver == &siodriver && xdev->id_enabled)
830#ifdef PC98
831				if (IS_PC98IN(xdev->id_iobase))
832					outb(xdev->id_iobase + 2, 0xf2);
833				else
834#endif
835				outb(xdev->id_iobase + com_mcr, 0);
836		already_init = TRUE;
837	}
838
839	if (COM_LLCONSOLE(dev)) {
840		printf("sio%d: reserved for low-level i/o\n", dev->id_unit);
841		return (0);
842	}
843
844#ifdef PC98
845	DELAY(10);
846	/*
847	 * If the port is i8251 UART (internal, B98_01)
848	 */
849	if(pc98_check_if_type(dev->id_iobase, &iod) == -1)
850		return 0;
851	if(IS_8251(iod.if_type)){
852		if ( iod.irq > 0 )
853			dev->id_irq = (1 << iod.irq);
854		outb(iod.cmd, 0);
855		DELAY(10);
856		outb(iod.cmd, 0);
857		DELAY(10);
858		outb(iod.cmd, 0);
859		DELAY(10);
860		outb(iod.cmd, CMD8251_RESET);
861		DELAY(1000);		/* for a while...*/
862		outb(iod.cmd, 0xf2);	/* MODE (dummy) */
863		DELAY(10);
864		outb(iod.cmd, 0x01);	/* CMD (dummy) */
865		DELAY(1000);		/* for a while...*/
866		if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) {
867			ret = 0;
868		}
869		switch (iod.if_type) {
870		case COM_IF_INTERNAL:
871			COM_INT_DISABLE
872			tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx));
873			outb( iod.ctrl, tmp|IEN_TxEMP );
874			DELAY(10);
875			ret = isa_irq_pending() ? 4 : 0;
876			outb( iod.ctrl, tmp );
877			COM_INT_ENABLE
878			break;
879#ifdef COM_IF_B98_01
880		case COM_IF_B98_01:
881			/* B98_01 doesn't activate TxEMP interrupt line
882			   when being reset, so we can't check irq pending.*/
883			ret = 4;
884			break;
885#endif
886		}
887		if (epson_machine_id==0x20) {	/* XXX */
888			ret = 4;
889		}
890		return ret;
891	}
892#endif /* PC98 */
893	/*
894	 * If the device is on a multiport card and has an AST/4
895	 * compatible interrupt control register, initialize this
896	 * register and prepare to leave MCR_IENABLE clear in the mcr.
897	 * Otherwise, prepare to set MCR_IENABLE in the mcr.
898	 * Point idev to the device struct giving the correct id_irq.
899	 * This is the struct for the master device if there is one.
900	 */
901	idev = dev;
902	mcr_image = MCR_IENABLE;
903#ifdef COM_MULTIPORT
904	if (COM_ISMULTIPORT(dev)) {
905		idev = find_isadev(isa_devtab_tty, &siodriver,
906				   COM_MPMASTER(dev));
907		if (idev == NULL) {
908			printf("sio%d: master device %d not configured\n",
909			       dev->id_unit, COM_MPMASTER(dev));
910			dev->id_irq = 0;
911			idev = dev;
912		}
913#ifndef PC98
914		if (!COM_NOTAST4(dev)) {
915			outb(idev->id_iobase + com_scr,
916			     idev->id_irq ? 0x80 : 0);
917			mcr_image = 0;
918		}
919#endif /* !PC98 */
920	}
921#endif /* COM_MULTIPORT */
922	if (idev->id_irq == 0)
923		mcr_image = 0;
924
925#ifdef PC98
926	switch(idev->id_irq){
927		case IRQ3: irqout = 4; break;
928		case IRQ5: irqout = 5; break;
929		case IRQ6: irqout = 6; break;
930		case IRQ12: irqout = 7; break;
931		default:
932			printf("sio%d: irq configuration error\n",dev->id_unit);
933			return (0);
934	}
935	outb(dev->id_iobase+0x1000, irqout);
936#endif
937	bzero(failures, sizeof failures);
938	iobase = dev->id_iobase;
939
940	/*
941	 * We don't want to get actual interrupts, just masked ones.
942	 * Interrupts from this line should already be masked in the ICU,
943	 * but mask them in the processor as well in case there are some
944	 * (misconfigured) shared interrupts.
945	 */
946	disable_intr();
947/* EXTRA DELAY? */
948
949	/*
950	 * Initialize the speed and the word size and wait long enough to
951	 * drain the maximum of 16 bytes of junk in device output queues.
952	 * The speed is undefined after a master reset and must be set
953	 * before relying on anything related to output.  There may be
954	 * junk after a (very fast) soft reboot and (apparently) after
955	 * master reset.
956	 * XXX what about the UART bug avoided by waiting in comparam()?
957	 * We don't want to to wait long enough to drain at 2 bps.
958	 */
959	if (iobase == siocniobase)
960		DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
961	else {
962		outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
963		outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
964		outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
965		outb(iobase + com_cfcr, CFCR_8BITS);
966		DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
967	}
968
969	/*
970	 * Enable the interrupt gate and disable device interupts.  This
971	 * should leave the device driving the interrupt line low and
972	 * guarantee an edge trigger if an interrupt can be generated.
973	 */
974/* EXTRA DELAY? */
975	outb(iobase + com_mcr, mcr_image);
976	outb(iobase + com_ier, 0);
977	DELAY(1000);		/* XXX */
978	irqmap[0] = isa_irq_pending();
979
980	/*
981	 * Attempt to set loopback mode so that we can send a null byte
982	 * without annoying any external device.
983	 */
984/* EXTRA DELAY? */
985	outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
986
987	/*
988	 * Attempt to generate an output interrupt.  On 8250's, setting
989	 * IER_ETXRDY generates an interrupt independent of the current
990	 * setting and independent of whether the THR is empty.  On 16450's,
991	 * setting IER_ETXRDY generates an interrupt independent of the
992	 * current setting.  On 16550A's, setting IER_ETXRDY only
993	 * generates an interrupt when IER_ETXRDY is not already set.
994	 */
995	outb(iobase + com_ier, IER_ETXRDY);
996
997	/*
998	 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
999	 * an interrupt.  They'd better generate one for actually doing
1000	 * output.  Loopback may be broken on the same incompatibles but
1001	 * it's unlikely to do more than allow the null byte out.
1002	 */
1003	outb(iobase + com_data, 0);
1004	DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
1005
1006	/*
1007	 * Turn off loopback mode so that the interrupt gate works again
1008	 * (MCR_IENABLE was hidden).  This should leave the device driving
1009	 * an interrupt line high.  It doesn't matter if the interrupt
1010	 * line oscillates while we are not looking at it, since interrupts
1011	 * are disabled.
1012	 */
1013/* EXTRA DELAY? */
1014	outb(iobase + com_mcr, mcr_image);
1015
1016    /*
1017	 * It's a definitly Serial PCMCIA(16550A), but still be required
1018	 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
1019	 */
1020	if ( COM_NOPROBE(dev) ) {
1021		/* Reading IIR register twice */
1022		for ( fn = 0; fn < 2; fn ++ ) {
1023			DELAY(10000);
1024			failures[6] = inb(iobase + com_iir);
1025		}
1026		/* Check IIR_TXRDY clear ? */
1027		result = IO_COMSIZE;
1028		if ( failures[6] & IIR_TXRDY ) {
1029			/* Nop, Double check with clearing IER */
1030			outb(iobase + com_ier, 0);
1031			if ( inb(iobase + com_iir) & IIR_NOPEND ) {
1032				/* Ok. we're familia this gang */
1033				dev->id_flags |= COM_C_IIR_TXRDYBUG; /* Set IIR_TXRDYBUG */
1034			} else {
1035				/* Unknow, Just omit this chip.. XXX*/
1036				result = 0;
1037			}
1038		} else {
1039			/* OK. this is well-known guys */
1040			dev->id_flags &= ~COM_C_IIR_TXRDYBUG; /*Clear IIR_TXRDYBUG*/
1041		}
1042		outb(iobase + com_cfcr, CFCR_8BITS);
1043		enable_intr();
1044		return (iobase == siocniobase ? IO_COMSIZE : result);
1045	}
1046
1047	/*
1048	 * Check that
1049	 *	o the CFCR, IER and MCR in UART hold the values written to them
1050	 *	  (the values happen to be all distinct - this is good for
1051	 *	  avoiding false positive tests from bus echoes).
1052	 *	o an output interrupt is generated and its vector is correct.
1053	 *	o the interrupt goes away when the IIR in the UART is read.
1054	 */
1055/* EXTRA DELAY? */
1056	failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
1057	failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
1058	failures[2] = inb(iobase + com_mcr) - mcr_image;
1059	DELAY(10000);		/* Some internal modems need this time */
1060	irqmap[1] = isa_irq_pending();
1061	failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
1062	DELAY(1000);		/* XXX */
1063	irqmap[2] = isa_irq_pending();
1064	failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
1065
1066	/*
1067	 * Turn off all device interrupts and check that they go off properly.
1068	 * Leave MCR_IENABLE alone.  For ports without a master port, it gates
1069	 * the OUT2 output of the UART to
1070	 * the ICU input.  Closing the gate would give a floating ICU input
1071	 * (unless there is another device driving at) and spurious interrupts.
1072	 * (On the system that this was first tested on, the input floats high
1073	 * and gives a (masked) interrupt as soon as the gate is closed.)
1074	 */
1075	outb(iobase + com_ier, 0);
1076	outb(iobase + com_cfcr, CFCR_8BITS);	/* dummy to avoid bus echo */
1077	failures[7] = inb(iobase + com_ier);
1078	DELAY(1000);		/* XXX */
1079	irqmap[3] = isa_irq_pending();
1080	failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
1081
1082	enable_intr();
1083
1084	irqs = irqmap[1] & ~irqmap[0];
1085	if (idev->id_irq != 0 && (idev->id_irq & irqs) == 0)
1086		printf(
1087		"sio%d: configured irq %d not in bitmap of probed irqs %#x\n",
1088		    dev->id_unit, ffs(idev->id_irq) - 1, irqs);
1089	if (bootverbose)
1090		printf("sio%d: irq maps: %#x %#x %#x %#x\n",
1091		    dev->id_unit, irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
1092
1093	result = IO_COMSIZE;
1094	for (fn = 0; fn < sizeof failures; ++fn)
1095		if (failures[fn]) {
1096			outb(iobase + com_mcr, 0);
1097			result = 0;
1098			if (bootverbose) {
1099				printf("sio%d: probe failed test(s):",
1100				    dev->id_unit);
1101				for (fn = 0; fn < sizeof failures; ++fn)
1102					if (failures[fn])
1103						printf(" %d", fn);
1104				printf("\n");
1105			}
1106			break;
1107		}
1108	return (iobase == siocniobase ? IO_COMSIZE : result);
1109}
1110
1111#ifdef COM_ESP
1112static int
1113espattach(isdp, com, esp_port)
1114	struct isa_device	*isdp;
1115	struct com_s		*com;
1116	Port_t			esp_port;
1117{
1118	u_char	dips;
1119	u_char	val;
1120
1121	/*
1122	 * Check the ESP-specific I/O port to see if we're an ESP
1123	 * card.  If not, return failure immediately.
1124	 */
1125	if ((inb(esp_port) & 0xf3) == 0) {
1126		printf(" port 0x%x is not an ESP board?\n", esp_port);
1127		return (0);
1128	}
1129
1130	/*
1131	 * We've got something that claims to be a Hayes ESP card.
1132	 * Let's hope so.
1133	 */
1134
1135	/* Get the dip-switch configuration */
1136	outb(esp_port + ESP_CMD1, ESP_GETDIPS);
1137	dips = inb(esp_port + ESP_STATUS1);
1138
1139	/*
1140	 * Bits 0,1 of dips say which COM port we are.
1141	 */
1142	if (com->iobase == likely_com_ports[dips & 0x03])
1143		printf(" : ESP");
1144	else {
1145		printf(" esp_port has com %d\n", dips & 0x03);
1146		return (0);
1147	}
1148
1149	/*
1150	 * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
1151	 */
1152	outb(esp_port + ESP_CMD1, ESP_GETTEST);
1153	val = inb(esp_port + ESP_STATUS1);	/* clear reg 1 */
1154	val = inb(esp_port + ESP_STATUS2);
1155	if ((val & 0x70) < 0x20) {
1156		printf("-old (%o)", val & 0x70);
1157		return (0);
1158	}
1159
1160	/*
1161	 * Check for ability to emulate 16550:  bit 7 == 1
1162	 */
1163	if ((dips & 0x80) == 0) {
1164		printf(" slave");
1165		return (0);
1166	}
1167
1168	/*
1169	 * Okay, we seem to be a Hayes ESP card.  Whee.
1170	 */
1171	com->esp = TRUE;
1172	com->esp_port = esp_port;
1173	return (1);
1174}
1175#endif /* COM_ESP */
1176
1177static int
1178sioattach(isdp)
1179	struct isa_device	*isdp;
1180{
1181	struct com_s	*com;
1182	dev_t		dev;
1183#ifdef COM_ESP
1184	Port_t		*espp;
1185#endif
1186	Port_t		iobase;
1187	int		s;
1188	int		unit;
1189
1190	isdp->id_ri_flags |= RI_FAST;
1191	iobase = isdp->id_iobase;
1192	unit = isdp->id_unit;
1193	com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
1194	if (com == NULL)
1195		return (0);
1196
1197	/*
1198	 * sioprobe() has initialized the device registers as follows:
1199	 *	o cfcr = CFCR_8BITS.
1200	 *	  It is most important that CFCR_DLAB is off, so that the
1201	 *	  data port is not hidden when we enable interrupts.
1202	 *	o ier = 0.
1203	 *	  Interrupts are only enabled when the line is open.
1204	 *	o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
1205	 *	  interrupt control register or the config specifies no irq.
1206	 *	  Keeping MCR_DTR and MCR_RTS off might stop the external
1207	 *	  device from sending before we are ready.
1208	 */
1209	bzero(com, sizeof *com);
1210	com->unit = unit;
1211	com->cfcr_image = CFCR_8BITS;
1212	com->dtr_wait = 3 * hz;
1213	com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
1214	com->no_irq = isdp->id_irq == 0;
1215	com->tx_fifo_size = 1;
1216	com->iptr = com->ibuf = com->ibuf1;
1217	com->ibufend = com->ibuf1 + RS_IBUFSIZE;
1218	com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
1219	com->obufs[0].l_head = com->obuf1;
1220	com->obufs[1].l_head = com->obuf2;
1221
1222	com->iobase = iobase;
1223#ifdef PC98
1224	if(pc98_set_ioport(com, iobase) == -1)
1225		if((iobase & 0x0f0) == 0xd0) {
1226			com->pc98_if_type = MC16550;
1227			com->data_port = iobase + com_data;
1228			com->int_id_port = iobase + com_iir;
1229			com->modem_ctl_port = iobase + com_mcr;
1230			com->mcr_image = inb(com->modem_ctl_port);
1231			com->line_status_port = iobase + com_lsr;
1232			com->modem_status_port = iobase + com_msr;
1233			com->intr_ctl_port = iobase + com_ier;
1234		}
1235#else /* not PC98 */
1236	com->data_port = iobase + com_data;
1237	com->int_id_port = iobase + com_iir;
1238	com->modem_ctl_port = iobase + com_mcr;
1239	com->mcr_image = inb(com->modem_ctl_port);
1240	com->line_status_port = iobase + com_lsr;
1241	com->modem_status_port = iobase + com_msr;
1242	com->intr_ctl_port = iobase + com_ier;
1243#endif
1244
1245	/*
1246	 * We don't use all the flags from <sys/ttydefaults.h> since they
1247	 * are only relevant for logins.  It's important to have echo off
1248	 * initially so that the line doesn't start blathering before the
1249	 * echo flag can be turned off.
1250	 */
1251	com->it_in.c_iflag = 0;
1252	com->it_in.c_oflag = 0;
1253	com->it_in.c_cflag = TTYDEF_CFLAG;
1254	com->it_in.c_lflag = 0;
1255	if (unit == comconsole) {
1256#ifdef PC98
1257		if(IS_8251(com->pc98_if_type))
1258			DELAY(100000);
1259#endif
1260		com->it_in.c_iflag = TTYDEF_IFLAG;
1261		com->it_in.c_oflag = TTYDEF_OFLAG;
1262		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
1263		com->it_in.c_lflag = TTYDEF_LFLAG;
1264		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
1265		com->lt_out.c_ispeed = com->lt_out.c_ospeed =
1266		com->lt_in.c_ispeed = com->lt_in.c_ospeed =
1267		com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
1268	} else
1269		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
1270	termioschars(&com->it_in);
1271	com->it_out = com->it_in;
1272
1273	/* attempt to determine UART type */
1274	printf("sio%d: type", unit);
1275
1276#ifdef DSI_SOFT_MODEM
1277	if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) {
1278	    printf(" Digicom Systems, Inc. SoftModem");
1279	goto determined_type;
1280	}
1281#endif /* DSI_SOFT_MODEM */
1282
1283#ifndef PC98
1284#ifdef COM_MULTIPORT
1285	if (!COM_ISMULTIPORT(isdp) && !COM_IIR_TXRDYBUG(isdp))
1286#else
1287	if (!COM_IIR_TXRDYBUG(isdp))
1288#endif
1289	{
1290		u_char	scr;
1291		u_char	scr1;
1292		u_char	scr2;
1293
1294		scr = inb(iobase + com_scr);
1295		outb(iobase + com_scr, 0xa5);
1296		scr1 = inb(iobase + com_scr);
1297		outb(iobase + com_scr, 0x5a);
1298		scr2 = inb(iobase + com_scr);
1299		outb(iobase + com_scr, scr);
1300		if (scr1 != 0xa5 || scr2 != 0x5a) {
1301			printf(" 8250");
1302			goto determined_type;
1303		}
1304	}
1305#endif /* !PC98 */
1306#ifdef PC98
1307	if(IS_8251(com->pc98_if_type)){
1308		com_int_TxRx_disable( com );
1309		com_cflag_and_speed_set( com, com->it_in.c_cflag,
1310						comdefaultrate );
1311		com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
1312		com_send_break_off( com );
1313		switch(com->pc98_if_type){
1314		case COM_IF_INTERNAL:
1315			printf(" 8251 (internal)");
1316			break;
1317#ifdef COM_IF_PC9861K
1318		case COM_IF_PC9861K:
1319			printf(" 8251 (PC9861K)");
1320			break;
1321#endif
1322#ifdef COM_IF_PIO9032B
1323		case COM_IF_PIO9032B:
1324			printf(" 8251 (PIO9032B)");
1325			break;
1326#endif
1327#ifdef COM_IF_B98_01
1328		case COM_IF_B98_01:
1329			printf(" 8251 (B98_01)");
1330			break;
1331#endif
1332		}
1333	} else {
1334#endif /* PC98 */
1335	outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
1336	DELAY(100);
1337	com->st16650a = 0;
1338	switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
1339	case FIFO_RX_LOW:
1340		printf(" 16450");
1341		break;
1342	case FIFO_RX_MEDL:
1343		printf(" 16450?");
1344		break;
1345	case FIFO_RX_MEDH:
1346		printf(" 16550?");
1347		break;
1348	case FIFO_RX_HIGH:
1349		if (COM_NOFIFO(isdp)) {
1350			printf(" 16550A fifo disabled");
1351		} else {
1352			com->hasfifo = TRUE;
1353			if (COM_ST16650A(isdp)) {
1354				com->st16650a = 1;
1355				com->tx_fifo_size = 32;
1356				printf(" ST16650A");
1357			} else {
1358				com->tx_fifo_size = COM_FIFOSIZE(isdp);
1359				printf(" 16550A");
1360			}
1361		}
1362#ifdef COM_ESP
1363		for (espp = likely_esp_ports; *espp != 0; espp++)
1364			if (espattach(isdp, com, *espp)) {
1365				com->tx_fifo_size = 1024;
1366				break;
1367			}
1368#endif
1369		if (!com->st16650a) {
1370			if (!com->tx_fifo_size)
1371				com->tx_fifo_size = 16;
1372			else
1373				printf(" lookalike with %d bytes FIFO",
1374				    com->tx_fifo_size);
1375		}
1376
1377		break;
1378	}
1379
1380#ifdef COM_ESP
1381	if (com->esp) {
1382		/*
1383		 * Set 16550 compatibility mode.
1384		 * We don't use the ESP_MODE_SCALE bit to increase the
1385		 * fifo trigger levels because we can't handle large
1386		 * bursts of input.
1387		 * XXX flow control should be set in comparam(), not here.
1388		 */
1389		outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1390		outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1391
1392		/* Set RTS/CTS flow control. */
1393		outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1394		outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1395		outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1396
1397		/* Set flow-control levels. */
1398		outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1399		outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1400		outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1401		outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1402		outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1403	}
1404#endif /* COM_ESP */
1405	outb(iobase + com_fifo, 0);
1406determined_type: ;
1407
1408#ifdef COM_MULTIPORT
1409	if (COM_ISMULTIPORT(isdp)) {
1410		com->multiport = TRUE;
1411		printf(" (multiport");
1412		if (unit == COM_MPMASTER(isdp))
1413			printf(" master");
1414		printf(")");
1415		com->no_irq = find_isadev(isa_devtab_tty, &siodriver,
1416					  COM_MPMASTER(isdp))->id_irq == 0;
1417	 }
1418#endif /* COM_MULTIPORT */
1419#ifdef PC98
1420	}
1421#endif
1422	if (unit == comconsole)
1423		printf(", console");
1424	if ( COM_IIR_TXRDYBUG(isdp) )
1425		printf(" with a bogus IIR_TXRDY register");
1426	printf("\n");
1427
1428	s = spltty();
1429	com_addr(unit) = com;
1430	splx(s);
1431
1432	dev = makedev(CDEV_MAJOR, 0);
1433	cdevsw_add(&dev, &sio_cdevsw, NULL);
1434#ifdef DEVFS
1435	com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
1436		unit, DV_CHR,
1437		UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
1438	com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
1439		unit | CONTROL_INIT_STATE, DV_CHR,
1440		UID_ROOT, GID_WHEEL, 0600, "ttyid%n", unit);
1441	com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
1442		unit | CONTROL_LOCK_STATE, DV_CHR,
1443		UID_ROOT, GID_WHEEL, 0600, "ttyld%n", unit);
1444	com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
1445		unit | CALLOUT_MASK, DV_CHR,
1446		UID_UUCP, GID_DIALER, 0660, "cuaa%n", unit);
1447	com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
1448		unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
1449		UID_UUCP, GID_DIALER, 0660, "cuaia%n", unit);
1450	com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
1451		unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
1452		UID_UUCP, GID_DIALER, 0660, "cuala%n", unit);
1453#endif
1454	com->id_flags = isdp->id_flags; /* Heritate id_flags for later */
1455	return (1);
1456}
1457
1458static int
1459sioopen(dev, flag, mode, p)
1460	dev_t		dev;
1461	int		flag;
1462	int		mode;
1463	struct proc	*p;
1464{
1465	struct com_s	*com;
1466	int		error;
1467	Port_t		iobase;
1468	int		mynor;
1469	int		s;
1470	struct tty	*tp;
1471	int		unit;
1472
1473	mynor = minor(dev);
1474	unit = MINOR_TO_UNIT(mynor);
1475	if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL)
1476		return (ENXIO);
1477	if (com->gone)
1478		return (ENXIO);
1479	if (mynor & CONTROL_MASK)
1480		return (0);
1481#if 0 /* XXX */
1482	tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
1483#else
1484	tp = com->tp = &sio_tty[unit];
1485#endif
1486	s = spltty();
1487	/*
1488	 * We jump to this label after all non-interrupted sleeps to pick
1489	 * up any changes of the device state.
1490	 */
1491open_top:
1492	while (com->state & CS_DTR_OFF) {
1493		error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
1494		if (com_addr(unit) == NULL)
1495			return (ENXIO);
1496		if (error != 0 || com->gone)
1497			goto out;
1498	}
1499	if (tp->t_state & TS_ISOPEN) {
1500		/*
1501		 * The device is open, so everything has been initialized.
1502		 * Handle conflicts.
1503		 */
1504		if (mynor & CALLOUT_MASK) {
1505			if (!com->active_out) {
1506				error = EBUSY;
1507				goto out;
1508			}
1509		} else {
1510			if (com->active_out) {
1511				if (flag & O_NONBLOCK) {
1512					error = EBUSY;
1513					goto out;
1514				}
1515				error =	tsleep(&com->active_out,
1516					       TTIPRI | PCATCH, "siobi", 0);
1517				if (com_addr(unit) == NULL)
1518					return (ENXIO);
1519				if (error != 0 || com->gone)
1520					goto out;
1521				goto open_top;
1522			}
1523		}
1524		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
1525			error = EBUSY;
1526			goto out;
1527		}
1528	} else {
1529		/*
1530		 * The device isn't open, so there are no conflicts.
1531		 * Initialize it.  Initialization is done twice in many
1532		 * cases: to preempt sleeping callin opens if we are
1533		 * callout, and to complete a callin open after DCD rises.
1534		 */
1535		tp->t_oproc = comstart;
1536		tp->t_param = comparam;
1537		tp->t_dev = dev;
1538		tp->t_termios = mynor & CALLOUT_MASK
1539				? com->it_out : com->it_in;
1540#ifdef PC98
1541		if(!IS_8251(com->pc98_if_type))
1542#endif
1543		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
1544		com->poll = com->no_irq;
1545		com->poll_output = com->loses_outints;
1546		++com->wopeners;
1547		error = comparam(tp, &tp->t_termios);
1548		--com->wopeners;
1549		if (error != 0)
1550			goto out;
1551#ifdef PC98
1552		if(IS_8251(com->pc98_if_type)){
1553			com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS);
1554			pc98_msrint_start(dev);
1555		}
1556#endif
1557		/*
1558		 * XXX we should goto open_top if comparam() slept.
1559		 */
1560		ttsetwater(tp);
1561		iobase = com->iobase;
1562		if (com->hasfifo) {
1563			/*
1564			 * (Re)enable and drain fifos.
1565			 *
1566			 * Certain SMC chips cause problems if the fifos
1567			 * are enabled while input is ready.  Turn off the
1568			 * fifo if necessary to clear the input.  We test
1569			 * the input ready bit after enabling the fifos
1570			 * since we've already enabled them in comparam()
1571			 * and to handle races between enabling and fresh
1572			 * input.
1573			 */
1574			while (TRUE) {
1575				outb(iobase + com_fifo,
1576				     FIFO_RCV_RST | FIFO_XMT_RST
1577				     | com->fifo_image);
1578				/*
1579				 * XXX the delays are for superstitious
1580				 * historical reasons.  It must be less than
1581				 * the character time at the maximum
1582				 * supported speed (87 usec at 115200 bps
1583				 * 8N1).  Otherwise we might loop endlessly
1584				 * if data is streaming in.  We used to use
1585				 * delays of 100.  That usually worked
1586				 * because DELAY(100) used to usually delay
1587				 * for about 85 usec instead of 100.
1588				 */
1589				DELAY(50);
1590				if (!(inb(com->line_status_port) & LSR_RXRDY))
1591					break;
1592				outb(iobase + com_fifo, 0);
1593				DELAY(50);
1594				(void) inb(com->data_port);
1595			}
1596		}
1597
1598		disable_intr();
1599#ifdef PC98
1600		if(IS_8251(com->pc98_if_type)){
1601			com_tiocm_bis(com, TIOCM_LE);
1602			com->pc98_prev_modem_status =
1603				pc98_get_modem_status(com);
1604			com_int_Rx_enable(com);
1605		} else {
1606#endif
1607		(void) inb(com->line_status_port);
1608		(void) inb(com->data_port);
1609		com->prev_modem_status = com->last_modem_status
1610		    = inb(com->modem_status_port);
1611		if (COM_IIR_TXRDYBUG(com)) {
1612			outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
1613						| IER_EMSC);
1614		} else {
1615			outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
1616						| IER_ERLS | IER_EMSC);
1617		}
1618#ifdef PC98
1619		}
1620#endif
1621		enable_intr();
1622		/*
1623		 * Handle initial DCD.  Callout devices get a fake initial
1624		 * DCD (trapdoor DCD).  If we are callout, then any sleeping
1625		 * callin opens get woken up and resume sleeping on "siobi"
1626		 * instead of "siodcd".
1627		 */
1628		/*
1629		 * XXX `mynor & CALLOUT_MASK' should be
1630		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
1631		 * TRAPDOOR_CARRIER is the default initial state for callout
1632		 * devices and SOFT_CARRIER is like CLOCAL except it hides
1633		 * the true carrier.
1634		 */
1635#ifdef PC98
1636		if ((IS_8251(com->pc98_if_type) &&
1637			(pc98_get_modem_status(com) & TIOCM_CAR)) ||
1638		    (!IS_8251(com->pc98_if_type) &&
1639			(com->prev_modem_status & MSR_DCD)) ||
1640		    mynor & CALLOUT_MASK)
1641#else
1642		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
1643#endif
1644			(*linesw[tp->t_line].l_modem)(tp, 1);
1645	}
1646	/*
1647	 * Wait for DCD if necessary.
1648	 */
1649	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1650	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1651		++com->wopeners;
1652		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
1653		if (com_addr(unit) == NULL)
1654			return (ENXIO);
1655		--com->wopeners;
1656		if (error != 0 || com->gone)
1657			goto out;
1658		goto open_top;
1659	}
1660	error =	(*linesw[tp->t_line].l_open)(dev, tp);
1661	disc_optim(tp, &tp->t_termios, com);
1662	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1663		com->active_out = TRUE;
1664	siosettimeout();
1665out:
1666	splx(s);
1667	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
1668		comhardclose(com);
1669	return (error);
1670}
1671
1672static int
1673sioclose(dev, flag, mode, p)
1674	dev_t		dev;
1675	int		flag;
1676	int		mode;
1677	struct proc	*p;
1678{
1679	struct com_s	*com;
1680	int		mynor;
1681	int		s;
1682	struct tty	*tp;
1683
1684	mynor = minor(dev);
1685	if (mynor & CONTROL_MASK)
1686		return (0);
1687	com = com_addr(MINOR_TO_UNIT(mynor));
1688	tp = com->tp;
1689	s = spltty();
1690	(*linesw[tp->t_line].l_close)(tp, flag);
1691#ifdef PC98
1692	com->modem_checking = 0;
1693#endif
1694	disc_optim(tp, &tp->t_termios, com);
1695	siostop(tp, FREAD | FWRITE);
1696	comhardclose(com);
1697	ttyclose(tp);
1698	siosettimeout();
1699	splx(s);
1700	if (com->gone) {
1701		printf("sio%d: gone\n", com->unit);
1702		s = spltty();
1703		com_addr(com->unit) = 0;
1704		bzero(tp,sizeof *tp);
1705		bzero(com,sizeof *com);
1706		free(com,M_TTYS);
1707		splx(s);
1708	}
1709	return (0);
1710}
1711
1712static void
1713comhardclose(com)
1714	struct com_s	*com;
1715{
1716	Port_t		iobase;
1717	int		s;
1718	struct tty	*tp;
1719	int		unit;
1720
1721	unit = com->unit;
1722	iobase = com->iobase;
1723	s = spltty();
1724	com->poll = FALSE;
1725	com->poll_output = FALSE;
1726	com->do_timestamp = FALSE;
1727	com->do_dcd_timestamp = FALSE;
1728#ifdef PC98
1729	if(IS_8251(com->pc98_if_type))
1730		com_send_break_off(com);
1731	else
1732#endif
1733	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1734	{
1735#ifdef PC98
1736		int tmp;
1737		if(IS_8251(com->pc98_if_type))
1738			com_int_TxRx_disable(com);
1739		else
1740#endif
1741		outb(iobase + com_ier, 0);
1742		tp = com->tp;
1743#ifdef PC98
1744		if(IS_8251(com->pc98_if_type))
1745			tmp = pc98_get_modem_status(com) & TIOCM_CAR;
1746		else
1747			tmp = com->prev_modem_status & MSR_DCD;
1748#endif
1749		if (tp->t_cflag & HUPCL
1750		    /*
1751		     * XXX we will miss any carrier drop between here and the
1752		     * next open.  Perhaps we should watch DCD even when the
1753		     * port is closed; it is not sufficient to check it at
1754		     * the next open because it might go up and down while
1755		     * we're not watching.
1756		     */
1757		    || !com->active_out
1758#ifdef PC98
1759		       && !(tmp)
1760#else
1761		       && !(com->prev_modem_status & MSR_DCD)
1762#endif
1763		       && !(com->it_in.c_cflag & CLOCAL)
1764		    || !(tp->t_state & TS_ISOPEN)) {
1765#ifdef PC98
1766			if(IS_8251(com->pc98_if_type))
1767				com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE);
1768			else
1769#endif
1770			(void)commctl(com, TIOCM_DTR, DMBIC);
1771			if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
1772				timeout(siodtrwakeup, com, com->dtr_wait);
1773				com->state |= CS_DTR_OFF;
1774			}
1775		}
1776#ifdef PC98
1777		else {
1778			if(IS_8251(com->pc98_if_type))
1779				com_tiocm_bic(com, TIOCM_LE );
1780		}
1781#endif
1782	}
1783	if (com->hasfifo) {
1784		/*
1785		 * Disable fifos so that they are off after controlled
1786		 * reboots.  Some BIOSes fail to detect 16550s when the
1787		 * fifos are enabled.
1788		 */
1789		outb(iobase + com_fifo, 0);
1790	}
1791	com->active_out = FALSE;
1792	wakeup(&com->active_out);
1793	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */
1794	splx(s);
1795}
1796
1797static int
1798sioread(dev, uio, flag)
1799	dev_t		dev;
1800	struct uio	*uio;
1801	int		flag;
1802{
1803	int		mynor;
1804	int		unit;
1805	struct tty	*tp;
1806
1807	mynor = minor(dev);
1808	if (mynor & CONTROL_MASK)
1809		return (ENODEV);
1810	unit = MINOR_TO_UNIT(mynor);
1811	if (com_addr(unit)->gone)
1812		return (ENODEV);
1813	tp = com_addr(unit)->tp;
1814	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1815}
1816
1817static int
1818siowrite(dev, uio, flag)
1819	dev_t		dev;
1820	struct uio	*uio;
1821	int		flag;
1822{
1823	int		mynor;
1824	struct tty	*tp;
1825	int		unit;
1826
1827	mynor = minor(dev);
1828	if (mynor & CONTROL_MASK)
1829		return (ENODEV);
1830
1831	unit = MINOR_TO_UNIT(mynor);
1832	if (com_addr(unit)->gone)
1833		return (ENODEV);
1834	tp = com_addr(unit)->tp;
1835	/*
1836	 * (XXX) We disallow virtual consoles if the physical console is
1837	 * a serial port.  This is in case there is a display attached that
1838	 * is not the console.  In that situation we don't need/want the X
1839	 * server taking over the console.
1840	 */
1841	if (constty != NULL && unit == comconsole)
1842		constty = NULL;
1843	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
1844}
1845
1846static void
1847siobusycheck(chan)
1848	void	*chan;
1849{
1850	struct com_s	*com;
1851	int		s;
1852
1853	com = (struct com_s *)chan;
1854
1855	/*
1856	 * Clear TS_BUSY if low-level output is complete.
1857	 * spl locking is sufficient because siointr1() does not set CS_BUSY.
1858	 * If siointr1() clears CS_BUSY after we look at it, then we'll get
1859	 * called again.  Reading the line status port outside of siointr1()
1860	 * is safe because CS_BUSY is clear so there are no output interrupts
1861	 * to lose.
1862	 */
1863	s = spltty();
1864	if (com->state & CS_BUSY)
1865		com->extra_state &= ~CSE_BUSYCHECK;	/* False alarm. */
1866#ifdef	PC98
1867	else if (IS_8251(com->pc98_if_type) &&
1868		 (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP))
1869		 == (STS8251_TxRDY | STS8251_TxEMP) ||
1870		 (inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1871		 == (LSR_TSRE | LSR_TXRDY)) {
1872#else
1873	else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1874	    == (LSR_TSRE | LSR_TXRDY)) {
1875#endif
1876		com->tp->t_state &= ~TS_BUSY;
1877		ttwwakeup(com->tp);
1878		com->extra_state &= ~CSE_BUSYCHECK;
1879	} else
1880		timeout(siobusycheck, com, hz / 100);
1881	splx(s);
1882}
1883
1884static void
1885siodtrwakeup(chan)
1886	void	*chan;
1887{
1888	struct com_s	*com;
1889
1890	com = (struct com_s *)chan;
1891	com->state &= ~CS_DTR_OFF;
1892	wakeup(&com->dtr_wait);
1893}
1894
1895void
1896siointr(unit)
1897	int	unit;
1898{
1899#ifndef COM_MULTIPORT
1900	COM_LOCK();
1901	siointr1(com_addr(unit));
1902	COM_UNLOCK();
1903#else /* COM_MULTIPORT */
1904	struct com_s    *com;
1905	bool_t		possibly_more_intrs;
1906
1907	/*
1908	 * Loop until there is no activity on any port.  This is necessary
1909	 * to get an interrupt edge more than to avoid another interrupt.
1910	 * If the IRQ signal is just an OR of the IRQ signals from several
1911	 * devices, then the edge from one may be lost because another is
1912	 * on.
1913	 */
1914	COM_LOCK();
1915	do {
1916		possibly_more_intrs = FALSE;
1917		for (unit = 0; unit < NSIOTOT; ++unit) {
1918			com = com_addr(unit);
1919			/*
1920			 * XXX COM_LOCK();
1921			 * would it work here, or be counter-productive?
1922			 */
1923#ifdef PC98
1924			if (com != NULL
1925			    && !com->gone
1926			    && IS_8251(com->pc98_if_type)){
1927				siointr1(com);
1928			} else
1929#endif /* PC98 */
1930			if (com != NULL
1931			    && !com->gone
1932			    && (inb(com->int_id_port) & IIR_IMASK)
1933			       != IIR_NOPEND) {
1934				siointr1(com);
1935				possibly_more_intrs = TRUE;
1936			}
1937			/* XXX COM_UNLOCK(); */
1938		}
1939	} while (possibly_more_intrs);
1940	COM_UNLOCK();
1941#endif /* COM_MULTIPORT */
1942}
1943
1944static void
1945siointr1(com)
1946	struct com_s	*com;
1947{
1948	u_char	line_status;
1949	u_char	modem_status;
1950	u_char	*ioptr;
1951	u_char	recv_data;
1952	u_char	int_ident;
1953	u_char	int_ctl;
1954	u_char	int_ctl_new;
1955
1956#ifdef PC98
1957	u_char	tmp=0;
1958recv_data=0;
1959#endif /* PC98 */
1960
1961	int_ctl = inb(com->intr_ctl_port);
1962	int_ctl_new = int_ctl;
1963
1964	while (!com->gone) {
1965#ifdef PC98
1966status_read:;
1967		if (IS_8251(com->pc98_if_type)) {
1968			tmp = inb(com->sts_port);
1969more_intr:
1970			line_status = 0;
1971			if (tmp & STS8251_TxRDY) line_status |= LSR_TXRDY;
1972			if (tmp & STS8251_RxRDY) line_status |= LSR_RXRDY;
1973			if (tmp & STS8251_TxEMP) line_status |= LSR_TSRE;
1974			if (tmp & STS8251_PE)    line_status |= LSR_PE;
1975			if (tmp & STS8251_OE)    line_status |= LSR_OE;
1976			if (tmp & STS8251_FE)    line_status |= LSR_FE;
1977			if (tmp & STS8251_BD_SD) line_status |= LSR_BI;
1978		} else
1979#endif /* PC98 */
1980		line_status = inb(com->line_status_port);
1981
1982		/* input event? (check first to help avoid overruns) */
1983		while (line_status & LSR_RCV_MASK) {
1984			/* break/unnattached error bits or real input? */
1985#ifdef PC98
1986			if(IS_8251(com->pc98_if_type)){
1987				recv_data = inb(com->data_port);
1988				if(tmp & 0x78){
1989					pc98_i8251_or_cmd(com,CMD8251_ER);
1990					recv_data = 0;
1991				}
1992			} else {
1993#endif /* PC98 */
1994			if (!(line_status & LSR_RXRDY))
1995				recv_data = 0;
1996			else
1997				recv_data = inb(com->data_port);
1998#ifdef PC98
1999			}
2000#endif
2001			if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
2002				/*
2003				 * Don't store BI if IGNBRK or FE/PE if IGNPAR.
2004				 * Otherwise, push the work to a higher level
2005				 * (to handle PARMRK) if we're bypassing.
2006				 * Otherwise, convert BI/FE and PE+INPCK to 0.
2007				 *
2008				 * This makes bypassing work right in the
2009				 * usual "raw" case (IGNBRK set, and IGNPAR
2010				 * and INPCK clear).
2011				 *
2012				 * Note: BI together with FE/PE means just BI.
2013				 */
2014				if (line_status & LSR_BI) {
2015#if defined(DDB) && defined(BREAK_TO_DEBUGGER)
2016					if (com->unit == comconsole) {
2017						breakpoint();
2018						goto cont;
2019					}
2020#endif
2021					if (com->tp == NULL
2022					    || com->tp->t_iflag & IGNBRK)
2023						goto cont;
2024				} else {
2025					if (com->tp == NULL
2026					    || com->tp->t_iflag & IGNPAR)
2027						goto cont;
2028				}
2029				if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
2030				    && (line_status & (LSR_BI | LSR_FE)
2031					|| com->tp->t_iflag & INPCK))
2032					recv_data = 0;
2033			}
2034			++com->bytes_in;
2035			if (com->hotchar != 0 && recv_data == com->hotchar)
2036				setsofttty();
2037			ioptr = com->iptr;
2038			if (ioptr >= com->ibufend)
2039				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
2040			else {
2041				if (com->do_timestamp)
2042					microtime(&com->timestamp);
2043				++com_events;
2044				schedsofttty();
2045#if 0 /* for testing input latency vs efficiency */
2046if (com->iptr - com->ibuf == 8)
2047	setsofttty();
2048#endif
2049				ioptr[0] = recv_data;
2050				ioptr[CE_INPUT_OFFSET] = line_status;
2051				com->iptr = ++ioptr;
2052				if (ioptr == com->ihighwater
2053				    && com->state & CS_RTS_IFLOW)
2054#ifdef PC98
2055					if(IS_8251(com->pc98_if_type))
2056						com_tiocm_bic(com, TIOCM_RTS);
2057					else
2058#endif
2059					outb(com->modem_ctl_port,
2060					     com->mcr_image &= ~MCR_RTS);
2061				if (line_status & LSR_OE)
2062					CE_RECORD(com, CE_OVERRUN);
2063			}
2064cont:
2065			/*
2066			 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
2067			 * jump from the top of the loop to here
2068			 */
2069#ifdef PC98
2070			if(IS_8251(com->pc98_if_type))
2071				goto status_read;
2072			else
2073#endif
2074			line_status = inb(com->line_status_port) & 0x7F;
2075		}
2076
2077		/* modem status change? (always check before doing output) */
2078#ifdef PC98
2079		if(!IS_8251(com->pc98_if_type)){
2080#endif
2081		modem_status = inb(com->modem_status_port);
2082		if (modem_status != com->last_modem_status) {
2083			if (com->do_dcd_timestamp
2084			    && !(com->last_modem_status & MSR_DCD)
2085			    && modem_status & MSR_DCD)
2086				microtime(&com->dcd_timestamp);
2087
2088			/*
2089			 * Schedule high level to handle DCD changes.  Note
2090			 * that we don't use the delta bits anywhere.  Some
2091			 * UARTs mess them up, and it's easy to remember the
2092			 * previous bits and calculate the delta.
2093			 */
2094			com->last_modem_status = modem_status;
2095			if (!(com->state & CS_CHECKMSR)) {
2096				com_events += LOTS_OF_EVENTS;
2097				com->state |= CS_CHECKMSR;
2098				setsofttty();
2099			}
2100
2101			/* handle CTS change immediately for crisp flow ctl */
2102			if (com->state & CS_CTS_OFLOW) {
2103				if (modem_status & MSR_CTS)
2104					com->state |= CS_ODEVREADY;
2105				else
2106					com->state &= ~CS_ODEVREADY;
2107			}
2108		}
2109#ifdef PC98
2110		}
2111#endif
2112
2113		/* output queued and everything ready? */
2114		if (line_status & LSR_TXRDY
2115		    && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2116			ioptr = com->obufq.l_head;
2117			if (com->tx_fifo_size > 1) {
2118				u_int	ocount;
2119
2120				ocount = com->obufq.l_tail - ioptr;
2121				if (ocount > com->tx_fifo_size)
2122					ocount = com->tx_fifo_size;
2123				com->bytes_out += ocount;
2124				do
2125					outb(com->data_port, *ioptr++);
2126				while (--ocount != 0);
2127			} else {
2128				outb(com->data_port, *ioptr++);
2129				++com->bytes_out;
2130			}
2131#ifdef PC98
2132			if(IS_8251(com->pc98_if_type))
2133				if ( !(pc98_check_i8251_interrupt(com) & IEN_TxFLAG) )
2134					com_int_Tx_enable(com);
2135#endif
2136			com->obufq.l_head = ioptr;
2137			if (COM_IIR_TXRDYBUG(com)) {
2138				int_ctl_new = int_ctl | IER_ETXRDY;
2139			}
2140			if (ioptr >= com->obufq.l_tail) {
2141				struct lbq	*qp;
2142
2143				qp = com->obufq.l_next;
2144				qp->l_queued = FALSE;
2145				qp = qp->l_next;
2146				if (qp != NULL) {
2147					com->obufq.l_head = qp->l_head;
2148					com->obufq.l_tail = qp->l_tail;
2149					com->obufq.l_next = qp;
2150				} else {
2151					/* output just completed */
2152					if ( COM_IIR_TXRDYBUG(com) ) {
2153						int_ctl_new = int_ctl & ~IER_ETXRDY;
2154					}
2155					com->state &= ~CS_BUSY;
2156#if defined(PC98)
2157					if(IS_8251(com->pc98_if_type))
2158						if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2159							com_int_Tx_disable(com);
2160#endif
2161				}
2162				if (!(com->state & CS_ODONE)) {
2163					com_events += LOTS_OF_EVENTS;
2164					com->state |= CS_ODONE;
2165					setsofttty();	/* handle at high level ASAP */
2166				}
2167			}
2168			if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) {
2169				outb(com->intr_ctl_port, int_ctl_new);
2170			}
2171		}
2172#ifdef PC98
2173		else if (line_status & LSR_TXRDY) {
2174			if(IS_8251(com->pc98_if_type))
2175				if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
2176					com_int_Tx_disable(com);
2177		}
2178		if(IS_8251(com->pc98_if_type))
2179			if ((tmp = inb(com->sts_port)) & STS8251_RxRDY)
2180				goto more_intr;
2181#endif
2182
2183		/* finished? */
2184#ifndef COM_MULTIPORT
2185#ifdef PC98
2186		if(IS_8251(com->pc98_if_type))
2187			return;
2188#endif
2189		if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
2190#endif /* COM_MULTIPORT */
2191			return;
2192	}
2193}
2194
2195static int
2196sioioctl(dev, cmd, data, flag, p)
2197	dev_t		dev;
2198	u_long		cmd;
2199	caddr_t		data;
2200	int		flag;
2201	struct proc	*p;
2202{
2203	struct com_s	*com;
2204	int		error;
2205	Port_t		iobase;
2206	int		mynor;
2207	int		s;
2208	struct tty	*tp;
2209#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2210	int		oldcmd;
2211	struct termios	term;
2212#endif
2213
2214	mynor = minor(dev);
2215	com = com_addr(MINOR_TO_UNIT(mynor));
2216	if (com->gone)
2217		return (ENODEV);
2218	iobase = com->iobase;
2219	if (mynor & CONTROL_MASK) {
2220		struct termios	*ct;
2221
2222		switch (mynor & CONTROL_MASK) {
2223		case CONTROL_INIT_STATE:
2224			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
2225			break;
2226		case CONTROL_LOCK_STATE:
2227			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
2228			break;
2229		default:
2230			return (ENODEV);	/* /dev/nodev */
2231		}
2232		switch (cmd) {
2233		case TIOCSETA:
2234			error = suser(p->p_ucred, &p->p_acflag);
2235			if (error != 0)
2236				return (error);
2237			*ct = *(struct termios *)data;
2238			return (0);
2239		case TIOCGETA:
2240			*(struct termios *)data = *ct;
2241			return (0);
2242		case TIOCGETD:
2243			*(int *)data = TTYDISC;
2244			return (0);
2245		case TIOCGWINSZ:
2246			bzero(data, sizeof(struct winsize));
2247			return (0);
2248#ifdef DSI_SOFT_MODEM
2249		/*
2250		 * Download micro-code to Digicom modem.
2251		 */
2252		case TIOCDSIMICROCODE:
2253			{
2254			u_long l;
2255			u_char *p,*pi;
2256
2257			pi = (u_char*)(*(caddr_t*)data);
2258			error = copyin(pi,&l,sizeof l);
2259			if(error)
2260				{return error;};
2261			pi += sizeof l;
2262
2263			p = malloc(l,M_TEMP,M_NOWAIT);
2264			if(!p)
2265				{return ENOBUFS;}
2266			error = copyin(pi,p,l);
2267			if(error)
2268				{free(p,M_TEMP); return error;};
2269			if(error = LoadSoftModem(
2270			    MINOR_TO_UNIT(mynor),iobase,l,p))
2271				{free(p,M_TEMP); return error;}
2272			free(p,M_TEMP);
2273			return(0);
2274			}
2275#endif /* DSI_SOFT_MODEM */
2276		default:
2277			return (ENOTTY);
2278		}
2279	}
2280	tp = com->tp;
2281#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2282	term = tp->t_termios;
2283	oldcmd = cmd;
2284	error = ttsetcompat(tp, &cmd, data, &term);
2285	if (error != 0)
2286		return (error);
2287	if (cmd != oldcmd)
2288		data = (caddr_t)&term;
2289#endif
2290	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
2291		int	cc;
2292		struct termios *dt = (struct termios *)data;
2293		struct termios *lt = mynor & CALLOUT_MASK
2294				     ? &com->lt_out : &com->lt_in;
2295
2296		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
2297			      | (dt->c_iflag & ~lt->c_iflag);
2298		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
2299			      | (dt->c_oflag & ~lt->c_oflag);
2300		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
2301			      | (dt->c_cflag & ~lt->c_cflag);
2302		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
2303			      | (dt->c_lflag & ~lt->c_lflag);
2304		for (cc = 0; cc < NCCS; ++cc)
2305			if (lt->c_cc[cc] != 0)
2306				dt->c_cc[cc] = tp->t_cc[cc];
2307		if (lt->c_ispeed != 0)
2308			dt->c_ispeed = tp->t_ispeed;
2309		if (lt->c_ospeed != 0)
2310			dt->c_ospeed = tp->t_ospeed;
2311	}
2312	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2313	if (error != ENOIOCTL)
2314		return (error);
2315	s = spltty();
2316	error = ttioctl(tp, cmd, data, flag);
2317	disc_optim(tp, &tp->t_termios, com);
2318	if (error != ENOIOCTL) {
2319		splx(s);
2320		return (error);
2321	}
2322#ifdef PC98
2323	if(IS_8251(com->pc98_if_type)){
2324	    switch (cmd) {
2325	    case TIOCSBRK:
2326		com_send_break_on( com );
2327		break;
2328	    case TIOCCBRK:
2329		com_send_break_off( com );
2330		break;
2331	    case TIOCSDTR:
2332		com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS );
2333		break;
2334	    case TIOCCDTR:
2335		com_tiocm_bic(com, TIOCM_DTR);
2336		break;
2337	/*
2338	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
2339	 * changes get undone on the next call to comparam().
2340	 */
2341	    case TIOCMSET:
2342		com_tiocm_set( com, *(int *)data );
2343		break;
2344	    case TIOCMBIS:
2345		com_tiocm_bis( com, *(int *)data );
2346		break;
2347	    case TIOCMBIC:
2348		com_tiocm_bic( com, *(int *)data );
2349		break;
2350	    case TIOCMGET:
2351		*(int *)data = com_tiocm_get(com);
2352		break;
2353	    case TIOCMSDTRWAIT:
2354		/* must be root since the wait applies to following logins */
2355		error = suser(p->p_ucred, &p->p_acflag);
2356		if (error != 0) {
2357			splx(s);
2358			return (error);
2359		}
2360		com->dtr_wait = *(int *)data * hz / 100;
2361		break;
2362	    case TIOCMGDTRWAIT:
2363		*(int *)data = com->dtr_wait * 100 / hz;
2364		break;
2365	    case TIOCTIMESTAMP:
2366		com->do_timestamp = TRUE;
2367		*(struct timeval *)data = com->timestamp;
2368		break;
2369	    case TIOCDCDTIMESTAMP:
2370		com->do_dcd_timestamp = TRUE;
2371		*(struct timeval *)data = com->dcd_timestamp;
2372		break;
2373	    default:
2374		splx(s);
2375		return (ENOTTY);
2376	    }
2377	} else {
2378#endif
2379	switch (cmd) {
2380	case TIOCSBRK:
2381		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
2382		break;
2383	case TIOCCBRK:
2384		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
2385		break;
2386	case TIOCSDTR:
2387		(void)commctl(com, TIOCM_DTR, DMBIS);
2388		break;
2389	case TIOCCDTR:
2390		(void)commctl(com, TIOCM_DTR, DMBIC);
2391		break;
2392	/*
2393	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
2394	 * changes get undone on the next call to comparam().
2395	 */
2396	case TIOCMSET:
2397		(void)commctl(com, *(int *)data, DMSET);
2398		break;
2399	case TIOCMBIS:
2400		(void)commctl(com, *(int *)data, DMBIS);
2401		break;
2402	case TIOCMBIC:
2403		(void)commctl(com, *(int *)data, DMBIC);
2404		break;
2405	case TIOCMGET:
2406		*(int *)data = commctl(com, 0, DMGET);
2407		break;
2408	case TIOCMSDTRWAIT:
2409		/* must be root since the wait applies to following logins */
2410		error = suser(p->p_ucred, &p->p_acflag);
2411		if (error != 0) {
2412			splx(s);
2413			return (error);
2414		}
2415		com->dtr_wait = *(int *)data * hz / 100;
2416		break;
2417	case TIOCMGDTRWAIT:
2418		*(int *)data = com->dtr_wait * 100 / hz;
2419		break;
2420	case TIOCTIMESTAMP:
2421		com->do_timestamp = TRUE;
2422		*(struct timeval *)data = com->timestamp;
2423		break;
2424	case TIOCDCDTIMESTAMP:
2425		com->do_dcd_timestamp = TRUE;
2426		*(struct timeval *)data = com->dcd_timestamp;
2427		break;
2428	default:
2429		splx(s);
2430		return (ENOTTY);
2431	}
2432#ifdef PC98
2433	}
2434#endif
2435	splx(s);
2436	return (0);
2437}
2438
2439void
2440siopoll()
2441{
2442	int		unit;
2443
2444	if (com_events == 0)
2445		return;
2446repeat:
2447	for (unit = 0; unit < NSIOTOT; ++unit) {
2448		u_char		*buf;
2449		struct com_s	*com;
2450		u_char		*ibuf;
2451		int		incc;
2452		struct tty	*tp;
2453#ifdef PC98
2454		int		tmp;
2455#endif
2456
2457		com = com_addr(unit);
2458		if (com == NULL)
2459			continue;
2460		if (com->gone)
2461			continue;
2462		tp = com->tp;
2463		if (tp == NULL) {
2464			/*
2465			 * XXX forget any events related to closed devices
2466			 * (actually never opened devices) so that we don't
2467			 * loop.
2468			 */
2469			disable_intr();
2470			incc = com->iptr - com->ibuf;
2471			com->iptr = com->ibuf;
2472			if (com->state & CS_CHECKMSR) {
2473				incc += LOTS_OF_EVENTS;
2474				com->state &= ~CS_CHECKMSR;
2475			}
2476			com_events -= incc;
2477			enable_intr();
2478			if (incc != 0)
2479				log(LOG_DEBUG,
2480				    "sio%d: %d events for device with no tp\n",
2481				    unit, incc);
2482			continue;
2483		}
2484
2485		/* switch the role of the low-level input buffers */
2486		if (com->iptr == (ibuf = com->ibuf)) {
2487			buf = NULL;     /* not used, but compiler can't tell */
2488			incc = 0;
2489		} else {
2490			buf = ibuf;
2491			disable_intr();
2492			incc = com->iptr - buf;
2493			com_events -= incc;
2494			if (ibuf == com->ibuf1)
2495				ibuf = com->ibuf2;
2496			else
2497				ibuf = com->ibuf1;
2498			com->ibufend = ibuf + RS_IBUFSIZE;
2499			com->ihighwater = ibuf + RS_IHIGHWATER;
2500			com->iptr = ibuf;
2501
2502			/*
2503			 * There is now room for another low-level buffer full
2504			 * of input, so enable RTS if it is now disabled and
2505			 * there is room in the high-level buffer.
2506			 */
2507#ifdef PC98
2508			if(IS_8251(com->pc98_if_type))
2509				tmp = com_tiocm_get(com) & TIOCM_RTS;
2510			else
2511				tmp = com->mcr_image & MCR_RTS;
2512#endif
2513			if ((com->state & CS_RTS_IFLOW)
2514#ifdef PC98
2515			    && !(tmp)
2516#else
2517			    && !(com->mcr_image & MCR_RTS)
2518#endif
2519			    && !(tp->t_state & TS_TBLOCK))
2520#ifdef PC98
2521				if(IS_8251(com->pc98_if_type))
2522					com_tiocm_bis(com, TIOCM_RTS);
2523				else
2524#endif
2525				outb(com->modem_ctl_port,
2526				     com->mcr_image |= MCR_RTS);
2527			enable_intr();
2528			com->ibuf = ibuf;
2529		}
2530
2531		if (com->state & CS_CHECKMSR) {
2532			u_char	delta_modem_status;
2533
2534#ifdef PC98
2535			if(!IS_8251(com->pc98_if_type)){
2536#endif
2537			disable_intr();
2538			delta_modem_status = com->last_modem_status
2539					     ^ com->prev_modem_status;
2540			com->prev_modem_status = com->last_modem_status;
2541			com_events -= LOTS_OF_EVENTS;
2542			com->state &= ~CS_CHECKMSR;
2543			enable_intr();
2544			if (delta_modem_status & MSR_DCD)
2545				(*linesw[tp->t_line].l_modem)
2546					(tp, com->prev_modem_status & MSR_DCD);
2547#ifdef PC98
2548			}
2549#endif
2550		}
2551		if (com->state & CS_ODONE) {
2552			disable_intr();
2553			com_events -= LOTS_OF_EVENTS;
2554			com->state &= ~CS_ODONE;
2555			enable_intr();
2556			if (!(com->state & CS_BUSY)
2557			    && !(com->extra_state & CSE_BUSYCHECK)) {
2558				timeout(siobusycheck, com, hz / 100);
2559				com->extra_state |= CSE_BUSYCHECK;
2560			}
2561			(*linesw[tp->t_line].l_start)(tp);
2562		}
2563		if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
2564		    !(tp->t_cflag & CREAD))
2565			continue;
2566		/*
2567		 * Avoid the grotesquely inefficient lineswitch routine
2568		 * (ttyinput) in "raw" mode.  It usually takes about 450
2569		 * instructions (that's without canonical processing or echo!).
2570		 * slinput is reasonably fast (usually 40 instructions plus
2571		 * call overhead).
2572		 */
2573		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
2574			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
2575			    && (com->state & CS_RTS_IFLOW
2576				|| tp->t_iflag & IXOFF)
2577			    && !(tp->t_state & TS_TBLOCK))
2578				ttyblock(tp);
2579			tk_nin += incc;
2580			tk_rawcc += incc;
2581			tp->t_rawcc += incc;
2582			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
2583				+= b_to_q((char *)buf, incc, &tp->t_rawq);
2584			ttwakeup(tp);
2585			if (tp->t_state & TS_TTSTOP
2586			    && (tp->t_iflag & IXANY
2587				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
2588				tp->t_state &= ~TS_TTSTOP;
2589				tp->t_lflag &= ~FLUSHO;
2590				comstart(tp);
2591			}
2592		} else {
2593			do {
2594				u_char	line_status;
2595				int	recv_data;
2596
2597				line_status = (u_char) buf[CE_INPUT_OFFSET];
2598				recv_data = (u_char) *buf++;
2599				if (line_status
2600				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
2601					if (line_status & LSR_BI)
2602						recv_data |= TTY_BI;
2603					if (line_status & LSR_FE)
2604						recv_data |= TTY_FE;
2605					if (line_status & LSR_OE)
2606						recv_data |= TTY_OE;
2607					if (line_status & LSR_PE)
2608						recv_data |= TTY_PE;
2609				}
2610				(*linesw[tp->t_line].l_rint)(recv_data, tp);
2611			} while (--incc > 0);
2612		}
2613		if (com_events == 0)
2614			break;
2615	}
2616	if (com_events >= LOTS_OF_EVENTS)
2617		goto repeat;
2618}
2619
2620static int
2621comparam(tp, t)
2622	struct tty	*tp;
2623	struct termios	*t;
2624{
2625	u_int		cfcr;
2626	int		cflag;
2627	struct com_s	*com;
2628	int		divisor;
2629	u_char		dlbh;
2630	u_char		dlbl;
2631	int		error;
2632	Port_t		iobase;
2633	int		s;
2634	int		unit;
2635	int		txtimeout;
2636#ifdef PC98
2637	Port_t		tmp_port;
2638	int		tmp_flg;
2639#endif
2640
2641#ifdef PC98
2642	cfcr = 0;
2643	unit = DEV_TO_UNIT(tp->t_dev);
2644	com = com_addr(unit);
2645	iobase = com->iobase;
2646	if(IS_8251(com->pc98_if_type)) {
2647		divisor = pc98_ttspeedtab(com, t->c_ospeed);
2648	} else
2649#endif
2650	/* do historical conversions */
2651	if (t->c_ispeed == 0)
2652		t->c_ispeed = t->c_ospeed;
2653
2654	/* check requested parameters */
2655	divisor = ttspeedtab(t->c_ospeed, comspeedtab);
2656	if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
2657		return (EINVAL);
2658
2659	/* parameters are OK, convert them to the com struct and the device */
2660#ifndef PC98
2661	unit = DEV_TO_UNIT(tp->t_dev);
2662	com = com_addr(unit);
2663	iobase = com->iobase;
2664#endif
2665	s = spltty();
2666#ifdef PC98
2667	if(IS_8251(com->pc98_if_type)){
2668		if(divisor == 0)
2669			com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
2670		else
2671			com_tiocm_bis( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
2672	} else {
2673#endif
2674	if (divisor == 0)
2675		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
2676	else
2677		(void)commctl(com, TIOCM_DTR, DMBIS);
2678#ifdef PC98
2679	}
2680#endif
2681	cflag = t->c_cflag;
2682#ifdef PC98
2683	if(!IS_8251(com->pc98_if_type)){
2684#endif
2685	switch (cflag & CSIZE) {
2686	case CS5:
2687		cfcr = CFCR_5BITS;
2688		break;
2689	case CS6:
2690		cfcr = CFCR_6BITS;
2691		break;
2692	case CS7:
2693		cfcr = CFCR_7BITS;
2694		break;
2695	default:
2696		cfcr = CFCR_8BITS;
2697		break;
2698	}
2699	if (cflag & PARENB) {
2700		cfcr |= CFCR_PENAB;
2701		if (!(cflag & PARODD))
2702			cfcr |= CFCR_PEVEN;
2703	}
2704	if (cflag & CSTOPB)
2705		cfcr |= CFCR_STOPB;
2706
2707	if (com->hasfifo && divisor != 0) {
2708		/*
2709		 * Use a fifo trigger level low enough so that the input
2710		 * latency from the fifo is less than about 16 msec and
2711		 * the total latency is less than about 30 msec.  These
2712		 * latencies are reasonable for humans.  Serial comms
2713		 * protocols shouldn't expect anything better since modem
2714		 * latencies are larger.
2715		 */
2716		com->fifo_image = t->c_ospeed <= 4800
2717				  ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
2718#ifdef COM_ESP
2719		/*
2720		 * The Hayes ESP card needs the fifo DMA mode bit set
2721		 * in compatibility mode.  If not, it will interrupt
2722		 * for each character received.
2723		 */
2724		if (com->esp)
2725			com->fifo_image |= FIFO_DMA_MODE;
2726#endif
2727		outb(iobase + com_fifo, com->fifo_image);
2728	}
2729
2730	/*
2731	 * Some UARTs lock up if the divisor latch registers are selected
2732	 * while the UART is doing output (they refuse to transmit anything
2733	 * more until given a hard reset).  Fix this by stopping filling
2734	 * the device buffers and waiting for them to drain.  Reading the
2735	 * line status port outside of siointr1() might lose some receiver
2736	 * error bits, but that is acceptable here.
2737	 */
2738#ifdef PC98
2739	}
2740#endif
2741	disable_intr();
2742retry:
2743	com->state &= ~CS_TTGO;
2744	txtimeout = tp->t_timeout;
2745	enable_intr();
2746#ifdef PC98
2747	if(IS_8251(com->pc98_if_type)){
2748		tmp_port = com->sts_port;
2749		tmp_flg = (STS8251_TxRDY|STS8251_TxEMP);
2750	} else {
2751		tmp_port = com->line_status_port;
2752		tmp_flg = (LSR_TSRE|LSR_TXRDY);
2753	}
2754	while ((inb(tmp_port) & tmp_flg) != tmp_flg) {
2755#else
2756	while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2757	       != (LSR_TSRE | LSR_TXRDY)) {
2758#endif
2759		tp->t_state |= TS_SO_OCOMPLETE;
2760		error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
2761				 "siotx", hz / 100);
2762		if (   txtimeout != 0
2763		    && (!error || error	== EAGAIN)
2764		    && (txtimeout -= hz	/ 100) <= 0
2765		   )
2766			error = EIO;
2767		if (com->gone)
2768			error = ENODEV;
2769		if (error != 0 && error != EAGAIN) {
2770			if (!(tp->t_state & TS_TTSTOP)) {
2771				disable_intr();
2772				com->state |= CS_TTGO;
2773				enable_intr();
2774			}
2775			splx(s);
2776			return (error);
2777		}
2778	}
2779
2780	disable_intr();		/* very important while com_data is hidden */
2781
2782	/*
2783	 * XXX - clearing CS_TTGO is not sufficient to stop further output,
2784	 * because siopoll() calls comstart() which usually sets it again
2785	 * because TS_TTSTOP is clear.  Setting TS_TTSTOP would not be
2786	 * sufficient, for similar reasons.
2787	 */
2788#ifdef PC98
2789	if ((inb(tmp_port) & tmp_flg) != tmp_flg)
2790#else
2791	if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2792	    != (LSR_TSRE | LSR_TXRDY))
2793#endif
2794		goto retry;
2795
2796#ifdef PC98
2797	if(!IS_8251(com->pc98_if_type)){
2798#endif
2799	if (divisor != 0) {
2800		outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
2801		/*
2802		 * Only set the divisor registers if they would change,
2803		 * since on some 16550 incompatibles (UMC8669F), setting
2804		 * them while input is arriving them loses sync until
2805		 * data stops arriving.
2806		 */
2807		dlbl = divisor & 0xFF;
2808		if (inb(iobase + com_dlbl) != dlbl)
2809			outb(iobase + com_dlbl, dlbl);
2810		dlbh = (u_int) divisor >> 8;
2811		if (inb(iobase + com_dlbh) != dlbh)
2812			outb(iobase + com_dlbh, dlbh);
2813	}
2814
2815
2816	outb(iobase + com_cfcr, com->cfcr_image = cfcr);
2817
2818#ifdef PC98
2819	} else
2820		com_cflag_and_speed_set(com, cflag, t->c_ospeed);
2821#endif
2822	if (!(tp->t_state & TS_TTSTOP))
2823		com->state |= CS_TTGO;
2824
2825	if (cflag & CRTS_IFLOW) {
2826		if (com->st16650a) {
2827			outb(iobase + com_cfcr, 0xbf);
2828			outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40);
2829		}
2830		com->state |= CS_RTS_IFLOW;
2831		/*
2832		 * If CS_RTS_IFLOW just changed from off to on, the change
2833		 * needs to be propagated to MCR_RTS.  This isn't urgent,
2834		 * so do it later by calling comstart() instead of repeating
2835		 * a lot of code from comstart() here.
2836		 */
2837	} else if (com->state & CS_RTS_IFLOW) {
2838		com->state &= ~CS_RTS_IFLOW;
2839		/*
2840		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
2841		 * on here, since comstart() won't do it later.
2842		 */
2843#ifdef PC98
2844		if(IS_8251(com->pc98_if_type))
2845			com_tiocm_bis(com, TIOCM_RTS);
2846		else
2847#endif
2848		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2849		if (com->st16650a) {
2850			outb(iobase + com_cfcr, 0xbf);
2851			outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40);
2852		}
2853	}
2854
2855
2856	/*
2857	 * Set up state to handle output flow control.
2858	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2859	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2860	 */
2861	com->state |= CS_ODEVREADY;
2862	com->state &= ~CS_CTS_OFLOW;
2863	if (cflag & CCTS_OFLOW) {
2864		com->state |= CS_CTS_OFLOW;
2865#ifdef PC98
2866		if(IS_8251(com->pc98_if_type)){
2867			if (!(pc98_get_modem_status(com) & TIOCM_CTS))
2868				com->state &= ~CS_ODEVREADY;
2869		} else {
2870#endif
2871		if (!(com->last_modem_status & MSR_CTS))
2872			com->state &= ~CS_ODEVREADY;
2873		if (com->st16650a) {
2874			outb(iobase + com_cfcr, 0xbf);
2875			outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80);
2876		}
2877#ifdef PC98
2878		}
2879#endif
2880	} else {
2881		if (com->st16650a) {
2882			outb(iobase + com_cfcr, 0xbf);
2883			outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80);
2884		}
2885	}
2886
2887
2888	outb(iobase + com_cfcr, com->cfcr_image);
2889
2890
2891	/* XXX shouldn't call functions while intrs are disabled. */
2892	disc_optim(tp, t, com);
2893	/*
2894	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
2895	 * unconditionally, but that defeated the careful discarding of
2896	 * stale input in sioopen().
2897	 */
2898	if (com->state >= (CS_BUSY | CS_TTGO))
2899		siointr1(com);
2900
2901	enable_intr();
2902	splx(s);
2903	comstart(tp);
2904	return (0);
2905}
2906
2907static void
2908comstart(tp)
2909	struct tty	*tp;
2910{
2911	struct com_s	*com;
2912	int		s;
2913	int		unit;
2914#ifdef PC98
2915	int		tmp;
2916#endif
2917
2918	unit = DEV_TO_UNIT(tp->t_dev);
2919	com = com_addr(unit);
2920	s = spltty();
2921	disable_intr();
2922	if (tp->t_state & TS_TTSTOP)
2923		com->state &= ~CS_TTGO;
2924	else
2925		com->state |= CS_TTGO;
2926	if (tp->t_state & TS_TBLOCK) {
2927#ifdef PC98
2928		if(IS_8251(com->pc98_if_type))
2929			tmp = com_tiocm_get(com) & TIOCM_RTS;
2930		else
2931			tmp = com->mcr_image & MCR_RTS;
2932		if (tmp && (com->state & CS_RTS_IFLOW))
2933#else
2934		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2935#endif
2936#ifdef PC98
2937			if(IS_8251(com->pc98_if_type))
2938				com_tiocm_bic(com, TIOCM_RTS);
2939			else
2940#endif
2941			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2942	} else {
2943#ifdef PC98
2944		if(IS_8251(com->pc98_if_type))
2945			tmp = com_tiocm_get(com) & TIOCM_RTS;
2946		else
2947			tmp = com->mcr_image & MCR_RTS;
2948		if (!(tmp) && com->iptr < com->ihighwater
2949			&& com->state & CS_RTS_IFLOW)
2950#else
2951		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2952		    && com->state & CS_RTS_IFLOW)
2953#endif
2954#ifdef PC98
2955			if(IS_8251(com->pc98_if_type))
2956				com_tiocm_bis(com, TIOCM_RTS);
2957			else
2958#endif
2959			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2960	}
2961	enable_intr();
2962	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2963		ttwwakeup(tp);
2964#ifdef PC98
2965/*		if(IS_8251(com->pc98_if_type))
2966			com_int_Tx_enable(com); */
2967#endif
2968		splx(s);
2969		return;
2970	}
2971	if (tp->t_outq.c_cc != 0) {
2972		struct lbq	*qp;
2973		struct lbq	*next;
2974
2975		if (!com->obufs[0].l_queued) {
2976			com->obufs[0].l_tail
2977			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2978						  sizeof com->obuf1);
2979			com->obufs[0].l_next = NULL;
2980			com->obufs[0].l_queued = TRUE;
2981			disable_intr();
2982			if (com->state & CS_BUSY) {
2983				qp = com->obufq.l_next;
2984				while ((next = qp->l_next) != NULL)
2985					qp = next;
2986				qp->l_next = &com->obufs[0];
2987			} else {
2988				com->obufq.l_head = com->obufs[0].l_head;
2989				com->obufq.l_tail = com->obufs[0].l_tail;
2990				com->obufq.l_next = &com->obufs[0];
2991				com->state |= CS_BUSY;
2992			}
2993			enable_intr();
2994		}
2995		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2996			com->obufs[1].l_tail
2997			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2998						  sizeof com->obuf2);
2999			com->obufs[1].l_next = NULL;
3000			com->obufs[1].l_queued = TRUE;
3001			disable_intr();
3002			if (com->state & CS_BUSY) {
3003				qp = com->obufq.l_next;
3004				while ((next = qp->l_next) != NULL)
3005					qp = next;
3006				qp->l_next = &com->obufs[1];
3007			} else {
3008				com->obufq.l_head = com->obufs[1].l_head;
3009				com->obufq.l_tail = com->obufs[1].l_tail;
3010				com->obufq.l_next = &com->obufs[1];
3011				com->state |= CS_BUSY;
3012			}
3013			enable_intr();
3014		}
3015		tp->t_state |= TS_BUSY;
3016	}
3017	disable_intr();
3018	if (com->state >= (CS_BUSY | CS_TTGO))
3019		siointr1(com);	/* fake interrupt to start output */
3020	enable_intr();
3021#ifdef PC98
3022/*		if(IS_8251(com->pc98_if_type))
3023			com_int_Tx_enable(com); */
3024#endif
3025	ttwwakeup(tp);
3026	splx(s);
3027}
3028
3029static void
3030siostop(tp, rw)
3031	struct tty	*tp;
3032	int		rw;
3033{
3034	struct com_s	*com;
3035
3036	com = com_addr(DEV_TO_UNIT(tp->t_dev));
3037	if (com->gone)
3038		return;
3039	disable_intr();
3040	if (rw & FWRITE) {
3041		if (com->hasfifo)
3042#ifdef COM_ESP
3043		    /* XXX avoid h/w bug. */
3044		    if (!com->esp)
3045#endif
3046			/* XXX does this flush everything? */
3047			outb(com->iobase + com_fifo,
3048			     FIFO_XMT_RST | com->fifo_image);
3049		com->obufs[0].l_queued = FALSE;
3050		com->obufs[1].l_queued = FALSE;
3051		if (com->state & CS_ODONE)
3052			com_events -= LOTS_OF_EVENTS;
3053		com->state &= ~(CS_ODONE | CS_BUSY);
3054		com->tp->t_state &= ~TS_BUSY;
3055	}
3056	if (rw & FREAD) {
3057		if (com->hasfifo)
3058#ifdef COM_ESP
3059		    /* XXX avoid h/w bug. */
3060		    if (!com->esp)
3061#endif
3062			/* XXX does this flush everything? */
3063			outb(com->iobase + com_fifo,
3064			     FIFO_RCV_RST | com->fifo_image);
3065		com_events -= (com->iptr - com->ibuf);
3066		com->iptr = com->ibuf;
3067	}
3068	enable_intr();
3069	comstart(tp);
3070}
3071
3072static struct tty *
3073siodevtotty(dev)
3074	dev_t	dev;
3075{
3076	int	mynor;
3077	int	unit;
3078
3079	mynor = minor(dev);
3080	if (mynor & CONTROL_MASK)
3081		return (NULL);
3082	unit = MINOR_TO_UNIT(mynor);
3083	if ((u_int) unit >= NSIOTOT)
3084		return (NULL);
3085	return (&sio_tty[unit]);
3086}
3087
3088static int
3089commctl(com, bits, how)
3090	struct com_s	*com;
3091	int		bits;
3092	int		how;
3093{
3094	int	mcr;
3095	int	msr;
3096
3097	if (how == DMGET) {
3098		bits = TIOCM_LE;	/* XXX - always enabled while open */
3099		mcr = com->mcr_image;
3100		if (mcr & MCR_DTR)
3101			bits |= TIOCM_DTR;
3102		if (mcr & MCR_RTS)
3103			bits |= TIOCM_RTS;
3104		msr = com->prev_modem_status;
3105		if (msr & MSR_CTS)
3106			bits |= TIOCM_CTS;
3107		if (msr & MSR_DCD)
3108			bits |= TIOCM_CD;
3109		if (msr & MSR_DSR)
3110			bits |= TIOCM_DSR;
3111		/*
3112		 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
3113		 * more volatile by reading the modem status a lot.  Perhaps
3114		 * we should latch both bits until the status is read here.
3115		 */
3116		if (msr & (MSR_RI | MSR_TERI))
3117			bits |= TIOCM_RI;
3118		return (bits);
3119	}
3120	mcr = 0;
3121	if (bits & TIOCM_DTR)
3122		mcr |= MCR_DTR;
3123	if (bits & TIOCM_RTS)
3124		mcr |= MCR_RTS;
3125	if (com->gone)
3126		return(0);
3127	disable_intr();
3128	switch (how) {
3129	case DMSET:
3130		outb(com->modem_ctl_port,
3131		     com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
3132		break;
3133	case DMBIS:
3134		outb(com->modem_ctl_port, com->mcr_image |= mcr);
3135		break;
3136	case DMBIC:
3137		outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
3138		break;
3139	}
3140	enable_intr();
3141	return (0);
3142}
3143
3144static void
3145siosettimeout()
3146{
3147	struct com_s	*com;
3148	bool_t		someopen;
3149	int		unit;
3150
3151	/*
3152	 * Set our timeout period to 1 second if no polled devices are open.
3153	 * Otherwise set it to max(1/200, 1/hz).
3154	 * Enable timeouts iff some device is open.
3155	 */
3156	untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
3157	sio_timeout = hz;
3158	someopen = FALSE;
3159	for (unit = 0; unit < NSIOTOT; ++unit) {
3160		com = com_addr(unit);
3161		if (com != NULL && com->tp != NULL
3162		    && com->tp->t_state & TS_ISOPEN && !com->gone) {
3163			someopen = TRUE;
3164			if (com->poll || com->poll_output) {
3165				sio_timeout = hz > 200 ? hz / 200 : 1;
3166				break;
3167			}
3168		}
3169	}
3170	if (someopen) {
3171		sio_timeouts_until_log = hz / sio_timeout;
3172		sio_timeout_handle = timeout(comwakeup, (void *)NULL,
3173					     sio_timeout);
3174	} else {
3175		/* Flush error messages, if any. */
3176		sio_timeouts_until_log = 1;
3177		comwakeup((void *)NULL);
3178		untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
3179	}
3180}
3181
3182static void
3183comwakeup(chan)
3184	void	*chan;
3185{
3186	struct com_s	*com;
3187	int		unit;
3188
3189	sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
3190
3191	/*
3192	 * Recover from lost output interrupts.
3193	 * Poll any lines that don't use interrupts.
3194	 */
3195	for (unit = 0; unit < NSIOTOT; ++unit) {
3196		com = com_addr(unit);
3197		if (com != NULL && !com->gone
3198		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
3199			disable_intr();
3200			siointr1(com);
3201			enable_intr();
3202		}
3203	}
3204
3205	/*
3206	 * Check for and log errors, but not too often.
3207	 */
3208	if (--sio_timeouts_until_log > 0)
3209		return;
3210	sio_timeouts_until_log = hz / sio_timeout;
3211	for (unit = 0; unit < NSIOTOT; ++unit) {
3212		int	errnum;
3213
3214		com = com_addr(unit);
3215		if (com == NULL)
3216			continue;
3217		if (com->gone)
3218			continue;
3219		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
3220			u_int	delta;
3221			u_long	total;
3222
3223			disable_intr();
3224			delta = com->delta_error_counts[errnum];
3225			com->delta_error_counts[errnum] = 0;
3226			enable_intr();
3227			if (delta == 0)
3228				continue;
3229			total = com->error_counts[errnum] += delta;
3230			log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
3231			    unit, delta, error_desc[errnum],
3232			    delta == 1 ? "" : "s", total);
3233		}
3234	}
3235}
3236
3237#ifdef PC98
3238/* commint is called when modem control line changes */
3239static void
3240commint(dev_t dev)
3241{
3242	register struct tty *tp;
3243	int	stat,delta;
3244	struct com_s *com;
3245	int	mynor,unit;
3246
3247	mynor = minor(dev);
3248	unit = MINOR_TO_UNIT(mynor);
3249	com = com_addr(unit);
3250	tp = com->tp;
3251
3252	stat = com_tiocm_get(com);
3253	delta = com_tiocm_get_delta(com);
3254
3255	if (com->state & CS_CTS_OFLOW) {
3256		if (stat & TIOCM_CTS)
3257			com->state |= CS_ODEVREADY;
3258		else
3259			com->state &= ~CS_ODEVREADY;
3260	}
3261	if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) {
3262	    if (stat & TIOCM_CAR )
3263		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
3264	    else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
3265		/* negate DTR, RTS */
3266		com_tiocm_bic(com, (tp->t_cflag & HUPCL) ?
3267				TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE );
3268		/* disable IENABLE */
3269		com_int_TxRx_disable( com );
3270	    }
3271	}
3272}
3273#endif
3274
3275static void
3276disc_optim(tp, t, com)
3277	struct tty	*tp;
3278	struct termios	*t;
3279	struct com_s	*com;
3280{
3281	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
3282	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
3283	    && (!(t->c_iflag & PARMRK)
3284		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
3285	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
3286	    && linesw[tp->t_line].l_rint == ttyinput)
3287		tp->t_state |= TS_CAN_BYPASS_L_RINT;
3288	else
3289		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
3290	com->hotchar = linesw[tp->t_line].l_hotchar;
3291}
3292
3293/*
3294 * Following are all routines needed for SIO to act as console
3295 */
3296#include <machine/cons.h>
3297
3298struct siocnstate {
3299	u_char	dlbl;
3300	u_char	dlbh;
3301	u_char	ier;
3302	u_char	cfcr;
3303	u_char	mcr;
3304};
3305
3306static speed_t siocngetspeed __P((Port_t, struct speedtab *));
3307static void siocnclose	__P((struct siocnstate *sp));
3308static void siocnopen	__P((struct siocnstate *sp));
3309static void siocntxwait	__P((void));
3310
3311static void
3312siocntxwait()
3313{
3314	int	timo;
3315
3316	/*
3317	 * Wait for any pending transmission to finish.  Required to avoid
3318	 * the UART lockup bug when the speed is changed, and for normal
3319	 * transmits.
3320	 */
3321	timo = 100000;
3322	while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
3323	       != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
3324		;
3325}
3326
3327/*
3328 * Read the serial port specified and try to figure out what speed
3329 * it's currently running at.  We're assuming the serial port has
3330 * been initialized and is basicly idle.  This routine is only intended
3331 * to be run at system startup.
3332 *
3333 * If the value read from the serial port doesn't make sense, return 0.
3334 */
3335
3336static speed_t
3337siocngetspeed(iobase, table)
3338	Port_t iobase;
3339	struct speedtab *table;
3340{
3341	int	code;
3342	u_char	dlbh;
3343	u_char	dlbl;
3344	u_char  cfcr;
3345
3346	cfcr = inb(iobase + com_cfcr);
3347	outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
3348
3349	dlbl = inb(iobase + com_dlbl);
3350	dlbh = inb(iobase + com_dlbh);
3351
3352	outb(iobase + com_cfcr, cfcr);
3353
3354	code = dlbh << 8 | dlbl;
3355
3356	for ( ; table->sp_speed != -1; table++)
3357		if (table->sp_code == code)
3358			return (table->sp_speed);
3359
3360	return 0;	/* didn't match anything sane */
3361}
3362
3363static void
3364siocnopen(sp)
3365	struct siocnstate	*sp;
3366{
3367	int	divisor;
3368	u_char	dlbh;
3369	u_char	dlbl;
3370	Port_t	iobase;
3371
3372	/*
3373	 * Save all the device control registers except the fifo register
3374	 * and set our default ones (cs8 -parenb speed=comdefaultrate).
3375	 * We can't save the fifo register since it is read-only.
3376	 */
3377	iobase = siocniobase;
3378	sp->ier = inb(iobase + com_ier);
3379	outb(iobase + com_ier, 0);	/* spltty() doesn't stop siointr() */
3380	siocntxwait();
3381	sp->cfcr = inb(iobase + com_cfcr);
3382	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3383	sp->dlbl = inb(iobase + com_dlbl);
3384	sp->dlbh = inb(iobase + com_dlbh);
3385	/*
3386	 * Only set the divisor registers if they would change, since on
3387	 * some 16550 incompatibles (Startech), setting them clears the
3388	 * data input register.  This also reduces the effects of the
3389	 * UMC8669F bug.
3390	 */
3391	divisor = ttspeedtab(comdefaultrate, comspeedtab);
3392	dlbl = divisor & 0xFF;
3393	if (sp->dlbl != dlbl)
3394		outb(iobase + com_dlbl, dlbl);
3395	dlbh = (u_int) divisor >> 8;
3396	if (sp->dlbh != dlbh)
3397		outb(iobase + com_dlbh, dlbh);
3398	outb(iobase + com_cfcr, CFCR_8BITS);
3399	sp->mcr = inb(iobase + com_mcr);
3400	/*
3401	 * We don't want interrupts, but must be careful not to "disable"
3402	 * them by clearing the MCR_IENABLE bit, since that might cause
3403	 * an interrupt by floating the IRQ line.
3404	 */
3405	outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
3406}
3407
3408static void
3409siocnclose(sp)
3410	struct siocnstate	*sp;
3411{
3412	Port_t	iobase;
3413
3414	/*
3415	 * Restore the device control registers.
3416	 */
3417	siocntxwait();
3418	iobase = siocniobase;
3419	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3420	if (sp->dlbl != inb(iobase + com_dlbl))
3421		outb(iobase + com_dlbl, sp->dlbl);
3422	if (sp->dlbh != inb(iobase + com_dlbh))
3423		outb(iobase + com_dlbh, sp->dlbh);
3424	outb(iobase + com_cfcr, sp->cfcr);
3425	/*
3426	 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
3427	 */
3428	outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
3429	outb(iobase + com_ier, sp->ier);
3430}
3431
3432void
3433siocnprobe(cp)
3434	struct consdev	*cp;
3435{
3436	speed_t			boot_speed;
3437	u_char			cfcr;
3438	struct isa_device	*dvp;
3439	int			s;
3440	struct siocnstate	sp;
3441
3442	/*
3443	 * Find our first enabled console, if any.  If it is a high-level
3444	 * console device, then initialize it and return successfully.
3445	 * If it is a low-level console device, then initialize it and
3446	 * return unsuccessfully.  It must be initialized in both cases
3447	 * for early use by console drivers and debuggers.  Initializing
3448	 * the hardware is not necessary in all cases, since the i/o
3449	 * routines initialize it on the fly, but it is necessary if
3450	 * input might arrive while the hardware is switched back to an
3451	 * uninitialized state.  We can't handle multiple console devices
3452	 * yet because our low-level routines don't take a device arg.
3453	 * We trust the user to set the console flags properly so that we
3454	 * don't need to probe.
3455	 */
3456	cp->cn_pri = CN_DEAD;
3457	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
3458		if (dvp->id_driver == &siodriver && dvp->id_enabled
3459		    && COM_CONSOLE(dvp)) {
3460			siocniobase = dvp->id_iobase;
3461			s = spltty();
3462			if (boothowto & RB_SERIAL) {
3463				boot_speed = siocngetspeed(siocniobase,
3464							   comspeedtab);
3465				if (boot_speed)
3466					comdefaultrate = boot_speed;
3467			}
3468
3469			/*
3470			 * Initialize the divisor latch.  We can't rely on
3471			 * siocnopen() to do this the first time, since it
3472			 * avoids writing to the latch if the latch appears
3473			 * to have the correct value.  Also, if we didn't
3474			 * just read the speed from the hardware, then we
3475			 * need to set the speed in hardware so that
3476			 * switching it later is null.
3477			 */
3478			cfcr = inb(siocniobase + com_cfcr);
3479			outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
3480			outb(siocniobase + com_dlbl,
3481			     COMBRD(comdefaultrate) & 0xff);
3482			outb(siocniobase + com_dlbh,
3483			     (u_int) COMBRD(comdefaultrate) >> 8);
3484			outb(siocniobase + com_cfcr, cfcr);
3485
3486			siocnopen(&sp);
3487			splx(s);
3488			if (!COM_LLCONSOLE(dvp)) {
3489				cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit);
3490				cp->cn_pri = COM_FORCECONSOLE(dvp)
3491					     || boothowto & RB_SERIAL
3492					     ? CN_REMOTE : CN_NORMAL;
3493			}
3494			break;
3495		}
3496}
3497
3498void
3499siocninit(cp)
3500	struct consdev	*cp;
3501{
3502	comconsole = DEV_TO_UNIT(cp->cn_dev);
3503}
3504
3505int
3506siocncheckc(dev)
3507	dev_t	dev;
3508{
3509	int	c;
3510	Port_t	iobase;
3511	int	s;
3512	struct siocnstate	sp;
3513
3514	iobase = siocniobase;
3515	s = spltty();
3516	siocnopen(&sp);
3517	if (inb(iobase + com_lsr) & LSR_RXRDY)
3518		c = inb(iobase + com_data);
3519	else
3520		c = -1;
3521	siocnclose(&sp);
3522	splx(s);
3523	return (c);
3524}
3525
3526
3527int
3528siocngetc(dev)
3529	dev_t	dev;
3530{
3531	int	c;
3532	Port_t	iobase;
3533	int	s;
3534	struct siocnstate	sp;
3535
3536	iobase = siocniobase;
3537	s = spltty();
3538	siocnopen(&sp);
3539	while (!(inb(iobase + com_lsr) & LSR_RXRDY))
3540		;
3541	c = inb(iobase + com_data);
3542	siocnclose(&sp);
3543	splx(s);
3544	return (c);
3545}
3546
3547void
3548siocnputc(dev, c)
3549	dev_t	dev;
3550	int	c;
3551{
3552	int	s;
3553	struct siocnstate	sp;
3554
3555	s = spltty();
3556	siocnopen(&sp);
3557	siocntxwait();
3558	outb(siocniobase + com_data, c);
3559	siocnclose(&sp);
3560	splx(s);
3561}
3562
3563#ifdef DSI_SOFT_MODEM
3564/*
3565 * The magic code to download microcode to a "Connection 14.4+Fax"
3566 * modem from Digicom Systems Inc.  Very magic.
3567 */
3568
3569#define DSI_ERROR(str) { ptr = str; goto error; }
3570static int
3571LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr)
3572{
3573    int int_c,int_k;
3574    int data_0188, data_0187;
3575
3576    /*
3577     * First see if it is a DSI SoftModem
3578     */
3579    if(!((inb(base_io+7) ^ inb(base_io+7)) & 0x80))
3580	return ENODEV;
3581
3582    data_0188 = inb(base_io+4);
3583    data_0187 = inb(base_io+3);
3584    outb(base_io+3,0x80);
3585    outb(base_io+4,0x0C);
3586    outb(base_io+0,0x31);
3587    outb(base_io+1,0x8C);
3588    outb(base_io+7,0x10);
3589    outb(base_io+7,0x19);
3590
3591    if(0x18 != (inb(base_io+7) & 0x1A))
3592	DSI_ERROR("dsp bus not granted");
3593
3594    if(0x01 != (inb(base_io+7) & 0x01)) {
3595	outb(base_io+7,0x18);
3596	outb(base_io+7,0x19);
3597	if(0x01 != (inb(base_io+7) & 0x01))
3598	    DSI_ERROR("program mem not granted");
3599    }
3600
3601    int_c = 0;
3602
3603    while(1) {
3604	if(int_c >= 7 || size <= 0x1800)
3605	    break;
3606
3607	for(int_k = 0 ; int_k < 0x800; int_k++) {
3608	    outb(base_io+0,*ptr++);
3609	    outb(base_io+1,*ptr++);
3610	    outb(base_io+2,*ptr++);
3611	}
3612
3613	size -= 0x1800;
3614	int_c++;
3615    }
3616
3617    if(size > 0x1800) {
3618 	outb(base_io+7,0x18);
3619 	outb(base_io+7,0x19);
3620	if(0x00 != (inb(base_io+7) & 0x01))
3621	    DSI_ERROR("program data not granted");
3622
3623	for(int_k = 0 ; int_k < 0x800; int_k++) {
3624	    outb(base_io+1,*ptr++);
3625	    outb(base_io+2,0);
3626	    outb(base_io+1,*ptr++);
3627	    outb(base_io+2,*ptr++);
3628	}
3629
3630	size -= 0x1800;
3631
3632	while(size > 0x1800) {
3633	    for(int_k = 0 ; int_k < 0xC00; int_k++) {
3634		outb(base_io+1,*ptr++);
3635		outb(base_io+2,*ptr++);
3636	    }
3637	    size -= 0x1800;
3638	}
3639
3640	if(size < 0x1800) {
3641	    for(int_k=0;int_k<size/2;int_k++) {
3642		outb(base_io+1,*ptr++);
3643		outb(base_io+2,*ptr++);
3644	    }
3645	}
3646
3647    } else if (size > 0) {
3648	if(int_c == 7) {
3649	    outb(base_io+7,0x18);
3650	    outb(base_io+7,0x19);
3651	    if(0x00 != (inb(base_io+7) & 0x01))
3652		DSI_ERROR("program data not granted");
3653	    for(int_k = 0 ; int_k < size/3; int_k++) {
3654		outb(base_io+1,*ptr++);
3655		outb(base_io+2,0);
3656		outb(base_io+1,*ptr++);
3657		outb(base_io+2,*ptr++);
3658	    }
3659	} else {
3660	    for(int_k = 0 ; int_k < size/3; int_k++) {
3661		outb(base_io+0,*ptr++);
3662		outb(base_io+1,*ptr++);
3663		outb(base_io+2,*ptr++);
3664	    }
3665	}
3666    }
3667    outb(base_io+7,0x11);
3668    outb(base_io+7,3);
3669
3670    outb(base_io+4,data_0188 & 0xfb);
3671
3672    outb(base_io+3,data_0187);
3673
3674    return 0;
3675error:
3676    printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr);
3677    outb(base_io+7,0x00); \
3678    outb(base_io+3,data_0187); \
3679    outb(base_io+4,data_0188);  \
3680    return EIO;
3681}
3682#endif /* DSI_SOFT_MODEM */
3683
3684/*
3685 * support PnP cards if we are using 'em
3686 */
3687
3688#if NPNP > 0
3689
3690static struct siopnp_ids {
3691	u_long vend_id;
3692	char *id_str;
3693} siopnp_ids[] = {
3694	{ 0x5015f435, "MOT1550"},
3695	{ 0x8113b04e, "Supra1381"},
3696	{ 0x9012b04e, "Supra1290"},
3697	{ 0x11007256, "USR0011"},
3698	{ 0x30207256, "USR2030"},
3699	{ 0 }
3700};
3701
3702static char *siopnp_probe(u_long csn, u_long vend_id);
3703static void siopnp_attach(u_long csn, u_long vend_id, char *name,
3704	struct isa_device *dev);
3705static u_long nsiopnp = NSIO;
3706
3707static struct pnp_device siopnp = {
3708	"siopnp",
3709	siopnp_probe,
3710	siopnp_attach,
3711	&nsiopnp,
3712	&tty_imask
3713};
3714DATA_SET (pnpdevice_set, siopnp);
3715
3716static char *
3717siopnp_probe(u_long csn, u_long vend_id)
3718{
3719	struct siopnp_ids *ids;
3720	char *s = NULL;
3721
3722	for(ids = siopnp_ids; ids->vend_id != 0; ids++) {
3723		if (vend_id == ids->vend_id) {
3724			s = ids->id_str;
3725			break;
3726		}
3727	}
3728
3729	if (s) {
3730		struct pnp_cinfo d;
3731		read_pnp_parms(&d, 0);
3732		if (d.enable == 0 || d.flags & 1) {
3733			printf("CSN %d is disabled.\n", csn);
3734			return (NULL);
3735		}
3736
3737	}
3738
3739	return (s);
3740}
3741
3742static void
3743siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev)
3744{
3745	struct pnp_cinfo d;
3746	struct isa_device *dvp;
3747
3748	if (dev->id_unit >= NSIOTOT)
3749		return;
3750
3751	if (read_pnp_parms(&d, 0) == 0) {
3752		printf("failed to read pnp parms\n");
3753		return;
3754	}
3755
3756	write_pnp_parms(&d, 0);
3757
3758	enable_pnp_card();
3759
3760	dev->id_iobase = d.port[0];
3761	dev->id_irq = (1 << d.irq[0]);
3762	dev->id_intr = siointr;
3763	dev->id_ri_flags = RI_FAST;
3764	dev->id_drq = -1;
3765
3766	if (dev->id_driver == NULL) {
3767		dev->id_driver = &siodriver;
3768		dvp = find_isadev(isa_devtab_tty, &siodriver, 0);
3769		if (dvp != NULL)
3770			dev->id_id = dvp->id_id;
3771	}
3772
3773	if ((dev->id_alive = sioprobe(dev)) != 0)
3774		sioattach(dev);
3775	else
3776		printf("sio%d: probe failed\n", dev->id_unit);
3777}
3778#endif
3779#ifdef PC98
3780/*
3781 *  pc98 local function
3782 */
3783
3784static void
3785com_tiocm_set(struct com_s *com, int msr)
3786{
3787	int	s;
3788	int	tmp = 0;
3789	int	mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS;
3790
3791	s=spltty();
3792	com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) )
3793	   | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3794	tmp |= (CMD8251_TxEN|CMD8251_RxEN);
3795	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3796	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3797	pc98_i8251_clear_or_cmd( com, mask, tmp );
3798	splx(s);
3799}
3800
3801static void
3802com_tiocm_bis(struct com_s *com, int msr)
3803{
3804	int	s;
3805	int	tmp = 0;
3806
3807	s=spltty();
3808	com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3809	tmp |= CMD8251_TxEN|CMD8251_RxEN;
3810	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3811	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3812
3813	pc98_i8251_or_cmd( com, tmp );
3814	splx(s);
3815}
3816
3817static void
3818com_tiocm_bic(struct com_s *com, int msr)
3819{
3820	int	s;
3821	int	tmp = msr;
3822
3823	s=spltty();
3824	com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3825	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3826	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3827
3828	pc98_i8251_clear_cmd( com, tmp );
3829	splx(s);
3830}
3831
3832static int
3833com_tiocm_get(struct com_s *com)
3834{
3835	return( com->pc98_prev_modem_status );
3836}
3837
3838static int
3839com_tiocm_get_delta(struct com_s *com)
3840{
3841	int	tmp;
3842
3843	tmp = com->pc98_modem_delta;
3844	com->pc98_modem_delta = 0;
3845	return( tmp );
3846}
3847
3848/* convert to TIOCM_?? ( ioctl.h ) */
3849static int
3850pc98_get_modem_status(struct com_s *com)
3851{
3852	int	stat, stat2;
3853	register int	msr;
3854
3855	stat  = inb(com->sts_port);
3856	stat2 = inb(com->in_modem_port);
3857	msr = com->pc98_prev_modem_status
3858			& ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3859	if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR;
3860	if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI;
3861	if (   stat & STS8251_DSR ) msr |= TIOCM_DSR;
3862	if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS;
3863#if COM_CARRIER_DETECT_EMULATE
3864	if ( msr & (TIOCM_DSR|TIOCM_CTS) ) {
3865		msr |= TIOCM_CAR;
3866	}
3867#endif
3868	return(msr);
3869}
3870
3871static void
3872pc98_check_msr(void* chan)
3873{
3874	int	msr, delta;
3875	int	s;
3876	register struct tty *tp;
3877	struct	com_s *com;
3878	int	mynor;
3879	int	unit;
3880	dev_t	dev;
3881
3882	dev=(dev_t)chan;
3883	mynor = minor(dev);
3884	unit = MINOR_TO_UNIT(mynor);
3885	com = com_addr(unit);
3886	tp = com->tp;
3887
3888	s = spltty();
3889	msr = pc98_get_modem_status(com);
3890	/* make change flag */
3891	delta = msr ^ com->pc98_prev_modem_status;
3892	if ( delta & TIOCM_CAR ) {
3893	    if ( com->modem_car_chg_timer ) {
3894		if ( -- com->modem_car_chg_timer )
3895		    msr ^= TIOCM_CAR;
3896	    } else {
3897		if ( com->modem_car_chg_timer = ( msr & TIOCM_CAR ) ?
3898			     DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE )
3899		    msr ^= TIOCM_CAR;
3900	    }
3901	} else
3902	    com->modem_car_chg_timer = 0;
3903	delta = ( msr ^ com->pc98_prev_modem_status ) &
3904			(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3905	com->pc98_prev_modem_status = msr;
3906	delta = ( com->pc98_modem_delta |= delta );
3907	splx(s);
3908	if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) {
3909		if ( delta ) {
3910			commint(dev);
3911		}
3912		timeout(pc98_check_msr, (caddr_t)dev,
3913					PC98_CHECK_MODEM_INTERVAL);
3914	} else {
3915		com->modem_checking = 0;
3916	}
3917}
3918
3919static void
3920pc98_msrint_start(dev_t dev)
3921{
3922	struct	com_s *com;
3923	int	mynor;
3924	int	unit;
3925	int	s = spltty();
3926
3927	mynor = minor(dev);
3928	unit = MINOR_TO_UNIT(mynor);
3929	com = com_addr(unit);
3930	/* modem control line check routine envoke interval is 1/10 sec */
3931	if ( com->modem_checking == 0 ) {
3932		com->pc98_prev_modem_status = pc98_get_modem_status(com);
3933		com->pc98_modem_delta = 0;
3934		timeout(pc98_check_msr, (caddr_t)dev,
3935					PC98_CHECK_MODEM_INTERVAL);
3936		com->modem_checking = 1;
3937	}
3938	splx(s);
3939}
3940
3941static void
3942pc98_disable_i8251_interrupt(struct com_s *com, int mod)
3943{
3944	/* disable interrupt */
3945	register int	tmp;
3946
3947	mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3948	COM_INT_DISABLE
3949	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3950	outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp );
3951	COM_INT_ENABLE
3952}
3953
3954static void
3955pc98_enable_i8251_interrupt(struct com_s *com, int mod)
3956{
3957	register int	tmp;
3958
3959	COM_INT_DISABLE
3960	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3961	outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp );
3962	COM_INT_ENABLE
3963}
3964
3965static int
3966pc98_check_i8251_interrupt(struct com_s *com)
3967{
3968	return ( com->intr_enable & 0x07 );
3969}
3970
3971static void
3972pc98_i8251_clear_cmd(struct com_s *com, int x)
3973{
3974	int	tmp;
3975
3976	COM_INT_DISABLE
3977	tmp = com->pc98_prev_siocmd & ~(x);
3978	outb(com->cmd_port, tmp);
3979	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3980	COM_INT_ENABLE
3981}
3982
3983static void
3984pc98_i8251_or_cmd(struct com_s *com, int x)
3985{
3986	int	tmp;
3987
3988	COM_INT_DISABLE
3989	tmp = com->pc98_prev_siocmd | (x);
3990	outb(com->cmd_port, tmp);
3991	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3992	COM_INT_ENABLE
3993}
3994
3995static void
3996pc98_i8251_set_cmd(struct com_s *com, int x)
3997{
3998	int	tmp;
3999
4000	COM_INT_DISABLE
4001	tmp = (x);
4002	outb(com->cmd_port, tmp);
4003	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4004	COM_INT_ENABLE
4005}
4006
4007static void
4008pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x)
4009{
4010	int	tmp;
4011	COM_INT_DISABLE
4012	tmp = com->pc98_prev_siocmd & ~(clr);
4013	tmp |= (x);
4014	outb(com->cmd_port, tmp);
4015	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
4016	COM_INT_ENABLE
4017}
4018
4019static int
4020pc98_i8251_get_cmd(struct com_s *com)
4021{
4022	return com->pc98_prev_siocmd;
4023}
4024
4025static int
4026pc98_i8251_get_mod(struct com_s *com)
4027{
4028	return com->pc98_prev_siomod;
4029}
4030
4031static void
4032pc98_i8251_reset(struct com_s *com, int mode, int command)
4033{
4034	outb(com->cmd_port, 0);	/* dummy */
4035	DELAY(2);
4036	outb(com->cmd_port, 0);	/* dummy */
4037	DELAY(2);
4038	outb(com->cmd_port, 0);	/* dummy */
4039	DELAY(2);
4040	outb(com->cmd_port, CMD8251_RESET);	/* internal reset */
4041	DELAY(2);
4042	outb(com->cmd_port, mode );	/* mode register */
4043	com->pc98_prev_siomod = mode;
4044	DELAY(2);
4045	pc98_i8251_set_cmd( com, (command|CMD8251_ER) );
4046}
4047
4048static void
4049pc98_check_sysclock(void)
4050{
4051	/* get system clock from port */
4052	if ( pc98_machine_type & M_8M ) {
4053	/* 8 MHz system & H98 */
4054		sysclock = 8;
4055	} else {
4056	/* 5 MHz system */
4057		sysclock = 5;
4058	}
4059}
4060
4061static void
4062com_cflag_and_speed_set( struct com_s *com, int cflag, int speed)
4063{
4064	int	cfcr=0, count;
4065	int	previnterrupt;
4066
4067	count = pc98_ttspeedtab( com, speed );
4068	if ( count < 0 ) return;
4069
4070	previnterrupt = pc98_check_i8251_interrupt(com);
4071	pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx );
4072
4073	switch ( cflag&CSIZE ) {
4074	  case CS5:
4075		cfcr = MOD8251_5BITS; break;
4076	  case CS6:
4077		cfcr = MOD8251_6BITS; break;
4078	  case CS7:
4079		cfcr = MOD8251_7BITS; break;
4080	  case CS8:
4081		cfcr = MOD8251_8BITS; break;
4082	}
4083	if ( cflag&PARENB ) {
4084	    if ( cflag&PARODD )
4085		cfcr |= MOD8251_PODD;
4086	    else
4087		cfcr |= MOD8251_PEVEN;
4088	} else
4089		cfcr |= MOD8251_PDISAB;
4090
4091	if ( cflag&CSTOPB )
4092		cfcr |= MOD8251_STOP2;
4093	else
4094		cfcr |= MOD8251_STOP1;
4095
4096	if ( count & 0x10000 )
4097		cfcr |= MOD8251_CLKX1;
4098	else
4099		cfcr |= MOD8251_CLKX16;
4100
4101	if (epson_machine_id != 0x20) {	/* XXX */
4102	{
4103		int	tmp;
4104		while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP))
4105			;
4106	}
4107	}
4108	/* set baud rate from ospeed */
4109	pc98_set_baud_rate( com, count );
4110
4111	if ( cfcr != pc98_i8251_get_mod(com) )
4112		pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) );
4113
4114	pc98_enable_i8251_interrupt( com, previnterrupt );
4115}
4116
4117static int
4118pc98_ttspeedtab(struct com_s *com, int speed)
4119{
4120	int	effect_sp, count=-1, mod;
4121
4122	switch ( com->pc98_if_type ) {
4123	    case COM_IF_INTERNAL:
4124		/* for *1CLK asynchronous! mode		, TEFUTEFU */
4125		effect_sp = ttspeedtab( speed, pc98speedtab );
4126		if ( effect_sp < 0 )
4127			effect_sp = ttspeedtab( (speed-1), pc98speedtab );
4128		if ( effect_sp <= 0 )
4129			return effect_sp;
4130		mod = (sysclock == 5 ? 2457600 : 1996800);
4131		if ( effect_sp == speed )
4132			mod /= 16;
4133		count = mod / effect_sp;
4134		if ( count > 65535 )
4135			return(-1);
4136		if ( effect_sp >= 2400 )
4137			if ( !(sysclock != 5 &&
4138				(effect_sp == 19200 || effect_sp == 38400)) )
4139				if ( ( mod % effect_sp ) != 0 )
4140					return(-1);
4141		if ( effect_sp != speed )
4142			count |= 0x10000;
4143		break;
4144#ifdef COM_IF_PC9861K
4145	    case COM_IF_PC9861K:
4146		effect_sp = speed;
4147		count = 1;
4148		break;
4149#endif
4150#ifdef COM_IF_PIO9032B
4151	    case COM_IF_PIO9032B:
4152		if ( speed == 0 ) return 0;
4153		count = ttspeedtab( speed, comspeedtab_pio9032b );
4154		if ( count < 0 ) return count;
4155		effect_sp = speed;
4156		break;
4157#endif
4158#ifdef COM_IF_B98_01
4159	    case COM_IF_B98_01:
4160		effect_sp=speed;
4161		count = ttspeedtab( speed, comspeedtab_b98_01 );
4162		if ( count <= 3 )
4163			return -1;         /* invalid speed/count */
4164		if ( count <= 5 )
4165			count |= 0x10000;  /* x1 mode for 76800 and 153600 */
4166		else
4167			count -= 4;        /* x16 mode for slower */
4168		break;
4169#endif
4170	}
4171	return count;
4172}
4173
4174static void
4175pc98_set_baud_rate( struct com_s *com, int count)
4176{
4177	int	s;
4178
4179	switch ( com->pc98_if_type ) {
4180	    case COM_IF_INTERNAL:
4181		if ( count < 0 ) {
4182			printf( "[ Illegal count : %d ]", count );
4183			return;
4184		} else if ( count == 0)
4185			return;
4186		/* set i8253 */
4187		s = splclock();
4188		outb( 0x77, 0xb6 );
4189		outb( 0x5f, 0);
4190		outb( 0x75, count & 0xff );
4191		outb( 0x5f, 0);
4192		outb( 0x75, (count >> 8) & 0xff );
4193		splx(s);
4194		break;
4195#if 0
4196#ifdef COM_IF_PC9861K
4197	    case COM_IF_PC9861K:
4198		break;
4199		/* ext. RS232C board: speed is determined by DIP switch */
4200#endif
4201#endif /* 0 */
4202#ifdef COM_IF_PIO9032B
4203	    case COM_IF_PIO9032B:
4204		outb( com_addr[unit], count & 0x07 );
4205		break;
4206#endif
4207#ifdef COM_IF_B98_01
4208	    case COM_IF_B98_01:
4209		outb( com->iobase,     count & 0x0f );
4210#ifdef B98_01_OLD
4211		/* some old board should be controlled in different way,
4212		   but this hasn't been tested yet.*/
4213		outb( com->iobase+2, ( count & 0x10000 ) ? 0xf0 : 0xf2 );
4214#endif
4215		break;
4216#endif
4217	}
4218}
4219static int
4220pc98_check_if_type( int iobase, struct siodev *iod)
4221{
4222	int	irr = 0, tmp = 0;
4223	int	ret = 0;
4224	static  short	irq_tab[2][8] = {
4225		{  3,  5,  6,  9, 10, 12, 13, -1},
4226		{  3, 10, 12, 13,  5,  6,  9, -1}
4227	};
4228	iod->irq = 0;
4229	switch ( iobase & 0xff ) {
4230		case IO_COM1:
4231			iod->if_type = COM_IF_INTERNAL;
4232			ret = 0; iod->irq = 4; break;
4233#ifdef COM_IF_PC9861K
4234		case IO_COM2:
4235			iod->if_type = COM_IF_PC9861K;
4236			ret = 1; irr = 0; tmp = 3; break;
4237		case IO_COM3:
4238			iod->if_type = COM_IF_PC9861K;
4239			ret = 2; irr = 1; tmp = 3; break;
4240#endif
4241#ifdef COM_IF_PIO9032B
4242	    case IO_COM_PIO9032B_2:
4243			iod->if_type = COM_IF_PIO9032B;
4244			ret = 1; irr = 0; tmp = 7; break;
4245	    case IO_COM_PIO9032B_3:
4246			iod->if_type = COM_IF_PIO9032B;
4247			ret = 2; irr = 1; tmp = 7; break;
4248#endif
4249#ifdef COM_IF_B98_01
4250	    case IO_COM_B98_01_2:
4251			iod->if_type = COM_IF_B98_01;
4252			ret = 1; irr = 0; tmp = 7;
4253			outb(iobase + 2, 0xf2);
4254			outb(iobase,     4);
4255			break;
4256	    case IO_COM_B98_01_3:
4257			iod->if_type = COM_IF_B98_01;
4258			ret = 2; irr = 1; tmp = 7;
4259			outb(iobase + 2, 0xf2);
4260			outb(iobase    , 4);
4261			break;
4262#endif
4263	    default:
4264			if((iobase & 0x0f0) == 0xd0){
4265				iod->if_type = MC16550;
4266				return 0;
4267			}
4268			return -1;
4269	}
4270
4271	iod->cmd  = ( iobase & 0xff00 )|PC98SIO_cmd_port(ret);
4272	iod->sts  = ( iobase & 0xff00 )|PC98SIO_sts_port(ret);
4273	iod->mod  = ( iobase & 0xff00 )|PC98SIO_in_modem_port(ret);
4274	iod->ctrl = ( iobase & 0xff00 )|PC98SIO_intr_ctrl_port(ret);
4275
4276	if ( iod->irq == 0 ) {
4277		tmp &= inb( iod->mod );
4278		iod->irq = irq_tab[irr][tmp];
4279		if ( iod->irq == -1 ) return -1;
4280	}
4281	return 0;
4282}
4283static int
4284pc98_set_ioport( struct com_s *com, int io_base )
4285{
4286	int	a, io, type;
4287
4288	switch ( io_base & 0xff ) {
4289	    case IO_COM1: a = 0; io = 0; type = COM_IF_INTERNAL;
4290					 pc98_check_sysclock(); break;
4291#ifdef COM_IF_PC9861K
4292	    case IO_COM2: a = 1; io = 0; type = COM_IF_PC9861K; break;
4293	    case IO_COM3: a = 2; io = 0; type = COM_IF_PC9861K; break;
4294#endif /* COM_IF_PC9861K */
4295#ifdef COM_IF_PIO9032B
4296			/* PIO9032B : I/O address is changeable */
4297	    case IO_COM_PIO9032B_2:
4298			a = 1; io = io_base & 0xff00;
4299			type = COM_IF_PIO9032B; break;
4300	    case IO_COM_PIO9032B_3:
4301			a = 2; io = io_base & 0xff00;
4302			type = COM_IF_PIO9032B; break;
4303#endif /* COM_IF_PIO9032B */
4304#ifdef COM_IF_B98_01
4305	    case IO_COM_B98_01_2:
4306			a = 1; io = 0; type = COM_IF_B98_01; break;
4307	    case IO_COM_B98_01_3:
4308			a = 2; io = 0; type = COM_IF_B98_01; break;
4309#endif /* COM_IF_B98_01*/
4310	    default:	/* i/o address not match */
4311		return -1;
4312	}
4313
4314	com->pc98_if_type	= type;
4315	com->data_port		= io | PC98SIO_data_port(a);
4316	com->cmd_port		= io | PC98SIO_cmd_port(a);
4317	com->sts_port		= io | PC98SIO_sts_port(a);
4318	com->in_modem_port	= io | PC98SIO_in_modem_port(a);
4319	com->intr_ctrl_port	= io | PC98SIO_intr_ctrl_port(a);
4320	return 0;
4321}
4322#endif /* PC98 defined */
4323