1 /* Support for the HID Boot Protocol. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/term.h>
21 #include <grub/machine/machine.h>
22 #include <grub/machine/console.h>
23 #include <grub/time.h>
24 #include <grub/cpu/io.h>
25 #include <grub/misc.h>
26 #include <grub/term.h>
29 #include <grub/time.h>
32 static char keyboard_map
[128] =
34 '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd',
35 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
36 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
37 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
38 '3', '4', '5', '6', '7', '8', '9', '0',
39 '\n', GRUB_TERM_ESC
, GRUB_TERM_BACKSPACE
, GRUB_TERM_TAB
, ' ', '-', '=', '[',
40 ']', '\\', '#', ';', '\'', '`', ',', '.',
41 '/', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
42 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
43 '\0', '\0', GRUB_TERM_HOME
, GRUB_TERM_PPAGE
, GRUB_TERM_DC
, GRUB_TERM_END
, GRUB_TERM_NPAGE
, GRUB_TERM_RIGHT
,
44 GRUB_TERM_LEFT
, GRUB_TERM_DOWN
, GRUB_TERM_UP
47 static char keyboard_map_shift
[128] =
49 '\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D',
50 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
51 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
52 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
53 '#', '$', '%', '^', '&', '*', '(', ')',
54 '\n', '\0', '\0', '\0', ' ', '_', '+', '{',
55 '}', '|', '#', ':', '"', '`', '<', '>',
59 static grub_usb_device_t usbdev
;
61 /* Valid values for bmRequestType. See HID definition version 1.11 section
63 #define USB_HID_HOST_TO_DEVICE 0x21
64 #define USB_HID_DEVICE_TO_HOST 0xA1
66 /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
67 #define USB_HID_GET_REPORT 0x01
68 #define USB_HID_GET_IDLE 0x02
69 #define USB_HID_GET_PROTOCOL 0x03
70 #define USB_HID_SET_REPORT 0x09
71 #define USB_HID_SET_IDLE 0x0A
72 #define USB_HID_SET_PROTOCOL 0x0B
77 struct grub_usb_desc_device
*descdev
;
79 auto int usb_iterate (grub_usb_device_t dev
);
80 int usb_iterate (grub_usb_device_t dev
)
82 descdev
= &dev
->descdev
;
84 grub_dprintf ("usb_keyboard", "%x %x %x\n",
85 descdev
->class, descdev
->subclass
, descdev
->protocol
);
88 if (descdev
->class != 0x09
89 || descdev
->subclass
== 0x01
90 || descdev
->protocol
!= 0x02)
94 if (descdev
->class != 0 || descdev
->subclass
!= 0 || descdev
->protocol
!= 0)
97 grub_printf ("HID found!\n");
103 grub_usb_iterate (usb_iterate
);
105 /* Place the device in boot mode. */
106 grub_usb_control_msg (usbdev
, USB_HID_HOST_TO_DEVICE
, USB_HID_SET_PROTOCOL
,
109 /* Reports every time an event occurs and not more often than that. */
110 grub_usb_control_msg (usbdev
, USB_HID_HOST_TO_DEVICE
, USB_HID_SET_IDLE
,
115 grub_usb_keyboard_getreport (grub_usb_device_t dev
, grub_uint8_t
*report
)
117 return grub_usb_control_msg (dev
, USB_HID_DEVICE_TO_HOST
, USB_HID_GET_REPORT
,
118 0, 0, 8, (char *) report
);
124 grub_usb_keyboard_checkkey (void)
126 grub_uint8_t data
[8];
129 grub_uint64_t currtime
;
133 currtime
= grub_get_time_ms ();
137 err
= grub_usb_keyboard_getreport (usbdev
, data
);
139 /* Implement a timeout. */
140 if (grub_get_time_ms () > currtime
+ timeout
)
143 while (err
|| !data
[2]);
148 grub_dprintf ("usb_keyboard",
149 "report: 0x%02x 0x%02x 0x%02x 0x%02x"
150 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
151 data
[0], data
[1], data
[2], data
[3],
152 data
[4], data
[5], data
[6], data
[7]);
154 /* Check if the Control or Shift key was pressed. */
155 if (data
[0] & 0x01 || data
[0] & 0x10)
156 key
= keyboard_map
[data
[2]] - 'a' + 1;
157 else if (data
[0] & 0x02 || data
[0] & 0x20)
158 key
= keyboard_map_shift
[data
[2]];
160 key
= keyboard_map
[data
[2]];
163 grub_printf ("Unknown key 0x%x detected\n", data
[2]);
166 /* Wait until the key is released. */
167 while (!err
&& data
[2])
169 err
= grub_usb_control_msg (usbdev
, USB_HID_DEVICE_TO_HOST
,
170 USB_HID_GET_REPORT
, 0, 0,
171 sizeof (data
), (char *) data
);
172 grub_dprintf ("usb_keyboard",
173 "report2: 0x%02x 0x%02x 0x%02x 0x%02x"
174 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
175 data
[0], data
[1], data
[2], data
[3],
176 data
[4], data
[5], data
[6], data
[7]);
180 grub_errno
= GRUB_ERR_NONE
;
187 GRUB_HIDBOOT_REPEAT_NONE
,
188 GRUB_HIDBOOT_REPEAT_FIRST
,
190 } grub_usb_keyboard_repeat_t
;
193 grub_usb_keyboard_getkey (void)
197 grub_uint8_t data
[8];
198 grub_uint64_t currtime
;
200 static grub_usb_keyboard_repeat_t repeat
= GRUB_HIDBOOT_REPEAT_NONE
;
206 key
= grub_usb_keyboard_checkkey ();
209 data
[2] = !0; /* Or whatever. */
214 case GRUB_HIDBOOT_REPEAT_FIRST
:
217 case GRUB_HIDBOOT_REPEAT
:
225 /* Wait until the key is released. */
226 currtime
= grub_get_time_ms ();
227 while (!err
&& data
[2])
229 /* Implement a timeout. */
230 if (grub_get_time_ms () > currtime
+ timeout
)
237 grub_errno
= GRUB_ERR_NONE
;
241 err
= grub_usb_keyboard_getreport (usbdev
, data
);
252 grub_errno
= GRUB_ERR_NONE
;
258 grub_usb_keyboard_getkeystatus (void)
260 grub_uint8_t data
[8];
263 grub_uint64_t currtime
;
266 /* Set idle time to the minimum offered by the spec (4 milliseconds) so
267 that we can find out the current state. */
268 grub_usb_control_msg (usbdev
, USB_HID_HOST_TO_DEVICE
, USB_HID_SET_IDLE
,
271 currtime
= grub_get_time_ms ();
275 err
= grub_usb_keyboard_getreport (usbdev
, data
);
277 /* Implement a timeout. */
278 if (grub_get_time_ms () > currtime
+ timeout
)
281 while (err
|| !data
[0]);
283 /* Go back to reporting every time an event occurs and not more often than
285 grub_usb_control_msg (usbdev
, USB_HID_HOST_TO_DEVICE
, USB_HID_SET_IDLE
,
288 /* We allowed a while for modifiers to show up in the report, but it is
289 not an error if they never did. */
293 grub_dprintf ("usb_keyboard",
294 "report: 0x%02x 0x%02x 0x%02x 0x%02x"
295 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
296 data
[0], data
[1], data
[2], data
[3],
297 data
[4], data
[5], data
[6], data
[7]);
299 /* Check Shift, Control, and Alt status. */
300 if (data
[0] & 0x02 || data
[0] & 0x20)
301 mods
|= GRUB_TERM_STATUS_SHIFT
;
302 if (data
[0] & 0x01 || data
[0] & 0x10)
303 mods
|= GRUB_TERM_STATUS_CTRL
;
304 if (data
[0] & 0x04 || data
[0] & 0x40)
305 mods
|= GRUB_TERM_STATUS_ALT
;
307 grub_errno
= GRUB_ERR_NONE
;
312 static struct grub_term_input grub_usb_keyboard_term
=
314 .name
= "usb_keyboard",
315 .checkkey
= grub_usb_keyboard_checkkey
,
316 .getkey
= grub_usb_keyboard_getkey
,
317 .getkeystatus
= grub_usb_keyboard_getkeystatus
,
321 GRUB_MOD_INIT(usb_keyboard
)
324 grub_term_register_input ("usb_keyboard", &grub_usb_keyboard_term
);
327 GRUB_MOD_FINI(usb_keyboard
)
329 grub_term_unregister_input (&grub_usb_keyboard_term
);