Applied a modified version of holger's regparm patches.
[people/adir/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 = 256;
92
93         while ( character == 256 ) {
94                 /* Doze for a while (until the next interrupt).  This works
95                  * fine, because the keyboard is interrupt-driven, and the
96                  * timer interrupt (approx. every 50msec) takes care of the
97                  * serial port, which is read by polling.  This reduces the
98                  * power dissipation of a modern CPU considerably, and also
99                  * makes Etherboot waiting for user interaction waste a lot
100                  * less CPU time in a VMware session.
101                  */
102                 cpu_nap();
103
104                 /* Keep processing background tasks while we wait for
105                  * input.
106                  */
107                 step();
108                 
109                 console = has_input();
110                 if ( console && console->getchar )
111                         character = console->getchar ();
112         }
113
114         /* CR -> LF translation */
115         if ( character == '\r' )
116                 character = '\n';
117
118         return character;
119 }
120
121 /** Check for available input on any console.
122  *
123  * @v None              -
124  * @ret True            Input is available on a console
125  * @ret False           Input is not available on any console
126  * @err None            -
127  *
128  * All enabled console devices are checked once for available input
129  * using each device's console_driver::iskey() method.  If any console
130  * device has input available, this call will return True.  If this
131  * call returns True, you can then safely call getchar() without
132  * blocking.
133  *
134  */
135 int iskey ( void ) {
136         return has_input() ? 1 : 0;
137 }