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

Cache object: aa143c8451102e2f4737775b21dbde11


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