sio.c revision 20129
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
34 *	$Id: sio.c,v 1.10 1996/12/04 04:21:07 asami Exp $
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						Debugger(
1844						    "serial console break");
1845						goto cont;
1846					}
1847#endif
1848					if (com->tp == NULL
1849					    || com->tp->t_iflag & IGNBRK)
1850						goto cont;
1851				} else {
1852					if (com->tp == NULL
1853					    || com->tp->t_iflag & IGNPAR)
1854						goto cont;
1855				}
1856				if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1857				    && (line_status & (LSR_BI | LSR_FE)
1858					|| com->tp->t_iflag & INPCK))
1859					recv_data = 0;
1860			}
1861
1862			++com->bytes_in;
1863			if (com->hotchar != 0 && recv_data == com->hotchar)
1864				setsofttty();
1865			ioptr = com->iptr;
1866			if (ioptr >= com->ibufend)
1867				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1868			else {
1869				if (com->do_timestamp)
1870					microtime(&com->timestamp);
1871				++com_events;
1872				schedsofttty();
1873#if 0 /* for testing input latency vs efficiency */
1874if (com->iptr - com->ibuf == 8)
1875	setsofttty();
1876#endif
1877				ioptr[0] = recv_data;
1878				ioptr[CE_INPUT_OFFSET] = line_status;
1879				com->iptr = ++ioptr;
1880				if (ioptr == com->ihighwater
1881				    && com->state & CS_RTS_IFLOW)
1882#ifdef PC98
1883					if(IS_8251(com->pc98_if_type))
1884						com_tiocm_bic(com, TIOCM_RTS);
1885					else
1886#endif
1887					outb(com->modem_ctl_port,
1888					     com->mcr_image &= ~MCR_RTS);
1889				if (line_status & LSR_OE)
1890					CE_RECORD(com, CE_OVERRUN);
1891			}
1892cont:
1893			/*
1894			 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1895			 * jump from the top of the loop to here
1896			 */
1897#ifdef PC98
1898			if(IS_8251(com->pc98_if_type))
1899				goto status_read;
1900			else
1901#endif
1902			line_status = inb(com->line_status_port) & 0x7F;
1903		}
1904
1905		/* modem status change? (always check before doing output) */
1906#ifdef PC98
1907		if(!IS_8251(com->pc98_if_type)){
1908#endif
1909		modem_status = inb(com->modem_status_port);
1910		if (modem_status != com->last_modem_status) {
1911			if (com->do_dcd_timestamp
1912			    && !(com->last_modem_status & MSR_DCD)
1913			    && modem_status & MSR_DCD)
1914				microtime(&com->dcd_timestamp);
1915
1916			/*
1917			 * Schedule high level to handle DCD changes.  Note
1918			 * that we don't use the delta bits anywhere.  Some
1919			 * UARTs mess them up, and it's easy to remember the
1920			 * previous bits and calculate the delta.
1921			 */
1922			com->last_modem_status = modem_status;
1923			if (!(com->state & CS_CHECKMSR)) {
1924				com_events += LOTS_OF_EVENTS;
1925				com->state |= CS_CHECKMSR;
1926				setsofttty();
1927			}
1928
1929			/* handle CTS change immediately for crisp flow ctl */
1930			if (com->state & CS_CTS_OFLOW) {
1931				if (modem_status & MSR_CTS)
1932					com->state |= CS_ODEVREADY;
1933				else
1934					com->state &= ~CS_ODEVREADY;
1935			}
1936		}
1937#ifdef PC98
1938		}
1939#endif
1940
1941		/* output queued and everything ready? */
1942		if (line_status & LSR_TXRDY
1943		    && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1944			ioptr = com->obufq.l_head;
1945			if (com->tx_fifo_size > 1) {
1946				u_int	ocount;
1947
1948				ocount = com->obufq.l_tail - ioptr;
1949				if (ocount > com->tx_fifo_size)
1950					ocount = com->tx_fifo_size;
1951				com->bytes_out += ocount;
1952				do
1953					outb(com->data_port, *ioptr++);
1954				while (--ocount != 0);
1955			} else {
1956				outb(com->data_port, *ioptr++);
1957				++com->bytes_out;
1958			}
1959#ifdef PC98
1960			if(IS_8251(com->pc98_if_type))
1961				if ( !(pc98_check_i8251_interrupt(com) & IEN_TxFLAG) )
1962					com_int_Tx_enable(com);
1963#endif
1964			com->obufq.l_head = ioptr;
1965			if (ioptr >= com->obufq.l_tail) {
1966				struct lbq	*qp;
1967
1968				qp = com->obufq.l_next;
1969				qp->l_queued = FALSE;
1970				qp = qp->l_next;
1971				if (qp != NULL) {
1972					com->obufq.l_head = qp->l_head;
1973					com->obufq.l_tail = qp->l_tail;
1974					com->obufq.l_next = qp;
1975				} else {
1976					/* output just completed */
1977					com->state &= ~CS_BUSY;
1978#if defined(PC98)
1979					if(IS_8251(com->pc98_if_type))
1980						if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
1981							com_int_Tx_disable(com);
1982#endif
1983				}
1984				if (!(com->state & CS_ODONE)) {
1985					com_events += LOTS_OF_EVENTS;
1986					com->state |= CS_ODONE;
1987					setsofttty();	/* handle at high level ASAP */
1988				}
1989			}
1990		}
1991#ifdef PC98
1992		else if (line_status & LSR_TXRDY) {
1993			if(IS_8251(com->pc98_if_type))
1994				if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG )
1995					com_int_Tx_disable(com);
1996		}
1997		if(IS_8251(com->pc98_if_type))
1998			if ((tmp = inb(com->sts_port)) & STS8251_RxRDY)
1999				goto more_intr;
2000#endif
2001
2002		/* finished? */
2003#ifndef COM_MULTIPORT
2004#ifdef PC98
2005		if(IS_8251(com->pc98_if_type))
2006			return;
2007#endif
2008		if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
2009#endif /* COM_MULTIPORT */
2010			return;
2011	}
2012}
2013
2014static int
2015sioioctl(dev, cmd, data, flag, p)
2016	dev_t		dev;
2017	int		cmd;
2018	caddr_t		data;
2019	int		flag;
2020	struct proc	*p;
2021{
2022	struct com_s	*com;
2023	int		error;
2024	Port_t		iobase;
2025	int		mynor;
2026	int		s;
2027	struct tty	*tp;
2028#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2029	int		oldcmd;
2030	struct termios	term;
2031#endif
2032
2033	mynor = minor(dev);
2034	com = com_addr(MINOR_TO_UNIT(mynor));
2035	if (com->gone)
2036		return (ENODEV);
2037	iobase = com->iobase;
2038	if (mynor & CONTROL_MASK) {
2039		struct termios	*ct;
2040
2041		switch (mynor & CONTROL_MASK) {
2042		case CONTROL_INIT_STATE:
2043			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
2044			break;
2045		case CONTROL_LOCK_STATE:
2046			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
2047			break;
2048		default:
2049			return (ENODEV);	/* /dev/nodev */
2050		}
2051		switch (cmd) {
2052		case TIOCSETA:
2053			error = suser(p->p_ucred, &p->p_acflag);
2054			if (error != 0)
2055				return (error);
2056			*ct = *(struct termios *)data;
2057			return (0);
2058		case TIOCGETA:
2059			*(struct termios *)data = *ct;
2060			return (0);
2061		case TIOCGETD:
2062			*(int *)data = TTYDISC;
2063			return (0);
2064		case TIOCGWINSZ:
2065			bzero(data, sizeof(struct winsize));
2066			return (0);
2067#ifdef DSI_SOFT_MODEM
2068		/*
2069		 * Download micro-code to Digicom modem.
2070		 */
2071		case TIOCDSIMICROCODE:
2072			{
2073			u_long l;
2074			u_char *p,*pi;
2075
2076			pi = (u_char*)(*(caddr_t*)data);
2077			error = copyin(pi,&l,sizeof l);
2078			if(error)
2079				{return error;};
2080			pi += sizeof l;
2081
2082			p = malloc(l,M_TEMP,M_NOWAIT);
2083			if(!p)
2084				{return ENOBUFS;}
2085			error = copyin(pi,p,l);
2086			if(error)
2087				{free(p,M_TEMP); return error;};
2088			if(error = LoadSoftModem(
2089			    MINOR_TO_UNIT(mynor),iobase,l,p))
2090				{free(p,M_TEMP); return error;}
2091			free(p,M_TEMP);
2092			return(0);
2093			}
2094#endif /* DSI_SOFT_MODEM */
2095		default:
2096			return (ENOTTY);
2097		}
2098	}
2099	tp = com->tp;
2100#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2101	term = tp->t_termios;
2102	oldcmd = cmd;
2103	error = ttsetcompat(tp, &cmd, data, &term);
2104	if (error != 0)
2105		return (error);
2106	if (cmd != oldcmd)
2107		data = (caddr_t)&term;
2108#endif
2109	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
2110		int	cc;
2111		struct termios *dt = (struct termios *)data;
2112		struct termios *lt = mynor & CALLOUT_MASK
2113				     ? &com->lt_out : &com->lt_in;
2114
2115		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
2116			      | (dt->c_iflag & ~lt->c_iflag);
2117		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
2118			      | (dt->c_oflag & ~lt->c_oflag);
2119		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
2120			      | (dt->c_cflag & ~lt->c_cflag);
2121		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
2122			      | (dt->c_lflag & ~lt->c_lflag);
2123		for (cc = 0; cc < NCCS; ++cc)
2124			if (lt->c_cc[cc] != 0)
2125				dt->c_cc[cc] = tp->t_cc[cc];
2126		if (lt->c_ispeed != 0)
2127			dt->c_ispeed = tp->t_ispeed;
2128		if (lt->c_ospeed != 0)
2129			dt->c_ospeed = tp->t_ospeed;
2130	}
2131	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2132	if (error >= 0)
2133		return (error);
2134	s = spltty();
2135	error = ttioctl(tp, cmd, data, flag);
2136	disc_optim(tp, &tp->t_termios, com);
2137	if (error >= 0) {
2138		splx(s);
2139		return (error);
2140	}
2141#ifdef PC98
2142	if(IS_8251(com->pc98_if_type)){
2143	switch (cmd) {
2144	case TIOCSBRK:
2145		com_send_break_on( com );
2146		break;
2147	case TIOCCBRK:
2148		com_send_break_off( com );
2149		break;
2150	case TIOCSDTR:
2151		(void)commctl(com, TIOCM_DTR, DMBIS);
2152		break;
2153	case TIOCCDTR:
2154		(void)commctl(com, TIOCM_DTR, DMBIC);
2155		break;
2156	/*
2157	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
2158	 * changes get undone on the next call to comparam().
2159	 */
2160	case TIOCMSET:
2161		(void)commctl(com, *(int *)data, DMSET);
2162		break;
2163	case TIOCMBIS:
2164		(void)commctl(com, *(int *)data, DMBIS);
2165		break;
2166	case TIOCMBIC:
2167		(void)commctl(com, *(int *)data, DMBIC);
2168		break;
2169	case TIOCMGET:
2170		*(int *)data = commctl(com, 0, DMGET);
2171		break;
2172	case TIOCMSDTRWAIT:
2173		/* must be root since the wait applies to following logins */
2174		error = suser(p->p_ucred, &p->p_acflag);
2175		if (error != 0) {
2176			splx(s);
2177			return (error);
2178		}
2179		com->dtr_wait = *(int *)data * hz / 100;
2180		break;
2181	case TIOCMGDTRWAIT:
2182		*(int *)data = com->dtr_wait * 100 / hz;
2183		break;
2184	case TIOCTIMESTAMP:
2185		com->do_timestamp = TRUE;
2186		*(struct timeval *)data = com->timestamp;
2187		break;
2188	case TIOCDCDTIMESTAMP:
2189		com->do_dcd_timestamp = TRUE;
2190		*(struct timeval *)data = com->dcd_timestamp;
2191		break;
2192	default:
2193		splx(s);
2194		return (ENOTTY);
2195	}
2196	} else {
2197#endif
2198	switch (cmd) {
2199	case TIOCSBRK:
2200		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
2201		break;
2202	case TIOCCBRK:
2203		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
2204		break;
2205	case TIOCSDTR:
2206		(void)commctl(com, TIOCM_DTR, DMBIS);
2207		break;
2208	case TIOCCDTR:
2209		(void)commctl(com, TIOCM_DTR, DMBIC);
2210		break;
2211	case TIOCMSET:
2212		(void)commctl(com, *(int *)data, DMSET);
2213		break;
2214	case TIOCMBIS:
2215		(void)commctl(com, *(int *)data, DMBIS);
2216		break;
2217	case TIOCMBIC:
2218		(void)commctl(com, *(int *)data, DMBIC);
2219		break;
2220	case TIOCMGET:
2221		*(int *)data = commctl(com, 0, DMGET);
2222		break;
2223	case TIOCMSDTRWAIT:
2224		/* must be root since the wait applies to following logins */
2225		error = suser(p->p_ucred, &p->p_acflag);
2226		if (error != 0) {
2227			splx(s);
2228			return (error);
2229		}
2230		com->dtr_wait = *(int *)data * hz / 100;
2231		break;
2232	case TIOCMGDTRWAIT:
2233		*(int *)data = com->dtr_wait * 100 / hz;
2234		break;
2235	case TIOCTIMESTAMP:
2236		com->do_timestamp = TRUE;
2237		*(struct timeval *)data = com->timestamp;
2238		break;
2239	default:
2240		splx(s);
2241		return (ENOTTY);
2242	}
2243#ifdef PC98
2244	}
2245#endif
2246	splx(s);
2247	return (0);
2248}
2249
2250void
2251siopoll()
2252{
2253	int		unit;
2254
2255	if (com_events == 0)
2256		return;
2257repeat:
2258	for (unit = 0; unit < NSIO; ++unit) {
2259		u_char		*buf;
2260		struct com_s	*com;
2261		u_char		*ibuf;
2262		int		incc;
2263		struct tty	*tp;
2264#ifdef PC98
2265		int		tmp;
2266#endif
2267
2268		com = com_addr(unit);
2269		if (com == NULL)
2270			continue;
2271		if (com->gone)
2272			continue;
2273		tp = com->tp;
2274		if (tp == NULL) {
2275			/*
2276			 * XXX forget any events related to closed devices
2277			 * (actually never opened devices) so that we don't
2278			 * loop.
2279			 */
2280			disable_intr();
2281			incc = com->iptr - com->ibuf;
2282			com->iptr = com->ibuf;
2283			if (com->state & CS_CHECKMSR) {
2284				incc += LOTS_OF_EVENTS;
2285				com->state &= ~CS_CHECKMSR;
2286			}
2287			com_events -= incc;
2288			enable_intr();
2289			if (incc != 0)
2290				log(LOG_DEBUG,
2291				    "sio%d: %d events for device with no tp\n",
2292				    unit, incc);
2293			continue;
2294		}
2295
2296		/* switch the role of the low-level input buffers */
2297		if (com->iptr == (ibuf = com->ibuf)) {
2298			buf = NULL;     /* not used, but compiler can't tell */
2299			incc = 0;
2300		} else {
2301			buf = ibuf;
2302			disable_intr();
2303			incc = com->iptr - buf;
2304			com_events -= incc;
2305			if (ibuf == com->ibuf1)
2306				ibuf = com->ibuf2;
2307			else
2308				ibuf = com->ibuf1;
2309			com->ibufend = ibuf + RS_IBUFSIZE;
2310			com->ihighwater = ibuf + RS_IHIGHWATER;
2311			com->iptr = ibuf;
2312
2313			/*
2314			 * There is now room for another low-level buffer full
2315			 * of input, so enable RTS if it is now disabled and
2316			 * there is room in the high-level buffer.
2317			 */
2318#ifdef PC98
2319			if(IS_8251(com->pc98_if_type))
2320				tmp = com_tiocm_get(com) & TIOCM_RTS;
2321			else
2322				tmp = com->mcr_image & MCR_RTS;
2323#endif
2324			if ((com->state & CS_RTS_IFLOW)
2325#ifdef PC98
2326			    && !(tmp)
2327#else
2328			    && !(com->mcr_image & MCR_RTS)
2329#endif
2330			    && !(tp->t_state & TS_TBLOCK))
2331#ifdef PC98
2332				if(IS_8251(com->pc98_if_type))
2333					com_tiocm_bis(com, TIOCM_RTS);
2334				else
2335#endif
2336				outb(com->modem_ctl_port,
2337				     com->mcr_image |= MCR_RTS);
2338			enable_intr();
2339			com->ibuf = ibuf;
2340		}
2341
2342		if (com->state & CS_CHECKMSR) {
2343			u_char	delta_modem_status;
2344
2345#ifdef PC98
2346			if(!IS_8251(com->pc98_if_type)){
2347#endif
2348			disable_intr();
2349			delta_modem_status = com->last_modem_status
2350					     ^ com->prev_modem_status;
2351			com->prev_modem_status = com->last_modem_status;
2352			com_events -= LOTS_OF_EVENTS;
2353			com->state &= ~CS_CHECKMSR;
2354			enable_intr();
2355			if (delta_modem_status & MSR_DCD)
2356				(*linesw[tp->t_line].l_modem)
2357					(tp, com->prev_modem_status & MSR_DCD);
2358#ifdef PC98
2359			}
2360#endif
2361		}
2362		if (com->state & CS_ODONE) {
2363			disable_intr();
2364			com_events -= LOTS_OF_EVENTS;
2365			com->state &= ~CS_ODONE;
2366			enable_intr();
2367			if (!(com->state & CS_BUSY))
2368				timeout(siobusycheck, com, hz / 100);
2369			(*linesw[tp->t_line].l_start)(tp);
2370		}
2371		if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
2372		    !(tp->t_cflag & CREAD))
2373			continue;
2374		/*
2375		 * Avoid the grotesquely inefficient lineswitch routine
2376		 * (ttyinput) in "raw" mode.  It usually takes about 450
2377		 * instructions (that's without canonical processing or echo!).
2378		 * slinput is reasonably fast (usually 40 instructions plus
2379		 * call overhead).
2380		 */
2381		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
2382			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
2383			    && (com->state & CS_RTS_IFLOW
2384				|| tp->t_iflag & IXOFF)
2385			    && !(tp->t_state & TS_TBLOCK))
2386				ttyblock(tp);
2387			tk_nin += incc;
2388			tk_rawcc += incc;
2389			tp->t_rawcc += incc;
2390			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
2391				+= b_to_q((char *)buf, incc, &tp->t_rawq);
2392			ttwakeup(tp);
2393			if (tp->t_state & TS_TTSTOP
2394			    && (tp->t_iflag & IXANY
2395				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
2396				tp->t_state &= ~TS_TTSTOP;
2397				tp->t_lflag &= ~FLUSHO;
2398				comstart(tp);
2399			}
2400		} else {
2401			do {
2402				u_char	line_status;
2403				int	recv_data;
2404
2405				line_status = (u_char) buf[CE_INPUT_OFFSET];
2406				recv_data = (u_char) *buf++;
2407				if (line_status
2408				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
2409					if (line_status & LSR_BI)
2410						recv_data |= TTY_BI;
2411					if (line_status & LSR_FE)
2412						recv_data |= TTY_FE;
2413					if (line_status & LSR_OE)
2414						recv_data |= TTY_OE;
2415					if (line_status & LSR_PE)
2416						recv_data |= TTY_PE;
2417				}
2418				(*linesw[tp->t_line].l_rint)(recv_data, tp);
2419			} while (--incc > 0);
2420		}
2421		if (com_events == 0)
2422			break;
2423	}
2424	if (com_events >= LOTS_OF_EVENTS)
2425		goto repeat;
2426}
2427
2428static int
2429comparam(tp, t)
2430	struct tty	*tp;
2431	struct termios	*t;
2432{
2433	u_int		cfcr;
2434	int		cflag;
2435	struct com_s	*com;
2436	int		divisor;
2437	u_char		dlbh;
2438	u_char		dlbl;
2439	int		error;
2440	Port_t		iobase;
2441	int		s;
2442	int		unit;
2443	int		txtimeout;
2444#ifdef PC98
2445	Port_t		tmp_port;
2446	int		tmp_flg;
2447#endif
2448
2449#ifdef PC98
2450	cfcr = 0;
2451	unit = DEV_TO_UNIT(tp->t_dev);
2452	com = com_addr(unit);
2453	iobase = com->iobase;
2454	if(IS_8251(com->pc98_if_type)) {
2455		divisor = pc98_ttspeedtab(com, t->c_ospeed);
2456	} else
2457#endif
2458	/* do historical conversions */
2459	if (t->c_ispeed == 0)
2460		t->c_ispeed = t->c_ospeed;
2461
2462	/* check requested parameters */
2463	divisor = ttspeedtab(t->c_ospeed, comspeedtab);
2464	if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
2465		return (EINVAL);
2466
2467	/* parameters are OK, convert them to the com struct and the device */
2468#ifndef PC98
2469	unit = DEV_TO_UNIT(tp->t_dev);
2470	com = com_addr(unit);
2471	iobase = com->iobase;
2472#endif
2473	s = spltty();
2474#ifdef PC98
2475	if(IS_8251(com->pc98_if_type)){
2476		if(divisor == 0){
2477			com_int_TxRx_disable( com );
2478			com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE );
2479		}
2480	} else {
2481#endif
2482	if (divisor == 0)
2483		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
2484	else
2485		(void)commctl(com, TIOCM_DTR, DMBIS);
2486#ifdef PC98
2487	}
2488#endif
2489	cflag = t->c_cflag;
2490#ifdef PC98
2491	if(!IS_8251(com->pc98_if_type)){
2492#endif
2493	switch (cflag & CSIZE) {
2494	case CS5:
2495		cfcr = CFCR_5BITS;
2496		break;
2497	case CS6:
2498		cfcr = CFCR_6BITS;
2499		break;
2500	case CS7:
2501		cfcr = CFCR_7BITS;
2502		break;
2503	default:
2504		cfcr = CFCR_8BITS;
2505		break;
2506	}
2507	if (cflag & PARENB) {
2508		cfcr |= CFCR_PENAB;
2509		if (!(cflag & PARODD))
2510			cfcr |= CFCR_PEVEN;
2511	}
2512	if (cflag & CSTOPB)
2513		cfcr |= CFCR_STOPB;
2514
2515	if (com->hasfifo && divisor != 0) {
2516		/*
2517		 * Use a fifo trigger level low enough so that the input
2518		 * latency from the fifo is less than about 16 msec and
2519		 * the total latency is less than about 30 msec.  These
2520		 * latencies are reasonable for humans.  Serial comms
2521		 * protocols shouldn't expect anything better since modem
2522		 * latencies are larger.
2523		 */
2524		com->fifo_image = t->c_ospeed <= 4800
2525				  ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
2526		outb(iobase + com_fifo, com->fifo_image);
2527	}
2528
2529	/*
2530	 * Some UARTs lock up if the divisor latch registers are selected
2531	 * while the UART is doing output (they refuse to transmit anything
2532	 * more until given a hard reset).  Fix this by stopping filling
2533	 * the device buffers and waiting for them to drain.  Reading the
2534	 * line status port outside of siointr1() might lose some receiver
2535	 * error bits, but that is acceptable here.
2536	 */
2537#ifdef PC98
2538	}
2539#endif
2540	disable_intr();
2541retry:
2542	com->state &= ~CS_TTGO;
2543	txtimeout = tp->t_timeout;
2544	enable_intr();
2545#ifdef PC98
2546	if(IS_8251(com->pc98_if_type)){
2547		tmp_port = com->sts_port;
2548		tmp_flg = (STS8251_TxRDY|STS8251_TxEMP);
2549	} else {
2550		tmp_port = com->line_status_port;
2551		tmp_flg = (LSR_TSRE|LSR_TXRDY);
2552	}
2553	while ((inb(tmp_port) & tmp_flg) != tmp_flg) {
2554#else
2555	while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2556	       != (LSR_TSRE | LSR_TXRDY)) {
2557#endif
2558		tp->t_state |= TS_SO_OCOMPLETE;
2559		error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
2560				 "siotx", hz / 100);
2561		if (   txtimeout != 0
2562		    && (!error || error	== EAGAIN)
2563		    && (txtimeout -= hz	/ 100) <= 0
2564		   )
2565			error = EIO;
2566		if (com->gone)
2567			error = ENODEV;
2568		if (error != 0 && error != EAGAIN) {
2569			if (!(tp->t_state & TS_TTSTOP)) {
2570				disable_intr();
2571				com->state |= CS_TTGO;
2572				enable_intr();
2573			}
2574			splx(s);
2575			return (error);
2576		}
2577	}
2578
2579	disable_intr();		/* very important while com_data is hidden */
2580
2581	/*
2582	 * XXX - clearing CS_TTGO is not sufficient to stop further output,
2583	 * because siopoll() calls comstart() which usually sets it again
2584	 * because TS_TTSTOP is clear.  Setting TS_TTSTOP would not be
2585	 * sufficient, for similar reasons.
2586	 */
2587#ifdef PC98
2588	if ((inb(tmp_port) & tmp_flg) != tmp_flg)
2589#else
2590	if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
2591	    != (LSR_TSRE | LSR_TXRDY))
2592#endif
2593		goto retry;
2594
2595#ifdef PC98
2596	if(!IS_8251(com->pc98_if_type)){
2597#endif
2598	if (divisor != 0) {
2599		outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
2600		/*
2601		 * Only set the divisor registers if they would change,
2602		 * since on some 16550 incompatibles (UMC8669F), setting
2603		 * them while input is arriving them loses sync until
2604		 * data stops arriving.
2605		 */
2606		dlbl = divisor & 0xFF;
2607		if (inb(iobase + com_dlbl) != dlbl)
2608			outb(iobase + com_dlbl, dlbl);
2609		dlbh = (u_int) divisor >> 8;
2610		if (inb(iobase + com_dlbh) != dlbh)
2611			outb(iobase + com_dlbh, dlbh);
2612	}
2613	outb(iobase + com_cfcr, com->cfcr_image = cfcr);
2614#ifdef PC98
2615	} else
2616		com_cflag_and_speed_set(com, cflag, t->c_ospeed);
2617#endif
2618	if (!(tp->t_state & TS_TTSTOP))
2619		com->state |= CS_TTGO;
2620	if (cflag & CRTS_IFLOW) {
2621		com->state |= CS_RTS_IFLOW;
2622		/*
2623		 * If CS_RTS_IFLOW just changed from off to on, the change
2624		 * needs to be propagated to MCR_RTS.  This isn't urgent,
2625		 * so do it later by calling comstart() instead of repeating
2626		 * a lot of code from comstart() here.
2627		 */
2628	} else if (com->state & CS_RTS_IFLOW) {
2629		com->state &= ~CS_RTS_IFLOW;
2630		/*
2631		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
2632		 * on here, since comstart() won't do it later.
2633		 */
2634		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2635	}
2636
2637	/*
2638	 * Set up state to handle output flow control.
2639	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2640	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2641	 */
2642	com->state |= CS_ODEVREADY;
2643	com->state &= ~CS_CTS_OFLOW;
2644	if (cflag & CCTS_OFLOW) {
2645		com->state |= CS_CTS_OFLOW;
2646#ifdef PC98
2647		if(IS_8251(com->pc98_if_type)){
2648			if (!(pc98_get_modem_status(com) & TIOCM_CTS))
2649				com->state &= ~CS_ODEVREADY;
2650		} else {
2651#endif
2652		if (!(com->last_modem_status & MSR_CTS))
2653			com->state &= ~CS_ODEVREADY;
2654#ifdef PC98
2655		}
2656#endif
2657	}
2658	/* XXX shouldn't call functions while intrs are disabled. */
2659	disc_optim(tp, t, com);
2660	/*
2661	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
2662	 * unconditionally, but that defeated the careful discarding of
2663	 * stale input in sioopen().
2664	 */
2665	if (com->state >= (CS_BUSY | CS_TTGO))
2666		siointr1(com);
2667
2668	enable_intr();
2669	splx(s);
2670	comstart(tp);
2671	return (0);
2672}
2673
2674static void
2675comstart(tp)
2676	struct tty	*tp;
2677{
2678	struct com_s	*com;
2679	int		s;
2680	int		unit;
2681#ifdef PC98
2682	int		tmp;
2683#endif
2684
2685	unit = DEV_TO_UNIT(tp->t_dev);
2686	com = com_addr(unit);
2687	s = spltty();
2688	disable_intr();
2689	if (tp->t_state & TS_TTSTOP)
2690		com->state &= ~CS_TTGO;
2691	else
2692		com->state |= CS_TTGO;
2693	if (tp->t_state & TS_TBLOCK) {
2694#ifdef PC98
2695		if(IS_8251(com->pc98_if_type))
2696			tmp = com_tiocm_get(com) & TIOCM_RTS;
2697		else
2698			tmp = com->mcr_image & MCR_RTS;
2699		if (tmp && (com->state & CS_RTS_IFLOW))
2700#else
2701		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2702#endif
2703#ifdef PC98
2704			if(IS_8251(com->pc98_if_type))
2705				com_tiocm_bic(com, TIOCM_RTS);
2706			else
2707#endif
2708			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2709	} else {
2710#ifdef PC98
2711		if(IS_8251(com->pc98_if_type))
2712			tmp = com_tiocm_get(com) & TIOCM_RTS;
2713		else
2714			tmp = com->mcr_image & MCR_RTS;
2715		if (!(tmp) && com->iptr < com->ihighwater
2716			&& com->state & CS_RTS_IFLOW)
2717#else
2718		if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2719		    && com->state & CS_RTS_IFLOW)
2720#endif
2721#ifdef PC98
2722			if(IS_8251(com->pc98_if_type))
2723				com_tiocm_bis(com, TIOCM_RTS);
2724			else
2725#endif
2726			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2727	}
2728	enable_intr();
2729	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2730#ifdef PC98
2731/*		if(IS_8251(com->pc98_if_type))
2732			com_int_Tx_enable(com); */
2733#endif
2734		splx(s);
2735		return;
2736	}
2737	if (tp->t_outq.c_cc != 0) {
2738		struct lbq	*qp;
2739		struct lbq	*next;
2740
2741		if (!com->obufs[0].l_queued) {
2742			com->obufs[0].l_tail
2743			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2744						  sizeof com->obuf1);
2745			com->obufs[0].l_next = NULL;
2746			com->obufs[0].l_queued = TRUE;
2747			disable_intr();
2748			if (com->state & CS_BUSY) {
2749				qp = com->obufq.l_next;
2750				while ((next = qp->l_next) != NULL)
2751					qp = next;
2752				qp->l_next = &com->obufs[0];
2753			} else {
2754				com->obufq.l_head = com->obufs[0].l_head;
2755				com->obufq.l_tail = com->obufs[0].l_tail;
2756				com->obufq.l_next = &com->obufs[0];
2757				com->state |= CS_BUSY;
2758			}
2759			enable_intr();
2760		}
2761		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2762			com->obufs[1].l_tail
2763			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2764						  sizeof com->obuf2);
2765			com->obufs[1].l_next = NULL;
2766			com->obufs[1].l_queued = TRUE;
2767			disable_intr();
2768			if (com->state & CS_BUSY) {
2769				qp = com->obufq.l_next;
2770				while ((next = qp->l_next) != NULL)
2771					qp = next;
2772				qp->l_next = &com->obufs[1];
2773			} else {
2774				com->obufq.l_head = com->obufs[1].l_head;
2775				com->obufq.l_tail = com->obufs[1].l_tail;
2776				com->obufq.l_next = &com->obufs[1];
2777				com->state |= CS_BUSY;
2778			}
2779			enable_intr();
2780		}
2781		tp->t_state |= TS_BUSY;
2782	}
2783	disable_intr();
2784	if (com->state >= (CS_BUSY | CS_TTGO))
2785		siointr1(com);	/* fake interrupt to start output */
2786	enable_intr();
2787#ifdef PC98
2788/*		if(IS_8251(com->pc98_if_type))
2789			com_int_Tx_enable(com); */
2790#endif
2791	ttwwakeup(tp);
2792	splx(s);
2793}
2794
2795static void
2796siostop(tp, rw)
2797	struct tty	*tp;
2798	int		rw;
2799{
2800	struct com_s	*com;
2801
2802	com = com_addr(DEV_TO_UNIT(tp->t_dev));
2803	if (com->gone)
2804		return;
2805	disable_intr();
2806	if (rw & FWRITE) {
2807		if (com->hasfifo)
2808			/* XXX does this flush everything? */
2809			outb(com->iobase + com_fifo,
2810			     FIFO_XMT_RST | com->fifo_image);
2811		com->obufs[0].l_queued = FALSE;
2812		com->obufs[1].l_queued = FALSE;
2813		if (com->state & CS_ODONE)
2814			com_events -= LOTS_OF_EVENTS;
2815		com->state &= ~(CS_ODONE | CS_BUSY);
2816		com->tp->t_state &= ~TS_BUSY;
2817	}
2818	if (rw & FREAD) {
2819		if (com->hasfifo)
2820			/* XXX does this flush everything? */
2821			outb(com->iobase + com_fifo,
2822			     FIFO_RCV_RST | com->fifo_image);
2823		com_events -= (com->iptr - com->ibuf);
2824		com->iptr = com->ibuf;
2825	}
2826	enable_intr();
2827	comstart(tp);
2828}
2829
2830static struct tty *
2831siodevtotty(dev)
2832	dev_t	dev;
2833{
2834	int	mynor;
2835	int	unit;
2836
2837	mynor = minor(dev);
2838	if (mynor & CONTROL_MASK)
2839		return (NULL);
2840	unit = MINOR_TO_UNIT(mynor);
2841	if ((u_int) unit >= NSIO)
2842		return (NULL);
2843	return (&sio_tty[unit]);
2844}
2845
2846static int
2847commctl(com, bits, how)
2848	struct com_s	*com;
2849	int		bits;
2850	int		how;
2851{
2852	int	mcr;
2853	int	msr;
2854
2855	if (how == DMGET) {
2856		bits = TIOCM_LE;	/* XXX - always enabled while open */
2857		mcr = com->mcr_image;
2858		if (mcr & MCR_DTR)
2859			bits |= TIOCM_DTR;
2860		if (mcr & MCR_RTS)
2861			bits |= TIOCM_RTS;
2862		msr = com->prev_modem_status;
2863		if (msr & MSR_CTS)
2864			bits |= TIOCM_CTS;
2865		if (msr & MSR_DCD)
2866			bits |= TIOCM_CD;
2867		if (msr & MSR_DSR)
2868			bits |= TIOCM_DSR;
2869		/*
2870		 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
2871		 * more volatile by reading the modem status a lot.  Perhaps
2872		 * we should latch both bits until the status is read here.
2873		 */
2874		if (msr & (MSR_RI | MSR_TERI))
2875			bits |= TIOCM_RI;
2876		return (bits);
2877	}
2878	mcr = 0;
2879	if (bits & TIOCM_DTR)
2880		mcr |= MCR_DTR;
2881	if (bits & TIOCM_RTS)
2882		mcr |= MCR_RTS;
2883	if (com->gone)
2884		return(0);
2885	disable_intr();
2886	switch (how) {
2887	case DMSET:
2888		outb(com->modem_ctl_port,
2889		     com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
2890		break;
2891	case DMBIS:
2892		outb(com->modem_ctl_port, com->mcr_image |= mcr);
2893		break;
2894	case DMBIC:
2895		outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
2896		break;
2897	}
2898	enable_intr();
2899	return (0);
2900}
2901
2902static void
2903siosettimeout()
2904{
2905	struct com_s	*com;
2906	bool_t		someopen;
2907	int		unit;
2908
2909	/*
2910	 * Set our timeout period to 1 second if no polled devices are open.
2911	 * Otherwise set it to max(1/200, 1/hz).
2912	 * Enable timeouts iff some device is open.
2913	 */
2914	untimeout(comwakeup, (void *)NULL);
2915	sio_timeout = hz;
2916	someopen = FALSE;
2917	for (unit = 0; unit < NSIO; ++unit) {
2918		com = com_addr(unit);
2919		if (com != NULL && com->tp != NULL
2920		    && com->tp->t_state & TS_ISOPEN && !com->gone) {
2921			someopen = TRUE;
2922			if (com->poll || com->poll_output) {
2923				sio_timeout = hz > 200 ? hz / 200 : 1;
2924				break;
2925			}
2926		}
2927	}
2928	if (someopen) {
2929		sio_timeouts_until_log = hz / sio_timeout;
2930		timeout(comwakeup, (void *)NULL, sio_timeout);
2931	} else {
2932		/* Flush error messages, if any. */
2933		sio_timeouts_until_log = 1;
2934		comwakeup((void *)NULL);
2935		untimeout(comwakeup, (void *)NULL);
2936	}
2937}
2938
2939static void
2940comwakeup(chan)
2941	void	*chan;
2942{
2943	struct com_s	*com;
2944	int		unit;
2945
2946	timeout(comwakeup, (void *)NULL, sio_timeout);
2947
2948	/*
2949	 * Recover from lost output interrupts.
2950	 * Poll any lines that don't use interrupts.
2951	 */
2952	for (unit = 0; unit < NSIO; ++unit) {
2953		com = com_addr(unit);
2954		if (com != NULL && !com->gone
2955		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2956			disable_intr();
2957			siointr1(com);
2958			enable_intr();
2959		}
2960	}
2961
2962	/*
2963	 * Check for and log errors, but not too often.
2964	 */
2965	if (--sio_timeouts_until_log > 0)
2966		return;
2967	sio_timeouts_until_log = hz / sio_timeout;
2968	for (unit = 0; unit < NSIO; ++unit) {
2969		int	errnum;
2970
2971		com = com_addr(unit);
2972		if (com == NULL)
2973			continue;
2974		if (com->gone)
2975			continue;
2976		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2977			u_int	delta;
2978			u_long	total;
2979
2980			disable_intr();
2981			delta = com->delta_error_counts[errnum];
2982			com->delta_error_counts[errnum] = 0;
2983			enable_intr();
2984			if (delta == 0)
2985				continue;
2986			total = com->error_counts[errnum] += delta;
2987			log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
2988			    unit, delta, error_desc[errnum],
2989			    delta == 1 ? "" : "s", total);
2990		}
2991	}
2992}
2993
2994#ifdef PC98
2995/* commint is called when modem control line changes */
2996static void
2997commint(dev_t dev)
2998{
2999	register struct tty *tp;
3000	int	stat,delta;
3001	struct com_s *com;
3002	int	mynor,unit;
3003
3004	mynor = minor(dev);
3005	unit = MINOR_TO_UNIT(mynor);
3006	com = com_addr(unit);
3007	tp = com->tp;
3008
3009	stat = com_tiocm_get(com);
3010	delta = com_tiocm_get_delta(com);
3011
3012	if (com->state & CS_CTS_OFLOW) {
3013		if (stat & TIOCM_CTS)
3014			com->state |= CS_ODEVREADY;
3015		else
3016			com->state &= ~CS_ODEVREADY;
3017	}
3018	if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) {
3019	    if (stat & TIOCM_CAR )
3020		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
3021	    else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
3022		/* negate DTR, RTS */
3023		com_tiocm_bic(com, (tp->t_cflag & HUPCL) ?
3024				TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE );
3025		/* disable IENABLE */
3026		com_int_TxRx_disable( com );
3027	    }
3028	}
3029}
3030#endif
3031
3032static void
3033disc_optim(tp, t, com)
3034	struct tty	*tp;
3035	struct termios	*t;
3036	struct com_s	*com;
3037{
3038	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
3039	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
3040	    && (!(t->c_iflag & PARMRK)
3041		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
3042	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
3043	    && linesw[tp->t_line].l_rint == ttyinput)
3044		tp->t_state |= TS_CAN_BYPASS_L_RINT;
3045	else
3046		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
3047	/*
3048	 * Prepare to reduce input latency for packet
3049	 * discplines with a end of packet character.
3050	 */
3051	if (tp->t_line == SLIPDISC)
3052		com->hotchar = 0xc0;
3053	else if (tp->t_line == PPPDISC)
3054		com->hotchar = 0x7e;
3055	else
3056		com->hotchar = 0;
3057}
3058
3059/*
3060 * Following are all routines needed for SIO to act as console
3061 */
3062#include <machine/cons.h>
3063
3064struct siocnstate {
3065	u_char	dlbl;
3066	u_char	dlbh;
3067	u_char	ier;
3068	u_char	cfcr;
3069	u_char	mcr;
3070};
3071
3072static	Port_t	siocniobase;
3073
3074static void siocnclose	__P((struct siocnstate *sp));
3075static void siocnopen	__P((struct siocnstate *sp));
3076static void siocntxwait	__P((void));
3077
3078static void
3079siocntxwait()
3080{
3081	int	timo;
3082
3083	/*
3084	 * Wait for any pending transmission to finish.  Required to avoid
3085	 * the UART lockup bug when the speed is changed, and for normal
3086	 * transmits.
3087	 */
3088	timo = 100000;
3089	while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
3090	       != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
3091		;
3092}
3093
3094static void
3095siocnopen(sp)
3096	struct siocnstate	*sp;
3097{
3098	int	divisor;
3099	u_char	dlbh;
3100	u_char	dlbl;
3101	Port_t	iobase;
3102
3103	/*
3104	 * Save all the device control registers except the fifo register
3105	 * and set our default ones (cs8 -parenb speed=comdefaultrate).
3106	 * We can't save the fifo register since it is read-only.
3107	 */
3108	iobase = siocniobase;
3109	sp->ier = inb(iobase + com_ier);
3110	outb(iobase + com_ier, 0);	/* spltty() doesn't stop siointr() */
3111	siocntxwait();
3112	sp->cfcr = inb(iobase + com_cfcr);
3113	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3114	sp->dlbl = inb(iobase + com_dlbl);
3115	sp->dlbh = inb(iobase + com_dlbh);
3116	/*
3117	 * Only set the divisor registers if they would change, since on
3118	 * some 16550 incompatibles (Startech), setting them clears the
3119	 * data input register.  This also reduces the effects of the
3120	 * UMC8669F bug.
3121	 */
3122	divisor = ttspeedtab(comdefaultrate, comspeedtab);
3123	dlbl = divisor & 0xFF;
3124	if (sp->dlbl != dlbl)
3125		outb(iobase + com_dlbl, dlbl);
3126	dlbh = (u_int) divisor >> 8;
3127	if (sp->dlbh != dlbh)
3128		outb(iobase + com_dlbh, dlbh);
3129	outb(iobase + com_cfcr, CFCR_8BITS);
3130	sp->mcr = inb(iobase + com_mcr);
3131	/*
3132	 * We don't want interrupts, but must be careful not to "disable"
3133	 * them by clearing the MCR_IENABLE bit, since that might cause
3134	 * an interrupt by floating the IRQ line.
3135	 */
3136	outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
3137}
3138
3139static void
3140siocnclose(sp)
3141	struct siocnstate	*sp;
3142{
3143	Port_t	iobase;
3144
3145	/*
3146	 * Restore the device control registers.
3147	 */
3148	siocntxwait();
3149	iobase = siocniobase;
3150	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
3151	if (sp->dlbl != inb(iobase + com_dlbl))
3152		outb(iobase + com_dlbl, sp->dlbl);
3153	if (sp->dlbh != inb(iobase + com_dlbh))
3154		outb(iobase + com_dlbh, sp->dlbh);
3155	outb(iobase + com_cfcr, sp->cfcr);
3156	/*
3157	 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
3158	 */
3159	outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
3160	outb(iobase + com_ier, sp->ier);
3161}
3162
3163void
3164siocnprobe(cp)
3165	struct consdev	*cp;
3166{
3167	int	unit;
3168
3169	/* XXX: ick */
3170	unit = DEV_TO_UNIT(CONUNIT);
3171	siocniobase = CONADDR;
3172
3173	/* make sure hardware exists?  XXX */
3174
3175	/* initialize required fields */
3176	cp->cn_dev = makedev(CDEV_MAJOR, unit);
3177#ifdef COMCONSOLE
3178	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
3179#else
3180	cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
3181#endif
3182}
3183
3184void
3185siocninit(cp)
3186	struct consdev	*cp;
3187{
3188	comconsole = DEV_TO_UNIT(cp->cn_dev);
3189}
3190
3191int
3192siocncheckc(dev)
3193	dev_t	dev;
3194{
3195	int	c;
3196	Port_t	iobase;
3197	int	s;
3198	struct siocnstate	sp;
3199
3200	iobase = siocniobase;
3201	s = spltty();
3202	siocnopen(&sp);
3203	if (inb(iobase + com_lsr) & LSR_RXRDY)
3204		c = inb(iobase + com_data);
3205	else
3206		c = -1;
3207	siocnclose(&sp);
3208	splx(s);
3209	return (c);
3210}
3211
3212
3213int
3214siocngetc(dev)
3215	dev_t	dev;
3216{
3217	int	c;
3218	Port_t	iobase;
3219	int	s;
3220	struct siocnstate	sp;
3221
3222	iobase = siocniobase;
3223	s = spltty();
3224	siocnopen(&sp);
3225	while (!(inb(iobase + com_lsr) & LSR_RXRDY))
3226		;
3227	c = inb(iobase + com_data);
3228	siocnclose(&sp);
3229	splx(s);
3230	return (c);
3231}
3232
3233void
3234siocnputc(dev, c)
3235	dev_t	dev;
3236	int	c;
3237{
3238	int	s;
3239	struct siocnstate	sp;
3240
3241	s = spltty();
3242	siocnopen(&sp);
3243	siocntxwait();
3244	outb(siocniobase + com_data, c);
3245	siocnclose(&sp);
3246	splx(s);
3247}
3248
3249#ifdef DSI_SOFT_MODEM
3250/*
3251 * The magic code to download microcode to a "Connection 14.4+Fax"
3252 * modem from Digicom Systems Inc.  Very magic.
3253 */
3254
3255#define DSI_ERROR(str) { ptr = str; goto error; }
3256static int
3257LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr)
3258{
3259    int int_c,int_k;
3260    int data_0188, data_0187;
3261
3262    /*
3263     * First see if it is a DSI SoftModem
3264     */
3265    if(!((inb(base_io+7) ^ inb(base_io+7) & 0x80)))
3266	return ENODEV;
3267
3268    data_0188 = inb(base_io+4);
3269    data_0187 = inb(base_io+3);
3270    outb(base_io+3,0x80);
3271    outb(base_io+4,0x0C);
3272    outb(base_io+0,0x31);
3273    outb(base_io+1,0x8C);
3274    outb(base_io+7,0x10);
3275    outb(base_io+7,0x19);
3276
3277    if(0x18 != (inb(base_io+7) & 0x1A))
3278	DSI_ERROR("dsp bus not granted");
3279
3280    if(0x01 != (inb(base_io+7) & 0x01)) {
3281	outb(base_io+7,0x18);
3282	outb(base_io+7,0x19);
3283	if(0x01 != (inb(base_io+7) & 0x01))
3284	    DSI_ERROR("program mem not granted");
3285    }
3286
3287    int_c = 0;
3288
3289    while(1) {
3290	if(int_c >= 7 || size <= 0x1800)
3291	    break;
3292
3293	for(int_k = 0 ; int_k < 0x800; int_k++) {
3294	    outb(base_io+0,*ptr++);
3295	    outb(base_io+1,*ptr++);
3296	    outb(base_io+2,*ptr++);
3297	}
3298
3299	size -= 0x1800;
3300	int_c++;
3301    }
3302
3303    if(size > 0x1800) {
3304 	outb(base_io+7,0x18);
3305 	outb(base_io+7,0x19);
3306	if(0x00 != (inb(base_io+7) & 0x01))
3307	    DSI_ERROR("program data not granted");
3308
3309	for(int_k = 0 ; int_k < 0x800; int_k++) {
3310	    outb(base_io+1,*ptr++);
3311	    outb(base_io+2,0);
3312	    outb(base_io+1,*ptr++);
3313	    outb(base_io+2,*ptr++);
3314	}
3315
3316	size -= 0x1800;
3317
3318	while(size > 0x1800) {
3319	    for(int_k = 0 ; int_k < 0xC00; int_k++) {
3320		outb(base_io+1,*ptr++);
3321		outb(base_io+2,*ptr++);
3322	    }
3323	    size -= 0x1800;
3324	}
3325
3326	if(size < 0x1800) {
3327	    for(int_k=0;int_k<size/2;int_k++) {
3328		outb(base_io+1,*ptr++);
3329		outb(base_io+2,*ptr++);
3330	    }
3331	}
3332
3333    } else if (size > 0) {
3334	if(int_c == 7) {
3335	    outb(base_io+7,0x18);
3336	    outb(base_io+7,0x19);
3337	    if(0x00 != (inb(base_io+7) & 0x01))
3338		DSI_ERROR("program data not granted");
3339	    for(int_k = 0 ; int_k < size/3; int_k++) {
3340		outb(base_io+1,*ptr++);
3341		outb(base_io+2,0);
3342		outb(base_io+1,*ptr++);
3343		outb(base_io+2,*ptr++);
3344	    }
3345	} else {
3346	    for(int_k = 0 ; int_k < size/3; int_k++) {
3347		outb(base_io+0,*ptr++);
3348		outb(base_io+1,*ptr++);
3349		outb(base_io+2,*ptr++);
3350	    }
3351	}
3352    }
3353    outb(base_io+7,0x11);
3354    outb(base_io+7,3);
3355
3356    outb(base_io+4,data_0188 & 0xfb);
3357
3358    outb(base_io+3,data_0187);
3359
3360    return 0;
3361error:
3362    printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr);
3363    outb(base_io+7,0x00); \
3364    outb(base_io+3,data_0187); \
3365    outb(base_io+4,data_0188);  \
3366    return EIO;
3367}
3368#endif /* DSI_SOFT_MODEM */
3369#ifdef PC98
3370/*
3371 *  pc98 local function
3372 */
3373
3374static void
3375com_tiocm_set(struct com_s *com, int msr)
3376{
3377	int	s;
3378	int	tmp = 0;
3379	int	mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS;
3380
3381	s=spltty();
3382	com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) )
3383	   | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3384	tmp |= (CMD8251_TxEN|CMD8251_RxEN);
3385	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3386	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3387	pc98_i8251_clear_or_cmd( com, mask, tmp );
3388	splx(s);
3389}
3390
3391static void
3392com_tiocm_bis(struct com_s *com, int msr)
3393{
3394	int	s;
3395	int	tmp = 0;
3396
3397	s=spltty();
3398	com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3399	tmp |= CMD8251_TxEN|CMD8251_RxEN;
3400	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3401	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3402
3403	pc98_i8251_or_cmd( com, tmp );
3404	splx(s);
3405}
3406
3407static void
3408com_tiocm_bic(struct com_s *com, int msr)
3409{
3410	int	s;
3411	int	tmp = msr;
3412
3413	s=spltty();
3414	com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) );
3415	if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR;
3416	if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS;
3417
3418	pc98_i8251_clear_cmd( com, tmp );
3419	splx(s);
3420}
3421
3422static int
3423com_tiocm_get(struct com_s *com)
3424{
3425	return( com->pc98_prev_modem_status );
3426}
3427
3428static int
3429com_tiocm_get_delta(struct com_s *com)
3430{
3431	int	tmp;
3432
3433	tmp = com->pc98_modem_delta;
3434	com->pc98_modem_delta = 0;
3435	return( tmp );
3436}
3437
3438/* convert to TIOCM_?? ( ioctl.h ) */
3439static int
3440pc98_get_modem_status(struct com_s *com)
3441{
3442	int	stat, stat2;
3443	register int	msr;
3444
3445	stat  = inb(com->sts_port);
3446	stat2 = inb(com->in_modem_port);
3447	msr = com->pc98_prev_modem_status
3448			& ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3449	if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR;
3450	if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI;
3451	if (   stat & STS8251_DSR ) msr |= TIOCM_DSR;
3452	if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS;
3453#if COM_CARRIER_DETECT_EMULATE
3454	if ( msr & (TIOCM_DSR|TIOCM_CTS) ) {
3455		msr |= TIOCM_CAR;
3456	}
3457#endif
3458	return(msr);
3459}
3460
3461static void
3462pc98_check_msr(void* chan)
3463{
3464	int	msr, delta;
3465	int	s;
3466	register struct tty *tp;
3467	struct	com_s *com;
3468	int	mynor;
3469	int	unit;
3470	dev_t	dev;
3471
3472	dev=(dev_t)chan;
3473	mynor = minor(dev);
3474	unit = MINOR_TO_UNIT(mynor);
3475	com = com_addr(unit);
3476	tp = com->tp;
3477
3478	s = spltty();
3479	msr = pc98_get_modem_status(com);
3480	/* make change flag */
3481	delta = msr ^ com->pc98_prev_modem_status;
3482	if ( delta & TIOCM_CAR ) {
3483	    if ( com->modem_car_chg_timer ) {
3484		if ( -- com->modem_car_chg_timer )
3485		    msr ^= TIOCM_CAR;
3486	    } else {
3487		if ( com->modem_car_chg_timer = ( msr & TIOCM_CAR ) ?
3488			     DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE )
3489		    msr ^= TIOCM_CAR;
3490	    }
3491	} else
3492	    com->modem_car_chg_timer = 0;
3493	delta = ( msr ^ com->pc98_prev_modem_status ) &
3494			(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
3495	com->pc98_prev_modem_status = msr;
3496	delta = ( com->pc98_modem_delta |= delta );
3497	splx(s);
3498	if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) {
3499		if ( delta ) {
3500			commint(dev);
3501		}
3502		timeout(pc98_check_msr, (caddr_t)dev,
3503					PC98_CHECK_MODEM_INTERVAL);
3504	} else {
3505		com->modem_checking = 0;
3506	}
3507}
3508
3509static void
3510pc98_msrint_start(dev_t dev)
3511{
3512	struct	com_s *com;
3513	int	mynor;
3514	int	unit;
3515	int	s = spltty();
3516
3517	mynor = minor(dev);
3518	unit = MINOR_TO_UNIT(mynor);
3519	com = com_addr(unit);
3520	/* modem control line check routine envoke interval is 1/10 sec */
3521	if ( com->modem_checking == 0 ) {
3522		com->pc98_prev_modem_status = pc98_get_modem_status(com);
3523		com->pc98_modem_delta = 0;
3524		timeout(pc98_check_msr, (caddr_t)dev,
3525					PC98_CHECK_MODEM_INTERVAL);
3526		com->modem_checking = 1;
3527	}
3528	splx(s);
3529}
3530
3531static void
3532pc98_disable_i8251_interrupt(struct com_s *com, int mod)
3533{
3534	/* disable interrupt */
3535	register int	tmp;
3536
3537	mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3538	COM_INT_DISABLE
3539	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3540	outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp );
3541	COM_INT_ENABLE
3542}
3543
3544static void
3545pc98_enable_i8251_interrupt(struct com_s *com, int mod)
3546{
3547	register int	tmp;
3548
3549	COM_INT_DISABLE
3550	tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx);
3551	outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp );
3552	COM_INT_ENABLE
3553}
3554
3555static int
3556pc98_check_i8251_interrupt(struct com_s *com)
3557{
3558	return ( com->intr_enable & 0x07 );
3559}
3560
3561static void
3562pc98_i8251_clear_cmd(struct com_s *com, int x)
3563{
3564	int	tmp;
3565
3566	COM_INT_DISABLE
3567	tmp = com->pc98_prev_siocmd & ~(x);
3568	outb(com->cmd_port, tmp);
3569	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3570	COM_INT_ENABLE
3571}
3572
3573static void
3574pc98_i8251_or_cmd(struct com_s *com, int x)
3575{
3576	int	tmp;
3577
3578	COM_INT_DISABLE
3579	tmp = com->pc98_prev_siocmd | (x);
3580	outb(com->cmd_port, tmp);
3581	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3582	COM_INT_ENABLE
3583}
3584
3585static void
3586pc98_i8251_set_cmd(struct com_s *com, int x)
3587{
3588	int	tmp;
3589
3590	COM_INT_DISABLE
3591	tmp = (x);
3592	outb(com->cmd_port, tmp);
3593	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3594	COM_INT_ENABLE
3595}
3596
3597static void
3598pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x)
3599{
3600	int	tmp;
3601	COM_INT_DISABLE
3602	tmp = com->pc98_prev_siocmd & ~(clr);
3603	tmp |= (x);
3604	outb(com->cmd_port, tmp);
3605	com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH);
3606	COM_INT_ENABLE
3607}
3608
3609static int
3610pc98_i8251_get_cmd(struct com_s *com)
3611{
3612	return com->pc98_prev_siocmd;
3613}
3614
3615static int
3616pc98_i8251_get_mod(struct com_s *com)
3617{
3618	return com->pc98_prev_siomod;
3619}
3620
3621static void
3622pc98_i8251_reset(struct com_s *com, int mode, int command)
3623{
3624	outb(com->cmd_port, 0);	/* dummy */
3625	DELAY(2);
3626	outb(com->cmd_port, 0);	/* dummy */
3627	DELAY(2);
3628	outb(com->cmd_port, 0);	/* dummy */
3629	DELAY(2);
3630	outb(com->cmd_port, CMD8251_RESET);	/* internal reset */
3631	DELAY(2);
3632	outb(com->cmd_port, mode );	/* mode register */
3633	com->pc98_prev_siomod = mode;
3634	DELAY(2);
3635	pc98_i8251_set_cmd( com, (command|CMD8251_ER) );
3636}
3637
3638static void
3639pc98_check_sysclock(void)
3640{
3641	/* get system clock from port */
3642	if ( pc98_machine_type & M_8M ) {
3643	/* 8 MHz system & H98 */
3644		sysclock = 8;
3645	} else {
3646	/* 5 MHz system */
3647		sysclock = 5;
3648	}
3649}
3650
3651static void
3652com_cflag_and_speed_set( struct com_s *com, int cflag, int speed)
3653{
3654	int	cfcr=0, count;
3655	int	previnterrupt;
3656
3657	count = pc98_ttspeedtab( com, speed );
3658	if ( count < 0 ) return;
3659
3660	previnterrupt = pc98_check_i8251_interrupt(com);
3661	pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx );
3662
3663	switch ( cflag&CSIZE ) {
3664	  case CS5:
3665		cfcr = MOD8251_5BITS; break;
3666	  case CS6:
3667		cfcr = MOD8251_6BITS; break;
3668	  case CS7:
3669		cfcr = MOD8251_7BITS; break;
3670	  case CS8:
3671		cfcr = MOD8251_8BITS; break;
3672	}
3673	if ( cflag&PARENB ) {
3674	    if ( cflag&PARODD )
3675		cfcr |= MOD8251_PODD;
3676	    else
3677		cfcr |= MOD8251_PEVEN;
3678	} else
3679		cfcr |= MOD8251_PDISAB;
3680
3681	if ( cflag&CSTOPB )
3682		cfcr |= MOD8251_STOP2;
3683	else
3684		cfcr |= MOD8251_STOP1;
3685
3686	if ( count & 0x10000 )
3687		cfcr |= MOD8251_CLKX1;
3688	else
3689		cfcr |= MOD8251_CLKX16;
3690
3691	if (epson_machine_id != 0x20) {	/* XXX */
3692	{
3693		int	tmp;
3694		while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP))
3695			;
3696	}
3697	}
3698	/* set baud rate from ospeed */
3699	pc98_set_baud_rate( com, count );
3700
3701	if ( cfcr != pc98_i8251_get_mod(com) )
3702		pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) );
3703
3704	pc98_enable_i8251_interrupt( com, previnterrupt );
3705}
3706
3707static int
3708pc98_ttspeedtab(struct com_s *com, int speed)
3709{
3710	int	effect_sp, count=-1, mod;
3711
3712	switch ( com->pc98_if_type ) {
3713	    case COM_IF_INTERNAL:
3714		/* for *1CLK asynchronous! mode		, TEFUTEFU */
3715		effect_sp = ttspeedtab( speed, pc98speedtab );
3716		if ( effect_sp < 0 )
3717			effect_sp = ttspeedtab( (speed-1), pc98speedtab );
3718		if ( effect_sp <= 0 )
3719			return effect_sp;
3720		mod = (sysclock == 5 ? 2457600 : 1996800);
3721		if ( effect_sp == speed )
3722			mod /= 16;
3723		count = mod / effect_sp;
3724		if ( count > 65535 )
3725			return(-1);
3726		if ( effect_sp >= 2400 )
3727			if ( !(sysclock != 5 &&
3728				(effect_sp == 19200 || effect_sp == 38400)) )
3729				if ( ( mod % effect_sp ) != 0 )
3730					return(-1);
3731		if ( effect_sp != speed )
3732			count |= 0x10000;
3733		break;
3734#ifdef COM_IF_PC9861K
3735	    case COM_IF_PC9861K:
3736		effect_sp = speed;
3737		count = 1;
3738		break;
3739#endif
3740#ifdef COM_IF_PIO9032B
3741	    case COM_IF_PIO9032B:
3742		if ( speed == 0 ) return 0;
3743		count = ttspeedtab( speed, comspeedtab_pio9032b );
3744		if ( count < 0 ) return count;
3745		effect_sp = speed;
3746		break;
3747#endif
3748#ifdef COM_IF_B98_01
3749	    case COM_IF_B98_01:
3750		effect_sp=speed;
3751		count = ttspeedtab( speed, comspeedtab_b98_01 );
3752		if ( count <= 3 )
3753			return -1;         /* invalid speed/count */
3754		if ( count <= 5 )
3755			count |= 0x10000;  /* x1 mode for 76800 and 153600 */
3756		else
3757			count -= 4;        /* x16 mode for slower */
3758		break;
3759#endif
3760	}
3761	return count;
3762}
3763
3764static void
3765pc98_set_baud_rate( struct com_s *com, int count)
3766{
3767	int	s;
3768
3769	switch ( com->pc98_if_type ) {
3770	    case COM_IF_INTERNAL:
3771		if ( count < 0 ) {
3772			printf( "[ Illegal count : %d ]", count );
3773			return;
3774		} else if ( count == 0)
3775			return;
3776		/* set i8253 */
3777		s = splclock();
3778		outb( 0x77, 0xb6 );
3779		outb( 0x5f, 0);
3780		outb( 0x75, count & 0xff );
3781		outb( 0x5f, 0);
3782		outb( 0x75, (count >> 8) & 0xff );
3783		splx(s);
3784		break;
3785#if 0
3786#ifdef COM_IF_PC9861K
3787	    case COM_IF_PC9861K:
3788		break;
3789		/* ext. RS232C board: speed is determined by DIP switch */
3790#endif
3791#endif /* 0 */
3792#ifdef COM_IF_PIO9032B
3793	    case COM_IF_PIO9032B:
3794		outb( com_addr[unit], count & 0x07 );
3795		break;
3796#endif
3797#ifdef COM_IF_B98_01
3798	    case COM_IF_B98_01:
3799		outb( com->iobase,     count & 0x0f );
3800#ifdef B98_01_OLD
3801		/* some old board should be controlled in different way,
3802		   but this hasn't been tested yet.*/
3803		outb( com->iobase+2, ( count & 0x10000 ) ? 0xf0 : 0xf2 );
3804#endif
3805		break;
3806#endif
3807	}
3808}
3809static int
3810pc98_check_if_type( int iobase, struct siodev *iod)
3811{
3812	int	irr = 0, tmp = 0;
3813	int	ret = 0;
3814	static  short	irq_tab[2][8] = {
3815		{  3,  5,  6,  9, 10, 12, 13, -1},
3816		{  3, 10, 12, 13,  5,  6,  9, -1}
3817	};
3818	iod->irq = 0;
3819	switch ( iobase & 0xff ) {
3820		case IO_COM1:
3821			iod->if_type = COM_IF_INTERNAL;
3822			ret = 0; iod->irq = 4; break;
3823#ifdef COM_IF_PC9861K
3824		case IO_COM2:
3825			iod->if_type = COM_IF_PC9861K;
3826			ret = 1; irr = 0; tmp = 3; break;
3827		case IO_COM3:
3828			iod->if_type = COM_IF_PC9861K;
3829			ret = 2; irr = 1; tmp = 3; break;
3830#endif
3831#ifdef COM_IF_PIO9032B
3832	    case IO_COM_PIO9032B_2:
3833			iod->if_type = COM_IF_PIO9032B;
3834			ret = 1; irr = 0; tmp = 7; break;
3835	    case IO_COM_PIO9032B_3:
3836			iod->if_type = COM_IF_PIO9032B;
3837			ret = 2; irr = 1; tmp = 7; break;
3838#endif
3839#ifdef COM_IF_B98_01
3840	    case IO_COM_B98_01_2:
3841			iod->if_type = COM_IF_B98_01;
3842			ret = 1; irr = 0; tmp = 7;
3843			outb(iobase + 2, 0xf2);
3844			outb(iobase,     4);
3845			break;
3846	    case IO_COM_B98_01_3:
3847			iod->if_type = COM_IF_B98_01;
3848			ret = 2; irr = 1; tmp = 7;
3849			outb(iobase + 2, 0xf2);
3850			outb(iobase    , 4);
3851			break;
3852#endif
3853	    default:
3854			if((iobase & 0x0f0) == 0xd0){
3855				iod->if_type = MC16550;
3856				return 0;
3857			}
3858			return -1;
3859	}
3860
3861	iod->cmd  = ( iobase & 0xff00 )|PC98SIO_cmd_port(ret);
3862	iod->sts  = ( iobase & 0xff00 )|PC98SIO_sts_port(ret);
3863	iod->mod  = ( iobase & 0xff00 )|PC98SIO_in_modem_port(ret);
3864	iod->ctrl = ( iobase & 0xff00 )|PC98SIO_intr_ctrl_port(ret);
3865
3866	if ( iod->irq == 0 ) {
3867		tmp &= inb( iod->mod );
3868		iod->irq = irq_tab[irr][tmp];
3869		if ( iod->irq == -1 ) return -1;
3870	}
3871	return 0;
3872}
3873static int
3874pc98_set_ioport( struct com_s *com, int io_base )
3875{
3876	int	a, io, type;
3877
3878	switch ( io_base & 0xff ) {
3879	    case IO_COM1: a = 0; io = 0; type = COM_IF_INTERNAL;
3880					 pc98_check_sysclock(); break;
3881#ifdef COM_IF_PC9861K
3882	    case IO_COM2: a = 1; io = 0; type = COM_IF_PC9861K; break;
3883	    case IO_COM3: a = 2; io = 0; type = COM_IF_PC9861K; break;
3884#endif /* COM_IF_PC9861K */
3885#ifdef COM_IF_PIO9032B
3886			/* PIO9032B : I/O address is changeable */
3887	    case IO_COM_PIO9032B_2:
3888			a = 1; io = io_base & 0xff00;
3889			type = COM_IF_PIO9032B; break;
3890	    case IO_COM_PIO9032B_3:
3891			a = 2; io = io_base & 0xff00;
3892			type = COM_IF_PIO9032B; break;
3893#endif /* COM_IF_PIO9032B */
3894#ifdef COM_IF_B98_01
3895	    case IO_COM_B98_01_2:
3896			a = 1; io = 0; type = COM_IF_B98_01; break;
3897	    case IO_COM_B98_01_3:
3898			a = 2; io = 0; type = COM_IF_B98_01; break;
3899#endif /* COM_IF_B98_01*/
3900	    default:	/* i/o address not match */
3901		return -1;
3902	}
3903
3904	com->pc98_if_type	= type;
3905	com->data_port		= io | PC98SIO_data_port(a);
3906	com->cmd_port		= io | PC98SIO_cmd_port(a);
3907	com->sts_port		= io | PC98SIO_sts_port(a);
3908	com->in_modem_port	= io | PC98SIO_in_modem_port(a);
3909	com->intr_ctrl_port	= io | PC98SIO_intr_ctrl_port(a);
3910	return 0;
3911}
3912#endif /* PC98 defined */
3913