Home | History | Annotate | Download | only in gdbstub
      1 /*
      2  * The serial port interface routines implement a simple polled i/o
      3  * interface to a standard serial port.  Due to the space restrictions
      4  * for the boot blocks, no BIOS support is used (since BIOS requires
      5  * expensive real/protected mode switches), instead the rudimentary
      6  * BIOS support is duplicated here.
      7  *
      8  * The base address and speed for the i/o port are passed from the
      9  * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
     10  * line control parameters are currently hard-coded to 8 bits, no
     11  * parity, 1 stop bit (8N1).  This can be changed in init_serial().
     12  */
     13 
     14 #include <stddef.h>
     15 #include <sys/io.h>
     16 #include "serial.h"
     17 
     18 /* Set default values if none specified */
     19 
     20 #ifndef COMCONSOLE
     21 #define COMCONSOLE	0x3f8
     22 #endif
     23 
     24 #ifndef COMSPEED
     25 #define COMSPEED	9600
     26 #endif
     27 
     28 #ifndef COMDATA
     29 #define COMDATA		8
     30 #endif
     31 
     32 #ifndef COMPARITY
     33 #define COMPARITY	0
     34 #endif
     35 
     36 #ifndef COMSTOP
     37 #define COMSTOP		1
     38 #endif
     39 
     40 #undef UART_BASE
     41 #define UART_BASE ( COMCONSOLE )
     42 
     43 #undef UART_BAUD
     44 #define UART_BAUD ( COMSPEED )
     45 
     46 #if ((115200%UART_BAUD) != 0)
     47 #error Bad ttys0 baud rate
     48 #endif
     49 
     50 #define COMBRD (115200/UART_BAUD)
     51 
     52 /* Line Control Settings */
     53 #define UART_LCS ( ( ( (COMDATA) - 5 )	<< 0 ) | \
     54 		   ( ( (COMPARITY) )	<< 3 ) | \
     55 		   ( ( (COMSTOP) - 1 )	<< 2 ) )
     56 
     57 /* Data */
     58 #define UART_RBR 0x00
     59 #define UART_TBR 0x00
     60 
     61 /* Control */
     62 #define UART_IER 0x01
     63 #define UART_IIR 0x02
     64 #define UART_FCR 0x02
     65 #define UART_LCR 0x03
     66 #define UART_MCR 0x04
     67 #define UART_DLL 0x00
     68 #define UART_DLM 0x01
     69 
     70 /* Status */
     71 #define UART_LSR 0x05
     72 #define  UART_LSR_TEMPT 0x40	/* Transmitter empty */
     73 #define  UART_LSR_THRE  0x20	/* Transmit-hold-register empty */
     74 #define  UART_LSR_BI	0x10	/* Break interrupt indicator */
     75 #define  UART_LSR_FE	0x08	/* Frame error indicator */
     76 #define  UART_LSR_PE	0x04	/* Parity error indicator */
     77 #define  UART_LSR_OE	0x02	/* Overrun error indicator */
     78 #define  UART_LSR_DR	0x01	/* Receiver data ready */
     79 
     80 #define UART_MSR 0x06
     81 #define UART_SCR 0x07
     82 
     83 #define uart_readb(addr) inb(addr)
     84 #define uart_writeb(val,addr) outb((val),(addr))
     85 
     86 /*
     87  * void serial_putc(int ch);
     88  *	Write character `ch' to port UART_BASE.
     89  */
     90 void serial_putc(int ch)
     91 {
     92     int status;
     93     for (;;) {
     94 	status = uart_readb(UART_BASE + UART_LSR);
     95 	if (status & UART_LSR_THRE) {
     96 	    /* TX buffer emtpy */
     97 	    uart_writeb(ch, UART_BASE + UART_TBR);
     98 	    break;
     99 	}
    100     }
    101 }
    102 
    103 /*
    104  * int serial_getc(void);
    105  *	Read a character from port UART_BASE.
    106  */
    107 int serial_getc(void)
    108 {
    109     int status;
    110     int ch;
    111     do {
    112 	status = uart_readb(UART_BASE + UART_LSR);
    113     } while ((status & 1) == 0);
    114     ch = uart_readb(UART_BASE + UART_RBR);	/* fetch (first) character */
    115     ch &= 0x7f;			/* remove any parity bits we get */
    116     if (ch == 0x7f) {		/* Make DEL... look like BS */
    117 	ch = 0x08;
    118     }
    119     return ch;
    120 }
    121 
    122 /*
    123  * int serial_init(void);
    124  *	Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
    125  */
    126 void serial_init(void)
    127 {
    128     int status;
    129     int divisor, lcs;
    130 
    131     divisor = COMBRD;
    132     lcs = UART_LCS;
    133 
    134 #ifdef COMPRESERVE
    135     lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
    136     uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
    137     divisor =
    138 	(uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE +
    139 							     UART_DLL);
    140     uart_writeb(lcs, UART_BASE + UART_LCR);
    141 #endif
    142 
    143     /* Set Baud Rate Divisor to COMSPEED, and test to see if the
    144      * serial port appears to be present.
    145      */
    146     uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
    147     uart_writeb(0xaa, UART_BASE + UART_DLL);
    148     if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
    149 	goto out;
    150     }
    151     uart_writeb(0x55, UART_BASE + UART_DLL);
    152     if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
    153 	goto out;
    154     }
    155     uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
    156     if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
    157 	goto out;
    158     }
    159     uart_writeb(0xaa, UART_BASE + UART_DLM);
    160     if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
    161 	goto out;
    162     }
    163     uart_writeb(0x55, UART_BASE + UART_DLM);
    164     if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
    165 	goto out;
    166     }
    167     uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
    168     if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
    169 	goto out;
    170     }
    171     uart_writeb(lcs, UART_BASE + UART_LCR);
    172 
    173     /* disable interrupts */
    174     uart_writeb(0x0, UART_BASE + UART_IER);
    175 
    176     /* disable fifo's */
    177     uart_writeb(0x00, UART_BASE + UART_FCR);
    178 
    179     /* Set clear to send, so flow control works... */
    180     uart_writeb((1 << 1), UART_BASE + UART_MCR);
    181 
    182     /* Flush the input buffer. */
    183     do {
    184 	/* rx buffer reg
    185 	 * throw away (unconditionally the first time)
    186 	 */
    187 	(void)uart_readb(UART_BASE + UART_RBR);
    188 	/* line status reg */
    189 	status = uart_readb(UART_BASE + UART_LSR);
    190     } while (status & UART_LSR_DR);
    191 out:
    192     return;
    193 }
    194