1 /*
2  * Driver for HID devices ported from CoreBoot
3  *
4  * Copyright (C) 2014 BALATON Zoltan
5  *
6  * This file was part of the libpayload project.
7  *
8  * Copyright (C) 2008-2010 coresystems GmbH
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "config.h"
35 #include "libopenbios/bindings.h"
36 #include <libc/string.h>
37 #include "libc/byteorder.h"
38 #include "libc/vsprintf.h"
39 #include "drivers/usb.h"
40 #include "usb.h"
41 
42 DECLARE_UNNAMED_NODE(usb_kbd, 0, sizeof(int));
43 
44 static void
keyboard_open(int * idx)45 keyboard_open(int *idx)
46 {
47 	RET(-1);
48 }
49 
50 static void
keyboard_close(int * idx)51 keyboard_close(int *idx)
52 {
53 }
54 
55 static void keyboard_read(void);
56 
57 NODE_METHODS( usb_kbd ) = {
58 	{ "open",		keyboard_open		},
59 	{ "close",		keyboard_close		},
60 	{ "read",               keyboard_read		},
61 };
62 
63 #ifdef CONFIG_DEBUG_USB
64 static const char *boot_protos[3] = { "(none)", "keyboard", "mouse" };
65 #endif
66 typedef enum { hid_proto_boot = 0, hid_proto_report = 1 } hid_proto;
67 enum { GET_REPORT = 0x1, GET_IDLE = 0x2, GET_PROTOCOL = 0x3, SET_REPORT =
68 		0x9, SET_IDLE = 0xa, SET_PROTOCOL = 0xb
69 };
70 
71 typedef union {
72 	struct {
73 		u8 modifiers;
74 		u8 repeats;
75 		u8 keys[6];
76 	};
77 	u8 buffer[8];
78 } usb_hid_keyboard_event_t;
79 
80 typedef struct {
81 	void* queue;
82 	hid_descriptor_t *descriptor;
83 
84 	usb_hid_keyboard_event_t previous;
85 	int lastkeypress;
86 	int repeat_delay;
87 } usbhid_inst_t;
88 
89 #define HID_INST(dev) ((usbhid_inst_t*)(dev)->data)
90 
91 static void
usb_hid_destroy(usbdev_t * dev)92 usb_hid_destroy (usbdev_t *dev)
93 {
94 	if (HID_INST(dev)->queue) {
95 		int i;
96 		for (i = 0; i <= dev->num_endp; i++) {
97 			if (dev->endpoints[i].endpoint == 0)
98 				continue;
99 			if (dev->endpoints[i].type != INTERRUPT)
100 				continue;
101 			if (dev->endpoints[i].direction != IN)
102 				continue;
103 			break;
104 		}
105 		dev->controller->destroy_intr_queue(
106 				&dev->endpoints[i], HID_INST(dev)->queue);
107 		HID_INST(dev)->queue = NULL;
108 	}
109 	free (dev->data);
110 }
111 
112 /* keybuffer is global to all USB keyboards */
113 static int keycount;
114 #define KEYBOARD_BUFFER_SIZE 16
115 static short keybuffer[KEYBOARD_BUFFER_SIZE];
116 
117 const char *countries[36][2] = {
118 	{ "unknown", "us" },
119 	{ "Arabic", "ae" },
120 	{ "Belgian", "be" },
121 	{ "Canadian-Bilingual", "ca" },
122 	{ "Canadian-French", "ca" },
123 	{ "Czech Republic", "cz" },
124 	{ "Danish", "dk" },
125 	{ "Finnish", "fi" },
126 	{ "French", "fr" },
127 	{ "German", "de" },
128 	{ "Greek", "gr" },
129 	{ "Hebrew", "il" },
130 	{ "Hungary", "hu" },
131 	{ "International (ISO)", "iso" },
132 	{ "Italian", "it" },
133 	{ "Japan (Katakana)", "jp" },
134 	{ "Korean", "us" },
135 	{ "Latin American", "us" },
136 	{ "Netherlands/Dutch", "nl" },
137 	{ "Norwegian", "no" },
138 	{ "Persian (Farsi)", "ir" },
139 	{ "Poland", "pl" },
140 	{ "Portuguese", "pt" },
141 	{ "Russia", "ru" },
142 	{ "Slovakia", "sl" },
143 	{ "Spanish", "es" },
144 	{ "Swedish", "se" },
145 	{ "Swiss/French", "ch" },
146 	{ "Swiss/German", "ch" },
147 	{ "Switzerland", "ch" },
148 	{ "Taiwan", "tw" },
149 	{ "Turkish-Q", "tr" },
150 	{ "UK", "uk" },
151 	{ "US", "us" },
152 	{ "Yugoslavia", "yu" },
153 	{ "Turkish-F", "tr" },
154 	/* 36 - 255: Reserved */
155 };
156 
157 
158 
159 struct layout_maps {
160 	const char *country;
161 	const short map[4][0x80];
162 };
163 
164 static const struct layout_maps *map;
165 
166 #define KEY_BREAK     0x101  /* Not on PC KBD */
167 #define KEY_DOWN      0x102  /* Down arrow key */
168 #define KEY_UP        0x103  /* Up arrow key */
169 #define KEY_LEFT      0x104  /* Left arrow key */
170 #define KEY_RIGHT     0x105  /* Right arrow key */
171 #define KEY_HOME      0x106  /* home key */
172 #define KEY_BACKSPACE 0x107  /* not on pc */
173 #define KEY_F0        0x108  /* function keys; 64 reserved */
174 #define KEY_F(n)      (KEY_F0 + (n))
175 
176 #define KEY_DC        0x14a  /* delete character */
177 #define KEY_IC        0x14b  /* insert char or enter ins mode */
178 
179 #define KEY_NPAGE     0x152  /* next page */
180 #define KEY_PPAGE     0x153  /* previous page */
181 
182 #define KEY_ENTER     0x157  /* enter or send (unreliable) */
183 
184 #define KEY_PRINT     0x15a  /* print/copy */
185 
186 #define KEY_END       0x166  /* end key */
187 
188 static const struct layout_maps keyboard_layouts[] = {
189 // #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
190 { .country = "us", .map = {
191 	{ /* No modifier */
192 	-1, -1, -1, -1, 'a', 'b', 'c', 'd',
193 	'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
194 	/* 0x10 */
195 	'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
196 	'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
197 	/* 0x20 */
198 	'3', '4', '5', '6', '7', '8', '9', '0',
199 	'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
200 	/* 0x30 */
201 	']', '\\', -1, ';', '\'', '`', ',', '.',
202 	'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
203 	/* 0x40 */
204 	KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
205 	KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
206 	/* 50 */
207 	KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
208 	KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
209 	/* 60 */
210 	KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
211 	-1, -1, -1, -1, -1, -1, -1, -1,
212 	/* 70 */
213 	-1, -1, -1, -1, -1, -1, -1, -1,
214 	-1, -1, -1, -1, -1, -1, -1, -1,
215 	 },
216 	{ /* Shift modifier */
217 	-1, -1, -1, -1, 'A', 'B', 'C', 'D',
218 	'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
219 	/* 0x10 */
220 	'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
221 	'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
222 	/* 0x20 */
223 	'#', '$', '%', '^', '&', '*', '(', ')',
224 	'\n', '\e', '\b', '\t', ' ', '_', '+', '{',
225 	/* 0x30 */
226 	'}', '|', -1, ':', '"', '~', '<', '>',
227 	'?', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
228 	/* 0x40 */
229 	KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
230 	KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
231 	/* 50 */
232 	KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
233 	KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
234 	/* 60 */
235 	KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
236 	-1, -1, -1, -1, -1, -1, -1, -1,
237 	/* 70 */
238 	-1, -1, -1, -1, -1, -1, -1, -1,
239 	-1, -1, -1, -1, -1, -1, -1, -1,
240 	 },
241 	{ /* Alt */
242 	-1, -1, -1, -1, 'a', 'b', 'c', 'd',
243 	'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
244 	/* 0x10 */
245 	'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
246 	'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
247 	/* 0x20 */
248 	'3', '4', '5', '6', '7', '8', '9', '0',
249 	'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
250 	/* 0x30 */
251 	']', '\\', -1, ';', '\'', '`', ',', '.',
252 	'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
253 	/* 0x40 */
254 	KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
255 	KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
256 	/* 50 */
257 	KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
258 	KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
259 	/* 60 */
260 	KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
261 	-1, -1, -1, -1, -1, -1, -1, -1,
262 	/* 70 */
263 	-1, -1, -1, -1, -1, -1, -1, -1,
264 	-1, -1, -1, -1, -1, -1, -1, -1,
265 	 },
266 	{ /* Shift+Alt modifier */
267 	-1, -1, -1, -1, 'A', 'B', 'C', 'D',
268 	'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
269 	/* 0x10 */
270 	'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
271 	'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
272 	/* 0x20 */
273 	'#', '$', '%', '^', '&', '*', '(', ')',
274 	'\n', '\e', '\b', '\t', ' ', '-', '=', '[',
275 	/* 0x30 */
276 	']', '\\', -1, ':', '\'', '`', ',', '.',
277 	'/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
278 	/* 0x40 */
279 	KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
280 	KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
281 	/* 50 */
282 	KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
283 	KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
284 	/* 60 */
285 	KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
286 	-1, -1, -1, -1, -1, -1, -1, -1,
287 	/* 70 */
288 	-1, -1, -1, -1, -1, -1, -1, -1,
289 	-1, -1, -1, -1, -1, -1, -1, -1,
290 	 }
291 }},
292 //#endif
293 };
294 
295 #define MOD_SHIFT    (1 << 0)
296 #define MOD_ALT      (1 << 1)
297 #define MOD_CTRL     (1 << 2)
298 
usb_hid_keyboard_queue(int ch)299 static void usb_hid_keyboard_queue(int ch) {
300 	/* ignore key presses if buffer full */
301 	if (keycount < KEYBOARD_BUFFER_SIZE)
302 		keybuffer[keycount++] = ch;
303 }
304 
305 #define KEYBOARD_REPEAT_MS	30
306 #define INITIAL_REPEAT_DELAY	10
307 #define REPEAT_DELAY		 2
308 
309 static void
usb_hid_process_keyboard_event(usbhid_inst_t * const inst,const usb_hid_keyboard_event_t * const current)310 usb_hid_process_keyboard_event(usbhid_inst_t *const inst,
311 		const usb_hid_keyboard_event_t *const current)
312 {
313 	const usb_hid_keyboard_event_t *const previous = &inst->previous;
314 
315 	int i, keypress = 0, modifiers = 0;
316 
317 	if (current->modifiers & 0x01) /* Left-Ctrl */   modifiers |= MOD_CTRL;
318 	if (current->modifiers & 0x02) /* Left-Shift */  modifiers |= MOD_SHIFT;
319 	if (current->modifiers & 0x04) /* Left-Alt */    modifiers |= MOD_ALT;
320 	if (current->modifiers & 0x08) /* Left-GUI */    ;
321 	if (current->modifiers & 0x10) /* Right-Ctrl */  modifiers |= MOD_CTRL;
322 	if (current->modifiers & 0x20) /* Right-Shift */ modifiers |= MOD_SHIFT;
323 	if (current->modifiers & 0x40) /* Right-AltGr */ modifiers |= MOD_ALT;
324 	if (current->modifiers & 0x80) /* Right-GUI */   ;
325 
326 	/* Did the event change at all? */
327 	if (inst->lastkeypress &&
328 			!memcmp(current, previous, sizeof(*current))) {
329 		/* No. Then it's a key repeat event. */
330 		if (inst->repeat_delay) {
331 			inst->repeat_delay--;
332 		} else {
333 			usb_hid_keyboard_queue(inst->lastkeypress);
334 			inst->repeat_delay = REPEAT_DELAY;
335 		}
336 
337 		return;
338 	}
339 
340 	inst->lastkeypress = 0;
341 
342 	for (i=0; i<6; i++) {
343 		int j;
344 		int skip = 0;
345 		// No more keys? skip
346 		if (current->keys[i] == 0)
347 			return;
348 
349 		for (j=0; j<6; j++) {
350 			if (current->keys[i] == previous->keys[j]) {
351 				skip = 1;
352 				break;
353 			}
354 		}
355 		if (skip)
356 			continue;
357 
358 
359 		/* Mask off MOD_CTRL */
360 		keypress = map->map[modifiers & 0x03][current->keys[i]];
361 
362 		if (modifiers & MOD_CTRL) {
363 			switch (keypress) {
364 			case 'a' ... 'z':
365 				keypress &= 0x1f;
366 				break;
367 			default:
368 				continue;
369 			}
370 		}
371 
372 		if (keypress == -1) {
373 			/* Debug: Print unknown keys */
374 			usb_debug ("usbhid: <%x> %x [ %x %x %x %x %x %x ] %d\n",
375 				current->modifiers, current->repeats,
376 			current->keys[0], current->keys[1],
377 			current->keys[2], current->keys[3],
378 			current->keys[4], current->keys[5], i);
379 
380 			/* Unknown key? Try next one in the queue */
381 			continue;
382 		}
383 
384 		usb_hid_keyboard_queue(keypress);
385 
386 		/* Remember for authentic key repeat */
387 		inst->lastkeypress = keypress;
388 		inst->repeat_delay = INITIAL_REPEAT_DELAY;
389 	}
390 }
391 
392 static void
usb_hid_poll(usbdev_t * dev)393 usb_hid_poll (usbdev_t *dev)
394 {
395 	usb_hid_keyboard_event_t current;
396 	const u8 *buf;
397 
398 	while ((buf=dev->controller->poll_intr_queue (HID_INST(dev)->queue))) {
399 		memcpy(&current.buffer, buf, 8);
400 		usb_hid_process_keyboard_event(HID_INST(dev), &current);
401 		HID_INST(dev)->previous = current;
402 	}
403 }
404 
405 static void
usb_hid_set_idle(usbdev_t * dev,interface_descriptor_t * interface,u16 duration)406 usb_hid_set_idle (usbdev_t *dev, interface_descriptor_t *interface, u16 duration)
407 {
408 	dev_req_t dr;
409 	dr.data_dir = host_to_device;
410 	dr.req_type = class_type;
411 	dr.req_recp = iface_recp;
412 	dr.bRequest = SET_IDLE;
413 	dr.wValue = __cpu_to_le16((duration >> 2) << 8);
414 	dr.wIndex = __cpu_to_le16(interface->bInterfaceNumber);
415 	dr.wLength = 0;
416 	dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
417 }
418 
419 static void
usb_hid_set_protocol(usbdev_t * dev,interface_descriptor_t * interface,hid_proto proto)420 usb_hid_set_protocol (usbdev_t *dev, interface_descriptor_t *interface, hid_proto proto)
421 {
422 	dev_req_t dr;
423 	dr.data_dir = host_to_device;
424 	dr.req_type = class_type;
425 	dr.req_recp = iface_recp;
426 	dr.bRequest = SET_PROTOCOL;
427 	dr.wValue = __cpu_to_le16(proto);
428 	dr.wIndex = __cpu_to_le16(interface->bInterfaceNumber);
429 	dr.wLength = 0;
430 	dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
431 }
432 
usb_hid_set_layout(const char * country)433 static int usb_hid_set_layout (const char *country)
434 {
435 	/* FIXME should be per keyboard */
436 	int i;
437 
438 	for (i=0; i<sizeof(keyboard_layouts)/sizeof(keyboard_layouts[0]); i++) {
439 		if (strncmp(keyboard_layouts[i].country, country,
440 					strlen(keyboard_layouts[i].country)))
441 			continue;
442 
443 		/* Found, changing keyboard layout */
444 		map = &keyboard_layouts[i];
445 		usb_debug("  Keyboard layout '%s'\n", map->country);
446 		return 0;
447 	}
448 
449 	usb_debug("  Keyboard layout '%s' not found, using '%s'\n",
450 			country, map->country);
451 
452 	/* Nothing found, not changed */
453 	return -1;
454 }
455 
456 void
usb_hid_init(usbdev_t * dev)457 usb_hid_init (usbdev_t *dev)
458 {
459 	configuration_descriptor_t *cd = (configuration_descriptor_t*)dev->configuration;
460 	interface_descriptor_t *interface = (interface_descriptor_t*)(((char *) cd) + cd->bLength);
461 
462 	if (interface->bInterfaceSubClass == hid_subclass_boot) {
463 		u8 countrycode = 0;
464 		usb_debug ("  supports boot interface..\n");
465 		usb_debug ("  it's a %s\n",
466 			boot_protos[interface->bInterfaceProtocol]);
467 		switch (interface->bInterfaceProtocol) {
468 		case hid_boot_proto_keyboard:
469 			dev->data = malloc (sizeof (usbhid_inst_t));
470 			if (!dev->data) {
471 				printk("Not enough memory for USB HID device.\n");
472 				return;
473                         }
474 			memset(&HID_INST(dev)->previous, 0x00,
475 			       sizeof(HID_INST(dev)->previous));
476 			usb_debug ("  configuring...\n");
477 			usb_hid_set_protocol(dev, interface, hid_proto_boot);
478 			usb_hid_set_idle(dev, interface, KEYBOARD_REPEAT_MS);
479 			usb_debug ("  activating...\n");
480 #if 0
481 			HID_INST (dev)->descriptor =
482 				(hid_descriptor_t *)
483 					get_descriptor(dev, gen_bmRequestType
484 					(device_to_host, standard_type, iface_recp),
485 					0x21, 0, 0);
486 			countrycode = HID_INST(dev)->descriptor->bCountryCode;
487 #endif
488 			/* 35 countries defined: */
489 			if (countrycode > 35)
490 				countrycode = 0;
491 			usb_debug ("  Keyboard has %s layout (country code %02x)\n",
492 					countries[countrycode][0], countrycode);
493 
494 			/* Set keyboard layout accordingly */
495 			usb_hid_set_layout(countries[countrycode][1]);
496 
497 			// only add here, because we only support boot-keyboard HID devices
498 			dev->destroy = usb_hid_destroy;
499 			dev->poll = usb_hid_poll;
500 			int i;
501 			for (i = 0; i <= dev->num_endp; i++) {
502 				if (dev->endpoints[i].endpoint == 0)
503 					continue;
504 				if (dev->endpoints[i].type != INTERRUPT)
505 					continue;
506 				if (dev->endpoints[i].direction != IN)
507 					continue;
508 				break;
509 			}
510 			usb_debug ("  found endpoint %x for interrupt-in\n", i);
511 			/* 20 buffers of 8 bytes, for every 10 msecs */
512 			HID_INST(dev)->queue = dev->controller->create_intr_queue (&dev->endpoints[i], 8, 20, 10);
513 			keycount = 0;
514 			usb_debug ("  configuration done.\n");
515 			break;
516 		default:
517 			usb_debug("NOTICE: HID interface protocol %d%s not supported.\n",
518 				 interface->bInterfaceProtocol,
519 				 (interface->bInterfaceProtocol == hid_boot_proto_mouse ?
520 				 " (USB mouse)" : ""));
521 			break;
522 		}
523 	}
524 }
525 
usbhid_havechar(void)526 static int usbhid_havechar (void)
527 {
528 	return (keycount != 0);
529 }
530 
usbhid_getchar(void)531 static int usbhid_getchar (void)
532 {
533 	short ret;
534 
535 	if (keycount == 0)
536 		return 0;
537 	ret = keybuffer[0];
538 	memmove(keybuffer, keybuffer + 1, --keycount);
539 
540 	return (int)ret;
541 }
542 
543 /* ( addr len -- actual ) */
keyboard_read(void)544 static void keyboard_read(void)
545 {
546 	char *addr;
547 	int len, key, i;
548 
549 	usb_poll();
550 	len=POP();
551 	addr=(char *)cell2pointer(POP());
552 
553 	for (i = 0; i < len; i++) {
554 	    if (!usbhid_havechar())
555 			break;
556 		key = usbhid_getchar();
557 		*addr++ = (char)key;
558 	}
559 	PUSH(i);
560 }
561 
ob_usb_hid_add_keyboard(const char * path)562 void ob_usb_hid_add_keyboard(const char *path)
563 {
564 	char name[128];
565 	phandle_t aliases;
566 
567 	fword("new-device");
568 
569 	push_str("keyboard");
570 	fword("device-name");
571 
572 	push_str("keyboard");
573 	fword("device-type");
574 
575 	snprintf(name, sizeof(name), "%s/keyboard", path);
576 	usb_debug("Found keyboard at %s\n", name);
577 
578 	BIND_NODE_METHODS(get_cur_dev(), usb_kbd);
579 
580 	fword("finish-device");
581 
582 	aliases = find_dev("/aliases");
583 	set_property(aliases, "keyboard", name, strlen(name) + 1);
584 }
585