|
|
1.1 root 1: // Code for handling USB Human Interface Devices (HID).
2: //
3: // Copyright (C) 2009 Kevin O'Connor <[email protected]>
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
1.1.1.3 ! root 12: #include "ps2port.h" // ATKBD_CMD_GETID
1.1 root 13:
14: struct usb_pipe *keyboard_pipe VAR16VISIBLE;
1.1.1.3 ! root 15: struct usb_pipe *mouse_pipe VAR16VISIBLE;
1.1 root 16:
17:
18: /****************************************************************
19: * Setup
20: ****************************************************************/
21:
1.1.1.3 ! root 22: // Send USB HID protocol message.
1.1 root 23: static int
1.1.1.3 ! root 24: set_protocol(struct usb_pipe *pipe, u16 val)
1.1 root 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;
1.1.1.3 ! root 32: return send_default_control(pipe, &req, NULL);
1.1 root 33: }
34:
1.1.1.3 ! root 35: // Send USB HID SetIdle request.
1.1 root 36: static int
1.1.1.3 ! root 37: set_idle(struct usb_pipe *pipe, int ms)
1.1 root 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;
1.1.1.3 ! root 42: req.wValue = (ms/4)<<8;
1.1 root 43: req.wIndex = 0;
44: req.wLength = 0;
1.1.1.3 ! root 45: return send_default_control(pipe, &req, NULL);
1.1 root 46: }
47:
1.1.1.3 ! root 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)
1.1 root 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:
1.1.1.3 ! root 60: if (epdesc->wMaxPacketSize != 8)
! 61: return -1;
1.1 root 62:
63: // Enable "boot" protocol.
1.1.1.3 ! root 64: int ret = set_protocol(pipe, 0);
1.1 root 65: if (ret)
66: return -1;
1.1.1.3 ! root 67: // Periodically send reports to enable key repeat.
! 68: ret = set_idle(pipe, KEYREPEATMS);
1.1 root 69: if (ret)
70: return -1;
71:
1.1.1.3 ! root 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)
1.1 root 99: return -1;
100:
1.1.1.3 ! root 101: dprintf(1, "USB mouse initialized\n");
1.1 root 102: return 0;
103: }
104:
1.1.1.3 ! root 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:
1.1 root 133: void
1.1.1.3 ! root 134: usb_hid_setup(void)
1.1 root 135: {
1.1.1.3 ! root 136: if (CONFIG_USB_KEYBOARD)
! 137: keyboard_pipe = NULL;
! 138: if (CONFIG_USB_MOUSE)
! 139: mouse_pipe = NULL;
1.1 root 140: }
141:
142:
143: /****************************************************************
144: * Keyboard events
145: ****************************************************************/
146:
1.1.1.3 ! root 147: // Mapping from USB key id to ps2 key sequence.
1.1 root 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:
1.1.1.3 ! root 164: // Mapping from USB modifier id to ps2 key sequence.
1.1 root 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:
1.1.1.3 ! root 170: #define RELEASEBIT 0x80
! 171:
! 172: // Format of USB keyboard event data
1.1 root 173: struct keyevent {
174: u8 modifiers;
175: u8 reserved;
176: u8 keys[6];
177: };
178:
1.1.1.3 ! root 179: // Translate data from KeyToScanCode[] to calls to process_key().
1.1 root 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);
1.1.1.3 ! root 188: process_key(0x1d | (keys & RELEASEBIT));
! 189: process_key(0x45 | (keys & RELEASEBIT));
1.1 root 190: return;
191: }
192: process_key(key);
193: }
194: process_key(keys);
195: }
196:
1.1.1.3 ! root 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.
1.1 root 209: static void
1.1.1.3 ! root 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
1.1 root 223: handle_key(struct keyevent *data)
224: {
1.1.1.3 ! root 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;
1.1 root 234: int i;
1.1.1.3 ! root 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;
1.1 root 262: for (i=0; i<ARRAY_SIZE(data->keys); i++) {
263: u8 key = data->keys[i];
264: if (!key)
265: continue;
1.1.1.3 ! root 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--;
1.1 root 280: }
1.1.1.3 ! root 281:
! 282: // Update old keys
! 283: SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
1.1 root 284: }
285:
1.1.1.3 ! root 286: // Check if a USB keyboard event is pending and process it if so.
! 287: static void
1.1.1.2 root 288: usb_check_key(void)
1.1 root 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: }
1.1.1.3 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.