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 "biosvar.h" // GET_GLOBAL
8 #include "config.h" // CONFIG_*
9 #include "output.h" // dprintf
10 #include "ps2port.h" // ATKBD_CMD_GETID
11 #include "usb.h" // usb_ctrlrequest
12 #include "usb-hid.h" // usb_keyboard_setup
13 #include "util.h" // process_key
14 
15 struct usb_pipe *keyboard_pipe VARFSEG;
16 struct usb_pipe *mouse_pipe VARFSEG;
17 
18 
19 /****************************************************************
20  * Setup
21  ****************************************************************/
22 
23 // Send USB HID protocol message.
24 static int
set_protocol(struct usb_pipe * pipe,u16 val)25 set_protocol(struct usb_pipe *pipe, u16 val)
26 {
27     struct usb_ctrlrequest req;
28     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
29     req.bRequest = HID_REQ_SET_PROTOCOL;
30     req.wValue = val;
31     req.wIndex = 0;
32     req.wLength = 0;
33     return usb_send_default_control(pipe, &req, NULL);
34 }
35 
36 // Send USB HID SetIdle request.
37 static int
set_idle(struct usb_pipe * pipe,int ms)38 set_idle(struct usb_pipe *pipe, int ms)
39 {
40     struct usb_ctrlrequest req;
41     req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
42     req.bRequest = HID_REQ_SET_IDLE;
43     req.wValue = (ms/4)<<8;
44     req.wIndex = 0;
45     req.wLength = 0;
46     return usb_send_default_control(pipe, &req, NULL);
47 }
48 
49 #define KEYREPEATWAITMS 500
50 #define KEYREPEATMS 33
51 
52 static int
usb_kbd_setup(struct usbdevice_s * usbdev,struct usb_endpoint_descriptor * epdesc)53 usb_kbd_setup(struct usbdevice_s *usbdev
54               , struct usb_endpoint_descriptor *epdesc)
55 {
56     if (! CONFIG_USB_KEYBOARD)
57         return -1;
58     if (keyboard_pipe)
59         // XXX - this enables the first found keyboard (could be random)
60         return -1;
61 
62     if (epdesc->wMaxPacketSize != 8)
63         return -1;
64 
65     // Enable "boot" protocol.
66     int ret = set_protocol(usbdev->defpipe, 0);
67     if (ret)
68         return -1;
69     // Periodically send reports to enable key repeat.
70     ret = set_idle(usbdev->defpipe, KEYREPEATMS);
71     if (ret)
72         return -1;
73 
74     keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
75     if (!keyboard_pipe)
76         return -1;
77 
78     dprintf(1, "USB keyboard initialized\n");
79     return 0;
80 }
81 
82 static int
usb_mouse_setup(struct usbdevice_s * usbdev,struct usb_endpoint_descriptor * epdesc)83 usb_mouse_setup(struct usbdevice_s *usbdev
84                 , struct usb_endpoint_descriptor *epdesc)
85 {
86     if (! CONFIG_USB_MOUSE)
87         return -1;
88     if (mouse_pipe)
89         // XXX - this enables the first found mouse (could be random)
90         return -1;
91 
92     if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
93         return -1;
94 
95     // Enable "boot" protocol.
96     int ret = set_protocol(usbdev->defpipe, 0);
97     if (ret)
98         return -1;
99 
100     mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
101     if (!mouse_pipe)
102         return -1;
103 
104     dprintf(1, "USB mouse initialized\n");
105     return 0;
106 }
107 
108 // Initialize a found USB HID device (if applicable).
109 int
usb_hid_setup(struct usbdevice_s * usbdev)110 usb_hid_setup(struct usbdevice_s *usbdev)
111 {
112     if (! CONFIG_USB_KEYBOARD && ! CONFIG_USB_MOUSE)
113         return -1;
114     dprintf(2, "usb_hid_setup %p\n", usbdev->defpipe);
115 
116     struct usb_interface_descriptor *iface = usbdev->iface;
117     if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
118         // Doesn't support boot protocol.
119         return -1;
120 
121     // Find intr in endpoint.
122     struct usb_endpoint_descriptor *epdesc = usb_find_desc(
123         usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
124     if (!epdesc) {
125         dprintf(1, "No usb hid intr in?\n");
126         return -1;
127     }
128 
129     if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
130         return usb_kbd_setup(usbdev, epdesc);
131     if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
132         return usb_mouse_setup(usbdev, epdesc);
133     return -1;
134 }
135 
136 
137 /****************************************************************
138  * Keyboard events
139  ****************************************************************/
140 
141 // Mapping from USB key id to ps2 key sequence.
142 static u16 KeyToScanCode[] VAR16 = {
143     0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
144     0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
145     0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
146     0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
147     0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
148     0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
149     0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
150     0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
151     0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
152     0xe145, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
153     0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
154     0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
155     0x0048, 0x0049, 0x0052, 0x0053
156 };
157 
158 // Mapping from USB modifier id to ps2 key sequence.
159 static u16 ModifierToScanCode[] VAR16 = {
160     //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
161     0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
162 };
163 
164 #define RELEASEBIT 0x80
165 
166 // Format of USB keyboard event data
167 struct keyevent {
168     u8 modifiers;
169     u8 reserved;
170     u8 keys[6];
171 };
172 
173 // Translate data from KeyToScanCode[] to calls to process_key().
174 static void
prockeys(u16 scancode,u8 key_release,u8 mods)175 prockeys(u16 scancode, u8 key_release, u8 mods)
176 {
177     if (scancode > 0xff) {
178         if (scancode == 0xe145) {
179             // XXX - a real AT keyboard would immediately send the key release
180             if (mods & ((1<<0) | (1<<4))) {
181                 // Cntr+Break key
182                 process_key(0xe0);
183                 process_key(0x46 | key_release);
184             } else {
185                 // Pause key
186                 process_key(0xe1);
187                 process_key(0x1d | key_release);
188                 process_key(0x45 | key_release);
189             }
190             return;
191         } else if (scancode == 0xe037 && mods & ((1<<2) | (1<<6))) {
192             // Alt+SysReq key
193             process_key(0x54 | key_release);
194             return;
195         }
196         process_key(0xe0);
197     }
198     process_key(scancode | key_release);
199 }
200 
201 // Handle a USB key press/release event.
202 static void
procscankey(u8 key,u8 key_release,u8 mods)203 procscankey(u8 key, u8 key_release, u8 mods)
204 {
205     if (key >= ARRAY_SIZE(KeyToScanCode))
206         return;
207     u16 scancode = GET_GLOBAL(KeyToScanCode[key]);
208     if (scancode)
209         prockeys(scancode, key_release, mods);
210 }
211 
212 // Handle a USB modifier press/release event.
213 static void
procmodkey(u8 mods,u8 key_release)214 procmodkey(u8 mods, u8 key_release)
215 {
216     int i;
217     for (i=0; mods; i++)
218         if (mods & (1<<i)) {
219             // Modifier key change.
220             prockeys(GET_GLOBAL(ModifierToScanCode[i]), key_release, 0);
221             mods &= ~(1<<i);
222         }
223 }
224 
225 struct usbkeyinfo {
226     union {
227         struct {
228             u8 modifiers;
229             u8 repeatcount;
230             u8 keys[6];
231         };
232         u64 data;
233     };
234 };
235 struct usbkeyinfo LastUSBkey VARLOW;
236 
237 // Process USB keyboard data.
238 static void
handle_key(struct keyevent * data)239 handle_key(struct keyevent *data)
240 {
241     dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
242 
243     // Load old keys.
244     struct usbkeyinfo old;
245     old.data = GET_LOW(LastUSBkey.data);
246 
247     // Check for keys no longer pressed.
248     int addpos = 0;
249     int i;
250     for (i=0; i<ARRAY_SIZE(old.keys); i++) {
251         u8 key = old.keys[i];
252         if (!key)
253             break;
254         int j;
255         for (j=0;; j++) {
256             if (j>=ARRAY_SIZE(data->keys)) {
257                 // Key released.
258                 procscankey(key, RELEASEBIT, data->modifiers);
259                 if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
260                     // Last pressed key released - disable repeat.
261                     old.repeatcount = 0xff;
262                 break;
263             }
264             if (data->keys[j] == key) {
265                 // Key still pressed.
266                 data->keys[j] = 0;
267                 old.keys[addpos++] = key;
268                 break;
269             }
270         }
271     }
272     procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
273 
274     // Process new keys
275     procmodkey(data->modifiers & ~old.modifiers, 0);
276     old.modifiers = data->modifiers;
277     for (i=0; i<ARRAY_SIZE(data->keys); i++) {
278         u8 key = data->keys[i];
279         if (!key)
280             continue;
281         // New key pressed.
282         procscankey(key, 0, data->modifiers);
283         old.keys[addpos++] = key;
284         old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
285     }
286     if (addpos < ARRAY_SIZE(old.keys))
287         old.keys[addpos] = 0;
288 
289     // Check for key repeat event.
290     if (addpos) {
291         if (!old.repeatcount)
292             procscankey(old.keys[addpos-1], 0, data->modifiers);
293         else if (old.repeatcount != 0xff)
294             old.repeatcount--;
295     }
296 
297     // Update old keys
298     SET_LOW(LastUSBkey.data, old.data);
299 }
300 
301 // Check if a USB keyboard event is pending and process it if so.
302 static void
usb_check_key(void)303 usb_check_key(void)
304 {
305     if (! CONFIG_USB_KEYBOARD)
306         return;
307     struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
308     if (!pipe)
309         return;
310 
311     for (;;) {
312         struct keyevent data;
313         int ret = usb_poll_intr(pipe, &data);
314         if (ret)
315             break;
316         handle_key(&data);
317     }
318 }
319 
320 // Test if USB keyboard is active.
321 inline int
usb_kbd_active(void)322 usb_kbd_active(void)
323 {
324     if (! CONFIG_USB_KEYBOARD)
325         return 0;
326     return GET_GLOBAL(keyboard_pipe) != NULL;
327 }
328 
329 // Handle a ps2 style keyboard command.
330 inline int
usb_kbd_command(int command,u8 * param)331 usb_kbd_command(int command, u8 *param)
332 {
333     if (! CONFIG_USB_KEYBOARD)
334         return -1;
335     dprintf(9, "usb keyboard cmd=%x\n", command);
336     switch (command) {
337     case ATKBD_CMD_GETID:
338         // Return the id of a standard AT keyboard.
339         param[0] = 0xab;
340         param[1] = 0x83;
341         return 0;
342     default:
343         return -1;
344     }
345 }
346 
347 
348 /****************************************************************
349  * Mouse events
350  ****************************************************************/
351 
352 // Format of USB mouse event data
353 struct mouseevent {
354     u8 buttons;
355     u8 x, y;
356     u8 reserved[5];
357 };
358 
359 // Process USB mouse data.
360 static void
handle_mouse(struct mouseevent * data)361 handle_mouse(struct mouseevent *data)
362 {
363     dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
364 
365     s8 x = data->x, y = -data->y;
366     u8 flag = ((data->buttons & 0x7) | (1<<3)
367                | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
368     process_mouse(flag);
369     process_mouse(x);
370     process_mouse(y);
371 }
372 
373 // Check if a USB mouse event is pending and process it if so.
374 static void
usb_check_mouse(void)375 usb_check_mouse(void)
376 {
377     if (! CONFIG_USB_MOUSE)
378         return;
379     struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
380     if (!pipe)
381         return;
382 
383     for (;;) {
384         struct mouseevent data;
385         int ret = usb_poll_intr(pipe, &data);
386         if (ret)
387             break;
388         handle_mouse(&data);
389     }
390 }
391 
392 // Test if USB mouse is active.
393 inline int
usb_mouse_active(void)394 usb_mouse_active(void)
395 {
396     if (! CONFIG_USB_MOUSE)
397         return 0;
398     return GET_GLOBAL(mouse_pipe) != NULL;
399 }
400 
401 // Handle a ps2 style mouse command.
402 inline int
usb_mouse_command(int command,u8 * param)403 usb_mouse_command(int command, u8 *param)
404 {
405     if (! CONFIG_USB_MOUSE)
406         return -1;
407     dprintf(9, "usb mouse cmd=%x\n", command);
408     switch (command) {
409     case PSMOUSE_CMD_ENABLE:
410     case PSMOUSE_CMD_DISABLE:
411     case PSMOUSE_CMD_SETSCALE11:
412         return 0;
413     case PSMOUSE_CMD_SETSCALE21:
414     case PSMOUSE_CMD_SETRATE:
415     case PSMOUSE_CMD_SETRES:
416         // XXX
417         return 0;
418     case PSMOUSE_CMD_RESET_BAT:
419     case PSMOUSE_CMD_GETID:
420         // Return the id of a standard AT mouse.
421         param[0] = 0xaa;
422         param[1] = 0x00;
423         return 0;
424 
425     case PSMOUSE_CMD_GETINFO:
426         param[0] = 0x00;
427         param[1] = 4;
428         param[2] = 100;
429         return 0;
430 
431     default:
432         return -1;
433     }
434 }
435 
436 // Check for USB events pending - called periodically from timer interrupt.
437 void
usb_check_event(void)438 usb_check_event(void)
439 {
440     usb_check_key();
441     usb_check_mouse();
442 }
443