grml...
[seabios.git] / src / usb-hid.c
1 // 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
12 #include "ps2port.h" // ATKBD_CMD_GETID
13
14 struct usb_pipe *keyboard_pipe VAR16VISIBLE;
15 struct usb_pipe *mouse_pipe VAR16VISIBLE;
16
17
18 /****************************************************************
19  * Setup
20  ****************************************************************/
21
22 // Send USB HID protocol message.
23 static int
24 set_protocol(struct usb_pipe *pipe, u16 val)
25 {
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;
32     return send_default_control(pipe, &req, NULL);
33 }
34
35 // Send USB HID SetIdle request.
36 static int
37 set_idle(struct usb_pipe *pipe, int ms)
38 {
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;
43     req.wIndex = 0;
44     req.wLength = 0;
45     return send_default_control(pipe, &req, NULL);
46 }
47
48 #define KEYREPEATWAITMS 500
49 #define KEYREPEATMS 33
50
51 static int
52 usb_kbd_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
53 {
54     if (! CONFIG_USB_KEYBOARD)
55         return -1;
56     if (keyboard_pipe)
57         // XXX - this enables the first found keyboard (could be random)
58         return -1;
59
60     if (epdesc->wMaxPacketSize != 8)
61         return -1;
62
63     // Enable "boot" protocol.
64     int ret = set_protocol(pipe, 0);
65     if (ret)
66         return -1;
67     // Periodically send reports to enable key repeat.
68     ret = set_idle(pipe, KEYREPEATMS);
69     if (ret)
70         return -1;
71
72     keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
73     if (!keyboard_pipe)
74         return -1;
75
76     dprintf(1, "USB keyboard initialized\n");
77     return 0;
78 }
79
80 static int
81 usb_mouse_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
82 {
83     if (! CONFIG_USB_MOUSE)
84         return -1;
85     if (mouse_pipe)
86         // XXX - this enables the first found mouse (could be random)
87         return -1;
88
89     if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
90         return -1;
91
92     // Enable "boot" protocol.
93     int ret = set_protocol(pipe, 0);
94     if (ret)
95         return -1;
96
97     mouse_pipe = alloc_intr_pipe(pipe, epdesc);
98     if (!mouse_pipe)
99         return -1;
100
101     dprintf(1, "USB mouse initialized\n");
102     return 0;
103 }
104
105 // Initialize a found USB HID device (if applicable).
106 int
107 usb_hid_init(struct usb_pipe *pipe
108              , struct usb_interface_descriptor *iface, int imax)
109 {
110     if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
111         return -1;
112     dprintf(2, "usb_hid_init %p\n", pipe);
113
114     if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
115         // Doesn't support boot protocol.
116         return -1;
117
118     // Find intr in endpoint.
119     struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
120         iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
121     if (!epdesc) {
122         dprintf(1, "No usb hid intr in?\n");
123         return -1;
124     }
125
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);
130     return -1;
131 }
132
133
134 /****************************************************************
135  * Keyboard events
136  ****************************************************************/
137
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
153 };
154
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
159 };
160
161 #define RELEASEBIT 0x80
162
163 // Format of USB keyboard event data
164 struct keyevent {
165     u8 modifiers;
166     u8 reserved;
167     u8 keys[6];
168 };
169
170 // Translate data from KeyToScanCode[] to calls to process_key().
171 static void
172 prockeys(u16 keys)
173 {
174     if (keys > 0xff) {
175         u8 key = keys>>8;
176         if (key == 0xe1) {
177             // Pause key
178             process_key(0xe1);
179             process_key(0x1d | (keys & RELEASEBIT));
180             process_key(0x45 | (keys & RELEASEBIT));
181             return;
182         }
183         process_key(key);
184     }
185     process_key(keys);
186 }
187
188 // Handle a USB key press/release event.
189 static void
190 procscankey(u8 key, u8 flags)
191 {
192     if (key >= ARRAY_SIZE(KeyToScanCode))
193         return;
194     u16 keys = GET_GLOBAL(KeyToScanCode[key]);
195     if (keys)
196         prockeys(keys | flags);
197 }
198
199 // Handle a USB modifier press/release event.
200 static void
201 procmodkey(u8 mods, u8 flags)
202 {
203     int i;
204     for (i=0; mods; i++)
205         if (mods & (1<<i)) {
206             // Modifier key change.
207             prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
208             mods &= ~(1<<i);
209         }
210 }
211
212 // Process USB keyboard data.
213 static void noinline
214 handle_key(struct keyevent *data)
215 {
216     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
217
218     // Load old keys.
219     u16 ebda_seg = get_ebda_seg();
220     struct usbkeyinfo old;
221     old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
222
223     // Check for keys no longer pressed.
224     int addpos = 0;
225     int i;
226     for (i=0; i<ARRAY_SIZE(old.keys); i++) {
227         u8 key = old.keys[i];
228         if (!key)
229             break;
230         int j;
231         for (j=0;; j++) {
232             if (j>=ARRAY_SIZE(data->keys)) {
233                 // Key released.
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;
238                 break;
239             }
240             if (data->keys[j] == key) {
241                 // Key still pressed.
242                 data->keys[j] = 0;
243                 old.keys[addpos++] = key;
244                 break;
245             }
246         }
247     }
248     procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
249
250     // Process new keys
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];
255         if (!key)
256             continue;
257         // New key pressed.
258         procscankey(key, 0);
259         old.keys[addpos++] = key;
260         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
261     }
262     if (addpos < ARRAY_SIZE(old.keys))
263         old.keys[addpos] = 0;
264
265     // Check for key repeat event.
266     if (addpos) {
267         if (!old.repeatcount)
268             procscankey(old.keys[addpos-1], 0);
269         else if (old.repeatcount != 0xff)
270             old.repeatcount--;
271     }
272
273     // Update old keys
274     SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
275 }
276
277 // Check if a USB keyboard event is pending and process it if so.
278 static void
279 usb_check_key(void)
280 {
281     if (! CONFIG_USB_KEYBOARD)
282         return;
283     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
284     if (!pipe)
285         return;
286
287     for (;;) {
288         struct keyevent data;
289         int ret = usb_poll_intr(pipe, &data);
290         if (ret)
291             break;
292         handle_key(&data);
293     }
294 }
295
296 // Test if USB keyboard is active.
297 inline int
298 usb_kbd_active(void)
299 {
300     if (! CONFIG_USB_KEYBOARD)
301         return 0;
302     return GET_GLOBAL(keyboard_pipe) != NULL;
303 }
304
305 // Handle a ps2 style keyboard command.
306 inline int
307 usb_kbd_command(int command, u8 *param)
308 {
309     if (! CONFIG_USB_KEYBOARD)
310         return -1;
311     dprintf(9, "usb keyboard cmd=%x\n", command);
312     switch (command) {
313     case ATKBD_CMD_GETID:
314         // Return the id of a standard AT keyboard.
315         param[0] = 0xab;
316         param[1] = 0x83;
317         return 0;
318     default:
319         return -1;
320     }
321 }
322
323
324 /****************************************************************
325  * Mouse events
326  ****************************************************************/
327
328 // Format of USB mouse event data
329 struct mouseevent {
330     u8 buttons;
331     u8 x, y;
332     u8 reserved[5];
333 };
334
335 // Process USB mouse data.
336 static void
337 handle_mouse(struct mouseevent *data)
338 {
339     dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
340
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));
344     process_mouse(flag);
345     process_mouse(x);
346     process_mouse(y);
347 }
348
349 // Check if a USB mouse event is pending and process it if so.
350 static void
351 usb_check_mouse(void)
352 {
353     if (! CONFIG_USB_MOUSE)
354         return;
355     struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
356     if (!pipe)
357         return;
358
359     for (;;) {
360         struct mouseevent data;
361         int ret = usb_poll_intr(pipe, &data);
362         if (ret)
363             break;
364         handle_mouse(&data);
365     }
366 }
367
368 // Test if USB mouse is active.
369 inline int
370 usb_mouse_active(void)
371 {
372     if (! CONFIG_USB_MOUSE)
373         return 0;
374     return GET_GLOBAL(mouse_pipe) != NULL;
375 }
376
377 // Handle a ps2 style mouse command.
378 inline int
379 usb_mouse_command(int command, u8 *param)
380 {
381     if (! CONFIG_USB_MOUSE)
382         return -1;
383     dprintf(9, "usb mouse cmd=%x\n", command);
384     switch (command) {
385     case PSMOUSE_CMD_ENABLE:
386     case PSMOUSE_CMD_DISABLE:
387     case PSMOUSE_CMD_SETSCALE11:
388         return 0;
389     case PSMOUSE_CMD_SETSCALE21:
390     case PSMOUSE_CMD_SETRATE:
391     case PSMOUSE_CMD_SETRES:
392         // XXX
393         return 0;
394     case PSMOUSE_CMD_RESET_BAT:
395     case PSMOUSE_CMD_GETID:
396         // Return the id of a standard AT mouse.
397         param[0] = 0xaa;
398         param[1] = 0x00;
399         return 0;
400
401     case PSMOUSE_CMD_GETINFO:
402         param[0] = 0x00;
403         param[1] = 4;
404         param[2] = 100;
405         return 0;
406
407     default:
408         return -1;
409     }
410 }
411
412 // Check for USB events pending - called periodically from timer interrupt.
413 void
414 usb_check_event(void)
415 {
416     usb_check_key();
417     usb_check_mouse();
418 }