blob: 8c4b803fe0a350dc9015d092786c0e83fdb6b248 [file] [log] [blame]
Kevin O'Connor114592f2009-09-28 21:32:08 -04001// Code for handling USB Human Interface Devices (HID).
2//
3// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
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
Kevin O'Connordd5a8a62010-05-01 19:59:34 -040012#include "ps2port.h" // ATKBD_CMD_GETID
Kevin O'Connor114592f2009-09-28 21:32:08 -040013
Kevin O'Connor59f02832009-10-12 10:09:15 -040014struct usb_pipe *keyboard_pipe VAR16VISIBLE;
Kevin O'Connor0e885762010-05-01 22:14:40 -040015struct usb_pipe *mouse_pipe VAR16VISIBLE;
Kevin O'Connor114592f2009-09-28 21:32:08 -040016
17
18/****************************************************************
19 * Setup
20 ****************************************************************/
21
Kevin O'Connor5718d562010-05-01 19:25:41 -040022// Send USB HID protocol message.
Kevin O'Connor114592f2009-09-28 21:32:08 -040023static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050024set_protocol(struct usb_pipe *pipe, u16 val)
Kevin O'Connor114592f2009-09-28 21:32:08 -040025{
26 struct usb_ctrlrequest req;
27 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
28 req.bRequest = HID_REQ_SET_PROTOCOL;
29 req.wValue = val;
30 req.wIndex = 0;
31 req.wLength = 0;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050032 return send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -040033}
34
Kevin O'Connor5718d562010-05-01 19:25:41 -040035// Send USB HID SetIdle request.
Kevin O'Connor114592f2009-09-28 21:32:08 -040036static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050037set_idle(struct usb_pipe *pipe, int ms)
Kevin O'Connor114592f2009-09-28 21:32:08 -040038{
39 struct usb_ctrlrequest req;
40 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
41 req.bRequest = HID_REQ_SET_IDLE;
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -050042 req.wValue = (ms/4)<<8;
Kevin O'Connor114592f2009-09-28 21:32:08 -040043 req.wIndex = 0;
44 req.wLength = 0;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050045 return send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -040046}
47
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -050048#define KEYREPEATWAITMS 500
49#define KEYREPEATMS 33
50
Kevin O'Connor0e885762010-05-01 22:14:40 -040051static int
Kevin O'Connor6a8e8952012-03-08 07:20:30 -050052usb_kbd_init(struct usbdevice_s *usbdev
53 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor114592f2009-09-28 21:32:08 -040054{
55 if (! CONFIG_USB_KEYBOARD)
56 return -1;
57 if (keyboard_pipe)
Kevin O'Connora5826b52009-10-24 17:57:29 -040058 // XXX - this enables the first found keyboard (could be random)
Kevin O'Connor114592f2009-09-28 21:32:08 -040059 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -040060
Kevin O'Connor0e885762010-05-01 22:14:40 -040061 if (epdesc->wMaxPacketSize != 8)
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050062 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -040063
64 // Enable "boot" protocol.
Kevin O'Connor6a8e8952012-03-08 07:20:30 -050065 int ret = set_protocol(usbdev->defpipe, 0);
Kevin O'Connor114592f2009-09-28 21:32:08 -040066 if (ret)
67 return -1;
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050068 // Periodically send reports to enable key repeat.
Kevin O'Connor6a8e8952012-03-08 07:20:30 -050069 ret = set_idle(usbdev->defpipe, KEYREPEATMS);
Kevin O'Connor114592f2009-09-28 21:32:08 -040070 if (ret)
71 return -1;
72
Kevin O'Connorc3d96c22012-03-10 09:03:25 -050073 keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050074 if (!keyboard_pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -040075 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -040076
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050077 dprintf(1, "USB keyboard initialized\n");
Kevin O'Connor114592f2009-09-28 21:32:08 -040078 return 0;
79}
80
Kevin O'Connor0e885762010-05-01 22:14:40 -040081static int
Kevin O'Connor6a8e8952012-03-08 07:20:30 -050082usb_mouse_init(struct usbdevice_s *usbdev
83 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor114592f2009-09-28 21:32:08 -040084{
Kevin O'Connor0e885762010-05-01 22:14:40 -040085 if (! CONFIG_USB_MOUSE)
86 return -1;
87 if (mouse_pipe)
88 // XXX - this enables the first found mouse (could be random)
89 return -1;
90
91 if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
92 return -1;
93
94 // Enable "boot" protocol.
Kevin O'Connor6a8e8952012-03-08 07:20:30 -050095 int ret = set_protocol(usbdev->defpipe, 0);
Kevin O'Connor0e885762010-05-01 22:14:40 -040096 if (ret)
97 return -1;
98
Kevin O'Connorc3d96c22012-03-10 09:03:25 -050099 mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400100 if (!mouse_pipe)
101 return -1;
102
103 dprintf(1, "USB mouse initialized\n");
104 return 0;
105}
106
107// Initialize a found USB HID device (if applicable).
108int
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500109usb_hid_init(struct usbdevice_s *usbdev)
Kevin O'Connor0e885762010-05-01 22:14:40 -0400110{
111 if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
112 return -1;
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500113 dprintf(2, "usb_hid_init %p\n", usbdev->defpipe);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400114
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500115 struct usb_interface_descriptor *iface = usbdev->iface;
Kevin O'Connor0e885762010-05-01 22:14:40 -0400116 if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
117 // Doesn't support boot protocol.
118 return -1;
119
120 // Find intr in endpoint.
121 struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500122 usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400123 if (!epdesc) {
124 dprintf(1, "No usb hid intr in?\n");
125 return -1;
126 }
127
128 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500129 return usb_kbd_init(usbdev, epdesc);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400130 if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500131 return usb_mouse_init(usbdev, epdesc);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400132 return -1;
133}
134
Kevin O'Connor114592f2009-09-28 21:32:08 -0400135
136/****************************************************************
137 * Keyboard events
138 ****************************************************************/
139
Kevin O'Connor5718d562010-05-01 19:25:41 -0400140// Mapping from USB key id to ps2 key sequence.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400141static 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
155};
156
Kevin O'Connor5718d562010-05-01 19:25:41 -0400157// Mapping from USB modifier id to ps2 key sequence.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400158static u16 ModifierToScanCode[] VAR16 = {
159 //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
160 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
161};
162
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500163#define RELEASEBIT 0x80
164
Kevin O'Connor0e885762010-05-01 22:14:40 -0400165// Format of USB keyboard event data
Kevin O'Connor114592f2009-09-28 21:32:08 -0400166struct keyevent {
167 u8 modifiers;
168 u8 reserved;
169 u8 keys[6];
170};
171
Kevin O'Connor5718d562010-05-01 19:25:41 -0400172// Translate data from KeyToScanCode[] to calls to process_key().
Kevin O'Connor114592f2009-09-28 21:32:08 -0400173static void
174prockeys(u16 keys)
175{
176 if (keys > 0xff) {
177 u8 key = keys>>8;
178 if (key == 0xe1) {
179 // Pause key
180 process_key(0xe1);
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500181 process_key(0x1d | (keys & RELEASEBIT));
182 process_key(0x45 | (keys & RELEASEBIT));
Kevin O'Connor114592f2009-09-28 21:32:08 -0400183 return;
184 }
185 process_key(key);
186 }
187 process_key(keys);
188}
189
Kevin O'Connor5718d562010-05-01 19:25:41 -0400190// Handle a USB key press/release event.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400191static void
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500192procscankey(u8 key, u8 flags)
193{
194 if (key >= ARRAY_SIZE(KeyToScanCode))
195 return;
196 u16 keys = GET_GLOBAL(KeyToScanCode[key]);
197 if (keys)
198 prockeys(keys | flags);
199}
200
Kevin O'Connor5718d562010-05-01 19:25:41 -0400201// Handle a USB modifier press/release event.
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500202static void
203procmodkey(u8 mods, u8 flags)
204{
205 int i;
206 for (i=0; mods; i++)
207 if (mods & (1<<i)) {
208 // Modifier key change.
209 prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
210 mods &= ~(1<<i);
211 }
212}
213
Kevin O'Connor2d012ec2012-05-13 12:39:16 -0400214struct usbkeyinfo {
215 union {
216 struct {
217 u8 modifiers;
218 u8 repeatcount;
219 u8 keys[6];
220 };
221 u64 data;
222 };
223};
224struct usbkeyinfo LastUSBkey VARLOW;
225
Kevin O'Connor5718d562010-05-01 19:25:41 -0400226// Process USB keyboard data.
Kevin O'Connorac7eb5e2012-05-28 14:42:16 -0400227static void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400228handle_key(struct keyevent *data)
229{
Kevin O'Connor78523312010-02-14 19:07:43 -0500230 dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500231
232 // Load old keys.
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500233 struct usbkeyinfo old;
Kevin O'Connor2d012ec2012-05-13 12:39:16 -0400234 old.data = GET_LOW(LastUSBkey.data);
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500235
236 // Check for keys no longer pressed.
237 int addpos = 0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400238 int i;
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500239 for (i=0; i<ARRAY_SIZE(old.keys); i++) {
240 u8 key = old.keys[i];
241 if (!key)
242 break;
243 int j;
244 for (j=0;; j++) {
245 if (j>=ARRAY_SIZE(data->keys)) {
246 // Key released.
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;
251 break;
252 }
253 if (data->keys[j] == key) {
254 // Key still pressed.
255 data->keys[j] = 0;
256 old.keys[addpos++] = key;
257 break;
258 }
259 }
260 }
261 procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
262
263 // Process new keys
264 procmodkey(data->modifiers & ~old.modifiers, 0);
265 old.modifiers = data->modifiers;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400266 for (i=0; i<ARRAY_SIZE(data->keys); i++) {
267 u8 key = data->keys[i];
Kevin O'Connor114592f2009-09-28 21:32:08 -0400268 if (!key)
269 continue;
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500270 // New key pressed.
271 procscankey(key, 0);
272 old.keys[addpos++] = key;
273 old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400274 }
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500275 if (addpos < ARRAY_SIZE(old.keys))
276 old.keys[addpos] = 0;
277
278 // Check for key repeat event.
279 if (addpos) {
280 if (!old.repeatcount)
281 procscankey(old.keys[addpos-1], 0);
282 else if (old.repeatcount != 0xff)
283 old.repeatcount--;
284 }
285
286 // Update old keys
Kevin O'Connor2d012ec2012-05-13 12:39:16 -0400287 SET_LOW(LastUSBkey.data, old.data);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400288}
289
Kevin O'Connor0e885762010-05-01 22:14:40 -0400290// Check if a USB keyboard event is pending and process it if so.
291static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500292usb_check_key(void)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400293{
294 if (! CONFIG_USB_KEYBOARD)
295 return;
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400296 struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400297 if (!pipe)
298 return;
299
300 for (;;) {
301 struct keyevent data;
302 int ret = usb_poll_intr(pipe, &data);
303 if (ret)
304 break;
305 handle_key(&data);
306 }
307}
Kevin O'Connordd5a8a62010-05-01 19:59:34 -0400308
309// Test if USB keyboard is active.
310inline int
311usb_kbd_active(void)
312{
Kevin O'Connor0e885762010-05-01 22:14:40 -0400313 if (! CONFIG_USB_KEYBOARD)
314 return 0;
Kevin O'Connordd5a8a62010-05-01 19:59:34 -0400315 return GET_GLOBAL(keyboard_pipe) != NULL;
316}
317
318// Handle a ps2 style keyboard command.
319inline int
320usb_kbd_command(int command, u8 *param)
321{
Kevin O'Connor0e885762010-05-01 22:14:40 -0400322 if (! CONFIG_USB_KEYBOARD)
323 return -1;
324 dprintf(9, "usb keyboard cmd=%x\n", command);
Kevin O'Connordd5a8a62010-05-01 19:59:34 -0400325 switch (command) {
326 case ATKBD_CMD_GETID:
327 // Return the id of a standard AT keyboard.
328 param[0] = 0xab;
329 param[1] = 0x83;
330 return 0;
331 default:
332 return -1;
333 }
334}
Kevin O'Connor0e885762010-05-01 22:14:40 -0400335
336
337/****************************************************************
338 * Mouse events
339 ****************************************************************/
340
341// Format of USB mouse event data
342struct mouseevent {
343 u8 buttons;
344 u8 x, y;
345 u8 reserved[5];
346};
347
348// Process USB mouse data.
349static void
350handle_mouse(struct mouseevent *data)
351{
352 dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
353
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));
357 process_mouse(flag);
358 process_mouse(x);
359 process_mouse(y);
360}
361
362// Check if a USB mouse event is pending and process it if so.
363static void
364usb_check_mouse(void)
365{
366 if (! CONFIG_USB_MOUSE)
367 return;
368 struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
369 if (!pipe)
370 return;
371
372 for (;;) {
373 struct mouseevent data;
374 int ret = usb_poll_intr(pipe, &data);
375 if (ret)
376 break;
377 handle_mouse(&data);
378 }
379}
380
381// Test if USB mouse is active.
382inline int
383usb_mouse_active(void)
384{
385 if (! CONFIG_USB_MOUSE)
386 return 0;
387 return GET_GLOBAL(mouse_pipe) != NULL;
388}
389
390// Handle a ps2 style mouse command.
391inline int
392usb_mouse_command(int command, u8 *param)
393{
394 if (! CONFIG_USB_MOUSE)
395 return -1;
396 dprintf(9, "usb mouse cmd=%x\n", command);
397 switch (command) {
398 case PSMOUSE_CMD_ENABLE:
399 case PSMOUSE_CMD_DISABLE:
400 case PSMOUSE_CMD_SETSCALE11:
401 return 0;
402 case PSMOUSE_CMD_SETSCALE21:
403 case PSMOUSE_CMD_SETRATE:
404 case PSMOUSE_CMD_SETRES:
405 // XXX
406 return 0;
407 case PSMOUSE_CMD_RESET_BAT:
408 case PSMOUSE_CMD_GETID:
409 // Return the id of a standard AT mouse.
410 param[0] = 0xaa;
411 param[1] = 0x00;
412 return 0;
413
414 case PSMOUSE_CMD_GETINFO:
415 param[0] = 0x00;
416 param[1] = 4;
417 param[2] = 100;
418 return 0;
419
420 default:
421 return -1;
422 }
423}
424
425// Check for USB events pending - called periodically from timer interrupt.
426void
427usb_check_event(void)
428{
429 usb_check_key();
430 usb_check_mouse();
431}