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/cy.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  * cyclades cyclom-y serial driver
    3  *      Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
    4  *
    5  * Copyright (c) 1993 Andrew Herbert.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name Andrew Herbert may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
   20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
   22  * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  * $FreeBSD: src/sys/i386/isa/cy.c,v 1.41.2.5 1999/09/05 08:12:30 peter Exp $
   31  */
   32 
   33 #include "cy.h"
   34 /*
   35  * TODO:
   36  * Check that cy16's work.
   37  * Implement BREAK.
   38  * Fix overflows when closing line.
   39  * Atomic COR change.
   40  * Consoles.
   41  */
   42 
   43 /*
   44  * Temporary compile-time configuration options.
   45  */
   46 #define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2)
   47                         /* Number of chars in the receiver FIFO before an
   48                          * an interrupt is generated.  Should depend on
   49                          * line speed.  Needs to be about 6 on a 486DX33
   50                          * for 4 active ports at 115200 bps.  Why doesn't
   51                          * 10 work?
   52                          */
   53 #define PollMode        /* Use polling-based irq service routine, not the
   54                          * hardware svcack lines.  Must be defined for
   55                          * Cyclom-16Y boards.  Less efficient for Cyclom-8Ys,
   56                          * and stops 4 * 115200 bps from working.
   57                          */
   58 #undef  Smarts          /* Enable slightly more CD1400 intelligence.  Mainly
   59                          * the output CR/LF processing, plus we can avoid a
   60                          * few checks usually done in ttyinput().
   61                          *
   62                          * XXX not fully implemented, and not particularly
   63                          * worthwhile.
   64                          */
   65 #undef  CyDebug         /* Include debugging code (not very expensive). */
   66 
   67 /* These will go away. */
   68 #undef  SOFT_CTS_OFLOW
   69 #define SOFT_HOTCHAR
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/reboot.h>
   74 #include <sys/ioctl.h>
   75 #include <sys/tty.h>
   76 #include <sys/proc.h>
   77 #include <sys/conf.h>
   78 #include <sys/dkstat.h>
   79 #include <sys/file.h>
   80 #include <sys/uio.h>
   81 #include <sys/kernel.h>
   82 #include <sys/malloc.h>
   83 #include <sys/syslog.h>
   84 #ifdef DEVFS
   85 #include <sys/devfsext.h>
   86 #endif
   87 
   88 #include <machine/clock.h>
   89 
   90 #include <i386/isa/isa_device.h>
   91 #include <i386/isa/cyreg.h>
   92 #include <i386/isa/ic/cd1400.h>
   93 
   94 /*
   95  * Dictionary so that I can name everything *sio* or *com* to compare with
   96  * sio.c.  There is also lots of ugly formatting and unnecessary ifdefs to
   97  * simplify the comparision.  These will go away.
   98  */
   99 #define LSR_BI          CD1400_RDSR_BREAK
  100 #define LSR_FE          CD1400_RDSR_FE
  101 #define LSR_OE          CD1400_RDSR_OE
  102 #define LSR_PE          CD1400_RDSR_PE
  103 #define MCR_DTR         CD1400_MSVR2_DTR
  104 #define MCR_RTS         CD1400_MSVR1_RTS
  105 #define MSR_CTS         CD1400_MSVR2_CTS
  106 #define MSR_DCD         CD1400_MSVR2_CD
  107 #define MSR_DSR         CD1400_MSVR2_DSR
  108 #define MSR_RI          CD1400_MSVR2_RI
  109 #define NSIO            (NCY * CY_MAX_PORTS)
  110 #define comconsole      cyconsole
  111 #define comdefaultrate  cydefaultrate
  112 #define com_events      cy_events
  113 #define comhardclose    cyhardclose
  114 #define commctl         cymctl
  115 #define comparam        cyparam
  116 #define comspeed        cyspeed
  117 #define comstart        cystart
  118 #define comwakeup       cywakeup
  119 #define nsio_tty        ncy_tty
  120 #define p_com_addr      p_cy_addr
  121 #define sioattach       cyattach
  122 #define sioclose        cyclose
  123 #define siodevtotty     cydevtotty
  124 #define siodriver       cydriver
  125 #define siodtrwakeup    cydtrwakeup
  126 #define sioioctl        cyioctl
  127 #define siointr         cyintr
  128 #define siointr1        cyintr1
  129 #define sioopen         cyopen
  130 #define siopoll         cypoll
  131 #define sioprobe        cyprobe
  132 #define sioread         cyread
  133 #define siosettimeout   cysettimeout
  134 #define siostop         cystop
  135 #define siowrite        cywrite
  136 #define sio_timeout     cy_timeout
  137 #define sio_timeouts_until_log  cy_timeouts_until_log
  138 #define sio_tty         cy_tty
  139 
  140 #define CY_MAX_PORTS            (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)
  141 
  142 /* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
  143 #define CD1400_xIVR_CHAN_SHIFT  3
  144 #define CD1400_xIVR_CHAN        0x1F    /* XXX reduce to pack Cyclom-8Ys */
  145 
  146 #define LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
  147 #define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
  148 #define RS_IBUFSIZE     256
  149 
  150 #define CALLOUT_MASK            0x80
  151 #define CONTROL_MASK            0x60
  152 #define CONTROL_INIT_STATE      0x20
  153 #define CONTROL_LOCK_STATE      0x40
  154 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
  155 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
  156 #define MINOR_TO_UNIT(mynor)    (((mynor) >> 16) * CY_MAX_PORTS + \
  157                                 (((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
  158 
  159 /*
  160  * Input buffer watermarks.
  161  * The external device is asked to stop sending when the buffer exactly reaches
  162  * high water, or when the high level requests it.
  163  * The high level is notified immediately (rather than at a later clock tick)
  164  * when this watermark is reached.
  165  * The buffer size is chosen so the watermark should almost never be reached.
  166  * The low watermark is invisibly 0 since the buffer is always emptied all at
  167  * once.
  168  */
  169 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
  170 
  171 /*
  172  * com state bits.
  173  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
  174  * than the other bits so that they can be tested as a group without masking
  175  * off the low bits.
  176  *
  177  * The following com and tty flags correspond closely:
  178  *      CS_BUSY         = TS_BUSY (maintained by comstart(), siopoll() and
  179  *                                 siostop())
  180  *      CS_TTGO         = ~TS_TTSTOP (maintained by comparam() and comstart())
  181  *      CS_CTS_OFLOW    = CCTS_OFLOW (maintained by comparam())
  182  *      CS_RTS_IFLOW    = CRTS_IFLOW (maintained by comparam())
  183  * TS_FLUSH is not used.
  184  * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
  185  * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
  186  */
  187 #define CS_BUSY         0x80    /* output in progress */
  188 #define CS_TTGO         0x40    /* output not stopped by XOFF */
  189 #define CS_ODEVREADY    0x20    /* external device h/w ready (CTS) */
  190 #define CS_CHECKMSR     1       /* check of MSR scheduled */
  191 #define CS_CTS_OFLOW    2       /* use CTS output flow control */
  192 #define CS_DTR_OFF      0x10    /* DTR held off */
  193 #define CS_ODONE        4       /* output completed */
  194 #define CS_RTS_IFLOW    8       /* use RTS input flow control */
  195 
  196 static  char const * const      error_desc[] = {
  197 #define CE_OVERRUN                      0
  198         "silo overflow",
  199 #define CE_INTERRUPT_BUF_OVERFLOW       1
  200         "interrupt-level buffer overflow",
  201 #define CE_TTY_BUF_OVERFLOW             2
  202         "tty-level buffer overflow",
  203 };
  204 
  205 #define CE_NTYPES                       3
  206 #define CE_RECORD(com, errnum)          (++(com)->delta_error_counts[errnum])
  207 
  208 /* types.  XXX - should be elsewhere */
  209 typedef u_char  bool_t;         /* boolean */
  210 typedef u_char volatile *cy_addr;
  211 
  212 /* queue of linear buffers */
  213 struct lbq {
  214         u_char  *l_head;        /* next char to process */
  215         u_char  *l_tail;        /* one past the last char to process */
  216         struct lbq *l_next;     /* next in queue */
  217         bool_t  l_queued;       /* nonzero if queued */
  218 };
  219 
  220 /* com device structure */
  221 struct com_s {
  222         u_char  state;          /* miscellaneous flag bits */
  223         bool_t  active_out;     /* nonzero if the callout device is open */
  224 #if 0
  225         u_char  cfcr_image;     /* copy of value written to CFCR */
  226         u_char  fifo_image;     /* copy of value written to FIFO */
  227         bool_t  hasfifo;        /* nonzero for 16550 UARTs */
  228         bool_t  loses_outints;  /* nonzero if device loses output interrupts */
  229 #endif
  230         u_char  mcr_image;      /* copy of value written to MCR */
  231 #if 0
  232 #ifdef COM_MULTIPORT
  233         bool_t  multiport;      /* is this unit part of a multiport device? */
  234 #endif /* COM_MULTIPORT */
  235         bool_t  no_irq;         /* nonzero if irq is not attached */
  236         bool_t  poll;           /* nonzero if polling is required */
  237         bool_t  poll_output;    /* nonzero if polling for output is required */
  238 #endif
  239         int     unit;           /* unit number */
  240         int     dtr_wait;       /* time to hold DTR down on close (* 1/hz) */
  241 #if 0
  242         u_int   tx_fifo_size;
  243 #endif
  244         u_int   wopeners;       /* # processes waiting for DCD in open() */
  245 
  246         /*
  247          * The high level of the driver never reads status registers directly
  248          * because there would be too many side effects to handle conveniently.
  249          * Instead, it reads copies of the registers stored here by the
  250          * interrupt handler.
  251          */
  252         u_char  last_modem_status;      /* last MSR read by intr handler */
  253         u_char  prev_modem_status;      /* last MSR handled by high level */
  254 
  255         u_char  hotchar;        /* ldisc-specific char to be handled ASAP */
  256         u_char  *ibuf;          /* start of input buffer */
  257         u_char  *ibufend;       /* end of input buffer */
  258         u_char  *ihighwater;    /* threshold in input buffer */
  259         u_char  *iptr;          /* next free spot in input buffer */
  260 
  261         struct lbq      obufq;  /* head of queue of output buffers */
  262         struct lbq      obufs[2];       /* output buffers */
  263 
  264         cy_addr cy_iobase;      /* base address of this port's cyclom */
  265         cy_addr iobase;         /* base address of this port's cd1400 */
  266         int cy_align;           /* index for register alignment */
  267 
  268         struct tty      *tp;    /* cross reference */
  269 
  270         /* Initial state. */
  271         struct termios  it_in;  /* should be in struct tty */
  272         struct termios  it_out;
  273 
  274         /* Lock state. */
  275         struct termios  lt_in;  /* should be in struct tty */
  276         struct termios  lt_out;
  277 
  278         bool_t  do_timestamp;
  279         bool_t  do_dcd_timestamp;
  280         struct timeval  timestamp;
  281         struct timeval  dcd_timestamp;
  282 
  283         u_long  bytes_in;       /* statistics */
  284         u_long  bytes_out;
  285         u_int   delta_error_counts[CE_NTYPES];
  286         u_long  error_counts[CE_NTYPES];
  287 
  288         u_int   recv_exception; /* exception chars received */
  289         u_int   mdm;            /* modem signal changes */
  290 #ifdef CyDebug
  291         u_int   start_count;    /* no. of calls to comstart() */
  292         u_int   start_real;     /* no. of calls that did something */
  293 #endif
  294         u_char  channel_control;/* CD1400 CCR control command shadow */
  295         u_char  cor[3];         /* CD1400 COR1-3 shadows */
  296         u_char  intr_enable;    /* CD1400 SRER shadow */
  297 
  298         /*
  299          * Ping-pong input buffers.  The extra factor of 2 in the sizes is
  300          * to allow for an error byte for each input byte.
  301          */
  302 #define CE_INPUT_OFFSET         RS_IBUFSIZE
  303         u_char  ibuf1[2 * RS_IBUFSIZE];
  304         u_char  ibuf2[2 * RS_IBUFSIZE];
  305 
  306         /*
  307          * Data area for output buffers.  Someday we should build the output
  308          * buffer queue without copying data.
  309          */
  310         u_char  obuf1[256];
  311         u_char  obuf2[256];
  312 #ifdef DEVFS
  313         void    *devfs_token_ttyd;
  314         void    *devfs_token_ttyl;
  315         void    *devfs_token_ttyi;
  316         void    *devfs_token_cuaa;
  317         void    *devfs_token_cual;
  318         void    *devfs_token_cuai;
  319 #endif
  320 };
  321 
  322 /*
  323  * XXX public functions in drivers should be declared in headers produced
  324  * by `config', not here.
  325  */
  326 
  327 /* Interrupt handling entry point. */
  328 void    siopoll         __P((void));
  329 
  330 /* Device switch entry points. */
  331 #define sioreset        noreset
  332 #define siommap         nommap
  333 #define siostrategy     nostrategy
  334 
  335 int     cyattach_common         __P((cy_addr cy_iobase, int cy_align));
  336 static  int     cy_units        __P((cy_addr cy_iobase, int cy_align));
  337 static  int     sioattach       __P((struct isa_device *dev));
  338 static  void    cd1400_channel_cmd __P((cy_addr iobase, int cmd, int cy_align));
  339 static  timeout_t siodtrwakeup;
  340 static  void    comhardclose    __P((struct com_s *com));
  341 #if 0
  342 static  void    siointr1        __P((struct com_s *com));
  343 #endif
  344 static  int     commctl         __P((struct com_s *com, int bits, int how));
  345 static  int     comparam        __P((struct tty *tp, struct termios *t));
  346 static  int     sioprobe        __P((struct isa_device *dev));
  347 static  void    siosettimeout   __P((void));
  348 static  int     comspeed        __P((speed_t speed, int *prescaler_io));
  349 static  void    comstart        __P((struct tty *tp));
  350 static  timeout_t comwakeup;
  351 static  void    disc_optim      __P((struct tty *tp, struct termios *t,
  352                                      struct com_s *com));
  353 
  354 #ifdef CyDebug
  355 void    cystatus        __P((int unit));
  356 #endif
  357 
  358 static char driver_name[] = "cy";
  359 
  360 /* table and macro for fast conversion from a unit number to its com struct */
  361 static  struct com_s    *p_com_addr[NSIO];
  362 #define com_addr(unit)  (p_com_addr[unit])
  363 
  364 struct isa_driver       siodriver = {
  365         sioprobe, sioattach, driver_name
  366 };
  367 
  368 static  d_open_t        sioopen;
  369 static  d_close_t       sioclose;
  370 static  d_read_t        sioread;
  371 static  d_write_t       siowrite;
  372 static  d_ioctl_t       sioioctl;
  373 static  d_stop_t        siostop;
  374 static  d_devtotty_t    siodevtotty;
  375 
  376 #define CDEV_MAJOR 48
  377 static struct cdevsw sio_cdevsw = {
  378         sioopen,        sioclose,       sioread,        siowrite,
  379         sioioctl,       siostop,        noreset,        siodevtotty,
  380         ttselect,       nommap,         NULL,           driver_name,
  381         NULL,           -1,
  382 };
  383 
  384 static  int     comconsole = -1;
  385 static  speed_t comdefaultrate = TTYDEF_SPEED;
  386 static  u_int   com_events;     /* input chars + weighted output completions */
  387 static  int     sio_timeout;
  388 static  int     sio_timeouts_until_log;
  389 #if 0 /* XXX */
  390 static struct tty       *sio_tty[NSIO];
  391 #else
  392 static struct tty       sio_tty[NSIO];
  393 #endif
  394 static  const int       nsio_tty = NSIO;
  395 
  396 #ifdef CyDebug
  397 static  u_int   cd_inbs;
  398 static  u_int   cy_inbs;
  399 static  u_int   cd_outbs;
  400 static  u_int   cy_outbs;
  401 static  u_int   cy_svrr_probes;
  402 static  u_int   cy_timeouts;
  403 #endif
  404 
  405 static  int     cy_nr_cd1400s[NCY];
  406 static  int     cy_total_devices;
  407 #undef  RxFifoThreshold
  408 static  int     volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
  409 static  int     cy_chip_offset[] = {
  410         0x0000,
  411         0x0400,
  412         0x0800,
  413         0x0c00,
  414         0x0200,
  415         0x0600,
  416         0x0a00,
  417         0x0e00
  418 };
  419 
  420 static int
  421 sioprobe(dev)
  422         struct isa_device       *dev;
  423 {
  424         cy_addr iobase;
  425 
  426         iobase = (cy_addr)dev->id_maddr;
  427 
  428         /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
  429         cd_inb(iobase, CY16_RESET, 0);  /* XXX? */
  430         DELAY(500);     /* wait for the board to get its act together */
  431 
  432         /* this is needed to get the board out of reset */
  433         cd_outb(iobase, CY_CLEAR_INTR, 0, 0);
  434         DELAY(500);
  435 
  436         return (cy_units(iobase, 0) == 0 ? 0 : -1);
  437 }
  438 
  439 static int
  440 cy_units(cy_iobase, cy_align)
  441         cy_addr cy_iobase;
  442         int cy_align;
  443 {
  444         cy_addr iobase;
  445         int cyu;
  446 
  447         for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
  448                 int     i;
  449                 u_char  firmware_version;
  450 
  451                 iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
  452                 /* wait for chip to become ready for new command */
  453                 for (i = 0; i < 10; i++) {
  454                         DELAY(50);
  455                         if (!cd_inb(iobase, CD1400_CCR, cy_align))
  456                                 break;
  457                 }
  458 
  459                 /* clear the GFRCR register */
  460                 cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
  461 
  462                 /* issue a reset command */
  463                 cd_outb(iobase, CD1400_CCR, cy_align,
  464                         CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
  465 
  466                 /* wait for the CD1400 to initialize itself */
  467                 for (i = 0; i < 200; i++) {
  468                         DELAY(50);
  469 
  470                         /* retrieve firmware version */
  471                         firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
  472                         if ((firmware_version & 0xf0) == 0x40)
  473                                 break;
  474                 }
  475 
  476                 /*
  477                  * Anything in the 0x40-0x4F range is fine.
  478                  * If one CD1400 is bad then we don't support higher
  479                  * numbered good ones on this board.
  480                  */
  481                 if ((firmware_version & 0xf0) != 0x40)
  482                         break;
  483         }
  484         return (cyu);
  485 }
  486 
  487 static int
  488 sioattach(isdp)
  489         struct isa_device *isdp;
  490 {
  491         int adapter;
  492 
  493         adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
  494         if (adapter < 0)
  495                 return (0);
  496         /*
  497          * XXX
  498          * This kludge is to allow ISA/PCI device specifications in the
  499          * kernel config file to be in any order.
  500          */
  501         if (isdp->id_unit != adapter) {
  502                 printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
  503                 isdp->id_unit = adapter; /* XXX */
  504         }
  505         isdp->id_ri_flags |= RI_FAST;
  506         return (1);
  507 }
  508 
  509 int
  510 cyattach_common(cy_iobase, cy_align)
  511         cy_addr cy_iobase;
  512         int cy_align;
  513 {
  514         int cyu, ncyu, unit, adapter;
  515         dev_t dev;
  516         cy_addr iobase;
  517 
  518         adapter = cy_total_devices;
  519         if ((u_int)adapter >= NCY) {
  520                 printf("cy%d: can't attach adapter: insufficient cy devices configured\n",
  521                     adapter);
  522                 return (-1);
  523         }
  524         ncyu = cy_units(cy_iobase, cy_align);
  525         if (ncyu == 0)
  526                 return (-1);
  527         cy_nr_cd1400s[adapter] = ncyu;
  528         cy_total_devices++;
  529 
  530         unit = adapter * CY_MAX_PORTS;
  531         for (cyu = 0; cyu < ncyu; ++cyu) {
  532                 int     cdu;
  533 
  534                 iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
  535                 /* Set up a receive timeout period of than 1+ ms. */
  536                 cd_outb(iobase, CD1400_PPR, cy_align,
  537                         howmany(CY_CLOCK / CD1400_PPR_PRESCALER, 1000));
  538 
  539                 for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
  540                         struct com_s    *com;
  541                         int             s;
  542 
  543                         com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
  544                         if (com == NULL)
  545                                 break;
  546                         bzero(com, sizeof *com);
  547                         com->unit = unit;
  548                         com->dtr_wait = 3 * hz;
  549                         com->iptr = com->ibuf = com->ibuf1;
  550                         com->ibufend = com->ibuf1 + RS_IBUFSIZE;
  551                         com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
  552                         com->obufs[0].l_head = com->obuf1;
  553                         com->obufs[1].l_head = com->obuf2;
  554 
  555                         com->cy_iobase = cy_iobase;
  556                         com->iobase = iobase;
  557                         com->cy_align = cy_align;
  558 
  559                         /*
  560                          * We don't use all the flags from <sys/ttydefaults.h> since they
  561                          * are only relevant for logins.  It's important to have echo off
  562                          * initially so that the line doesn't start blathering before the
  563                          * echo flag can be turned off.
  564                          */
  565                         com->it_in.c_iflag = 0;
  566                         com->it_in.c_oflag = 0;
  567                         com->it_in.c_cflag = TTYDEF_CFLAG;
  568                         com->it_in.c_lflag = 0;
  569                         if (unit == comconsole) {
  570                                 com->it_in.c_iflag = TTYDEF_IFLAG;
  571                                 com->it_in.c_oflag = TTYDEF_OFLAG;
  572                                 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
  573                                 com->it_in.c_lflag = TTYDEF_LFLAG;
  574                                 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
  575                         }
  576                         termioschars(&com->it_in);
  577                         com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
  578                         com->it_out = com->it_in;
  579 
  580                         s = spltty();
  581                         com_addr(unit) = com;
  582                         splx(s);
  583 
  584                         dev = makedev(CDEV_MAJOR, 0);
  585                         cdevsw_add(&dev, &sio_cdevsw, NULL);
  586 #ifdef DEVFS
  587                         com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
  588                                 unit, DV_CHR,
  589                                 UID_ROOT, GID_WHEEL, 0600, "ttyc%n%n", adapter,
  590                                 unit % CY_MAX_PORTS);
  591                         com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
  592                                 unit | CONTROL_INIT_STATE, DV_CHR,
  593                                 UID_ROOT, GID_WHEEL, 0600, "ttyic%n%n", adapter,
  594                                 unit % CY_MAX_PORTS);
  595                         com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
  596                                 unit | CONTROL_LOCK_STATE, DV_CHR,
  597                                 UID_ROOT, GID_WHEEL, 0600, "ttylc%n%n", adapter,
  598                                 unit % CY_MAX_PORTS);
  599                         com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
  600                                 unit | CALLOUT_MASK, DV_CHR,
  601                                 UID_UUCP, GID_DIALER, 0660, "cuac%n%n", adapter,
  602                                 unit % CY_MAX_PORTS);
  603                         com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
  604                                 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
  605                                 UID_UUCP, GID_DIALER, 0660, "cuaic%n%n", adapter,
  606                                 unit % CY_MAX_PORTS);
  607                         com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
  608                                 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
  609                                 UID_UUCP, GID_DIALER, 0660, "cualc%n%n", adapter,
  610                                 unit % CY_MAX_PORTS);
  611 #endif
  612                 }
  613         }
  614 
  615         /* ensure an edge for the next interrupt */
  616         cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
  617 
  618         return (adapter);
  619 }
  620 
  621 static int
  622 sioopen(dev, flag, mode, p)
  623         dev_t           dev;
  624         int             flag;
  625         int             mode;
  626         struct proc     *p;
  627 {
  628         struct com_s    *com;
  629         int             error;
  630         cy_addr         iobase;
  631         int             mynor;
  632         int             s;
  633         struct tty      *tp;
  634         int             unit;
  635 
  636         mynor = minor(dev);
  637         unit = MINOR_TO_UNIT(mynor);
  638         if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
  639                 return (ENXIO);
  640         if (mynor & CONTROL_MASK)
  641                 return (0);
  642 #if 0 /* XXX */
  643         tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
  644 #else
  645         tp = com->tp = &sio_tty[unit];
  646 #endif
  647         s = spltty();
  648         /*
  649          * We jump to this label after all non-interrupted sleeps to pick
  650          * up any changes of the device state.
  651          */
  652 open_top:
  653         while (com->state & CS_DTR_OFF) {
  654                 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0);
  655                 if (error != 0)
  656                         goto out;
  657         }
  658         if (tp->t_state & TS_ISOPEN) {
  659                 /*
  660                  * The device is open, so everything has been initialized.
  661                  * Handle conflicts.
  662                  */
  663                 if (mynor & CALLOUT_MASK) {
  664                         if (!com->active_out) {
  665                                 error = EBUSY;
  666                                 goto out;
  667                         }
  668                 } else {
  669                         if (com->active_out) {
  670                                 if (flag & O_NONBLOCK) {
  671                                         error = EBUSY;
  672                                         goto out;
  673                                 }
  674                                 error = tsleep(&com->active_out,
  675                                                TTIPRI | PCATCH, "cybi", 0);
  676                                 if (error != 0)
  677                                         goto out;
  678                                 goto open_top;
  679                         }
  680                 }
  681                 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
  682                         error = EBUSY;
  683                         goto out;
  684                 }
  685         } else {
  686                 /*
  687                  * The device isn't open, so there are no conflicts.
  688                  * Initialize it.  Initialization is done twice in many
  689                  * cases: to preempt sleeping callin opens if we are
  690                  * callout, and to complete a callin open after DCD rises.
  691                  */
  692                 tp->t_oproc = comstart;
  693                 tp->t_param = comparam;
  694                 tp->t_dev = dev;
  695                 tp->t_termios = mynor & CALLOUT_MASK
  696                                 ? com->it_out : com->it_in;
  697 #if 0
  698                 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
  699                 com->poll = com->no_irq;
  700                 com->poll_output = com->loses_outints;
  701 #endif
  702                 ++com->wopeners;
  703                 iobase = com->iobase;
  704 
  705                 /* reset this channel */
  706                 cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
  707                 cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET, com->cy_align);
  708 
  709                 /*
  710                  * Resetting disables the transmitter and receiver as well as
  711                  * flushing the fifos so some of our cached state becomes
  712                  * invalid.  The documentation suggests that all registers
  713                  * for the current channel are reset to defaults, but
  714                  * apparently none are.  We wouldn't want DTR cleared.
  715                  */
  716                 com->channel_control = 0;
  717 
  718                 /* Encode per-board unit in LIVR for access in intr routines. */
  719                 cd_outb(iobase, CD1400_LIVR, com->cy_align,
  720                         (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
  721 
  722                 /*
  723                  * raise dtr and generally set things up correctly.  this
  724                  * has the side-effect of selecting the appropriate cd1400
  725                  * channel, to help us with subsequent channel control stuff
  726                  */
  727                 error = comparam(tp, &tp->t_termios);
  728                 --com->wopeners;
  729                 if (error != 0)
  730                         goto out;
  731                 /*
  732                  * XXX we should goto open_top if comparam() slept.
  733                  */
  734                 ttsetwater(tp);
  735 #if 0
  736                 if (com->hasfifo) {
  737                         /*
  738                          * (Re)enable and drain fifos.
  739                          *
  740                          * Certain SMC chips cause problems if the fifos
  741                          * are enabled while input is ready.  Turn off the
  742                          * fifo if necessary to clear the input.  We test
  743                          * the input ready bit after enabling the fifos
  744                          * since we've already enabled them in comparam()
  745                          * and to handle races between enabling and fresh
  746                          * input.
  747                          */
  748                         while (TRUE) {
  749                                 outb(iobase + com_fifo,
  750                                      FIFO_RCV_RST | FIFO_XMT_RST
  751                                      | com->fifo_image);
  752                                 DELAY(100);
  753                                 if (!(inb(com->line_status_port) & LSR_RXRDY))
  754                                         break;
  755                                 outb(iobase + com_fifo, 0);
  756                                 DELAY(100);
  757                                 (void) inb(com->data_port);
  758                         }
  759                 }
  760 
  761                 disable_intr();
  762                 (void) inb(com->line_status_port);
  763                 (void) inb(com->data_port);
  764                 com->prev_modem_status = com->last_modem_status
  765                     = inb(com->modem_status_port);
  766                 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
  767                                        | IER_EMSC);
  768                 enable_intr();
  769 #else /* !0 */
  770                 /* XXX raise RTS too */
  771                 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
  772                 disable_intr();
  773                 com->prev_modem_status = com->last_modem_status
  774                     = cd_inb(iobase, CD1400_MSVR2, com->cy_align);
  775                 cd_outb(iobase, CD1400_SRER, com->cy_align,
  776                         com->intr_enable
  777                             = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
  778                 enable_intr();
  779 #endif /* 0 */
  780                 /*
  781                  * Handle initial DCD.  Callout devices get a fake initial
  782                  * DCD (trapdoor DCD).  If we are callout, then any sleeping
  783                  * callin opens get woken up and resume sleeping on "cybi"
  784                  * instead of "cydcd".
  785                  */
  786                 /*
  787                  * XXX `mynor & CALLOUT_MASK' should be
  788                  * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
  789                  * TRAPDOOR_CARRIER is the default initial state for callout
  790                  * devices and SOFT_CARRIER is like CLOCAL except it hides
  791                  * the true carrier.
  792                  */
  793                 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
  794                         (*linesw[tp->t_line].l_modem)(tp, 1);
  795         }
  796         /*
  797          * Wait for DCD if necessary.
  798          */
  799         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
  800             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
  801                 ++com->wopeners;
  802                 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0);
  803                 --com->wopeners;
  804                 if (error != 0)
  805                         goto out;
  806                 goto open_top;
  807         }
  808         error = (*linesw[tp->t_line].l_open)(dev, tp);
  809         disc_optim(tp, &tp->t_termios, com);
  810         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
  811                 com->active_out = TRUE;
  812         siosettimeout();
  813 out:
  814         splx(s);
  815         if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
  816                 comhardclose(com);
  817         return (error);
  818 }
  819 
  820 static int
  821 sioclose(dev, flag, mode, p)
  822         dev_t           dev;
  823         int             flag;
  824         int             mode;
  825         struct proc     *p;
  826 {
  827         struct com_s    *com;
  828         int             mynor;
  829         int             s;
  830         struct tty      *tp;
  831 
  832         mynor = minor(dev);
  833         if (mynor & CONTROL_MASK)
  834                 return (0);
  835         com = com_addr(MINOR_TO_UNIT(mynor));
  836         tp = com->tp;
  837         s = spltty();
  838         (*linesw[tp->t_line].l_close)(tp, flag);
  839         disc_optim(tp, &tp->t_termios, com);
  840         siostop(tp, FREAD | FWRITE);
  841         comhardclose(com);
  842         ttyclose(tp);
  843         siosettimeout();
  844         splx(s);
  845 #ifdef broken /* session holds a ref to the tty; can't deallocate */
  846         ttyfree(tp);
  847         com->tp = sio_tty[unit] = NULL;
  848 #endif
  849         return (0);
  850 }
  851 
  852 static void
  853 comhardclose(com)
  854         struct com_s    *com;
  855 {
  856         cy_addr         iobase;
  857         int             s;
  858         struct tty      *tp;
  859         int             unit;
  860 
  861         unit = com->unit;
  862         iobase = com->iobase;
  863         s = spltty();
  864 #if 0
  865         com->poll = FALSE;
  866         com->poll_output = FALSE;
  867 #endif
  868         com->do_timestamp = 0;
  869         cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
  870 #if 0
  871         outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
  872 #endif
  873 
  874         {
  875 #if 0
  876                 outb(iobase + com_ier, 0);
  877 #else
  878                 disable_intr();
  879                 cd_outb(iobase, CD1400_SRER, com->cy_align, com->intr_enable = 0);
  880                 enable_intr();
  881 #endif
  882                 tp = com->tp;
  883                 if ((tp->t_cflag & HUPCL)
  884                     /*
  885                      * XXX we will miss any carrier drop between here and the
  886                      * next open.  Perhaps we should watch DCD even when the
  887                      * port is closed; it is not sufficient to check it at
  888                      * the next open because it might go up and down while
  889                      * we're not watching.
  890                      */
  891                     || !com->active_out
  892                        && !(com->prev_modem_status & MSR_DCD)
  893                        && !(com->it_in.c_cflag & CLOCAL)
  894                     || !(tp->t_state & TS_ISOPEN)) {
  895                         (void)commctl(com, TIOCM_DTR, DMBIC);
  896 
  897                         /* Disable receiver (leave transmitter enabled). */
  898                         com->channel_control = CD1400_CCR_CMDCHANCTL
  899                                                | CD1400_CCR_XMTEN
  900                                                | CD1400_CCR_RCVDIS;
  901                         cd1400_channel_cmd(iobase, com->channel_control, com->cy_align);
  902 
  903                         if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
  904                                 timeout(siodtrwakeup, com, com->dtr_wait);
  905                                 com->state |= CS_DTR_OFF;
  906                         }
  907                 }
  908         }
  909 #if 0
  910         if (com->hasfifo) {
  911                 /*
  912                  * Disable fifos so that they are off after controlled
  913                  * reboots.  Some BIOSes fail to detect 16550s when the
  914                  * fifos are enabled.
  915                  */
  916                 outb(iobase + com_fifo, 0);
  917         }
  918 #endif
  919         com->active_out = FALSE;
  920         wakeup(&com->active_out);
  921         wakeup(TSA_CARR_ON(tp));        /* restart any wopeners */
  922         splx(s);
  923 }
  924 
  925 static int
  926 sioread(dev, uio, flag)
  927         dev_t           dev;
  928         struct uio      *uio;
  929         int             flag;
  930 {
  931         int             mynor;
  932         struct tty      *tp;
  933 
  934         mynor = minor(dev);
  935         if (mynor & CONTROL_MASK)
  936                 return (ENODEV);
  937         tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
  938         return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
  939 }
  940 
  941 static int
  942 siowrite(dev, uio, flag)
  943         dev_t           dev;
  944         struct uio      *uio;
  945         int             flag;
  946 {
  947         int             mynor;
  948         struct tty      *tp;
  949         int             unit;
  950 
  951         mynor = minor(dev);
  952         if (mynor & CONTROL_MASK)
  953                 return (ENODEV);
  954 
  955         unit = MINOR_TO_UNIT(mynor);
  956         tp = com_addr(unit)->tp;
  957         /*
  958          * (XXX) We disallow virtual consoles if the physical console is
  959          * a serial port.  This is in case there is a display attached that
  960          * is not the console.  In that situation we don't need/want the X
  961          * server taking over the console.
  962          */
  963         if (constty != NULL && unit == comconsole)
  964                 constty = NULL;
  965 #ifdef Smarts
  966         /* XXX duplicate ttwrite(), but without so much output processing on
  967          * CR & LF chars.  Hardly worth the effort, given that high-throughput
  968          * sessions are raw anyhow.
  969          */
  970 #else
  971         return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  972 #endif
  973 }
  974 
  975 static void
  976 siodtrwakeup(chan)
  977         void    *chan;
  978 {
  979         struct com_s    *com;
  980 
  981         com = (struct com_s *)chan;
  982         com->state &= ~CS_DTR_OFF;
  983         wakeup(&com->dtr_wait);
  984 }
  985 
  986 void
  987 siointr(unit)
  988         int     unit;
  989 {
  990         cy_addr cy_iobase, iobase;
  991         int baseu, cyu, cy_align;
  992         u_char status;
  993 
  994         baseu = unit * CY_MAX_PORTS;
  995         cy_iobase = com_addr(baseu)->cy_iobase;
  996         cy_align = com_addr(baseu)->cy_align;
  997 
  998         /* check each CD1400 in turn */
  999         for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
 1000                 iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
 1001                 /* poll to see if it has any work */
 1002                 status = cd_inb(iobase, CD1400_SVRR, cy_align);
 1003                 if (status == 0)
 1004                         continue;
 1005 #ifdef CyDebug
 1006                 ++cy_svrr_probes;
 1007 #endif
 1008                 /* service requests as appropriate, giving priority to RX */
 1009                 if (status & CD1400_SVRR_RXRDY) {
 1010                         struct com_s    *com;
 1011                         u_int           count;
 1012                         u_char          *ioptr;
 1013                         u_char          line_status;
 1014                         u_char          recv_data;
 1015                         u_char          serv_type;
 1016 #ifdef PollMode
 1017                         u_char          save_car;
 1018                         u_char          save_rir;
 1019 #endif
 1020 
 1021 #ifdef PollMode
 1022                         save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
 1023                         save_car = cd_inb(iobase, CD1400_CAR, cy_align);
 1024 
 1025                         /* enter rx service */
 1026                         cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
 1027 
 1028                         serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
 1029                         com = com_addr(baseu
 1030                                        + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
 1031                                           & CD1400_xIVR_CHAN));
 1032 #else
 1033                         /* ack receive service */
 1034                         serv_type = cy_inb(iobase, CY8_SVCACKR);
 1035 
 1036                         com = com_addr(baseu +
 1037                                        + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
 1038                                           & CD1400_xIVR_CHAN));
 1039 #endif
 1040 
 1041                 if (serv_type & CD1400_RIVR_EXCEPTION) {
 1042                         ++com->recv_exception;
 1043                         line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
 1044                         /* break/unnattached error bits or real input? */
 1045                         recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
 1046 #ifndef SOFT_HOTCHAR
 1047                         if (line_status & CD1400_RDSR_SPECIAL
 1048                             && com->hotchar != 0)
 1049                                 setsofttty();
 1050 #endif
 1051 #if 1 /* XXX "intelligent" PFO error handling would break O error handling */
 1052                         if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {
 1053                                 /*
 1054                                   Don't store PE if IGNPAR and BI if IGNBRK,
 1055                                   this hack allows "raw" tty optimization
 1056                                   works even if IGN* is set.
 1057                                 */
 1058                                 if (   com->tp == NULL
 1059                                     || !(com->tp->t_state & TS_ISOPEN)
 1060                                     || (line_status & (LSR_PE|LSR_FE))
 1061                                     &&  (com->tp->t_iflag & IGNPAR)
 1062                                     || (line_status & LSR_BI)
 1063                                     &&  (com->tp->t_iflag & IGNBRK))
 1064                                         goto cont;
 1065                                 if (   (line_status & (LSR_PE|LSR_FE))
 1066                                     && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)
 1067                                     && ((line_status & LSR_FE)
 1068                                     ||  (line_status & LSR_PE)
 1069                                     &&  (com->tp->t_iflag & INPCK)))
 1070                                         recv_data = 0;
 1071                         }
 1072 #endif /* 1 */
 1073                         ++com->bytes_in;
 1074 #ifdef SOFT_HOTCHAR
 1075                         if (com->hotchar != 0 && recv_data == com->hotchar)
 1076                                 setsofttty();
 1077 #endif
 1078                         ioptr = com->iptr;
 1079                         if (ioptr >= com->ibufend)
 1080                                 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
 1081                         else {
 1082                                 if (com->do_timestamp)
 1083                                         microtime(&com->timestamp);
 1084                                 ++com_events;
 1085                                 ioptr[0] = recv_data;
 1086                                 ioptr[CE_INPUT_OFFSET] = line_status;
 1087                                 com->iptr = ++ioptr;
 1088                                 if (ioptr == com->ihighwater
 1089                                     && com->state & CS_RTS_IFLOW)
 1090 #if 0
 1091                                         outb(com->modem_ctl_port,
 1092                                              com->mcr_image &= ~MCR_RTS);
 1093 #else
 1094                                         cd_outb(iobase, CD1400_MSVR1, cy_align,
 1095                                                 com->mcr_image &= ~MCR_RTS);
 1096 #endif
 1097                                 if (line_status & LSR_OE)
 1098                                         CE_RECORD(com, CE_OVERRUN);
 1099                         }
 1100                         goto cont;
 1101                 } else {
 1102                         int     ifree;
 1103 
 1104                         count = cd_inb(iobase, CD1400_RDCR, cy_align);
 1105                         if (!count)
 1106                                 goto cont;
 1107                         com->bytes_in += count;
 1108                         ioptr = com->iptr;
 1109                         ifree = com->ibufend - ioptr;
 1110                         if (count > ifree) {
 1111                                 count -= ifree;
 1112                                 com_events += ifree;
 1113                                 if (ifree != 0) {
 1114                                         if (com->do_timestamp)
 1115                                                 microtime(&com->timestamp);
 1116                                         do {
 1117                                                 recv_data = cd_inb(iobase,
 1118                                                                    CD1400_RDSR, cy_align);
 1119 #ifdef SOFT_HOTCHAR
 1120                                                 if (com->hotchar != 0
 1121                                                     && recv_data
 1122                                                        == com->hotchar)
 1123                                                         setsofttty();
 1124 #endif
 1125                                                 ioptr[0] = recv_data;
 1126                                                 ioptr[CE_INPUT_OFFSET] = 0;
 1127                                                 ++ioptr;
 1128                                         } while (--ifree != 0);
 1129                                 }
 1130                                 com->delta_error_counts
 1131                                     [CE_INTERRUPT_BUF_OVERFLOW] += count;
 1132                                 do {
 1133                                         recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
 1134 #ifdef SOFT_HOTCHAR
 1135                                         if (com->hotchar != 0
 1136                                             && recv_data == com->hotchar)
 1137                                                 setsofttty();
 1138 #endif
 1139                                 } while (--count != 0);
 1140                         } else {
 1141                                 if (com->do_timestamp)
 1142                                         microtime(&com->timestamp);
 1143                                 if (ioptr <= com->ihighwater
 1144                                     && ioptr + count > com->ihighwater
 1145                                     && com->state & CS_RTS_IFLOW)
 1146 #if 0
 1147                                         outb(com->modem_ctl_port,
 1148                                              com->mcr_image &= ~MCR_RTS);
 1149 #else
 1150                                         cd_outb(iobase, CD1400_MSVR1, cy_align,
 1151                                                 com->mcr_image &= ~MCR_RTS);
 1152 #endif
 1153                                 com_events += count;
 1154                                 do {
 1155                                         recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
 1156 #ifdef SOFT_HOTCHAR
 1157                                         if (com->hotchar != 0
 1158                                             && recv_data == com->hotchar)
 1159                                                 setsofttty();
 1160 #endif
 1161                                         ioptr[0] = recv_data;
 1162                                         ioptr[CE_INPUT_OFFSET] = 0;
 1163                                         ++ioptr;
 1164                                 } while (--count != 0);
 1165                         }
 1166                         com->iptr = ioptr;
 1167                 }
 1168 cont:
 1169 
 1170                         /* terminate service context */
 1171 #ifdef PollMode
 1172                         cd_outb(iobase, CD1400_RIR, cy_align,
 1173                                 save_rir
 1174                                 & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
 1175                         cd_outb(iobase, CD1400_CAR, cy_align, save_car);
 1176 #else
 1177                         cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1178 #endif
 1179                 }
 1180                 if (status & CD1400_SVRR_MDMCH) {
 1181                         struct com_s    *com;
 1182                         u_char  modem_status;
 1183 #ifdef PollMode
 1184                         u_char  save_car;
 1185                         u_char  save_mir;
 1186 #else
 1187                         u_char  vector;
 1188 #endif
 1189 
 1190 #ifdef PollMode
 1191                         save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
 1192                         save_car = cd_inb(iobase, CD1400_CAR, cy_align);
 1193 
 1194                         /* enter modem service */
 1195                         cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
 1196 
 1197                         com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
 1198                                        + (save_mir & CD1400_MIR_CHAN));
 1199 #else
 1200                         /* ack modem service */
 1201                         vector = cy_inb(iobase, CY8_SVCACKM);
 1202 
 1203                         com = com_addr(baseu
 1204                                        + ((vector >> CD1400_xIVR_CHAN_SHIFT)
 1205                                           & CD1400_xIVR_CHAN));
 1206 #endif
 1207                         ++com->mdm;
 1208                         modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
 1209                 if (modem_status != com->last_modem_status) {
 1210                         if (com->do_dcd_timestamp
 1211                             && !(com->last_modem_status & MSR_DCD)
 1212                             && modem_status & MSR_DCD)
 1213                                 microtime(&com->dcd_timestamp);
 1214 
 1215                         /*
 1216                          * Schedule high level to handle DCD changes.  Note
 1217                          * that we don't use the delta bits anywhere.  Some
 1218                          * UARTs mess them up, and it's easy to remember the
 1219                          * previous bits and calculate the delta.
 1220                          */
 1221                         com->last_modem_status = modem_status;
 1222                         if (!(com->state & CS_CHECKMSR)) {
 1223                                 com_events += LOTS_OF_EVENTS;
 1224                                 com->state |= CS_CHECKMSR;
 1225                                 setsofttty();
 1226                         }
 1227 
 1228 #ifdef SOFT_CTS_OFLOW
 1229                         /* handle CTS change immediately for crisp flow ctl */
 1230                         if (com->state & CS_CTS_OFLOW) {
 1231                                 if (modem_status & MSR_CTS) {
 1232                                         com->state |= CS_ODEVREADY;
 1233                                         if (com->state >= (CS_BUSY | CS_TTGO
 1234                                                            | CS_ODEVREADY)
 1235                                             && !(com->intr_enable
 1236                                                  & CD1400_SRER_TXRDY))
 1237                                                 cd_outb(iobase, CD1400_SRER, cy_align,
 1238                                                         com->intr_enable
 1239                                                         |= CD1400_SRER_TXRDY);
 1240                                 } else {
 1241                                         com->state &= ~CS_ODEVREADY;
 1242                                         if (com->intr_enable & CD1400_SRER_TXRDY)
 1243                                                 cd_outb(iobase, CD1400_SRER, cy_align,
 1244                                                         com->intr_enable
 1245                                                         &= ~CD1400_SRER_TXRDY);
 1246                                 }
 1247                         }
 1248 #endif
 1249                 }
 1250 
 1251                         /* terminate service context */
 1252 #ifdef PollMode
 1253                         cd_outb(iobase, CD1400_MIR, cy_align,
 1254                                 save_mir
 1255                                 & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
 1256                         cd_outb(iobase, CD1400_CAR, cy_align, save_car);
 1257 #else
 1258                         cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1259 #endif
 1260                 }
 1261                 if (status & CD1400_SVRR_TXRDY) {
 1262                         struct com_s    *com;
 1263 #ifdef PollMode
 1264                         u_char  save_car;
 1265                         u_char  save_tir;
 1266 #else
 1267                         u_char  vector;
 1268 #endif
 1269 
 1270 #ifdef PollMode
 1271                         save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
 1272                         save_car = cd_inb(iobase, CD1400_CAR, cy_align);
 1273 
 1274                         /* enter tx service */
 1275                         cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
 1276                         com = com_addr(baseu
 1277                                        + cyu * CD1400_NO_OF_CHANNELS
 1278                                        + (save_tir & CD1400_TIR_CHAN));
 1279 #else
 1280                         /* ack transmit service */
 1281                         vector = cy_inb(iobase, CY8_SVCACKT);
 1282 
 1283                         com = com_addr(baseu
 1284                                        + ((vector >> CD1400_xIVR_CHAN_SHIFT)
 1285                                           & CD1400_xIVR_CHAN));
 1286 #endif
 1287 
 1288                 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
 1289                         u_char  *ioptr;
 1290                         u_int   ocount;
 1291 
 1292                         ioptr = com->obufq.l_head;
 1293                                 ocount = com->obufq.l_tail - ioptr;
 1294                                 if (ocount > CD1400_TX_FIFO_SIZE)
 1295                                         ocount = CD1400_TX_FIFO_SIZE;
 1296                                 com->bytes_out += ocount;
 1297                                 do
 1298                                         cd_outb(iobase, CD1400_TDR, cy_align, *ioptr++);
 1299                                 while (--ocount != 0);
 1300                         com->obufq.l_head = ioptr;
 1301                         if (ioptr >= com->obufq.l_tail) {
 1302                                 struct lbq      *qp;
 1303 
 1304                                 qp = com->obufq.l_next;
 1305                                 qp->l_queued = FALSE;
 1306                                 qp = qp->l_next;
 1307                                 if (qp != NULL) {
 1308                                         com->obufq.l_head = qp->l_head;
 1309                                         com->obufq.l_tail = qp->l_tail;
 1310                                         com->obufq.l_next = qp;
 1311                                 } else {
 1312                                         /* output just completed */
 1313                                         com->state &= ~CS_BUSY;
 1314                                         cd_outb(iobase, CD1400_SRER, cy_align,
 1315                                                 com->intr_enable
 1316                                                 &= ~CD1400_SRER_TXRDY);
 1317                                 }
 1318                                 if (!(com->state & CS_ODONE)) {
 1319                                         com_events += LOTS_OF_EVENTS;
 1320                                         com->state |= CS_ODONE;
 1321                                         setsofttty();   /* handle at high level ASAP */
 1322                                 }
 1323                         }
 1324                 }
 1325 
 1326                         /* terminate service context */
 1327 #ifdef PollMode
 1328                         cd_outb(iobase, CD1400_TIR, cy_align,
 1329                                 save_tir
 1330                                 & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
 1331                         cd_outb(iobase, CD1400_CAR, cy_align, save_car);
 1332 #else
 1333                         cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1334 #endif
 1335                 }
 1336         }
 1337 
 1338         /* ensure an edge for the next interrupt */
 1339         cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
 1340 
 1341         schedsofttty();
 1342 }
 1343 
 1344 #if 0
 1345 static void
 1346 siointr1(com)
 1347         struct com_s    *com;
 1348 {
 1349 }
 1350 #endif
 1351 
 1352 static int
 1353 sioioctl(dev, cmd, data, flag, p)
 1354         dev_t           dev;
 1355         int             cmd;
 1356         caddr_t         data;
 1357         int             flag;
 1358         struct proc     *p;
 1359 {
 1360         struct com_s    *com;
 1361         int             error;
 1362         cy_addr         iobase;
 1363         int             mynor;
 1364         int             s;
 1365         struct tty      *tp;
 1366 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1367         int             oldcmd;
 1368         struct termios  term;
 1369 #endif
 1370 
 1371         mynor = minor(dev);
 1372         com = com_addr(MINOR_TO_UNIT(mynor));
 1373         iobase = com->iobase;
 1374         if (mynor & CONTROL_MASK) {
 1375                 struct termios  *ct;
 1376 
 1377                 switch (mynor & CONTROL_MASK) {
 1378                 case CONTROL_INIT_STATE:
 1379                         ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
 1380                         break;
 1381                 case CONTROL_LOCK_STATE:
 1382                         ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
 1383                         break;
 1384                 default:
 1385                         return (ENODEV);        /* /dev/nodev */
 1386                 }
 1387                 switch (cmd) {
 1388                 case TIOCSETA:
 1389                         error = suser(p->p_ucred, &p->p_acflag);
 1390                         if (error != 0)
 1391                                 return (error);
 1392                         *ct = *(struct termios *)data;
 1393                         return (0);
 1394                 case TIOCGETA:
 1395                         *(struct termios *)data = *ct;
 1396                         return (0);
 1397                 case TIOCGETD:
 1398                         *(int *)data = TTYDISC;
 1399                         return (0);
 1400                 case TIOCGWINSZ:
 1401                         bzero(data, sizeof(struct winsize));
 1402                         return (0);
 1403                 default:
 1404                         return (ENOTTY);
 1405                 }
 1406         }
 1407         tp = com->tp;
 1408 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1409         term = tp->t_termios;
 1410         oldcmd = cmd;
 1411         error = ttsetcompat(tp, &cmd, data, &term);
 1412         if (error != 0)
 1413                 return (error);
 1414         if (cmd != oldcmd)
 1415                 data = (caddr_t)&term;
 1416 #endif
 1417         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1418                 int     cc;
 1419                 struct termios *dt = (struct termios *)data;
 1420                 struct termios *lt = mynor & CALLOUT_MASK
 1421                                      ? &com->lt_out : &com->lt_in;
 1422 
 1423                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
 1424                               | (dt->c_iflag & ~lt->c_iflag);
 1425                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
 1426                               | (dt->c_oflag & ~lt->c_oflag);
 1427                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
 1428                               | (dt->c_cflag & ~lt->c_cflag);
 1429                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
 1430                               | (dt->c_lflag & ~lt->c_lflag);
 1431                 for (cc = 0; cc < NCCS; ++cc)
 1432                         if (lt->c_cc[cc] != 0)
 1433                                 dt->c_cc[cc] = tp->t_cc[cc];
 1434                 if (lt->c_ispeed != 0)
 1435                         dt->c_ispeed = tp->t_ispeed;
 1436                 if (lt->c_ospeed != 0)
 1437                         dt->c_ospeed = tp->t_ospeed;
 1438         }
 1439         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
 1440         if (error >= 0)
 1441                 return (error);
 1442         s = spltty();
 1443         error = ttioctl(tp, cmd, data, flag);
 1444         disc_optim(tp, &tp->t_termios, com);
 1445         if (error >= 0) {
 1446                 splx(s);
 1447                 return (error);
 1448         }
 1449         cd_outb(iobase, CD1400_CAR, com->cy_align, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
 1450         switch (cmd) {
 1451 #if 0
 1452         case TIOCSBRK:
 1453                 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
 1454                 break;
 1455         case TIOCCBRK:
 1456                 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
 1457                 break;
 1458 #endif /* 0 */
 1459         case TIOCSDTR:
 1460                 (void)commctl(com, TIOCM_DTR, DMBIS);
 1461                 break;
 1462         case TIOCCDTR:
 1463                 (void)commctl(com, TIOCM_DTR, DMBIC);
 1464                 break;
 1465         /*
 1466          * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
 1467          * changes get undone on the next call to comparam().
 1468          */
 1469         case TIOCMSET:
 1470                 (void)commctl(com, *(int *)data, DMSET);
 1471                 break;
 1472         case TIOCMBIS:
 1473                 (void)commctl(com, *(int *)data, DMBIS);
 1474                 break;
 1475         case TIOCMBIC:
 1476                 (void)commctl(com, *(int *)data, DMBIC);
 1477                 break;
 1478         case TIOCMGET:
 1479                 *(int *)data = commctl(com, 0, DMGET);
 1480                 break;
 1481         case TIOCMSDTRWAIT:
 1482                 /* must be root since the wait applies to following logins */
 1483                 error = suser(p->p_ucred, &p->p_acflag);
 1484                 if (error != 0) {
 1485                         splx(s);
 1486                         return (error);
 1487                 }
 1488                 com->dtr_wait = *(int *)data * hz / 100;
 1489                 break;
 1490         case TIOCMGDTRWAIT:
 1491                 *(int *)data = com->dtr_wait * 100 / hz;
 1492                 break;
 1493         case TIOCTIMESTAMP:
 1494                 com->do_timestamp = TRUE;
 1495                 *(struct timeval *)data = com->timestamp;
 1496                 break;
 1497         case TIOCDCDTIMESTAMP:
 1498                 com->do_dcd_timestamp = TRUE;
 1499                 *(struct timeval *)data = com->dcd_timestamp;
 1500                 break;
 1501         default:
 1502                 splx(s);
 1503                 return (ENOTTY);
 1504         }
 1505         splx(s);
 1506         return (0);
 1507 }
 1508 
 1509 void
 1510 siopoll()
 1511 {
 1512         int             unit;
 1513 
 1514 #ifdef CyDebug
 1515         ++cy_timeouts;
 1516 #endif
 1517         if (com_events == 0)
 1518                 return;
 1519 repeat:
 1520         for (unit = 0; unit < NSIO; ++unit) {
 1521                 u_char          *buf;
 1522                 struct com_s    *com;
 1523                 u_char          *ibuf;
 1524                 cy_addr         iobase;
 1525                 int             incc;
 1526                 struct tty      *tp;
 1527 
 1528                 com = com_addr(unit);
 1529                 if (com == NULL)
 1530                         continue;
 1531                 tp = com->tp;
 1532                 if (tp == NULL) {
 1533                         /*
 1534                          * XXX forget any events related to closed devices
 1535                          * (actually never opened devices) so that we don't
 1536                          * loop.
 1537                          */
 1538                         disable_intr();
 1539                         incc = com->iptr - com->ibuf;
 1540                         com->iptr = com->ibuf;
 1541                         if (com->state & CS_CHECKMSR) {
 1542                                 incc += LOTS_OF_EVENTS;
 1543                                 com->state &= ~CS_CHECKMSR;
 1544                         }
 1545                         com_events -= incc;
 1546                         enable_intr();
 1547                         if (incc != 0)
 1548                                 log(LOG_DEBUG,
 1549                                     "sio%d: %d events for device with no tp\n",
 1550                                     unit, incc);
 1551                         continue;
 1552                 }
 1553 
 1554                 /* switch the role of the low-level input buffers */
 1555                 if (com->iptr == (ibuf = com->ibuf)) {
 1556                         buf = NULL;     /* not used, but compiler can't tell */
 1557                         incc = 0;
 1558                 } else {
 1559                         buf = ibuf;
 1560                         disable_intr();
 1561                         incc = com->iptr - buf;
 1562                         com_events -= incc;
 1563                         if (ibuf == com->ibuf1)
 1564                                 ibuf = com->ibuf2;
 1565                         else
 1566                                 ibuf = com->ibuf1;
 1567                         com->ibufend = ibuf + RS_IBUFSIZE;
 1568                         com->ihighwater = ibuf + RS_IHIGHWATER;
 1569                         com->iptr = ibuf;
 1570 
 1571                         /*
 1572                          * There is now room for another low-level buffer full
 1573                          * of input, so enable RTS if it is now disabled and
 1574                          * there is room in the high-level buffer.
 1575                          */
 1576                         if ((com->state & CS_RTS_IFLOW)
 1577                             && !(com->mcr_image & MCR_RTS)
 1578                             && !(tp->t_state & TS_TBLOCK))
 1579 #if 0
 1580                                 outb(com->modem_ctl_port,
 1581                                      com->mcr_image |= MCR_RTS);
 1582 #else
 1583                                 iobase = com->iobase,
 1584                                 cd_outb(iobase, CD1400_CAR, com->cy_align,
 1585                                         unit & CD1400_CAR_CHAN),
 1586                                 cd_outb(iobase, CD1400_MSVR1, com->cy_align,
 1587                                         com->mcr_image |= MCR_RTS);
 1588 #endif
 1589                         enable_intr();
 1590                         com->ibuf = ibuf;
 1591                 }
 1592 
 1593                 if (com->state & CS_CHECKMSR) {
 1594                         u_char  delta_modem_status;
 1595 
 1596                         disable_intr();
 1597                         delta_modem_status = com->last_modem_status
 1598                                              ^ com->prev_modem_status;
 1599                         com->prev_modem_status = com->last_modem_status;
 1600                         com_events -= LOTS_OF_EVENTS;
 1601                         com->state &= ~CS_CHECKMSR;
 1602                         enable_intr();
 1603                         if (delta_modem_status & MSR_DCD)
 1604                                 (*linesw[tp->t_line].l_modem)
 1605                                         (tp, com->prev_modem_status & MSR_DCD);
 1606                 }
 1607                 if (com->state & CS_ODONE) {
 1608                         disable_intr();
 1609                         com_events -= LOTS_OF_EVENTS;
 1610                         com->state &= ~CS_ODONE;
 1611                         if (!(com->state & CS_BUSY))
 1612                                 com->tp->t_state &= ~TS_BUSY;
 1613                         enable_intr();
 1614                         (*linesw[tp->t_line].l_start)(tp);
 1615                 }
 1616                 if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
 1617                         continue;
 1618                 /*
 1619                  * Avoid the grotesquely inefficient lineswitch routine
 1620                  * (ttyinput) in "raw" mode.  It usually takes about 450
 1621                  * instructions (that's without canonical processing or echo!).
 1622                  * slinput is reasonably fast (usually 40 instructions plus
 1623                  * call overhead).
 1624                  */
 1625                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1626                         if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
 1627                             && (com->state & CS_RTS_IFLOW
 1628                                 || tp->t_iflag & IXOFF)
 1629                             && !(tp->t_state & TS_TBLOCK))
 1630                                 ttyblock(tp);
 1631                         tk_nin += incc;
 1632                         tk_rawcc += incc;
 1633                         tp->t_rawcc += incc;
 1634                         com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
 1635                                 += b_to_q((char *)buf, incc, &tp->t_rawq);
 1636                         ttwakeup(tp);
 1637                         if (tp->t_state & TS_TTSTOP
 1638                             && (tp->t_iflag & IXANY
 1639                                 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
 1640                                 tp->t_state &= ~TS_TTSTOP;
 1641                                 tp->t_lflag &= ~FLUSHO;
 1642                                 comstart(tp);
 1643                         }
 1644                 } else {
 1645                         do {
 1646                                 u_char  line_status;
 1647                                 int     recv_data;
 1648 
 1649                                 line_status = (u_char) buf[CE_INPUT_OFFSET];
 1650                                 recv_data = (u_char) *buf++;
 1651                                 if (line_status
 1652                                     & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
 1653                                         if (line_status & LSR_BI)
 1654                                                 recv_data |= TTY_BI;
 1655                                         if (line_status & LSR_FE)
 1656                                                 recv_data |= TTY_FE;
 1657                                         if (line_status & LSR_OE)
 1658                                                 recv_data |= TTY_OE;
 1659                                         if (line_status & LSR_PE)
 1660                                                 recv_data |= TTY_PE;
 1661                                 }
 1662                                 (*linesw[tp->t_line].l_rint)(recv_data, tp);
 1663                         } while (--incc > 0);
 1664                 }
 1665                 if (com_events == 0)
 1666                         break;
 1667         }
 1668         if (com_events >= LOTS_OF_EVENTS)
 1669                 goto repeat;
 1670 }
 1671 
 1672 static int
 1673 comparam(tp, t)
 1674         struct tty      *tp;
 1675         struct termios  *t;
 1676 {
 1677         int             bits;
 1678         int             cflag;
 1679         struct com_s    *com;
 1680         u_char          cor_change;
 1681         int             idivisor;
 1682         int             iflag;
 1683         cy_addr         iobase;
 1684         int             iprescaler;
 1685         int             itimeout;
 1686         int             odivisor;
 1687         int             oprescaler;
 1688         u_char          opt;
 1689         int             s;
 1690         int             unit;
 1691 
 1692         /* do historical conversions */
 1693         if (t->c_ispeed == 0)
 1694                 t->c_ispeed = t->c_ospeed;
 1695 
 1696         /* check requested parameters */
 1697         idivisor = comspeed(t->c_ispeed, &iprescaler);
 1698         if (idivisor < 0)
 1699                 return (EINVAL);
 1700         odivisor = comspeed(t->c_ospeed, &oprescaler);
 1701         if (odivisor < 0)
 1702                 return (EINVAL);
 1703 
 1704         /* parameters are OK, convert them to the com struct and the device */
 1705         unit = DEV_TO_UNIT(tp->t_dev);
 1706         com = com_addr(unit);
 1707         iobase = com->iobase;
 1708         s = spltty();
 1709         cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
 1710         if (odivisor == 0)
 1711                 (void)commctl(com, TIOCM_DTR, DMBIC);   /* hang up line */
 1712         else
 1713                 (void)commctl(com, TIOCM_DTR, DMBIS);
 1714 
 1715         if (idivisor != 0) {
 1716                 cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor);
 1717                 cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler);
 1718         }
 1719         if (odivisor != 0) {
 1720                 cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor);
 1721                 cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler);
 1722         }
 1723 
 1724         /*
 1725          * channel control
 1726          *      receiver enable
 1727          *      transmitter enable (always set)
 1728          */
 1729         cflag = t->c_cflag;
 1730         opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
 1731               | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
 1732         if (opt != com->channel_control) {
 1733                 com->channel_control = opt;
 1734                 cd1400_channel_cmd(iobase, opt, com->cy_align);
 1735         }
 1736 
 1737 #ifdef Smarts
 1738         /* set special chars */
 1739         /* XXX if one is _POSIX_VDISABLE, can't use some others */
 1740         if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
 1741                 cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]);
 1742         if (t->c_cc[VSTART] != _POSIX_VDISABLE)
 1743                 cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]);
 1744         if (t->c_cc[VINTR] != _POSIX_VDISABLE)
 1745                 cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]);
 1746         if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
 1747                 cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]);
 1748 #endif
 1749 
 1750         /*
 1751          * set channel option register 1 -
 1752          *      parity mode
 1753          *      stop bits
 1754          *      char length
 1755          */
 1756         opt = 0;
 1757         /* parity */
 1758         if (cflag & PARENB) {
 1759                 if (cflag & PARODD)
 1760                         opt |= CD1400_COR1_PARODD;
 1761                 opt |= CD1400_COR1_PARNORMAL;
 1762         }
 1763         iflag = t->c_iflag;
 1764         if (!(iflag & INPCK))
 1765                 opt |= CD1400_COR1_NOINPCK;
 1766         bits = 1 + 1;
 1767         /* stop bits */
 1768         if (cflag & CSTOPB) {
 1769                 ++bits;
 1770                 opt |= CD1400_COR1_STOP2;
 1771         }
 1772         /* char length */
 1773         switch (cflag & CSIZE) {
 1774         case CS5:
 1775                 bits += 5;
 1776                 opt |= CD1400_COR1_CS5;
 1777                 break;
 1778         case CS6:
 1779                 bits += 6;
 1780                 opt |= CD1400_COR1_CS6;
 1781                 break;
 1782         case CS7:
 1783                 bits += 7;
 1784                 opt |= CD1400_COR1_CS7;
 1785                 break;
 1786         default:
 1787                 bits += 8;
 1788                 opt |= CD1400_COR1_CS8;
 1789                 break;
 1790         }
 1791         cor_change = 0;
 1792         if (opt != com->cor[0]) {
 1793                 cor_change |= CD1400_CCR_COR1;
 1794                 cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt);
 1795         }
 1796 
 1797         /*
 1798          * Set receive time-out period, normally to max(one char time, 5 ms).
 1799          */
 1800         if (t->c_ispeed == 0)
 1801                 itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align);
 1802         else {
 1803                 itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
 1804 #ifdef SOFT_HOTCHAR
 1805 #define MIN_RTP         1
 1806 #else
 1807 #define MIN_RTP         5
 1808 #endif
 1809                 if (itimeout < MIN_RTP)
 1810                         itimeout = MIN_RTP;
 1811         }
 1812         if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
 1813             && t->c_cc[VTIME] * 10 > itimeout)
 1814                 itimeout = t->c_cc[VTIME] * 10;
 1815         if (itimeout > 255)
 1816                 itimeout = 255;
 1817         cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout);
 1818 
 1819         /*
 1820          * set channel option register 2 -
 1821          *      flow control
 1822          */
 1823         opt = 0;
 1824 #ifdef Smarts
 1825         if (iflag & IXANY)
 1826                 opt |= CD1400_COR2_IXANY;
 1827         if (iflag & IXOFF)
 1828                 opt |= CD1400_COR2_IXOFF;
 1829 #endif
 1830 #ifndef SOFT_CTS_OFLOW
 1831         if (cflag & CCTS_OFLOW)
 1832                 opt |= CD1400_COR2_CCTS_OFLOW;
 1833 #endif
 1834         if (opt != com->cor[1]) {
 1835                 cor_change |= CD1400_CCR_COR2;
 1836                 cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt);
 1837         }
 1838 
 1839         /*
 1840          * set channel option register 3 -
 1841          *      receiver FIFO interrupt threshold
 1842          *      flow control
 1843          */
 1844         opt = RxFifoThreshold;
 1845 #ifdef Smarts
 1846         if (t->c_lflag & ICANON)
 1847                 opt |= CD1400_COR3_SCD34;       /* detect INTR & SUSP chars */
 1848         if (iflag & IXOFF)
 1849                 /* detect and transparently handle START and STOP chars */
 1850                 opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
 1851 #endif
 1852         if (opt != com->cor[2]) {
 1853                 cor_change |= CD1400_CCR_COR3;
 1854                 cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
 1855         }
 1856 
 1857         /* notify the CD1400 if COR1-3 have changed */
 1858         if (cor_change)
 1859                 cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change, com->cy_align);
 1860 
 1861         /*
 1862          * set channel option register 4 -
 1863          *      CR/NL processing
 1864          *      break processing
 1865          *      received exception processing
 1866          */
 1867         opt = 0;
 1868         if (iflag & IGNCR)
 1869                 opt |= CD1400_COR4_IGNCR;
 1870 #ifdef Smarts
 1871         /*
 1872          * we need a new ttyinput() for this, as we don't want to
 1873          * have ICRNL && INLCR being done in both layers, or to have
 1874          * synchronisation problems
 1875          */
 1876         if (iflag & ICRNL)
 1877                 opt |= CD1400_COR4_ICRNL;
 1878         if (iflag & INLCR)
 1879                 opt |= CD1400_COR4_INLCR;
 1880 #endif
 1881         if (iflag & IGNBRK)
 1882                 opt |= CD1400_COR4_IGNBRK;
 1883         if (!(iflag & BRKINT))
 1884                 opt |= CD1400_COR4_NOBRKINT;
 1885 #if 0
 1886         /* XXX using this "intelligence" breaks reporting of overruns. */
 1887         if (iflag & IGNPAR)
 1888                 opt |= CD1400_COR4_PFO_DISCARD;
 1889         else {
 1890                 if (iflag & PARMRK)
 1891                         opt |= CD1400_COR4_PFO_ESC;
 1892                 else
 1893                         opt |= CD1400_COR4_PFO_NUL;
 1894         }
 1895 #else
 1896         opt |= CD1400_COR4_PFO_EXCEPTION;
 1897 #endif
 1898         cd_outb(iobase, CD1400_COR4, com->cy_align, opt);
 1899 
 1900         /*
 1901          * set channel option register 5 -
 1902          */
 1903         opt = 0;
 1904         if (iflag & ISTRIP)
 1905                 opt |= CD1400_COR5_ISTRIP;
 1906         if (t->c_iflag & IEXTEN)
 1907                 /* enable LNEXT (e.g. ctrl-v quoting) handling */
 1908                 opt |= CD1400_COR5_LNEXT;
 1909 #ifdef Smarts
 1910         if (t->c_oflag & ONLCR)
 1911                 opt |= CD1400_COR5_ONLCR;
 1912         if (t->c_oflag & OCRNL)
 1913                 opt |= CD1400_COR5_OCRNL;
 1914 #endif
 1915         cd_outb(iobase, CD1400_COR5, com->cy_align, opt);
 1916 
 1917         /*
 1918          * We always generate modem status change interrupts for CD changes.
 1919          * Among other things, this is necessary to track TS_CARR_ON for
 1920          * pstat to print even when the driver doesn't care.  CD changes
 1921          * should be rare so interrupts for them are not worth extra code to
 1922          * avoid.  We avoid interrupts for other modem status changes (except
 1923          * for CTS changes when SOFT_CTS_OFLOW is configured) since this is
 1924          * simplest and best.
 1925          */
 1926 
 1927         /*
 1928          * set modem change option register 1
 1929          *      generate modem interrupts on which 1 -> 0 input transitions
 1930          *      also controls auto-DTR output flow-control, which we don't use
 1931          */
 1932         opt = CD1400_MCOR1_CDzd;
 1933 #ifdef SOFT_CTS_OFLOW
 1934         if (cflag & CCTS_OFLOW)
 1935                 opt |= CD1400_MCOR1_CTSzd;
 1936 #endif
 1937         cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt);
 1938 
 1939         /*
 1940          * set modem change option register 2
 1941          *      generate modem interrupts on specific 0 -> 1 input transitions
 1942          */
 1943         opt = CD1400_MCOR2_CDod;
 1944 #ifdef SOFT_CTS_OFLOW
 1945         if (cflag & CCTS_OFLOW)
 1946                 opt |= CD1400_MCOR2_CTSod;
 1947 #endif
 1948         cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt);
 1949 
 1950         /*
 1951          * XXX should have done this long ago, but there is too much state
 1952          * to change all atomically.
 1953          */
 1954         disable_intr();
 1955 
 1956         com->state &= ~CS_TTGO;
 1957         if (!(tp->t_state & TS_TTSTOP))
 1958                 com->state |= CS_TTGO;
 1959         if (cflag & CRTS_IFLOW) {
 1960                 com->state |= CS_RTS_IFLOW;
 1961                 /*
 1962                  * If CS_RTS_IFLOW just changed from off to on, the change
 1963                  * needs to be propagated to MCR_RTS.  This isn't urgent,
 1964                  * so do it later by calling comstart() instead of repeating
 1965                  * a lot of code from comstart() here.
 1966                  */
 1967         } else if (com->state & CS_RTS_IFLOW) {
 1968                 com->state &= ~CS_RTS_IFLOW;
 1969                 /*
 1970                  * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
 1971                  * on here, since comstart() won't do it later.
 1972                  */
 1973 #if 0
 1974                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 1975 #else
 1976                 cd_outb(iobase, CD1400_MSVR1, com->cy_align,
 1977                         com->mcr_image |= MCR_RTS);
 1978 #endif
 1979         }
 1980 
 1981         /*
 1982          * Set up state to handle output flow control.
 1983          * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
 1984          * Now has 10+ msec latency, while CTS flow has 50- usec latency.
 1985          */
 1986         com->state |= CS_ODEVREADY;
 1987 #ifdef SOFT_CTS_OFLOW
 1988         com->state &= ~CS_CTS_OFLOW;
 1989         if (cflag & CCTS_OFLOW) {
 1990                 com->state |= CS_CTS_OFLOW;
 1991                 if (!(com->last_modem_status & MSR_CTS))
 1992                         com->state &= ~CS_ODEVREADY;
 1993         }
 1994 #endif
 1995         /* XXX shouldn't call functions while intrs are disabled. */
 1996         disc_optim(tp, t, com);
 1997 #if 0
 1998         /*
 1999          * Recover from fiddling with CS_TTGO.  We used to call siointr1()
 2000          * unconditionally, but that defeated the careful discarding of
 2001          * stale input in sioopen().
 2002          */
 2003         if (com->state >= (CS_BUSY | CS_TTGO))
 2004                 siointr1(com);
 2005 #endif
 2006         if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
 2007                 if (!(com->intr_enable & CD1400_SRER_TXRDY))
 2008                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2009                                 com->intr_enable |= CD1400_SRER_TXRDY);
 2010         } else {
 2011                 if (com->intr_enable & CD1400_SRER_TXRDY)
 2012                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2013                                 com->intr_enable &= ~CD1400_SRER_TXRDY);
 2014         }
 2015 
 2016         enable_intr();
 2017         splx(s);
 2018         comstart(tp);
 2019         return (0);
 2020 }
 2021 
 2022 static void
 2023 comstart(tp)
 2024         struct tty      *tp;
 2025 {
 2026         struct com_s    *com;
 2027         cy_addr         iobase;
 2028         int             s;
 2029 #ifdef CyDebug
 2030         bool_t          started;
 2031 #endif
 2032         int             unit;
 2033 
 2034         unit = DEV_TO_UNIT(tp->t_dev);
 2035         com = com_addr(unit);
 2036         iobase = com->iobase;
 2037         s = spltty();
 2038 
 2039 #ifdef CyDebug
 2040         ++com->start_count;
 2041         started = FALSE;
 2042 #endif
 2043 
 2044         disable_intr();
 2045         cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
 2046         if (tp->t_state & TS_TTSTOP) {
 2047                 com->state &= ~CS_TTGO;
 2048                 if (com->intr_enable & CD1400_SRER_TXRDY)
 2049                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2050                                 com->intr_enable &= ~CD1400_SRER_TXRDY);
 2051         } else {
 2052                 com->state |= CS_TTGO;
 2053                 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
 2054                     && !(com->intr_enable & CD1400_SRER_TXRDY))
 2055                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2056                                 com->intr_enable |= CD1400_SRER_TXRDY);
 2057         }
 2058         if (tp->t_state & TS_TBLOCK) {
 2059                 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
 2060 #if 0
 2061                         outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
 2062 #else
 2063                         cd_outb(iobase, CD1400_MSVR1, com->cy_align,
 2064                                 com->mcr_image &= ~MCR_RTS);
 2065 #endif
 2066         } else {
 2067                 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
 2068                     && com->state & CS_RTS_IFLOW)
 2069 #if 0
 2070                         outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 2071 #else
 2072                         cd_outb(iobase, CD1400_MSVR1, com->cy_align,
 2073                                 com->mcr_image |= MCR_RTS);
 2074 #endif
 2075         }
 2076         enable_intr();
 2077         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
 2078                 splx(s);
 2079                 return;
 2080         }
 2081         if (tp->t_outq.c_cc != 0) {
 2082                 struct lbq      *qp;
 2083                 struct lbq      *next;
 2084 
 2085                 if (!com->obufs[0].l_queued) {
 2086 #ifdef CyDebug
 2087                         started = TRUE;
 2088 #endif
 2089                         com->obufs[0].l_tail
 2090                             = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
 2091                                                   sizeof com->obuf1);
 2092                         com->obufs[0].l_next = NULL;
 2093                         com->obufs[0].l_queued = TRUE;
 2094                         disable_intr();
 2095                         if (com->state & CS_BUSY) {
 2096                                 qp = com->obufq.l_next;
 2097                                 while ((next = qp->l_next) != NULL)
 2098                                         qp = next;
 2099                                 qp->l_next = &com->obufs[0];
 2100                         } else {
 2101                                 com->obufq.l_head = com->obufs[0].l_head;
 2102                                 com->obufq.l_tail = com->obufs[0].l_tail;
 2103                                 com->obufq.l_next = &com->obufs[0];
 2104                                 com->state |= CS_BUSY;
 2105                                 if (com->state >= (CS_BUSY | CS_TTGO
 2106                                                    | CS_ODEVREADY))
 2107                                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2108                                                 com->intr_enable
 2109                                                 |= CD1400_SRER_TXRDY);
 2110                         }
 2111                         enable_intr();
 2112                 }
 2113                 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
 2114 #ifdef CyDebug
 2115                         started = TRUE;
 2116 #endif
 2117                         com->obufs[1].l_tail
 2118                             = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
 2119                                                   sizeof com->obuf2);
 2120                         com->obufs[1].l_next = NULL;
 2121                         com->obufs[1].l_queued = TRUE;
 2122                         disable_intr();
 2123                         if (com->state & CS_BUSY) {
 2124                                 qp = com->obufq.l_next;
 2125                                 while ((next = qp->l_next) != NULL)
 2126                                         qp = next;
 2127                                 qp->l_next = &com->obufs[1];
 2128                         } else {
 2129                                 com->obufq.l_head = com->obufs[1].l_head;
 2130                                 com->obufq.l_tail = com->obufs[1].l_tail;
 2131                                 com->obufq.l_next = &com->obufs[1];
 2132                                 com->state |= CS_BUSY;
 2133                                 if (com->state >= (CS_BUSY | CS_TTGO
 2134                                                    | CS_ODEVREADY))
 2135                                         cd_outb(iobase, CD1400_SRER, com->cy_align,
 2136                                                 com->intr_enable
 2137                                                 |= CD1400_SRER_TXRDY);
 2138                         }
 2139                         enable_intr();
 2140                 }
 2141                 tp->t_state |= TS_BUSY;
 2142         }
 2143 #ifdef CyDebug
 2144         if (started)
 2145                 ++com->start_real;
 2146 #endif
 2147 #if 0
 2148         disable_intr();
 2149         if (com->state >= (CS_BUSY | CS_TTGO))
 2150                 siointr1(com);  /* fake interrupt to start output */
 2151         enable_intr();
 2152 #endif
 2153         ttwwakeup(tp);
 2154         splx(s);
 2155 }
 2156 
 2157 static void
 2158 siostop(tp, rw)
 2159         struct tty      *tp;
 2160         int             rw;
 2161 {
 2162         struct com_s    *com;
 2163 
 2164         com = com_addr(DEV_TO_UNIT(tp->t_dev));
 2165         disable_intr();
 2166         if (rw & FWRITE) {
 2167                 com->obufs[0].l_queued = FALSE;
 2168                 com->obufs[1].l_queued = FALSE;
 2169                 if (com->state & CS_ODONE)
 2170                         com_events -= LOTS_OF_EVENTS;
 2171                 com->state &= ~(CS_ODONE | CS_BUSY);
 2172                 com->tp->t_state &= ~TS_BUSY;
 2173         }
 2174         if (rw & FREAD) {
 2175                 com_events -= (com->iptr - com->ibuf);
 2176                 com->iptr = com->ibuf;
 2177         }
 2178         enable_intr();
 2179         comstart(tp);
 2180 
 2181         /* XXX should clear h/w fifos too. */
 2182 }
 2183 
 2184 static struct tty *
 2185 siodevtotty(dev)
 2186         dev_t   dev;
 2187 {
 2188         int     mynor;
 2189         int     unit;
 2190 
 2191         mynor = minor(dev);
 2192         if (mynor & CONTROL_MASK)
 2193                 return (NULL);
 2194         unit = MINOR_TO_UNIT(mynor);
 2195         if ((u_int) unit >= NSIO)
 2196                 return (NULL);
 2197         return (&sio_tty[unit]);
 2198 }
 2199 
 2200 static int
 2201 commctl(com, bits, how)
 2202         struct com_s    *com;
 2203         int             bits;
 2204         int             how;
 2205 {
 2206         cy_addr iobase;
 2207         int     mcr;
 2208         int     msr;
 2209 
 2210         iobase = com->iobase;
 2211         if (how == DMGET) {
 2212                 if (com->channel_control & CD1400_CCR_RCVEN)
 2213                         bits |= TIOCM_LE;
 2214                 mcr = com->mcr_image;
 2215                 if (mcr & MCR_DTR)
 2216                         bits |= TIOCM_DTR;
 2217                 if (mcr & MCR_RTS)
 2218                         /* XXX wired on for Cyclom-8Ys */
 2219                         bits |= TIOCM_RTS;
 2220 
 2221                 /*
 2222                  * We must read the modem status from the hardware because
 2223                  * we don't generate modem status change interrupts for all
 2224                  * changes, so com->prev_modem_status is not guaranteed to
 2225                  * be up to date.  This is safe, unlike for sio, because
 2226                  * reading the status register doesn't clear pending modem
 2227                  * status change interrupts.
 2228                  */
 2229                 msr = cd_inb(iobase, CD1400_MSVR2, com->cy_align);
 2230 
 2231                 if (msr & MSR_CTS)
 2232                         bits |= TIOCM_CTS;
 2233                 if (msr & MSR_DCD)
 2234                         bits |= TIOCM_CD;
 2235                 if (msr & MSR_DSR)
 2236                         bits |= TIOCM_DSR;
 2237                 if (msr & MSR_RI)
 2238                         /* XXX not connected except for Cyclom-16Y? */
 2239                         bits |= TIOCM_RI;
 2240                 return (bits);
 2241         }
 2242         mcr = 0;
 2243         if (bits & TIOCM_DTR)
 2244                 mcr |= MCR_DTR;
 2245         if (bits & TIOCM_RTS)
 2246                 mcr |= MCR_RTS;
 2247         disable_intr();
 2248         switch (how) {
 2249         case DMSET:
 2250                 com->mcr_image = mcr;
 2251                 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
 2252                 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
 2253                 break;
 2254         case DMBIS:
 2255                 com->mcr_image = mcr = com->mcr_image | mcr;
 2256                 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
 2257                 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
 2258                 break;
 2259         case DMBIC:
 2260                 com->mcr_image = mcr = com->mcr_image & ~mcr;
 2261                 cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
 2262                 cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
 2263                 break;
 2264         }
 2265         enable_intr();
 2266         return (0);
 2267 }
 2268 
 2269 static void
 2270 siosettimeout()
 2271 {
 2272         struct com_s    *com;
 2273         bool_t          someopen;
 2274         int             unit;
 2275 
 2276         /*
 2277          * Set our timeout period to 1 second if no polled devices are open.
 2278          * Otherwise set it to max(1/200, 1/hz).
 2279          * Enable timeouts iff some device is open.
 2280          */
 2281         untimeout(comwakeup, (void *)NULL);
 2282         sio_timeout = hz;
 2283         someopen = FALSE;
 2284         for (unit = 0; unit < NSIO; ++unit) {
 2285                 com = com_addr(unit);
 2286                 if (com != NULL && com->tp != NULL
 2287                     && com->tp->t_state & TS_ISOPEN) {
 2288                         someopen = TRUE;
 2289 #if 0
 2290                         if (com->poll || com->poll_output) {
 2291                                 sio_timeout = hz > 200 ? hz / 200 : 1;
 2292                                 break;
 2293                         }
 2294 #endif
 2295                 }
 2296         }
 2297         if (someopen) {
 2298                 sio_timeouts_until_log = hz / sio_timeout;
 2299                 timeout(comwakeup, (void *)NULL, sio_timeout);
 2300         } else {
 2301                 /* Flush error messages, if any. */
 2302                 sio_timeouts_until_log = 1;
 2303                 comwakeup((void *)NULL);
 2304                 untimeout(comwakeup, (void *)NULL);
 2305         }
 2306 }
 2307 
 2308 static void
 2309 comwakeup(chan)
 2310         void    *chan;
 2311 {
 2312         struct com_s    *com;
 2313         int             unit;
 2314 
 2315         timeout(comwakeup, (void *)NULL, sio_timeout);
 2316 
 2317 #if 0
 2318         /*
 2319          * Recover from lost output interrupts.
 2320          * Poll any lines that don't use interrupts.
 2321          */
 2322         for (unit = 0; unit < NSIO; ++unit) {
 2323                 com = com_addr(unit);
 2324                 if (com != NULL
 2325                     && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
 2326                         disable_intr();
 2327                         siointr1(com);
 2328                         enable_intr();
 2329                 }
 2330         }
 2331 #endif
 2332 
 2333         /*
 2334          * Check for and log errors, but not too often.
 2335          */
 2336         if (--sio_timeouts_until_log > 0)
 2337                 return;
 2338         sio_timeouts_until_log = hz / sio_timeout;
 2339         for (unit = 0; unit < NSIO; ++unit) {
 2340                 int     errnum;
 2341 
 2342                 com = com_addr(unit);
 2343                 if (com == NULL)
 2344                         continue;
 2345                 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
 2346                         u_int   delta;
 2347                         u_long  total;
 2348 
 2349                         disable_intr();
 2350                         delta = com->delta_error_counts[errnum];
 2351                         com->delta_error_counts[errnum] = 0;
 2352                         enable_intr();
 2353                         if (delta == 0)
 2354                                 continue;
 2355                         total = com->error_counts[errnum] += delta;
 2356                         log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
 2357                             unit, delta, error_desc[errnum],
 2358                             delta == 1 ? "" : "s", total);
 2359                 }
 2360         }
 2361 }
 2362 
 2363 static void
 2364 disc_optim(tp, t, com)
 2365         struct tty      *tp;
 2366         struct termios  *t;
 2367         struct com_s    *com;
 2368 {
 2369 #ifndef SOFT_HOTCHAR
 2370         cy_addr iobase;
 2371         u_char  opt;
 2372 #endif
 2373 
 2374         /*
 2375          * XXX can skip a lot more cases if Smarts.  Maybe
 2376          * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
 2377          * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
 2378          */
 2379         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 2380             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 2381             && (!(t->c_iflag & PARMRK)
 2382                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 2383             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 2384             && linesw[tp->t_line].l_rint == ttyinput)
 2385                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2386         else
 2387                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2388         /*
 2389          * Prepare to reduce input latency for packet
 2390          * discplines with a end of packet character.
 2391          */
 2392         if (tp->t_line == SLIPDISC)
 2393                 com->hotchar = 0xc0;
 2394         else if (tp->t_line == PPPDISC)
 2395                 com->hotchar = 0x7e;
 2396         else
 2397                 com->hotchar = 0;
 2398 #ifndef SOFT_HOTCHAR
 2399         iobase = com->iobase;
 2400         cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN);
 2401         opt = com->cor[2] & ~CD1400_COR3_SCD34;
 2402         if (com->hotchar != 0) {
 2403                 cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar);
 2404                 cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar);
 2405                 opt |= CD1400_COR3_SCD34;
 2406         }
 2407         if (opt != com->cor[2]) {
 2408                 cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
 2409                 cd1400_channel_cmd(com->iobase,
 2410                                    CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3, com->cy_align);
 2411         }
 2412 #endif
 2413 }
 2414 
 2415 #ifdef Smarts
 2416 /* standard line discipline input routine */
 2417 int
 2418 cyinput(c, tp)
 2419         int             c;
 2420         struct tty      *tp;
 2421 {
 2422         /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
 2423          * bits, as they are done by the CD1400.  Hardly worth the effort,
 2424          * given that high-throughput sessions are raw anyhow.
 2425          */
 2426 }
 2427 #endif /* Smarts */
 2428 
 2429 static int
 2430 comspeed(speed, prescaler_io)
 2431         speed_t speed;
 2432         int     *prescaler_io;
 2433 {
 2434         int     actual;
 2435         int     error;
 2436         int     divider;
 2437         int     prescaler;
 2438         int     prescaler_unit;
 2439 
 2440         if (speed == 0)
 2441                 return (0);
 2442         if (speed < 0 || speed > 150000)
 2443                 return (-1);
 2444 
 2445         /* determine which prescaler to use */
 2446         for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
 2447                 prescaler_unit--, prescaler >>= 2) {
 2448                 if (CY_CLOCK / prescaler / speed > 63)
 2449                         break;
 2450         }
 2451 
 2452         divider = (CY_CLOCK / prescaler * 2 / speed + 1) / 2; /* round off */
 2453         if (divider > 255)
 2454                 divider = 255;
 2455         actual = CY_CLOCK/prescaler/divider;
 2456         error = ((actual - speed) * 2000 / speed + 1) / 2;      /* percentage */
 2457 
 2458         /* 3.0% max error tolerance */
 2459         if (error < -30 || error > 30)
 2460                 return (-1);
 2461 
 2462 #if 0
 2463         printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
 2464         printf("divider = %d (%x)\n", divider, divider);
 2465         printf("actual = %d\n", actual);
 2466         printf("error = %d\n", error);
 2467 #endif
 2468 
 2469         *prescaler_io = prescaler_unit;
 2470         return (divider);
 2471 }
 2472 
 2473 static void
 2474 cd1400_channel_cmd(iobase, cmd, cy_align)
 2475         cy_addr iobase;
 2476         int     cmd;
 2477         int     cy_align;
 2478 {
 2479         /* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
 2480            as the card is probed every round?  Replaced delaycount with 8k.
 2481            Either delaycount has to be implemented in FreeBSD or more sensible
 2482            way of doing these should be implemented.  DELAY isn't enough here.
 2483            */
 2484         u_int   maxwait = 5 * 8 * 1024; /* approx. 5 ms */
 2485 
 2486         /* wait for processing of previous command to complete */
 2487         while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--)
 2488                 ;
 2489 
 2490         if (!maxwait)
 2491                 log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
 2492                     5 * 8 * 1024);
 2493 
 2494         cd_outb(iobase, CD1400_CCR, cy_align, cmd);
 2495 }
 2496 
 2497 #ifdef CyDebug
 2498 /* useful in ddb */
 2499 void
 2500 cystatus(unit)
 2501         int     unit;
 2502 {
 2503         struct com_s    *com;
 2504         cy_addr         iobase;
 2505         u_int           ocount;
 2506         struct tty      *tp;
 2507 
 2508         com = com_addr(unit);
 2509         printf("info for channel %d\n", unit);
 2510         printf("------------------\n");
 2511         printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
 2512         printf("calls to upper layer:\t\t%d\n", cy_timeouts);
 2513         if (com == NULL)
 2514                 return;
 2515         iobase = com->iobase;
 2516         printf("\n");
 2517         printf("cd1400 base address:\\tt%p\n", iobase);
 2518         cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
 2519         printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
 2520         printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
 2521                com->cor[0], com->cor[1], com->cor[2]);
 2522         printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
 2523                cd_inb(iobase, CD1400_SRER, com->cy_align), com->intr_enable);
 2524         printf("service request register:\t0x%02x\n",
 2525                cd_inb(iobase, CD1400_SVRR, com->cy_align));
 2526         printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
 2527                cd_inb(iobase, CD1400_MSVR2, com->cy_align), com->prev_modem_status);
 2528         printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
 2529                cd_inb(iobase, CD1400_RIR, com->cy_align),
 2530                cd_inb(iobase, CD1400_TIR, com->cy_align),
 2531                cd_inb(iobase, CD1400_MIR, com->cy_align));
 2532         printf("\n");
 2533         printf("com state:\t\t\t0x%02x\n", com->state);
 2534         printf("calls to comstart():\t\t%d (%d useful)\n",
 2535                com->start_count, com->start_real);
 2536         printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
 2537         ocount = 0;
 2538         if (com->obufs[0].l_queued)
 2539                 ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
 2540         if (com->obufs[1].l_queued)
 2541                 ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
 2542         printf("tx buffer chars:\t\t%u\n", ocount);
 2543         printf("received chars:\t\t\t%d\n", com->bytes_in);
 2544         printf("received exceptions:\t\t%d\n", com->recv_exception);
 2545         printf("modem signal deltas:\t\t%d\n", com->mdm);
 2546         printf("transmitted chars:\t\t%d\n", com->bytes_out);
 2547         printf("\n");
 2548         tp = com->tp;
 2549         if (tp != NULL) {
 2550                 printf("tty state:\t\t\t0x%08x\n", tp->t_state);
 2551                 printf("upper layer queue lengths:\t%d raw, %d canon, %d output\n",
 2552                        tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
 2553         } else
 2554                 printf("tty state:\t\t\tclosed\n");
 2555 }
 2556 #endif /* CyDebug */

Cache object: 191975c400da00ccb4c4909c6a1f160f


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