#ifdef CONSOLE_SERIAL
#include "etherboot.h"
#include "linux-asm-io.h"
/*
* 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 serial_init().
*/
static int found = 0;
#define UART_BASE COMCONSOLE
#ifndef CONSPEED
#define CONSPEED 115200
#endif
#if ((115200%CONSPEED) != 0)
#error Bad ttys0 baud rate
#endif
#define COMBRD (115200/CONSPEED)
/* Line Control Settings */
#ifndef COMPARM
/* Set 8bit, 1 stop bit, no parity */
#define COMPARM 0x03
#endif
#define UART_LCS COMPARM
/* 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_MSR 0x06
#define UART_SCR 0x07
/*
* void serial_putc(int ch);
* Write character `ch' to port COMCONSOLE.
*/
void serial_putc(int ch)
{
int i;
int status;
if (!found) {
/* no serial interface */
return;
}
i = 10000; /* timeout */
while(--i > 0) {
status = inb(COMCONSOLE + UART_LSR);
if (status & (1 << 5)) {
/* TX buffer emtpy */
outb(ch, COMCONSOLE + UART_TBR);
break;
}
}
}
/*
* int serial_getc(void);
* Read a character from port COMCONSOLE.
*/
int serial_getc(void)
{
int status;
int ch;
do {
status = inb(COMCONSOLE + UART_LSR);
} while((status & 1) == 0);
ch = inb(COMCONSOLE + 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_ischar(void);
* If there is a character in the input buffer of port COMCONSOLE,
* return nonzero; otherwise return 0.
*/
int serial_ischar(void)
{
int status;
if (!found)
return 0;
status = inb(COMCONSOLE + UART_LSR); /* line status reg; */
return status & 1; /* rx char available */
}
#if !defined(COMBRD) && defined(CONSPEED)
/* Recent GNU as versions with ELF output format define / as a comment
* character, because some misguided spec says so. Do it the easy way and
* just check for the usual values. This is only compiled by gcc, so
* #elif can be used (bcc doesn't understand it). */
#if (CONSPEED == 115200)
#define COMBRD 1
#elif (CONSPEED == 57600)
#define COMBRD 2
#elif (CONSPEED == 38400)
#define COMBRD 3
#elif (CONSPEED == 19200)
#define COMBRD 6
#elif (CONSPEED == 9600)
#define COMBRD 12
#elif (CONSPEED == 2400)
#define COMBRD 48
#elif (CONSPEED == 1200)
#define COMBRD 96
#elif (CONSPEED == 300)
#define COMBRD 384
#else
#error Add your unusual baud rate to the table in serial.S!
#define COMBRD (115200 / CONSPEED)
#endif
#endif
/*
* int serial_init(void);
* Initialize port COMCONSOLE to speed CONSPEED, line settings 8N1.
*/
int serial_init(void)
{
int initialized = 0;
int status;
int divisor, lcs;
divisor = COMBRD;
lcs = UART_LCS;
#ifdef COMPRESERVE
lcs = inb(COMCONSOLE + UART_LCR) & 0x7f;
outb(0x80 | lcs, COMCONSOLE + UART_LCR);
divisor = (inb(COMCONSOLE + UART_DLM) << 8) | inb(COMCONSOLE + UART_DLL);
outb(lcs, COMCONSOLE + UART_LCR);
#endif
/* Set Baud Rate Divisor to CONSPEED, and test to see if the
* serial port appears to be present.
*/
outb(0x80 | lcs, COMCONSOLE + UART_LCR);
outb(0xaa, COMCONSOLE + UART_DLL);
if (inb(COMCONSOLE + UART_DLL) != 0xaa)
goto out;
outb(0x55, COMCONSOLE + UART_DLL);
if (inb(COMCONSOLE + UART_DLL) != 0x55)
goto out;
outb(divisor & 0xff, COMCONSOLE + UART_DLL);
if (inb(COMCONSOLE + UART_DLL) != (divisor & 0xff))
goto out;
outb(0xaa, COMCONSOLE + UART_DLM);
if (inb(COMCONSOLE + UART_DLM) != 0xaa)
goto out;
outb(0x55, COMCONSOLE + UART_DLM);
if (inb(COMCONSOLE + UART_DLM) != 0x55)
goto out;
outb((divisor >> 8) & 0xff, COMCONSOLE + UART_DLM);
if (inb(COMCONSOLE + UART_DLM) != ((divisor >> 8) & 0xff))
goto out;
outb(lcs, COMCONSOLE + UART_LCR);
/* disable interrupts */
outb(0x0, COMCONSOLE + UART_IER);
/* disable fifo's */
outb(0x00, COMCONSOLE + UART_FCR);
/* Set clear to send, so flow control works... */
outb((1<<1), COMCONSOLE + UART_MCR);
/* Flush the input buffer. */
do {
/* rx buffer reg
* throw away (unconditionally the first time)
*/
inb(COMCONSOLE + UART_RBR);
/* line status reg */
status = inb(COMCONSOLE + UART_LSR);
} while(status & 1);
initialized = 1;
out:
found = initialized;
return initialized;
}
/*
* void serial_fini(void);
* Cleanup our use of the serial port, in particular flush the
* output buffer so we don't accidentially loose characters.
*/
void serial_fini(void)
{
int i, status;
if (!found) {
/* no serial interface */
return;
}
/* Flush the output buffer to avoid dropping characters,
* if we are reinitializing the serial port.
*/
i = 10000; /* timeout */
do {
status = inb(COMCONSOLE + UART_LSR);
} while((--i > 0) || (!(status & (1 << 6))));
found = 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1