| #include "stddef.h" |
| #include <ipxe/console.h> |
| #include <ipxe/process.h> |
| #include <ipxe/nap.h> |
| |
| /** @file */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| |
| /** Current console usage */ |
| int console_usage = CONSOLE_USAGE_STDOUT; |
| |
| /** Console width */ |
| unsigned int console_width = CONSOLE_DEFAULT_WIDTH; |
| |
| /** Console height */ |
| unsigned int console_height = CONSOLE_DEFAULT_HEIGHT; |
| |
| /** |
| * Write a single character to each console device |
| * |
| * @v character Character to be written |
| * @ret character Character written |
| * |
| * The character is written out to all enabled console devices, using |
| * each device's console_driver::putchar() method. |
| */ |
| int putchar ( int character ) { |
| struct console_driver *console; |
| |
| /* Automatic LF -> CR,LF translation */ |
| if ( character == '\n' ) |
| putchar ( '\r' ); |
| |
| for_each_table_entry ( console, CONSOLES ) { |
| if ( ( ! ( console->disabled & CONSOLE_DISABLED_OUTPUT ) ) && |
| ( console_usage & console->usage ) && |
| console->putchar ) |
| console->putchar ( character ); |
| } |
| |
| return character; |
| } |
| |
| /** |
| * Check to see if any input is available on any console |
| * |
| * @ret console Console device that has input available, or NULL |
| * |
| * All enabled console devices are checked once for available input |
| * using each device's console_driver::iskey() method. The first |
| * console device that has available input will be returned, if any. |
| */ |
| static struct console_driver * has_input ( void ) { |
| struct console_driver *console; |
| |
| for_each_table_entry ( console, CONSOLES ) { |
| if ( ( ! ( console->disabled & CONSOLE_DISABLED_INPUT ) ) && |
| console->iskey ) { |
| if ( console->iskey () ) |
| return console; |
| } |
| } |
| return NULL; |
| } |
| |
| /** |
| * Read a single character from any console |
| * |
| * @ret character Character read from a console. |
| * |
| * A character will be read from the first enabled console device that |
| * has input available using that console's console_driver::getchar() |
| * method. If no console has input available to be read, this method |
| * will block. To perform a non-blocking read, use something like |
| * |
| * @code |
| * |
| * int key = iskey() ? getchar() : -1; |
| * |
| * @endcode |
| * |
| * The character read will not be echoed back to any console. |
| */ |
| int getchar ( void ) { |
| struct console_driver *console; |
| int character; |
| |
| while ( 1 ) { |
| console = has_input(); |
| if ( console && console->getchar ) { |
| character = console->getchar (); |
| break; |
| } |
| |
| /* Doze for a while (until the next interrupt). This works |
| * fine, because the keyboard is interrupt-driven, and the |
| * timer interrupt (approx. every 50msec) takes care of the |
| * serial port, which is read by polling. This reduces the |
| * power dissipation of a modern CPU considerably, and also |
| * makes Etherboot waiting for user interaction waste a lot |
| * less CPU time in a VMware session. |
| */ |
| cpu_nap(); |
| |
| /* Keep processing background tasks while we wait for |
| * input. |
| */ |
| step(); |
| } |
| |
| /* CR -> LF translation */ |
| if ( character == '\r' ) |
| character = '\n'; |
| |
| return character; |
| } |
| |
| /** |
| * Check for available input on any console |
| * |
| * @ret is_available Input is available on a console |
| * |
| * All enabled console devices are checked once for available input |
| * using each device's console_driver::iskey() method. If any console |
| * device has input available, this call will return true. If this |
| * call returns true, you can then safely call getchar() without |
| * blocking. |
| */ |
| int iskey ( void ) { |
| return has_input() ? 1 : 0; |
| } |
| |
| /** |
| * Configure console |
| * |
| * @v config Console configuration |
| * @ret rc Return status code |
| * |
| * The configuration is passed to all configurable consoles, including |
| * those which are currently disabled. Consoles may choose to enable |
| * or disable themselves depending upon the configuration. |
| * |
| * If configuration fails, then all consoles will be reset. |
| */ |
| int console_configure ( struct console_configuration *config ) { |
| struct console_driver *console; |
| int rc; |
| |
| /* Reset console width and height */ |
| console_set_size ( CONSOLE_DEFAULT_WIDTH, CONSOLE_DEFAULT_HEIGHT ); |
| |
| /* Try to configure each console */ |
| for_each_table_entry ( console, CONSOLES ) { |
| if ( ( console->configure ) && |
| ( ( rc = console->configure ( config ) ) != 0 ) ) |
| goto err; |
| } |
| |
| return 0; |
| |
| err: |
| /* Reset all consoles, avoiding a potential infinite loop */ |
| if ( config ) |
| console_reset(); |
| return rc; |
| } |