Merge branch 'dmigen' into phcoder
[grub2/phcoder.git] / term / usb_keyboard.c
blobc827955aba859ddf8c136ef15c178846d28c1ae4
1 /* Support for the HID Boot Protocol. */
2 /*
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>
27 #include <grub/usb.h>
28 #include <grub/dl.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 '}', '|', '#', ':', '"', '`', '<', '>',
56 '?'
59 static grub_usb_device_t usbdev;
61 static void
62 grub_usb_hid (void)
64 struct grub_usb_desc_device *descdev;
66 auto int usb_iterate (grub_usb_device_t dev);
67 int usb_iterate (grub_usb_device_t dev)
69 descdev = &dev->descdev;
71 grub_dprintf ("usb_keyboard", "%x %x %x\n",
72 descdev->class, descdev->subclass, descdev->protocol);
74 #if 0
75 if (descdev->class != 0x09
76 || descdev->subclass == 0x01
77 || descdev->protocol != 0x02)
78 return 0;
79 #endif
81 if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0)
82 return 0;
84 grub_printf ("HID found!\n");
86 usbdev = dev;
88 return 1;
90 grub_usb_iterate (usb_iterate);
92 /* Place the device in boot mode. */
93 grub_usb_control_msg (usbdev, 0x21, 0x0B, 0, 0, 0, 0);
95 /* Reports every time an event occurs and not more often than that. */
96 grub_usb_control_msg (usbdev, 0x21, 0x0A, 0<<8, 0, 0, 0);
99 static grub_err_t
100 grub_usb_keyboard_getreport (grub_usb_device_t dev, unsigned char *report)
102 return grub_usb_control_msg (dev, (1 << 7) | (1 << 5) | 1, 0x01, 0, 0,
103 8, (char *) report);
108 static int
109 grub_usb_keyboard_checkkey (void)
111 unsigned char data[8];
112 int key;
113 int i;
114 grub_err_t err;
116 data[2] = 0;
117 for (i = 0; i < 50; i++)
119 /* Get_Report. */
120 err = grub_usb_keyboard_getreport (usbdev, data);
122 if (! err && data[2])
123 break;
126 if (err || !data[2])
127 return -1;
129 grub_dprintf ("usb_keyboard",
130 "report: 0x%02x 0x%02x 0x%02x 0x%02x"
131 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
132 data[0], data[1], data[2], data[3],
133 data[4], data[5], data[6], data[7]);
135 /* Check if the Control or Shift key was pressed. */
136 if (data[0] & 0x01 || data[0] & 0x10)
137 key = keyboard_map[data[2]] - 'a' + 1;
138 else if (data[0] & 0x02 || data[0] & 0x20)
139 key = keyboard_map_shift[data[2]];
140 else
141 key = keyboard_map[data[2]];
143 if (key == 0)
144 grub_printf ("Unknown key 0x%x detected\n", data[2]);
146 #if 0
147 /* Wait until the key is released. */
148 while (!err && data[2])
150 err = grub_usb_control_msg (usbdev, (1 << 7) | (1 << 5) | 1, 0x01, 0, 0,
151 sizeof (data), (char *) data);
152 grub_dprintf ("usb_keyboard",
153 "report2: 0x%02x 0x%02x 0x%02x 0x%02x"
154 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
155 data[0], data[1], data[2], data[3],
156 data[4], data[5], data[6], data[7]);
158 #endif
160 grub_errno = GRUB_ERR_NONE;
162 return key;
165 typedef enum
167 GRUB_HIDBOOT_REPEAT_NONE,
168 GRUB_HIDBOOT_REPEAT_FIRST,
169 GRUB_HIDBOOT_REPEAT
170 } grub_usb_keyboard_repeat_t;
172 static int
173 grub_usb_keyboard_getkey (void)
175 int key;
176 grub_err_t err;
177 unsigned char data[8];
178 grub_uint64_t currtime;
179 int timeout;
180 static grub_usb_keyboard_repeat_t repeat = GRUB_HIDBOOT_REPEAT_NONE;
182 again:
186 key = grub_usb_keyboard_checkkey ();
187 } while (key == -1);
189 data[2] = !0; /* Or whatever. */
190 err = 0;
192 switch (repeat)
194 case GRUB_HIDBOOT_REPEAT_FIRST:
195 timeout = 500;
196 break;
197 case GRUB_HIDBOOT_REPEAT:
198 timeout = 50;
199 break;
200 default:
201 timeout = 100;
202 break;
205 /* Wait until the key is released. */
206 currtime = grub_get_time_ms ();
207 while (!err && data[2])
209 /* Implement a timeout. */
210 if (grub_get_time_ms () > currtime + timeout)
212 if (repeat == 0)
213 repeat = 1;
214 else
215 repeat = 2;
217 grub_errno = GRUB_ERR_NONE;
218 return key;
221 err = grub_usb_keyboard_getreport (usbdev, data);
224 if (repeat)
226 repeat = 0;
227 goto again;
230 repeat = 0;
232 grub_errno = GRUB_ERR_NONE;
234 return key;
237 static struct grub_term_input grub_usb_keyboard_term =
239 .name = "usb_keyboard",
240 .checkkey = grub_usb_keyboard_checkkey,
241 .getkey = grub_usb_keyboard_getkey,
242 .next = 0
245 GRUB_MOD_INIT(usb_keyboard)
247 grub_usb_hid ();
248 grub_term_register_input ("usb_keyboard", &grub_usb_keyboard_term);
251 GRUB_MOD_FINI(usb_keyboard)
253 grub_term_unregister_input (&grub_usb_keyboard_term);