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

Cache object: 8055bc835df85a6bb586de78570d9b85


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