2
* GRUB -- GRand Unified Bootloader
3
* Copyright (C) 2007,2008,2009 Free Software Foundation, Inc.
5
* GRUB is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* GRUB is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20
#include <grub/at_keyboard.h>
21
#include <grub/cpu/at_keyboard.h>
22
#include <grub/cpu/io.h>
23
#include <grub/misc.h>
24
#include <grub/term.h>
26
static short at_keyboard_status = 0;
27
static int pending_key = -1;
29
#define KEYBOARD_STATUS_SHIFT_L (1 << 0)
30
#define KEYBOARD_STATUS_SHIFT_R (1 << 1)
31
#define KEYBOARD_STATUS_ALT_L (1 << 2)
32
#define KEYBOARD_STATUS_ALT_R (1 << 3)
33
#define KEYBOARD_STATUS_CTRL_L (1 << 4)
34
#define KEYBOARD_STATUS_CTRL_R (1 << 5)
35
#define KEYBOARD_STATUS_CAPS_LOCK (1 << 6)
36
#define KEYBOARD_STATUS_NUM_LOCK (1 << 7)
38
static grub_uint8_t led_status;
40
#define KEYBOARD_LED_SCROLL (1 << 0)
41
#define KEYBOARD_LED_NUM (1 << 1)
42
#define KEYBOARD_LED_CAPS (1 << 2)
44
static char keyboard_map[128] =
46
'\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6',
47
'7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB,
48
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
49
'o', 'p', '[', ']', '\n', '\0', 'a', 's',
50
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
51
'\'', '`', '\0', '\\', 'z', 'x', 'c', 'v',
52
'b', 'n', 'm', ',', '.', '/', '\0', '*',
53
'\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0',
54
'\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_HOME,
55
GRUB_TERM_UP, GRUB_TERM_NPAGE, '-', GRUB_TERM_LEFT, '\0', GRUB_TERM_RIGHT, '+', GRUB_TERM_END,
56
GRUB_TERM_DOWN, GRUB_TERM_PPAGE, '\0', GRUB_TERM_DC, '\0', '\0', '\0', '\0',
57
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
58
'\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT,
62
static char keyboard_map_shift[128] =
64
'\0', '\0', '!', '@', '#', '$', '%', '^',
65
'&', '*', '(', ')', '_', '+', '\0', '\0',
66
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
67
'O', 'P', '{', '}', '\n', '\0', 'A', 'S',
68
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
69
'\"', '~', '\0', '|', 'Z', 'X', 'C', 'V',
70
'B', 'N', 'M', '<', '>', '?'
73
static grub_uint8_t grub_keyboard_controller_orig;
76
keyboard_controller_wait_until_ready (void)
78
while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)));
82
grub_keyboard_controller_write (grub_uint8_t c)
84
keyboard_controller_wait_until_ready ();
85
grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS);
86
grub_outb (c, KEYBOARD_REG_DATA);
90
grub_keyboard_controller_read (void)
92
keyboard_controller_wait_until_ready ();
93
grub_outb (KEYBOARD_COMMAND_READ, KEYBOARD_REG_STATUS);
94
return grub_inb (KEYBOARD_REG_DATA);
98
keyboard_controller_led (grub_uint8_t leds)
100
keyboard_controller_wait_until_ready ();
101
grub_outb (0xed, KEYBOARD_REG_DATA);
102
keyboard_controller_wait_until_ready ();
103
grub_outb (leds & 0x7, KEYBOARD_REG_DATA);
106
/* FIXME: This should become an interrupt service routine. For now
107
it's just used to catch events from control keys. */
109
grub_keyboard_isr (char key)
111
char is_make = KEYBOARD_ISMAKE (key);
112
key = KEYBOARD_SCANCODE (key);
117
at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L;
120
at_keyboard_status |= KEYBOARD_STATUS_SHIFT_R;
123
at_keyboard_status |= KEYBOARD_STATUS_CTRL_L;
126
at_keyboard_status |= KEYBOARD_STATUS_ALT_L;
129
/* Skip grub_dprintf. */
136
at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L;
139
at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_R;
142
at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L;
145
at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L;
148
/* Skip grub_dprintf. */
151
#ifdef DEBUG_AT_KEYBOARD
152
grub_dprintf ("atkeyb", "Control key 0x%0x was %s\n", key, is_make ? "pressed" : "unpressed");
156
/* If there is a raw key pending, return it; otherwise return -1. */
158
grub_keyboard_getkey (void)
161
if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
163
key = grub_inb (KEYBOARD_REG_DATA);
164
/* FIXME */ grub_keyboard_isr (key);
165
if (! KEYBOARD_ISMAKE (key))
167
return (KEYBOARD_SCANCODE (key));
170
/* If there is a character pending, return it; otherwise return -1. */
172
grub_at_keyboard_getkey_noblock (void)
175
code = grub_keyboard_getkey ();
178
#ifdef DEBUG_AT_KEYBOARD
179
grub_dprintf ("atkeyb", "Detected key 0x%x\n", key);
184
/* Caps lock sends scan code twice. Get the second one and discard it. */
185
while (grub_keyboard_getkey () == -1);
187
at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK;
188
led_status ^= KEYBOARD_LED_CAPS;
189
keyboard_controller_led (led_status);
191
#ifdef DEBUG_AT_KEYBOARD
192
grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK));
197
/* Num lock sends scan code twice. Get the second one and discard it. */
198
while (grub_keyboard_getkey () == -1);
200
at_keyboard_status ^= KEYBOARD_STATUS_NUM_LOCK;
201
led_status ^= KEYBOARD_LED_NUM;
202
keyboard_controller_led (led_status);
204
#ifdef DEBUG_AT_KEYBOARD
205
grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK));
210
/* For scroll lock we don't keep track of status. Only update its led. */
211
led_status ^= KEYBOARD_LED_SCROLL;
212
keyboard_controller_led (led_status);
216
if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R))
217
key = keyboard_map[code] - 'a' + 1;
218
else if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L | KEYBOARD_STATUS_SHIFT_R))
219
&& keyboard_map_shift[code])
220
key = keyboard_map_shift[code];
222
key = keyboard_map[code];
225
grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code);
227
if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)
229
if ((key >= 'a') && (key <= 'z'))
231
else if ((key >= 'A') && (key <= 'Z'))
239
grub_at_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused)))
241
if (pending_key != -1)
244
pending_key = grub_at_keyboard_getkey_noblock ();
246
if (pending_key != -1)
253
grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
256
if (pending_key != -1)
264
key = grub_at_keyboard_getkey_noblock ();
270
grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unused)))
273
at_keyboard_status = 0;
274
grub_keyboard_controller_orig = grub_keyboard_controller_read ();
275
grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1);
276
return GRUB_ERR_NONE;
280
grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
282
grub_keyboard_controller_write (grub_keyboard_controller_orig);
283
return GRUB_ERR_NONE;
286
static struct grub_term_input grub_at_keyboard_term =
288
.name = "at_keyboard",
289
.init = grub_keyboard_controller_init,
290
.fini = grub_keyboard_controller_fini,
291
.checkkey = grub_at_keyboard_checkkey,
292
.getkey = grub_at_keyboard_getkey,
295
GRUB_MOD_INIT(at_keyboard)
297
grub_term_register_input ("at_keyboard", &grub_at_keyboard_term);
300
GRUB_MOD_FINI(at_keyboard)
302
grub_term_unregister_input (&grub_at_keyboard_term);