/* * Copyright (C) 2014 Michael Brown . * * 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 #include #include #include #include #include #include #include #include /* 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 );