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 "biosvar.h" // GET_GLOBAL
8 #include "config.h" // CONFIG_*
9 #include "output.h" // dprintf
10 #include "ps2port.h" // ATKBD_CMD_GETID
11 #include "usb.h" // usb_ctrlrequest
12 #include "usb-hid.h" // usb_keyboard_setup
13 #include "util.h" // process_key
15 struct usb_pipe *keyboard_pipe VARFSEG;
16 struct usb_pipe *mouse_pipe VARFSEG;
19 /****************************************************************
21 ****************************************************************/
23 // Send USB HID protocol message.
25 set_protocol(struct usb_pipe *pipe, u16 val)
27 struct usb_ctrlrequest req;
28 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
29 req.bRequest = HID_REQ_SET_PROTOCOL;
33 return usb_send_default_control(pipe, &req, NULL);
36 // Send USB HID SetIdle request.
38 set_idle(struct usb_pipe *pipe, int ms)
40 struct usb_ctrlrequest req;
41 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
42 req.bRequest = HID_REQ_SET_IDLE;
43 req.wValue = (ms/4)<<8;
46 return usb_send_default_control(pipe, &req, NULL);
49 #define KEYREPEATWAITMS 500
50 #define KEYREPEATMS 33
53 usb_kbd_setup(struct usbdevice_s *usbdev
54 , struct usb_endpoint_descriptor *epdesc)
56 if (! CONFIG_USB_KEYBOARD)
59 // XXX - this enables the first found keyboard (could be random)
62 if (epdesc->wMaxPacketSize != 8)
65 // Enable "boot" protocol.
66 int ret = set_protocol(usbdev->defpipe, 0);
69 // Periodically send reports to enable key repeat.
70 ret = set_idle(usbdev->defpipe, KEYREPEATMS);
74 keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
78 dprintf(1, "USB keyboard initialized\n");
83 usb_mouse_setup(struct usbdevice_s *usbdev
84 , struct usb_endpoint_descriptor *epdesc)
86 if (! CONFIG_USB_MOUSE)
89 // XXX - this enables the first found mouse (could be random)
92 if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
95 // Enable "boot" protocol.
96 int ret = set_protocol(usbdev->defpipe, 0);
100 mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
104 dprintf(1, "USB mouse initialized\n");
108 // Initialize a found USB HID device (if applicable).
110 usb_hid_setup(struct usbdevice_s *usbdev)
112 if (! CONFIG_USB_KEYBOARD && ! CONFIG_USB_MOUSE)
114 dprintf(2, "usb_hid_setup %p\n", usbdev->defpipe);
116 struct usb_interface_descriptor *iface = usbdev->iface;
117 if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
118 // Doesn't support boot protocol.
121 // Find intr in endpoint.
122 struct usb_endpoint_descriptor *epdesc = usb_find_desc(
123 usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
125 dprintf(1, "No usb hid intr in?\n");
129 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
130 return usb_kbd_setup(usbdev, epdesc);
131 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
132 return usb_mouse_setup(usbdev, epdesc);
137 /****************************************************************
139 ****************************************************************/
141 // Mapping from USB key id to ps2 key sequence.
142 static u16 KeyToScanCode[] VAR16 = {
143 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
144 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
145 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
146 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
147 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
148 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
149 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
150 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
151 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
152 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
153 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
154 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
155 0x0048, 0x0049, 0x0052, 0x0053
158 // Mapping from USB modifier id to ps2 key sequence.
159 static u16 ModifierToScanCode[] VAR16 = {
160 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
161 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
164 #define RELEASEBIT 0x80
166 // Format of USB keyboard event data
173 // Translate data from KeyToScanCode[] to calls to process_key().
182 process_key(0x1d | (keys & RELEASEBIT));
183 process_key(0x45 | (keys & RELEASEBIT));
191 // Handle a USB key press/release event.
193 procscankey(u8 key, u8 flags)
195 if (key >= ARRAY_SIZE(KeyToScanCode))
197 u16 keys = GET_GLOBAL(KeyToScanCode[key]);
199 prockeys(keys | flags);
202 // Handle a USB modifier press/release event.
204 procmodkey(u8 mods, u8 flags)
209 // Modifier key change.
210 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
225 struct usbkeyinfo LastUSBkey VARLOW;
227 // Process USB keyboard data.
229 handle_key(struct keyevent *data)
231 dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
234 struct usbkeyinfo old;
235 old.data = GET_LOW(LastUSBkey.data);
237 // Check for keys no longer pressed.
240 for (i=0; i<ARRAY_SIZE(old.keys); i++) {
241 u8 key = old.keys[i];
246 if (j>=ARRAY_SIZE(data->keys)) {
248 procscankey(key, RELEASEBIT);
249 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
250 // Last pressed key released - disable repeat.
251 old.repeatcount = 0xff;
254 if (data->keys[j] == key) {
255 // Key still pressed.
257 old.keys[addpos++] = key;
262 procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
265 procmodkey(data->modifiers & ~old.modifiers, 0);
266 old.modifiers = data->modifiers;
267 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
268 u8 key = data->keys[i];
273 old.keys[addpos++] = key;
274 old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
276 if (addpos < ARRAY_SIZE(old.keys))
277 old.keys[addpos] = 0;
279 // Check for key repeat event.
281 if (!old.repeatcount)
282 procscankey(old.keys[addpos-1], 0);
283 else if (old.repeatcount != 0xff)
288 SET_LOW(LastUSBkey.data, old.data);
291 // Check if a USB keyboard event is pending and process it if so.
295 if (! CONFIG_USB_KEYBOARD)
297 struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
302 struct keyevent data;
303 int ret = usb_poll_intr(pipe, &data);
310 // Test if USB keyboard is active.
314 if (! CONFIG_USB_KEYBOARD)
316 return GET_GLOBAL(keyboard_pipe) != NULL;
319 // Handle a ps2 style keyboard command.
321 usb_kbd_command(int command, u8 *param)
323 if (! CONFIG_USB_KEYBOARD)
325 dprintf(9, "usb keyboard cmd=%x\n", command);
327 case ATKBD_CMD_GETID:
328 // Return the id of a standard AT keyboard.
338 /****************************************************************
340 ****************************************************************/
342 // Format of USB mouse event data
349 // Process USB mouse data.
351 handle_mouse(struct mouseevent *data)
353 dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
355 s8 x = data->x, y = -data->y;
356 u8 flag = ((data->buttons & 0x7) | (1<<3)
357 | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
363 // Check if a USB mouse event is pending and process it if so.
365 usb_check_mouse(void)
367 if (! CONFIG_USB_MOUSE)
369 struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
374 struct mouseevent data;
375 int ret = usb_poll_intr(pipe, &data);
382 // Test if USB mouse is active.
384 usb_mouse_active(void)
386 if (! CONFIG_USB_MOUSE)
388 return GET_GLOBAL(mouse_pipe) != NULL;
391 // Handle a ps2 style mouse command.
393 usb_mouse_command(int command, u8 *param)
395 if (! CONFIG_USB_MOUSE)
397 dprintf(9, "usb mouse cmd=%x\n", command);
399 case PSMOUSE_CMD_ENABLE:
400 case PSMOUSE_CMD_DISABLE:
401 case PSMOUSE_CMD_SETSCALE11:
403 case PSMOUSE_CMD_SETSCALE21:
404 case PSMOUSE_CMD_SETRATE:
405 case PSMOUSE_CMD_SETRES:
408 case PSMOUSE_CMD_RESET_BAT:
409 case PSMOUSE_CMD_GETID:
410 // Return the id of a standard AT mouse.
415 case PSMOUSE_CMD_GETINFO:
426 // Check for USB events pending - called periodically from timer interrupt.
428 usb_check_event(void)