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