home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gdb-4.16-base.tgz / gdb-4.16-base.tar / fsf / gdb / utils / amd-udi / montip / serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-23  |  16.2 KB  |  608 lines

  1. static char _[] = "@(#)serial.c    5.21 93/10/26 09:47:06, Srini, AMD.";
  2. /******************************************************************************
  3.  * Copyright 1991 Advanced Micro Devices, Inc.
  4.  *
  5.  * This software is the property of Advanced Micro Devices, Inc  (AMD)  which
  6.  * specifically  grants the user the right to modify, use and distribute this
  7.  * software provided this notice is not removed or altered.  All other rights
  8.  * are reserved by AMD.
  9.  *
  10.  * AMD MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS
  11.  * SOFTWARE.  IN NO EVENT SHALL AMD BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL
  12.  * DAMAGES IN CONNECTION WITH OR ARISING FROM THE FURNISHING, PERFORMANCE, OR
  13.  * USE OF THIS SOFTWARE.
  14.  *
  15.  * So that all may benefit from your experience, please report  any  problems
  16.  * or  suggestions about this software to the 29K Technical Support Center at
  17.  * 800-29-29-AMD (800-292-9263) in the USA, or 0800-89-1131  in  the  UK,  or
  18.  * 0031-11-1129 in Japan, toll free.  The direct dial number is 512-462-4118.
  19.  *
  20.  * Advanced Micro Devices, Inc.
  21.  * 29K Support Products
  22.  * Mail Stop 573
  23.  * 5900 E. Ben White Blvd.
  24.  * Austin, TX 78741
  25.  * 800-292-9263
  26.  *****************************************************************************
  27.  *      Engineer: Srini Subramanian.
  28.  *****************************************************************************
  29.  * This module contains the functions to initialize, read, and write to the
  30.  * serial ports (COM1, COM2,...) on a PC.
  31.  *****************************************************************************
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <conio.h>
  36. #include <bios.h>
  37. #include <dos.h>  
  38. #include <string.h>
  39. #include "types.h"
  40. #include "memspcs.h"
  41. #include "messages.h"
  42. #include "mtip.h"
  43. #include "tdfunc.h"
  44.  
  45. /* Serial Port Defs */
  46.  /*
  47.  * Divisors for different baud rates to be used to initialize DLA
  48.  * register.
  49.  */
  50. #define    _DIV_COM_110    1047
  51. #define    _DIV_COM_150    768
  52. #define    _DIV_COM_300    384
  53. #define    _DIV_COM_600    192
  54. #define    _DIV_COM_1200    96
  55. #define    _DIV_COM_2400    48
  56. #define    _DIV_COM_4800    24
  57. #define    _DIV_COM_9600    12
  58. #define    _DIV_COM_19200    6
  59. #define    _DIV_COM_38400    3
  60. #define    _DIV_COM_115200    1
  61.  
  62. #define    LCR_DLAB    0x80
  63.  
  64. #define    DLA_LOW_OFFSET    0x0
  65.  
  66.  
  67. /*
  68. ** Definitions
  69. */
  70.  
  71. #define BUF_SIZE               2048
  72.  
  73. /*
  74. ** This data structure is used by the interrupt driven
  75. ** serial I/O.
  76. */
  77.  
  78. struct serial_io_t {
  79.    int error;                      /* Error code */
  80.    unsigned int    port;           /* Port number */
  81.    unsigned int    port_code;      /* Port code (for bios calls) */
  82.    unsigned int    int_number;     /* Port interrupt number      */
  83.    unsigned int    int_mask;       /* Port interrupt mask        */
  84.    unsigned int    baud;           /* Port baud rate             */
  85.    unsigned int    old_vector_ds;  /* Interrupt vector (old)     */
  86.    unsigned int    old_vector_dx;
  87.    volatile
  88.    unsigned char  *start;          /* Start of ring buffer       */
  89.    volatile
  90.    unsigned char  *end;            /* End of ring buffer         */
  91.    };
  92.  
  93. static unsigned char   serial_io_buffer[BUF_SIZE];
  94.  
  95. /* These definitions are from bios.h */
  96. #define CHAR_SIZE         _COM_CHR8
  97. #define STOP_BITS        _COM_STOP1
  98. #define PARITY        _COM_NOPARITY
  99.  
  100. /*
  101. ** Serial port definitions
  102. */
  103.  
  104. #define INTR_MASK    0x21    /* 8259 Interrupt Mask Port */
  105. #define INTR_EOI     0x20    /* 8259 EOI Port */
  106.  
  107. #define COM1         0x3f8   /* COM1 Port Base */
  108. #define COM1_CODE    0x00    /* COM1 Port Code */
  109. #define COM1_INT     0x0c    /* COM1 Interrupt Number */
  110. #define COM1_MASK    0x10    /* COM1 Interrupt Mask (IRQ4) */
  111.  
  112. #define COM2         0x2f8   /* COM2 Port Base */
  113. #define COM2_CODE    0x01    /* COM2 Port Code */
  114. #define COM2_INT     0x0b    /* COM2 Interrupt Number */
  115. #define COM2_MASK    0x08    /* COM2 Interrupt Mask (IRQ3) */
  116.  
  117. #define MSR_OFFSET   0x6     /* Modem Status Register offset */
  118. #define LSR_OFFSET   0x5     /* Line status Register offset */
  119. #define MCR_OFFSET   0x4     /* Modem Control Register offset */
  120. #define LCR_OFFSET   0x3     /* Line Control Register offest */
  121. #define    IID_OFFSET   0x2     /* Interrupt pending register */
  122. #define IER_OFFSET   0x1     /* Interrupt Enable Register offest */
  123.  
  124. /* Bits in Line Status Register (LSR) */
  125. #define AC1   0x80    /* Always clear */
  126. #define TSRE  0x40    /* Transmitter Shift Register Empty */
  127. #define THRE  0x20    /* Transmitter Holding Register Empty */
  128. #define BI    0x10    /* Break Interrupt */
  129. #define FE    0x08    /* Framing Error */
  130. #define PE    0x04    /* Parity Error */
  131. #define OE    0x02    /* Overrun Error */
  132. #define DR    0x01    /* Data Ready */
  133.  
  134. /* Bits in Modem Control Register */
  135. #define CD    0x80
  136. #define RI    0x40
  137. #define DSR   0x20
  138. #define CTS   0x10
  139. #define OUT2  0x08
  140. #define RTS   0x02
  141. #define DTR   0x01
  142.  
  143. #define MAX_BLOCK      1000    
  144.  
  145. /*  function prototypes */
  146.  
  147. void   endian_cvt PARAMS((union msg_t *, int));
  148. void   tip_convert32 PARAMS((BYTE *));
  149. INT32    init_parport (char *);
  150.  
  151. void   interrupt far serial_int PARAMS((void));
  152. void    (interrupt far *OldVector)();
  153. int    get_byte_serial PARAMS((void));
  154.  
  155. extern    int    BlockCount;
  156. extern    int    lpt_initialize;
  157. /* globals */
  158.  
  159. struct serial_io_t serial_io;
  160.  
  161. INT32  in_msg_length=0;
  162. INT32  in_byte_count=0;
  163.  
  164. /*
  165. ** Serial Port functions
  166. */
  167.  
  168. /*
  169. ** This function is used to initialize the communication
  170. ** channel.  First the serial_io data structure is
  171. ** initialized.  Then the new interrupt vector is installed.
  172. ** Finally, the port is initialized, with DTR, RTS and OUT2
  173. ** set.
  174. **
  175. */
  176.  
  177. INT32 write_memory_serial (ignore1, ignore2, ignore3, ignore4, ignore5, ignore6)
  178.     INT32 ignore1;
  179.     ADDR32 ignore2;
  180.     BYTE *ignore3;
  181.     INT32 ignore4; 
  182.     INT32 ignore5;
  183.     INT32 ignore6; 
  184.     return(-1); }
  185.  
  186. INT32 read_memory_serial (ignore1, ignore2, ignore3, ignore4, ignore5, ignore6)
  187.     INT32 ignore1;
  188.     ADDR32 ignore2;
  189.     BYTE *ignore3;
  190.     INT32 ignore4;
  191.     INT32 ignore5;
  192.     INT32 ignore6;
  193. { return(-1); }
  194.  
  195. INT32 fill_memory_serial() { return(-1); }
  196.  
  197. INT32
  198. init_comm_serial(ignore1, ignore2)
  199. INT32 ignore1;
  200. INT32 ignore2;
  201.    {
  202.    unsigned result;
  203.    unsigned config;
  204.    unsigned   int comm_status;
  205.  
  206.    /* Initialize serial_io */
  207.    serial_io.error = FALSE;
  208.  
  209.    /* Set up port number */
  210.    if ((strcmp(tip_config.comm_port, "com1") == 0) ||
  211.        (strcmp(tip_config.comm_port, "com1:") == 0)) {
  212.       serial_io.port = COM1;
  213.       serial_io.port_code = COM1_CODE;
  214.       serial_io.int_number = COM1_INT;
  215.       serial_io.int_mask = COM1_MASK;
  216.       }
  217.    else
  218.    if ((strcmp(tip_config.comm_port, "com2") == 0) ||
  219.        (strcmp(tip_config.comm_port, "com2:") == 0)) {
  220.       serial_io.port = COM2;
  221.       serial_io.port_code = COM2_CODE;
  222.       serial_io.int_number = COM2_INT;
  223.       serial_io.int_mask = COM2_MASK;
  224.       }
  225.    else
  226.       return((INT32) -1);
  227.  
  228.     /* Check status */
  229.     comm_status = inp(serial_io.port+LSR_OFFSET);
  230. #if 0
  231.     /* reset any communication errors */
  232.     outp(serial_io.port+LSR_OFFSET, 
  233.                (unsigned int) (comm_status & ~(FE|PE|OE)));
  234. #endif
  235.                    
  236.  
  237.    /* Get baud rate (Note: MS-DOS only goes to 9600) */
  238.    outp (serial_io.port+LCR_OFFSET, LCR_DLAB);
  239.  
  240.    if (strcmp(tip_config.baud_rate, "110") == 0)
  241.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_110);
  242.    else
  243.    if (strcmp(tip_config.baud_rate, "150") == 0)
  244.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_150);
  245.    else
  246.    if (strcmp(tip_config.baud_rate, "300") == 0)
  247.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_300);
  248.    else
  249.    if (strcmp(tip_config.baud_rate, "600") == 0)
  250.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_600);
  251.    else
  252.    if (strcmp(tip_config.baud_rate, "1200") == 0)
  253.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_1200);
  254.    else
  255.    if (strcmp(tip_config.baud_rate, "2400") == 0)
  256.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_2400);
  257.    else
  258.    if (strcmp(tip_config.baud_rate, "4800") == 0)
  259.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_4800);
  260.    else
  261.    if (strcmp(tip_config.baud_rate, "9600") == 0)
  262.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_9600);
  263.    else
  264.    if (strcmp(tip_config.baud_rate, "19200") == 0)
  265.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_19200);
  266.    else
  267.    if (strcmp(tip_config.baud_rate, "38400") == 0)
  268.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_38400);
  269.    else
  270.    if (strcmp(tip_config.baud_rate, "115200") == 0)
  271.       outpw (serial_io.port+DLA_LOW_OFFSET, _DIV_COM_115200);
  272.    else
  273.       return((INT32) -1);  /* EMBAUD); */
  274.  
  275.    /* Set LCR */
  276.    outp (serial_io.port+LCR_OFFSET, 
  277.         (unsigned int) (_COM_CHR8|_COM_STOP1|_COM_NOPARITY));
  278.  
  279.    /* Save old interrupt vector */
  280.    OldVector = _dos_getvect (serial_io.int_number);
  281.  
  282.    /* Initialize ring buffer */
  283.    serial_io.start = serial_io_buffer;
  284.    serial_io.end = serial_io_buffer;
  285.  
  286.    /* Install interrupt vector */
  287.    /* Note:  the interrupt handler should be in the same code */
  288.    /*        segment as this function.  We will use CS for    */
  289.    /*        the segment offset value.                        */
  290.  
  291.    _dos_setvect(serial_io.int_number, serial_int); /* new handler */
  292.  
  293.    /* Turn on DTR, RTS and OUT2 */
  294.    result = outp((serial_io.port+MCR_OFFSET), (DTR | RTS | OUT2));
  295.  
  296.    /* Enable interrupt on serial port controller */
  297.    result = outp((serial_io.port+IER_OFFSET), 0x01);
  298.  
  299.    /* Set interrupt mask on 8259 */
  300.    config = inp(INTR_MASK);  /* Get current 8259 mask */
  301.    result = outp(INTR_MASK, (config & ~serial_io.int_mask));
  302.  
  303.    /* Set global message indices */
  304.    in_msg_length = 0;
  305.    in_byte_count = 0;
  306.  
  307.    /* initialize parallel port */
  308.    if (lpt_initialize)
  309.       return (init_parport(tip_config.par_port));
  310.  
  311.    return((INT32) 0);
  312.    }  /* end init_comm_serial() */
  313.  
  314. /*
  315. ** This function is used to send bytes over the serial line.
  316. ** If the bytes are successfully sent, a zero is returned.  
  317. ** If the bytes are not sent, a -1 is returned.
  318. */
  319.  
  320. INT32
  321. send_bfr_serial(bfr_ptr, length, port_base, comm_err)
  322.    BYTE   *bfr_ptr;
  323.    INT32  length;
  324.    INT32  port_base;
  325.    INT32  *comm_err;
  326.    {
  327.    int        retries;
  328.    INT32      byte_count = 0;
  329.    unsigned   int comm_status;
  330.    unsigned   int result;
  331.  
  332.    /* Send message */
  333.    retries = 0;
  334.    do {
  335.  
  336.       /* check user interrupt */
  337.       SIGINT_POLL
  338.       /* Check if data ready */
  339.       comm_status = inp(serial_io.port+LSR_OFFSET);
  340.  
  341.       /* Check for communication errors */
  342.       if ((comm_status & (FE | PE | OE)) != 0) {
  343.       *comm_err = 1;
  344.       return (-1);
  345.       }
  346.  
  347.       /* If Transmitter Holding Register Empty (THRE) */
  348.       /* send out data */
  349.       if ((comm_status & THRE) != 0) {
  350.          result = outp(serial_io.port, bfr_ptr[byte_count]);
  351.          byte_count = byte_count + 1;
  352.          retries = 0;
  353.          } else {
  354.             retries = retries + 1;
  355.             if (retries >= 20000)   
  356.                return (-1);   /* EMNOSEND); */
  357.             }
  358.  
  359.       } while (byte_count < length );  
  360.  
  361.    return(0);
  362.    }  /* end send_bfr_serial() */
  363.  
  364. /*
  365. ** This function is used to receive bytes over a serial line.
  366. **
  367. ** If block equals NONBLOCK then the function returns as soon
  368. ** there are no bytes remaining in the UART.           
  369. ** If block equals BLOCK then the function waits until all
  370. ** bytes are gotten before returning.
  371. ** 
  372. ** If all bytes requested are gotten, 0 is returned, else -1.
  373. */
  374.  
  375. INT32
  376. recv_bfr_serial(bfr_ptr, length, block, port_base, comm_err)
  377.    BYTE   *bfr_ptr;
  378.    INT32  length;
  379.    INT32  block;
  380.    INT32  port_base;
  381.    INT32  *comm_err;
  382.    {
  383.    int        comm_status;
  384.    int        c;
  385.    int        result;  
  386.    int        bytes_free;
  387.  
  388.    int      block_count = 0;
  389.  
  390.    /* Loop as long as characters keep coming */
  391.    for (;;) {
  392.  
  393.       /* Check for communication errors */
  394.       comm_status = inp(serial_io.port+LSR_OFFSET);
  395.       if ((comm_status & (FE | PE | OE)) != 0)
  396.       {
  397.       *comm_err = 1;
  398.       return (-1);
  399.       }
  400.  
  401.       /* Check for buffer overflow */
  402.       if (serial_io.error == TRUE)
  403.        {
  404.       *comm_err = 1;
  405.       return (-1);
  406.        }
  407.  
  408.       /* Do flow control.  If the buffer is 9/10 full, */
  409.       /* deassert DTR and RTS.  If the buffer becomes */
  410.       /* 1/10 full, reassert DTR and RTS.              */
  411.       bytes_free = (int) (serial_io.start - serial_io.end);
  412.       if (bytes_free <= 0)
  413.          bytes_free = BUF_SIZE + bytes_free;
  414.  
  415.       comm_status = inp(serial_io.port+MCR_OFFSET);
  416.       if (bytes_free <= (BUF_SIZE/10))
  417.          result = outp((serial_io.port+MCR_OFFSET),
  418.                        (comm_status & ~DTR & ~RTS));
  419.  
  420.       if (bytes_free >= ((9*BUF_SIZE)/10))
  421.          result = outp((serial_io.port+MCR_OFFSET),
  422.                        (comm_status | DTR | RTS));
  423.  
  424.       /* Get character */
  425.       c = get_byte_serial();
  426.  
  427.       /* return if no char & not blocking */
  428.       if ((c == -1) && (block == NONBLOCK))
  429.          return (-1);  
  430.  
  431.       /* return if no char, blocking, and past block count */
  432.       if ((c == -1) && (block == BLOCK) && (block_count++ > BlockCount))
  433.          return (-1);  
  434.  
  435.       /* Save byte in bfr_ptr buffer */
  436.       if (c != -1) {
  437.             bfr_ptr[in_byte_count] = (BYTE) c;
  438.       block_count = 0;
  439.             in_byte_count = in_byte_count + 1;
  440.       }
  441.  
  442.       /* Message received ? */
  443.       if (in_byte_count == length) {
  444.          in_byte_count = 0;
  445.          return(0);
  446.          }
  447.       }      /* end for(;;) */
  448.    }          /* end recv_bfr_serial() */
  449.  
  450.  
  451. /*
  452. ** This function is used to reset the communication
  453. ** channel.  This is used when resyncing the host and
  454. ** target and when exiting the monitor.
  455. */
  456.  
  457. INT32
  458. reset_comm_serial(ignore1, ignore2)
  459. INT32    ignore1;
  460. INT32    ignore2;
  461.    {
  462.    unsigned   int status;
  463.  
  464. #define    CLEAR_STAT    (int) 1
  465.  
  466.   do {
  467.     /* Clear LSR */
  468.     inp(serial_io.port+LSR_OFFSET);
  469.     /* Clear RX reg */
  470.     inp (serial_io.port);
  471.     /* Clear MSR */
  472.     inp (serial_io.port+MSR_OFFSET);
  473.     /* interrupt pending ? */
  474.     status = inp(serial_io.port+IID_OFFSET);
  475.   } while (status != CLEAR_STAT);
  476.  
  477. #if 0
  478.     /* reset any communication errors */
  479.     outp(serial_io.port+LSR_OFFSET, 
  480.                (unsigned int) (comm_status & ~(FE|PE|OE)));
  481. #endif
  482.                    
  483.    /* Initialize serial_io */
  484.    serial_io.error = FALSE;
  485.  
  486.    /* Initialize ring buffer */
  487.    serial_io.start = serial_io_buffer;
  488.    serial_io.end = serial_io_buffer;
  489.  
  490.    /* Set global message indices */
  491.    in_msg_length = 0;
  492.    in_byte_count = 0;
  493.  
  494.    return((INT32) 0);
  495.    }  /* end reset_comm_serial() */
  496.  
  497.  
  498. INT32
  499. exit_comm_serial(ignore1, ignore2)
  500. INT32    ignore1;
  501. INT32    ignore2;
  502.    {
  503.    /* Initialize serial_io */
  504.    serial_io.error = FALSE;
  505.  
  506.    /* Initialize ring buffer */
  507.    serial_io.start = serial_io_buffer;
  508.    serial_io.end = serial_io_buffer;
  509.  
  510.    /* Set global message indices */
  511.    in_msg_length = 0;
  512.    in_byte_count = 0;
  513.  
  514.    /* install old handler back */
  515.    _dos_setvect(serial_io.int_number, OldVector);
  516.  
  517.    return((INT32) 0);
  518.    }  /* end reset_comm_serial() */
  519.  
  520. /*
  521. ** This function is usually used to "kick-start" the target.
  522. ** This is nesessary when targets are shared memory boards.
  523. ** With serial communications, this function does nothing.
  524. */
  525.  
  526. void
  527. go_serial(ignore1, ignore2)
  528. INT32 ignore1;
  529. INT32 ignore2;
  530.    {
  531.    return;
  532.    }  /* end go_serial() */
  533.  
  534.  
  535.  
  536. /*
  537. ** This function is used to get a byte from the the
  538. ** serial_io_buffer.  The data in this buffer is written
  539. ** by the interrupt handler.
  540. **
  541. ** If no data is available, a -1 is returned.  Otherwise
  542. ** a character is returned.
  543. */
  544.  
  545. int
  546. get_byte_serial()
  547.    {
  548.    int result=-1;
  549.  
  550.       /* Turn interrupts off while reading buffer */
  551.      _disable();
  552.  
  553.    /* No bytes available */
  554.    if (serial_io.start == serial_io.end)
  555.       result = -1;
  556.    else {
  557.  
  558.       /* Return character */
  559.       result = (int) *serial_io.start;
  560.       serial_io.start++;
  561.       /* Check for wrap around */
  562.       if (serial_io.start >= (serial_io_buffer+BUF_SIZE)) {
  563.          serial_io.start = serial_io_buffer;         
  564.       }
  565.  
  566.     }
  567.       /* Turn interrupts back on */
  568.       _enable();
  569.  
  570.    return (result);
  571.    }  /* end get_byte_serial() */
  572.  
  573.  
  574.  
  575. /*
  576. ** This function is the interrupt handler which buffers
  577. ** incoming characters.
  578. **
  579. ** Note:  The "interrupt" keyword is not well documented.
  580. **        It produces a procedure which returns with an
  581. **        "iret" instead of the usual "ret".
  582. */
  583.  
  584. void interrupt serial_int()
  585.    {
  586.    int c;
  587.  
  588.    /* Get character */
  589.    c = inp(serial_io.port);
  590.  
  591.    *serial_io.end = (unsigned char) c;
  592.    serial_io.end++;
  593.    /* Check for wrap around */
  594.    if (serial_io.end >= (serial_io_buffer+BUF_SIZE))
  595.       serial_io.end = serial_io_buffer;         
  596.  
  597.    /* Has the buffer overflowed? */
  598.    if (serial_io.start == serial_io.end)
  599.       serial_io.error = TRUE;
  600.  
  601.    /* Send EOI to 8259 */
  602.    (void) outp(INTR_EOI, 0x20);
  603.  
  604.    }  /* end serial_int() */
  605.  
  606.  
  607.