aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/console.c
blob: ad6e495b1c4a9c40384609544a71c32e8b6a9de8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "stddef.h"
#include "console.h"

/** @file */

#include "bios.h"

static struct console_driver console_drivers[0] __table_start ( console );
static struct console_driver console_drivers_end[0] __table_end ( console );

/**
 * Write a single character to each console device.
 *
 * @v character		Character to be written
 * @ret None
 * @err None
 *
 * The character is written out to all enabled console devices, using
 * each device's console_driver::putchar() method.
 *
 */
void putchar ( int character ) {
	struct console_driver *console;

	/* Automatic LF -> CR,LF translation */
	if ( character == '\n' )
		putchar ( '\r' );

	for ( console = console_drivers; console < console_drivers_end ;
	      console++ ) {
		if ( ( ! console->disabled ) && console->putchar )
			console->putchar ( character );
	}
}

/**
 * Check to see if any input is available on any console.
 *
 * @v None
 * @ret console		Console device that has input available, if any.
 * @ret NULL		No console device has input available.
 * @err None
 *
 * All enabled console devices are checked once for available input
 * using each device's console_driver::iskey() method.  The first
 * console device that has available input will be returned, if any.
 *
 */
static struct console_driver * has_input ( void ) {
	struct console_driver *console;

	for ( console = console_drivers; console < console_drivers_end ;
	      console++ ) {
		if ( ( ! console->disabled ) && console->iskey ) {
			if ( console->iskey () )
				return console;
		}
	}
	return NULL;
}

/**
 * Read a single character from any console.
 *
 * @v None
 * @ret character	Character read from a console.
 * @err None
 *
 * A character will be read from the first enabled console device that
 * has input available using that console's console_driver::getchar()
 * method.  If no console has input available to be read, this method
 * will block.  To perform a non-blocking read, use something like
 *
 * @code
 *
 *   int key = iskey() ? getchar() : -1;
 *
 * @endcode
 *
 * The character read will not be echoed back to any console.
 *
 * @bug We need a cleaner way to pick up cpu_nap().  It makes a
 * real-mode call, and so we don't want to use it with LinuxBIOS.
 *
 */
int getchar ( void ) {
	struct console_driver *console;
	int character = 256;

	while ( character == 256 ) {
		/* Doze for a while (until the next interrupt).  This works
		 * fine, because the keyboard is interrupt-driven, and the
		 * timer interrupt (approx. every 50msec) takes care of the
		 * serial port, which is read by polling.  This reduces the
		 * power dissipation of a modern CPU considerably, and also
		 * makes Etherboot waiting for user interaction waste a lot
		 * less CPU time in a VMware session.
		 */
		cpu_nap();
		
		console = has_input();
		if ( console && console->getchar )
			character = console->getchar ();
	}

	/* CR -> LF translation */
	if ( character == '\r' )
		character = '\n';

	return character;
}

/** Check for available input on any console.
 *
 * @v None
 * @ret True		Input is available on a console
 * @ret False		Input is not available on any console
 * @err None
 *
 * All enabled console devices are checked once for available input
 * using each device's console_driver::iskey() method.  If any console
 * device has input available, this call will return True.  If this
 * call returns True, you can then safely call getchar() without
 * blocking.
 *
 */
int iskey ( void ) {
	return has_input() ? 1 : 0;
}