| /* | |
| * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * 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_OR_UBDL ); | |
| /** @file | |
| * | |
| * Serial console | |
| * | |
| */ | |
| #include <stddef.h> | |
| #include <string.h> | |
| #include <ipxe/init.h> | |
| #include <ipxe/uart.h> | |
| #include <ipxe/console.h> | |
| #include <ipxe/serial.h> | |
| #include <ipxe/ns16550.h> | |
| #include <config/console.h> | |
| #include <config/serial.h> | |
| /* 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 | |
| #ifdef SERIAL_FIXED | |
| #define SERIAL_PREFIX_fixed | |
| #else | |
| #define SERIAL_PREFIX_fixed __fixed_ | |
| #endif | |
| /* Serial console UART */ | |
| #ifndef COMCONSOLE | |
| #define COMCONSOLE NULL | |
| #endif | |
| /* Serial console baud rate */ | |
| #ifndef COMSPEED | |
| #define COMSPEED 0 | |
| #endif | |
| /** Active serial console UART | |
| * | |
| * Explicitly initialised to @c NULL since this variable may be | |
| * accessed before .bss has been zeroed. | |
| */ | |
| struct uart *serial_console = NULL; | |
| /** | |
| * Get fixed serial console UART | |
| * | |
| * @ret uart Serial console UART, or NULL | |
| */ | |
| struct uart * fixed_serial_console ( void ) { | |
| struct uart *uart = COMCONSOLE; | |
| unsigned int baud = COMSPEED; | |
| /* Set default baud rate, if applicable */ | |
| if ( uart && baud ) | |
| uart->baud = baud; | |
| return uart; | |
| } | |
| /** | |
| * Print a character to serial console | |
| * | |
| * @v character Character to be printed | |
| */ | |
| static void serial_putchar ( int character ) { | |
| /* Do nothing if we have no UART */ | |
| if ( ! serial_console ) | |
| return; | |
| /* Transmit character */ | |
| uart_transmit ( serial_console, character ); | |
| } | |
| /** | |
| * Get character from serial console | |
| * | |
| * @ret character Character read from console | |
| */ | |
| static int serial_getchar ( void ) { | |
| uint8_t data; | |
| /* Do nothing if we have no UART */ | |
| if ( ! serial_console ) | |
| 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 ) | |
| 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 ) { | |
| struct uart *uart; | |
| int rc; | |
| /* Get default serial console, if any */ | |
| uart = default_serial_console(); | |
| if ( ! uart ) | |
| return; | |
| /* Initialise UART */ | |
| if ( ( rc = uart_init ( uart ) ) != 0 ) { | |
| DBGC ( uart, "SERIAL could not initialise %s: %s\n", | |
| uart->name, strerror ( rc ) ); | |
| return; | |
| } | |
| /* Record UART as serial console */ | |
| serial_console = uart; | |
| DBGC ( uart, "SERIAL using %s\n", uart->name ); | |
| } | |
| /** | |
| * 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 ) | |
| 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 ) = { | |
| .name = "serial", | |
| .initialise = serial_init, | |
| }; | |
| /** Serial console startup function */ | |
| struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = { | |
| .name = "serial", | |
| .shutdown = serial_shutdown, | |
| }; | |
| PROVIDE_SERIAL_INLINE ( null, default_serial_console ); | |
| PROVIDE_SERIAL ( fixed, default_serial_console, fixed_serial_console ); |