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);
134 /****************************************************************
136 ****************************************************************/
138 // Mapping from USB key id to ps2 key sequence.
139 static u16 KeyToScanCode[] VAR16 = {
140 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
141 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
142 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
143 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
144 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
145 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
146 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
147 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
148 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
149 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
150 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
151 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
152 0x0048, 0x0049, 0x0052, 0x0053
155 // Mapping from USB modifier id to ps2 key sequence.
156 static u16 ModifierToScanCode[] VAR16 = {
157 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
158 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
161 #define RELEASEBIT 0x80
163 // Format of USB keyboard event data
170 // Translate data from KeyToScanCode[] to calls to process_key().
179 process_key(0x1d | (keys & RELEASEBIT));
180 process_key(0x45 | (keys & RELEASEBIT));
188 // Handle a USB key press/release event.
190 procscankey(u8 key, u8 flags)
192 if (key >= ARRAY_SIZE(KeyToScanCode))
194 u16 keys = GET_GLOBAL(KeyToScanCode[key]);
196 prockeys(keys | flags);
199 // Handle a USB modifier press/release event.
201 procmodkey(u8 mods, u8 flags)
206 // Modifier key change.
207 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
212 // Process USB keyboard data.
214 handle_key(struct keyevent *data)
216 dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
219 u16 ebda_seg = get_ebda_seg();
220 struct usbkeyinfo old;
221 old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
223 // Check for keys no longer pressed.
226 for (i=0; i<ARRAY_SIZE(old.keys); i++) {
227 u8 key = old.keys[i];
232 if (j>=ARRAY_SIZE(data->keys)) {
234 procscankey(key, RELEASEBIT);
235 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
236 // Last pressed key released - disable repeat.
237 old.repeatcount = 0xff;
240 if (data->keys[j] == key) {
241 // Key still pressed.
243 old.keys[addpos++] = key;
248 procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
251 procmodkey(data->modifiers & ~old.modifiers, 0);
252 old.modifiers = data->modifiers;
253 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
254 u8 key = data->keys[i];
259 old.keys[addpos++] = key;
260 old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
262 if (addpos < ARRAY_SIZE(old.keys))
263 old.keys[addpos] = 0;
265 // Check for key repeat event.
267 if (!old.repeatcount)
268 procscankey(old.keys[addpos-1], 0);
269 else if (old.repeatcount != 0xff)
274 SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
277 // Check if a USB keyboard event is pending and process it if so.
281 if (! CONFIG_USB_KEYBOARD)
283 struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
288 struct keyevent data;
289 int ret = usb_poll_intr(pipe, &data);
296 // Test if USB keyboard is active.
300 if (! CONFIG_USB_KEYBOARD)
302 return GET_GLOBAL(keyboard_pipe) != NULL;
305 // Handle a ps2 style keyboard command.
307 usb_kbd_command(int command, u8 *param)
309 if (! CONFIG_USB_KEYBOARD)
311 dprintf(9, "usb keyboard cmd=%x\n", command);
313 case ATKBD_CMD_GETID:
314 // Return the id of a standard AT keyboard.
324 /****************************************************************
326 ****************************************************************/
328 // Format of USB mouse event data
335 // Process USB mouse data.
337 handle_mouse(struct mouseevent *data)
339 dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
341 s8 x = data->x, y = -data->y;
342 u8 flag = ((data->buttons & 0x7) | (1<<3)
343 | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
349 // Check if a USB mouse event is pending and process it if so.
351 usb_check_mouse(void)
353 if (! CONFIG_USB_MOUSE)
355 struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
360 struct mouseevent data;
361 int ret = usb_poll_intr(pipe, &data);
368 // Test if USB mouse is active.
370 usb_mouse_active(void)
372 if (! CONFIG_USB_MOUSE)
374 return GET_GLOBAL(mouse_pipe) != NULL;
377 // Handle a ps2 style mouse command.
379 usb_mouse_command(int command, u8 *param)
381 if (! CONFIG_USB_MOUSE)
383 dprintf(9, "usb mouse cmd=%x\n", command);
385 case PSMOUSE_CMD_ENABLE:
386 case PSMOUSE_CMD_DISABLE:
387 case PSMOUSE_CMD_SETSCALE11:
389 case PSMOUSE_CMD_SETSCALE21:
390 case PSMOUSE_CMD_SETRATE:
391 case PSMOUSE_CMD_SETRES:
394 case PSMOUSE_CMD_RESET_BAT:
395 case PSMOUSE_CMD_GETID:
396 // Return the id of a standard AT mouse.
401 case PSMOUSE_CMD_GETINFO:
412 // Check for USB events pending - called periodically from timer interrupt.
414 usb_check_event(void)