home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1066 / fas.c next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  48.9 KB  |  1,999 lines

  1. /* FAS Final Async Solution driver for 386 versions of system V UNIX */
  2.  
  3. /* Originally written by
  4. Jim Murray              encore!cloud9!jjmhome!jjm
  5. 2 Mohawk Circle         harvard!m2c!jjmhome!jjm
  6. Westboro Mass 01581     jjm%jjmhome@m2c.m2c.org
  7. USA                     voice (508) 366-2813
  8. */
  9.  
  10. /* Current author:
  11. Uwe Doering        gemini@geminix.mbx.sub.org
  12. Billstedter Pfad 17 B
  13. 1000 Berlin 20
  14. West Germany
  15. */
  16.  
  17. #ident    "@(#)fas.c    2.06"
  18.  
  19. /* Note: This source code was quite heavily optimized for speed. You
  20.          may wonder that register variables aren't used everywhere.
  21.          This is because there is an overhead in memory accesses
  22.          when using register variables. As you may know data accesses
  23.          usually need much more wait states on the memory bus than
  24.          code accesses (because of page or cache misses). Therefore
  25.          saving some data accesses has higher priority than saving
  26.          code accesses.
  27.  
  28.          You may also note some not very elegant constructions that
  29.          may be intentional because they are faster. If you want to
  30.          make style improvements you should check the assembler output
  31.          whether this wouldn't slow things down.
  32.  
  33.          Decisions for speed optimization were based on assembler
  34.          listings produced by the standard UNIX V 3.X/386 C compiler.
  35. */
  36.  
  37. #include <sys/fas.h>
  38.  
  39. #if !defined (__GNUC__)
  40. #include <sys/inline.h>
  41.  
  42. /* This is a terrible ugly kludge to speed up the `inb' and `outb'
  43.    functions. I.e., originally, the `outb' inline function had an
  44.    overhead of four data memory accesses for parameter passing. This
  45.    parameter passing actually consumed more clock cycles than the
  46.    assembler `outb' command itself. Although this solution can't
  47.    prevent unnessessary register moves it limits them at least to
  48.    register to register moves that are much faster. You need a
  49.    line like the following in the declaration part of every
  50.    function that uses `inb' or `outb' calls:
  51.  
  52.     REGVAR;
  53.  
  54.    This hack should work with every compiler that knows about the
  55.    UNIX V 3.X/386 standard compiler's inline assembler directives.
  56. */
  57.  
  58. asm    void loadal (val)
  59. {
  60. %reg    val;
  61.     movl    val,%eax
  62. %mem    val;
  63.     movb    val,%al
  64. }
  65.  
  66. asm    void loaddx (val)
  67. {
  68. %reg    val;
  69.     movl    val,%edx
  70. %mem    val;
  71.     movw    val,%dx
  72. }
  73.  
  74. asm    void outbyte ()
  75. {
  76.     outb    (%dx)
  77. }
  78.  
  79. asm    int inbyte ()
  80. {
  81.     xorl    %eax,%eax
  82.     inb    (%dx)
  83. }
  84.  
  85. /* The port parameter of the `outb' macro must be one of the predefined
  86.    port macros from `fas.h' or a simple uint variable (no indirection
  87.    is allowed). Additionally, `fip' must be a register variable in the
  88.    functions where `outb' is used. This prevents the destruction of the
  89.    `eax' CPU register while loading the `edx' register with the port
  90.    address. This is highly compiler implementation specific.
  91. */
  92. #define outb(port,val) (regvar = (val), loadal (regvar), regvar = (port), loaddx (regvar), outbyte ())
  93.  
  94. #define inb(port) (regvar = (port), loaddx (regvar), inbyte ())
  95.  
  96. #define REGVAR register uint    regvar
  97.  
  98. /* This function inserts the address optimization assembler pseudo-op
  99.    wherever called.
  100. */
  101.  
  102. asm    void optim ()
  103. {
  104.     .optim
  105. }
  106.  
  107. /* This dummy function has nothing to do but to call optim so that
  108.    the `.optim' assembler pseudo-op will be included in the assembler
  109.    file. This must be the first of all functions.
  110. */
  111.  
  112. #if defined (OPTIM)    /* Define for uPort, ISC doesn't know about */
  113. static void        /* `.optim', but has turned on optimization by */
  114. dummy ()        /* default, so we don't need it there anyway. */
  115. {
  116.     optim ();
  117. }
  118. #endif
  119.  
  120. #else
  121.  
  122. #define REGVAR
  123.  
  124. extern uint    inb ();
  125. extern void    outb ();
  126.  
  127. #endif
  128.  
  129. /* functions provided by this driver */
  130. int        fasinit ();
  131. int        fasopen ();
  132. int        fasclose ();
  133. int        fasread ();
  134. int        faswrite ();
  135. int        fasioctl ();
  136. int        fasintr ();
  137. static int    fas_proc ();
  138. static void    fas_param ();
  139. static void    fas_mproc ();
  140. static uint    fas_rproc ();
  141. static void    fas_xproc ();
  142. static int    fas_rxfer ();
  143. static int    fas_xxfer ();
  144. static void    fas_cmd ();
  145. static void    fas_open_device ();
  146. static void    fas_close_device ();
  147. static int    fas_test_device ();
  148.  
  149. /* functions used by this driver */
  150. extern void    ttrstrt ();
  151. extern void    ttinit ();
  152. extern int    ttiocom ();
  153. extern void    ttyflush ();
  154. extern uint    spltty ();
  155. extern uint    splx ();
  156. extern int    sleep ();
  157. extern void    wakeup ();
  158. extern void    signal ();
  159. extern uint    timeout ();
  160. extern void    untimeout ();
  161. extern void    delay ();
  162. extern void    printf ();
  163.  
  164. /* the following stuff is defined in space.c */
  165. extern uint    fas_physical_units;
  166. extern uint    fas_port [];
  167. extern uint    fas_vec [];
  168. extern uint    fas_mcb [];
  169. extern uint    fas_modem [];
  170. extern uint    fas_flow [];
  171. extern uint    fas_int_ack_port [];
  172. extern uint    fas_int_ack [];
  173. extern uint    fas_mux_ack_port [];
  174. extern uint    fas_mux_ack [];
  175. extern struct fas_info    fas_info [];
  176. extern struct tty    fas_tty [];
  177. extern struct fas_info    *fas_info_ptr [];
  178. extern struct tty    *fas_tty_ptr [];
  179. /* end of space.c references */
  180.  
  181. /* fas_is_initted
  182.    Flag to indicate that we have been thru init.
  183.    This is realy only necessary for systems that use asyputchar
  184.    and asygetchar but it doesn't hurt to have it anyway.
  185. */
  186. int    fas_is_initted = FALSE;
  187.  
  188. /* array of pointers to the first fas_info structure for each
  189.    interrupt vector
  190. */
  191. static struct fas_info    *fas_first_int_user [NUM_INT_VECTORS];
  192.  
  193. /* the values for the various baud rates */
  194. static uint    fas_speeds [CBAUD + 1] =
  195. {    0,            BAUD_BASE/50,
  196.     BAUD_BASE/75,        BAUD_BASE/110,
  197.     (2*BAUD_BASE+134)/269,    BAUD_BASE/150,
  198.     BAUD_BASE/200,        BAUD_BASE/300,
  199.     BAUD_BASE/600,        BAUD_BASE/1200,
  200.     BAUD_BASE/1800,        BAUD_BASE/2400,
  201.     BAUD_BASE/4800,        BAUD_BASE/9600,
  202.     BAUD_BASE/19200,    BAUD_BASE/38400
  203. };
  204.  
  205. /* time for one character to completely leave the transmitter shift register */
  206. static uint    fas_ctimes [CBAUD + 1] =
  207. {    1,        HZ*15/50+2,
  208.     HZ*15/75+2,    HZ*15/110+2,
  209.     HZ*30/269+2,    HZ*15/150+2,
  210.     HZ*15/200+2,    HZ*15/300+2,
  211.     HZ*15/600+2,    HZ*15/1200+2,
  212.     HZ*15/1800+2,    HZ*15/2400+2,
  213.     HZ*15/4800+2,    HZ*15/9600+2,
  214.     HZ*15/19200+2,    HZ*15/38400+2
  215. };
  216.  
  217. /* dynamically adapt xmit buffer size to baud rate to prevent long buffer
  218.    drains at low speeds
  219.    These values are checked against boundaries and will be modified if
  220.    necessary before use. Checking is done in fas_param (). Drain time
  221.    is about 5 seconds with continuous character flow.
  222. */
  223. static uint    fas_xbuf_size [CBAUD + 1] =
  224. {    0,        50/2,
  225.     75/2,        110/2,
  226.     269/4,        150/2,
  227.     200/2,        300/2,
  228.     600/2,        1200/2,
  229.     1800/2,        2400/2,
  230.     4800/2,        9600/2,
  231.     19200/2,    38400/2
  232. };
  233.  
  234. /* lookup table for minor device number -> open mode flags translation */
  235. static uint    fas_open_modes [16] =
  236. {
  237.     OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL,
  238.     OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HW_HANDSHAKE,
  239.     OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON,
  240.     OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HW_HANDSHAKE,
  241.     OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN,
  242.     OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_HW_HANDSHAKE,
  243.     OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_FAKE_CARR_ON,
  244.     OS_OPEN_FOR_DIALOUT | OS_CHECK_CARR_ON_OPEN | OS_FAKE_CARR_ON | OS_HW_HANDSHAKE,
  245.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT,
  246.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HW_HANDSHAKE,
  247.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_UNBLOCK_ENABLE,
  248.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_UNBLOCK_ENABLE | OS_HW_HANDSHAKE,
  249.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN,
  250.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HW_HANDSHAKE,
  251.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_UNBLOCK_ENABLE,
  252.     OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_UNBLOCK_ENABLE | OS_HW_HANDSHAKE
  253. };
  254.  
  255. /* The following defines are used to take apart the minor device numbers. */
  256. #define GET_UNIT(dev)        ((dev) & 0x0f)
  257. #define GET_OPEN_MODE(dev)    (fas_open_modes [((dev) >> 4) & 0x0f])
  258.  
  259. /* lock device against concurrent use */
  260. #define get_device_lock(fip) \
  261. {\
  262.     /* sleep while device is used by an other process */\
  263.     while ((fip)->device_flags.i & DF_DEVICE_LOCKED)\
  264.         (void) sleep((caddr_t) &(fip)->device_flags.i, PZERO - 1);\
  265.     (fip)->device_flags.s |= DF_DEVICE_LOCKED;\
  266. }
  267.  
  268. /* release device */
  269. #define release_device_lock(fip) \
  270. {\
  271.     (fip)->device_flags.s &= ~DF_DEVICE_LOCKED;\
  272.     /* wakeup the process that may wait for this device */\
  273.     wakeup ((caddr_t) &(fip)->device_flags.i);\
  274. }
  275.  
  276. /* fasinit
  277.    This routine checks for the presense of the devices in the fas_port
  278.    array and if the device is present tests and initializes it.
  279.    During the initialization if the device is determined to be a
  280.    NS16550A chip the DF_DEVICE_HAS_FIFO flag is set and the FIFO will
  281.    be used.
  282.  
  283.    At boot time you will see a status message on the screen with a string
  284.    of symbols that show the init state of the ports. The symbols are as
  285.    follows:
  286.  
  287.       -   not defined in the fas_port array
  288.       ?   can't initialize port
  289.       !   port test procedure failed
  290.       *   port is initialized
  291.       F   port is initialized and has FIFOs (NS16550)
  292.  
  293.    This is convenient to check whether you have entered the proper port
  294.    base addresses in space.c.
  295. */
  296.  
  297. int
  298. fasinit ()
  299. {
  300.     register struct fas_info    *fip;
  301.     register uint    unit;
  302.     uint    logical_units;
  303.     uint    port;
  304.     char    port_stat [MAX_UNITS + 1];
  305.     REGVAR;
  306.  
  307.     if (fas_is_initted)
  308.         return(0);
  309.  
  310.     fas_is_initted = TRUE;
  311.  
  312.     for (unit = 0, logical_units = fas_physical_units * 2;
  313.         unit < logical_units; unit++)
  314.         fas_tty_ptr [unit] = &fas_tty [unit];
  315.  
  316.     for (unit = 0; unit < fas_physical_units; unit++)
  317.     {
  318.         fas_info_ptr [unit] = fip = &fas_info [unit];
  319.         port_stat [unit] = '-';
  320.         if (port = fas_port [unit])
  321.         {
  322.             /* init all of its ports */
  323.             fip->uart_port_0 = port;
  324.             fip->uart_port_1 = port + 1;
  325.             fip->uart_port_2 = port + 2;
  326.             fip->uart_port_3 = port + 3;
  327.             fip->uart_port_4 = port + 4;
  328.             fip->uart_port_5 = port + 5;
  329.             fip->uart_port_6 = port + 6;
  330.             fip->int_ack_port = fas_int_ack_port [unit];
  331.             fip->int_ack = fas_int_ack [unit];
  332.             fip->vec = fas_vec [unit];
  333.             fip->modem.i = fas_modem [unit];
  334.             fip->flow.i = fas_flow [unit];
  335.             fip->recv_ring_put_ptr = fip->recv_buffer;
  336.             fip->recv_ring_take_ptr = fip->recv_buffer;
  337.             fip->xmit_ring_put_ptr = fip->xmit_buffer;
  338.             fip->xmit_ring_take_ptr = fip->xmit_buffer;
  339.  
  340.             fip->ier.c = IE_NONE;    /* disable all ints */
  341.             outb (INT_ENABLE_PORT, fip->ier.i);
  342.             if (inb (INT_ENABLE_PORT) != fip->ier.i)
  343.             {
  344.                 port_stat [unit] = '?';
  345.                 continue;    /* a hardware error */
  346.             }
  347.  
  348.             if (!fas_test_device (fip))
  349.             {
  350.                 port_stat [unit] = '!';
  351.                 continue;    /* a hardware error */
  352.             }
  353.  
  354.             fip->lcr.c = 0;
  355.             outb (LINE_CTL_PORT, fip->lcr.i);
  356.             fip->mcr.i = fas_mcb [unit];
  357.             outb (MDM_CTL_PORT, fip->mcr.i);
  358.  
  359.             port_stat [unit] = '*';
  360.  
  361.             /* let's see if it's an NS16550 */
  362.             outb (FIFO_CTL_PORT, STANDARD_FIFO_INIT);
  363.             if (!(~inb (INT_ID_PORT) & II_FIFO_ENABLED))
  364.             {
  365.                 fip->device_flags.s |= DF_DEVICE_HAS_FIFO;
  366.                 port_stat [unit] = 'F';
  367.             }
  368.             /* clear and disable the FIFO */
  369.             outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
  370.  
  371.             /* clear potential interrupts */
  372.             inb (MDM_STATUS_PORT);
  373.             inb (RCV_DATA_PORT);
  374.             inb (RCV_DATA_PORT);
  375.             inb (LINE_STATUS_PORT);
  376.             inb (INT_ID_PORT);
  377.             if (INT_ACK_PORT)
  378.                 outb (INT_ACK_PORT, fip->int_ack);
  379.             if (port = fas_mux_ack_port [fip->vec])
  380.                 outb (port, fas_mux_ack [fip->vec]);
  381.  
  382.             /* show that it is present and configured */
  383.             fip->device_flags.s |= DF_DEVICE_CONFIGURED;
  384.         }
  385.     }
  386.  
  387. #if defined (NEED_PUT_GETCHAR)
  388.     fip = &fas_info [0];
  389.     fip->mcr.c |= INITIAL_MDM_CONTROL;
  390.     outb (MDM_CTL_PORT, fip->mcr.i);
  391.  
  392.     fip->lcr.c = INITIAL_LINE_CONTROL;
  393.     outb (LINE_CTL_PORT, fip->lcr.i | LC_ENABLE_DIVISOR);
  394.     outb (DIVISOR_LSB_PORT, INITIAL_BAUD_RATE);
  395.     outb (DIVISOR_MSB_PORT, (INITIAL_BAUD_RATE) >> 8);
  396.     outb (LINE_CTL_PORT, fip->lcr.i);
  397. #endif
  398.  
  399.     port_stat [unit] = '\0';
  400.     printf ("\nFAS 2.06.0 async driver: Port 0-%d init state is [%s]\n\n",
  401.             unit - 1,
  402.             port_stat);
  403.  
  404.     return(0);
  405. }
  406.  
  407. /* Open a line */
  408.  
  409. /* There are a few differences between this and a normal serial
  410.    device.
  411.  
  412.    For each physical port there are two logical minor devices.
  413.    For each logical minor device there are several operating modes
  414.    that are selected by some of the higher bits of the minor
  415.    device number. Only one logical minor device can be open at
  416.    the same time.
  417.  
  418.  - Minor devices that *don't* block on open if no carrier is present:
  419.  
  420.     Bitmap:   0 m m h x x x x
  421.  
  422.        `m m' are the mode bits as follows:
  423.  
  424.         0 0   The carrier signal is totally ignored. With carrier high->low
  425.           *no* SIGHUP signal is generated.
  426.         0 1   After an initial open, the carrier signal is ignored.
  427.           Although, carrier high->low generates a SIGHUP signal. From
  428.           thereon the device is carrier controlled until the last
  429.           process has closed the device. An ioctl call with a TCSETA*
  430.                   command resets the device to ignore carrier again until the
  431.                   next carrier high->low.
  432.         1 0   The device is carrier controlled. Additionally, if on open
  433.           the carrier signal is low, a SIGHUP signal is sent
  434.                   immediately.
  435.         1 1   The device behaves the same as with mode `0 1'. Additionally,
  436.           if on open the carrier signal is low, a SIGHUP signal is sent
  437.           immediately.
  438.  
  439.  - Minor devices that *do* block on open if no carrier is present:
  440.  
  441.     Bitmap:   1 m m h x x x x
  442.  
  443.        `m m' are the mode bits as follows:
  444.  
  445.         0 0   The device is carrier controlled.
  446.         0 1   The device is carrier controlled. An unblock signal wakes
  447.                   up the waiting open and I/O is possible regardless of
  448.                   carrier until a carrier high->low. Thereafter the device
  449.                   is again fully carrier controlled.
  450.         1 0   Same as mode `0 0', but a parallel non-blocking open
  451.           is possible while waiting for carrier.
  452.         1 1   Same as mode `0 1', but a parallel non-blocking open
  453.           is possible while waiting for carrier.
  454.  
  455.  - Description of the remaining bits of the bitmap:
  456.  
  457.        `h'    If set to `1', the device has hardware handshake. Refer
  458.           to the `space.c' file to determine which port signals
  459.           are actually used for that purpose.
  460.        `x x x x'
  461.           This is the physical port number. This driver supports
  462.           up to 16 ports. If you need more, you should use an
  463.           intelligent serial card because more than 16 devices
  464.           will eat up to much CPU time with this dumb-port approach.
  465.  
  466.  - Note: If a device is carrier controlled, this implies the generation of
  467.      a SIGHUP signal with every carrier high->low. This is of course only
  468.      true if the CLOCAL flag is *not* set.
  469.  
  470.      If you use more than a few ports and you have a high volume of
  471.      receiver data at a high baud rate, the ports may lose characters.
  472.      This is simply a hardware limitation and can't be cured by any
  473.      software. But there is a pin-to-pin compatible replacement
  474.      for the i8250 and NS16450 devices. It's the NS16550 and has
  475.      separate 16-character I/O FIFOs. This will make any character
  476.      loss at least very improbable. Also, the system is loaded
  477.      much less because whenever possible up to 16 characters are
  478.      processed at a single port interrupt.
  479.  
  480.          On my own system I prefer a minor device number of `0011xxxx'
  481.          (48 + device #) for the non-blocking tty node and `1101xxxx'
  482.          (208 + device #) for the blocking tty node. This gives me
  483.          the SIGHUP signal on carrier loss and hardware flow control
  484.          with both logical devices. Dialout while a dialin open
  485.          is waiting for the carrier is also possible with this setup.
  486.  
  487. This function is called for every open, as opposed to the fasclose
  488. function which is called only with the last close.
  489. */
  490.  
  491. int
  492. fasopen (dev, flag)
  493. int    dev;
  494. int    flag;
  495. {
  496.     register struct fas_info    *fip;
  497.     register struct tty        *ttyp;
  498.     register uint    open_mode;
  499.     uint    physical_unit;
  500.     int    old_level;
  501.  
  502.     physical_unit = GET_UNIT (dev);
  503.  
  504.     /* check for valid port number */
  505.     if (physical_unit >= fas_physical_units)
  506.     {
  507.         u.u_error = ENXIO;
  508.         return(-1);
  509.     }
  510.  
  511.     fip = fas_info_ptr [physical_unit];
  512.  
  513.     /* was the port present at init time ? */
  514.     if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
  515.     {
  516.         u.u_error = ENXIO;
  517.         return(-1);
  518.     }
  519.  
  520.     open_mode = GET_OPEN_MODE (dev);
  521.  
  522.     old_level = spltty ();
  523.     get_device_lock (fip);
  524.  
  525.     /* If this is a getty open and the device is already open
  526.        for dialout, wait until device is closed.
  527.     */
  528.     while ((open_mode & OS_OPEN_FOR_GETTY)
  529.             && (fip->o_state & OS_OPEN_FOR_DIALOUT))
  530.     {
  531.         release_device_lock (fip);
  532.         (void) sleep ((caddr_t) &fip->o_state, TTIPRI);
  533.         get_device_lock (fip);
  534.     }
  535.     
  536.     /* If the device is already open and another open uses a different
  537.        open mode or if a getty open waits for carrier and doesn't allow
  538.        parallel dialout opens, return with I/O error.
  539.     */
  540.     if ((fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY)
  541.                 ? (OS_OPEN_STATES | OS_WAIT_OPEN)
  542.                 : (OS_OPEN_STATES | OS_NO_DIALOUT)))
  543.         && ((open_mode ^ fip->o_state) & OS_TEST_MASK))
  544.     {
  545.         u.u_error = EIO;
  546.         release_device_lock (fip);
  547.         (void) splx (old_level);
  548.         return(-1);
  549.     }
  550.  
  551.     /* set up pointer to tty structure */
  552.     ttyp = (open_mode & OS_OPEN_FOR_GETTY)
  553.         ? fas_tty_ptr [physical_unit + fas_physical_units]
  554.         : fas_tty_ptr [physical_unit];
  555.  
  556.     /* things to do on first open only */
  557.     if (!(fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY)
  558.                 ? (OS_OPEN_STATES | OS_WAIT_OPEN)
  559.                 : OS_OPEN_STATES)))
  560.     {
  561.         /* init data structures */
  562.         fip->tty = ttyp;
  563.         ttinit (ttyp);
  564.         ttyp->t_proc = fas_proc;
  565.         fip->po_state = fip->o_state;
  566.         fip->o_state = open_mode & ~OS_OPEN_STATES;
  567.         /* open physical device if not yet open */
  568.         if (!(fip->device_flags.i & DF_DEVICE_OPEN))
  569.             fas_open_device (fip);
  570.         fas_param (fip);    /* set up port registers */
  571.         fas_mproc (fip, fip->msr);    /* set up modem status flags */
  572.     }
  573.  
  574.     /* If getty open and the FNDELAY flag is not set,
  575.        block and wait for carrier.
  576.     */
  577.     if ((open_mode & OS_OPEN_FOR_GETTY) && !(flag & FNDELAY))
  578.     {
  579.         /* sleep while open for dialout or no carrier */
  580.         while ((fip->o_state & OS_OPEN_FOR_DIALOUT)
  581.             || !(ttyp->t_state & CARR_ON))
  582.         {
  583.             ttyp->t_state |= WOPEN;
  584.             release_device_lock (fip);
  585.             (void) sleep((caddr_t) &ttyp->t_canq, TTIPRI);
  586.             get_device_lock (fip);
  587.             ttyp->t_state &= ~WOPEN;
  588.         }
  589.     }
  590.  
  591.     (*linesw [ttyp->t_line].l_open) (ttyp);
  592.  
  593.     /* set open type flags */
  594.     fip->o_state = open_mode;
  595.  
  596.     if ((open_mode & OS_CHECK_CARR_ON_OPEN)
  597.         && (~fip->msr & fip->modem.m.ca)
  598.         && !(fip->cflag & CLOCAL))
  599.     {
  600.         signal (ttyp->t_pgrp, SIGHUP);
  601.         ttyflush (ttyp, FREAD | FWRITE);
  602.     }
  603.  
  604.     release_device_lock (fip);
  605.     (void) splx (old_level);
  606.     return(0);
  607. }
  608.  
  609. /* Close a tty line. This is only called if there is no other
  610.    concurrent open left. A blocked getty open is not counted as
  611.    a concurrent open because in this state it isn't really open.
  612. */
  613. int
  614. fasclose (dev)
  615. int    dev;
  616. {
  617.     register struct fas_info    *fip;
  618.     register struct tty        *ttyp;
  619.     uint    open_mode;
  620.     uint    physical_unit;
  621.     int    old_level;
  622.  
  623.     physical_unit = GET_UNIT (dev);
  624.  
  625.     fip = fas_info_ptr [physical_unit];
  626.  
  627.     open_mode = GET_OPEN_MODE (dev);
  628.  
  629.     /* set up pointer to tty structure */
  630.     ttyp = (open_mode & OS_OPEN_FOR_GETTY)
  631.         ? fas_tty_ptr [physical_unit + fas_physical_units]
  632.         : fas_tty_ptr [physical_unit];
  633.     
  634.     old_level = spltty ();
  635.  
  636.     (*linesw [ttyp->t_line].l_close) (ttyp);
  637.  
  638.     get_device_lock (fip);
  639.  
  640.     if (open_mode & OS_OPEN_FOR_GETTY)
  641.     {
  642.         /* not waiting any more */
  643.         ttyp->t_state &= ~WOPEN;
  644.         if (!(fip->o_state & OS_OPEN_FOR_DIALOUT))
  645.         {
  646.             fas_close_device (fip);
  647.             fip->o_state = OS_DEVICE_CLOSED;
  648.         }
  649.         else
  650.             fip->po_state = OS_DEVICE_CLOSED;
  651.     }
  652.     else
  653.     {
  654.         fas_close_device (fip);
  655.         fip->o_state = OS_DEVICE_CLOSED;
  656.         /* If there is a waiting getty open on
  657.            this port, reopen the physical device.
  658.         */
  659.         if (fip->po_state & OS_WAIT_OPEN)
  660.         {
  661.             /* get the getty version of the
  662.                tty structure
  663.             */
  664.             fip->tty = fas_tty_ptr [physical_unit
  665.                     + fas_physical_units];
  666.             fip->o_state = fip->po_state;
  667.             fip->po_state = OS_DEVICE_CLOSED;
  668.             if (!(fip->device_flags.i & DF_DO_HANGUP))
  669.             {
  670.                 fas_open_device (fip);
  671.                 fas_param (fip);    /* set up port registers */
  672.                 fas_mproc (fip, fip->msr);    /* set up modem status flags */
  673.             }
  674.         }
  675.         wakeup ((caddr_t) &fip->o_state);
  676.     }
  677.  
  678.     if (!(fip->device_flags.i & DF_DO_HANGUP))
  679.         release_device_lock (fip);
  680.  
  681.     (void) splx (old_level);
  682.     return(0);
  683. }
  684.  
  685. /* read characters from the input buffer */
  686. int
  687. fasread (dev)
  688. int    dev;
  689. {
  690.     register struct fas_info    *fip;
  691.     register struct tty    *ttyp;
  692.     int    old_level;
  693.     REGVAR;
  694.  
  695.     fip = fas_info_ptr [GET_UNIT (dev)];
  696.  
  697.     ttyp = fip->tty;
  698.  
  699.     (*linesw [ttyp->t_line].l_read) (ttyp);
  700.  
  701.     old_level = spltty ();
  702.  
  703.     /* fill the unix buffer as much as possible */
  704.     while (fip->recv_ring_cnt)
  705.     {
  706.         if (fas_rxfer (fip))
  707.             break;
  708.  
  709.         (void) splx (old_level);    /* allow some interrupts */
  710.         old_level = spltty ();
  711.     }
  712.  
  713.     /* If input buffer level has dropped below
  714.        the low water mark and input was stopped
  715.        by hardware handshake, restart input.
  716.     */
  717.     if ((fip->device_flags.i & DF_HWI_STOPPED)
  718.         && (fip->recv_ring_cnt < HW_LOW_WATER))
  719.     {
  720.         fip->mcr.c |= fip->flow.m.ic;
  721.         outb (MDM_CTL_PORT, fip->mcr.i);
  722.         fip->device_flags.s &= ~DF_HWI_STOPPED;
  723.     }
  724.  
  725.     /* If input buffer level has dropped below
  726.        the low water mark and input was stopped
  727.        by XOFF, send XON to restart input.
  728.     */
  729.     if ((fip->device_flags.i & DF_SWI_STOPPED)
  730.         && (fip->recv_ring_cnt < SW_LOW_WATER))
  731.     {
  732.         fip->device_flags.s &= ~DF_SWI_STOPPED;
  733.         fip->device_flags.s ^= DF_SW_FC_REQ;
  734.         if (fip->device_flags.i & DF_SW_FC_REQ)
  735.         {
  736.             ttyp->t_state |= TTXON;
  737.             fas_cmd (fip, ttyp, T_OUTPUT);
  738.         }
  739.         else
  740.             ttyp->t_state &= ~TTXOFF;
  741.     }
  742.  
  743.     (void) splx (old_level);
  744.     return(0);
  745. }
  746.  
  747. /* write characters to the output buffer */
  748. int
  749. faswrite (dev)
  750. int    dev;
  751. {
  752.     register struct fas_info    *fip;
  753.     register struct tty    *ttyp;
  754.     int    old_level;
  755.  
  756.     fip = fas_info_ptr [GET_UNIT (dev)];
  757.  
  758.     ttyp = fip->tty;
  759.  
  760.     (*linesw [ttyp->t_line].l_write) (ttyp);
  761.  
  762.     old_level = spltty ();
  763.  
  764.     /* fill the transmitter ring buffer as much as possible */
  765.     while (!fas_xxfer (fip))
  766.     {
  767.         (void) splx (old_level);    /* allow some interrupts */
  768.         old_level = spltty ();
  769.     }
  770.  
  771.     (void) splx (old_level);
  772.     return(0);
  773. }
  774.  
  775. /* process ioctl calls */
  776. int
  777. fasioctl (dev, cmd, arg3, arg4)
  778. int    dev;
  779. int    cmd;
  780. union ioctl_arg    arg3;
  781. int    arg4;
  782. {
  783.     register struct fas_info    *fip;
  784.     register struct tty    *ttyp;
  785.     uint    old_t_state;
  786.     int    old_level;
  787.  
  788.     fip = fas_info_ptr [GET_UNIT (dev)];
  789.  
  790.     ttyp = fip->tty;
  791.  
  792.     /* if it is a TCSETA* command, call fas_param () */
  793.     if (ttiocom (ttyp, cmd, arg3, arg4))
  794.     {
  795.         old_level = spltty ();
  796.         old_t_state = ttyp->t_state;
  797.         fas_param (fip);
  798.         /* if we switched off CLOCAL mode and the *real* carrier
  799.            is missing we send the SIGHUP signal once
  800.         */
  801.         if (!(ttyp->t_state & CARR_ON) && (old_t_state & CARR_ON))
  802.         {
  803.             signal (ttyp->t_pgrp, SIGHUP);
  804.             ttyflush (ttyp, FREAD | FWRITE);
  805.         }
  806.         (void) splx (old_level);
  807.     }
  808.     return(0);
  809. }
  810.  
  811. /* pass fas commands to the fas multi-function procedure */
  812. static int
  813. fas_proc (ttyp, arg2)
  814. struct tty    *ttyp;
  815. int    arg2;
  816. {
  817.     register uint    physical_unit;
  818.     int    old_level;
  819.  
  820.     physical_unit = ttyp - &fas_tty [0];
  821.     if (physical_unit >= fas_physical_units)
  822.         physical_unit -= fas_physical_units;
  823.  
  824.     old_level = spltty ();
  825.     fas_cmd (fas_info_ptr [physical_unit], ttyp, arg2);
  826.     (void) splx (old_level);
  827.     return (0);
  828. }
  829.  
  830. /* set up a port according to the given termio structure */
  831. static void
  832. fas_param (fip)
  833. register struct fas_info    *fip;
  834. {
  835.     register uint    cflag;
  836.     uint    divisor;
  837.     int    xmit_ring_size;
  838.     REGVAR;
  839.  
  840.     cflag = fip->tty->t_cflag;
  841.  
  842.     /* hangup line if it is baud rate 0, else enable line */
  843.     if ((cflag & CBAUD) == B0)
  844.     {
  845.         cflag = (cflag & ~CBAUD) | (fip->cflag & CBAUD);
  846.         fip->mcr.c &= ~fip->modem.m.en;
  847.         outb (MDM_CTL_PORT, fip->mcr.i);
  848.         fip->device_flags.s &= ~DF_MODEM_ENABLED;
  849.     }
  850.     else
  851.     {
  852.         if (!(fip->device_flags.i & DF_MODEM_ENABLED))
  853.         {
  854.             fip->mcr.c |= fip->modem.m.en;
  855.             outb (MDM_CTL_PORT, fip->mcr.i);
  856.             fip->device_flags.s |= DF_MODEM_ENABLED;
  857.         }
  858.     }
  859.  
  860.     /* don't change break flag */
  861.     fip->lcr.c &= LC_SET_BREAK_LEVEL;
  862.  
  863.     /* set character size */
  864.     switch (cflag & CSIZE)
  865.     {
  866.     case CS5:
  867.         fip->lcr.c |= LC_WORDLEN_5;
  868.         break;
  869.  
  870.     case CS6:
  871.         fip->lcr.c |= LC_WORDLEN_6;
  872.         break;
  873.  
  874.     case CS7:
  875.         fip->lcr.c |= LC_WORDLEN_7;
  876.         break;
  877.  
  878.     default:
  879.         fip->lcr.c |= LC_WORDLEN_8;
  880.         break;
  881.     }
  882.  
  883.     /* set # of stop bits */
  884.     if (cflag & CSTOPB)
  885.         fip->lcr.c |= LC_STOPBITS_LONG;
  886.  
  887.     /* set parity */
  888.     if (cflag & PARENB)
  889.     {
  890.         fip->lcr.c |= LC_ENABLE_PARITY;
  891.  
  892.         if (!(cflag & PARODD))
  893.             fip->lcr.c |= LC_EVEN_PARITY;
  894.     }
  895.  
  896.     /* We write the counter divisor and the LCR register only
  897.        if we need to (whenever the corresponding cflag bits
  898.        have changed). This prevents character corruption under
  899.        some special conditions.
  900.     */
  901.     if ((cflag ^ fip->cflag) & CBAUD)
  902.     {
  903.         /* get counter divisor for selected baud rate */
  904.         divisor = fas_speeds [cflag & CBAUD];
  905.         outb (LINE_CTL_PORT, fip->lcr.i | LC_ENABLE_DIVISOR);
  906.         outb (DIVISOR_LSB_PORT, divisor);
  907.         outb (DIVISOR_MSB_PORT, divisor >> 8);
  908.         outb (LINE_CTL_PORT, fip->lcr.i);
  909.         /* check dynamic xmit ring buffer size against boundaries,
  910.                    modify it if necessary and update the fas_info structure
  911.         */
  912.         xmit_ring_size = fas_xbuf_size [cflag & CBAUD] - TTXOHI;
  913.         if (xmit_ring_size < OUTPUT_FIFO_SIZE * 2)
  914.             xmit_ring_size = OUTPUT_FIFO_SIZE * 2;
  915.         if (xmit_ring_size > XMIT_BUFF_SIZE)
  916.             xmit_ring_size = XMIT_BUFF_SIZE;
  917.         fip->xmit_ring_size = xmit_ring_size;
  918.         /* disable the transmitter for some time to give the
  919.            receiving side a chance to follow this change (only if
  920.            there has been output recently)
  921.         */
  922.         if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  923.         {
  924.             if (!(fip->tty->t_state & BUSY))
  925.                 fip->device_flags.s |= DF_XMIT_DISABLED;
  926.         }
  927.     }
  928.     else if ((cflag ^ fip->cflag) & (CSIZE | CSTOPB | PARENB | PARODD))
  929.     {
  930.         outb (LINE_CTL_PORT, fip->lcr.i);
  931.         /* disable the transmitter for some time to give the
  932.            receiving side a chance to follow this change (only if
  933.            there has been output recently)
  934.         */
  935.         if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  936.         {
  937.             if (!(fip->tty->t_state & BUSY))
  938.                 fip->device_flags.s |= DF_XMIT_DISABLED;
  939.         }
  940.     }
  941.  
  942.     /* disable modem control signals if required by open mode */
  943.     if (fip->o_state & OS_CLOCAL)
  944.         cflag |= CLOCAL;
  945.  
  946.     /* Fake the carrier detect state flag if CLOCAL mode or if
  947.        requested by open mode.
  948.     */
  949.     if (!(~fip->msr & fip->modem.m.ca)
  950.         || (fip->o_state & OS_FAKE_CARR_ON)
  951.         || (cflag & CLOCAL))
  952.         fip->tty->t_state |= CARR_ON;
  953.     else
  954.         fip->tty->t_state &= ~CARR_ON;
  955.  
  956. #if defined (XCLUDE)    /* SYSV 3.2 Xenix compatibility */
  957.     if (cflag & XCLUDE)
  958.         fip->o_state |= OS_EXCLUSIVE_OPEN;
  959.     else
  960.         fip->o_state &= ~OS_EXCLUSIVE_OPEN;
  961. #endif
  962.  
  963.     fip->cflag = cflag;
  964.     fip->iflag = fip->tty->t_iflag;
  965. }
  966.  
  967. /* Main fas interrupt handler. Actual character processing is splitted
  968.    into sub-functions.
  969. */
  970. int
  971. fasintr (vect)
  972. int    vect;
  973. {
  974.     register struct fas_info    *fip;
  975.     register uint    status;
  976.     int    done;
  977.     uint    port;
  978.     REGVAR;
  979.  
  980.     /* I believe that the 8259 is set up for edge trigger. Therefore
  981.        I must loop until I make a complete pass without getting
  982.        any UARTs that are interrupting.
  983.     */
  984.     do
  985.     {
  986.         done = TRUE;
  987.         fip = fas_first_int_user [vect];
  988.  
  989.         /* loop through all users of this interrupt vector */
  990.         for (; ; fip = fip->next_int_user)
  991.         {
  992.             if (!fip)
  993.                 break;    /* all users done */
  994.  
  995.             /* process only ports that we expect ints from
  996.                and that actually need to be serviced
  997.             */
  998. fastloop:
  999.             if (inb (INT_ID_PORT) & II_NO_INTS_PENDING)
  1000.             {
  1001.                 /* speed beats beauty */
  1002.                 fip = fip->next_int_user;
  1003.                 if (fip)
  1004.                     goto fastloop;
  1005.                 break;
  1006.             }
  1007.  
  1008.             done = FALSE;    /* not done if we got an int */
  1009.  
  1010.             do
  1011.             {
  1012.                 /* read in all the characters from the FIFO */
  1013.                 if ((status = inb (LINE_STATUS_PORT))
  1014.                     & LS_RCV_INT)
  1015.                 {
  1016.                     status = fas_rproc (fip, status);
  1017.                     sysinfo.rcvint++;
  1018.                 }
  1019.  
  1020.                 /* Is it a transmitter empty int ? */
  1021.                 if ((status & LS_XMIT_AVAIL)
  1022.                     && (fip->device_flags.i & DF_XMIT_BUSY))
  1023.                 {
  1024.                     fip->device_flags.s &= ~DF_XMIT_BUSY;
  1025.                     fas_cmd (fip, fip->tty, T_OUTPUT);
  1026.                     if (!(fip->device_flags.i & DF_XMIT_BUSY)
  1027.                         && !fip->xmit_ring_cnt)
  1028.                     {
  1029.                         fip->device_flags.s |=
  1030.                             DF_GUARD_TIMEOUT
  1031.                             | DF_ADAPT_TIMEOUT;
  1032.                         fip->tty->t_state |=
  1033.                             TIMEOUT;
  1034.                         fip->timeout_idx =
  1035.                             timeout (
  1036.                             ttrstrt, fip->tty,
  1037.                             fas_ctimes [fip->cflag
  1038.                                 & CBAUD]);
  1039.                     }
  1040.                     sysinfo.xmtint++;
  1041.                 }
  1042.  
  1043.                 /* Has there been a polarity change on
  1044.                    some of the modem lines ?
  1045.                 */
  1046.                 if (((status = inb (MDM_STATUS_PORT))
  1047.                     ^ fip->msr) & MS_ANY_PRESENT)
  1048.                 {
  1049.                     fas_mproc (fip, status);
  1050.                     sysinfo.mdmint++;
  1051.                 }
  1052.             } while (!(inb (INT_ID_PORT) & II_NO_INTS_PENDING));
  1053.  
  1054.             /* clear the port interrupt */
  1055.             if (INT_ACK_PORT)
  1056.                 outb (INT_ACK_PORT, fip->int_ack);
  1057.  
  1058.             /* process the characters in the ring buffer */
  1059.             if (fip->recv_ring_cnt)
  1060.             {
  1061.                 (void) fas_rxfer (fip);
  1062.                 /* If input buffer level has risen above the
  1063.                    high water mark and input is not yet
  1064.                    stopped, stop input by hardware handshake.
  1065.                 */
  1066.                 if ((fip->o_state & OS_HW_HANDSHAKE)
  1067.                     && !(fip->device_flags.i & DF_HWI_STOPPED)
  1068.                     && (fip->recv_ring_cnt > HW_HIGH_WATER))
  1069.                 {
  1070.                     fip->mcr.c &= ~fip->flow.m.ic;
  1071.                     outb (MDM_CTL_PORT, fip->mcr.i);
  1072.                     fip->device_flags.s |= DF_HWI_STOPPED;
  1073.                 }
  1074.                 /* If input buffer level has risen above the
  1075.                    high water mark and input is not yet
  1076.                    stopped, send XOFF to stop input.
  1077.                 */
  1078.                 if ((fip->iflag & IXOFF)
  1079.                     && !(fip->device_flags.i & DF_SWI_STOPPED)
  1080.                     && (fip->recv_ring_cnt > SW_HIGH_WATER))
  1081.                 {
  1082.                     fip->device_flags.s |= DF_SWI_STOPPED;
  1083.                     fip->device_flags.s ^= DF_SW_FC_REQ;
  1084.                     if (fip->device_flags.i & DF_SW_FC_REQ)
  1085.                     {
  1086.                         fip->tty->t_state |= TTXOFF;
  1087.                         fas_cmd (fip, fip->tty, T_OUTPUT);
  1088.                     }
  1089.                     else
  1090.                         fip->tty->t_state &= ~TTXON;
  1091.                 }
  1092.             }
  1093.         }
  1094.     } while (!done);
  1095.  
  1096.     /* clear the mux interrupt since we have scanned all
  1097.        of the ports that share this interrupt vector
  1098.     */    
  1099.     if (port = fas_mux_ack_port [vect])
  1100.         outb (port, fas_mux_ack [vect]);
  1101.  
  1102.     return(0);
  1103. }
  1104.  
  1105. /* modem status interrupt handler */
  1106. static void
  1107. fas_mproc (fip, mdm_status)
  1108. register struct fas_info    *fip;
  1109. register uint    mdm_status;
  1110. {
  1111.     register struct tty    *ttyp;
  1112.  
  1113.     ttyp = fip->tty;
  1114.  
  1115.     /* Check the output flow control signals and set the state flag
  1116.        accordingly.
  1117.     */
  1118.     if (fip->o_state & OS_HW_HANDSHAKE)
  1119.     {
  1120.         if (!(~mdm_status & fip->flow.m.oc)
  1121.             || (~mdm_status & fip->flow.m.oe))
  1122.         {
  1123.             if (fip->device_flags.i & DF_HWO_STOPPED)
  1124.             {
  1125.                 fip->device_flags.s &= ~DF_HWO_STOPPED;
  1126.                 fas_cmd (fip, ttyp, T_OUTPUT);
  1127.             }
  1128.         }
  1129.         else
  1130.             fip->device_flags.s |= DF_HWO_STOPPED;
  1131.     }
  1132.  
  1133.     /* Check the carrier detect signal and set the state flags
  1134.        accordingly. Also, if not in clocal mode, send SIGHUP on
  1135.        carrier loss and flush the buffers.
  1136.     */
  1137.     if (!(fip->cflag & CLOCAL))
  1138.     {
  1139.         if (!(~mdm_status & fip->modem.m.ca))
  1140.         {
  1141.             ttyp->t_state |= CARR_ON;
  1142.             /* Unblock getty open only if it is ready to run. */
  1143.             if (fip->o_state & OS_WAIT_OPEN)
  1144.                 wakeup ((caddr_t) &ttyp->t_canq);
  1145.         }
  1146.         else
  1147.         {
  1148.             if (!(~fip->msr & fip->modem.m.ca))
  1149.             {
  1150.                 ttyp->t_state &= ~CARR_ON;
  1151.                 if (ttyp->t_state & ISOPEN)
  1152.                     signal (ttyp->t_pgrp, SIGHUP);
  1153.                 ttyflush (ttyp, FREAD | FWRITE);
  1154.             }
  1155.         }
  1156.     }
  1157.  
  1158.     /* Check the unblock signal. If low->high edge, fake CARR_ON state
  1159.        flag and wake up getty open.
  1160.     */
  1161.     if ((fip->o_state & OS_UNBLOCK_ENABLE)
  1162.         && !(fip->cflag & CLOCAL)
  1163.         && !(~mdm_status & fip->modem.m.ub)
  1164.         && (~fip->msr & fip->modem.m.ub)
  1165.         && (fip->o_state & OS_WAIT_OPEN))
  1166.     {
  1167.         ttyp->t_state |= CARR_ON;
  1168.         wakeup ((caddr_t) &ttyp->t_canq);
  1169.     }
  1170.  
  1171.     fip->msr = mdm_status;
  1172. }
  1173.  
  1174. /* Receiver interrupt handler. Translates input characters to character
  1175.    sequences as described in TERMIO(7) man page.
  1176. */
  1177. static uint
  1178. fas_rproc (fip, line_status)
  1179. register struct fas_info    *fip;
  1180. uint    line_status;
  1181. {
  1182.     struct tty    *ttyp;
  1183.     uint    charac;
  1184.     register uint    csize;
  1185.     unchar    metta [4];
  1186.     REGVAR;
  1187.  
  1188.     ttyp = fip->tty;
  1189.  
  1190.     /* Translate characters from FIFO according to the TERMIO(7)
  1191.        man page.
  1192.     */
  1193.     do
  1194.     {
  1195.         charac = (line_status & LS_RCV_AVAIL)
  1196.                 ? inb (RCV_DATA_PORT)
  1197.                 : 0;    /* was line status int only */
  1198.  
  1199.         if (!(fip->cflag & CREAD) || !(ttyp->t_state & ISOPEN))
  1200.             continue;
  1201.  
  1202.         csize = 0;
  1203.  
  1204.         if (fip->iflag & ISTRIP)
  1205.             charac &= 0x7f;
  1206.  
  1207.         if ((line_status & LS_PARITY_ERROR)
  1208.             && !(fip->iflag & INPCK))
  1209.             line_status &= ~LS_PARITY_ERROR;
  1210.  
  1211.         if (line_status & (LS_PARITY_ERROR
  1212.                     | LS_FRAMING_ERROR
  1213.                     | LS_BREAK_DETECTED))
  1214.         {
  1215.             if (line_status & LS_BREAK_DETECTED)
  1216.             {
  1217.                 if (!(fip->iflag & IGNBRK))
  1218.                     if (fip->iflag & BRKINT)
  1219.                         (*linesw [ttyp->t_line].l_input)
  1220.                             (ttyp, L_BREAK);
  1221.                     else
  1222.                     {
  1223.                         metta [csize] = 0;
  1224.                         csize++;
  1225.                         if (fip->iflag & PARMRK)
  1226.                         {
  1227.                             metta [csize] = 0;
  1228.                             csize++;
  1229.                             metta [csize] = 0xff;
  1230.                             csize++;
  1231.                         }
  1232.                     }
  1233.             }
  1234.             else if (!(fip->iflag & IGNPAR))
  1235.                 if (fip->iflag & PARMRK)
  1236.                 {
  1237.                     metta [csize] = charac;
  1238.                     csize++;
  1239.                     metta [csize] = 0;
  1240.                     csize++;
  1241.                     metta [csize] = 0xff;
  1242.                     csize++;
  1243.                 }
  1244.                 else
  1245.                 {
  1246.                     metta [csize] = 0;
  1247.                     csize++;
  1248.                 }
  1249.         }
  1250.         else if (line_status & LS_RCV_AVAIL)
  1251.         {
  1252.             if (fip->iflag & IXON)
  1253.             {
  1254.                 if (fip->device_flags.i & DF_SWO_STOPPED)
  1255.                 {
  1256.                     if ((charac == CSTART)
  1257.                         || (fip->iflag & IXANY))
  1258.                     {
  1259.                         fip->device_flags.s &=
  1260.                             ~DF_SWO_STOPPED;
  1261.                         ttyp->t_state &= ~TTSTOP;
  1262.                         /* restart output */
  1263.                         fas_cmd (fip, ttyp, T_OUTPUT);
  1264.                     }
  1265.                 }
  1266.                 else
  1267.                 {
  1268.                     if (charac == CSTOP)
  1269.                     {
  1270.                         fip->device_flags.s |=
  1271.                             DF_SWO_STOPPED;
  1272.                         ttyp->t_state |= TTSTOP;
  1273.                     }
  1274.                 }
  1275.                 if ((charac == CSTART) || (charac == CSTOP))
  1276.                     continue;
  1277.             }
  1278.  
  1279.             if ((charac == 0xff) && (fip->iflag & PARMRK))
  1280.             {
  1281.                 metta [csize] = 0xff;
  1282.                 csize++;
  1283.                 metta [csize] = 0xff;
  1284.                 csize++;
  1285.             }
  1286.             else
  1287.             {
  1288.                 if (fip->recv_ring_cnt <= RECV_BUFF_SIZE - 4)
  1289.                 {
  1290.                     fip->recv_ring_cnt++;
  1291.                     *fip->recv_ring_put_ptr = charac;
  1292.                     if (++fip->recv_ring_put_ptr
  1293.                         != &fip->recv_buffer
  1294.                             [RECV_BUFF_SIZE])
  1295.                         continue;
  1296.                     fip->recv_ring_put_ptr =
  1297.                             &fip->recv_buffer [0];
  1298.                 }
  1299.                 continue;
  1300.             }
  1301.         }
  1302.  
  1303.         if (!(csize) || (fip->recv_ring_cnt > RECV_BUFF_SIZE - 4))
  1304.             continue;
  1305.  
  1306.         fip->recv_ring_cnt += csize;
  1307.  
  1308.         /* store translation in ring buffer */
  1309.         do
  1310.         {
  1311.             do
  1312.             {
  1313.                 *fip->recv_ring_put_ptr = (metta - 1)[csize];
  1314.                 if (++fip->recv_ring_put_ptr
  1315.                     == &fip->recv_buffer [RECV_BUFF_SIZE])
  1316.                     break;
  1317.                 csize--;
  1318.             } while (csize);
  1319.             if (!csize)
  1320.                 break;
  1321.             fip->recv_ring_put_ptr = &fip->recv_buffer [0];
  1322.             csize--;
  1323.         } while (csize);
  1324.     } while ((line_status = inb (LINE_STATUS_PORT)) & LS_RCV_INT);
  1325.  
  1326.     return (line_status);
  1327. }
  1328.  
  1329. /* Output characters to the transmitter register. */
  1330. static void
  1331. fas_xproc (fip, out_cnt)
  1332. register struct fas_info    *fip;
  1333. register uint    out_cnt;
  1334. {
  1335.     REGVAR;
  1336.  
  1337.     fip->xmit_ring_cnt -= out_cnt;
  1338.  
  1339.     do
  1340.     {
  1341.         do
  1342.         {
  1343.             outb (XMT_DATA_PORT, *fip->xmit_ring_take_ptr);
  1344.             if (++fip->xmit_ring_take_ptr
  1345.                     == &fip->xmit_buffer [XMIT_BUFF_SIZE])
  1346.                 break;
  1347.             out_cnt--;
  1348.         } while (out_cnt);
  1349.         if (!out_cnt)
  1350.             break;
  1351.         fip->xmit_ring_take_ptr = &fip->xmit_buffer [0];
  1352.         out_cnt--;
  1353.     } while (out_cnt);
  1354. }
  1355.  
  1356. /* Receiver ring buffer -> UNIX buffer transfer function. */
  1357. static int
  1358. fas_rxfer (fip)
  1359. register struct fas_info    *fip;
  1360. {
  1361.     register struct tty    *ttyp;
  1362.     register uint    num_to_xfer;
  1363.  
  1364.     ttyp = fip->tty;
  1365.  
  1366.     /* determin how many characters to transfer */
  1367.     num_to_xfer = (TTYHOG - 1) - ttyp->t_rawq.c_cc;
  1368.  
  1369.     if (!num_to_xfer || !ttyp->t_rbuf.c_ptr)
  1370.         return (1);    /* input buffer full */
  1371.  
  1372.     /* determin how many characters are in one contigous block */
  1373.     if (fip->recv_ring_cnt < num_to_xfer)
  1374.         num_to_xfer = fip->recv_ring_cnt;
  1375.     if (ttyp->t_rbuf.c_count < num_to_xfer)
  1376.         num_to_xfer = ttyp->t_rbuf.c_count;
  1377.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1378.     {
  1379.         if (INPUT_FIFO_SIZE * 2 < num_to_xfer)
  1380.             num_to_xfer = INPUT_FIFO_SIZE * 2;
  1381.     }
  1382.     else
  1383.     {
  1384.         if (8 < num_to_xfer)
  1385.             num_to_xfer = 8;
  1386.     }
  1387.  
  1388.     fip->recv_ring_cnt -= num_to_xfer;
  1389.     ttyp->t_rbuf.c_count -= num_to_xfer;
  1390.  
  1391.     /* do the transfer */
  1392.     do
  1393.     {
  1394.         do
  1395.         {
  1396.             *ttyp->t_rbuf.c_ptr = *fip->recv_ring_take_ptr;
  1397.             ttyp->t_rbuf.c_ptr++;
  1398.             if (++fip->recv_ring_take_ptr
  1399.                     == &fip->recv_buffer [RECV_BUFF_SIZE])
  1400.                 break;
  1401.             num_to_xfer--;
  1402.         } while (num_to_xfer);
  1403.         if (!num_to_xfer)
  1404.             break;
  1405.         fip->recv_ring_take_ptr = &fip->recv_buffer [0];
  1406.         num_to_xfer--;
  1407.     } while (num_to_xfer);
  1408.  
  1409.     ttyp->t_rbuf.c_ptr -= ttyp->t_rbuf.c_size
  1410.                 - ttyp->t_rbuf.c_count;
  1411.     (*linesw [ttyp->t_line].l_input) (ttyp, L_BUF);
  1412.  
  1413.     return (0);
  1414. }
  1415.  
  1416. /* UNIX buffer -> transmitter ring buffer transfer function. */
  1417. static int
  1418. fas_xxfer (fip)
  1419. register struct fas_info    *fip;
  1420. {
  1421.     register struct tty    *ttyp;
  1422.     register int    num_to_xfer;
  1423.  
  1424.     ttyp = fip->tty;
  1425.  
  1426.     /* set the maximum character limit */
  1427.     num_to_xfer = fip->xmit_ring_size - fip->xmit_ring_cnt;
  1428.  
  1429.     /* Return if transmitter ring buffer is full. */
  1430.     if (num_to_xfer < 1)
  1431.         return (1);
  1432.  
  1433.     /* Check if tbuf is empty. If it is empty, reset buffer
  1434.        pointer and counter and get the next chunk of output
  1435.        characters.
  1436.     */
  1437.     if (!ttyp->t_tbuf.c_ptr || !ttyp->t_tbuf.c_count)
  1438.     {
  1439.         if (ttyp->t_tbuf.c_ptr)
  1440.             ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size;
  1441.         if (!((*linesw [ttyp->t_line].l_output) (ttyp)
  1442.                 & CPRES))
  1443.             return (1);
  1444.     }
  1445.  
  1446.     /* Determine how many chars to transfer this time. */
  1447.     if (ttyp->t_tbuf.c_count < num_to_xfer)
  1448.         num_to_xfer = ttyp->t_tbuf.c_count;
  1449.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1450.     {
  1451.         if (OUTPUT_FIFO_SIZE * 2 < num_to_xfer)
  1452.             num_to_xfer = OUTPUT_FIFO_SIZE * 2;
  1453.     }
  1454.     else
  1455.     {
  1456.         if (8 < num_to_xfer)
  1457.             num_to_xfer = 8;
  1458.     }
  1459.  
  1460.     fip->xmit_ring_cnt += num_to_xfer;
  1461.     ttyp->t_tbuf.c_count -= num_to_xfer;
  1462.     ttyp->t_state |= BUSY;
  1463.  
  1464.     /* do the transfer */
  1465.     do
  1466.     {
  1467.         do
  1468.         {
  1469.             *fip->xmit_ring_put_ptr = *ttyp->t_tbuf.c_ptr;
  1470.             ttyp->t_tbuf.c_ptr++;
  1471.             if (++fip->xmit_ring_put_ptr
  1472.                     == &fip->xmit_buffer [XMIT_BUFF_SIZE])
  1473.                 break;
  1474.             num_to_xfer--;
  1475.         } while (num_to_xfer);
  1476.         if (!num_to_xfer)
  1477.             break;
  1478.         fip->xmit_ring_put_ptr = &fip->xmit_buffer [0];
  1479.         num_to_xfer--;
  1480.     } while (num_to_xfer);
  1481.  
  1482.     return (0);
  1483. }
  1484.  
  1485. /* Several functions for flow control, character output and special event
  1486.    requests and handling.
  1487. */
  1488. static void
  1489. fas_cmd (fip, ttyp, arg2)
  1490. register struct fas_info    *fip;
  1491. register struct tty    *ttyp;
  1492. int    arg2;
  1493. {
  1494.     uint    num_to_output, out_cnt;
  1495.     REGVAR;
  1496.  
  1497.     switch (arg2)
  1498.     {
  1499.     case T_TIME:    /* process delayed events */
  1500.         /* handle break request */
  1501.         if (fip->device_flags.i & DF_DO_BREAK)
  1502.         {
  1503.             /* set up break request flags */
  1504.             fip->lcr.c |= LC_SET_BREAK_LEVEL;
  1505.             outb (LINE_CTL_PORT, fip->lcr.i);
  1506.             fip->device_flags.s &= ~DF_DO_BREAK;
  1507.             fip->timeout_idx = timeout (ttrstrt, ttyp, BREAK_TIME);
  1508.             break;
  1509.         }
  1510.         /* reset break state */
  1511.         if (fip->lcr.i & LC_SET_BREAK_LEVEL)
  1512.         {
  1513.             fip->lcr.c &= ~LC_SET_BREAK_LEVEL;
  1514.             outb (LINE_CTL_PORT, fip->lcr.i);
  1515.             fip->device_flags.s |= DF_GUARD_TIMEOUT
  1516.                         | DF_ADAPT_TIMEOUT;
  1517.             fip->timeout_idx = timeout (ttrstrt, ttyp,
  1518.                     fas_ctimes [fip->cflag & CBAUD]);
  1519.             break;
  1520.         }
  1521.         /* handle hangup request */
  1522.         if (fip->device_flags.i & DF_DO_HANGUP)
  1523.         {
  1524.             if (fip->device_flags.i & DF_MODEM_ENABLED)
  1525.             {
  1526.                 fip->mcr.c &= ~(fip->modem.m.en
  1527.                         | fip->flow.m.ic);
  1528.                 outb (MDM_CTL_PORT, fip->mcr.i);
  1529.                 fip->device_flags.s &= ~DF_MODEM_ENABLED;
  1530.                 (void) timeout (ttrstrt, ttyp, HANGUP_TIME);
  1531.                 break;
  1532.             }
  1533.             else
  1534.             {
  1535.                 fip->device_flags.s &= ~DF_DO_HANGUP;
  1536.                 /* If there was a waiting getty open on this
  1537.                    port, reopen the physical device.
  1538.                 */
  1539.                 if (fip->o_state & OS_WAIT_OPEN)
  1540.                 {
  1541.                     fas_open_device (fip);
  1542.                     fas_param (fip);    /* set up port regs */
  1543.                     fas_mproc (fip, fip->msr);    /* set up mdm stat flags */
  1544.                 }
  1545.                 release_device_lock (fip);
  1546.                 break;
  1547.             }
  1548.         }
  1549.         if (fip->device_flags.i & DF_GUARD_TIMEOUT)
  1550.         {
  1551.             fip->device_flags.s &= ~(DF_XMIT_DISABLED
  1552.                         | DF_GUARD_TIMEOUT);
  1553.             if (!fip->xmit_ring_cnt)
  1554.                 ttyp->t_state &= ~BUSY;
  1555.             fip->timeout_idx = timeout (ttrstrt, ttyp, ADAPT_TIME);
  1556.         }
  1557.         else
  1558.         {
  1559.             fip->device_flags.s &= ~(DF_XMIT_DISABLED
  1560.                         | DF_ADAPT_TIMEOUT);
  1561.         }
  1562.         ttyp->t_state &= ~TIMEOUT;
  1563.         /* FALL THRU */
  1564.  
  1565.     case T_OUTPUT:    /* output characters to the transmitter */
  1566. start:
  1567.         /* proceed only if transmitter is available */
  1568.         if (fip->device_flags.i & (DF_HWO_STOPPED | DF_XMIT_DISABLED
  1569.                         | DF_XMIT_BUSY))
  1570.             break;
  1571.  
  1572.         /* transfer some characters to the transmitter ring buffer */
  1573.         (void) fas_xxfer (fip);
  1574.  
  1575.         /* determine the transmitter FIFO size */
  1576.         num_to_output = (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1577.                 ? OUTPUT_FIFO_SIZE
  1578.                 : 1;
  1579.  
  1580.         /* handle XON/XOFF input flow control requests */
  1581.         if (fip->device_flags.i & DF_SW_FC_REQ)
  1582.         {
  1583.             outb (XMT_DATA_PORT, (fip->device_flags.i & DF_SWI_STOPPED)
  1584.                         ? CSTOP
  1585.                         : CSTART);
  1586.             ttyp->t_state &= ~(TTXON | TTXOFF);
  1587.             fip->device_flags.s |= DF_XMIT_BUSY;
  1588.             fip->device_flags.s &= ~DF_SW_FC_REQ;
  1589.             /* disable adapt timeout */
  1590.             if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  1591.             {
  1592.                 fip->device_flags.s &= ~(DF_GUARD_TIMEOUT
  1593.                             | DF_ADAPT_TIMEOUT);
  1594.                 ttyp->t_state &= ~TIMEOUT;
  1595.                 untimeout (fip->timeout_idx);
  1596.             }
  1597.             num_to_output--;
  1598.         }
  1599.  
  1600.         /* bail out if output is suspended by XOFF */
  1601.         if (fip->device_flags.i & DF_SWO_STOPPED)
  1602.             break;
  1603.  
  1604.         /* Determine how many chars to put into the transmitter
  1605.            register.
  1606.         */
  1607.         if (fip->xmit_ring_cnt < num_to_output)
  1608.             num_to_output = fip->xmit_ring_cnt;
  1609.  
  1610.         /* no characters available ? */
  1611.         if (!num_to_output)
  1612.             break;
  1613.  
  1614.         /* output characters */
  1615.         fas_xproc (fip, num_to_output);
  1616.  
  1617.         /* signal that transmitter is busy now */
  1618.         fip->device_flags.s |= DF_XMIT_BUSY;
  1619.         /* disable adapt timeout */
  1620.         if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  1621.         {
  1622.             fip->device_flags.s &= ~(DF_GUARD_TIMEOUT
  1623.                         | DF_ADAPT_TIMEOUT);
  1624.             ttyp->t_state &= ~TIMEOUT;
  1625.             untimeout (fip->timeout_idx);
  1626.         }
  1627.         break;
  1628.  
  1629.     case T_SUSPEND:    /* suspend character output */
  1630.         fip->device_flags.s |= DF_SWO_STOPPED;
  1631.         ttyp->t_state |= TTSTOP;
  1632.         break;
  1633.  
  1634.     case T_RESUME:    /* restart character output */
  1635.         fip->device_flags.s &= ~DF_SWO_STOPPED;
  1636.         ttyp->t_state &= ~TTSTOP;
  1637.         goto start;
  1638.  
  1639.     case T_BLOCK:    /* stop character input, request XOFF */
  1640.         ttyp->t_state |= TBLOCK;
  1641.         break;    /* note: we do our own XON/XOFF */
  1642.  
  1643.     case T_UNBLOCK:    /* restart character input, request XON */
  1644.         ttyp->t_state &= ~TBLOCK;
  1645.         break;    /* note: we do our own XON/XOFF */
  1646.  
  1647.     case T_RFLUSH:    /* flush input buffers and restart input */
  1648.         fip->recv_ring_take_ptr = fip->recv_ring_put_ptr;
  1649.         fip->recv_ring_cnt = 0;
  1650.         if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1651.             outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP
  1652.                         | FIFO_CLR_RECV);
  1653.         if (fip->device_flags.i & DF_HWI_STOPPED)
  1654.         {
  1655.             fip->mcr.c |= fip->flow.m.ic;
  1656.             outb (MDM_CTL_PORT, fip->mcr.i);
  1657.             fip->device_flags.s &= ~DF_HWI_STOPPED;
  1658.         }
  1659.         ttyp->t_state &= ~TBLOCK;
  1660.         if (fip->device_flags.i & DF_SWI_STOPPED)
  1661.         {
  1662.             fip->device_flags.s &= ~DF_SWI_STOPPED;
  1663.             fip->device_flags.s ^= DF_SW_FC_REQ;
  1664.             if (fip->device_flags.i & DF_SW_FC_REQ)
  1665.             {
  1666.                 ttyp->t_state |= TTXON;
  1667.                 goto start;
  1668.             }
  1669.             else
  1670.                 ttyp->t_state &= ~TTXOFF;
  1671.         }
  1672.         break;
  1673.  
  1674.     case T_WFLUSH:    /* flush output buffer and restart output */
  1675.         if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1676.             outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP
  1677.                         | FIFO_CLR_XMIT);
  1678.  
  1679.         fip->xmit_ring_take_ptr = fip->xmit_ring_put_ptr;
  1680.         fip->xmit_ring_cnt = 0;
  1681.  
  1682.         if (!(fip->device_flags.i & (DF_XMIT_BUSY | DF_GUARD_TIMEOUT)))
  1683.             ttyp->t_state &= ~BUSY;
  1684.  
  1685.         fip->device_flags.s &= ~DF_SWO_STOPPED;
  1686.         ttyp->t_state &= ~TTSTOP;
  1687.  
  1688.         if (ttyp->t_tbuf.c_ptr)
  1689.             ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size
  1690.                         - ttyp->t_tbuf.c_count;
  1691.         do
  1692.         {
  1693.             ttyp->t_tbuf.c_count = 0;
  1694.         } while ((*linesw [ttyp->t_line].l_output) (ttyp) & CPRES);
  1695.         break;
  1696.  
  1697.     case T_BREAK:    /* do a break on the transmitter line */
  1698.         if (fip->device_flags.i & DF_XMIT_DISABLED)
  1699.         {
  1700.             fip->device_flags.s |= DF_DO_BREAK;
  1701.             ttyp->t_state |= TIMEOUT;
  1702.         }
  1703.         else
  1704.         {
  1705.             /* set up break request flags */
  1706.             fip->lcr.c |= LC_SET_BREAK_LEVEL;
  1707.             outb (LINE_CTL_PORT, fip->lcr.i);
  1708.             /* disable adapt timeout */
  1709.             if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  1710.             {
  1711.                 fip->device_flags.s &= ~DF_ADAPT_TIMEOUT;
  1712.                 untimeout (fip->timeout_idx);
  1713.             }
  1714.             fip->device_flags.s |= DF_XMIT_DISABLED;
  1715.             ttyp->t_state |= TIMEOUT;
  1716.             fip->timeout_idx = timeout (ttrstrt, ttyp, BREAK_TIME);
  1717.         }
  1718.         break;
  1719.  
  1720.     case T_PARM:    /* set up the port according to the termio structure */
  1721.         fas_param (fip);
  1722.         break;
  1723.  
  1724.     case T_SWTCH:    /* handle layer switch request */
  1725.         break;
  1726.     }
  1727. }
  1728.  
  1729. /* open device physically */
  1730. static void
  1731. fas_open_device (fip)
  1732. register struct fas_info    *fip;
  1733. {
  1734.     REGVAR;
  1735.  
  1736.     fip->device_flags.s &= DF_DEVICE_CONFIGURED | DF_DEVICE_HAS_FIFO
  1737.                 | DF_DEVICE_LOCKED;
  1738.     fip->cflag = 0;
  1739.     fip->iflag = 0;
  1740.     fip->recv_ring_take_ptr = fip->recv_ring_put_ptr;
  1741.     fip->recv_ring_cnt = 0;
  1742.     fip->xmit_ring_take_ptr = fip->xmit_ring_put_ptr;
  1743.     fip->xmit_ring_cnt = 0;
  1744.  
  1745.     /* hook into the interrupt users chain */
  1746.     fip->next_int_user = fas_first_int_user [fip->vec];
  1747.     if (fip->next_int_user)
  1748.         fip->next_int_user->prev_int_user = fip;
  1749.     fas_first_int_user [fip->vec] = fip;
  1750.     fip->prev_int_user = (struct fas_info *) NULL;
  1751.  
  1752.     fip->lcr.c = 0;
  1753.     outb (LINE_CTL_PORT, fip->lcr.i);
  1754.  
  1755.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1756.         outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
  1757.  
  1758.     /* clear interrupts */
  1759.     inb (MDM_STATUS_PORT);
  1760.     inb (RCV_DATA_PORT);
  1761.     inb (RCV_DATA_PORT);
  1762.     inb (LINE_STATUS_PORT);
  1763.     inb (INT_ID_PORT);
  1764.     if (INT_ACK_PORT)
  1765.         outb (INT_ACK_PORT, fip->int_ack);
  1766.  
  1767.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1768.         outb (FIFO_CTL_PORT, STANDARD_FIFO_INIT);
  1769.  
  1770.     fip->ier.c = IE_INIT_MODE;
  1771.     outb (INT_ENABLE_PORT, fip->ier.i);
  1772.  
  1773.     fip->msr = inb (MDM_STATUS_PORT);
  1774.  
  1775.     fip->mcr.c |= fip->modem.m.en | fip->flow.m.ic;
  1776.     outb (MDM_CTL_PORT, fip->mcr.i);
  1777.  
  1778.     fip->device_flags.s |= DF_DEVICE_OPEN | DF_MODEM_ENABLED;
  1779. }
  1780.  
  1781. /* close device physically */
  1782. static void
  1783. fas_close_device (fip)
  1784. register struct fas_info    *fip;
  1785. {
  1786.     REGVAR;
  1787.  
  1788.     fip->device_flags.s &= ~DF_DEVICE_OPEN;
  1789.     fip->ier.c = IE_NONE;    /* disable all ints from UART */
  1790.     outb (INT_ENABLE_PORT, fip->ier.i);
  1791.     if (INT_ACK_PORT)
  1792.         outb (INT_ACK_PORT, fip->int_ack);
  1793.  
  1794.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1795.         outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
  1796.  
  1797.     /* unhook from interrupt users chain */
  1798.     if (fip->prev_int_user)
  1799.         fip->prev_int_user->next_int_user = fip->next_int_user;
  1800.     else
  1801.         fas_first_int_user [fip->vec] = fip->next_int_user;
  1802.     if (fip->next_int_user)
  1803.         fip->next_int_user->prev_int_user = fip->prev_int_user;
  1804.  
  1805.     /* disable adapt timeout */
  1806.     if (fip->device_flags.i & DF_ADAPT_TIMEOUT)
  1807.     {
  1808.         fip->device_flags.s &= ~(DF_XMIT_DISABLED | DF_ADAPT_TIMEOUT);
  1809.         untimeout (fip->timeout_idx);
  1810.     }
  1811.  
  1812.     if (fip->cflag & HUPCL)
  1813.     {
  1814.         /* request hangup */
  1815.         fip->device_flags.s |= DF_DO_HANGUP;
  1816.         (void) timeout (ttrstrt, fip->tty, HANGUP_DELAY);
  1817.     }
  1818. }
  1819.  
  1820. /* test device thoroughly */
  1821. static int
  1822. fas_test_device (fip)
  1823. register struct fas_info    *fip;
  1824. {
  1825.     register unchar    *cptr;
  1826.     int    done;
  1827.     REGVAR;
  1828.  
  1829.     /* make sure FIFO is off */
  1830.     outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
  1831.  
  1832.     /* set counter divisor */
  1833.     outb (LINE_CTL_PORT, LC_ENABLE_DIVISOR);
  1834.     outb (DIVISOR_LSB_PORT, fas_speeds [B38400]);
  1835.     outb (DIVISOR_MSB_PORT, fas_speeds [B38400] >> 8);
  1836.     outb (LINE_CTL_PORT, 0);
  1837.  
  1838.     /* switch to local loopback */
  1839.     outb (MDM_CTL_PORT, MC_SET_LOOPBACK);
  1840.     delay (fas_ctimes [B38400]);
  1841.  
  1842.     /* clear flags */
  1843.     inb (RCV_DATA_PORT);
  1844.     inb (RCV_DATA_PORT);
  1845.     inb (LINE_STATUS_PORT);
  1846.  
  1847.     /* test pattern */
  1848.     cptr = (unchar *) "\377\125\252\045\244\0";
  1849.  
  1850.     do
  1851.     {
  1852.         done = FALSE;
  1853.  
  1854.         /* test transmitter and receiver with parity odd */
  1855.         outb (LINE_CTL_PORT, LC_WORDLEN_8 | LC_ENABLE_PARITY);
  1856.         if (~inb (LINE_STATUS_PORT) & (LS_XMIT_AVAIL | LS_XMIT_COMPLETE))
  1857.             break;
  1858.  
  1859.         outb (XMT_DATA_PORT, *cptr);
  1860.         delay (fas_ctimes [B38400]);
  1861.         if ((inb (LINE_STATUS_PORT) & LS_RCV_INT) != LS_RCV_AVAIL)
  1862.             break;
  1863.  
  1864.         if (inb (RCV_DATA_PORT) != *cptr)
  1865.             break;
  1866.  
  1867.         /* test transmitter and receiver with parity even */
  1868.         outb (LINE_CTL_PORT, LC_WORDLEN_8 | LC_ENABLE_PARITY
  1869.                     | LC_EVEN_PARITY);
  1870.         if (~inb (LINE_STATUS_PORT) & (LS_XMIT_AVAIL | LS_XMIT_COMPLETE))
  1871.             break;
  1872.  
  1873.         outb (XMT_DATA_PORT, *cptr);
  1874.         delay (fas_ctimes [B38400]);
  1875.         if ((inb (LINE_STATUS_PORT) & LS_RCV_INT) != LS_RCV_AVAIL)
  1876.             break;
  1877.  
  1878.         if (inb (RCV_DATA_PORT) != *cptr)
  1879.             break;
  1880.  
  1881.         done = TRUE;
  1882.     } while (*cptr++);
  1883.  
  1884.     if (done)
  1885.     {
  1886.         /* test pattern */
  1887.         cptr = (unchar *) "\005\140\012\220\006\120\011\240\017\360\0\0";
  1888.  
  1889.         do
  1890.         {
  1891.             done = FALSE;
  1892.  
  1893.             /* test modem control and status lines */
  1894.             outb (MDM_CTL_PORT, *cptr | MC_SET_LOOPBACK);
  1895.             if ((inb (MDM_STATUS_PORT) & MS_ANY_PRESENT)
  1896.                 != *(cptr + 1))
  1897.                 break;
  1898.  
  1899.             done = TRUE;
  1900.         } while (*((ushort *) cptr)++);
  1901.     }
  1902.  
  1903.     /* switch back to normal operation */
  1904.     outb (MDM_CTL_PORT, 0);
  1905.     delay (fas_ctimes [B38400]);
  1906.  
  1907.     return (done);
  1908. }
  1909.  
  1910. #if defined (NEED_PUT_GETCHAR)
  1911.  
  1912. int
  1913. asyputchar (arg1)
  1914. unchar    arg1;
  1915. {
  1916.     register struct    fas_info    *fip;
  1917.     REGVAR;
  1918.  
  1919.     if (!fas_is_initted)
  1920.         fasinit();
  1921.  
  1922.     fip = &fas_info [0];
  1923.     if (fip->device_flags.i & DF_DEVICE_CONFIGURED)
  1924.     {
  1925.         while (!(inb (LINE_STATUS_PORT) & LS_XMIT_AVAIL))
  1926.             ;
  1927.         outb (XMT_DATA_PORT, arg1);
  1928.         if (arg1 == 10)
  1929.             asyputchar(13);
  1930.     }
  1931.     return(0);
  1932. }
  1933.  
  1934. int
  1935. asygetchar ()
  1936. {
  1937.     register struct    fas_info    *fip;
  1938.     REGVAR;
  1939.  
  1940.     if (!fas_is_initted)
  1941.         fasinit();
  1942.  
  1943.     fip = &fas_info [0];
  1944.     if ((fip->device_flags.i & DF_DEVICE_CONFIGURED)
  1945.         && (inb (LINE_STATUS_PORT) & LS_RCV_AVAIL))
  1946.         return (inb (RCV_DATA_PORT));
  1947.     else
  1948.         return (-1);
  1949. }
  1950. #endif
  1951.  
  1952. #if defined (NEED_INIT8250)
  1953.  
  1954. /* reset the requested port to be used directly by a DOS process */
  1955. int
  1956. init8250 (port, ier)
  1957. ushort    port, ier;    /* ier not used in this stub */
  1958. {
  1959.     register struct fas_info    *fip;
  1960.     register uint    physical_unit;
  1961.     int    old_level;
  1962.     REGVAR;
  1963.  
  1964.     /* See if the port address matches a port that is used by
  1965.        the fas driver.
  1966.     */
  1967.     for (physical_unit = 0; physical_unit < fas_physical_units;
  1968.             physical_unit++)
  1969.         if (port == fas_port [physical_unit])
  1970.             break;
  1971.  
  1972.     if (physical_unit >= fas_physical_units)
  1973.         return(-1);    /* port didn't match */
  1974.  
  1975.     fip = fas_info_ptr [physical_unit];
  1976.  
  1977.     old_level = spltty ();
  1978.  
  1979.     fip->ier.c = IE_NONE;
  1980.     outb (INT_ENABLE_PORT, fip->ier.i);
  1981.     if (INT_ACK_PORT)
  1982.         outb (INT_ACK_PORT, fip->int_ack);
  1983.  
  1984.     fip->mcr.c &= ~fip->flow.m.ic;
  1985.     outb (MDM_CTL_PORT, fip->mcr.i);
  1986.  
  1987.     if (fip->device_flags.i & DF_DEVICE_HAS_FIFO)
  1988.         outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
  1989.  
  1990.     inb (MDM_STATUS_PORT);
  1991.     inb (RCV_DATA_PORT);
  1992.     inb (RCV_DATA_PORT);
  1993.     inb (LINE_STATUS_PORT);
  1994.     inb (INT_ID_PORT);
  1995.     (void) splx (old_level);
  1996.     return (0);
  1997. }
  1998. #endif
  1999.