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