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