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