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