serial.c

Go to the documentation of this file.
00001 /*
00002  * The serial port interface routines implement a simple polled i/o
00003  * interface to a standard serial port.  Due to the space restrictions
00004  * for the boot blocks, no BIOS support is used (since BIOS requires
00005  * expensive real/protected mode switches), instead the rudimentary
00006  * BIOS support is duplicated here.
00007  *
00008  * The base address and speed for the i/o port are passed from the
00009  * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
00010  * line control parameters are currently hard-coded to 8 bits, no
00011  * parity, 1 stop bit (8N1).  This can be changed in init_serial().
00012  */
00013 
00014 FILE_LICENCE ( GPL2_OR_LATER );
00015 
00016 #include "stddef.h"
00017 #include <gpxe/init.h>
00018 #include <gpxe/io.h>
00019 #include <unistd.h>
00020 #include <gpxe/serial.h>
00021 #include "config/serial.h"
00022 
00023 /* Set default values if none specified */
00024 
00025 #ifndef COMCONSOLE
00026 #define COMCONSOLE      0x3f8
00027 #endif
00028 
00029 #ifndef COMSPEED
00030 #define COMSPEED        9600
00031 #endif
00032 
00033 #ifndef COMDATA
00034 #define COMDATA         8
00035 #endif
00036 
00037 #ifndef COMPARITY
00038 #define COMPARITY       0
00039 #endif
00040 
00041 #ifndef COMSTOP
00042 #define COMSTOP         1
00043 #endif
00044 
00045 #undef UART_BASE
00046 #define UART_BASE ( COMCONSOLE )
00047 
00048 #undef UART_BAUD
00049 #define UART_BAUD ( COMSPEED )
00050 
00051 #if ((115200%UART_BAUD) != 0)
00052 #error Bad ttys0 baud rate
00053 #endif
00054 
00055 #define COMBRD (115200/UART_BAUD)
00056 
00057 /* Line Control Settings */
00058 #define UART_LCS ( ( ( (COMDATA) - 5 )  << 0 ) | \
00059                    ( ( (COMPARITY) )    << 3 ) | \
00060                    ( ( (COMSTOP) - 1 )  << 2 ) )
00061 
00062 /* Data */
00063 #define UART_RBR 0x00
00064 #define UART_TBR 0x00
00065 
00066 /* Control */
00067 #define UART_IER 0x01
00068 #define UART_IIR 0x02
00069 #define UART_FCR 0x02
00070 #define UART_LCR 0x03
00071 #define UART_MCR 0x04
00072 #define UART_DLL 0x00
00073 #define UART_DLM 0x01
00074 
00075 /* Status */
00076 #define UART_LSR 0x05
00077 #define  UART_LSR_TEMPT 0x40    /* Transmitter empty */
00078 #define  UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
00079 #define  UART_LSR_BI    0x10    /* Break interrupt indicator */
00080 #define  UART_LSR_FE    0x08    /* Frame error indicator */
00081 #define  UART_LSR_PE    0x04    /* Parity error indicator */
00082 #define  UART_LSR_OE    0x02    /* Overrun error indicator */
00083 #define  UART_LSR_DR    0x01    /* Receiver data ready */
00084 
00085 #define UART_MSR 0x06
00086 #define UART_SCR 0x07
00087 
00088 #if defined(UART_MEM)
00089 #define uart_readb(addr) readb((addr))
00090 #define uart_writeb(val,addr) writeb((val),(addr))
00091 #else
00092 #define uart_readb(addr) inb((addr))
00093 #define uart_writeb(val,addr) outb((val),(addr))
00094 #endif
00095 
00096 /*
00097  * void serial_putc(int ch);
00098  *      Write character `ch' to port UART_BASE.
00099  */
00100 void serial_putc ( int ch ) {
00101         int i;
00102         int status;
00103         i = 1000; /* timeout */
00104         while(--i > 0) {
00105                 status = uart_readb(UART_BASE + UART_LSR);
00106                 if (status & UART_LSR_THRE) { 
00107                         /* TX buffer emtpy */
00108                         uart_writeb(ch, UART_BASE + UART_TBR);
00109                         break;
00110                 }
00111                 mdelay(2);
00112         }
00113 }
00114 
00115 /*
00116  * int serial_getc(void);
00117  *      Read a character from port UART_BASE.
00118  */
00119 int serial_getc ( void ) {
00120         int status;
00121         int ch;
00122         do {
00123                 status = uart_readb(UART_BASE + UART_LSR);
00124         } while((status & 1) == 0);
00125         ch = uart_readb(UART_BASE + UART_RBR);  /* fetch (first) character */
00126         ch &= 0x7f;                             /* remove any parity bits we get */
00127         if (ch == 0x7f) {                       /* Make DEL... look like BS */
00128                 ch = 0x08;
00129         }
00130         return ch;
00131 }
00132 
00133 /*
00134  * int serial_ischar(void);
00135  *       If there is a character in the input buffer of port UART_BASE,
00136  *       return nonzero; otherwise return 0.
00137  */
00138 int serial_ischar ( void ) {
00139         int status;
00140         status = uart_readb(UART_BASE + UART_LSR);      /* line status reg; */
00141         return status & 1;              /* rx char available */
00142 }
00143 
00144 /*
00145  * int serial_init(void);
00146  *      Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
00147  */
00148 static void serial_init ( void ) {
00149         int status;
00150         int divisor, lcs;
00151 
00152         DBG ( "Serial port %#x initialising\n", UART_BASE );
00153 
00154         divisor = COMBRD;
00155         lcs = UART_LCS;
00156 
00157 
00158 #ifdef COMPRESERVE
00159         lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
00160         uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
00161         divisor = (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + UART_DLL);
00162         uart_writeb(lcs, UART_BASE + UART_LCR);
00163 #endif
00164 
00165         /* Set Baud Rate Divisor to COMSPEED, and test to see if the
00166          * serial port appears to be present.
00167          */
00168         uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
00169         uart_writeb(0xaa, UART_BASE + UART_DLL);
00170         if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
00171                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
00172                 goto out;
00173         }
00174         uart_writeb(0x55, UART_BASE + UART_DLL);
00175         if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
00176                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
00177                 goto out;
00178         }
00179         uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
00180         if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
00181                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
00182                 goto out;
00183         }
00184         uart_writeb(0xaa, UART_BASE + UART_DLM);
00185         if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
00186                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
00187                 goto out;
00188         }
00189         uart_writeb(0x55, UART_BASE + UART_DLM);
00190         if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
00191                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
00192                 goto out;
00193         }
00194         uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
00195         if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
00196                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
00197                 goto out;
00198         }
00199         uart_writeb(lcs, UART_BASE + UART_LCR);
00200         
00201         /* disable interrupts */
00202         uart_writeb(0x0, UART_BASE + UART_IER);
00203 
00204         /* disable fifo's */
00205         uart_writeb(0x00, UART_BASE + UART_FCR);
00206 
00207         /* Set clear to send, so flow control works... */
00208         uart_writeb((1<<1), UART_BASE + UART_MCR);
00209 
00210 
00211         /* Flush the input buffer. */
00212         do {
00213                 /* rx buffer reg
00214                  * throw away (unconditionally the first time)
00215                  */
00216                 (void) uart_readb(UART_BASE + UART_RBR);
00217                 /* line status reg */
00218                 status = uart_readb(UART_BASE + UART_LSR);
00219         } while(status & UART_LSR_DR);
00220  out:
00221         return;
00222 }
00223 
00224 /*
00225  * void serial_fini(void);
00226  *      Cleanup our use of the serial port, in particular flush the
00227  *      output buffer so we don't accidentially lose characters.
00228  */
00229 static void serial_fini ( int flags __unused ) {
00230         int i, status;
00231         /* Flush the output buffer to avoid dropping characters,
00232          * if we are reinitializing the serial port.
00233          */
00234         i = 10000; /* timeout */
00235         do {
00236                 status = uart_readb(UART_BASE + UART_LSR);
00237         } while((--i > 0) && !(status & UART_LSR_TEMPT));
00238         /* Don't mark it as disabled; it's still usable */
00239 }
00240 
00241 /**
00242  * Serial driver initialisation function
00243  *
00244  * Initialise serial port early on so that it is available to capture
00245  * early debug messages.
00246  */
00247 struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
00248         .initialise = serial_init,
00249 };
00250 
00251 /** Serial driver startup function */
00252 struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
00253         .shutdown = serial_fini,
00254 };

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1