The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/isa/sio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD$
   34  *      from: @(#)com.c 7.5 (Berkeley) 5/16/91
   35  *      from: i386/isa sio.c,v 1.215
   36  */
   37 
   38 #include "opt_comconsole.h"
   39 #include "opt_compat.h"
   40 #include "opt_ddb.h"
   41 #include "opt_devfs.h"
   42 /* #include "opt_sio.h" */
   43 #include "sio.h"
   44 /* #include "pnp.h" */
   45 #define NPNP 0
   46 
   47 /*
   48  * Serial driver, based on 386BSD-0.1 com driver.
   49  * Mostly rewritten to use pseudo-DMA.
   50  * Works for National Semiconductor NS8250-NS16550AF UARTs.
   51  * COM driver, based on HP dca driver.
   52  *
   53  * Changes for PC-Card integration:
   54  *      - Added PC-Card driver table and handlers
   55  */
   56 #include <sys/param.h>
   57 #include <sys/systm.h>
   58 #include <sys/reboot.h>
   59 #include <sys/malloc.h>
   60 #include <sys/tty.h>
   61 #include <sys/proc.h>
   62 #include <sys/module.h>
   63 #include <sys/conf.h>
   64 #include <sys/dkstat.h>
   65 #include <sys/fcntl.h>
   66 #include <sys/interrupt.h>
   67 #include <sys/kernel.h>
   68 #include <sys/syslog.h>
   69 #include <sys/sysctl.h>
   70 #include <sys/bus.h>
   71 #include <sys/rman.h>
   72 #ifdef DEVFS
   73 #include <sys/devfsext.h>
   74 #endif
   75 
   76 #include <isa/isareg.h>
   77 #include <isa/isavar.h>
   78 #include <machine/lock.h>
   79 
   80 #include <machine/clock.h>
   81 #include <machine/ipl.h>
   82 #include <machine/resource.h>
   83 
   84 #include <isa/sioreg.h>
   85 
   86 #ifdef COM_ESP
   87 #include <isa/ic/esp.h>
   88 #endif
   89 #include <isa/ic/ns16550.h>
   90 
   91 #if 0
   92 
   93 #include "card.h"
   94 #if NCARD > 0
   95 #include <sys/module.h>
   96 #include <pccard/cardinfo.h>
   97 #include <pccard/slot.h>
   98 #endif
   99 
  100 #if NPNP > 0
  101 #include <i386/isa/pnp.h>
  102 #endif
  103 
  104 #endif
  105 
  106 #define disable_intr()  0
  107 #define enable_intr()   0
  108 
  109 #ifdef SMP
  110 #define disable_intr()  COM_DISABLE_INTR()
  111 #define enable_intr()   COM_ENABLE_INTR()
  112 #endif /* SMP */
  113 
  114 #ifndef EXTRA_SIO
  115 #if NPNP > 0
  116 #define EXTRA_SIO MAX_PNP_CARDS
  117 #else
  118 #define EXTRA_SIO 0
  119 #endif
  120 #endif
  121 
  122 #define NSIOTOT (NSIO + EXTRA_SIO)
  123 
  124 #define LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
  125 #define RS_IBUFSIZE     256
  126 
  127 #define CALLOUT_MASK            0x80
  128 #define CONTROL_MASK            0x60
  129 #define CONTROL_INIT_STATE      0x20
  130 #define CONTROL_LOCK_STATE      0x40
  131 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
  132 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
  133 #define MINOR_TO_UNIT(mynor)    ((mynor) & ~MINOR_MAGIC_MASK)
  134 
  135 #ifdef COM_MULTIPORT
  136 /* checks in flags for multiport and which is multiport "master chip"
  137  * for a given card
  138  */
  139 #define COM_ISMULTIPORT(flags)  ((flags) & 0x01)
  140 #define COM_MPMASTER(flags)     (((flags) >> 8) & 0x0ff)
  141 #define COM_NOTAST4(flags)      ((flags) & 0x04)
  142 #endif /* COM_MULTIPORT */
  143 
  144 #define COM_CONSOLE(flags)      ((flags) & 0x10)
  145 #define COM_FORCECONSOLE(flags) ((flags) & 0x20)
  146 #define COM_LLCONSOLE(flags)    ((flags) & 0x40)
  147 #define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
  148 #define COM_NOFIFO(flags)               ((flags) & 0x02)
  149 #define COM_ST16650A(flags)     ((flags) & 0x20000)
  150 #define COM_C_NOPROBE           (0x40000)
  151 #define COM_NOPROBE(flags)      ((flags) & COM_C_NOPROBE)
  152 #define COM_C_IIR_TXRDYBUG      (0x80000)
  153 #define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
  154 #define COM_FIFOSIZE(flags)     (((flags) & 0xff000000) >> 24)
  155 
  156 #define com_scr         7       /* scratch register for 16450-16550 (R/W) */
  157 
  158 /*
  159  * Input buffer watermarks.
  160  * The external device is asked to stop sending when the buffer exactly reaches
  161  * high water, or when the high level requests it.
  162  * The high level is notified immediately (rather than at a later clock tick)
  163  * when this watermark is reached.
  164  * The buffer size is chosen so the watermark should almost never be reached.
  165  * The low watermark is invisibly 0 since the buffer is always emptied all at
  166  * once.
  167  */
  168 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
  169 
  170 /*
  171  * com state bits.
  172  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
  173  * than the other bits so that they can be tested as a group without masking
  174  * off the low bits.
  175  *
  176  * The following com and tty flags correspond closely:
  177  *      CS_BUSY         = TS_BUSY (maintained by comstart(), siopoll() and
  178  *                                 siostop())
  179  *      CS_TTGO         = ~TS_TTSTOP (maintained by comparam() and comstart())
  180  *      CS_CTS_OFLOW    = CCTS_OFLOW (maintained by comparam())
  181  *      CS_RTS_IFLOW    = CRTS_IFLOW (maintained by comparam())
  182  * TS_FLUSH is not used.
  183  * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
  184  * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
  185  */
  186 #define CS_BUSY         0x80    /* output in progress */
  187 #define CS_TTGO         0x40    /* output not stopped by XOFF */
  188 #define CS_ODEVREADY    0x20    /* external device h/w ready (CTS) */
  189 #define CS_CHECKMSR     1       /* check of MSR scheduled */
  190 #define CS_CTS_OFLOW    2       /* use CTS output flow control */
  191 #define CS_DTR_OFF      0x10    /* DTR held off */
  192 #define CS_ODONE        4       /* output completed */
  193 #define CS_RTS_IFLOW    8       /* use RTS input flow control */
  194 #define CSE_BUSYCHECK   1       /* siobusycheck() scheduled */
  195 
  196 static  char const * const      error_desc[] = {
  197 #define CE_OVERRUN                      0
  198         "silo overflow",
  199 #define CE_INTERRUPT_BUF_OVERFLOW       1
  200         "interrupt-level buffer overflow",
  201 #define CE_TTY_BUF_OVERFLOW             2
  202         "tty-level buffer overflow",
  203 };
  204 
  205 #define CE_NTYPES                       3
  206 #define CE_RECORD(com, errnum)          (++(com)->delta_error_counts[errnum])
  207 
  208 /* types.  XXX - should be elsewhere */
  209 typedef u_int   Port_t;         /* hardware port */
  210 typedef u_char  bool_t;         /* boolean */
  211 
  212 /* queue of linear buffers */
  213 struct lbq {
  214         u_char  *l_head;        /* next char to process */
  215         u_char  *l_tail;        /* one past the last char to process */
  216         struct lbq *l_next;     /* next in queue */
  217         bool_t  l_queued;       /* nonzero if queued */
  218 };
  219 
  220 /* com device structure */
  221 struct com_s {
  222         u_int   flags;          /* Copy isa device flags */
  223         u_char  state;          /* miscellaneous flag bits */
  224         bool_t  active_out;     /* nonzero if the callout device is open */
  225         u_char  cfcr_image;     /* copy of value written to CFCR */
  226 #ifdef COM_ESP
  227         bool_t  esp;            /* is this unit a hayes esp board? */
  228 #endif
  229         u_char  extra_state;    /* more flag bits, separate for order trick */
  230         u_char  fifo_image;     /* copy of value written to FIFO */
  231         bool_t  hasfifo;        /* nonzero for 16550 UARTs */
  232         bool_t  st16650a;       /* Is a Startech 16650A or RTS/CTS compat */
  233         bool_t  loses_outints;  /* nonzero if device loses output interrupts */
  234         u_char  mcr_image;      /* copy of value written to MCR */
  235 #ifdef COM_MULTIPORT
  236         bool_t  multiport;      /* is this unit part of a multiport device? */
  237 #endif /* COM_MULTIPORT */
  238         bool_t  no_irq;         /* nonzero if irq is not attached */
  239         bool_t  gone;           /* hardware disappeared */
  240         bool_t  poll;           /* nonzero if polling is required */
  241         bool_t  poll_output;    /* nonzero if polling for output is required */
  242         int     unit;           /* unit number */
  243         int     dtr_wait;       /* time to hold DTR down on close (* 1/hz) */
  244         u_int   tx_fifo_size;
  245         u_int   wopeners;       /* # processes waiting for DCD in open() */
  246 
  247         /*
  248          * The high level of the driver never reads status registers directly
  249          * because there would be too many side effects to handle conveniently.
  250          * Instead, it reads copies of the registers stored here by the
  251          * interrupt handler.
  252          */
  253         u_char  last_modem_status;      /* last MSR read by intr handler */
  254         u_char  prev_modem_status;      /* last MSR handled by high level */
  255 
  256         u_char  hotchar;        /* ldisc-specific char to be handled ASAP */
  257         u_char  *ibuf;          /* start of input buffer */
  258         u_char  *ibufend;       /* end of input buffer */
  259         u_char  *ihighwater;    /* threshold in input buffer */
  260         u_char  *iptr;          /* next free spot in input buffer */
  261 
  262         struct lbq      obufq;  /* head of queue of output buffers */
  263         struct lbq      obufs[2];       /* output buffers */
  264 
  265         Port_t  data_port;      /* i/o ports */
  266 #ifdef COM_ESP
  267         Port_t  esp_port;
  268 #endif
  269         Port_t  int_id_port;
  270         Port_t  iobase;
  271         Port_t  modem_ctl_port;
  272         Port_t  line_status_port;
  273         Port_t  modem_status_port;
  274         Port_t  intr_ctl_port;  /* Ports of IIR register */
  275 
  276         struct tty      *tp;    /* cross reference */
  277 
  278         /* Initial state. */
  279         struct termios  it_in;  /* should be in struct tty */
  280         struct termios  it_out;
  281 
  282         /* Lock state. */
  283         struct termios  lt_in;  /* should be in struct tty */
  284         struct termios  lt_out;
  285 
  286         bool_t  do_timestamp;
  287         bool_t  do_dcd_timestamp;
  288         struct timeval  timestamp;
  289         struct timeval  dcd_timestamp;
  290 
  291         u_long  bytes_in;       /* statistics */
  292         u_long  bytes_out;
  293         u_int   delta_error_counts[CE_NTYPES];
  294         u_long  error_counts[CE_NTYPES];
  295 
  296         /*
  297          * Ping-pong input buffers.  The extra factor of 2 in the sizes is
  298          * to allow for an error byte for each input byte.
  299          */
  300 #define CE_INPUT_OFFSET         RS_IBUFSIZE
  301         u_char  ibuf1[2 * RS_IBUFSIZE];
  302         u_char  ibuf2[2 * RS_IBUFSIZE];
  303 
  304         /*
  305          * Data area for output buffers.  Someday we should build the output
  306          * buffer queue without copying data.
  307          */
  308         u_char  obuf1[256];
  309         u_char  obuf2[256];
  310 #ifdef DEVFS
  311         void    *devfs_token_ttyd;
  312         void    *devfs_token_ttyl;
  313         void    *devfs_token_ttyi;
  314         void    *devfs_token_cuaa;
  315         void    *devfs_token_cual;
  316         void    *devfs_token_cuai;
  317 #endif
  318 };
  319 
  320 #ifdef COM_ESP
  321 static  int     espattach       __P((struct isa_device *isdp, struct com_s *com,
  322                                      Port_t esp_port));
  323 #endif
  324 static  int     sioattach       __P((device_t dev));
  325 
  326 static  timeout_t siobusycheck;
  327 static  timeout_t siodtrwakeup;
  328 static  void    comhardclose    __P((struct com_s *com));
  329 static  void    siointr1        __P((struct com_s *com));
  330 static  void    siointr         __P((void *arg));
  331 static  int     commctl         __P((struct com_s *com, int bits, int how));
  332 static  int     comparam        __P((struct tty *tp, struct termios *t));
  333 static  swihand_t siopoll;
  334 static  int     sioprobe        __P((device_t dev));
  335 static  void    siosettimeout   __P((void));
  336 static  void    comstart        __P((struct tty *tp));
  337 static  timeout_t comwakeup;
  338 static  void    disc_optim      __P((struct tty *tp, struct termios *t,
  339                                      struct com_s *com));
  340 
  341 #ifdef DSI_SOFT_MODEM
  342 static  int     LoadSoftModem   __P((int unit,int base_io, u_long size, u_char *ptr));
  343 #endif /* DSI_SOFT_MODEM */
  344 
  345 static char driver_name[] = "sio";
  346 
  347 /* table and macro for fast conversion from a unit number to its com struct */
  348 static  devclass_t      sio_devclass;
  349 #define com_addr(unit)  ((struct com_s *) \
  350                          devclass_get_softc(sio_devclass, unit))
  351 
  352 static device_method_t sio_methods[] = {
  353         /* Device interface */
  354         DEVMETHOD(device_probe,         sioprobe),
  355         DEVMETHOD(device_attach,        sioattach),
  356 
  357         { 0, 0 }
  358 };
  359 
  360 static driver_t sio_driver = {
  361         driver_name,
  362         sio_methods,
  363         DRIVER_TYPE_TTY,
  364         sizeof(struct com_s),
  365 };
  366 
  367 static  d_open_t        sioopen;
  368 static  d_close_t       sioclose;
  369 static  d_read_t        sioread;
  370 static  d_write_t       siowrite;
  371 static  d_ioctl_t       sioioctl;
  372 static  d_stop_t        siostop;
  373 static  d_devtotty_t    siodevtotty;
  374 
  375 #define CDEV_MAJOR      28
  376 static  struct cdevsw   sio_cdevsw = {
  377         sioopen,        sioclose,       sioread,        siowrite,
  378         sioioctl,       siostop,        noreset,        siodevtotty,
  379         ttpoll,         nommap,         NULL,           driver_name,
  380         NULL,           -1,             nodump,         nopsize,
  381         D_TTY,
  382 };
  383 
  384 int     comconsole = -1;
  385 static  volatile speed_t        comdefaultrate = CONSPEED;
  386 static  volatile speed_t        gdbdefaultrate = CONSPEED;
  387 static  u_int   com_events;     /* input chars + weighted output completions */
  388 static  Port_t  siocniobase;
  389 static  Port_t  siogdbiobase;
  390 static  bool_t  sio_registered;
  391 static  int     sio_timeout;
  392 static  int     sio_timeouts_until_log;
  393 static  struct  callout_handle sio_timeout_handle
  394     = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
  395 #if 0 /* XXX */
  396 static struct tty       *sio_tty[NSIOTOT];
  397 #else
  398 static struct tty       sio_tty[NSIOTOT];
  399 #endif
  400 static  const int       nsio_tty = NSIOTOT;
  401 
  402 static  struct speedtab comspeedtab[] = {
  403         { 0,            0 },
  404         { 50,           COMBRD(50) },
  405         { 75,           COMBRD(75) },
  406         { 110,          COMBRD(110) },
  407         { 134,          COMBRD(134) },
  408         { 150,          COMBRD(150) },
  409         { 200,          COMBRD(200) },
  410         { 300,          COMBRD(300) },
  411         { 600,          COMBRD(600) },
  412         { 1200,         COMBRD(1200) },
  413         { 1800,         COMBRD(1800) },
  414         { 2400,         COMBRD(2400) },
  415         { 4800,         COMBRD(4800) },
  416         { 9600,         COMBRD(9600) },
  417         { 19200,        COMBRD(19200) },
  418         { 38400,        COMBRD(38400) },
  419         { 57600,        COMBRD(57600) },
  420         { 115200,       COMBRD(115200) },
  421         { -1,           -1 }
  422 };
  423 
  424 #ifdef COM_ESP
  425 /* XXX configure this properly. */
  426 static  Port_t  likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
  427 static  Port_t  likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
  428 #endif
  429 
  430 /*
  431  * handle sysctl read/write requests for console speed
  432  * 
  433  * In addition to setting comdefaultrate for I/O through /dev/console,
  434  * also set the initial and lock values for the /dev/ttyXX device
  435  * if there is one associated with the console.  Finally, if the /dev/tty
  436  * device has already been open, change the speed on the open running port
  437  * itself.
  438  */
  439 
  440 static int
  441 sysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS
  442 {
  443         int error, s;
  444         speed_t newspeed;
  445         struct com_s *com;
  446         struct tty *tp;
  447 
  448         newspeed = comdefaultrate;
  449 
  450         error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
  451         if (error || !req->newptr)
  452                 return (error);
  453 
  454         comdefaultrate = newspeed;
  455 
  456         if (comconsole < 0)             /* serial console not selected? */
  457                 return (0);
  458 
  459         com = com_addr(comconsole);
  460         if (!com)
  461                 return (ENXIO);
  462 
  463         /*
  464          * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
  465          * (note, the lock rates really are boolean -- if non-zero, disallow
  466          *  speed changes)
  467          */
  468         com->it_in.c_ispeed  = com->it_in.c_ospeed =
  469         com->lt_in.c_ispeed  = com->lt_in.c_ospeed =
  470         com->it_out.c_ispeed = com->it_out.c_ospeed =
  471         com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate;
  472 
  473         /*
  474          * if we're open, change the running rate too
  475          */
  476         tp = com->tp;
  477         if (tp && (tp->t_state & TS_ISOPEN)) {
  478                 tp->t_termios.c_ispeed =
  479                 tp->t_termios.c_ospeed = comdefaultrate;
  480                 s = spltty();
  481                 error = comparam(tp, &tp->t_termios);
  482                 splx(s);
  483         }
  484         return error;
  485 }
  486 
  487 SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
  488             0, 0, sysctl_machdep_comdefaultrate, "I", "");
  489 
  490 #if NCARD > 0
  491 /*
  492  *      PC-Card (PCMCIA) specific code.
  493  */
  494 static int      sioinit         __P((struct pccard_devinfo *));
  495 static void     siounload       __P((struct pccard_devinfo *));
  496 static int      card_intr       __P((struct pccard_devinfo *));
  497 
  498 PCCARD_MODULE(sio, sioinit, siounload, card_intr, 0, tty_imask);
  499 
  500 /*
  501  *      Initialize the device - called from Slot manager.
  502  */
  503 int
  504 sioinit(struct pccard_devinfo *devi)
  505 {
  506 
  507         /* validate unit number. */
  508         if (devi->isahd.id_unit >= (NSIOTOT))
  509                 return(ENODEV);
  510         /* Make sure it isn't already probed. */
  511         if (com_addr(devi->isahd.id_unit))
  512                 return(EBUSY);
  513 
  514         /* It's already probed as serial by Upper */
  515         devi->isahd.id_flags |= COM_C_NOPROBE; 
  516 
  517         /*
  518          * Probe the device. If a value is returned, the
  519          * device was found at the location.
  520          */
  521         if (sioprobe(&devi->isahd) == 0)
  522                 return(ENXIO);
  523         if (sioattach(&devi->isahd) == 0)
  524                 return(ENXIO);
  525 
  526         return(0);
  527 }
  528 
  529 /*
  530  *      siounload - unload the driver and clear the table.
  531  *      XXX TODO:
  532  *      This is usually called when the card is ejected, but
  533  *      can be caused by a modunload of a controller driver.
  534  *      The idea is to reset the driver's view of the device
  535  *      and ensure that any driver entry points such as
  536  *      read and write do not hang.
  537  */
  538 static void
  539 siounload(struct pccard_devinfo *devi)
  540 {
  541         struct com_s    *com;
  542 
  543         if (!devi) {
  544                 printf("NULL devi in siounload\n");
  545                 return;
  546         }
  547         com = com_addr(devi->isahd.id_unit);
  548         if (!com) {
  549                 printf("NULL com in siounload\n");
  550                 return;
  551         }
  552         if (!com->iobase) {
  553                 printf("sio%d already unloaded!\n",devi->isahd.id_unit);
  554                 return;
  555         }
  556         if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
  557                 com->gone = 1;
  558                 printf("sio%d: unload\n", devi->isahd.id_unit);
  559                 com->tp->t_gen++;
  560                 ttyclose(com->tp);
  561                 ttwakeup(com->tp);
  562                 ttwwakeup(com->tp);
  563         } else {
  564                 com_addr(com->unit) = NULL;
  565                 bzero(com, sizeof *com);
  566                 free(com,M_TTYS);
  567                 printf("sio%d: unload,gone\n", devi->isahd.id_unit);
  568         }
  569 }
  570 
  571 /*
  572  *      card_intr - Shared interrupt called from
  573  *      front end of PC-Card handler.
  574  */
  575 static int
  576 card_intr(struct pccard_devinfo *devi)
  577 {
  578         struct com_s    *com;
  579 
  580         COM_LOCK();
  581         com = com_addr(devi->isahd.id_unit);
  582         if (com && !com->gone)
  583                 siointr1(com_addr(devi->isahd.id_unit));
  584         COM_UNLOCK();
  585         return(1);
  586 }
  587 #endif /* NCARD > 0 */
  588 
  589 #define SET_FLAG(dev, bit)      isa_set_flags(dev, isa_get_flags(dev) | (bit))
  590 #define CLR_FLAG(dev, bit)      isa_set_flags(dev, isa_get_flags(dev) & ~(bit))
  591 
  592 static int
  593 sioprobe(dev)
  594         device_t        dev;
  595 {
  596         static bool_t   already_init;
  597         bool_t          failures[10];
  598         int             fn;
  599         device_t        idev;
  600         Port_t          iobase;
  601         intrmask_t      irqmap[4];
  602         intrmask_t      irqs;
  603         u_char          mcr_image;
  604         int             result;
  605         device_t        xdev;
  606         u_int           flags = isa_get_flags(dev);
  607 
  608         if (!already_init) {
  609                 /*
  610                  * Turn off MCR_IENABLE for all likely serial ports.  An unused
  611                  * port with its MCR_IENABLE gate open will inhibit interrupts
  612                  * from any used port that shares the interrupt vector.
  613                  * XXX the gate enable is elsewhere for some multiports.
  614                  */
  615                 device_t *devs;
  616                 int count, i;
  617 
  618                 devclass_get_devices(sio_devclass, &devs, &count);
  619                 for (i = 0; i < count; i++) {
  620                         xdev = devs[i];
  621                         outb(isa_get_port(xdev) + com_mcr, 0);
  622                 }
  623                 free(devs, M_TEMP);
  624                 already_init = TRUE;
  625         }
  626 
  627         if (COM_LLCONSOLE(flags)) {
  628                 printf("sio%d: reserved for low-level i/o\n",
  629                        device_get_unit(dev));
  630                 return (ENXIO);
  631         }
  632 
  633         /*
  634          * If the device is on a multiport card and has an AST/4
  635          * compatible interrupt control register, initialize this
  636          * register and prepare to leave MCR_IENABLE clear in the mcr.
  637          * Otherwise, prepare to set MCR_IENABLE in the mcr.
  638          * Point idev to the device struct giving the correct id_irq.
  639          * This is the struct for the master device if there is one.
  640          */
  641         idev = dev;
  642         mcr_image = MCR_IENABLE;
  643 #ifdef COM_MULTIPORT
  644         if (COM_ISMULTIPORT(flags)) {
  645                 idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags));
  646                 if (idev == NULL) {
  647                         printf("sio%d: master device %d not configured\n",
  648                                device_get_unit(dev), COM_MPMASTER(flags));
  649                         isa_set_irq(dev, 0);
  650                         idev = dev;
  651                 }
  652                 if (!COM_NOTAST4(flags)) {
  653                         outb(isa_get_port(idev) + com_scr,
  654                              isa_get_irq(idev) >= 0 ? 0x80 : 0);
  655                         mcr_image = 0;
  656                 }
  657         }
  658 #endif /* COM_MULTIPORT */
  659         if (isa_get_irq(idev) < 0)
  660                 mcr_image = 0;
  661 
  662         bzero(failures, sizeof failures);
  663         iobase = isa_get_port(dev);
  664 
  665         /*
  666          * We don't want to get actual interrupts, just masked ones.
  667          * Interrupts from this line should already be masked in the ICU,
  668          * but mask them in the processor as well in case there are some
  669          * (misconfigured) shared interrupts.
  670          */
  671         disable_intr();
  672 /* EXTRA DELAY? */
  673 
  674         /*
  675          * Initialize the speed and the word size and wait long enough to
  676          * drain the maximum of 16 bytes of junk in device output queues.
  677          * The speed is undefined after a master reset and must be set
  678          * before relying on anything related to output.  There may be
  679          * junk after a (very fast) soft reboot and (apparently) after
  680          * master reset.
  681          * XXX what about the UART bug avoided by waiting in comparam()?
  682          * We don't want to to wait long enough to drain at 2 bps.
  683          */
  684         if (iobase == siocniobase)
  685                 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
  686         else {
  687                 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
  688                 outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
  689                 outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
  690                 outb(iobase + com_cfcr, CFCR_8BITS);
  691                 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
  692         }
  693 
  694         /*
  695          * Enable the interrupt gate and disable device interupts.  This
  696          * should leave the device driving the interrupt line low and
  697          * guarantee an edge trigger if an interrupt can be generated.
  698          */
  699 /* EXTRA DELAY? */
  700         outb(iobase + com_mcr, mcr_image);
  701         outb(iobase + com_ier, 0);
  702         DELAY(1000);            /* XXX */
  703         irqmap[0] = isa_irq_pending();
  704 
  705         /*
  706          * Attempt to set loopback mode so that we can send a null byte
  707          * without annoying any external device.
  708          */
  709 /* EXTRA DELAY? */
  710         outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
  711 
  712         /*
  713          * Attempt to generate an output interrupt.  On 8250's, setting
  714          * IER_ETXRDY generates an interrupt independent of the current
  715          * setting and independent of whether the THR is empty.  On 16450's,
  716          * setting IER_ETXRDY generates an interrupt independent of the
  717          * current setting.  On 16550A's, setting IER_ETXRDY only
  718          * generates an interrupt when IER_ETXRDY is not already set.
  719          */
  720         outb(iobase + com_ier, IER_ETXRDY);
  721 
  722         /*
  723          * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
  724          * an interrupt.  They'd better generate one for actually doing
  725          * output.  Loopback may be broken on the same incompatibles but
  726          * it's unlikely to do more than allow the null byte out.
  727          */
  728         outb(iobase + com_data, 0);
  729         DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
  730 
  731         /*
  732          * Turn off loopback mode so that the interrupt gate works again
  733          * (MCR_IENABLE was hidden).  This should leave the device driving
  734          * an interrupt line high.  It doesn't matter if the interrupt
  735          * line oscillates while we are not looking at it, since interrupts
  736          * are disabled.
  737          */
  738 /* EXTRA DELAY? */
  739         outb(iobase + com_mcr, mcr_image);
  740 
  741     /*
  742          * It's a definitly Serial PCMCIA(16550A), but still be required
  743          * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
  744          */
  745         if ( COM_NOPROBE(flags) ) {
  746                 /* Reading IIR register twice */
  747                 for ( fn = 0; fn < 2; fn ++ ) {
  748                         DELAY(10000);
  749                         failures[6] = inb(iobase + com_iir);
  750                 }
  751                 /* Check IIR_TXRDY clear ? */
  752                 isa_set_portsize(dev, IO_COMSIZE);
  753                 result = 0;
  754                 if ( failures[6] & IIR_TXRDY ) {
  755                         /* Nop, Double check with clearing IER */
  756                         outb(iobase + com_ier, 0);
  757                         if ( inb(iobase + com_iir) & IIR_NOPEND ) {
  758                                 /* Ok. we're familia this gang */
  759                                 SET_FLAG(dev, COM_C_IIR_TXRDYBUG); /* Set IIR_TXRDYBUG */
  760                         } else {
  761                                 /* Unknow, Just omit this chip.. XXX*/
  762                                 result = ENXIO;
  763                         }
  764                 } else {
  765                         /* OK. this is well-known guys */
  766                         CLR_FLAG(dev, COM_C_IIR_TXRDYBUG); /*Clear IIR_TXRDYBUG*/
  767                 }
  768                 outb(iobase + com_cfcr, CFCR_8BITS);
  769                 enable_intr();
  770                 return (iobase == siocniobase ? 0 : result);
  771         }
  772 
  773         /*
  774          * Check that
  775          *      o the CFCR, IER and MCR in UART hold the values written to them
  776          *        (the values happen to be all distinct - this is good for
  777          *        avoiding false positive tests from bus echoes).
  778          *      o an output interrupt is generated and its vector is correct.
  779          *      o the interrupt goes away when the IIR in the UART is read.
  780          */
  781 /* EXTRA DELAY? */
  782         failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
  783         failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
  784         failures[2] = inb(iobase + com_mcr) - mcr_image;
  785         DELAY(10000);           /* Some internal modems need this time */
  786         irqmap[1] = isa_irq_pending();
  787         failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
  788         DELAY(1000);            /* XXX */
  789         irqmap[2] = isa_irq_pending();
  790         failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
  791 
  792         /*
  793          * Turn off all device interrupts and check that they go off properly.
  794          * Leave MCR_IENABLE alone.  For ports without a master port, it gates
  795          * the OUT2 output of the UART to
  796          * the ICU input.  Closing the gate would give a floating ICU input
  797          * (unless there is another device driving at) and spurious interrupts.
  798          * (On the system that this was first tested on, the input floats high
  799          * and gives a (masked) interrupt as soon as the gate is closed.)
  800          */
  801         outb(iobase + com_ier, 0);
  802         outb(iobase + com_cfcr, CFCR_8BITS);    /* dummy to avoid bus echo */
  803         failures[7] = inb(iobase + com_ier);
  804         DELAY(1000);            /* XXX */
  805         irqmap[3] = isa_irq_pending();
  806         failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
  807 
  808         enable_intr();
  809 
  810         irqs = irqmap[1] & ~irqmap[0];
  811         if (isa_get_irq(idev) >= 0 && ((1 << isa_get_irq(idev)) & irqs) == 0)
  812                 printf(
  813                 "sio%d: configured irq %d not in bitmap of probed irqs %#x\n",
  814                     device_get_unit(dev), isa_get_irq(idev), irqs);
  815         if (bootverbose)
  816                 printf("sio%d: irq maps: %#x %#x %#x %#x\n",
  817                     device_get_unit(dev),
  818                     irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
  819 
  820         isa_set_portsize(dev, IO_COMSIZE);
  821         result = 0;
  822         for (fn = 0; fn < sizeof failures; ++fn)
  823                 if (failures[fn]) {
  824                         outb(iobase + com_mcr, 0);
  825                         result = ENXIO;
  826                         if (bootverbose) {
  827                                 printf("sio%d: probe failed test(s):",
  828                                     device_get_unit(dev));
  829                                 for (fn = 0; fn < sizeof failures; ++fn)
  830                                         if (failures[fn])
  831                                                 printf(" %d", fn);
  832                                 printf("\n");
  833                         }
  834                         break;
  835                 }
  836         return (iobase == siocniobase ? 0 : result);
  837 }
  838 
  839 #ifdef COM_ESP
  840 static int
  841 espattach(isdp, com, esp_port)
  842         struct isa_device       *isdp;
  843         struct com_s            *com;
  844         Port_t                  esp_port;
  845 {
  846         u_char  dips;
  847         u_char  val;
  848 
  849         /*
  850          * Check the ESP-specific I/O port to see if we're an ESP
  851          * card.  If not, return failure immediately.
  852          */
  853         if ((inb(esp_port) & 0xf3) == 0) {
  854                 printf(" port 0x%x is not an ESP board?\n", esp_port);
  855                 return (0);
  856         }
  857 
  858         /*
  859          * We've got something that claims to be a Hayes ESP card.
  860          * Let's hope so.
  861          */
  862 
  863         /* Get the dip-switch configuration */
  864         outb(esp_port + ESP_CMD1, ESP_GETDIPS);
  865         dips = inb(esp_port + ESP_STATUS1);
  866 
  867         /*
  868          * Bits 0,1 of dips say which COM port we are.
  869          */
  870         if (com->iobase == likely_com_ports[dips & 0x03])
  871                 printf(" : ESP");
  872         else {
  873                 printf(" esp_port has com %d\n", dips & 0x03);
  874                 return (0);
  875         }
  876 
  877         /*
  878          * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
  879          */
  880         outb(esp_port + ESP_CMD1, ESP_GETTEST);
  881         val = inb(esp_port + ESP_STATUS1);      /* clear reg 1 */
  882         val = inb(esp_port + ESP_STATUS2);
  883         if ((val & 0x70) < 0x20) {
  884                 printf("-old (%o)", val & 0x70);
  885                 return (0);
  886         }
  887 
  888         /*
  889          * Check for ability to emulate 16550:  bit 7 == 1
  890          */
  891         if ((dips & 0x80) == 0) {
  892                 printf(" slave");
  893                 return (0);
  894         }
  895 
  896         /*
  897          * Okay, we seem to be a Hayes ESP card.  Whee.
  898          */
  899         com->esp = TRUE;
  900         com->esp_port = esp_port;
  901         return (1);
  902 }
  903 #endif /* COM_ESP */
  904 
  905 static int
  906 sioattach(dev)
  907         device_t        dev;
  908 {
  909         struct com_s    *com;
  910 #ifdef COM_ESP
  911         Port_t          *espp;
  912 #endif
  913         Port_t          iobase;
  914         int             s;
  915         int             unit;
  916         void            *ih;
  917         struct resource *res;
  918         int             zero = 0;
  919         u_int           flags = isa_get_flags(dev);
  920 
  921 #if 0
  922         isdp->id_ri_flags |= RI_FAST;
  923 #endif
  924         iobase = isa_get_port(dev);
  925         unit = device_get_unit(dev);
  926         com = device_get_softc(dev);
  927 
  928         /*
  929          * sioprobe() has initialized the device registers as follows:
  930          *      o cfcr = CFCR_8BITS.
  931          *        It is most important that CFCR_DLAB is off, so that the
  932          *        data port is not hidden when we enable interrupts.
  933          *      o ier = 0.
  934          *        Interrupts are only enabled when the line is open.
  935          *      o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
  936          *        interrupt control register or the config specifies no irq.
  937          *        Keeping MCR_DTR and MCR_RTS off might stop the external
  938          *        device from sending before we are ready.
  939          */
  940         bzero(com, sizeof *com);
  941         com->unit = unit;
  942         com->cfcr_image = CFCR_8BITS;
  943         com->dtr_wait = 3 * hz;
  944         com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
  945         com->no_irq = isa_get_irq(dev) < 0;
  946         com->tx_fifo_size = 1;
  947         com->iptr = com->ibuf = com->ibuf1;
  948         com->ibufend = com->ibuf1 + RS_IBUFSIZE;
  949         com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
  950         com->obufs[0].l_head = com->obuf1;
  951         com->obufs[1].l_head = com->obuf2;
  952 
  953         com->iobase = iobase;
  954         com->data_port = iobase + com_data;
  955         com->int_id_port = iobase + com_iir;
  956         com->modem_ctl_port = iobase + com_mcr;
  957         com->mcr_image = inb(com->modem_ctl_port);
  958         com->line_status_port = iobase + com_lsr;
  959         com->modem_status_port = iobase + com_msr;
  960         com->intr_ctl_port = iobase + com_ier;
  961 
  962         /*
  963          * We don't use all the flags from <sys/ttydefaults.h> since they
  964          * are only relevant for logins.  It's important to have echo off
  965          * initially so that the line doesn't start blathering before the
  966          * echo flag can be turned off.
  967          */
  968         com->it_in.c_iflag = 0;
  969         com->it_in.c_oflag = 0;
  970         com->it_in.c_cflag = TTYDEF_CFLAG;
  971         com->it_in.c_lflag = 0;
  972         if (unit == comconsole) {
  973                 com->it_in.c_iflag = TTYDEF_IFLAG;
  974                 com->it_in.c_oflag = TTYDEF_OFLAG;
  975                 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
  976                 com->it_in.c_lflag = TTYDEF_LFLAG;
  977                 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
  978                 com->lt_out.c_ispeed = com->lt_out.c_ospeed =
  979                 com->lt_in.c_ispeed = com->lt_in.c_ospeed =
  980                 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
  981         } else
  982                 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
  983         termioschars(&com->it_in);
  984         com->it_out = com->it_in;
  985 
  986         /* attempt to determine UART type */
  987         printf("sio%d: type", unit);
  988 
  989 #ifdef DSI_SOFT_MODEM
  990         if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) {
  991             printf(" Digicom Systems, Inc. SoftModem");
  992         goto determined_type;
  993         }
  994 #endif /* DSI_SOFT_MODEM */
  995 
  996 #ifdef COM_MULTIPORT
  997         if (!COM_ISMULTIPORT(flags) && !COM_IIR_TXRDYBUG(flags))
  998 #else
  999         if (!COM_IIR_TXRDYBUG(flags))
 1000 #endif
 1001         {
 1002                 u_char  scr;
 1003                 u_char  scr1;
 1004                 u_char  scr2;
 1005 
 1006                 scr = inb(iobase + com_scr);
 1007                 outb(iobase + com_scr, 0xa5);
 1008                 scr1 = inb(iobase + com_scr);
 1009                 outb(iobase + com_scr, 0x5a);
 1010                 scr2 = inb(iobase + com_scr);
 1011                 outb(iobase + com_scr, scr);
 1012                 if (scr1 != 0xa5 || scr2 != 0x5a) {
 1013                         printf(" 8250");
 1014                         goto determined_type;
 1015                 }
 1016         }
 1017         outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
 1018         DELAY(100);
 1019         com->st16650a = 0;
 1020         switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
 1021         case FIFO_RX_LOW:
 1022                 printf(" 16450");
 1023                 break;
 1024         case FIFO_RX_MEDL:
 1025                 printf(" 16450?");
 1026                 break;
 1027         case FIFO_RX_MEDH:
 1028                 printf(" 16550?");
 1029                 break;
 1030         case FIFO_RX_HIGH:
 1031                 if (COM_NOFIFO(flags)) {
 1032                         printf(" 16550A fifo disabled");
 1033                 } else {
 1034                         com->hasfifo = TRUE;
 1035                         if (COM_ST16650A(flags)) {
 1036                                 com->st16650a = 1;
 1037                                 com->tx_fifo_size = 32;
 1038                                 printf(" ST16650A");
 1039                         } else {
 1040                                 com->tx_fifo_size = COM_FIFOSIZE(flags);
 1041                                 printf(" 16550A");
 1042                         }
 1043                 }
 1044 #ifdef COM_ESP
 1045                 for (espp = likely_esp_ports; *espp != 0; espp++)
 1046                         if (espattach(dev, com, *espp)) {
 1047                                 com->tx_fifo_size = 1024;
 1048                                 break;
 1049                         }
 1050 #endif
 1051                 if (!com->st16650a) {
 1052                         if (!com->tx_fifo_size)
 1053                                 com->tx_fifo_size = 16;
 1054                         else
 1055                                 printf(" lookalike with %d bytes FIFO",
 1056                                     com->tx_fifo_size);
 1057                 }
 1058 
 1059                 break;
 1060         }
 1061         
 1062 #ifdef COM_ESP
 1063         if (com->esp) {
 1064                 /*
 1065                  * Set 16550 compatibility mode.
 1066                  * We don't use the ESP_MODE_SCALE bit to increase the
 1067                  * fifo trigger levels because we can't handle large
 1068                  * bursts of input.
 1069                  * XXX flow control should be set in comparam(), not here.
 1070                  */
 1071                 outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
 1072                 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
 1073 
 1074                 /* Set RTS/CTS flow control. */
 1075                 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
 1076                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
 1077                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
 1078 
 1079                 /* Set flow-control levels. */
 1080                 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
 1081                 outb(com->esp_port + ESP_CMD2, HIBYTE(768));
 1082                 outb(com->esp_port + ESP_CMD2, LOBYTE(768));
 1083                 outb(com->esp_port + ESP_CMD2, HIBYTE(512));
 1084                 outb(com->esp_port + ESP_CMD2, LOBYTE(512));
 1085         }
 1086 #endif /* COM_ESP */
 1087         outb(iobase + com_fifo, 0);
 1088 determined_type: ;
 1089 
 1090 #ifdef COM_MULTIPORT
 1091         if (COM_ISMULTIPORT(flags)) {
 1092                 com->multiport = TRUE;
 1093                 printf(" (multiport");
 1094                 if (unit == COM_MPMASTER(flags))
 1095                         printf(" master");
 1096                 printf(")");
 1097                 com->no_irq =
 1098                         isa_get_irq(devclass_get_device
 1099                                     (sio_devclass, COM_MPMASTER(flags))) < 0;
 1100          }
 1101 #endif /* COM_MULTIPORT */
 1102         if (unit == comconsole)
 1103                 printf(", console");
 1104         if ( COM_IIR_TXRDYBUG(flags) )
 1105                 printf(" with a bogus IIR_TXRDY register");
 1106         printf("\n");
 1107 
 1108         if (!sio_registered) {
 1109                 register_swi(SWI_TTY, siopoll);
 1110                 sio_registered = TRUE;
 1111         }
 1112 #ifdef DEVFS
 1113         com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
 1114                 unit, DV_CHR,
 1115                 UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit);
 1116         com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
 1117                 unit | CONTROL_INIT_STATE, DV_CHR,
 1118                 UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit);
 1119         com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
 1120                 unit | CONTROL_LOCK_STATE, DV_CHR,
 1121                 UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit);
 1122         com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
 1123                 unit | CALLOUT_MASK, DV_CHR,
 1124                 UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit);
 1125         com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
 1126                 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
 1127                 UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit);
 1128         com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
 1129                 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
 1130                 UID_UUCP, GID_DIALER, 0660, "cuala%r", unit);
 1131 #endif
 1132         com->flags = isa_get_flags(dev); /* Heritate id_flags for later */
 1133 
 1134         res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, 0ul, ~0ul, 1,
 1135                                  RF_SHAREABLE | RF_ACTIVE);
 1136         BUS_SETUP_INTR(device_get_parent(dev), dev, res, siointr, com,
 1137                        &ih);
 1138 
 1139         return (0);
 1140 }
 1141 
 1142 static int
 1143 sioopen(dev, flag, mode, p)
 1144         dev_t           dev;
 1145         int             flag;
 1146         int             mode;
 1147         struct proc     *p;
 1148 {
 1149         struct com_s    *com;
 1150         int             error;
 1151         Port_t          iobase;
 1152         int             mynor;
 1153         int             s;
 1154         struct tty      *tp;
 1155         int             unit;
 1156 
 1157         mynor = minor(dev);
 1158         unit = MINOR_TO_UNIT(mynor);
 1159         if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL)
 1160                 return (ENXIO);
 1161         if (com->gone)
 1162                 return (ENXIO);
 1163         if (mynor & CONTROL_MASK)
 1164                 return (0);
 1165 #if 0 /* XXX */
 1166         tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
 1167 #else
 1168         tp = com->tp = &sio_tty[unit];
 1169 #endif
 1170         s = spltty();
 1171         /*
 1172          * We jump to this label after all non-interrupted sleeps to pick
 1173          * up any changes of the device state.
 1174          */
 1175 open_top:
 1176         while (com->state & CS_DTR_OFF) {
 1177                 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
 1178                 if (com_addr(unit) == NULL)
 1179                         return (ENXIO);
 1180                 if (error != 0 || com->gone)
 1181                         goto out;
 1182         }
 1183         if (tp->t_state & TS_ISOPEN) {
 1184                 /*
 1185                  * The device is open, so everything has been initialized.
 1186                  * Handle conflicts.
 1187                  */
 1188                 if (mynor & CALLOUT_MASK) {
 1189                         if (!com->active_out) {
 1190                                 error = EBUSY;
 1191                                 goto out;
 1192                         }
 1193                 } else {
 1194                         if (com->active_out) {
 1195                                 if (flag & O_NONBLOCK) {
 1196                                         error = EBUSY;
 1197                                         goto out;
 1198                                 }
 1199                                 error = tsleep(&com->active_out,
 1200                                                TTIPRI | PCATCH, "siobi", 0);
 1201                                 if (com_addr(unit) == NULL)
 1202                                         return (ENXIO);
 1203                                 if (error != 0 || com->gone)
 1204                                         goto out;
 1205                                 goto open_top;
 1206                         }
 1207                 }
 1208                 if (tp->t_state & TS_XCLUDE &&
 1209                     suser(p->p_ucred, &p->p_acflag)) {
 1210                         error = EBUSY;
 1211                         goto out;
 1212                 }
 1213         } else {
 1214                 /*
 1215                  * The device isn't open, so there are no conflicts.
 1216                  * Initialize it.  Initialization is done twice in many
 1217                  * cases: to preempt sleeping callin opens if we are
 1218                  * callout, and to complete a callin open after DCD rises.
 1219                  */
 1220                 tp->t_oproc = comstart;
 1221                 tp->t_param = comparam;
 1222                 tp->t_dev = dev;
 1223                 tp->t_termios = mynor & CALLOUT_MASK
 1224                                 ? com->it_out : com->it_in;
 1225                 tp->t_ififosize = 2 * RS_IBUFSIZE;
 1226                 tp->t_ispeedwat = (speed_t)-1;
 1227                 tp->t_ospeedwat = (speed_t)-1;
 1228                 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
 1229                 com->poll = com->no_irq;
 1230                 com->poll_output = com->loses_outints;
 1231                 ++com->wopeners;
 1232                 error = comparam(tp, &tp->t_termios);
 1233                 --com->wopeners;
 1234                 if (error != 0)
 1235                         goto out;
 1236                 /*
 1237                  * XXX we should goto open_top if comparam() slept.
 1238                  */
 1239                 iobase = com->iobase;
 1240                 if (com->hasfifo) {
 1241                         /*
 1242                          * (Re)enable and drain fifos.
 1243                          *
 1244                          * Certain SMC chips cause problems if the fifos
 1245                          * are enabled while input is ready.  Turn off the
 1246                          * fifo if necessary to clear the input.  We test
 1247                          * the input ready bit after enabling the fifos
 1248                          * since we've already enabled them in comparam()
 1249                          * and to handle races between enabling and fresh
 1250                          * input.
 1251                          */
 1252                         while (TRUE) {
 1253                                 outb(iobase + com_fifo,
 1254                                      FIFO_RCV_RST | FIFO_XMT_RST
 1255                                      | com->fifo_image);
 1256                                 /*
 1257                                  * XXX the delays are for superstitious
 1258                                  * historical reasons.  It must be less than
 1259                                  * the character time at the maximum
 1260                                  * supported speed (87 usec at 115200 bps
 1261                                  * 8N1).  Otherwise we might loop endlessly
 1262                                  * if data is streaming in.  We used to use
 1263                                  * delays of 100.  That usually worked
 1264                                  * because DELAY(100) used to usually delay
 1265                                  * for about 85 usec instead of 100.
 1266                                  */
 1267                                 DELAY(50);
 1268                                 if (!(inb(com->line_status_port) & LSR_RXRDY))
 1269                                         break;
 1270                                 outb(iobase + com_fifo, 0);
 1271                                 DELAY(50);
 1272                                 (void) inb(com->data_port);
 1273                         }
 1274                 }
 1275 
 1276                 disable_intr();
 1277                 (void) inb(com->line_status_port);
 1278                 (void) inb(com->data_port);
 1279                 com->prev_modem_status = com->last_modem_status
 1280                     = inb(com->modem_status_port);
 1281                 if (COM_IIR_TXRDYBUG(com->flags)) {
 1282                         outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
 1283                                                 | IER_EMSC);
 1284                 } else {
 1285                         outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
 1286                                                 | IER_ERLS | IER_EMSC);
 1287                 }
 1288                 enable_intr();
 1289                 /*
 1290                  * Handle initial DCD.  Callout devices get a fake initial
 1291                  * DCD (trapdoor DCD).  If we are callout, then any sleeping
 1292                  * callin opens get woken up and resume sleeping on "siobi"
 1293                  * instead of "siodcd".
 1294                  */
 1295                 /*
 1296                  * XXX `mynor & CALLOUT_MASK' should be
 1297                  * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
 1298                  * TRAPDOOR_CARRIER is the default initial state for callout
 1299                  * devices and SOFT_CARRIER is like CLOCAL except it hides
 1300                  * the true carrier.
 1301                  */
 1302                 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
 1303                         (*linesw[tp->t_line].l_modem)(tp, 1);
 1304         }
 1305         /*
 1306          * Wait for DCD if necessary.
 1307          */
 1308         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
 1309             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
 1310                 ++com->wopeners;
 1311                 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
 1312                 if (com_addr(unit) == NULL)
 1313                         return (ENXIO);
 1314                 --com->wopeners;
 1315                 if (error != 0 || com->gone)
 1316                         goto out;
 1317                 goto open_top;
 1318         }
 1319         error = (*linesw[tp->t_line].l_open)(dev, tp);
 1320         disc_optim(tp, &tp->t_termios, com);
 1321         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
 1322                 com->active_out = TRUE;
 1323         siosettimeout();
 1324 out:
 1325         splx(s);
 1326         if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
 1327                 comhardclose(com);
 1328         return (error);
 1329 }
 1330 
 1331 static int
 1332 sioclose(dev, flag, mode, p)
 1333         dev_t           dev;
 1334         int             flag;
 1335         int             mode;
 1336         struct proc     *p;
 1337 {
 1338         struct com_s    *com;
 1339         int             mynor;
 1340         int             s;
 1341         struct tty      *tp;
 1342 
 1343         mynor = minor(dev);
 1344         if (mynor & CONTROL_MASK)
 1345                 return (0);
 1346         com = com_addr(MINOR_TO_UNIT(mynor));
 1347         tp = com->tp;
 1348         s = spltty();
 1349         (*linesw[tp->t_line].l_close)(tp, flag);
 1350         disc_optim(tp, &tp->t_termios, com);
 1351         siostop(tp, FREAD | FWRITE);
 1352         comhardclose(com);
 1353         ttyclose(tp);
 1354         siosettimeout();
 1355         splx(s);
 1356         if (com->gone) {
 1357                 printf("sio%d: gone\n", com->unit);
 1358                 s = spltty();
 1359                 bzero(tp,sizeof *tp);
 1360                 bzero(com,sizeof *com);
 1361                 splx(s);
 1362         }
 1363         return (0);
 1364 }
 1365 
 1366 static void
 1367 comhardclose(com)
 1368         struct com_s    *com;
 1369 {
 1370         Port_t          iobase;
 1371         int             s;
 1372         struct tty      *tp;
 1373         int             unit;
 1374 
 1375         unit = com->unit;
 1376         iobase = com->iobase;
 1377         s = spltty();
 1378         com->poll = FALSE;
 1379         com->poll_output = FALSE;
 1380         com->do_timestamp = FALSE;
 1381         com->do_dcd_timestamp = FALSE;
 1382         outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
 1383         {
 1384                 outb(iobase + com_ier, 0);
 1385                 tp = com->tp;
 1386                 if (tp->t_cflag & HUPCL
 1387                     /*
 1388                      * XXX we will miss any carrier drop between here and the
 1389                      * next open.  Perhaps we should watch DCD even when the
 1390                      * port is closed; it is not sufficient to check it at
 1391                      * the next open because it might go up and down while
 1392                      * we're not watching.
 1393                      */
 1394                     || !com->active_out
 1395                        && !(com->prev_modem_status & MSR_DCD)
 1396                        && !(com->it_in.c_cflag & CLOCAL)
 1397                     || !(tp->t_state & TS_ISOPEN)) {
 1398                         (void)commctl(com, TIOCM_DTR, DMBIC);
 1399                         if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
 1400                                 timeout(siodtrwakeup, com, com->dtr_wait);
 1401                                 com->state |= CS_DTR_OFF;
 1402                         }
 1403                 }
 1404         }
 1405         if (com->hasfifo) {
 1406                 /*
 1407                  * Disable fifos so that they are off after controlled
 1408                  * reboots.  Some BIOSes fail to detect 16550s when the
 1409                  * fifos are enabled.
 1410                  */
 1411                 outb(iobase + com_fifo, 0);
 1412         }
 1413         com->active_out = FALSE;
 1414         wakeup(&com->active_out);
 1415         wakeup(TSA_CARR_ON(tp));        /* restart any wopeners */
 1416         splx(s);
 1417 }
 1418 
 1419 static int
 1420 sioread(dev, uio, flag)
 1421         dev_t           dev;
 1422         struct uio      *uio;
 1423         int             flag;
 1424 {
 1425         int             mynor;
 1426         int             unit;
 1427         struct tty      *tp;
 1428 
 1429         mynor = minor(dev);
 1430         if (mynor & CONTROL_MASK)
 1431                 return (ENODEV);
 1432         unit = MINOR_TO_UNIT(mynor);
 1433         if (com_addr(unit)->gone)
 1434                 return (ENODEV);
 1435         tp = com_addr(unit)->tp;
 1436         return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
 1437 }
 1438 
 1439 static int
 1440 siowrite(dev, uio, flag)
 1441         dev_t           dev;
 1442         struct uio      *uio;
 1443         int             flag;
 1444 {
 1445         int             mynor;
 1446         struct tty      *tp;
 1447         int             unit;
 1448 
 1449         mynor = minor(dev);
 1450         if (mynor & CONTROL_MASK)
 1451                 return (ENODEV);
 1452 
 1453         unit = MINOR_TO_UNIT(mynor);
 1454         if (com_addr(unit)->gone)
 1455                 return (ENODEV);
 1456         tp = com_addr(unit)->tp;
 1457         /*
 1458          * (XXX) We disallow virtual consoles if the physical console is
 1459          * a serial port.  This is in case there is a display attached that
 1460          * is not the console.  In that situation we don't need/want the X
 1461          * server taking over the console.
 1462          */
 1463         if (constty != NULL && unit == comconsole)
 1464                 constty = NULL;
 1465         return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
 1466 }
 1467 
 1468 static void
 1469 siobusycheck(chan)
 1470         void    *chan;
 1471 {
 1472         struct com_s    *com;
 1473         int             s;
 1474 
 1475         com = (struct com_s *)chan;
 1476 
 1477         /*
 1478          * Clear TS_BUSY if low-level output is complete.
 1479          * spl locking is sufficient because siointr1() does not set CS_BUSY.
 1480          * If siointr1() clears CS_BUSY after we look at it, then we'll get
 1481          * called again.  Reading the line status port outside of siointr1()
 1482          * is safe because CS_BUSY is clear so there are no output interrupts
 1483          * to lose.
 1484          */
 1485         s = spltty();
 1486         if (com->state & CS_BUSY)
 1487                 com->extra_state &= ~CSE_BUSYCHECK;     /* False alarm. */
 1488         else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
 1489             == (LSR_TSRE | LSR_TXRDY)) {
 1490                 com->tp->t_state &= ~TS_BUSY;
 1491                 ttwwakeup(com->tp);
 1492                 com->extra_state &= ~CSE_BUSYCHECK;
 1493         } else
 1494                 timeout(siobusycheck, com, hz / 100);
 1495         splx(s);
 1496 }
 1497 
 1498 static void
 1499 siodtrwakeup(chan)
 1500         void    *chan;
 1501 {
 1502         struct com_s    *com;
 1503 
 1504         com = (struct com_s *)chan;
 1505         com->state &= ~CS_DTR_OFF;
 1506         wakeup(&com->dtr_wait);
 1507 }
 1508 
 1509 void
 1510 siointr(arg)
 1511         void            *arg;
 1512 {
 1513 #ifndef COM_MULTIPORT
 1514         COM_LOCK();
 1515         siointr1((struct com_s *) arg);
 1516         COM_UNLOCK();
 1517 #else /* COM_MULTIPORT */
 1518         bool_t          possibly_more_intrs;
 1519 
 1520         /*
 1521          * Loop until there is no activity on any port.  This is necessary
 1522          * to get an interrupt edge more than to avoid another interrupt.
 1523          * If the IRQ signal is just an OR of the IRQ signals from several
 1524          * devices, then the edge from one may be lost because another is
 1525          * on.
 1526          */
 1527         COM_LOCK();
 1528         do {
 1529                 possibly_more_intrs = FALSE;
 1530                 for (unit = 0; unit < NSIOTOT; ++unit) {
 1531                         com = com_addr(unit);
 1532                         /*
 1533                          * XXX COM_LOCK();
 1534                          * would it work here, or be counter-productive?
 1535                          */
 1536                         if (com != NULL 
 1537                             && !com->gone
 1538                             && (inb(com->int_id_port) & IIR_IMASK)
 1539                                != IIR_NOPEND) {
 1540                                 siointr1(com);
 1541                                 possibly_more_intrs = TRUE;
 1542                         }
 1543                         /* XXX COM_UNLOCK(); */
 1544                 }
 1545         } while (possibly_more_intrs);
 1546         COM_UNLOCK();
 1547 #endif /* COM_MULTIPORT */
 1548 }
 1549 
 1550 static void
 1551 siointr1(com)
 1552         struct com_s    *com;
 1553 {
 1554         u_char  line_status;
 1555         u_char  modem_status;
 1556         u_char  *ioptr;
 1557         u_char  recv_data;
 1558         u_char  int_ident;
 1559         u_char  int_ctl;
 1560         u_char  int_ctl_new;
 1561 
 1562         int_ctl = inb(com->intr_ctl_port);
 1563         int_ctl_new = int_ctl;
 1564 
 1565         while (!com->gone) {
 1566                 line_status = inb(com->line_status_port);
 1567 
 1568                 /* input event? (check first to help avoid overruns) */
 1569                 while (line_status & LSR_RCV_MASK) {
 1570                         /* break/unnattached error bits or real input? */
 1571                         if (!(line_status & LSR_RXRDY))
 1572                                 recv_data = 0;
 1573                         else
 1574                                 recv_data = inb(com->data_port);
 1575                         if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
 1576                                 /*
 1577                                  * Don't store BI if IGNBRK or FE/PE if IGNPAR.
 1578                                  * Otherwise, push the work to a higher level
 1579                                  * (to handle PARMRK) if we're bypassing.
 1580                                  * Otherwise, convert BI/FE and PE+INPCK to 0.
 1581                                  *
 1582                                  * This makes bypassing work right in the
 1583                                  * usual "raw" case (IGNBRK set, and IGNPAR
 1584                                  * and INPCK clear).
 1585                                  *
 1586                                  * Note: BI together with FE/PE means just BI.
 1587                                  */
 1588                                 if (line_status & LSR_BI) {
 1589 #if defined(DDB) && defined(BREAK_TO_DEBUGGER)
 1590                                         if (com->unit == comconsole) {
 1591                                                 breakpoint();
 1592                                                 goto cont;
 1593                                         }
 1594 #endif
 1595                                         if (com->tp == NULL
 1596                                             || com->tp->t_iflag & IGNBRK)
 1597                                                 goto cont;
 1598                                 } else {
 1599                                         if (com->tp == NULL
 1600                                             || com->tp->t_iflag & IGNPAR)
 1601                                                 goto cont;
 1602                                 }
 1603                                 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
 1604                                     && (line_status & (LSR_BI | LSR_FE)
 1605                                         || com->tp->t_iflag & INPCK))
 1606                                         recv_data = 0;
 1607                         }
 1608                         ++com->bytes_in;
 1609                         if (com->hotchar != 0 && recv_data == com->hotchar)
 1610                                 setsofttty();
 1611                         ioptr = com->iptr;
 1612                         if (ioptr >= com->ibufend)
 1613                                 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
 1614                         else {
 1615                                 if (com->do_timestamp)
 1616                                         microtime(&com->timestamp);
 1617                                 ++com_events;
 1618                                 schedsofttty();
 1619 #if 0 /* for testing input latency vs efficiency */
 1620 if (com->iptr - com->ibuf == 8)
 1621         setsofttty();
 1622 #endif
 1623                                 ioptr[0] = recv_data;
 1624                                 ioptr[CE_INPUT_OFFSET] = line_status;
 1625                                 com->iptr = ++ioptr;
 1626                                 if (ioptr == com->ihighwater
 1627                                     && com->state & CS_RTS_IFLOW)
 1628                                         outb(com->modem_ctl_port,
 1629                                              com->mcr_image &= ~MCR_RTS);
 1630                                 if (line_status & LSR_OE)
 1631                                         CE_RECORD(com, CE_OVERRUN);
 1632                         }
 1633 cont:
 1634                         /*
 1635                          * "& 0x7F" is to avoid the gcc-1.40 generating a slow
 1636                          * jump from the top of the loop to here
 1637                          */
 1638                         line_status = inb(com->line_status_port) & 0x7F;
 1639                 }
 1640 
 1641                 /* modem status change? (always check before doing output) */
 1642                 modem_status = inb(com->modem_status_port);
 1643                 if (modem_status != com->last_modem_status) {
 1644                         if (com->do_dcd_timestamp
 1645                             && !(com->last_modem_status & MSR_DCD)
 1646                             && modem_status & MSR_DCD)
 1647                                 microtime(&com->dcd_timestamp);
 1648 
 1649                         /*
 1650                          * Schedule high level to handle DCD changes.  Note
 1651                          * that we don't use the delta bits anywhere.  Some
 1652                          * UARTs mess them up, and it's easy to remember the
 1653                          * previous bits and calculate the delta.
 1654                          */
 1655                         com->last_modem_status = modem_status;
 1656                         if (!(com->state & CS_CHECKMSR)) {
 1657                                 com_events += LOTS_OF_EVENTS;
 1658                                 com->state |= CS_CHECKMSR;
 1659                                 setsofttty();
 1660                         }
 1661 
 1662                         /* handle CTS change immediately for crisp flow ctl */
 1663                         if (com->state & CS_CTS_OFLOW) {
 1664                                 if (modem_status & MSR_CTS)
 1665                                         com->state |= CS_ODEVREADY;
 1666                                 else
 1667                                         com->state &= ~CS_ODEVREADY;
 1668                         }
 1669                 }
 1670 
 1671                 /* output queued and everything ready? */
 1672                 if (line_status & LSR_TXRDY
 1673                     && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
 1674                         ioptr = com->obufq.l_head;
 1675                         if (com->tx_fifo_size > 1) {
 1676                                 u_int   ocount;
 1677 
 1678                                 ocount = com->obufq.l_tail - ioptr;
 1679                                 if (ocount > com->tx_fifo_size)
 1680                                         ocount = com->tx_fifo_size;
 1681                                 com->bytes_out += ocount;
 1682                                 do
 1683                                         outb(com->data_port, *ioptr++);
 1684                                 while (--ocount != 0);
 1685                         } else {
 1686                                 outb(com->data_port, *ioptr++);
 1687                                 ++com->bytes_out;
 1688                         }
 1689                         com->obufq.l_head = ioptr;
 1690                         if (COM_IIR_TXRDYBUG(com->flags)) {
 1691                                 int_ctl_new = int_ctl | IER_ETXRDY;
 1692                         }
 1693                         if (ioptr >= com->obufq.l_tail) {
 1694                                 struct lbq      *qp;
 1695 
 1696                                 qp = com->obufq.l_next;
 1697                                 qp->l_queued = FALSE;
 1698                                 qp = qp->l_next;
 1699                                 if (qp != NULL) {
 1700                                         com->obufq.l_head = qp->l_head;
 1701                                         com->obufq.l_tail = qp->l_tail;
 1702                                         com->obufq.l_next = qp;
 1703                                 } else {
 1704                                         /* output just completed */
 1705                                         if ( COM_IIR_TXRDYBUG(com->flags) ) {
 1706                                                 int_ctl_new = int_ctl & ~IER_ETXRDY;
 1707                                         }
 1708                                         com->state &= ~CS_BUSY;
 1709                                 }
 1710                                 if (!(com->state & CS_ODONE)) {
 1711                                         com_events += LOTS_OF_EVENTS;
 1712                                         com->state |= CS_ODONE;
 1713                                         setsofttty();   /* handle at high level ASAP */
 1714                                 }
 1715                         }
 1716                         if ( COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
 1717                                 outb(com->intr_ctl_port, int_ctl_new);
 1718                         }
 1719                 }
 1720 
 1721                 /* finished? */
 1722 #ifndef COM_MULTIPORT
 1723                 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
 1724 #endif /* COM_MULTIPORT */
 1725                         return;
 1726         }
 1727 }
 1728 
 1729 static int
 1730 sioioctl(dev, cmd, data, flag, p)
 1731         dev_t           dev;
 1732         u_long          cmd;
 1733         caddr_t         data;
 1734         int             flag;
 1735         struct proc     *p;
 1736 {
 1737         struct com_s    *com;
 1738         int             error;
 1739         Port_t          iobase;
 1740         int             mynor;
 1741         int             s;
 1742         struct tty      *tp;
 1743 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1744         u_long          oldcmd;
 1745         struct termios  term;
 1746 #endif
 1747 
 1748         mynor = minor(dev);
 1749         com = com_addr(MINOR_TO_UNIT(mynor));
 1750         if (com->gone)
 1751                 return (ENODEV);
 1752         iobase = com->iobase;
 1753         if (mynor & CONTROL_MASK) {
 1754                 struct termios  *ct;
 1755 
 1756                 switch (mynor & CONTROL_MASK) {
 1757                 case CONTROL_INIT_STATE:
 1758                         ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
 1759                         break;
 1760                 case CONTROL_LOCK_STATE:
 1761                         ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
 1762                         break;
 1763                 default:
 1764                         return (ENODEV);        /* /dev/nodev */
 1765                 }
 1766                 switch (cmd) {
 1767                 case TIOCSETA:
 1768                         error = suser(p->p_ucred, &p->p_acflag);
 1769                         if (error != 0)
 1770                                 return (error);
 1771                         *ct = *(struct termios *)data;
 1772                         return (0);
 1773                 case TIOCGETA:
 1774                         *(struct termios *)data = *ct;
 1775                         return (0);
 1776                 case TIOCGETD:
 1777                         *(int *)data = TTYDISC;
 1778                         return (0);
 1779                 case TIOCGWINSZ:
 1780                         bzero(data, sizeof(struct winsize));
 1781                         return (0);
 1782 #ifdef DSI_SOFT_MODEM
 1783                 /*
 1784                  * Download micro-code to Digicom modem.
 1785                  */
 1786                 case TIOCDSIMICROCODE:
 1787                         {
 1788                         u_long l;
 1789                         u_char *p,*pi;
 1790 
 1791                         pi = (u_char*)(*(caddr_t*)data);
 1792                         error = copyin(pi,&l,sizeof l);
 1793                         if(error)
 1794                                 {return error;};
 1795                         pi += sizeof l;
 1796 
 1797                         p = malloc(l,M_TEMP,M_NOWAIT);
 1798                         if(!p)
 1799                                 {return ENOBUFS;}
 1800                         error = copyin(pi,p,l);
 1801                         if(error)
 1802                                 {free(p,M_TEMP); return error;};
 1803                         if(error = LoadSoftModem(
 1804                             MINOR_TO_UNIT(mynor),iobase,l,p))
 1805                                 {free(p,M_TEMP); return error;}
 1806                         free(p,M_TEMP);
 1807                         return(0);
 1808                         }
 1809 #endif /* DSI_SOFT_MODEM */
 1810                 default:
 1811                         return (ENOTTY);
 1812                 }
 1813         }
 1814         tp = com->tp;
 1815 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1816         term = tp->t_termios;
 1817         oldcmd = cmd;
 1818         error = ttsetcompat(tp, &cmd, data, &term);
 1819         if (error != 0)
 1820                 return (error);
 1821         if (cmd != oldcmd)
 1822                 data = (caddr_t)&term;
 1823 #endif
 1824         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1825                 int     cc;
 1826                 struct termios *dt = (struct termios *)data;
 1827                 struct termios *lt = mynor & CALLOUT_MASK
 1828                                      ? &com->lt_out : &com->lt_in;
 1829 
 1830                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
 1831                               | (dt->c_iflag & ~lt->c_iflag);
 1832                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
 1833                               | (dt->c_oflag & ~lt->c_oflag);
 1834                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
 1835                               | (dt->c_cflag & ~lt->c_cflag);
 1836                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
 1837                               | (dt->c_lflag & ~lt->c_lflag);
 1838                 for (cc = 0; cc < NCCS; ++cc)
 1839                         if (lt->c_cc[cc] != 0)
 1840                                 dt->c_cc[cc] = tp->t_cc[cc];
 1841                 if (lt->c_ispeed != 0)
 1842                         dt->c_ispeed = tp->t_ispeed;
 1843                 if (lt->c_ospeed != 0)
 1844                         dt->c_ospeed = tp->t_ospeed;
 1845         }
 1846         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
 1847         if (error != ENOIOCTL)
 1848                 return (error);
 1849         s = spltty();
 1850         error = ttioctl(tp, cmd, data, flag);
 1851         disc_optim(tp, &tp->t_termios, com);
 1852         if (error != ENOIOCTL) {
 1853                 splx(s);
 1854                 return (error);
 1855         }
 1856         switch (cmd) {
 1857         case TIOCSBRK:
 1858                 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
 1859                 break;
 1860         case TIOCCBRK:
 1861                 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
 1862                 break;
 1863         case TIOCSDTR:
 1864                 (void)commctl(com, TIOCM_DTR, DMBIS);
 1865                 break;
 1866         case TIOCCDTR:
 1867                 (void)commctl(com, TIOCM_DTR, DMBIC);
 1868                 break;
 1869         /*
 1870          * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
 1871          * changes get undone on the next call to comparam().
 1872          */
 1873         case TIOCMSET:
 1874                 (void)commctl(com, *(int *)data, DMSET);
 1875                 break;
 1876         case TIOCMBIS:
 1877                 (void)commctl(com, *(int *)data, DMBIS);
 1878                 break;
 1879         case TIOCMBIC:
 1880                 (void)commctl(com, *(int *)data, DMBIC);
 1881                 break;
 1882         case TIOCMGET:
 1883                 *(int *)data = commctl(com, 0, DMGET);
 1884                 break;
 1885         case TIOCMSDTRWAIT:
 1886                 /* must be root since the wait applies to following logins */
 1887                 error = suser(p->p_ucred, &p->p_acflag);
 1888                 if (error != 0) {
 1889                         splx(s);
 1890                         return (error);
 1891                 }
 1892                 com->dtr_wait = *(int *)data * hz / 100;
 1893                 break;
 1894         case TIOCMGDTRWAIT:
 1895                 *(int *)data = com->dtr_wait * 100 / hz;
 1896                 break;
 1897         case TIOCTIMESTAMP:
 1898                 com->do_timestamp = TRUE;
 1899                 *(struct timeval *)data = com->timestamp;
 1900                 break;
 1901         case TIOCDCDTIMESTAMP:
 1902                 com->do_dcd_timestamp = TRUE;
 1903                 *(struct timeval *)data = com->dcd_timestamp;
 1904                 break;
 1905         default:
 1906                 splx(s);
 1907                 return (ENOTTY);
 1908         }
 1909         splx(s);
 1910         return (0);
 1911 }
 1912 
 1913 static void
 1914 siopoll()
 1915 {
 1916         int             unit;
 1917 
 1918         if (com_events == 0)
 1919                 return;
 1920 repeat:
 1921         for (unit = 0; unit < NSIOTOT; ++unit) {
 1922                 u_char          *buf;
 1923                 struct com_s    *com;
 1924                 u_char          *ibuf;
 1925                 int             incc;
 1926                 struct tty      *tp;
 1927 
 1928                 com = com_addr(unit);
 1929                 if (com == NULL)
 1930                         continue;
 1931                 tp = com->tp;
 1932                 if (tp == NULL || com->gone) {
 1933                         /*
 1934                          * Discard any events related to never-opened or
 1935                          * going-away devices.
 1936                          */
 1937                         disable_intr();
 1938                         incc = com->iptr - com->ibuf;
 1939                         com->iptr = com->ibuf;
 1940                         if (com->state & CS_CHECKMSR) {
 1941                                 incc += LOTS_OF_EVENTS;
 1942                                 com->state &= ~CS_CHECKMSR;
 1943                         }
 1944                         com_events -= incc;
 1945                         enable_intr();
 1946                         continue;
 1947                 }
 1948 
 1949                 /* switch the role of the low-level input buffers */
 1950                 if (com->iptr == (ibuf = com->ibuf)) {
 1951                         buf = NULL;     /* not used, but compiler can't tell */
 1952                         incc = 0;
 1953                 } else {
 1954                         buf = ibuf;
 1955                         disable_intr();
 1956                         incc = com->iptr - buf;
 1957                         com_events -= incc;
 1958                         if (ibuf == com->ibuf1)
 1959                                 ibuf = com->ibuf2;
 1960                         else
 1961                                 ibuf = com->ibuf1;
 1962                         com->ibufend = ibuf + RS_IBUFSIZE;
 1963                         com->ihighwater = ibuf + RS_IHIGHWATER;
 1964                         com->iptr = ibuf;
 1965 
 1966                         /*
 1967                          * There is now room for another low-level buffer full
 1968                          * of input, so enable RTS if it is now disabled and
 1969                          * there is room in the high-level buffer.
 1970                          */
 1971                         if ((com->state & CS_RTS_IFLOW)
 1972                             && !(com->mcr_image & MCR_RTS)
 1973                             && !(tp->t_state & TS_TBLOCK))
 1974                                 outb(com->modem_ctl_port,
 1975                                      com->mcr_image |= MCR_RTS);
 1976                         enable_intr();
 1977                         com->ibuf = ibuf;
 1978                 }
 1979 
 1980                 if (com->state & CS_CHECKMSR) {
 1981                         u_char  delta_modem_status;
 1982 
 1983                         disable_intr();
 1984                         delta_modem_status = com->last_modem_status
 1985                                              ^ com->prev_modem_status;
 1986                         com->prev_modem_status = com->last_modem_status;
 1987                         com_events -= LOTS_OF_EVENTS;
 1988                         com->state &= ~CS_CHECKMSR;
 1989                         enable_intr();
 1990                         if (delta_modem_status & MSR_DCD)
 1991                                 (*linesw[tp->t_line].l_modem)
 1992                                         (tp, com->prev_modem_status & MSR_DCD);
 1993                 }
 1994                 if (com->state & CS_ODONE) {
 1995                         disable_intr();
 1996                         com_events -= LOTS_OF_EVENTS;
 1997                         com->state &= ~CS_ODONE;
 1998                         enable_intr();
 1999                         if (!(com->state & CS_BUSY)
 2000                             && !(com->extra_state & CSE_BUSYCHECK)) {
 2001                                 timeout(siobusycheck, com, hz / 100);
 2002                                 com->extra_state |= CSE_BUSYCHECK;
 2003                         }
 2004                         (*linesw[tp->t_line].l_start)(tp);
 2005                 }
 2006                 if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
 2007                     !(tp->t_cflag & CREAD))
 2008                         continue;
 2009                 /*
 2010                  * Avoid the grotesquely inefficient lineswitch routine
 2011                  * (ttyinput) in "raw" mode.  It usually takes about 450
 2012                  * instructions (that's without canonical processing or echo!).
 2013                  * slinput is reasonably fast (usually 40 instructions plus
 2014                  * call overhead).
 2015                  */
 2016                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 2017                         if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
 2018                             && (com->state & CS_RTS_IFLOW
 2019                                 || tp->t_iflag & IXOFF)
 2020                             && !(tp->t_state & TS_TBLOCK))
 2021                                 ttyblock(tp);
 2022                         tk_nin += incc;
 2023                         tk_rawcc += incc;
 2024                         tp->t_rawcc += incc;
 2025                         com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
 2026                                 += b_to_q((char *)buf, incc, &tp->t_rawq);
 2027                         ttwakeup(tp);
 2028                         if (tp->t_state & TS_TTSTOP
 2029                             && (tp->t_iflag & IXANY
 2030                                 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
 2031                                 tp->t_state &= ~TS_TTSTOP;
 2032                                 tp->t_lflag &= ~FLUSHO;
 2033                                 comstart(tp);
 2034                         }
 2035                 } else {
 2036                         do {
 2037                                 u_char  line_status;
 2038                                 int     recv_data;
 2039 
 2040                                 line_status = (u_char) buf[CE_INPUT_OFFSET];
 2041                                 recv_data = (u_char) *buf++;
 2042                                 if (line_status
 2043                                     & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
 2044                                         if (line_status & LSR_BI)
 2045                                                 recv_data |= TTY_BI;
 2046                                         if (line_status & LSR_FE)
 2047                                                 recv_data |= TTY_FE;
 2048                                         if (line_status & LSR_OE)
 2049                                                 recv_data |= TTY_OE;
 2050                                         if (line_status & LSR_PE)
 2051                                                 recv_data |= TTY_PE;
 2052                                 }
 2053                                 (*linesw[tp->t_line].l_rint)(recv_data, tp);
 2054                         } while (--incc > 0);
 2055                 }
 2056                 if (com_events == 0)
 2057                         break;
 2058         }
 2059         if (com_events >= LOTS_OF_EVENTS)
 2060                 goto repeat;
 2061 }
 2062 
 2063 static int
 2064 comparam(tp, t)
 2065         struct tty      *tp;
 2066         struct termios  *t;
 2067 {
 2068         u_int           cfcr;
 2069         int             cflag;
 2070         struct com_s    *com;
 2071         int             divisor;
 2072         u_char          dlbh;
 2073         u_char          dlbl;
 2074         int             error;
 2075         Port_t          iobase;
 2076         int             s;
 2077         int             unit;
 2078         int             txtimeout;
 2079 
 2080         /* do historical conversions */
 2081         if (t->c_ispeed == 0)
 2082                 t->c_ispeed = t->c_ospeed;
 2083 
 2084         /* check requested parameters */
 2085         divisor = ttspeedtab(t->c_ospeed, comspeedtab);
 2086         if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
 2087                 return (EINVAL);
 2088 
 2089         /* parameters are OK, convert them to the com struct and the device */
 2090         unit = DEV_TO_UNIT(tp->t_dev);
 2091         com = com_addr(unit);
 2092         iobase = com->iobase;
 2093         s = spltty();
 2094         if (divisor == 0)
 2095                 (void)commctl(com, TIOCM_DTR, DMBIC);   /* hang up line */
 2096         else
 2097                 (void)commctl(com, TIOCM_DTR, DMBIS);
 2098         cflag = t->c_cflag;
 2099         switch (cflag & CSIZE) {
 2100         case CS5:
 2101                 cfcr = CFCR_5BITS;
 2102                 break;
 2103         case CS6:
 2104                 cfcr = CFCR_6BITS;
 2105                 break;
 2106         case CS7:
 2107                 cfcr = CFCR_7BITS;
 2108                 break;
 2109         default:
 2110                 cfcr = CFCR_8BITS;
 2111                 break;
 2112         }
 2113         if (cflag & PARENB) {
 2114                 cfcr |= CFCR_PENAB;
 2115                 if (!(cflag & PARODD))
 2116                         cfcr |= CFCR_PEVEN;
 2117         }
 2118         if (cflag & CSTOPB)
 2119                 cfcr |= CFCR_STOPB;
 2120 
 2121         if (com->hasfifo && divisor != 0) {
 2122                 /*
 2123                  * Use a fifo trigger level low enough so that the input
 2124                  * latency from the fifo is less than about 16 msec and
 2125                  * the total latency is less than about 30 msec.  These
 2126                  * latencies are reasonable for humans.  Serial comms
 2127                  * protocols shouldn't expect anything better since modem
 2128                  * latencies are larger.
 2129                  */
 2130                 com->fifo_image = t->c_ospeed <= 4800
 2131                                   ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
 2132 #ifdef COM_ESP
 2133                 /*
 2134                  * The Hayes ESP card needs the fifo DMA mode bit set
 2135                  * in compatibility mode.  If not, it will interrupt
 2136                  * for each character received.
 2137                  */
 2138                 if (com->esp)
 2139                         com->fifo_image |= FIFO_DMA_MODE;
 2140 #endif
 2141                 outb(iobase + com_fifo, com->fifo_image);
 2142         }
 2143 
 2144         /*
 2145          * Some UARTs lock up if the divisor latch registers are selected
 2146          * while the UART is doing output (they refuse to transmit anything
 2147          * more until given a hard reset).  Fix this by stopping filling
 2148          * the device buffers and waiting for them to drain.  Reading the
 2149          * line status port outside of siointr1() might lose some receiver
 2150          * error bits, but that is acceptable here.
 2151          */
 2152         disable_intr();
 2153 retry:
 2154         com->state &= ~CS_TTGO;
 2155         txtimeout = tp->t_timeout;
 2156         enable_intr();
 2157         while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
 2158                != (LSR_TSRE | LSR_TXRDY)) {
 2159                 tp->t_state |= TS_SO_OCOMPLETE;
 2160                 error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
 2161                                  "siotx", hz / 100);
 2162                 if (   txtimeout != 0
 2163                     && (!error || error == EAGAIN)
 2164                     && (txtimeout -= hz / 100) <= 0
 2165                    )
 2166                         error = EIO;
 2167                 if (com->gone)
 2168                         error = ENODEV;
 2169                 if (error != 0 && error != EAGAIN) {
 2170                         if (!(tp->t_state & TS_TTSTOP)) {
 2171                                 disable_intr();
 2172                                 com->state |= CS_TTGO;
 2173                                 enable_intr();
 2174                         }
 2175                         splx(s);
 2176                         return (error);
 2177                 }
 2178         }
 2179 
 2180         disable_intr();         /* very important while com_data is hidden */
 2181 
 2182         /*
 2183          * XXX - clearing CS_TTGO is not sufficient to stop further output,
 2184          * because siopoll() calls comstart() which usually sets it again
 2185          * because TS_TTSTOP is clear.  Setting TS_TTSTOP would not be
 2186          * sufficient, for similar reasons.
 2187          */
 2188         if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
 2189             != (LSR_TSRE | LSR_TXRDY))
 2190                 goto retry;
 2191 
 2192         if (divisor != 0) {
 2193                 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
 2194                 /*
 2195                  * Only set the divisor registers if they would change,
 2196                  * since on some 16550 incompatibles (UMC8669F), setting
 2197                  * them while input is arriving them loses sync until
 2198                  * data stops arriving.
 2199                  */
 2200                 dlbl = divisor & 0xFF;
 2201                 if (inb(iobase + com_dlbl) != dlbl)
 2202                         outb(iobase + com_dlbl, dlbl);
 2203                 dlbh = (u_int) divisor >> 8;
 2204                 if (inb(iobase + com_dlbh) != dlbh)
 2205                         outb(iobase + com_dlbh, dlbh);
 2206         }
 2207 
 2208 
 2209         outb(iobase + com_cfcr, com->cfcr_image = cfcr);
 2210 
 2211         if (!(tp->t_state & TS_TTSTOP))
 2212                 com->state |= CS_TTGO;
 2213 
 2214         if (cflag & CRTS_IFLOW) {
 2215                 if (com->st16650a) {
 2216                         outb(iobase + com_cfcr, 0xbf);
 2217                         outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40);
 2218                 }
 2219                 com->state |= CS_RTS_IFLOW;
 2220                 /*
 2221                  * If CS_RTS_IFLOW just changed from off to on, the change
 2222                  * needs to be propagated to MCR_RTS.  This isn't urgent,
 2223                  * so do it later by calling comstart() instead of repeating
 2224                  * a lot of code from comstart() here.
 2225                  */
 2226         } else if (com->state & CS_RTS_IFLOW) {
 2227                 com->state &= ~CS_RTS_IFLOW;
 2228                 /*
 2229                  * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
 2230                  * on here, since comstart() won't do it later.
 2231                  */
 2232                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 2233                 if (com->st16650a) {
 2234                         outb(iobase + com_cfcr, 0xbf);
 2235                         outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40);
 2236                 }
 2237         }
 2238 
 2239 
 2240         /*
 2241          * Set up state to handle output flow control.
 2242          * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
 2243          * Now has 10+ msec latency, while CTS flow has 50- usec latency.
 2244          */
 2245         com->state |= CS_ODEVREADY;
 2246         com->state &= ~CS_CTS_OFLOW;
 2247         if (cflag & CCTS_OFLOW) {
 2248                 com->state |= CS_CTS_OFLOW;
 2249                 if (!(com->last_modem_status & MSR_CTS))
 2250                         com->state &= ~CS_ODEVREADY;
 2251                 if (com->st16650a) {
 2252                         outb(iobase + com_cfcr, 0xbf);
 2253                         outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80);
 2254                 }
 2255         } else {
 2256                 if (com->st16650a) {
 2257                         outb(iobase + com_cfcr, 0xbf);
 2258                         outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80);
 2259                 }
 2260         }
 2261 
 2262 
 2263         outb(iobase + com_cfcr, com->cfcr_image);
 2264 
 2265 
 2266         /* XXX shouldn't call functions while intrs are disabled. */
 2267         disc_optim(tp, t, com);
 2268         /*
 2269          * Recover from fiddling with CS_TTGO.  We used to call siointr1()
 2270          * unconditionally, but that defeated the careful discarding of
 2271          * stale input in sioopen().
 2272          */
 2273         if (com->state >= (CS_BUSY | CS_TTGO))
 2274                 siointr1(com);
 2275 
 2276         enable_intr();
 2277         splx(s);
 2278         comstart(tp);
 2279         return (0);
 2280 }
 2281 
 2282 static void
 2283 comstart(tp)
 2284         struct tty      *tp;
 2285 {
 2286         struct com_s    *com;
 2287         int             s;
 2288         int             unit;
 2289 
 2290         unit = DEV_TO_UNIT(tp->t_dev);
 2291         com = com_addr(unit);
 2292         s = spltty();
 2293         disable_intr();
 2294         if (tp->t_state & TS_TTSTOP)
 2295                 com->state &= ~CS_TTGO;
 2296         else
 2297                 com->state |= CS_TTGO;
 2298         if (tp->t_state & TS_TBLOCK) {
 2299                 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
 2300                         outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
 2301         } else {
 2302                 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
 2303                     && com->state & CS_RTS_IFLOW)
 2304                         outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 2305         }
 2306         enable_intr();
 2307         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
 2308                 ttwwakeup(tp);
 2309                 splx(s);
 2310                 return;
 2311         }
 2312         if (tp->t_outq.c_cc != 0) {
 2313                 struct lbq      *qp;
 2314                 struct lbq      *next;
 2315 
 2316                 if (!com->obufs[0].l_queued) {
 2317                         com->obufs[0].l_tail
 2318                             = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
 2319                                                   sizeof com->obuf1);
 2320                         com->obufs[0].l_next = NULL;
 2321                         com->obufs[0].l_queued = TRUE;
 2322                         disable_intr();
 2323                         if (com->state & CS_BUSY) {
 2324                                 qp = com->obufq.l_next;
 2325                                 while ((next = qp->l_next) != NULL)
 2326                                         qp = next;
 2327                                 qp->l_next = &com->obufs[0];
 2328                         } else {
 2329                                 com->obufq.l_head = com->obufs[0].l_head;
 2330                                 com->obufq.l_tail = com->obufs[0].l_tail;
 2331                                 com->obufq.l_next = &com->obufs[0];
 2332                                 com->state |= CS_BUSY;
 2333                         }
 2334                         enable_intr();
 2335                 }
 2336                 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
 2337                         com->obufs[1].l_tail
 2338                             = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
 2339                                                   sizeof com->obuf2);
 2340                         com->obufs[1].l_next = NULL;
 2341                         com->obufs[1].l_queued = TRUE;
 2342                         disable_intr();
 2343                         if (com->state & CS_BUSY) {
 2344                                 qp = com->obufq.l_next;
 2345                                 while ((next = qp->l_next) != NULL)
 2346                                         qp = next;
 2347                                 qp->l_next = &com->obufs[1];
 2348                         } else {
 2349                                 com->obufq.l_head = com->obufs[1].l_head;
 2350                                 com->obufq.l_tail = com->obufs[1].l_tail;
 2351                                 com->obufq.l_next = &com->obufs[1];
 2352                                 com->state |= CS_BUSY;
 2353                         }
 2354                         enable_intr();
 2355                 }
 2356                 tp->t_state |= TS_BUSY;
 2357         }
 2358         disable_intr();
 2359         if (com->state >= (CS_BUSY | CS_TTGO))
 2360                 siointr1(com);  /* fake interrupt to start output */
 2361         enable_intr();
 2362         ttwwakeup(tp);
 2363         splx(s);
 2364 }
 2365 
 2366 static void
 2367 siostop(tp, rw)
 2368         struct tty      *tp;
 2369         int             rw;
 2370 {
 2371         struct com_s    *com;
 2372 
 2373         com = com_addr(DEV_TO_UNIT(tp->t_dev));
 2374         if (com->gone)
 2375                 return;
 2376         disable_intr();
 2377         if (rw & FWRITE) {
 2378                 if (com->hasfifo)
 2379 #ifdef COM_ESP
 2380                     /* XXX avoid h/w bug. */
 2381                     if (!com->esp)
 2382 #endif
 2383                         /* XXX does this flush everything? */
 2384                         outb(com->iobase + com_fifo,
 2385                              FIFO_XMT_RST | com->fifo_image);
 2386                 com->obufs[0].l_queued = FALSE;
 2387                 com->obufs[1].l_queued = FALSE;
 2388                 if (com->state & CS_ODONE)
 2389                         com_events -= LOTS_OF_EVENTS;
 2390                 com->state &= ~(CS_ODONE | CS_BUSY);
 2391                 com->tp->t_state &= ~TS_BUSY;
 2392         }
 2393         if (rw & FREAD) {
 2394                 if (com->hasfifo)
 2395 #ifdef COM_ESP
 2396                     /* XXX avoid h/w bug. */
 2397                     if (!com->esp)
 2398 #endif
 2399                         /* XXX does this flush everything? */
 2400                         outb(com->iobase + com_fifo,
 2401                              FIFO_RCV_RST | com->fifo_image);
 2402                 com_events -= (com->iptr - com->ibuf);
 2403                 com->iptr = com->ibuf;
 2404         }
 2405         enable_intr();
 2406         comstart(tp);
 2407 }
 2408 
 2409 static struct tty *
 2410 siodevtotty(dev)
 2411         dev_t   dev;
 2412 {
 2413         int     mynor;
 2414         int     unit;
 2415 
 2416         mynor = minor(dev);
 2417         if (mynor & CONTROL_MASK)
 2418                 return (NULL);
 2419         unit = MINOR_TO_UNIT(mynor);
 2420         if ((u_int) unit >= NSIOTOT)
 2421                 return (NULL);
 2422         return (&sio_tty[unit]);
 2423 }
 2424 
 2425 static int
 2426 commctl(com, bits, how)
 2427         struct com_s    *com;
 2428         int             bits;
 2429         int             how;
 2430 {
 2431         int     mcr;
 2432         int     msr;
 2433 
 2434         if (how == DMGET) {
 2435                 bits = TIOCM_LE;        /* XXX - always enabled while open */
 2436                 mcr = com->mcr_image;
 2437                 if (mcr & MCR_DTR)
 2438                         bits |= TIOCM_DTR;
 2439                 if (mcr & MCR_RTS)
 2440                         bits |= TIOCM_RTS;
 2441                 msr = com->prev_modem_status;
 2442                 if (msr & MSR_CTS)
 2443                         bits |= TIOCM_CTS;
 2444                 if (msr & MSR_DCD)
 2445                         bits |= TIOCM_CD;
 2446                 if (msr & MSR_DSR)
 2447                         bits |= TIOCM_DSR;
 2448                 /*
 2449                  * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
 2450                  * more volatile by reading the modem status a lot.  Perhaps
 2451                  * we should latch both bits until the status is read here.
 2452                  */
 2453                 if (msr & (MSR_RI | MSR_TERI))
 2454                         bits |= TIOCM_RI;
 2455                 return (bits);
 2456         }
 2457         mcr = 0;
 2458         if (bits & TIOCM_DTR)
 2459                 mcr |= MCR_DTR;
 2460         if (bits & TIOCM_RTS)
 2461                 mcr |= MCR_RTS;
 2462         if (com->gone)
 2463                 return(0);
 2464         disable_intr();
 2465         switch (how) {
 2466         case DMSET:
 2467                 outb(com->modem_ctl_port,
 2468                      com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
 2469                 break;
 2470         case DMBIS:
 2471                 outb(com->modem_ctl_port, com->mcr_image |= mcr);
 2472                 break;
 2473         case DMBIC:
 2474                 outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
 2475                 break;
 2476         }
 2477         enable_intr();
 2478         return (0);
 2479 }
 2480 
 2481 static void
 2482 siosettimeout()
 2483 {
 2484         struct com_s    *com;
 2485         bool_t          someopen;
 2486         int             unit;
 2487 
 2488         /*
 2489          * Set our timeout period to 1 second if no polled devices are open.
 2490          * Otherwise set it to max(1/200, 1/hz).
 2491          * Enable timeouts iff some device is open.
 2492          */
 2493         untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
 2494         sio_timeout = hz;
 2495         someopen = FALSE;
 2496         for (unit = 0; unit < NSIOTOT; ++unit) {
 2497                 com = com_addr(unit);
 2498                 if (com != NULL && com->tp != NULL
 2499                     && com->tp->t_state & TS_ISOPEN && !com->gone) {
 2500                         someopen = TRUE;
 2501                         if (com->poll || com->poll_output) {
 2502                                 sio_timeout = hz > 200 ? hz / 200 : 1;
 2503                                 break;
 2504                         }
 2505                 }
 2506         }
 2507         if (someopen) {
 2508                 sio_timeouts_until_log = hz / sio_timeout;
 2509                 sio_timeout_handle = timeout(comwakeup, (void *)NULL,
 2510                                              sio_timeout);
 2511         } else {
 2512                 /* Flush error messages, if any. */
 2513                 sio_timeouts_until_log = 1;
 2514                 comwakeup((void *)NULL);
 2515                 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
 2516         }
 2517 }
 2518 
 2519 static void
 2520 comwakeup(chan)
 2521         void    *chan;
 2522 {
 2523         struct com_s    *com;
 2524         int             unit;
 2525 
 2526         sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
 2527 
 2528         /*
 2529          * Recover from lost output interrupts.
 2530          * Poll any lines that don't use interrupts.
 2531          */
 2532         for (unit = 0; unit < NSIOTOT; ++unit) {
 2533                 com = com_addr(unit);
 2534                 if (com != NULL && !com->gone
 2535                     && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
 2536                         disable_intr();
 2537                         siointr1(com);
 2538                         enable_intr();
 2539                 }
 2540         }
 2541 
 2542         /*
 2543          * Check for and log errors, but not too often.
 2544          */
 2545         if (--sio_timeouts_until_log > 0)
 2546                 return;
 2547         sio_timeouts_until_log = hz / sio_timeout;
 2548         for (unit = 0; unit < NSIOTOT; ++unit) {
 2549                 int     errnum;
 2550 
 2551                 com = com_addr(unit);
 2552                 if (com == NULL)
 2553                         continue;
 2554                 if (com->gone)
 2555                         continue;
 2556                 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
 2557                         u_int   delta;
 2558                         u_long  total;
 2559 
 2560                         disable_intr();
 2561                         delta = com->delta_error_counts[errnum];
 2562                         com->delta_error_counts[errnum] = 0;
 2563                         enable_intr();
 2564                         if (delta == 0)
 2565                                 continue;
 2566                         total = com->error_counts[errnum] += delta;
 2567                         log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
 2568                             unit, delta, error_desc[errnum],
 2569                             delta == 1 ? "" : "s", total);
 2570                 }
 2571         }
 2572 }
 2573 
 2574 static void
 2575 disc_optim(tp, t, com)
 2576         struct tty      *tp;
 2577         struct termios  *t;
 2578         struct com_s    *com;
 2579 {
 2580         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 2581             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 2582             && (!(t->c_iflag & PARMRK)
 2583                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 2584             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 2585             && linesw[tp->t_line].l_rint == ttyinput)
 2586                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2587         else
 2588                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2589         com->hotchar = linesw[tp->t_line].l_hotchar;
 2590 }
 2591 
 2592 /*
 2593  * Following are all routines needed for SIO to act as console
 2594  */
 2595 #include <machine/cons.h>
 2596 
 2597 struct siocnstate {
 2598         u_char  dlbl;
 2599         u_char  dlbh;
 2600         u_char  ier;
 2601         u_char  cfcr;
 2602         u_char  mcr;
 2603 };
 2604 
 2605 static speed_t siocngetspeed __P((Port_t, struct speedtab *));
 2606 static void siocnclose  __P((struct siocnstate *sp, Port_t iobase));
 2607 static void siocnopen   __P((struct siocnstate *sp, Port_t iobase, int speed));
 2608 static void siocntxwait __P((Port_t iobase));
 2609 
 2610 static void
 2611 siocntxwait(iobase)
 2612         Port_t  iobase;
 2613 {
 2614         int     timo;
 2615 
 2616         /*
 2617          * Wait for any pending transmission to finish.  Required to avoid
 2618          * the UART lockup bug when the speed is changed, and for normal
 2619          * transmits.
 2620          */
 2621         timo = 100000;
 2622         while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
 2623                != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
 2624                 ;
 2625 }
 2626 
 2627 /*
 2628  * Read the serial port specified and try to figure out what speed
 2629  * it's currently running at.  We're assuming the serial port has
 2630  * been initialized and is basicly idle.  This routine is only intended
 2631  * to be run at system startup.
 2632  *
 2633  * If the value read from the serial port doesn't make sense, return 0.
 2634  */
 2635 
 2636 static speed_t
 2637 siocngetspeed(iobase, table)
 2638         Port_t iobase;
 2639         struct speedtab *table;
 2640 {
 2641         int     code;
 2642         u_char  dlbh;
 2643         u_char  dlbl;
 2644         u_char  cfcr;
 2645 
 2646         cfcr = inb(iobase + com_cfcr);
 2647         outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
 2648 
 2649         dlbl = inb(iobase + com_dlbl);
 2650         dlbh = inb(iobase + com_dlbh);
 2651 
 2652         outb(iobase + com_cfcr, cfcr);
 2653 
 2654         code = dlbh << 8 | dlbl;
 2655 
 2656         for ( ; table->sp_speed != -1; table++)
 2657                 if (table->sp_code == code)
 2658                         return (table->sp_speed);
 2659 
 2660         return 0;       /* didn't match anything sane */
 2661 }
 2662 
 2663 static void
 2664 siocnopen(sp, iobase, speed)
 2665         struct siocnstate       *sp;
 2666         Port_t                  iobase;
 2667         int                     speed;
 2668 {
 2669         int     divisor;
 2670         u_char  dlbh;
 2671         u_char  dlbl;
 2672 
 2673         /*
 2674          * Save all the device control registers except the fifo register
 2675          * and set our default ones (cs8 -parenb speed=comdefaultrate).
 2676          * We can't save the fifo register since it is read-only.
 2677          */
 2678         sp->ier = inb(iobase + com_ier);
 2679         outb(iobase + com_ier, 0);      /* spltty() doesn't stop siointr() */
 2680         siocntxwait(iobase);
 2681         sp->cfcr = inb(iobase + com_cfcr);
 2682         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
 2683         sp->dlbl = inb(iobase + com_dlbl);
 2684         sp->dlbh = inb(iobase + com_dlbh);
 2685         /*
 2686          * Only set the divisor registers if they would change, since on
 2687          * some 16550 incompatibles (Startech), setting them clears the
 2688          * data input register.  This also reduces the effects of the
 2689          * UMC8669F bug.
 2690          */
 2691         divisor = ttspeedtab(speed, comspeedtab);
 2692         dlbl = divisor & 0xFF;
 2693         if (sp->dlbl != dlbl)
 2694                 outb(iobase + com_dlbl, dlbl);
 2695         dlbh = (u_int) divisor >> 8;
 2696         if (sp->dlbh != dlbh)
 2697                 outb(iobase + com_dlbh, dlbh);
 2698         outb(iobase + com_cfcr, CFCR_8BITS);
 2699         sp->mcr = inb(iobase + com_mcr);
 2700         /*
 2701          * We don't want interrupts, but must be careful not to "disable"
 2702          * them by clearing the MCR_IENABLE bit, since that might cause
 2703          * an interrupt by floating the IRQ line.
 2704          */
 2705         outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
 2706 }
 2707 
 2708 static void
 2709 siocnclose(sp, iobase)
 2710         struct siocnstate       *sp;
 2711         Port_t                  iobase;
 2712 {
 2713         /*
 2714          * Restore the device control registers.
 2715          */
 2716         siocntxwait(iobase);
 2717         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
 2718         if (sp->dlbl != inb(iobase + com_dlbl))
 2719                 outb(iobase + com_dlbl, sp->dlbl);
 2720         if (sp->dlbh != inb(iobase + com_dlbh))
 2721                 outb(iobase + com_dlbh, sp->dlbh);
 2722         outb(iobase + com_cfcr, sp->cfcr);
 2723         /*
 2724          * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
 2725          */
 2726         outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
 2727         outb(iobase + com_ier, sp->ier);
 2728 }
 2729 
 2730 void
 2731 siocnprobe(cp)
 2732         struct consdev  *cp;
 2733 {
 2734 #if 0
 2735         speed_t                 boot_speed;
 2736         u_char                  cfcr;
 2737         struct isa_device       *dvp;
 2738         int                     s;
 2739         struct siocnstate       sp;
 2740 
 2741         /*
 2742          * Find our first enabled console, if any.  If it is a high-level
 2743          * console device, then initialize it and return successfully.
 2744          * If it is a low-level console device, then initialize it and
 2745          * return unsuccessfully.  It must be initialized in both cases
 2746          * for early use by console drivers and debuggers.  Initializing
 2747          * the hardware is not necessary in all cases, since the i/o
 2748          * routines initialize it on the fly, but it is necessary if
 2749          * input might arrive while the hardware is switched back to an
 2750          * uninitialized state.  We can't handle multiple console devices
 2751          * yet because our low-level routines don't take a device arg.
 2752          * We trust the user to set the console flags properly so that we
 2753          * don't need to probe.
 2754          */
 2755         cp->cn_pri = CN_DEAD;
 2756         for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
 2757                 if (dvp->id_driver == &siodriver && dvp->id_enabled
 2758                     && COM_CONSOLE(dvp)) {
 2759                         siocniobase = dvp->id_iobase;
 2760                         s = spltty();
 2761                         if (boothowto & RB_SERIAL) {
 2762                                 boot_speed = siocngetspeed(siocniobase,
 2763                                                            comspeedtab);
 2764                                 if (boot_speed)
 2765                                         comdefaultrate = boot_speed;
 2766                         }
 2767 
 2768                         /*
 2769                          * Initialize the divisor latch.  We can't rely on
 2770                          * siocnopen() to do this the first time, since it 
 2771                          * avoids writing to the latch if the latch appears
 2772                          * to have the correct value.  Also, if we didn't
 2773                          * just read the speed from the hardware, then we
 2774                          * need to set the speed in hardware so that
 2775                          * switching it later is null.
 2776                          */
 2777                         cfcr = inb(siocniobase + com_cfcr);
 2778                         outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
 2779                         outb(siocniobase + com_dlbl,
 2780                              COMBRD(comdefaultrate) & 0xff);
 2781                         outb(siocniobase + com_dlbh,
 2782                              (u_int) COMBRD(comdefaultrate) >> 8);
 2783                         outb(siocniobase + com_cfcr, cfcr);
 2784 
 2785                         siocnopen(&sp, siocniobase, comdefaultrate);
 2786                         splx(s);
 2787                         if (!COM_LLCONSOLE(dvp)) {
 2788                                 cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit);
 2789                                 cp->cn_pri = COM_FORCECONSOLE(dvp)
 2790                                              || boothowto & RB_SERIAL
 2791                                              ? CN_REMOTE : CN_NORMAL;
 2792                         }
 2793                         break;
 2794                 }
 2795 #endif
 2796 }
 2797 
 2798 struct consdev siocons = {
 2799         NULL, NULL, siocngetc, siocncheckc, siocnputc,
 2800         NULL, makedev(CDEV_MAJOR, 0), CN_NORMAL,
 2801 };
 2802 
 2803 extern struct consdev *cn_tab;
 2804 
 2805 int
 2806 siocnattach(port, speed)
 2807         int port;
 2808         int speed;
 2809 {
 2810         int                     s;
 2811         u_char                  cfcr;
 2812         struct siocnstate       sp;
 2813 
 2814         siocniobase = port;
 2815         comdefaultrate = speed;
 2816 
 2817         s = spltty();
 2818 
 2819         /*
 2820          * Initialize the divisor latch.  We can't rely on
 2821          * siocnopen() to do this the first time, since it 
 2822          * avoids writing to the latch if the latch appears
 2823          * to have the correct value.  Also, if we didn't
 2824          * just read the speed from the hardware, then we
 2825          * need to set the speed in hardware so that
 2826          * switching it later is null.
 2827          */
 2828         cfcr = inb(siocniobase + com_cfcr);
 2829         outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
 2830         outb(siocniobase + com_dlbl,
 2831              COMBRD(comdefaultrate) & 0xff);
 2832         outb(siocniobase + com_dlbh,
 2833              (u_int) COMBRD(comdefaultrate) >> 8);
 2834         outb(siocniobase + com_cfcr, cfcr);
 2835 
 2836         siocnopen(&sp, siocniobase, comdefaultrate);
 2837         splx(s);
 2838 
 2839         cn_tab = &siocons;
 2840         return 0;
 2841 }
 2842 
 2843 int
 2844 siogdbattach(port, speed)
 2845         int port;
 2846         int speed;
 2847 {
 2848         int                     s;
 2849         u_char                  cfcr;
 2850         struct siocnstate       sp;
 2851 
 2852         siogdbiobase = port;
 2853         gdbdefaultrate = speed;
 2854 
 2855         s = spltty();
 2856 
 2857         /*
 2858          * Initialize the divisor latch.  We can't rely on
 2859          * siocnopen() to do this the first time, since it 
 2860          * avoids writing to the latch if the latch appears
 2861          * to have the correct value.  Also, if we didn't
 2862          * just read the speed from the hardware, then we
 2863          * need to set the speed in hardware so that
 2864          * switching it later is null.
 2865          */
 2866         cfcr = inb(siogdbiobase + com_cfcr);
 2867         outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr);
 2868         outb(siogdbiobase + com_dlbl,
 2869              COMBRD(gdbdefaultrate) & 0xff);
 2870         outb(siogdbiobase + com_dlbh,
 2871              (u_int) COMBRD(gdbdefaultrate) >> 8);
 2872         outb(siogdbiobase + com_cfcr, cfcr);
 2873 
 2874         siocnopen(&sp, siogdbiobase, gdbdefaultrate);
 2875         splx(s);
 2876 
 2877         return 0;
 2878 }
 2879 
 2880 void
 2881 siocninit(cp)
 2882         struct consdev  *cp;
 2883 {
 2884         comconsole = DEV_TO_UNIT(cp->cn_dev);
 2885 }
 2886 
 2887 int
 2888 siocncheckc(dev)
 2889         dev_t   dev;
 2890 {
 2891         int     c;
 2892         Port_t  iobase;
 2893         int     s;
 2894         struct siocnstate       sp;
 2895 
 2896         iobase = siocniobase;
 2897         s = spltty();
 2898         siocnopen(&sp, iobase, comdefaultrate);
 2899         if (inb(iobase + com_lsr) & LSR_RXRDY)
 2900                 c = inb(iobase + com_data);
 2901         else
 2902                 c = -1;
 2903         siocnclose(&sp, iobase);
 2904         splx(s);
 2905         return (c);
 2906 }
 2907 
 2908 
 2909 int
 2910 siocngetc(dev)
 2911         dev_t   dev;
 2912 {
 2913         int     c;
 2914         Port_t  iobase;
 2915         int     s;
 2916         struct siocnstate       sp;
 2917 
 2918         iobase = siocniobase;
 2919         s = spltty();
 2920         siocnopen(&sp, iobase, comdefaultrate);
 2921         while (!(inb(iobase + com_lsr) & LSR_RXRDY))
 2922                 ;
 2923         c = inb(iobase + com_data);
 2924         siocnclose(&sp, iobase);
 2925         splx(s);
 2926         return (c);
 2927 }
 2928 
 2929 void
 2930 siocnputc(dev, c)
 2931         dev_t   dev;
 2932         int     c;
 2933 {
 2934         int     s;
 2935         struct siocnstate       sp;
 2936 
 2937         s = spltty();
 2938         siocnopen(&sp, siocniobase, comdefaultrate);
 2939         siocntxwait(siocniobase);
 2940         outb(siocniobase + com_data, c);
 2941         siocnclose(&sp, siocniobase);
 2942         splx(s);
 2943 }
 2944 
 2945 int
 2946 siogdbgetc()
 2947 {
 2948         int     c;
 2949         Port_t  iobase;
 2950         int     s;
 2951         struct siocnstate       sp;
 2952 
 2953         iobase = siogdbiobase;
 2954         s = spltty();
 2955         siocnopen(&sp, iobase, gdbdefaultrate);
 2956         while (!(inb(iobase + com_lsr) & LSR_RXRDY))
 2957                 ;
 2958         c = inb(iobase + com_data);
 2959         siocnclose(&sp, iobase);
 2960         splx(s);
 2961         return (c);
 2962 }
 2963 
 2964 void
 2965 siogdbputc(c)
 2966         int     c;
 2967 {
 2968         int     s;
 2969         struct siocnstate       sp;
 2970 
 2971         s = spltty();
 2972         siocnopen(&sp, siogdbiobase, gdbdefaultrate);
 2973         siocntxwait(siogdbiobase);
 2974         outb(siogdbiobase + com_data, c);
 2975         siocnclose(&sp, siogdbiobase);
 2976         splx(s);
 2977 }
 2978 
 2979 #ifdef DSI_SOFT_MODEM
 2980 /*
 2981  * The magic code to download microcode to a "Connection 14.4+Fax"
 2982  * modem from Digicom Systems Inc.  Very magic.
 2983  */
 2984 
 2985 #define DSI_ERROR(str) { ptr = str; goto error; }
 2986 static int
 2987 LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr)
 2988 {
 2989     int int_c,int_k;
 2990     int data_0188, data_0187;
 2991 
 2992     /*
 2993      * First see if it is a DSI SoftModem
 2994      */
 2995     if(!((inb(base_io+7) ^ inb(base_io+7)) & 0x80))
 2996         return ENODEV;
 2997 
 2998     data_0188 = inb(base_io+4);
 2999     data_0187 = inb(base_io+3);
 3000     outb(base_io+3,0x80);
 3001     outb(base_io+4,0x0C);
 3002     outb(base_io+0,0x31);
 3003     outb(base_io+1,0x8C);
 3004     outb(base_io+7,0x10);
 3005     outb(base_io+7,0x19);
 3006 
 3007     if(0x18 != (inb(base_io+7) & 0x1A))
 3008         DSI_ERROR("dsp bus not granted");
 3009 
 3010     if(0x01 != (inb(base_io+7) & 0x01)) {
 3011         outb(base_io+7,0x18);
 3012         outb(base_io+7,0x19);
 3013         if(0x01 != (inb(base_io+7) & 0x01))
 3014             DSI_ERROR("program mem not granted");
 3015     }
 3016 
 3017     int_c = 0;
 3018 
 3019     while(1) {
 3020         if(int_c >= 7 || size <= 0x1800)
 3021             break;
 3022 
 3023         for(int_k = 0 ; int_k < 0x800; int_k++) {
 3024             outb(base_io+0,*ptr++);
 3025             outb(base_io+1,*ptr++);
 3026             outb(base_io+2,*ptr++);
 3027         }
 3028 
 3029         size -= 0x1800;
 3030         int_c++;
 3031     }
 3032 
 3033     if(size > 0x1800) {
 3034         outb(base_io+7,0x18);
 3035         outb(base_io+7,0x19);
 3036         if(0x00 != (inb(base_io+7) & 0x01))
 3037             DSI_ERROR("program data not granted");
 3038 
 3039         for(int_k = 0 ; int_k < 0x800; int_k++) {
 3040             outb(base_io+1,*ptr++);
 3041             outb(base_io+2,0);
 3042             outb(base_io+1,*ptr++);
 3043             outb(base_io+2,*ptr++);
 3044         }
 3045 
 3046         size -= 0x1800;
 3047 
 3048         while(size > 0x1800) {
 3049             for(int_k = 0 ; int_k < 0xC00; int_k++) {
 3050                 outb(base_io+1,*ptr++);
 3051                 outb(base_io+2,*ptr++);
 3052             }
 3053             size -= 0x1800;
 3054         }
 3055 
 3056         if(size < 0x1800) {
 3057             for(int_k=0;int_k<size/2;int_k++) {
 3058                 outb(base_io+1,*ptr++);
 3059                 outb(base_io+2,*ptr++);
 3060             }
 3061         }
 3062 
 3063     } else if (size > 0) {
 3064         if(int_c == 7) {
 3065             outb(base_io+7,0x18);
 3066             outb(base_io+7,0x19);
 3067             if(0x00 != (inb(base_io+7) & 0x01))
 3068                 DSI_ERROR("program data not granted");
 3069             for(int_k = 0 ; int_k < size/3; int_k++) {
 3070                 outb(base_io+1,*ptr++);
 3071                 outb(base_io+2,0);
 3072                 outb(base_io+1,*ptr++);
 3073                 outb(base_io+2,*ptr++);
 3074             }
 3075         } else {
 3076             for(int_k = 0 ; int_k < size/3; int_k++) {
 3077                 outb(base_io+0,*ptr++);
 3078                 outb(base_io+1,*ptr++);
 3079                 outb(base_io+2,*ptr++);
 3080             }
 3081         }
 3082     }
 3083     outb(base_io+7,0x11);
 3084     outb(base_io+7,3);
 3085 
 3086     outb(base_io+4,data_0188 & 0xfb);
 3087 
 3088     outb(base_io+3,data_0187);
 3089 
 3090     return 0;
 3091 error:
 3092     printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr);
 3093     outb(base_io+7,0x00); \
 3094     outb(base_io+3,data_0187); \
 3095     outb(base_io+4,data_0188);  \
 3096     return EIO;
 3097 }
 3098 #endif /* DSI_SOFT_MODEM */
 3099 
 3100 /*
 3101  * support PnP cards if we are using 'em
 3102  */
 3103 
 3104 #if NPNP > 0
 3105 
 3106 static pnpid_t siopnp_ids[] = {
 3107         { 0x5015f435, "MOT1550"},
 3108         { 0x8113b04e, "Supra1381"},
 3109         { 0x9012b04e, "Supra1290"},
 3110         { 0x7121b04e, "SupraExpress 56i Sp"},
 3111         { 0x11007256, "USR0011"},
 3112         { 0x01017256, "USR0101"},
 3113         { 0x30207256, "USR2030"},
 3114         { 0x31307256, "USR3031"},
 3115         { 0 }
 3116 };
 3117 
 3118 static char *siopnp_probe(u_long csn, u_long vend_id);
 3119 static void siopnp_attach(u_long csn, u_long vend_id, char *name,
 3120         struct isa_device *dev);
 3121 static u_long nsiopnp = NSIO;
 3122 
 3123 static struct pnp_device siopnp = {
 3124         "siopnp",
 3125         siopnp_probe,
 3126         siopnp_attach,
 3127         &nsiopnp,
 3128         &tty_imask
 3129 };
 3130 DATA_SET (pnpdevice_set, siopnp);
 3131 
 3132 static char *
 3133 siopnp_probe(u_long csn, u_long vend_id)
 3134 {
 3135         pnpid_t *id;
 3136         char *s = NULL;
 3137 
 3138         for(id = siopnp_ids; id->vend_id != 0; id++) {
 3139                 if (vend_id == id->vend_id) {
 3140                         s = id->id_str;
 3141                         break;
 3142                 }
 3143         }
 3144 
 3145         if (s) {
 3146                 struct pnp_cinfo d;
 3147                 read_pnp_parms(&d, 0);
 3148                 if (d.enable == 0 || d.flags & 1) {
 3149                         printf("CSN %lu is disabled.\n", csn);
 3150                         return (NULL);
 3151                 }
 3152 
 3153         }
 3154 
 3155         return (s);
 3156 }
 3157 
 3158 static void
 3159 siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev)
 3160 {
 3161         struct pnp_cinfo d;
 3162         struct isa_device *dvp;
 3163 
 3164         if (dev->id_unit >= NSIOTOT)
 3165                 return;
 3166 
 3167         if (read_pnp_parms(&d, 0) == 0) {
 3168                 printf("failed to read pnp parms\n");
 3169                 return;
 3170         }
 3171 
 3172         write_pnp_parms(&d, 0);
 3173 
 3174         enable_pnp_card();
 3175 
 3176         dev->id_iobase = d.port[0];
 3177         dev->id_irq = (1 << d.irq[0]);
 3178         dev->id_intr = siointr;
 3179         dev->id_ri_flags = RI_FAST;
 3180         dev->id_drq = -1;
 3181 
 3182         if (dev->id_driver == NULL) {
 3183                 dev->id_driver = &siodriver;
 3184                 dvp = find_isadev(isa_devtab_tty, &siodriver, 0);
 3185                 if (dvp != NULL)
 3186                         dev->id_id = dvp->id_id;
 3187         }
 3188 
 3189         if ((dev->id_alive = sioprobe(dev)) != 0)
 3190                 sioattach(dev);
 3191         else
 3192                 printf("sio%d: probe failed\n", dev->id_unit);
 3193 }
 3194 #endif
 3195 
 3196 CDEV_DRIVER_MODULE(sio, isa, sio_driver, sio_devclass,
 3197                    CDEV_MAJOR, sio_cdevsw, 0, 0);

Cache object: fa18a703cb35bd227633aef1dbdc6bb7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.