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