Files
ipxe/src/core/console.c
T
Michael Brown 03401f9d21 [console] Allow consoles to update the recorded console size
Provide a mechanism for consoles to update the recorded console width
and height, and use this width and height to provide the curses COLS
and LINES variables.

We choose not to use ANSI escape sequences to obtain the width and
height, for two reasons:

- iPXE's model is that all output is sent to all consoles; we could
  therefore end up with multiple consoles reporting conflicting widths
  and heights

- when a serial console is in use, we probably don't want to resize
  the output shown on the BIOS console to match the size of the serial
  console, since it's likely that the serial console is in use only
  for debugging.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2013-12-06 17:47:54 +00:00

165 lines
4.2 KiB
C

#include "stddef.h"
#include <ipxe/console.h>
#include <ipxe/process.h>
#include <ipxe/nap.h>
/** @file */
FILE_LICENCE ( GPL2_OR_LATER );
/** 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
*
* The character is written out to all enabled console devices, using
* each device's console_driver::putchar() method.
*/
void 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 );
}
}
/**
* 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;
}