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/misc.h>
21 #include <grub/term.h>
22 #include <grub/keyboard_layouts.h>
25 #define KEYBOARD_LED_SCROLL (1 << 0)
26 #define KEYBOARD_LED_NUM (1 << 1)
27 #define KEYBOARD_LED_CAPS (1 << 2)
29 static const grub_uint8_t set1_mapping
[128] =
31 /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE
,
32 /* 0x02 */ GRUB_KEYBOARD_KEY_1
, GRUB_KEYBOARD_KEY_2
,
33 /* 0x04 */ GRUB_KEYBOARD_KEY_3
, GRUB_KEYBOARD_KEY_4
,
34 /* 0x06 */ GRUB_KEYBOARD_KEY_5
, GRUB_KEYBOARD_KEY_6
,
35 /* 0x08 */ GRUB_KEYBOARD_KEY_7
, GRUB_KEYBOARD_KEY_8
,
36 /* 0x0a */ GRUB_KEYBOARD_KEY_9
, GRUB_KEYBOARD_KEY_0
,
37 /* 0x0c */ GRUB_KEYBOARD_KEY_DASH
, GRUB_KEYBOARD_KEY_EQUAL
,
38 /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE
, GRUB_KEYBOARD_KEY_TAB
,
39 /* 0x10 */ GRUB_KEYBOARD_KEY_Q
, GRUB_KEYBOARD_KEY_W
,
40 /* 0x12 */ GRUB_KEYBOARD_KEY_E
, GRUB_KEYBOARD_KEY_R
,
41 /* 0x14 */ GRUB_KEYBOARD_KEY_T
, GRUB_KEYBOARD_KEY_Y
,
42 /* 0x16 */ GRUB_KEYBOARD_KEY_U
, GRUB_KEYBOARD_KEY_I
,
43 /* 0x18 */ GRUB_KEYBOARD_KEY_O
, GRUB_KEYBOARD_KEY_P
,
44 /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET
, GRUB_KEYBOARD_KEY_RBRACKET
,
45 /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER
, GRUB_KEYBOARD_KEY_LEFT_CTRL
,
46 /* 0x1e */ GRUB_KEYBOARD_KEY_A
, GRUB_KEYBOARD_KEY_S
,
47 /* 0x20 */ GRUB_KEYBOARD_KEY_D
, GRUB_KEYBOARD_KEY_F
,
48 /* 0x22 */ GRUB_KEYBOARD_KEY_G
, GRUB_KEYBOARD_KEY_H
,
49 /* 0x24 */ GRUB_KEYBOARD_KEY_J
, GRUB_KEYBOARD_KEY_K
,
50 /* 0x26 */ GRUB_KEYBOARD_KEY_L
, GRUB_KEYBOARD_KEY_SEMICOLON
,
51 /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE
, GRUB_KEYBOARD_KEY_RQUOTE
,
52 /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT
, GRUB_KEYBOARD_KEY_BACKSLASH
,
53 /* 0x2c */ GRUB_KEYBOARD_KEY_Z
, GRUB_KEYBOARD_KEY_X
,
54 /* 0x2e */ GRUB_KEYBOARD_KEY_C
, GRUB_KEYBOARD_KEY_V
,
55 /* 0x30 */ GRUB_KEYBOARD_KEY_B
, GRUB_KEYBOARD_KEY_N
,
56 /* 0x32 */ GRUB_KEYBOARD_KEY_M
, GRUB_KEYBOARD_KEY_COMMA
,
57 /* 0x34 */ GRUB_KEYBOARD_KEY_DOT
, GRUB_KEYBOARD_KEY_SLASH
,
58 /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT
, GRUB_KEYBOARD_KEY_NUMMUL
,
59 /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT
, GRUB_KEYBOARD_KEY_SPACE
,
60 /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK
, GRUB_KEYBOARD_KEY_F1
,
61 /* 0x3c */ GRUB_KEYBOARD_KEY_F2
, GRUB_KEYBOARD_KEY_F3
,
62 /* 0x3e */ GRUB_KEYBOARD_KEY_F4
, GRUB_KEYBOARD_KEY_F5
,
63 /* 0x40 */ GRUB_KEYBOARD_KEY_F6
, GRUB_KEYBOARD_KEY_F7
,
64 /* 0x42 */ GRUB_KEYBOARD_KEY_F8
, GRUB_KEYBOARD_KEY_F9
,
65 /* 0x44 */ GRUB_KEYBOARD_KEY_F10
, GRUB_KEYBOARD_KEY_NUM_LOCK
,
66 /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK
, GRUB_KEYBOARD_KEY_NUM7
,
67 /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8
, GRUB_KEYBOARD_KEY_NUM9
,
68 /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS
, GRUB_KEYBOARD_KEY_NUM4
,
69 /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5
, GRUB_KEYBOARD_KEY_NUM6
,
70 /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS
, GRUB_KEYBOARD_KEY_NUM1
,
71 /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2
, GRUB_KEYBOARD_KEY_NUM3
,
72 /* 0x52 */ GRUB_KEYBOARD_KEY_NUM0
, GRUB_KEYBOARD_KEY_NUMDOT
,
74 /* 0x56 */ GRUB_KEYBOARD_KEY_102ND
, GRUB_KEYBOARD_KEY_F11
,
75 /* 0x58 */ GRUB_KEYBOARD_KEY_F12
, 0,
81 /* OLPC keys. Just mapped to normal keys. */
82 /* 0x64 */ 0, GRUB_KEYBOARD_KEY_UP
,
83 /* 0x66 */ GRUB_KEYBOARD_KEY_DOWN
, GRUB_KEYBOARD_KEY_LEFT
,
84 /* 0x68 */ GRUB_KEYBOARD_KEY_RIGHT
, 0,
89 /* 0x72 */ 0, GRUB_KEYBOARD_KEY_JP_RO
,
94 /* 0x7c */ 0, GRUB_KEYBOARD_KEY_JP_YEN
,
95 /* 0x7e */ GRUB_KEYBOARD_KEY_KPCOMMA
100 grub_uint8_t from
, to
;
101 } set1_e0_mapping
[] =
103 {0x1c, GRUB_KEYBOARD_KEY_NUMENTER
},
104 {0x1d, GRUB_KEYBOARD_KEY_RIGHT_CTRL
},
105 {0x35, GRUB_KEYBOARD_KEY_NUMSLASH
},
106 {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT
},
107 {0x47, GRUB_KEYBOARD_KEY_HOME
},
108 {0x48, GRUB_KEYBOARD_KEY_UP
},
109 {0x49, GRUB_KEYBOARD_KEY_PPAGE
},
110 {0x4b, GRUB_KEYBOARD_KEY_LEFT
},
111 {0x4d, GRUB_KEYBOARD_KEY_RIGHT
},
112 {0x4f, GRUB_KEYBOARD_KEY_END
},
113 {0x50, GRUB_KEYBOARD_KEY_DOWN
},
114 {0x51, GRUB_KEYBOARD_KEY_NPAGE
},
115 {0x52, GRUB_KEYBOARD_KEY_INSERT
},
116 {0x53, GRUB_KEYBOARD_KEY_DELETE
},
119 static const grub_uint8_t set2_mapping
[256] =
121 /* 0x00 */ 0, GRUB_KEYBOARD_KEY_F9
,
122 /* 0x02 */ 0, GRUB_KEYBOARD_KEY_F5
,
123 /* 0x04 */ GRUB_KEYBOARD_KEY_F3
, GRUB_KEYBOARD_KEY_F1
,
124 /* 0x06 */ GRUB_KEYBOARD_KEY_F2
, GRUB_KEYBOARD_KEY_F12
,
125 /* 0x08 */ 0, GRUB_KEYBOARD_KEY_F10
,
126 /* 0x0a */ GRUB_KEYBOARD_KEY_F8
, GRUB_KEYBOARD_KEY_F6
,
127 /* 0x0c */ GRUB_KEYBOARD_KEY_F4
, GRUB_KEYBOARD_KEY_TAB
,
128 /* 0x0e */ GRUB_KEYBOARD_KEY_RQUOTE
, 0,
129 /* 0x10 */ 0, GRUB_KEYBOARD_KEY_LEFT_ALT
,
130 /* 0x12 */ GRUB_KEYBOARD_KEY_LEFT_SHIFT
, 0,
131 /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL
, GRUB_KEYBOARD_KEY_Q
,
132 /* 0x16 */ GRUB_KEYBOARD_KEY_1
, 0,
134 /* 0x1a */ GRUB_KEYBOARD_KEY_Z
, GRUB_KEYBOARD_KEY_S
,
135 /* 0x1c */ GRUB_KEYBOARD_KEY_A
, GRUB_KEYBOARD_KEY_W
,
136 /* 0x1e */ GRUB_KEYBOARD_KEY_2
, 0,
137 /* 0x20 */ 0, GRUB_KEYBOARD_KEY_C
,
138 /* 0x22 */ GRUB_KEYBOARD_KEY_X
, GRUB_KEYBOARD_KEY_D
,
139 /* 0x24 */ GRUB_KEYBOARD_KEY_E
, GRUB_KEYBOARD_KEY_4
,
140 /* 0x26 */ GRUB_KEYBOARD_KEY_3
, 0,
141 /* 0x28 */ 0, GRUB_KEYBOARD_KEY_SPACE
,
142 /* 0x2a */ GRUB_KEYBOARD_KEY_V
, GRUB_KEYBOARD_KEY_F
,
143 /* 0x2c */ GRUB_KEYBOARD_KEY_T
, GRUB_KEYBOARD_KEY_R
,
144 /* 0x2e */ GRUB_KEYBOARD_KEY_5
, 0,
145 /* 0x30 */ 0, GRUB_KEYBOARD_KEY_N
,
146 /* 0x32 */ GRUB_KEYBOARD_KEY_B
, GRUB_KEYBOARD_KEY_H
,
147 /* 0x34 */ GRUB_KEYBOARD_KEY_G
, GRUB_KEYBOARD_KEY_Y
,
148 /* 0x36 */ GRUB_KEYBOARD_KEY_6
, 0,
150 /* 0x3a */ GRUB_KEYBOARD_KEY_M
, GRUB_KEYBOARD_KEY_J
,
151 /* 0x3c */ GRUB_KEYBOARD_KEY_U
, GRUB_KEYBOARD_KEY_7
,
152 /* 0x3e */ GRUB_KEYBOARD_KEY_8
, 0,
153 /* 0x40 */ 0, GRUB_KEYBOARD_KEY_COMMA
,
154 /* 0x42 */ GRUB_KEYBOARD_KEY_K
, GRUB_KEYBOARD_KEY_I
,
155 /* 0x44 */ GRUB_KEYBOARD_KEY_O
, GRUB_KEYBOARD_KEY_0
,
156 /* 0x46 */ GRUB_KEYBOARD_KEY_9
, 0,
157 /* 0x48 */ 0, GRUB_KEYBOARD_KEY_DOT
,
158 /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH
, GRUB_KEYBOARD_KEY_L
,
159 /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON
, GRUB_KEYBOARD_KEY_P
,
160 /* 0x4e */ GRUB_KEYBOARD_KEY_DASH
, 0,
161 /* 0x50 */ 0, GRUB_KEYBOARD_KEY_JP_RO
,
162 /* 0x52 */ GRUB_KEYBOARD_KEY_DQUOTE
, 0,
163 /* 0x54 */ GRUB_KEYBOARD_KEY_LBRACKET
, GRUB_KEYBOARD_KEY_EQUAL
,
165 /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK
, GRUB_KEYBOARD_KEY_RIGHT_SHIFT
,
166 /* 0x5a */ GRUB_KEYBOARD_KEY_ENTER
, GRUB_KEYBOARD_KEY_RBRACKET
,
167 /* 0x5c */ 0, GRUB_KEYBOARD_KEY_BACKSLASH
,
169 /* 0x60 */ 0, GRUB_KEYBOARD_KEY_102ND
,
172 /* 0x66 */ GRUB_KEYBOARD_KEY_BACKSPACE
, 0,
173 /* 0x68 */ 0, GRUB_KEYBOARD_KEY_NUM1
,
174 /* 0x6a */ GRUB_KEYBOARD_KEY_JP_YEN
, GRUB_KEYBOARD_KEY_NUM4
,
175 /* 0x6c */ GRUB_KEYBOARD_KEY_NUM7
, GRUB_KEYBOARD_KEY_KPCOMMA
,
177 /* 0x70 */ GRUB_KEYBOARD_KEY_NUM0
, GRUB_KEYBOARD_KEY_NUMDOT
,
178 /* 0x72 */ GRUB_KEYBOARD_KEY_NUM2
, GRUB_KEYBOARD_KEY_NUM5
,
179 /* 0x74 */ GRUB_KEYBOARD_KEY_NUM6
, GRUB_KEYBOARD_KEY_NUM8
,
180 /* 0x76 */ GRUB_KEYBOARD_KEY_ESCAPE
, GRUB_KEYBOARD_KEY_NUM_LOCK
,
181 /* 0x78 */ GRUB_KEYBOARD_KEY_F11
, GRUB_KEYBOARD_KEY_NUMPLUS
,
182 /* 0x7a */ GRUB_KEYBOARD_KEY_NUM3
, GRUB_KEYBOARD_KEY_NUMMINUS
,
183 /* 0x7c */ GRUB_KEYBOARD_KEY_NUMMUL
, GRUB_KEYBOARD_KEY_NUM9
,
184 /* 0x7e */ GRUB_KEYBOARD_KEY_SCROLL_LOCK
, 0,
186 /* 0x82 */ 0, GRUB_KEYBOARD_KEY_F7
,
191 grub_uint8_t from
, to
;
192 } set2_e0_mapping
[] =
194 {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT
},
195 {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL
},
196 {0x4a, GRUB_KEYBOARD_KEY_NUMSLASH
},
197 {0x5a, GRUB_KEYBOARD_KEY_NUMENTER
},
198 {0x69, GRUB_KEYBOARD_KEY_END
},
199 {0x6b, GRUB_KEYBOARD_KEY_LEFT
},
200 {0x6c, GRUB_KEYBOARD_KEY_HOME
},
201 {0x70, GRUB_KEYBOARD_KEY_INSERT
},
202 {0x71, GRUB_KEYBOARD_KEY_DELETE
},
203 {0x72, GRUB_KEYBOARD_KEY_DOWN
},
204 {0x74, GRUB_KEYBOARD_KEY_RIGHT
},
205 {0x75, GRUB_KEYBOARD_KEY_UP
},
206 {0x7a, GRUB_KEYBOARD_KEY_NPAGE
},
207 {0x7d, GRUB_KEYBOARD_KEY_PPAGE
},
211 fetch_key (struct grub_ps2_state
*ps2_state
, grub_uint8_t at_key
, int *is_break
)
216 /* May happen if no keyboard is connected. Just ignore this. */
221 ps2_state
->e0_received
= 1;
225 if ((ps2_state
->current_set
== 2 || ps2_state
->current_set
== 3) && at_key
== 0xf0)
227 ps2_state
->f0_received
= 1;
231 /* Setting LEDs may generate ACKs. */
232 if (at_key
== GRUB_AT_ACK
)
235 was_ext
= ps2_state
->e0_received
;
236 ps2_state
->e0_received
= 0;
238 switch (ps2_state
->current_set
)
241 *is_break
= !!(at_key
& 0x80);
243 ret
= set1_mapping
[at_key
& 0x7f];
247 for (i
= 0; i
< ARRAY_SIZE (set1_e0_mapping
); i
++)
248 if (set1_e0_mapping
[i
].from
== (at_key
& 0x7f))
250 ret
= set1_e0_mapping
[i
].to
;
256 *is_break
= ps2_state
->f0_received
;
257 ps2_state
->f0_received
= 0;
259 ret
= set2_mapping
[at_key
];
263 for (i
= 0; i
< ARRAY_SIZE (set2_e0_mapping
); i
++)
264 if (set2_e0_mapping
[i
].from
== at_key
)
266 ret
= set2_e0_mapping
[i
].to
;
277 grub_dprintf ("atkeyb", "Unknown key 0xe0+0x%02x from set %d\n",
278 at_key
, ps2_state
->current_set
);
280 grub_dprintf ("atkeyb", "Unknown key 0x%02x from set %d\n",
281 at_key
, ps2_state
->current_set
);
287 /* FIXME: This should become an interrupt service routine. For now
288 it's just used to catch events from control keys. */
290 grub_keyboard_isr (struct grub_ps2_state
*ps2_state
,
291 grub_keyboard_key_t key
, int is_break
)
296 case GRUB_KEYBOARD_KEY_LEFT_SHIFT
:
297 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_LSHIFT
;
299 case GRUB_KEYBOARD_KEY_RIGHT_SHIFT
:
300 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_RSHIFT
;
302 case GRUB_KEYBOARD_KEY_LEFT_CTRL
:
303 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_LCTRL
;
305 case GRUB_KEYBOARD_KEY_RIGHT_CTRL
:
306 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_RCTRL
;
308 case GRUB_KEYBOARD_KEY_RIGHT_ALT
:
309 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_RALT
;
311 case GRUB_KEYBOARD_KEY_LEFT_ALT
:
312 ps2_state
->at_keyboard_status
|= GRUB_TERM_STATUS_LALT
;
320 case GRUB_KEYBOARD_KEY_LEFT_SHIFT
:
321 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_LSHIFT
;
323 case GRUB_KEYBOARD_KEY_RIGHT_SHIFT
:
324 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_RSHIFT
;
326 case GRUB_KEYBOARD_KEY_LEFT_CTRL
:
327 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_LCTRL
;
329 case GRUB_KEYBOARD_KEY_RIGHT_CTRL
:
330 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_RCTRL
;
332 case GRUB_KEYBOARD_KEY_RIGHT_ALT
:
333 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_RALT
;
335 case GRUB_KEYBOARD_KEY_LEFT_ALT
:
336 ps2_state
->at_keyboard_status
&= ~GRUB_TERM_STATUS_LALT
;
343 /* If there is a key pending, return it; otherwise return GRUB_TERM_NO_KEY. */
345 grub_ps2_process_incoming_byte (struct grub_ps2_state
*ps2_state
,
351 code
= fetch_key (ps2_state
, at_key
, &is_break
);
353 return GRUB_TERM_NO_KEY
;
355 if (grub_keyboard_isr (ps2_state
, code
, is_break
))
356 return GRUB_TERM_NO_KEY
;
358 return GRUB_TERM_NO_KEY
;
359 #ifdef DEBUG_AT_KEYBOARD
360 grub_dprintf ("atkeyb", "Detected key 0x%x\n", code
);
364 case GRUB_KEYBOARD_KEY_CAPS_LOCK
:
365 ps2_state
->at_keyboard_status
^= GRUB_TERM_STATUS_CAPS
;
366 ps2_state
->led_status
^= KEYBOARD_LED_CAPS
;
368 #ifdef DEBUG_AT_KEYBOARD
369 grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(ps2_state
->at_keyboard_status
& GRUB_KEYBOARD_STATUS_CAPS_LOCK
));
371 return GRUB_TERM_NO_KEY
;
372 case GRUB_KEYBOARD_KEY_NUM_LOCK
:
373 ps2_state
->at_keyboard_status
^= GRUB_TERM_STATUS_NUM
;
374 ps2_state
->led_status
^= KEYBOARD_LED_NUM
;
376 #ifdef DEBUG_AT_KEYBOARD
377 grub_dprintf ("atkeyb", "num_lock = %d\n", !!(ps2_state
->at_keyboard_status
& GRUB_KEYBOARD_STATUS_NUM_LOCK
));
379 return GRUB_TERM_NO_KEY
;
380 case GRUB_KEYBOARD_KEY_SCROLL_LOCK
:
381 ps2_state
->at_keyboard_status
^= GRUB_TERM_STATUS_SCROLL
;
382 ps2_state
->led_status
^= KEYBOARD_LED_SCROLL
;
383 return GRUB_TERM_NO_KEY
;
385 return grub_term_map_key (code
, ps2_state
->at_keyboard_status
);