home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_09_12 / 9n12075a < prev    next >
Text File  |  1991-07-27  |  17KB  |  443 lines

  1. /** LISTING 3 ** UARTLOW.C ***************************
  2.  
  3.    Low level device driver routines for UART
  4. *****************************************************/
  5. #define UARTMAIN 1       
  6.  
  7. #include <conio.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stddef.h>
  11. #include <dos.h>
  12.  
  13. #include "uart.h"
  14. #include "uartmacs.c"
  15.  
  16. /* 
  17.  *  Compile Options  :  /AL /Ox /Zp /c
  18.  *           (Large library, optimization
  19.  *            for maxium speed, pack structures).
  20.  *           Note: /Ox does the following optimizations
  21.  *              Relaxed alias checking
  22.  *              Loop optimization
  23.  *              Intrinsic substitution
  24.  *              Optimization for speed
  25.  *              Removing stack probing
  26. */
  27. #pragma check_stack(off)
  28.  
  29. void interrupt far Asynch_driver(void)
  30. {              
  31.    register int value_from_port;   
  32.    register int cur_char;
  33.    static unsigned char near cur_port;
  34.    static struct t_port_info *p_cur_port_info; 
  35.    static int near interrupts_processed;
  36.    static int near i;  
  37.    static char *p_temp;
  38.    static char tx_char;
  39.  
  40.    /* Note - interrupts are automatically disabled by
  41.              CPU before entering interrupt routine. */
  42.    
  43.    do 
  44.    {   /* Loop until we make one complete pass 
  45.           without processing any interrupts */
  46.  
  47.        /* Set flag indicating that we haven't 
  48.           processed any interrupts on this pass
  49.           through the loop yet. */
  50.        interrupts_processed = 0;  
  51.  
  52.        /* Address the port entry of the first port in 
  53.           the system. */
  54.        p_cur_port_info = gp_port_info;
  55.        for (cur_port=1;cur_port<=g_num_ports;
  56.             cur_port++)
  57.        {   /* Loop through all the ports */
  58.  
  59.            /* read port's interrupt identification register */
  60.            value_from_port = inp(p_cur_port_info->
  61.                base_address+INTERRUPT_IDENT_REGISTER);
  62.  
  63.            if ( value_from_port & 0x01 )  
  64.            {   /* No interrupt pending */
  65.            
  66.                /* If less than MAX_RCVFIFO characters
  67.                   have been read without receiving a
  68.                   receive data interrupt, check line 
  69.                   status register to see if there is 
  70.                   still data in the FIFO.  This code
  71.                   will function correctly even if there
  72.                   isn't a FIFO. */
  73.                if (p_cur_port_info->non_int_chars < 
  74.                    MAX_RCVFIFO)
  75.                {
  76.                    /* read port's line status register */
  77.                    value_from_port = 
  78.                        inp(p_cur_port_info->
  79.                            base_address +
  80.                            LINE_STATUS_REGISTER);
  81.  
  82.                    /* Delay for port to catch up */
  83.                    IO_DELAY(1);         
  84.  
  85.                    if ( value_from_port & 0x01 )
  86.                    {   /* Data is ready */
  87.  
  88.                        /* Increment number of chars 
  89.                           processed from fifo without 
  90.                           interrupt */
  91.                        p_cur_port_info->
  92.                            non_int_chars++;
  93.  
  94.                        /* We have found at least one 
  95.                           interrupt pending so we will 
  96.                           have to make at least one 
  97.                           more pass. */
  98.                        interrupts_processed = 1;       
  99.  
  100.                        /* Skip normal interrupt 
  101.                           identification logic, and go
  102.                           right to reading the data. */
  103.                        goto force_read_data;
  104.                    }   /* End data is ready */
  105.  
  106.                }   /* End p_cur_port_info->
  107.                       non_int_chars < MAX_RCVFIFO) */
  108.            }   /* end no interrupt pending */
  109.            else
  110.            {   /* There is an interrupt pending
  111.                   from this port */
  112.                /* We have found at least one interrupt 
  113.                   pending so we will have to make at 
  114.                   least one more pass. */
  115.                interrupts_processed = 1;
  116.  
  117.                /* Mask out unwanted bits from interrupt
  118.                   identification.  */
  119.                value_from_port &= IIR_MASK;        
  120.  
  121.                switch (value_from_port)
  122.                {   /* Conditional execution depending
  123.                       on type of interrupt */
  124.  
  125.                    /* Interrupt for Receiver Line
  126.                       Status */
  127.                    case 0x06 :
  128.  
  129.                        /* Clear receive register */
  130.                        cur_char =
  131.                            inp(p_cur_port_info->
  132.                                base_address +
  133.                                RECEIVE_REGISTER);
  134.  
  135.                        /* Clear high word of character
  136.                           before breaking down error */
  137.                        cur_char &= 0x00ff;
  138.  
  139.                        /* read port's line status 
  140.                           register */
  141.                        value_from_port = 
  142.                            inp(p_cur_port_info->
  143.                                base_address + 
  144.                                LINE_STATUS_REGISTER);
  145.  
  146.                        if (value_from_port & 0x10)
  147.                        {   /* Received 'break' */ 
  148.                            cur_char |= BREAK_SIGNAL;
  149.                        }   
  150.  
  151.                        if (value_from_port & 0x08)
  152.                        {   /*  framing error */
  153.                            cur_char |= FRAMING_ERROR;
  154.                        }   
  155.            
  156.                        if (value_from_port & 0x04)
  157.                        {   /* parity error */
  158.                            cur_char |= PARITY_ERROR;
  159.                        }   
  160.            
  161.                        if (value_from_port & 0x02)
  162.                        {   /* overrun error */
  163.                            cur_char |= OVERRUN_ERROR;
  164.                        }   
  165.  
  166.                        goto add_char_to_rx_buf;
  167.  
  168.  
  169.                    /* Interrupt for data received */
  170.                    case 0x04 :
  171.                    
  172.                        /* Check line status register to
  173.                           see if data is ready */
  174.                        value_from_port = 
  175.                            inp(p_cur_port_info->
  176.                                base_address +
  177.                                LINE_STATUS_REGISTER);
  178.                        if ( !(value_from_port & 0x01) )
  179.                            break;
  180.  
  181.                        /* Set number of characters 
  182.                           received without data receive
  183.                           interrupt to 0. */
  184.                        p_cur_port_info->
  185.                            non_int_chars = 0;     
  186.  
  187.                        force_read_data:
  188.  
  189.                        /* read received data 
  190.                           register */
  191.                        cur_char =
  192.                            inp(p_cur_port_info->
  193.                                base_address+
  194.                                RECEIVE_REGISTER);
  195.  
  196.                        /* Clear high word of character
  197.                           before breaking down error */
  198.                        cur_char &= 0x00ff;
  199.  
  200.                        add_char_to_rx_buf:
  201.  
  202.                        /* Calculate pointer to next
  203.                           position in circular 
  204.                           receive buffer */
  205.                        p_temp = p_cur_port_info->
  206.                            a_receive_buffer + 
  207.                            p_cur_port_info->rx_tail;
  208.  
  209.                        /* Calculate next tail position
  210.                           in receive buffer */
  211.                        p_cur_port_info->rx_tail += 2;
  212.                        if (p_cur_port_info->rx_tail >=
  213.                            (BUFFER_SIZE * 2) )
  214.                           p_cur_port_info->rx_tail = 0; 
  215.  
  216.                        /* Check for receive buffer 
  217.                           overflow */
  218.                        if (p_cur_port_info->rx_tail ==
  219.                            p_cur_port_info->rx_head)
  220.                            {   /* Receive buffer has 
  221.                                   overflowed.  Update 
  222.                                   flag to reflect this,
  223.                                   and advance head 
  224.                                   (losing one char). */
  225.                                cur_char |= 
  226.                                    BUFFER_OVERRUN;
  227.                                
  228.                                p_cur_port_info->rx_head
  229.                                    += 2;
  230.                                if (p_cur_port_info->
  231.                                    rx_head >=
  232.                                    (BUFFER_SIZE * 2) )
  233.                                   p_cur_port_info->
  234.                                        rx_head = 0; 
  235.                            }
  236.  
  237.                        /* Add character with coded 
  238.                           error condition flag to 
  239.                           circular buffer */
  240.                        *( (int *) p_temp) = cur_char;
  241.  
  242.                        break;
  243.  
  244.                    /* Interrupt for Transmit Holding
  245.                       Register Emtpy */
  246.                    case 0x02 : 
  247.                        if (p_cur_port_info->tx_head !=
  248.                            p_cur_port_info->tx_tail ) 
  249.                        {   /* Have data to transmit */
  250.  
  251.                            if (p_cur_port_info->
  252.                                obey_rts_cts && 
  253.                               !p_cur_port_info->
  254.                                cts_state)
  255.                            {   /* Require Clear To 
  256.                                   Send before 
  257.                                   transmitting */
  258.  
  259.                                /* Raise the Request To
  260.                                   Send signal */
  261.                                RAISE_RTS;
  262.  
  263.                                break;
  264.                            }
  265.  
  266.                            /* read port's line status 
  267.                               register */
  268.                            value_from_port = 
  269.                                inp(p_cur_port_info->
  270.                                  base_address +
  271.                                  LINE_STATUS_REGISTER);
  272.         
  273.                            /* Delay for port to catch 
  274.                               up */
  275.                            IO_DELAY(2);       
  276.  
  277.                            /* Make sure transmit 
  278.                               holding register is 
  279.                               really empty. */
  280.                            if ( !(value_from_port 
  281.                                   & 0x20) )
  282.                                break;
  283.  
  284.                            /* Transmit as many chars as
  285.                               port can handle (depends
  286.                               on presence/absence of
  287.                               fifo), until transmit
  288.                               circular buffer is 
  289.                               empty */
  290.                            for (i=0;
  291.                                 (i<p_cur_port_info->
  292.                                    max_tx_chars) &&
  293.                                 (p_cur_port_info->
  294.                                  tx_head !=
  295.                                  p_cur_port_info->
  296.                                  tx_tail ) ;
  297.                                 i++)
  298.                            {
  299.                                /* Get next character 
  300.                                   to transmit and 
  301.                                   increment transmit
  302.                                   data pointer. */
  303.                                tx_char = 
  304.                                    p_cur_port_info->
  305.                                    a_transmit_buffer[
  306.                                      p_cur_port_info->
  307.                                        tx_head++];
  308.                                if (p_cur_port_info->
  309.                                    tx_head >=
  310.                                    BUFFER_SIZE)
  311.                                    p_cur_port_info->
  312.                                    tx_head = 0;
  313.  
  314.                                /* Transmit the 
  315.                                   character */
  316.                                outp(p_cur_port_info->
  317.                                     base_address +
  318.                                     TRANSMIT_REGISTER,
  319.                                     tx_char);
  320.                            }   /* End for TX loop */
  321.  
  322.                        }   /* end if data to
  323.                               transmit */
  324.                        else
  325.                        {   /* No data to send */
  326.  
  327.                            if (p_cur_port_info->
  328.                                obey_rts_cts)
  329.                            {   /* No data to send, port
  330.                                   is using flow 
  331.                                   control */
  332.  
  333.                                /* Turn off the Request
  334.                                   To Send signal */
  335.                                DROP_RTS;
  336.                            }
  337.  
  338.                        }   /* End no data to send */
  339.  
  340.                        break;
  341.  
  342.                    /* Interrupt for modem status 
  343.                       change */
  344.                    case 0x00 :
  345.                        /* read port's modem status 
  346.                           register */
  347.                        value_from_port = 
  348.                            inp(p_cur_port_info->
  349.                                base_address +
  350.                                MODEM_STATUS_REGISTER);
  351.  
  352.                        if (value_from_port & 0x02) 
  353.                        {   /* Change in Data Set Ready */
  354.  
  355.                            if (IS_DSR(value_from_port))
  356.                                /* DSR came on */
  357.                                p_cur_port_info->
  358.                                    dsr_state = 1;
  359.                            else
  360.                                /* DSR went off */
  361.                                p_cur_port_info->
  362.                                    dsr_state = 0;
  363.  
  364.                        }  /* End if delta data set ready */
  365.  
  366.                        if (value_from_port & 0x08)
  367.                        {      /* Change In Data Carrier Detect */
  368.  
  369.                            if (IS_DCD(value_from_port))
  370.                                /* DCD came on */
  371.                                p_cur_port_info->
  372.                                    dcd_state = 1;
  373.                            else
  374.                                /* DCD went off */
  375.                                p_cur_port_info->
  376.                                    dcd_state = 0;
  377.  
  378.                        } /* End if delta carrier detect */
  379.  
  380.                        if (value_from_port & 0x01)
  381.                        {       /* Change in Clear To Send */
  382.  
  383.                            if (IS_CTS(value_from_port))
  384.                                {
  385.                                   /* CTS came on */
  386.                                   p_cur_port_info->
  387.                                       cts_state = 1;
  388.  
  389.                                   /* Generate a 
  390.                                      Transmit Holding
  391.                                      Register Empty
  392.                                      Interrupt to allow
  393.                                      data to be sent */
  394.                                   BOUNCE_THRE;
  395.                                }
  396.                            else
  397.                                /* CTS went off */
  398.                                p_cur_port_info->
  399.                                    cts_state = 0;
  400.  
  401.                        } /* End if delta clear to send */
  402.  
  403.                        if (value_from_port & 0x04)
  404.                        {       /* Change in Ring Indicator state */
  405.  
  406.                           if (IS_RING(value_from_port))
  407.                           {    /* Ringing in */
  408.  
  409.                                /* Put ring indication 
  410.                                   into circular buffer
  411.                                   */
  412.                                cur_char = 
  413.                                    RING_INDICATION;
  414.                                goto add_char_to_rx_buf;
  415.                           }
  416.                        } /* End if delta ring indicator */
  417.                        break;
  418.  
  419.                    /* Unkown interrupt */
  420.                    default : break;
  421.  
  422.                }   /* End switch on type of 
  423.                       interrupt */
  424.  
  425.            }   /* end interrupt pending */
  426.  
  427.            p_cur_port_info++;      /* Point at next port */
  428.  
  429.        }   /* End loop through all ports */
  430.  
  431.    } while (interrupts_processed == 0);
  432.  
  433.    /* Output non-specific End Of Interrupt to 8259 
  434.       interrupt controller for IRQs 0 - 7 */
  435.    outp(R8259A_CONTROL,0x20);        
  436.  
  437.    /* Note - Interrupts are not re-enabled to ensure 
  438.              that the IRET will be executed before the
  439.              next interrupt */
  440.  
  441.    return;
  442. }
  443.