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

Cache object: a646d7c934e69c70bfdafb7ff1dcf5c3


[ 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.