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