iPXE
serial.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /** @file
00027  *
00028  * Serial console
00029  *
00030  */
00031 
00032 #include <stddef.h>
00033 #include <string.h>
00034 #include <ipxe/init.h>
00035 #include <ipxe/uart.h>
00036 #include <ipxe/console.h>
00037 #include <ipxe/serial.h>
00038 #include <config/console.h>
00039 #include <config/serial.h>
00040 
00041 /* Set default console usage if applicable */
00042 #if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
00043 #undef CONSOLE_SERIAL
00044 #define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
00045 #endif
00046 
00047 /* UART port number */
00048 #ifdef COMCONSOLE
00049 #define CONSOLE_PORT COMCONSOLE
00050 #else
00051 #define CONSOLE_PORT 0
00052 #endif
00053 
00054 /* UART baud rate */
00055 #ifdef COMPRESERVE
00056 #define CONSOLE_BAUD 0
00057 #else
00058 #define CONSOLE_BAUD COMSPEED
00059 #endif
00060 
00061 /* UART line control register value */
00062 #ifdef COMPRESERVE
00063 #define CONSOLE_LCR 0
00064 #else
00065 #define CONSOLE_LCR UART_LCR_WPS ( COMDATA, COMPARITY, COMSTOP )
00066 #endif
00067 
00068 /** Serial console UART */
00069 struct uart serial_console;
00070 
00071 /**
00072  * Print a character to serial console
00073  *
00074  * @v character         Character to be printed
00075  */
00076 static void serial_putchar ( int character ) {
00077 
00078         /* Do nothing if we have no UART */
00079         if ( ! serial_console.base )
00080                 return;
00081 
00082         /* Transmit character */
00083         uart_transmit ( &serial_console, character );
00084 }
00085 
00086 /**
00087  * Get character from serial console
00088  *
00089  * @ret character       Character read from console
00090  */
00091 static int serial_getchar ( void ) {
00092         uint8_t data;
00093 
00094         /* Do nothing if we have no UART */
00095         if ( ! serial_console.base )
00096                 return 0;
00097 
00098         /* Wait for data to be ready */
00099         while ( ! uart_data_ready ( &serial_console ) ) {}
00100 
00101         /* Receive data */
00102         data = uart_receive ( &serial_console );
00103 
00104         /* Strip any high bit and convert DEL to backspace */
00105         data &= 0x7f;
00106         if ( data == 0x7f )
00107                 data = 0x08;
00108 
00109         return data;
00110 }
00111 
00112 /**
00113  * Check for character ready to read from serial console
00114  *
00115  * @ret True            Character available to read
00116  * @ret False           No character available to read
00117  */
00118 static int serial_iskey ( void ) {
00119 
00120         /* Do nothing if we have no UART */
00121         if ( ! serial_console.base )
00122                 return 0;
00123 
00124         /* Check UART */
00125         return uart_data_ready ( &serial_console );
00126 }
00127 
00128 /** Serial console */
00129 struct console_driver serial_console_driver __console_driver = {
00130         .putchar = serial_putchar,
00131         .getchar = serial_getchar,
00132         .iskey = serial_iskey,
00133         .usage = CONSOLE_SERIAL,
00134 };
00135 
00136 /** Initialise serial console */
00137 static void serial_init ( void ) {
00138         int rc;
00139 
00140         /* Do nothing if we have no default port */
00141         if ( ! CONSOLE_PORT )
00142                 return;
00143 
00144         /* Select UART */
00145         if ( ( rc = uart_select ( &serial_console, CONSOLE_PORT ) ) != 0 ) {
00146                 DBG ( "Could not select UART %d: %s\n",
00147                       CONSOLE_PORT, strerror ( rc ) );
00148                 return;
00149         }
00150 
00151         /* Initialise UART */
00152         if ( ( rc = uart_init ( &serial_console, CONSOLE_BAUD,
00153                                 CONSOLE_LCR ) ) != 0 ) {
00154                 DBG ( "Could not initialise UART %d baud %d LCR %#02x: %s\n",
00155                       CONSOLE_PORT, CONSOLE_BAUD, CONSOLE_LCR, strerror ( rc ));
00156                 return;
00157         }
00158 }
00159 
00160 /**
00161  * Shut down serial console
00162  *
00163  * @v flags             Shutdown flags
00164  */
00165 static void serial_shutdown ( int flags __unused ) {
00166 
00167         /* Do nothing if we have no UART */
00168         if ( ! serial_console.base )
00169                 return;
00170 
00171         /* Flush any pending output */
00172         uart_flush ( &serial_console );
00173 
00174         /* Leave console enabled; it's still usable */
00175 }
00176 
00177 /** Serial console initialisation function */
00178 struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = {
00179         .initialise = serial_init,
00180 };
00181 
00182 /** Serial console startup function */
00183 struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
00184         .shutdown = serial_shutdown,
00185 };