home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / CTASK11.ZIP / TSKSIO.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-07-01  |  23.6 KB  |  921 lines

  1. /*
  2.    TSKSIO.C - CTask - Serial I/O interface routines.
  3.  
  4.    Public Domain Software written by
  5.       Thomas Wagner
  6.       Patschkauer Weg 31
  7.       D-1000 Berlin 33
  8.       West Germany
  9.  
  10.    With version 1.1, support for shared IRQ lines and dynamically
  11.    defined ports was added. The tables used are
  12.  
  13.       port_list   The pointer to the list of defined ports. Newly
  14.                   defined ports are added to the end of the list.
  15.                   Ports can never be deleted. Each port descriptor
  16.                   contains the hardware info for the port, plus a
  17.                   pointer to the associated sio-control-block if the
  18.                   port was initialized.
  19.                   
  20.       port_last   The pointer to the last element in port_list.
  21.  
  22.       irq_array   Is an array of pointers to sio-control-blocks. For
  23.                   each possible IRQ-line the entry in this table points
  24.                   to the first block active for this line. If the IRQ
  25.                   is shared, sio-blocks are chained into this list via 
  26.                   their "next" pointer.
  27.  
  28.       irq_procs   Contains the pointer to the interrupt handler function
  29.                   for the corresponding IRQ-line.
  30.  
  31.       sio_data    Contains the statically defined sio control blocks.
  32.       port_descr  Contains the statically defined port descriptor blocks.
  33.  
  34.    NOTE:    You can not dynamically define ports for IRQ-lines that
  35.             have no interrupt handler function defined. To be completely
  36.             flexible, you would have to define sioint-handlers for all
  37.             possible IRQs and enter the addresses into the irq_procs array.
  38.  
  39.    CAUTION: Please restrict the installation and removal of v24-
  40.             ports to *one* task. The manipulation of the lists is
  41.             not protected, so simultaneous install/remove calls
  42.             may cause trouble. Since ports are normally installed and
  43.             removed in the main task, the protection of critical regions
  44.             seemed unnecessary.
  45.  
  46.    CAUTION: Shared interrupt logic and IRQ-lines above 4 were not
  47.             tested due to the lack of suitable hardware. Changes may
  48.             be necessary in the handling of the modem control register
  49.             OUT2 line that normally controls interrupt enable, depending
  50.             on the multiport-hardware installed in the target system.
  51. */
  52.  
  53. #include "tsk.h"
  54. #include "sio.h"
  55.  
  56. #define MAX_IRQ   16    /* Maximum number of interrupt lines, 
  57.                            16 for AT, 8 for XT. Can be left at 16 */
  58.  
  59. #define CHAIN_IRQBIT    0x04  /* Chained int controller IRQ bit */
  60.  
  61. #define RESTORE_DEFAULT 1     /* Restore parameter for remove_all */
  62.  
  63. typedef void (interrupt far * intprocptr)(void);
  64.  
  65. #define RTS       0x02
  66. #define DTR       0x01
  67. #define OUT2      0x08
  68.  
  69. #define ERR_MASK  0x1e
  70.  
  71. #define inta00    0x20   /* 8259 interrupt controller control-port */
  72. #define inta01    0x21   /* 8259 interrupt controller mask-port */
  73.  
  74. #define inta10    0xa0   /* secondary 8259 control-port for IRQ 8-15 */
  75. #define inta11    0xa1   /* secondary 8259 mask-port for IRQ 8-15 */
  76.  
  77. #define rdserv    0x0b   /* read service register control value */
  78. #define eoi       0x20   /* end of interrupt signal for 8259 */
  79.  
  80. #define intdata   0x0b   /* Enable Interrupts except Line status */
  81.  
  82. #define rxreadybit 0x01
  83. #define txemptybit 0x40
  84. #define txreadybit 0x20
  85. #define framingbit 0x08
  86. #define breakbit   0x10
  87.  
  88. /* Note: In version 1.1, port offsets start at 0, not 8 */
  89.  
  90. #define linecontrol  0x03
  91. #define linestatus   0x05
  92. #define intid        0x02
  93. #define intenable    0x01
  94. #define modemcontrol 0x04
  95. #define modemstatus  0x06
  96. #define receivedata  0x00
  97. #define transmitdata 0x00
  98.  
  99. #define baudreg_dll  0x00     /* baud rate least significant byte */
  100. #define baudreg_dlm  0x01     /* baud rate most significant byte */
  101.  
  102. /*
  103.    Default values for initialising the ports.
  104.    Change to your liking (but remember that OUT2 must be set in the
  105.    modem control register to allow interrupts to come through with 
  106.    normal controllers).
  107. */
  108.  
  109. #define dflt_modcon 0x0b   /* Modem Control: Activate DTR, RTS, OUT2 */
  110. #define dflt_baud   96     /* Baud Rate Divisor: 1200 Baud */
  111. #define dflt_lcon   0x03   /* Line Control: No Parity, 1 Stop, 8 Data */
  112.  
  113. /*
  114.    Defined baud rates. You may expand this table with non-standard
  115.    rates if desired.
  116. */
  117.  
  118. local long baud_table [] = {
  119.                                50L, 2304L,
  120.                                75L, 1536L,
  121.                               110L, 1047L,
  122.                               134L,  857L,
  123.                               150L,  768L,
  124.                               300L,  384L,
  125.                               600L,  192L,
  126.                              1200L,   96L,
  127.                              1800L,   64L,
  128.                              2000L,   58L,
  129.                              2400L,   48L,
  130.                              3600L,   32L,
  131.                              4800L,   24L,
  132.                              7200L,   16L,
  133.                              9600L,   12L,
  134.                             19200L,    6L,
  135.                             38400L,    3L,
  136.                                 0L,    0L };
  137.  
  138. /*-------------------------------------------------------------------------*/
  139.  
  140. /*
  141.    To add static support for other COM-Ports, define
  142.       - Port base
  143.       - IRQ-Line
  144.       - Interrupt vector
  145.    here, and add the necessary data to the port_descr array.
  146.    If the port does *not* share an IRQ with the predefined ports,
  147.    define the corresponding interrupt function by duplicating siointx,
  148.    and place the entry for this function into the irq_procs array.
  149.  
  150.    Note that ports may also be defined on-line if TSK_DYNAMIC is enabled.
  151. */
  152.  
  153. #define STATIC_PORTS  2       /* Number of statically defined ports */
  154.  
  155. /* Note: In version 1.1, port offsets start at 0, not 8 */
  156.  
  157. #define com1_base    0x3f8    /* COM1 port base */
  158. #define com2_base    0x2f8    /* COM2 port base */
  159.  
  160. #define com1_irq     4        /* IRQ-Line for COM1 */
  161. #define com2_irq     3        /* IRQ-Line for COM2 */
  162.  
  163. #define com1_vect    0x0c     /* Interrupt vector for COM1 */
  164. #define com2_vect    0x0b     /* Interrupt vector for COM2 */
  165.  
  166. /*-------------------------------------------------------------------------*/
  167.  
  168.  
  169. local void interrupt far sioint3 (void);
  170. local void interrupt far sioint4 (void);
  171.  
  172. /* 
  173.    Table of Interrupt handler functions for each IRQ line.
  174. */
  175.  
  176. local intprocptr irq_procs [MAX_IRQ] = {  NULL,    /* IRQ 0 */
  177.                                           NULL,    /* IRQ 1 */
  178.                                           NULL,    /* IRQ 2 */
  179.                                           sioint3, /* IRQ 3 */
  180.                                           sioint4, /* IRQ 4 */
  181.                                           NULL,    /* IRQ 5 */
  182.                                           NULL,    /* IRQ 6 */
  183.                                           NULL,    /* IRQ 7 */
  184.                                           NULL,    /* IRQ 8 */
  185.                                           NULL,    /* IRQ 9 */
  186.                                           NULL,    /* IRQ 10 */
  187.                                           NULL,    /* IRQ 11 */
  188.                                           NULL,    /* IRQ 12 */
  189.                                           NULL,    /* IRQ 13 */
  190.                                           NULL,    /* IRQ 14 */
  191.                                           NULL };  /* IRQ 15 */
  192.  
  193.  
  194. local sio_datarec sio_data [STATIC_PORTS];
  195.  
  196. /* When adding entries to port_descr, be sure to chain the 
  197.    elements in ascending order via the first field, and to
  198.    increase the internal port number in the second field. */
  199.  
  200. local port_data port_descr [STATIC_PORTS] = {
  201.      { &port_descr[1], 0, NULL, com1_base, com1_irq, com1_vect },
  202.      { NULL,           1, NULL, com2_base, com2_irq, com2_vect }
  203.                                             };
  204.  
  205. local sioptr  irq_array [MAX_IRQ] = { NULL };
  206.  
  207. local portptr port_list = &port_descr [0];
  208. local portptr port_last = &port_descr [1];
  209.  
  210. local int ports = STATIC_PORTS;
  211.  
  212. extern funcptr v24_remove_func;
  213.  
  214. /*-------------------------------------------------------------------------*/
  215.  
  216.  
  217. local void near change_rts (sioptr data, int on)
  218. {
  219.    data->rtsoff = (byte)(!on);
  220.    data->cmodcontrol = (data->cmodcontrol & ~RTS) | ((on) ? RTS : 0);
  221.    tsk_outp (data->port_base + modemcontrol, data->cmodcontrol);
  222. }
  223.  
  224.  
  225. local void near transmit_ready (sioptr data)
  226. {
  227.    int i;
  228. #if (MSC)
  229.    int temp;
  230. #endif
  231.  
  232.    if ((i = data->r_xoff) < 0)
  233.       {
  234. #if (MSC)
  235.       temp = (i == -1) ? XOFF : XON;
  236.       tsk_outp (data->port_base + transmitdata, temp);
  237. #else
  238.       /* NOTE: Microsoft C 5.0 generates an "Internal Compiler Error"
  239.                when compiling the following statement.
  240.       */
  241.       tsk_outp (data->port_base + transmitdata, (i == -1) ? XOFF : XON);
  242. #endif
  243.       data->r_xoff = (i == -1) ? 1 : 0;
  244.       data->xmit_pending = 1;
  245.       return;
  246.       }
  247.  
  248.    data->xmit_pending = 0;
  249.  
  250.    if (!(data->wait_xmit = (byte)(check_pipe (&data->xmit_pipe) != -1)))
  251.       return;
  252.  
  253.    if ((data->modem_flags & data->modstat) ^ data->modem_flags)
  254.       return;
  255.  
  256.    if (data->flags & XONXOFF && data->t_xoff)
  257.       return;
  258.  
  259.    data->wait_xmit = 0;
  260.  
  261.    if ((i = c_read_pipe (&data->xmit_pipe)) < 0)
  262.       return;
  263.  
  264.    tsk_outp (data->port_base + transmitdata, (byte)i);
  265.    data->xmit_pending = 1;
  266. }
  267.  
  268.  
  269. local void near modem_status_int (sioptr data)
  270. {
  271.    data->modstat = tsk_inp (data->port_base + modemstatus);
  272.  
  273.    if (data->wait_xmit)
  274.       transmit_ready (data);
  275. }
  276.  
  277.  
  278. local void near receive_ready (sioptr data)
  279. {
  280.    word status;
  281.    word ch;
  282.  
  283.    while ((status = tsk_inp (data->port_base + linestatus)) & rxreadybit)
  284.       {
  285.       tsk_nop ();
  286.       ch = tsk_inp (data->port_base + receivedata);
  287.  
  288.       if (data->flags & XONXOFF)
  289.          {
  290.          if (ch == XON)
  291.             {
  292.             data->t_xoff = 0;
  293.             if (data->wait_xmit)
  294.                transmit_ready (data);
  295.             continue;
  296.             }
  297.          else if (ch == XOFF)
  298.             {
  299.             data->t_xoff = 1;
  300.             continue;
  301.             }
  302.          if (!data->r_xoff && 
  303.              wpipe_free (&data->rcv_pipe) < data->xoff_threshold)
  304.             {
  305.             data->r_xoff = -1;
  306.             if (!data->xmit_pending)
  307.                transmit_ready (data);
  308.             }
  309.          }
  310.  
  311.       if (data->flags & RTSCTS && !data->rtsoff)
  312.          if (wpipe_free (&data->rcv_pipe) < data->xoff_threshold)
  313.             change_rts (data, 0);
  314.  
  315.       status = (status & ERR_MASK) << 8;
  316.       if (c_write_wpipe (&data->rcv_pipe, ch | status) < 0)
  317.          data->overrun = 1;
  318.       }
  319. }
  320.  
  321.  
  322. /*-------------------------------------------------------------------------*/
  323.  
  324.  
  325. local void near sioint (sioptr data)
  326. {
  327.    int id;
  328.  
  329.    while (!((id = tsk_inp (data->port_base + intid)) & 1))
  330.       switch (id & 0x07)
  331.          {
  332.          case 0x00:  modem_status_int (data);
  333.                      break;
  334.  
  335.          case 0x02:  transmit_ready (data);
  336.                      break;
  337.  
  338.          case 0x04:  receive_ready (data);
  339.                      break;
  340.  
  341. /*       case 0x06:  line_status_int (data); (currently not used)
  342.                      break;
  343. */
  344.          }
  345. }
  346.  
  347.  
  348. local void interrupt far sioint3 (void)
  349. {
  350.    sioptr curr;
  351.  
  352.    tsk_sti ();
  353.    for (curr = irq_array [3]; curr != NULL; curr = curr->next)
  354.       sioint (curr);
  355.  
  356.    tsk_cli ();
  357.    /* NOTE: for IRQ's 8-15, add the following here:
  358.       tsk_outp (inta10, eoi);
  359.    */
  360.    tsk_outp (inta00, eoi);
  361. }
  362.  
  363.  
  364. local void interrupt far sioint4 (void)
  365. {
  366.    sioptr curr;
  367.  
  368.    tsk_sti ();
  369.    for (curr = irq_array [4]; curr != NULL; curr = curr->next)
  370.       sioint (curr);
  371.  
  372.    tsk_cli ();
  373.    /* NOTE: for IRQ's 8-15, add the following here:
  374.       tsk_outp (inta10, eoi);
  375.    */
  376.    tsk_outp (inta00, eoi);
  377. }
  378.  
  379. /*-------------------------------------------------------------------------*/
  380.  
  381. int far v24_define_port (int base, byte irq, byte vector)
  382. {
  383. #if (TSK_DYNAMIC)
  384.    portptr portp;
  385.  
  386.    if (irq >= MAX_IRQ)
  387.       return -1; 
  388.    if (irq_procs [irq] == NULL)
  389.       return -1; 
  390.  
  391.    if ((portp = tsk_alloc (sizeof (port_data))) == NULL)
  392.       return -1;
  393.    portp->pnum = ports;
  394.    portp->base = base;
  395.    portp->irq = irq;
  396.    portp->vector = vector;
  397.    portp->next = NULL;
  398.    portp->sio = NULL;
  399.  
  400.    if (port_list == NULL)
  401.       port_list = portp;
  402.    else
  403.       port_last->next = portp;
  404.  
  405.    port_last = portp;
  406.    ports++;
  407.  
  408.    return portp->pnum;
  409.  
  410. #else
  411.    return -1;
  412. #endif
  413. }
  414.  
  415.  
  416. local sioptr ret_error (sioptr sio)
  417. {
  418.    sio->port->sio = NULL;
  419. #if (TSK_DYNAMIC)
  420.    if (sio->port->pnum >= STATIC_PORTS)
  421.       tsk_free (sio);
  422. #endif
  423.    return NULL; 
  424. }
  425.  
  426. sioptr far v24_install (int port, int init,
  427.                         farptr rcvbuf, word rcvsize,
  428.                         farptr xmitbuf, word xmitsize)
  429. {
  430.    sioptr sio;
  431.    portptr portp;
  432.    int pbase;
  433.    intprocptr far *intptr;
  434.    int i, inta;
  435.  
  436. #if (TSK_NAMEPAR)
  437.    static char xname [] = "SIOnXMIT", rname [] = "SIOnRCV";
  438.  
  439.    xname [3] = rname [3] = (char)(port & 0x7f) + '0';
  440. #endif
  441.  
  442.    if (port < 0 || !rcvsize || !xmitsize)
  443.       return NULL;
  444.  
  445.    portp = port_list;
  446.  
  447.    if (port & 0x80)     /* Relative port number */
  448.       {
  449.       port &= 0x7f;
  450.       if (port > 4)
  451.          return NULL; 
  452.       pbase = *((wordptr)(MK_FP (0x40, port * 2)));
  453.       if (!pbase)
  454.          return NULL;
  455.  
  456.       for (port = 0; port < ports; port++, portp = portp->next)
  457.          if (portp->base == pbase)
  458.             break;
  459.  
  460.       if (port >= ports)
  461.          return NULL;
  462.       }
  463.    else 
  464.       {
  465.       if (port > ports)
  466.          return NULL;
  467.       for (port = 0; port < ports; port++)
  468.          portp = portp->next;
  469.       }
  470.  
  471.    if (portp->sio != NULL) /* Port already in use ? */
  472.       return NULL;
  473.  
  474.    if (port < STATIC_PORTS)
  475.       portp->sio = sio = &sio_data [port];
  476.    else
  477. #if (TSK_DYNAMIC)
  478.       if ((portp->sio = sio = tsk_alloc (sizeof (sio_datarec))) == NULL)
  479.          return NULL;
  480. #else
  481.       return NULL;
  482. #endif
  483.  
  484.    pbase = sio->port_base = portp->base;
  485.    sio->port = portp;
  486.  
  487.    /* Check if port accessible by modifying the modem control register */
  488.  
  489.    i = sio->cmodcontrol = sio->save_mcon = tsk_inp (pbase + modemcontrol);
  490.    if (i & 0xe0)
  491.       return ret_error (sio);
  492.    tsk_nop ();
  493.    tsk_outp (pbase + modemcontrol, 0xe0 | i);
  494.    tsk_nop ();
  495.    if (tsk_inp (pbase + modemcontrol) != (byte) i)
  496.       return ret_error (sio);
  497.  
  498.    /* Port seems OK */
  499.  
  500.    if (create_pipe (&sio->xmit_pipe, xmitbuf, xmitsize
  501. #if (TSK_NAMEPAR)
  502.                 , xname
  503. #endif
  504.                 ) == NULL)
  505.       return ret_error (sio);
  506.  
  507.    if (create_wpipe (&sio->rcv_pipe, rcvbuf, rcvsize
  508. #if (TSK_NAMEPAR)
  509.                 , rname
  510. #endif
  511.                 ) == NULL)
  512.       {
  513.       delete_pipe (&sio->xmit_pipe);
  514.       return ret_error (sio);
  515.       }
  516.  
  517.    sio->civect = portp->vector;
  518.    sio->irqbit = (byte)(1 << (portp->irq & 0x07));
  519.  
  520.    sio->wait_xmit = sio->xmit_pending = 0;
  521.    sio->overrun = 0;
  522.    sio->flags = 0;
  523.    sio->modem_flags = 0;
  524.    sio->r_xoff = sio->t_xoff = 0;
  525.    sio->rtsoff = 0;
  526.  
  527.    sio->clcontrol = sio->save_lcon = tsk_inp (pbase + linecontrol);
  528.    tsk_nop ();
  529.    sio->save_inten = tsk_inp (pbase + intenable);
  530.    tsk_nop ();
  531.  
  532.    if (init)
  533.       {
  534.       sio->clcontrol = dflt_lcon;
  535.       sio->cmodcontrol = dflt_modcon;
  536.       }
  537.  
  538.    tsk_outp (pbase + linecontrol, sio->clcontrol | 0x80);
  539.    tsk_nop ();
  540.    sio->save_bd1 = tsk_inp (pbase + baudreg_dll);
  541.    tsk_nop ();
  542.    sio->save_bd2 = tsk_inp (pbase + baudreg_dlm);
  543.    tsk_nop ();
  544.    tsk_outp (pbase + linecontrol, sio->clcontrol);
  545.    tsk_nop ();
  546.  
  547.    tsk_outp (pbase + intenable, 0);
  548.  
  549.    if (irq_array [portp->irq] == NULL)
  550.       {
  551.       intptr = (intprocptr far *)MK_FP (0, sio->civect * 4);
  552.       tsk_cli ();
  553.       sio->savvect = *intptr;
  554.       *intptr = irq_procs [portp->irq];
  555.       tsk_sti ();
  556.       }
  557.  
  558.    if (init)
  559.       {
  560.       tsk_outp (pbase + linecontrol, dflt_lcon | 0x80);
  561.       tsk_nop ();
  562.       tsk_outp (pbase + baudreg_dll, dflt_baud);
  563.       tsk_nop ();
  564.       tsk_outp (pbase + baudreg_dlm, dflt_baud >> 8);
  565.       tsk_nop ();
  566.       tsk_outp (pbase + linecontrol, dflt_lcon);
  567.       tsk_nop ();
  568.       tsk_outp (pbase + modemcontrol, dflt_modcon);
  569.       tsk_nop ();
  570.       }
  571.    else
  572.       {
  573.       i = tsk_inp (pbase + modemcontrol) | OUT2;
  574.       tsk_nop ();
  575.       tsk_outp (pbase + modemcontrol, i);
  576.       tsk_nop ();
  577.       }
  578.  
  579.    while (tsk_inp (pbase + linestatus) & rxreadybit)
  580.       {
  581.       tsk_nop ();
  582.       tsk_inp (pbase + receivedata);
  583.       tsk_nop ();
  584.       }
  585.    tsk_nop ();
  586.  
  587.    tsk_inp (pbase + linestatus);
  588.    tsk_nop ();
  589.    sio->modstat = tsk_inp (pbase + modemstatus);
  590.    tsk_nop ();
  591.    tsk_inp (pbase + intid);
  592.    tsk_nop ();
  593.  
  594.    inta = (portp->irq > 7) ? inta11 : inta01;
  595.  
  596.    if (irq_array [portp->irq] == NULL)
  597.       {
  598.       if (portp->irq > 7)
  599.          {
  600.          i = tsk_inp (inta01) & ~CHAIN_IRQBIT;
  601.          tsk_nop ();
  602.          tsk_outp (inta01, i);
  603.          }
  604.  
  605.       sio->save_irq = (byte)((i = tsk_inp (inta)) & sio->irqbit);
  606.       tsk_nop ();
  607.       tsk_outp (inta, i & ~sio->irqbit);
  608.       }
  609.    else
  610.       sio->save_irq = (irq_array [portp->irq])->save_irq;
  611.  
  612.    tsk_cli ();
  613.    sio->next = irq_array [portp->irq];
  614.    irq_array [portp->irq] = sio;
  615.    tsk_sti ();
  616.  
  617.    v24_remove_func = v24_remove_all;
  618.  
  619.    tsk_outp (pbase + intenable, intdata);
  620.  
  621.     return sio;
  622.    }
  623.  
  624.  
  625. void far v24_remove (sioptr sio, int restore)
  626.    {
  627.    intprocptr far *intptr;
  628.    int pbase, i, inta;
  629.    portptr portp;
  630.    sioptr curr, last;
  631.  
  632.    pbase = sio->port_base;
  633.    portp = sio->port;
  634.  
  635.    last = NULL;
  636.    curr = irq_array [portp->irq];
  637.    while (curr != sio && curr != NULL)
  638.       {
  639.       last = curr;
  640.       curr = curr->next;
  641.       }
  642.    if (curr == NULL)
  643.       return;
  644.  
  645.    tsk_outp (pbase + intenable, 0);
  646.    tsk_cli ();
  647.    if (last == NULL)
  648.       irq_array [portp->irq] = sio->next;
  649.    else
  650.       last->next = sio->next;
  651.    tsk_sti ();
  652.  
  653.    inta = (portp->irq > 7) ? inta11 : inta01;
  654.  
  655.    if (restore)
  656.       {
  657.       tsk_outp (pbase + modemcontrol, sio->save_mcon);
  658.       tsk_nop ();
  659.       tsk_outp (pbase + linecontrol, sio->save_lcon | 0x80);
  660.       tsk_nop ();
  661.       tsk_outp (pbase + baudreg_dll, sio->save_bd1);
  662.       tsk_nop ();
  663.       tsk_outp (pbase + baudreg_dlm, sio->save_bd2);
  664.       tsk_nop ();
  665.       tsk_outp (pbase + linecontrol, sio->save_lcon);
  666.       tsk_nop ();
  667.       if (irq_array [portp->irq] == NULL)
  668.          {
  669.          tsk_cli ();
  670.          tsk_outp (pbase + intenable, sio->save_inten);
  671.          i = tsk_inp (inta) & ~sio->irqbit;
  672.          tsk_nop ();
  673.          tsk_outp (inta, i | sio->save_irq);
  674.          }
  675.       }
  676.    else if (irq_array [portp->irq] == NULL)
  677.       {
  678.       tsk_cli ();
  679.       i = tsk_inp (inta) | sio->irqbit;
  680.       tsk_nop ();
  681.       tsk_outp (inta, i);
  682.       }
  683.  
  684.    if (irq_array [portp->irq] == NULL)
  685.       {
  686.       tsk_cli ();
  687.       intptr = (intprocptr far *)MK_FP (0, sio->civect * 4);
  688.       *intptr = sio->savvect;
  689.       }
  690.    tsk_sti ();
  691.  
  692.    portp->sio = NULL;
  693.    delete_pipe (&sio->xmit_pipe);
  694.    delete_wpipe (&sio->rcv_pipe);
  695.  
  696. #if (TSK_DYNAMIC)
  697.    if (portp->pnum >= STATIC_PORTS)
  698.       tsk_free (sio);
  699. #endif
  700.    }
  701.  
  702.  
  703. void far v24_remove_all (void)
  704. {
  705.    int i;
  706.    sioptr sio;
  707.  
  708.    for (i = 0; i < MAX_IRQ; i++)
  709.       {
  710.       while ((sio = irq_array [i]) != NULL)
  711.          v24_remove (sio, RESTORE_DEFAULT);
  712.       }
  713. }
  714.  
  715. /*-------------------------------------------------------------------------*/
  716.  
  717. /*
  718.    void v24_change_rts (sioptr sio, int on)
  719. */
  720.  
  721. void far v24_change_rts (sioptr sio, int on)
  722. {
  723.    sio->cmodcontrol = (sio->cmodcontrol & ~RTS) | ((on) ? RTS : 0);
  724.    tsk_outp (sio->port_base + modemcontrol, sio->cmodcontrol);
  725. }
  726.  
  727. /*
  728.    void v24_change_dtr (sioptr sio, int on)
  729. */
  730.  
  731. void far v24_change_dtr (sioptr sio, int on)
  732. {
  733.    sio->cmodcontrol = (sio->cmodcontrol & ~DTR) | ((on) ? DTR : 0);
  734.    tsk_outp (sio->port_base + modemcontrol, sio->cmodcontrol);
  735. }
  736.  
  737.  
  738. /*
  739.    void far v24_change_baud (sioptr sio, int rate)
  740. */
  741.  
  742. void far v24_change_baud (sioptr sio, long rate)
  743. {
  744.    int i;
  745.  
  746.    for (i = 0; baud_table [i]; i += 2)
  747.       if (baud_table [i] == rate)
  748.          break;
  749.    if (!(i = (int)baud_table [i + 1]))
  750.       return;
  751.  
  752.    tsk_outp (sio->port_base + linecontrol, sio->clcontrol | (byte)0x80);
  753.    tsk_nop ();
  754.    tsk_outp (sio->port_base + baudreg_dll, (byte)i);
  755.    tsk_nop ();
  756.    tsk_outp (sio->port_base + baudreg_dlm, (byte)(i >> 8));
  757.    tsk_nop ();
  758.    tsk_outp (sio->port_base + linecontrol, sio->clcontrol);
  759. }
  760.  
  761.  
  762. void far v24_change_parity (sioptr sio, int par)
  763. {
  764.    sio->clcontrol = (sio->clcontrol & 0xc7) | par;
  765.    tsk_outp (sio->port_base + linecontrol, sio->clcontrol);
  766. }
  767.  
  768.  
  769. void far v24_change_wordlength (sioptr sio, int len)
  770. {
  771.    int i;
  772.  
  773.    switch (len)
  774.       {
  775.       case 5:  i = 0x00; break;
  776.       case 6:  i = 0x01; break;
  777.       case 7:  i = 0x02; break;
  778.       case 8:  i = 0x03; break;
  779.       default: return;
  780.       }
  781.    sio->clcontrol = (sio->clcontrol & 0xfc) | i;
  782.    tsk_outp (sio->port_base + linecontrol, sio->clcontrol);
  783. }
  784.  
  785.  
  786. void far v24_change_stopbits (sioptr sio, int n)
  787. {
  788.    int i;
  789.  
  790.    switch (n)
  791.       {
  792.       case 1:  i = 0x00; break;
  793.       case 2:  i = 0x04; break;
  794.       default: return;
  795.       }
  796.    sio->clcontrol = (sio->clcontrol & 0xfb) | i;
  797.    tsk_outp (sio->port_base + linecontrol, sio->clcontrol);
  798. }
  799.  
  800.  
  801. void far v24_watch_modem (sioptr sio, byte flags)
  802. {
  803.    sio->modem_flags = flags & (CTS | DSR | RI | CD);
  804. }
  805.  
  806.  
  807. void far v24_protocol (sioptr sio, int prot, word offthresh, word onthresh)
  808. {
  809.    byte old;
  810.    
  811.    old = sio->flags;
  812.    sio->flags = (byte)prot;
  813.    if (prot)
  814.       {
  815.       if (!offthresh)
  816.          offthresh = 10;
  817.       sio->xoff_threshold = offthresh;
  818.       if (onthresh <= offthresh)
  819.          onthresh = offthresh + 10;
  820.       sio->xon_threshold = onthresh;
  821.       }
  822.  
  823.    if ((old & RTSCTS) != ((byte)prot & RTSCTS))
  824.       {
  825.       change_rts (sio, 1);
  826.       sio->modem_flags = (sio->modem_flags & ~CTS) |
  827.                          ((prot & RTSCTS) ? CTS : 0);
  828.       }
  829.  
  830.    if (!(prot & XONXOFF))
  831.       {
  832.       if (sio->r_xoff)
  833.          sio->r_xoff = -2;
  834.       sio->t_xoff = 0;
  835.       }
  836.  
  837.    if (!sio->xmit_pending)
  838.       transmit_ready (sio);
  839. }
  840.  
  841.  
  842. /*-------------------------------------------------------------------------*/
  843.  
  844.  
  845. int far v24_send (sioptr sio, byte ch, dword timeout)
  846. {
  847.    int res;
  848.  
  849.    if ((res = write_pipe (&sio->xmit_pipe, ch, timeout)) < 0)
  850.       return res;
  851.    tsk_cli ();
  852.    if (!sio->xmit_pending)
  853.       transmit_ready (sio);
  854.    tsk_sti ();
  855.    return 0;
  856. }
  857.  
  858.  
  859. int far v24_receive (sioptr sio, dword timeout)
  860. {
  861.    int res;
  862.    
  863.    if ((res = (int)read_wpipe (&sio->rcv_pipe, timeout)) < 0)
  864.       return res;
  865.  
  866.    if (!sio->flags)
  867.       return res;
  868.  
  869.    if (wpipe_free (&sio->rcv_pipe) > sio->xon_threshold)
  870.       {
  871.       tsk_cli ();
  872.       if (sio->r_xoff)
  873.          {
  874.          sio->r_xoff = -2;
  875.          if (!sio->xmit_pending)
  876.             transmit_ready (sio);
  877.          }
  878.       tsk_sti ();
  879.  
  880.       if (sio->rtsoff)
  881.          change_rts (sio, 1);
  882.       }
  883.    return res;
  884. }
  885.  
  886.  
  887. int far v24_overrun (sioptr sio)
  888. {
  889.    int res;
  890.  
  891.    res = sio->overrun;
  892.    sio->overrun = 0;
  893.    return res;
  894. }
  895.  
  896.  
  897. int far v24_check (sioptr sio)
  898. {
  899.    return check_wpipe (&sio->rcv_pipe);
  900. }
  901.  
  902.  
  903. int far v24_modem_status (sioptr sio)
  904. {
  905.    return sio->modstat;
  906. }
  907.  
  908.  
  909. int far v24_complete (sioptr sio)
  910. {
  911.    return (check_pipe (&sio->xmit_pipe) == -1);
  912. }
  913.  
  914.  
  915. int far v24_wait_complete (sioptr sio, dword timeout)
  916. {
  917.    return wait_pipe_empty (&sio->xmit_pipe, timeout);
  918. }
  919.  
  920.  
  921.