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