iPXE
console.c
Go to the documentation of this file.
00001 #include "stddef.h"
00002 #include <ipxe/console.h>
00003 #include <ipxe/process.h>
00004 #include <ipxe/nap.h>
00005 
00006 /** @file */
00007 
00008 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00009 
00010 /** Current console usage */
00011 int console_usage = CONSOLE_USAGE_STDOUT;
00012 
00013 /** Console width */
00014 unsigned int console_width = CONSOLE_DEFAULT_WIDTH;
00015 
00016 /** Console height */
00017 unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
00018 
00019 /**
00020  * Write a single character to each console device
00021  *
00022  * @v character         Character to be written
00023  *
00024  * The character is written out to all enabled console devices, using
00025  * each device's console_driver::putchar() method.
00026  */
00027 void putchar ( int character ) {
00028         struct console_driver *console;
00029 
00030         /* Automatic LF -> CR,LF translation */
00031         if ( character == '\n' )
00032                 putchar ( '\r' );
00033 
00034         for_each_table_entry ( console, CONSOLES ) {
00035                 if ( ( ! ( console->disabled & CONSOLE_DISABLED_OUTPUT ) ) &&
00036                      ( console_usage & console->usage ) &&
00037                      console->putchar )
00038                         console->putchar ( character );
00039         }
00040 }
00041 
00042 /**
00043  * Check to see if any input is available on any console
00044  *
00045  * @ret console         Console device that has input available, or NULL
00046  *
00047  * All enabled console devices are checked once for available input
00048  * using each device's console_driver::iskey() method.  The first
00049  * console device that has available input will be returned, if any.
00050  */
00051 static struct console_driver * has_input ( void ) {
00052         struct console_driver *console;
00053 
00054         for_each_table_entry ( console, CONSOLES ) {
00055                 if ( ( ! ( console->disabled & CONSOLE_DISABLED_INPUT ) ) &&
00056                      console->iskey ) {
00057                         if ( console->iskey () )
00058                                 return console;
00059                 }
00060         }
00061         return NULL;
00062 }
00063 
00064 /**
00065  * Read a single character from any console
00066  *
00067  * @ret character       Character read from a console.
00068  *
00069  * A character will be read from the first enabled console device that
00070  * has input available using that console's console_driver::getchar()
00071  * method.  If no console has input available to be read, this method
00072  * will block.  To perform a non-blocking read, use something like
00073  *
00074  * @code
00075  *
00076  *   int key = iskey() ? getchar() : -1;
00077  *
00078  * @endcode
00079  *
00080  * The character read will not be echoed back to any console.
00081  */
00082 int getchar ( void ) {
00083         struct console_driver *console;
00084         int character;
00085 
00086         while ( 1 ) {
00087                 console = has_input();
00088                 if ( console && console->getchar ) {
00089                         character = console->getchar ();
00090                         break;
00091                 }
00092 
00093                 /* Doze for a while (until the next interrupt).  This works
00094                  * fine, because the keyboard is interrupt-driven, and the
00095                  * timer interrupt (approx. every 50msec) takes care of the
00096                  * serial port, which is read by polling.  This reduces the
00097                  * power dissipation of a modern CPU considerably, and also
00098                  * makes Etherboot waiting for user interaction waste a lot
00099                  * less CPU time in a VMware session.
00100                  */
00101                 cpu_nap();
00102 
00103                 /* Keep processing background tasks while we wait for
00104                  * input.
00105                  */
00106                 step();
00107         }
00108 
00109         /* CR -> LF translation */
00110         if ( character == '\r' )
00111                 character = '\n';
00112 
00113         return character;
00114 }
00115 
00116 /**
00117  * Check for available input on any console
00118  *
00119  * @ret is_available    Input is available on a console
00120  *
00121  * All enabled console devices are checked once for available input
00122  * using each device's console_driver::iskey() method.  If any console
00123  * device has input available, this call will return true.  If this
00124  * call returns true, you can then safely call getchar() without
00125  * blocking.
00126  */
00127 int iskey ( void ) {
00128         return has_input() ? 1 : 0;
00129 }
00130 
00131 /**
00132  * Configure console
00133  *
00134  * @v config            Console configuration
00135  * @ret rc              Return status code
00136  *
00137  * The configuration is passed to all configurable consoles, including
00138  * those which are currently disabled.  Consoles may choose to enable
00139  * or disable themselves depending upon the configuration.
00140  *
00141  * If configuration fails, then all consoles will be reset.
00142  */
00143 int console_configure ( struct console_configuration *config ) {
00144         struct console_driver *console;
00145         int rc;
00146 
00147         /* Reset console width and height */
00148         console_set_size ( CONSOLE_DEFAULT_WIDTH, CONSOLE_DEFAULT_HEIGHT );
00149 
00150         /* Try to configure each console */
00151         for_each_table_entry ( console, CONSOLES ) {
00152                 if ( ( console->configure ) &&
00153                      ( ( rc = console->configure ( config ) ) != 0 ) )
00154                                 goto err;
00155         }
00156 
00157         return 0;
00158 
00159  err:
00160         /* Reset all consoles, avoiding a potential infinite loop */
00161         if ( config )
00162                 console_reset();
00163         return rc;
00164 }