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