tizen 2.3.1 release
[external/qemu.git] / roms / seabios / 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 usbdevice_s *usbdev
53              , struct usb_endpoint_descriptor *epdesc)
54 {
55     if (! CONFIG_USB_KEYBOARD)
56         return -1;
57     if (keyboard_pipe)
58         // XXX - this enables the first found keyboard (could be random)
59         return -1;
60
61     if (epdesc->wMaxPacketSize != 8)
62         return -1;
63
64     // Enable "boot" protocol.
65     int ret = set_protocol(usbdev->defpipe, 0);
66     if (ret)
67         return -1;
68     // Periodically send reports to enable key repeat.
69     ret = set_idle(usbdev->defpipe, KEYREPEATMS);
70     if (ret)
71         return -1;
72
73     keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
74     if (!keyboard_pipe)
75         return -1;
76
77     dprintf(1, "USB keyboard initialized\n");
78     return 0;
79 }
80
81 static int
82 usb_mouse_init(struct usbdevice_s *usbdev
83                , struct usb_endpoint_descriptor *epdesc)
84 {
85     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.
95     int ret = set_protocol(usbdev->defpipe, 0);
96     if (ret)
97         return -1;
98
99     mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
100     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).
108 int
109 usb_hid_init(struct usbdevice_s *usbdev)
110 {
111     if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
112         return -1;
113     dprintf(2, "usb_hid_init %p\n", usbdev->defpipe);
114
115     struct usb_interface_descriptor *iface = usbdev->iface;
116     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(
122         usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
123     if (!epdesc) {
124         dprintf(1, "No usb hid intr in?\n");
125         return -1;
126     }
127
128     if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
129         return usb_kbd_init(usbdev, epdesc);
130     if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
131         return usb_mouse_init(usbdev, epdesc);
132     return -1;
133 }
134
135
136 /****************************************************************
137  * Keyboard events
138  ****************************************************************/
139
140 // Mapping from USB key id to ps2 key sequence.
141 static 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
157 // Mapping from USB modifier id to ps2 key sequence.
158 static u16 ModifierToScanCode[] VAR16 = {
159     //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
160     0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
161 };
162
163 #define RELEASEBIT 0x80
164
165 // Format of USB keyboard event data
166 struct keyevent {
167     u8 modifiers;
168     u8 reserved;
169     u8 keys[6];
170 };
171
172 // Translate data from KeyToScanCode[] to calls to process_key().
173 static void
174 prockeys(u16 keys)
175 {
176     if (keys > 0xff) {
177         u8 key = keys>>8;
178         if (key == 0xe1) {
179             // Pause key
180             process_key(0xe1);
181             process_key(0x1d | (keys & RELEASEBIT));
182             process_key(0x45 | (keys & RELEASEBIT));
183             return;
184         }
185         process_key(key);
186     }
187     process_key(keys);
188 }
189
190 // Handle a USB key press/release event.
191 static void
192 procscankey(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
201 // Handle a USB modifier press/release event.
202 static void
203 procmodkey(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
214 struct usbkeyinfo {
215     union {
216         struct {
217             u8 modifiers;
218             u8 repeatcount;
219             u8 keys[6];
220         };
221         u64 data;
222     };
223 };
224 struct usbkeyinfo LastUSBkey VARLOW;
225
226 // Process USB keyboard data.
227 static void
228 handle_key(struct keyevent *data)
229 {
230     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
231
232     // Load old keys.
233     struct usbkeyinfo old;
234     old.data = GET_LOW(LastUSBkey.data);
235
236     // Check for keys no longer pressed.
237     int addpos = 0;
238     int i;
239     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;
266     for (i=0; i<ARRAY_SIZE(data->keys); i++) {
267         u8 key = data->keys[i];
268         if (!key)
269             continue;
270         // New key pressed.
271         procscankey(key, 0);
272         old.keys[addpos++] = key;
273         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
274     }
275     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
287     SET_LOW(LastUSBkey.data, old.data);
288 }
289
290 // Check if a USB keyboard event is pending and process it if so.
291 static void
292 usb_check_key(void)
293 {
294     if (! CONFIG_USB_KEYBOARD)
295         return;
296     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
297     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 }
308
309 // Test if USB keyboard is active.
310 inline int
311 usb_kbd_active(void)
312 {
313     if (! CONFIG_USB_KEYBOARD)
314         return 0;
315     return GET_GLOBAL(keyboard_pipe) != NULL;
316 }
317
318 // Handle a ps2 style keyboard command.
319 inline int
320 usb_kbd_command(int command, u8 *param)
321 {
322     if (! CONFIG_USB_KEYBOARD)
323         return -1;
324     dprintf(9, "usb keyboard cmd=%x\n", command);
325     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 }
335
336
337 /****************************************************************
338  * Mouse events
339  ****************************************************************/
340
341 // Format of USB mouse event data
342 struct mouseevent {
343     u8 buttons;
344     u8 x, y;
345     u8 reserved[5];
346 };
347
348 // Process USB mouse data.
349 static void
350 handle_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.
363 static void
364 usb_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.
382 inline int
383 usb_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.
391 inline int
392 usb_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.
426 void
427 usb_check_event(void)
428 {
429     usb_check_key();
430     usb_check_mouse();
431 }