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