diff --git a/src/arch/i386/interface/syslinux/comboot_call.c b/src/arch/i386/interface/syslinux/comboot_call.c index 1854501d..4d033409 100644 --- a/src/arch/i386/interface/syslinux/comboot_call.c +++ b/src/arch/i386/interface/syslinux/comboot_call.c @@ -41,8 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include "config/console.h" -#include "config/serial.h" /** The "SYSLINUX" version string */ static char __bss16_array ( syslinux_version, [32] ); @@ -261,8 +259,10 @@ static __asmcall void int21 ( struct i386_all_regs *ix86 ) { break; case 0x04: /* Write Character to Serial Port */ - serial_putc ( ix86->regs.dl ); - ix86->flags &= ~CF; + if ( serial_console.base ) { + uart_transmit ( &serial_console, ix86->regs.dl ); + ix86->flags &= ~CF; + } break; case 0x09: /* Write DOS String to Console */ @@ -455,15 +455,12 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { break; case 0x000B: /* Get Serial Console Configuration */ -#if defined(CONSOLE_SERIAL) && !defined(COMPRESERVE) - ix86->regs.dx = COMCONSOLE; - ix86->regs.cx = 115200 / COMSPEED; - ix86->regs.bx = 0; -#else - ix86->regs.dx = 0; -#endif - - ix86->flags &= ~CF; + if ( serial_console.base ) { + ix86->regs.dx = ( ( intptr_t ) serial_console.base ); + ix86->regs.cx = serial_console.divisor; + ix86->regs.bx = 0; + ix86->flags &= ~CF; + } break; case 0x000E: /* Get configuration file name */ diff --git a/src/config/config.c b/src/config/config.c index 9cc23949..120a1d4f 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -55,7 +55,7 @@ PROVIDE_REQUIRING_SYMBOL(); REQUIRE_OBJECT ( bios_console ); #endif #ifdef CONSOLE_SERIAL -REQUIRE_OBJECT ( serial_console ); +REQUIRE_OBJECT ( serial ); #endif #ifdef CONSOLE_DIRECT_VGA REQUIRE_OBJECT ( video_subr ); diff --git a/src/config/serial.h b/src/config/serial.h index 08368efd..27040dc5 100644 --- a/src/config/serial.h +++ b/src/config/serial.h @@ -13,11 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#define COM1 0x3f8 -#define COM2 0x2f8 -#define COM3 0x3e8 -#define COM4 0x2e8 - #define COMCONSOLE COM1 /* I/O port address */ /* Keep settings from a previous user of the serial port (e.g. lilo or diff --git a/src/core/serial.c b/src/core/serial.c index 7e4460ab..4ce02551 100644 --- a/src/core/serial.c +++ b/src/core/serial.c @@ -1,259 +1,184 @@ /* - * 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. + * Copyright (C) 2014 Michael Brown . * - * 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(). + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. */ -FILE_LICENCE ( GPL2_OR_LATER ); +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include "stddef.h" +/** @file + * + * Serial console + * + */ + +#include #include -#include -#include +#include +#include #include -#include "config/serial.h" +#include +#include -/* Set default values if none specified */ - -#ifndef COMCONSOLE -#define COMCONSOLE 0x3f8 +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) ) +#undef CONSOLE_SERIAL +#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #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 - -#if defined(UART_MEM) -#define uart_readb(addr) readb((addr)) -#define uart_writeb(val,addr) writeb((val),(addr)) +/* UART port number */ +#ifdef COMCONSOLE +#define CONSOLE_PORT COMCONSOLE #else -#define uart_readb(addr) inb((addr)) -#define uart_writeb(val,addr) outb((val),(addr)) +#define CONSOLE_PORT 0 #endif -/* Boolean for the state of serial driver initialization */ -int serial_initialized = 0; - -/* - * void serial_putc(int ch); - * Write character `ch' to port UART_BASE. - */ -void serial_putc ( int ch ) { - int i; - int status; - i = 1000; /* timeout */ - while(--i > 0) { - status = uart_readb(UART_BASE + UART_LSR); - if (status & UART_LSR_THRE) { - /* TX buffer emtpy */ - uart_writeb(ch, UART_BASE + UART_TBR); - break; - } - mdelay(2); - } -} - -/* - * 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_ischar(void); - * If there is a character in the input buffer of port UART_BASE, - * return nonzero; otherwise return 0. - */ -int serial_ischar ( void ) { - int status; - status = uart_readb(UART_BASE + UART_LSR); /* line status reg; */ - return status & 1; /* rx char available */ -} - -/* - * int serial_init(void); - * Initialize port UART_BASE to speed COMSPEED, line settings 8N1. - */ -static void serial_init ( void ) { - int status; - int divisor, lcs; - - DBG ( "Serial port %#x initialising\n", UART_BASE ); - - divisor = COMBRD; - lcs = UART_LCS; - - +/* UART baud rate */ #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); +#define CONSOLE_BAUD 0 +#else +#define CONSOLE_BAUD COMSPEED #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) { - DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); - goto out; - } - uart_writeb(0x55, UART_BASE + UART_DLL); - if (uart_readb(UART_BASE + UART_DLL) != 0x55) { - DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); - goto out; - } - uart_writeb(divisor & 0xff, UART_BASE + UART_DLL); - if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) { - DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); - goto out; - } - uart_writeb(0xaa, UART_BASE + UART_DLM); - if (uart_readb(UART_BASE + UART_DLM) != 0xaa) { - DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); - goto out; - } - uart_writeb(0x55, UART_BASE + UART_DLM); - if (uart_readb(UART_BASE + UART_DLM) != 0x55) { - DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); - goto out; - } - uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM); - if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) { - DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); - goto out; - } - uart_writeb(lcs, UART_BASE + UART_LCR); - - /* disable interrupts */ - uart_writeb(0x0, UART_BASE + UART_IER); +/* UART line control register value */ +#ifdef COMPRESERVE +#define CONSOLE_LCR 0 +#else +#define CONSOLE_LCR UART_LCR_WPS ( COMDATA, COMPARITY, COMSTOP ) +#endif - /* enable fifos */ - uart_writeb(0x01, UART_BASE + UART_FCR); +/** Serial console UART */ +struct uart serial_console; - /* 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); - - /* Note that serial support has been initialized */ - serial_initialized = 1; - out: - return; -} - -/* - * void serial_fini(void); - * Cleanup our use of the serial port, in particular flush the - * output buffer so we don't accidentially lose characters. +/** + * Print a character to serial console + * + * @v character Character to be printed */ -static void serial_fini ( int flags __unused ) { - int i, status; - /* Flush the output buffer to avoid dropping characters, - * if we are reinitializing the serial port. - */ - i = 10000; /* timeout */ - do { - status = uart_readb(UART_BASE + UART_LSR); - } while((--i > 0) && !(status & UART_LSR_TEMPT)); - /* Don't mark it as disabled; it's still usable */ +static void serial_putchar ( int character ) { + + /* Do nothing if we have no UART */ + if ( ! serial_console.base ) + return; + + /* Transmit character */ + uart_transmit ( &serial_console, character ); } /** - * Serial driver initialisation function + * Get character from serial console * - * Initialise serial port early on so that it is available to capture - * early debug messages. + * @ret character Character read from console */ -struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = { +static int serial_getchar ( void ) { + uint8_t data; + + /* Do nothing if we have no UART */ + if ( ! serial_console.base ) + return 0; + + /* Wait for data to be ready */ + while ( ! uart_data_ready ( &serial_console ) ) {} + + /* Receive data */ + data = uart_receive ( &serial_console ); + + /* Strip any high bit and convert DEL to backspace */ + data &= 0x7f; + if ( data == 0x7f ) + data = 0x08; + + return data; +} + +/** + * Check for character ready to read from serial console + * + * @ret True Character available to read + * @ret False No character available to read + */ +static int serial_iskey ( void ) { + + /* Do nothing if we have no UART */ + if ( ! serial_console.base ) + return 0; + + /* Check UART */ + return uart_data_ready ( &serial_console ); +} + +/** Serial console */ +struct console_driver serial_console_driver __console_driver = { + .putchar = serial_putchar, + .getchar = serial_getchar, + .iskey = serial_iskey, + .usage = CONSOLE_SERIAL, +}; + +/** Initialise serial console */ +static void serial_init ( void ) { + int rc; + + /* Do nothing if we have no default port */ + if ( ! CONSOLE_PORT ) + return; + + /* Select UART */ + if ( ( rc = uart_select ( &serial_console, CONSOLE_PORT ) ) != 0 ) { + DBG ( "Could not select UART %d: %s\n", + CONSOLE_PORT, strerror ( rc ) ); + return; + } + + /* Initialise UART */ + if ( ( rc = uart_init ( &serial_console, CONSOLE_BAUD, + CONSOLE_LCR ) ) != 0 ) { + DBG ( "Could not initialise UART %d baud %d LCR %#02x: %s\n", + CONSOLE_PORT, CONSOLE_BAUD, CONSOLE_LCR, strerror ( rc )); + return; + } +} + +/** + * Shut down serial console + * + * @v flags Shutdown flags + */ +static void serial_shutdown ( int flags __unused ) { + + /* Do nothing if we have no UART */ + if ( ! serial_console.base ) + return; + + /* Flush any pending output */ + uart_flush ( &serial_console ); + + /* Leave console enabled; it's still usable */ +} + +/** Serial console initialisation function */ +struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = { .initialise = serial_init, }; -/** Serial driver startup function */ +/** Serial console startup function */ struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = { - .shutdown = serial_fini, + .shutdown = serial_shutdown, }; diff --git a/src/core/serial_console.c b/src/core/serial_console.c deleted file mode 100644 index de9b84ca..00000000 --- a/src/core/serial_console.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include - -/** @file - * - * Serial console - * - */ - -/* Set default console usage if applicable */ -#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) ) -#undef CONSOLE_SERIAL -#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) -#endif - -struct console_driver serial_console __console_driver; - -static void serial_console_init ( void ) { - /* - * Check if serial driver initialization is done. - * If so, it's time to enable the serial console. - */ - if ( serial_initialized ) - serial_console.disabled = 0; -} - -struct console_driver serial_console __console_driver = { - .putchar = serial_putc, - .getchar = serial_getc, - .iskey = serial_ischar, - .disabled = CONSOLE_DISABLED, - .usage = CONSOLE_SERIAL, -}; - -/** - * Serial console initialisation function - */ -struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = { - .initialise = serial_console_init, -}; diff --git a/src/include/ipxe/init.h b/src/include/ipxe/init.h index e051dc6c..025cfaf3 100644 --- a/src/include/ipxe/init.h +++ b/src/include/ipxe/init.h @@ -26,10 +26,9 @@ struct init_fn { */ #define INIT_EARLY 01 /**< Early initialisation */ -#define INIT_SERIAL 02 /**< Serial driver initialisation */ -#define INIT_CONSOLE 03 /**< Console initialisation */ -#define INIT_NORMAL 04 /**< Normal initialisation */ -#define INIT_LATE 05 /**< Late initialisation */ +#define INIT_CONSOLE 02 /**< Console initialisation */ +#define INIT_NORMAL 03 /**< Normal initialisation */ +#define INIT_LATE 04 /**< Late initialisation */ /** @} */ diff --git a/src/include/ipxe/serial.h b/src/include/ipxe/serial.h index 86d05370..83be59c3 100644 --- a/src/include/ipxe/serial.h +++ b/src/include/ipxe/serial.h @@ -3,15 +3,14 @@ /** @file * - * Serial driver functions + * Serial console * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -extern void serial_putc ( int ch ); -extern int serial_getc ( void ); -extern int serial_ischar ( void ); -extern int serial_initialized; +#include + +extern struct uart serial_console; #endif /* _IPXE_SERIAL_H */