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