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 usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
54 if (! CONFIG_USB_KEYBOARD)
57 // XXX - this enables the first found keyboard (could be random)
60 if (epdesc->wMaxPacketSize != 8)
63 // Enable "boot" protocol.
64 int ret = set_protocol(pipe, 0);
67 // Periodically send reports to enable key repeat.
68 ret = set_idle(pipe, KEYREPEATMS);
72 keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
76 dprintf(1, "USB keyboard initialized\n");
81 usb_mouse_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
83 if (! CONFIG_USB_MOUSE)
86 // XXX - this enables the first found mouse (could be random)
89 if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
92 // Enable "boot" protocol.
93 int ret = set_protocol(pipe, 0);
97 mouse_pipe = alloc_intr_pipe(pipe, epdesc);
101 dprintf(1, "USB mouse initialized\n");
105 // Initialize a found USB HID device (if applicable).
107 usb_hid_init(struct usb_pipe *pipe
108 , struct usb_interface_descriptor *iface, int imax)
110 if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
112 dprintf(2, "usb_hid_init %p\n", pipe);
114 if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
115 // Doesn't support boot protocol.
118 // Find intr in endpoint.
119 struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
120 iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
122 dprintf(1, "No usb hid intr in?\n");
126 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
127 return usb_kbd_init(pipe, epdesc);
128 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
129 return usb_mouse_init(pipe, epdesc);
136 if (CONFIG_USB_KEYBOARD)
137 keyboard_pipe = NULL;
138 if (CONFIG_USB_MOUSE)
143 /****************************************************************
145 ****************************************************************/
147 // Mapping from USB key id to ps2 key sequence.
148 static u16 KeyToScanCode[] VAR16 = {
149 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
150 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
151 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
152 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
153 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
154 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
155 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
156 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
157 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
158 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
159 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
160 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
161 0x0048, 0x0049, 0x0052, 0x0053
164 // Mapping from USB modifier id to ps2 key sequence.
165 static u16 ModifierToScanCode[] VAR16 = {
166 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
167 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
170 #define RELEASEBIT 0x80
172 // Format of USB keyboard event data
179 // Translate data from KeyToScanCode[] to calls to process_key().
188 process_key(0x1d | (keys & RELEASEBIT));
189 process_key(0x45 | (keys & RELEASEBIT));
197 // Handle a USB key press/release event.
199 procscankey(u8 key, u8 flags)
201 if (key >= ARRAY_SIZE(KeyToScanCode))
203 u16 keys = GET_GLOBAL(KeyToScanCode[key]);
205 prockeys(keys | flags);
208 // Handle a USB modifier press/release event.
210 procmodkey(u8 mods, u8 flags)
215 // Modifier key change.
216 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
221 // Process USB keyboard data.
223 handle_key(struct keyevent *data)
225 dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
228 u16 ebda_seg = get_ebda_seg();
229 struct usbkeyinfo old;
230 old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
232 // Check for keys no longer pressed.
235 for (i=0; i<ARRAY_SIZE(old.keys); i++) {
236 u8 key = old.keys[i];
241 if (j>=ARRAY_SIZE(data->keys)) {
243 procscankey(key, RELEASEBIT);
244 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
245 // Last pressed key released - disable repeat.
246 old.repeatcount = 0xff;
249 if (data->keys[j] == key) {
250 // Key still pressed.
252 old.keys[addpos++] = key;
257 procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
260 procmodkey(data->modifiers & ~old.modifiers, 0);
261 old.modifiers = data->modifiers;
262 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
263 u8 key = data->keys[i];
268 old.keys[addpos++] = key;
269 old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
271 if (addpos < ARRAY_SIZE(old.keys))
272 old.keys[addpos] = 0;
274 // Check for key repeat event.
276 if (!old.repeatcount)
277 procscankey(old.keys[addpos-1], 0);
278 else if (old.repeatcount != 0xff)
283 SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
286 // Check if a USB keyboard event is pending and process it if so.
290 if (! CONFIG_USB_KEYBOARD)
292 struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
297 struct keyevent data;
298 int ret = usb_poll_intr(pipe, &data);
305 // Test if USB keyboard is active.
309 if (! CONFIG_USB_KEYBOARD)
311 return GET_GLOBAL(keyboard_pipe) != NULL;
314 // Handle a ps2 style keyboard command.
316 usb_kbd_command(int command, u8 *param)
318 if (! CONFIG_USB_KEYBOARD)
320 dprintf(9, "usb keyboard cmd=%x\n", command);
322 case ATKBD_CMD_GETID:
323 // Return the id of a standard AT keyboard.
333 /****************************************************************
335 ****************************************************************/
337 // Format of USB mouse event data
344 // Process USB mouse data.
346 handle_mouse(struct mouseevent *data)
348 dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
350 s8 x = data->x, y = -data->y;
351 u8 flag = ((data->buttons & 0x7) | (1<<3)
352 | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
358 // Check if a USB mouse event is pending and process it if so.
360 usb_check_mouse(void)
362 if (! CONFIG_USB_MOUSE)
364 struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
369 struct mouseevent data;
370 int ret = usb_poll_intr(pipe, &data);
377 // Test if USB mouse is active.
379 usb_mouse_active(void)
381 if (! CONFIG_USB_MOUSE)
383 return GET_GLOBAL(mouse_pipe) != NULL;
386 // Handle a ps2 style mouse command.
388 usb_mouse_command(int command, u8 *param)
390 if (! CONFIG_USB_MOUSE)
392 dprintf(9, "usb mouse cmd=%x\n", command);
394 case PSMOUSE_CMD_ENABLE:
395 case PSMOUSE_CMD_DISABLE:
396 case PSMOUSE_CMD_SETSCALE11:
398 case PSMOUSE_CMD_SETSCALE21:
399 case PSMOUSE_CMD_SETRATE:
400 case PSMOUSE_CMD_SETRES:
403 case PSMOUSE_CMD_RESET_BAT:
404 case PSMOUSE_CMD_GETID:
405 // Return the id of a standard AT mouse.
410 case PSMOUSE_CMD_GETINFO:
421 // Check for USB events pending - called periodically from timer interrupt.
423 usb_check_event(void)