• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
putchar(int character)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  */
has_input(void)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  */
getchar(void)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  */
iskey(void)128 int iskey ( void ) {
129 	return has_input() ? 1 : 0;
130 }
131