2 * This file is part of the libpayload project.
4 * Copyright (C) 2008-2010 coresystems GmbH
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 enum { hid_subclass_none = 0, hid_subclass_boot = 1 };
36 typedef enum { hid_proto_boot = 0, hid_proto_report = 1 } hid_proto;
37 enum { hid_boot_proto_none = 0, hid_boot_proto_keyboard =
38 1, hid_boot_proto_mouse = 2
40 static const char *boot_protos[3] = { "(none)", "keyboard", "mouse" };
41 enum { GET_REPORT = 0x1, GET_IDLE = 0x2, GET_PROTOCOL = 0x3, SET_REPORT =
42 0x9, SET_IDLE = 0xa, SET_PROTOCOL = 0xb
46 usb_hid_destroy (usbdev_t *dev)
53 hid_descriptor_t *descriptor;
56 #define HID_INST(dev) ((usbhid_inst_t*)(dev)->data)
58 /* keybuffer is global to all USB keyboards */
60 #define KEYBOARD_BUFFER_SIZE 16
61 static short keybuffer[KEYBOARD_BUFFER_SIZE];
63 const char *countries[36][2] = {
64 { "not supported", "us" },
67 { "Canadian-Bilingual", "ca" },
68 { "Canadian-French", "ca" },
69 { "Czech Republic", "cz" },
77 { "International (ISO)", "iso" },
79 { "Japan (Katakana)", "jp" },
81 { "Latin American", "us" },
82 { "Netherlands/Dutch", "nl" },
83 { "Norwegian", "no" },
84 { "Persian (Farsi)", "ir" },
86 { "Portuguese", "pt" },
91 { "Swiss/French", "ch" },
92 { "Swiss/German", "ch" },
93 { "Switzerland", "ch" },
95 { "Turkish-Q", "tr" },
98 { "Yugoslavia", "yu" },
99 { "Turkish-F", "tr" },
100 /* 36 - 255: Reserved */
107 const short map[4][0x80];
110 static const struct layout_maps *map;
112 static const struct layout_maps keyboard_layouts[] = {
113 // #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
114 { .country = "us", .map = {
116 -1, -1, -1, -1, 'a', 'b', 'c', 'd',
117 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
119 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
120 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
122 '3', '4', '5', '6', '7', '8', '9', '0',
123 '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
125 ']', '\\', -1, ';', '\'', '`', ',', '.',
126 '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
128 KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
129 KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
131 KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
132 KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
134 KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
135 -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1,
138 -1, -1, -1, -1, -1, -1, -1, -1,
140 { /* Shift modifier */
141 -1, -1, -1, -1, 'A', 'B', 'C', 'D',
142 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
144 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
145 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
147 '#', '$', '%', '^', '&', '*', '(', ')',
148 '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
150 ']', '\\', -1, ':', '\'', '`', ',', '.',
151 '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
153 KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
154 KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
156 KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
157 KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
159 KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
160 -1, -1, -1, -1, -1, -1, -1, -1,
162 -1, -1, -1, -1, -1, -1, -1, -1,
163 -1, -1, -1, -1, -1, -1, -1, -1,
166 -1, -1, -1, -1, 'a', 'b', 'c', 'd',
167 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
169 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
170 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
172 '3', '4', '5', '6', '7', '8', '9', '0',
173 '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
175 ']', '\\', -1, ';', '\'', '`', ',', '.',
176 '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
178 KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
179 KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
181 KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
182 KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
184 KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
185 -1, -1, -1, -1, -1, -1, -1, -1,
187 -1, -1, -1, -1, -1, -1, -1, -1,
188 -1, -1, -1, -1, -1, -1, -1, -1,
190 { /* Shift+Alt modifier */
191 -1, -1, -1, -1, 'A', 'B', 'C', 'D',
192 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
194 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
195 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
197 '#', '$', '%', '^', '&', '*', '(', ')',
198 '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
200 ']', '\\', -1, ':', '\'', '`', ',', '.',
201 '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
203 KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
204 KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
206 KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
207 KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
209 KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
210 -1, -1, -1, -1, -1, -1, -1, -1,
212 -1, -1, -1, -1, -1, -1, -1, -1,
213 -1, -1, -1, -1, -1, -1, -1, -1,
219 #define MOD_SHIFT (1 << 0)
220 #define MOD_ALT (1 << 1)
221 #define MOD_CTRL (1 << 2)
223 static void usb_hid_keyboard_queue(int ch) {
224 /* ignore key presses if buffer full */
225 if (keycount < KEYBOARD_BUFFER_SIZE)
226 keybuffer[keycount++] = ch;
236 } usb_hid_keyboard_event_t;
238 #define KEYBOARD_REPEAT_MS 30
239 #define INITIAL_REPEAT_DELAY 10
240 #define REPEAT_DELAY 2
243 usb_hid_process_keyboard_event(usb_hid_keyboard_event_t *current,
244 usb_hid_keyboard_event_t *previous)
246 int i, keypress = 0, modifiers = 0;
247 static int lastkeypress = 0, repeat_delay = INITIAL_REPEAT_DELAY;
249 if (current->modifiers & 0x01) /* Left-Ctrl */ modifiers |= MOD_CTRL;
250 if (current->modifiers & 0x02) /* Left-Shift */ modifiers |= MOD_SHIFT;
251 if (current->modifiers & 0x04) /* Left-Alt */ modifiers |= MOD_ALT;
252 if (current->modifiers & 0x08) /* Left-GUI */ ;
253 if (current->modifiers & 0x10) /* Right-Ctrl */ modifiers |= MOD_CTRL;
254 if (current->modifiers & 0x20) /* Right-Shift */ modifiers |= MOD_SHIFT;
255 if (current->modifiers & 0x40) /* Right-AltGr */ modifiers |= MOD_ALT;
256 if (current->modifiers & 0x80) /* Right-GUI */ ;
258 if ((current->modifiers & 0x05) && ((current->keys[0] == 0x4c) ||
259 (current->keys[0]==0x63))) {
260 /* vulcan nerve pinch */
265 /* Did the event change at all? */
266 if (lastkeypress && !memcmp(current, previous, sizeof(usb_hid_keyboard_event_t))) {
267 /* No. Then it's a key repeat event. */
271 usb_hid_keyboard_queue(lastkeypress);
272 repeat_delay = REPEAT_DELAY;
280 for (i=0; i<6; i++) {
283 // No more keys? skip
284 if (current->keys[i] == 0)
287 for (j=0; j<6; j++) {
288 if (current->keys[i] == previous->keys[j]) {
297 /* Mask off MOD_CTRL */
298 keypress = map->map[modifiers & 0x03][current->keys[i]];
300 if (modifiers & MOD_CTRL) {
310 if (keypress == -1) {
311 /* Debug: Print unknown keys */
312 debug ("usbhid: <%x> %x [ %x %x %x %x %x %x ] %d\n",
313 current->modifiers, current->repeats,
314 current->keys[0], current->keys[1],
315 current->keys[2], current->keys[3],
316 current->keys[4], current->keys[5], i);
318 /* Unknown key? Try next one in the queue */
322 usb_hid_keyboard_queue(keypress);
324 /* Remember for authentic key repeat */
325 lastkeypress = keypress;
326 repeat_delay = INITIAL_REPEAT_DELAY;
331 usb_hid_poll (usbdev_t *dev)
333 usb_hid_keyboard_event_t current;
334 static usb_hid_keyboard_event_t previous = {
335 .buffer = { 0, 0, 0, 0, 0, 0, 0, 0}
338 while ((buf=dev->controller->poll_intr_queue (HID_INST(dev)->queue))) {
339 memcpy(¤t.buffer, buf, 8);
340 usb_hid_process_keyboard_event(¤t, &previous);
346 usb_hid_set_idle (usbdev_t *dev, interface_descriptor_t *interface, u16 duration)
349 dr.data_dir = host_to_device;
350 dr.req_type = class_type;
351 dr.req_recp = iface_recp;
352 dr.bRequest = SET_IDLE;
353 dr.wValue = (duration >> 2) << 8;
354 dr.wIndex = interface->bInterfaceNumber;
356 dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
360 usb_hid_set_protocol (usbdev_t *dev, interface_descriptor_t *interface, hid_proto proto)
363 dr.data_dir = host_to_device;
364 dr.req_type = class_type;
365 dr.req_recp = iface_recp;
366 dr.bRequest = SET_PROTOCOL;
368 dr.wIndex = interface->bInterfaceNumber;
370 dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
373 static struct console_input_driver cons = {
374 .havekey = usbhid_havechar,
375 .getchar = usbhid_getchar
379 static int usb_hid_set_layout (const char *country)
381 /* FIXME should be per keyboard */
384 for (i=0; i<ARRAY_SIZE(keyboard_layouts); i++) {
385 if (strncmp(keyboard_layouts[i].country, country,
386 strlen(keyboard_layouts[i].country)))
389 /* Found, changing keyboard layout */
390 map = &keyboard_layouts[i];
391 printf(" Keyboard layout '%s'\n", map->country);
395 printf(" Keyboard layout '%s' not found, using '%s'\n",
396 country, map->country);
398 /* Nothing found, not changed */
403 usb_hid_init (usbdev_t *dev)
406 static int installed = 0;
409 console_add_input_driver (&cons);
412 configuration_descriptor_t *cd = (configuration_descriptor_t*)dev->configuration;
413 interface_descriptor_t *interface = (interface_descriptor_t*)(((char *) cd) + cd->bLength);
415 if (interface->bInterfaceSubClass == hid_subclass_boot) {
417 debug (" supports boot interface..\n");
418 debug (" it's a %s\n",
419 boot_protos[interface->bInterfaceProtocol]);
420 switch (interface->bInterfaceProtocol) {
421 case hid_boot_proto_keyboard:
422 dev->data = malloc (sizeof (usbhid_inst_t));
424 usb_fatal("Not enough memory for USB HID device.\n");
425 debug (" configuring...\n");
426 usb_hid_set_protocol(dev, interface, hid_proto_boot);
427 usb_hid_set_idle(dev, interface, KEYBOARD_REPEAT_MS);
428 debug (" activating...\n");
430 HID_INST (dev)->descriptor =
432 get_descriptor(dev, gen_bmRequestType
433 (device_to_host, standard_type, iface_recp),
435 countrycode = HID_INST(dev)->descriptor->bCountryCode;
436 /* 35 countries defined: */
437 if (countrycode > 35)
439 debug (" Keyboard has %s layout (country code %02x)\n",
440 countries[countrycode][0], countrycode);
442 /* Set keyboard layout accordingly */
443 usb_hid_set_layout(countries[countrycode][1]);
445 // only add here, because we only support boot-keyboard HID devices
446 dev->destroy = usb_hid_destroy;
447 dev->poll = usb_hid_poll;
449 for (i = 0; i <= dev->num_endp; i++) {
450 if (dev->endpoints[i].endpoint == 0)
452 if (dev->endpoints[i].type != INTERRUPT)
454 if (dev->endpoints[i].direction != IN)
458 debug (" found endpoint %x for interrupt-in\n", i);
459 /* 20 buffers of 8 bytes, for every 10 msecs */
460 HID_INST(dev)->queue = dev->controller->create_intr_queue (&dev->endpoints[i], 8, 20, 10);
462 debug (" configuration done.\n");
464 case hid_boot_proto_mouse:
465 debug("NOTICE: USB mice are not supported.\n");
471 int usbhid_havechar (void)
473 return (keycount != 0);
476 int usbhid_getchar (void)
483 memmove(keybuffer, keybuffer + 1, --keycount);