1 #include "stddef.h" 2 #include "console.h" 3 #include <gpxe/process.h> 4 #include <gpxe/nap.h> 5 6 /** @file */ 7 8 FILE_LICENCE ( GPL2_OR_LATER ); 9 10 /** 11 * Write a single character to each console device. 12 * 13 * @v character Character to be written 14 * @ret None - 15 * @err None - 16 * 17 * The character is written out to all enabled console devices, using 18 * each device's console_driver::putchar() method. 19 * 20 */ 21 void putchar ( int character ) { 22 struct console_driver *console; 23 24 /* Automatic LF -> CR,LF translation */ 25 if ( character == '\n' ) 26 putchar ( '\r' ); 27 28 for_each_table_entry ( console, CONSOLES ) { 29 if ( ( ! console->disabled ) && console->putchar ) 30 console->putchar ( character ); 31 } 32 } 33 34 /** 35 * Check to see if any input is available on any console. 36 * 37 * @v None - 38 * @ret console Console device that has input available, if any. 39 * @ret NULL No console device has input available. 40 * @err None - 41 * 42 * All enabled console devices are checked once for available input 43 * using each device's console_driver::iskey() method. The first 44 * console device that has available input will be returned, if any. 45 * 46 */ 47 static struct console_driver * has_input ( void ) { 48 struct console_driver *console; 49 50 for_each_table_entry ( console, CONSOLES ) { 51 if ( ( ! console->disabled ) && console->iskey ) { 52 if ( console->iskey () ) 53 return console; 54 } 55 } 56 return NULL; 57 } 58 59 /** 60 * Read a single character from any console. 61 * 62 * @v None - 63 * @ret character Character read from a console. 64 * @err None - 65 * 66 * A character will be read from the first enabled console device that 67 * has input available using that console's console_driver::getchar() 68 * method. If no console has input available to be read, this method 69 * will block. To perform a non-blocking read, use something like 70 * 71 * @code 72 * 73 * int key = iskey() ? getchar() : -1; 74 * 75 * @endcode 76 * 77 * The character read will not be echoed back to any console. 78 * 79 */ 80 int getchar ( void ) { 81 struct console_driver *console; 82 int character; 83 84 while ( 1 ) { 85 console = has_input(); 86 if ( console && console->getchar ) { 87 character = console->getchar (); 88 break; 89 } 90 91 /* Doze for a while (until the next interrupt). This works 92 * fine, because the keyboard is interrupt-driven, and the 93 * timer interrupt (approx. every 50msec) takes care of the 94 * serial port, which is read by polling. This reduces the 95 * power dissipation of a modern CPU considerably, and also 96 * makes Etherboot waiting for user interaction waste a lot 97 * less CPU time in a VMware session. 98 */ 99 cpu_nap(); 100 101 /* Keep processing background tasks while we wait for 102 * input. 103 */ 104 step(); 105 } 106 107 /* CR -> LF translation */ 108 if ( character == '\r' ) 109 character = '\n'; 110 111 return character; 112 } 113 114 /** Check for available input on any console. 115 * 116 * @v None - 117 * @ret True Input is available on a console 118 * @ret False Input is not available on any console 119 * @err None - 120 * 121 * All enabled console devices are checked once for available input 122 * using each device's console_driver::iskey() method. If any console 123 * device has input available, this call will return True. If this 124 * call returns True, you can then safely call getchar() without 125 * blocking. 126 * 127 */ 128 int iskey ( void ) { 129 return has_input() ? 1 : 0; 130 } 131