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