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