Fix error causing USB HID "boot" protocol to not be enabled.
[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 void
134 usb_hid_setup(void)
135 {
136     if (CONFIG_USB_KEYBOARD)
137         keyboard_pipe = NULL;
138     if (CONFIG_USB_MOUSE)
139         mouse_pipe = NULL;
140 }
141
142
143 /****************************************************************
144  * Keyboard events
145  ****************************************************************/
146
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
162 };
163
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
168 };
169
170 #define RELEASEBIT 0x80
171
172 // Format of USB keyboard event data
173 struct keyevent {
174     u8 modifiers;
175     u8 reserved;
176     u8 keys[6];
177 };
178
179 // Translate data from KeyToScanCode[] to calls to process_key().
180 static void
181 prockeys(u16 keys)
182 {
183     if (keys > 0xff) {
184         u8 key = keys>>8;
185         if (key == 0xe1) {
186             // Pause key
187             process_key(0xe1);
188             process_key(0x1d | (keys & RELEASEBIT));
189             process_key(0x45 | (keys & RELEASEBIT));
190             return;
191         }
192         process_key(key);
193     }
194     process_key(keys);
195 }
196
197 // Handle a USB key press/release event.
198 static void
199 procscankey(u8 key, u8 flags)
200 {
201     if (key >= ARRAY_SIZE(KeyToScanCode))
202         return;
203     u16 keys = GET_GLOBAL(KeyToScanCode[key]);
204     if (keys)
205         prockeys(keys | flags);
206 }
207
208 // Handle a USB modifier press/release event.
209 static void
210 procmodkey(u8 mods, u8 flags)
211 {
212     int i;
213     for (i=0; mods; i++)
214         if (mods & (1<<i)) {
215             // Modifier key change.
216             prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
217             mods &= ~(1<<i);
218         }
219 }
220
221 // Process USB keyboard data.
222 static void noinline
223 handle_key(struct keyevent *data)
224 {
225     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
226
227     // Load old keys.
228     u16 ebda_seg = get_ebda_seg();
229     struct usbkeyinfo old;
230     old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
231
232     // Check for keys no longer pressed.
233     int addpos = 0;
234     int i;
235     for (i=0; i<ARRAY_SIZE(old.keys); i++) {
236         u8 key = old.keys[i];
237         if (!key)
238             break;
239         int j;
240         for (j=0;; j++) {
241             if (j>=ARRAY_SIZE(data->keys)) {
242                 // Key released.
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;
247                 break;
248             }
249             if (data->keys[j] == key) {
250                 // Key still pressed.
251                 data->keys[j] = 0;
252                 old.keys[addpos++] = key;
253                 break;
254             }
255         }
256     }
257     procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
258
259     // Process new keys
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];
264         if (!key)
265             continue;
266         // New key pressed.
267         procscankey(key, 0);
268         old.keys[addpos++] = key;
269         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
270     }
271     if (addpos < ARRAY_SIZE(old.keys))
272         old.keys[addpos] = 0;
273
274     // Check for key repeat event.
275     if (addpos) {
276         if (!old.repeatcount)
277             procscankey(old.keys[addpos-1], 0);
278         else if (old.repeatcount != 0xff)
279             old.repeatcount--;
280     }
281
282     // Update old keys
283     SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
284 }
285
286 // Check if a USB keyboard event is pending and process it if so.
287 static void
288 usb_check_key(void)
289 {
290     if (! CONFIG_USB_KEYBOARD)
291         return;
292     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
293     if (!pipe)
294         return;
295
296     for (;;) {
297         struct keyevent data;
298         int ret = usb_poll_intr(pipe, &data);
299         if (ret)
300             break;
301         handle_key(&data);
302     }
303 }
304
305 // Test if USB keyboard is active.
306 inline int
307 usb_kbd_active(void)
308 {
309     if (! CONFIG_USB_KEYBOARD)
310         return 0;
311     return GET_GLOBAL(keyboard_pipe) != NULL;
312 }
313
314 // Handle a ps2 style keyboard command.
315 inline int
316 usb_kbd_command(int command, u8 *param)
317 {
318     if (! CONFIG_USB_KEYBOARD)
319         return -1;
320     dprintf(9, "usb keyboard cmd=%x\n", command);
321     switch (command) {
322     case ATKBD_CMD_GETID:
323         // Return the id of a standard AT keyboard.
324         param[0] = 0xab;
325         param[1] = 0x83;
326         return 0;
327     default:
328         return -1;
329     }
330 }
331
332
333 /****************************************************************
334  * Mouse events
335  ****************************************************************/
336
337 // Format of USB mouse event data
338 struct mouseevent {
339     u8 buttons;
340     u8 x, y;
341     u8 reserved[5];
342 };
343
344 // Process USB mouse data.
345 static void
346 handle_mouse(struct mouseevent *data)
347 {
348     dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
349
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));
353     process_mouse(flag);
354     process_mouse(x);
355     process_mouse(y);
356 }
357
358 // Check if a USB mouse event is pending and process it if so.
359 static void
360 usb_check_mouse(void)
361 {
362     if (! CONFIG_USB_MOUSE)
363         return;
364     struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
365     if (!pipe)
366         return;
367
368     for (;;) {
369         struct mouseevent data;
370         int ret = usb_poll_intr(pipe, &data);
371         if (ret)
372             break;
373         handle_mouse(&data);
374     }
375 }
376
377 // Test if USB mouse is active.
378 inline int
379 usb_mouse_active(void)
380 {
381     if (! CONFIG_USB_MOUSE)
382         return 0;
383     return GET_GLOBAL(mouse_pipe) != NULL;
384 }
385
386 // Handle a ps2 style mouse command.
387 inline int
388 usb_mouse_command(int command, u8 *param)
389 {
390     if (! CONFIG_USB_MOUSE)
391         return -1;
392     dprintf(9, "usb mouse cmd=%x\n", command);
393     switch (command) {
394     case PSMOUSE_CMD_ENABLE:
395     case PSMOUSE_CMD_DISABLE:
396     case PSMOUSE_CMD_SETSCALE11:
397         return 0;
398     case PSMOUSE_CMD_SETSCALE21:
399     case PSMOUSE_CMD_SETRATE:
400     case PSMOUSE_CMD_SETRES:
401         // XXX
402         return 0;
403     case PSMOUSE_CMD_RESET_BAT:
404     case PSMOUSE_CMD_GETID:
405         // Return the id of a standard AT mouse.
406         param[0] = 0xaa;
407         param[1] = 0x00;
408         return 0;
409
410     case PSMOUSE_CMD_GETINFO:
411         param[0] = 0x00;
412         param[1] = 4;
413         param[2] = 100;
414         return 0;
415
416     default:
417         return -1;
418     }
419 }
420
421 // Check for USB events pending - called periodically from timer interrupt.
422 void
423 usb_check_event(void)
424 {
425     usb_check_key();
426     usb_check_mouse();
427 }