1 // Code for handling USB Human Interface Devices (HID).
3 // Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 #include "util.h" // dprintf
8 #include "usb-hid.h" // usb_keyboard_setup
9 #include "config.h" // CONFIG_*
10 #include "usb.h" // usb_ctrlrequest
11 #include "biosvar.h" // GET_GLOBAL
12 #include "ps2port.h" // ATKBD_CMD_GETID
14 struct usb_pipe *keyboard_pipe VAR16VISIBLE;
15 struct usb_pipe *mouse_pipe VAR16VISIBLE;
18 /****************************************************************
20 ****************************************************************/
22 // Send USB HID protocol message.
24 set_protocol(struct usb_pipe *pipe, u16 val)
26 struct usb_ctrlrequest req;
27 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
28 req.bRequest = HID_REQ_SET_PROTOCOL;
32 return send_default_control(pipe, &req, NULL);
35 // Send USB HID SetIdle request.
37 set_idle(struct usb_pipe *pipe, int ms)
39 struct usb_ctrlrequest req;
40 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
41 req.bRequest = HID_REQ_SET_IDLE;
42 req.wValue = (ms/4)<<8;
45 return send_default_control(pipe, &req, NULL);
48 #define KEYREPEATWAITMS 500
49 #define KEYREPEATMS 33
52 usb_kbd_init(struct usbdevice_s *usbdev
53 , struct usb_endpoint_descriptor *epdesc)
55 if (! CONFIG_USB_KEYBOARD)
58 // XXX - this enables the first found keyboard (could be random)
61 if (epdesc->wMaxPacketSize != 8)
64 // Enable "boot" protocol.
65 int ret = set_protocol(usbdev->defpipe, 0);
68 // Periodically send reports to enable key repeat.
69 ret = set_idle(usbdev->defpipe, KEYREPEATMS);
73 keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
77 dprintf(1, "USB keyboard initialized\n");
82 usb_mouse_init(struct usbdevice_s *usbdev
83 , struct usb_endpoint_descriptor *epdesc)
85 if (! CONFIG_USB_MOUSE)
88 // XXX - this enables the first found mouse (could be random)
91 if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
94 // Enable "boot" protocol.
95 int ret = set_protocol(usbdev->defpipe, 0);
99 mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
103 dprintf(1, "USB mouse initialized\n");
107 // Initialize a found USB HID device (if applicable).
109 usb_hid_init(struct usbdevice_s *usbdev)
111 if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
113 dprintf(2, "usb_hid_init %p\n", usbdev->defpipe);
115 struct usb_interface_descriptor *iface = usbdev->iface;
116 if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
117 // Doesn't support boot protocol.
120 // Find intr in endpoint.
121 struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
122 usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
124 dprintf(1, "No usb hid intr in?\n");
128 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
129 return usb_kbd_init(usbdev, epdesc);
130 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
131 return usb_mouse_init(usbdev, epdesc);
136 /****************************************************************
138 ****************************************************************/
140 // Mapping from USB key id to ps2 key sequence.
141 static u16 KeyToScanCode[] VAR16 = {
142 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
143 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
144 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
145 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
146 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
147 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
148 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
149 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
150 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
151 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
152 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
153 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
154 0x0048, 0x0049, 0x0052, 0x0053
157 // Mapping from USB modifier id to ps2 key sequence.
158 static u16 ModifierToScanCode[] VAR16 = {
159 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
160 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
163 #define RELEASEBIT 0x80
165 // Format of USB keyboard event data
172 // Translate data from KeyToScanCode[] to calls to process_key().
181 process_key(0x1d | (keys & RELEASEBIT));
182 process_key(0x45 | (keys & RELEASEBIT));
190 // Handle a USB key press/release event.
192 procscankey(u8 key, u8 flags)
194 if (key >= ARRAY_SIZE(KeyToScanCode))
196 u16 keys = GET_GLOBAL(KeyToScanCode[key]);
198 prockeys(keys | flags);
201 // Handle a USB modifier press/release event.
203 procmodkey(u8 mods, u8 flags)
208 // Modifier key change.
209 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
224 struct usbkeyinfo LastUSBkey VARLOW;
226 // Process USB keyboard data.
228 handle_key(struct keyevent *data)
230 dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
233 struct usbkeyinfo old;
234 old.data = GET_LOW(LastUSBkey.data);
236 // Check for keys no longer pressed.
239 for (i=0; i<ARRAY_SIZE(old.keys); i++) {
240 u8 key = old.keys[i];
245 if (j>=ARRAY_SIZE(data->keys)) {
247 procscankey(key, RELEASEBIT);
248 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
249 // Last pressed key released - disable repeat.
250 old.repeatcount = 0xff;
253 if (data->keys[j] == key) {
254 // Key still pressed.
256 old.keys[addpos++] = key;
261 procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
264 procmodkey(data->modifiers & ~old.modifiers, 0);
265 old.modifiers = data->modifiers;
266 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
267 u8 key = data->keys[i];
272 old.keys[addpos++] = key;
273 old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
275 if (addpos < ARRAY_SIZE(old.keys))
276 old.keys[addpos] = 0;
278 // Check for key repeat event.
280 if (!old.repeatcount)
281 procscankey(old.keys[addpos-1], 0);
282 else if (old.repeatcount != 0xff)
287 SET_LOW(LastUSBkey.data, old.data);
290 // Check if a USB keyboard event is pending and process it if so.
294 if (! CONFIG_USB_KEYBOARD)
296 struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
301 struct keyevent data;
302 int ret = usb_poll_intr(pipe, &data);
309 // Test if USB keyboard is active.
313 if (! CONFIG_USB_KEYBOARD)
315 return GET_GLOBAL(keyboard_pipe) != NULL;
318 // Handle a ps2 style keyboard command.
320 usb_kbd_command(int command, u8 *param)
322 if (! CONFIG_USB_KEYBOARD)
324 dprintf(9, "usb keyboard cmd=%x\n", command);
326 case ATKBD_CMD_GETID:
327 // Return the id of a standard AT keyboard.
337 /****************************************************************
339 ****************************************************************/
341 // Format of USB mouse event data
348 // Process USB mouse data.
350 handle_mouse(struct mouseevent *data)
352 dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
354 s8 x = data->x, y = -data->y;
355 u8 flag = ((data->buttons & 0x7) | (1<<3)
356 | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
362 // Check if a USB mouse event is pending and process it if so.
364 usb_check_mouse(void)
366 if (! CONFIG_USB_MOUSE)
368 struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
373 struct mouseevent data;
374 int ret = usb_poll_intr(pipe, &data);
381 // Test if USB mouse is active.
383 usb_mouse_active(void)
385 if (! CONFIG_USB_MOUSE)
387 return GET_GLOBAL(mouse_pipe) != NULL;
390 // Handle a ps2 style mouse command.
392 usb_mouse_command(int command, u8 *param)
394 if (! CONFIG_USB_MOUSE)
396 dprintf(9, "usb mouse cmd=%x\n", command);
398 case PSMOUSE_CMD_ENABLE:
399 case PSMOUSE_CMD_DISABLE:
400 case PSMOUSE_CMD_SETSCALE11:
402 case PSMOUSE_CMD_SETSCALE21:
403 case PSMOUSE_CMD_SETRATE:
404 case PSMOUSE_CMD_SETRES:
407 case PSMOUSE_CMD_RESET_BAT:
408 case PSMOUSE_CMD_GETID:
409 // Return the id of a standard AT mouse.
414 case PSMOUSE_CMD_GETINFO:
425 // Check for USB events pending - called periodically from timer interrupt.
427 usb_check_event(void)