|
|
1.1 ! root 1: /* ! 2: * QEMU USB HID devices ! 3: * ! 4: * Copyright (c) 2005 Fabrice Bellard ! 5: * Copyright (c) 2007 OpenMoko, Inc. ([email protected]) ! 6: * ! 7: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 8: * of this software and associated documentation files (the "Software"), to deal ! 9: * in the Software without restriction, including without limitation the rights ! 10: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 11: * copies of the Software, and to permit persons to whom the Software is ! 12: * furnished to do so, subject to the following conditions: ! 13: * ! 14: * The above copyright notice and this permission notice shall be included in ! 15: * all copies or substantial portions of the Software. ! 16: * ! 17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 18: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 22: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 23: * THE SOFTWARE. ! 24: */ ! 25: #include "hw/hw.h" ! 26: #include "console.h" ! 27: #include "hw/usb.h" ! 28: #include "hw/usb/desc.h" ! 29: #include "qemu-timer.h" ! 30: #include "hw/hid.h" ! 31: ! 32: /* HID interface requests */ ! 33: #define GET_REPORT 0xa101 ! 34: #define GET_IDLE 0xa102 ! 35: #define GET_PROTOCOL 0xa103 ! 36: #define SET_REPORT 0x2109 ! 37: #define SET_IDLE 0x210a ! 38: #define SET_PROTOCOL 0x210b ! 39: ! 40: /* HID descriptor types */ ! 41: #define USB_DT_HID 0x21 ! 42: #define USB_DT_REPORT 0x22 ! 43: #define USB_DT_PHY 0x23 ! 44: ! 45: typedef struct USBHIDState { ! 46: USBDevice dev; ! 47: USBEndpoint *intr; ! 48: HIDState hid; ! 49: } USBHIDState; ! 50: ! 51: enum { ! 52: STR_MANUFACTURER = 1, ! 53: STR_PRODUCT_MOUSE, ! 54: STR_PRODUCT_TABLET, ! 55: STR_PRODUCT_KEYBOARD, ! 56: STR_SERIALNUMBER, ! 57: STR_CONFIG_MOUSE, ! 58: STR_CONFIG_TABLET, ! 59: STR_CONFIG_KEYBOARD, ! 60: }; ! 61: ! 62: static const USBDescStrings desc_strings = { ! 63: [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, ! 64: [STR_PRODUCT_MOUSE] = "QEMU USB Mouse", ! 65: [STR_PRODUCT_TABLET] = "QEMU USB Tablet", ! 66: [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard", ! 67: [STR_SERIALNUMBER] = "42", /* == remote wakeup works */ ! 68: [STR_CONFIG_MOUSE] = "HID Mouse", ! 69: [STR_CONFIG_TABLET] = "HID Tablet", ! 70: [STR_CONFIG_KEYBOARD] = "HID Keyboard", ! 71: }; ! 72: ! 73: static const USBDescIface desc_iface_mouse = { ! 74: .bInterfaceNumber = 0, ! 75: .bNumEndpoints = 1, ! 76: .bInterfaceClass = USB_CLASS_HID, ! 77: .bInterfaceSubClass = 0x01, /* boot */ ! 78: .bInterfaceProtocol = 0x02, ! 79: .ndesc = 1, ! 80: .descs = (USBDescOther[]) { ! 81: { ! 82: /* HID descriptor */ ! 83: .data = (uint8_t[]) { ! 84: 0x09, /* u8 bLength */ ! 85: USB_DT_HID, /* u8 bDescriptorType */ ! 86: 0x01, 0x00, /* u16 HID_class */ ! 87: 0x00, /* u8 country_code */ ! 88: 0x01, /* u8 num_descriptors */ ! 89: USB_DT_REPORT, /* u8 type: Report */ ! 90: 52, 0, /* u16 len */ ! 91: }, ! 92: }, ! 93: }, ! 94: .eps = (USBDescEndpoint[]) { ! 95: { ! 96: .bEndpointAddress = USB_DIR_IN | 0x01, ! 97: .bmAttributes = USB_ENDPOINT_XFER_INT, ! 98: .wMaxPacketSize = 4, ! 99: .bInterval = 0x0a, ! 100: }, ! 101: }, ! 102: }; ! 103: ! 104: static const USBDescIface desc_iface_tablet = { ! 105: .bInterfaceNumber = 0, ! 106: .bNumEndpoints = 1, ! 107: .bInterfaceClass = USB_CLASS_HID, ! 108: .bInterfaceProtocol = 0x02, ! 109: .ndesc = 1, ! 110: .descs = (USBDescOther[]) { ! 111: { ! 112: /* HID descriptor */ ! 113: .data = (uint8_t[]) { ! 114: 0x09, /* u8 bLength */ ! 115: USB_DT_HID, /* u8 bDescriptorType */ ! 116: 0x01, 0x00, /* u16 HID_class */ ! 117: 0x00, /* u8 country_code */ ! 118: 0x01, /* u8 num_descriptors */ ! 119: USB_DT_REPORT, /* u8 type: Report */ ! 120: 74, 0, /* u16 len */ ! 121: }, ! 122: }, ! 123: }, ! 124: .eps = (USBDescEndpoint[]) { ! 125: { ! 126: .bEndpointAddress = USB_DIR_IN | 0x01, ! 127: .bmAttributes = USB_ENDPOINT_XFER_INT, ! 128: .wMaxPacketSize = 8, ! 129: .bInterval = 0x0a, ! 130: }, ! 131: }, ! 132: }; ! 133: ! 134: static const USBDescIface desc_iface_keyboard = { ! 135: .bInterfaceNumber = 0, ! 136: .bNumEndpoints = 1, ! 137: .bInterfaceClass = USB_CLASS_HID, ! 138: .bInterfaceSubClass = 0x01, /* boot */ ! 139: .bInterfaceProtocol = 0x01, /* keyboard */ ! 140: .ndesc = 1, ! 141: .descs = (USBDescOther[]) { ! 142: { ! 143: /* HID descriptor */ ! 144: .data = (uint8_t[]) { ! 145: 0x09, /* u8 bLength */ ! 146: USB_DT_HID, /* u8 bDescriptorType */ ! 147: 0x11, 0x01, /* u16 HID_class */ ! 148: 0x00, /* u8 country_code */ ! 149: 0x01, /* u8 num_descriptors */ ! 150: USB_DT_REPORT, /* u8 type: Report */ ! 151: 0x3f, 0, /* u16 len */ ! 152: }, ! 153: }, ! 154: }, ! 155: .eps = (USBDescEndpoint[]) { ! 156: { ! 157: .bEndpointAddress = USB_DIR_IN | 0x01, ! 158: .bmAttributes = USB_ENDPOINT_XFER_INT, ! 159: .wMaxPacketSize = 8, ! 160: .bInterval = 0x0a, ! 161: }, ! 162: }, ! 163: }; ! 164: ! 165: static const USBDescDevice desc_device_mouse = { ! 166: .bcdUSB = 0x0100, ! 167: .bMaxPacketSize0 = 8, ! 168: .bNumConfigurations = 1, ! 169: .confs = (USBDescConfig[]) { ! 170: { ! 171: .bNumInterfaces = 1, ! 172: .bConfigurationValue = 1, ! 173: .iConfiguration = STR_CONFIG_MOUSE, ! 174: .bmAttributes = 0xa0, ! 175: .bMaxPower = 50, ! 176: .nif = 1, ! 177: .ifs = &desc_iface_mouse, ! 178: }, ! 179: }, ! 180: }; ! 181: ! 182: static const USBDescDevice desc_device_tablet = { ! 183: .bcdUSB = 0x0100, ! 184: .bMaxPacketSize0 = 8, ! 185: .bNumConfigurations = 1, ! 186: .confs = (USBDescConfig[]) { ! 187: { ! 188: .bNumInterfaces = 1, ! 189: .bConfigurationValue = 1, ! 190: .iConfiguration = STR_CONFIG_TABLET, ! 191: .bmAttributes = 0xa0, ! 192: .bMaxPower = 50, ! 193: .nif = 1, ! 194: .ifs = &desc_iface_tablet, ! 195: }, ! 196: }, ! 197: }; ! 198: ! 199: static const USBDescDevice desc_device_keyboard = { ! 200: .bcdUSB = 0x0100, ! 201: .bMaxPacketSize0 = 8, ! 202: .bNumConfigurations = 1, ! 203: .confs = (USBDescConfig[]) { ! 204: { ! 205: .bNumInterfaces = 1, ! 206: .bConfigurationValue = 1, ! 207: .iConfiguration = STR_CONFIG_KEYBOARD, ! 208: .bmAttributes = 0xa0, ! 209: .bMaxPower = 50, ! 210: .nif = 1, ! 211: .ifs = &desc_iface_keyboard, ! 212: }, ! 213: }, ! 214: }; ! 215: ! 216: static const USBDesc desc_mouse = { ! 217: .id = { ! 218: .idVendor = 0x0627, ! 219: .idProduct = 0x0001, ! 220: .bcdDevice = 0, ! 221: .iManufacturer = STR_MANUFACTURER, ! 222: .iProduct = STR_PRODUCT_MOUSE, ! 223: .iSerialNumber = STR_SERIALNUMBER, ! 224: }, ! 225: .full = &desc_device_mouse, ! 226: .str = desc_strings, ! 227: }; ! 228: ! 229: static const USBDesc desc_tablet = { ! 230: .id = { ! 231: .idVendor = 0x0627, ! 232: .idProduct = 0x0001, ! 233: .bcdDevice = 0, ! 234: .iManufacturer = STR_MANUFACTURER, ! 235: .iProduct = STR_PRODUCT_TABLET, ! 236: .iSerialNumber = STR_SERIALNUMBER, ! 237: }, ! 238: .full = &desc_device_tablet, ! 239: .str = desc_strings, ! 240: }; ! 241: ! 242: static const USBDesc desc_keyboard = { ! 243: .id = { ! 244: .idVendor = 0x0627, ! 245: .idProduct = 0x0001, ! 246: .bcdDevice = 0, ! 247: .iManufacturer = STR_MANUFACTURER, ! 248: .iProduct = STR_PRODUCT_KEYBOARD, ! 249: .iSerialNumber = STR_SERIALNUMBER, ! 250: }, ! 251: .full = &desc_device_keyboard, ! 252: .str = desc_strings, ! 253: }; ! 254: ! 255: static const uint8_t qemu_mouse_hid_report_descriptor[] = { ! 256: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 257: 0x09, 0x02, /* Usage (Mouse) */ ! 258: 0xa1, 0x01, /* Collection (Application) */ ! 259: 0x09, 0x01, /* Usage (Pointer) */ ! 260: 0xa1, 0x00, /* Collection (Physical) */ ! 261: 0x05, 0x09, /* Usage Page (Button) */ ! 262: 0x19, 0x01, /* Usage Minimum (1) */ ! 263: 0x29, 0x03, /* Usage Maximum (3) */ ! 264: 0x15, 0x00, /* Logical Minimum (0) */ ! 265: 0x25, 0x01, /* Logical Maximum (1) */ ! 266: 0x95, 0x03, /* Report Count (3) */ ! 267: 0x75, 0x01, /* Report Size (1) */ ! 268: 0x81, 0x02, /* Input (Data, Variable, Absolute) */ ! 269: 0x95, 0x01, /* Report Count (1) */ ! 270: 0x75, 0x05, /* Report Size (5) */ ! 271: 0x81, 0x01, /* Input (Constant) */ ! 272: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 273: 0x09, 0x30, /* Usage (X) */ ! 274: 0x09, 0x31, /* Usage (Y) */ ! 275: 0x09, 0x38, /* Usage (Wheel) */ ! 276: 0x15, 0x81, /* Logical Minimum (-0x7f) */ ! 277: 0x25, 0x7f, /* Logical Maximum (0x7f) */ ! 278: 0x75, 0x08, /* Report Size (8) */ ! 279: 0x95, 0x03, /* Report Count (3) */ ! 280: 0x81, 0x06, /* Input (Data, Variable, Relative) */ ! 281: 0xc0, /* End Collection */ ! 282: 0xc0, /* End Collection */ ! 283: }; ! 284: ! 285: static const uint8_t qemu_tablet_hid_report_descriptor[] = { ! 286: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 287: 0x09, 0x01, /* Usage (Pointer) */ ! 288: 0xa1, 0x01, /* Collection (Application) */ ! 289: 0x09, 0x01, /* Usage (Pointer) */ ! 290: 0xa1, 0x00, /* Collection (Physical) */ ! 291: 0x05, 0x09, /* Usage Page (Button) */ ! 292: 0x19, 0x01, /* Usage Minimum (1) */ ! 293: 0x29, 0x03, /* Usage Maximum (3) */ ! 294: 0x15, 0x00, /* Logical Minimum (0) */ ! 295: 0x25, 0x01, /* Logical Maximum (1) */ ! 296: 0x95, 0x03, /* Report Count (3) */ ! 297: 0x75, 0x01, /* Report Size (1) */ ! 298: 0x81, 0x02, /* Input (Data, Variable, Absolute) */ ! 299: 0x95, 0x01, /* Report Count (1) */ ! 300: 0x75, 0x05, /* Report Size (5) */ ! 301: 0x81, 0x01, /* Input (Constant) */ ! 302: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 303: 0x09, 0x30, /* Usage (X) */ ! 304: 0x09, 0x31, /* Usage (Y) */ ! 305: 0x15, 0x00, /* Logical Minimum (0) */ ! 306: 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */ ! 307: 0x35, 0x00, /* Physical Minimum (0) */ ! 308: 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */ ! 309: 0x75, 0x10, /* Report Size (16) */ ! 310: 0x95, 0x02, /* Report Count (2) */ ! 311: 0x81, 0x02, /* Input (Data, Variable, Absolute) */ ! 312: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 313: 0x09, 0x38, /* Usage (Wheel) */ ! 314: 0x15, 0x81, /* Logical Minimum (-0x7f) */ ! 315: 0x25, 0x7f, /* Logical Maximum (0x7f) */ ! 316: 0x35, 0x00, /* Physical Minimum (same as logical) */ ! 317: 0x45, 0x00, /* Physical Maximum (same as logical) */ ! 318: 0x75, 0x08, /* Report Size (8) */ ! 319: 0x95, 0x01, /* Report Count (1) */ ! 320: 0x81, 0x06, /* Input (Data, Variable, Relative) */ ! 321: 0xc0, /* End Collection */ ! 322: 0xc0, /* End Collection */ ! 323: }; ! 324: ! 325: static const uint8_t qemu_keyboard_hid_report_descriptor[] = { ! 326: 0x05, 0x01, /* Usage Page (Generic Desktop) */ ! 327: 0x09, 0x06, /* Usage (Keyboard) */ ! 328: 0xa1, 0x01, /* Collection (Application) */ ! 329: 0x75, 0x01, /* Report Size (1) */ ! 330: 0x95, 0x08, /* Report Count (8) */ ! 331: 0x05, 0x07, /* Usage Page (Key Codes) */ ! 332: 0x19, 0xe0, /* Usage Minimum (224) */ ! 333: 0x29, 0xe7, /* Usage Maximum (231) */ ! 334: 0x15, 0x00, /* Logical Minimum (0) */ ! 335: 0x25, 0x01, /* Logical Maximum (1) */ ! 336: 0x81, 0x02, /* Input (Data, Variable, Absolute) */ ! 337: 0x95, 0x01, /* Report Count (1) */ ! 338: 0x75, 0x08, /* Report Size (8) */ ! 339: 0x81, 0x01, /* Input (Constant) */ ! 340: 0x95, 0x05, /* Report Count (5) */ ! 341: 0x75, 0x01, /* Report Size (1) */ ! 342: 0x05, 0x08, /* Usage Page (LEDs) */ ! 343: 0x19, 0x01, /* Usage Minimum (1) */ ! 344: 0x29, 0x05, /* Usage Maximum (5) */ ! 345: 0x91, 0x02, /* Output (Data, Variable, Absolute) */ ! 346: 0x95, 0x01, /* Report Count (1) */ ! 347: 0x75, 0x03, /* Report Size (3) */ ! 348: 0x91, 0x01, /* Output (Constant) */ ! 349: 0x95, 0x06, /* Report Count (6) */ ! 350: 0x75, 0x08, /* Report Size (8) */ ! 351: 0x15, 0x00, /* Logical Minimum (0) */ ! 352: 0x25, 0xff, /* Logical Maximum (255) */ ! 353: 0x05, 0x07, /* Usage Page (Key Codes) */ ! 354: 0x19, 0x00, /* Usage Minimum (0) */ ! 355: 0x29, 0xff, /* Usage Maximum (255) */ ! 356: 0x81, 0x00, /* Input (Data, Array) */ ! 357: 0xc0, /* End Collection */ ! 358: }; ! 359: ! 360: static void usb_hid_changed(HIDState *hs) ! 361: { ! 362: USBHIDState *us = container_of(hs, USBHIDState, hid); ! 363: ! 364: usb_wakeup(us->intr); ! 365: } ! 366: ! 367: static void usb_hid_handle_reset(USBDevice *dev) ! 368: { ! 369: USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); ! 370: ! 371: hid_reset(&us->hid); ! 372: } ! 373: ! 374: static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, ! 375: int request, int value, int index, int length, uint8_t *data) ! 376: { ! 377: USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); ! 378: HIDState *hs = &us->hid; ! 379: int ret; ! 380: ! 381: ret = usb_desc_handle_control(dev, p, request, value, index, length, data); ! 382: if (ret >= 0) { ! 383: return ret; ! 384: } ! 385: ! 386: ret = 0; ! 387: switch (request) { ! 388: /* hid specific requests */ ! 389: case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: ! 390: switch (value >> 8) { ! 391: case 0x22: ! 392: if (hs->kind == HID_MOUSE) { ! 393: memcpy(data, qemu_mouse_hid_report_descriptor, ! 394: sizeof(qemu_mouse_hid_report_descriptor)); ! 395: ret = sizeof(qemu_mouse_hid_report_descriptor); ! 396: } else if (hs->kind == HID_TABLET) { ! 397: memcpy(data, qemu_tablet_hid_report_descriptor, ! 398: sizeof(qemu_tablet_hid_report_descriptor)); ! 399: ret = sizeof(qemu_tablet_hid_report_descriptor); ! 400: } else if (hs->kind == HID_KEYBOARD) { ! 401: memcpy(data, qemu_keyboard_hid_report_descriptor, ! 402: sizeof(qemu_keyboard_hid_report_descriptor)); ! 403: ret = sizeof(qemu_keyboard_hid_report_descriptor); ! 404: } ! 405: break; ! 406: default: ! 407: goto fail; ! 408: } ! 409: break; ! 410: case GET_REPORT: ! 411: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { ! 412: ret = hid_pointer_poll(hs, data, length); ! 413: } else if (hs->kind == HID_KEYBOARD) { ! 414: ret = hid_keyboard_poll(hs, data, length); ! 415: } ! 416: break; ! 417: case SET_REPORT: ! 418: if (hs->kind == HID_KEYBOARD) { ! 419: ret = hid_keyboard_write(hs, data, length); ! 420: } else { ! 421: goto fail; ! 422: } ! 423: break; ! 424: case GET_PROTOCOL: ! 425: if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { ! 426: goto fail; ! 427: } ! 428: ret = 1; ! 429: data[0] = hs->protocol; ! 430: break; ! 431: case SET_PROTOCOL: ! 432: if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { ! 433: goto fail; ! 434: } ! 435: ret = 0; ! 436: hs->protocol = value; ! 437: break; ! 438: case GET_IDLE: ! 439: ret = 1; ! 440: data[0] = hs->idle; ! 441: break; ! 442: case SET_IDLE: ! 443: hs->idle = (uint8_t) (value >> 8); ! 444: hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); ! 445: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { ! 446: hid_pointer_activate(hs); ! 447: } ! 448: ret = 0; ! 449: break; ! 450: default: ! 451: fail: ! 452: ret = USB_RET_STALL; ! 453: break; ! 454: } ! 455: return ret; ! 456: } ! 457: ! 458: static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) ! 459: { ! 460: USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); ! 461: HIDState *hs = &us->hid; ! 462: uint8_t buf[p->iov.size]; ! 463: int ret = 0; ! 464: ! 465: switch (p->pid) { ! 466: case USB_TOKEN_IN: ! 467: if (p->ep->nr == 1) { ! 468: int64_t curtime = qemu_get_clock_ns(vm_clock); ! 469: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { ! 470: hid_pointer_activate(hs); ! 471: } ! 472: if (!hid_has_events(hs) && ! 473: (!hs->idle || hs->next_idle_clock - curtime > 0)) { ! 474: return USB_RET_NAK; ! 475: } ! 476: hid_set_next_idle(hs, curtime); ! 477: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { ! 478: ret = hid_pointer_poll(hs, buf, p->iov.size); ! 479: } else if (hs->kind == HID_KEYBOARD) { ! 480: ret = hid_keyboard_poll(hs, buf, p->iov.size); ! 481: } ! 482: usb_packet_copy(p, buf, ret); ! 483: } else { ! 484: goto fail; ! 485: } ! 486: break; ! 487: case USB_TOKEN_OUT: ! 488: default: ! 489: fail: ! 490: ret = USB_RET_STALL; ! 491: break; ! 492: } ! 493: return ret; ! 494: } ! 495: ! 496: static void usb_hid_handle_destroy(USBDevice *dev) ! 497: { ! 498: USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); ! 499: ! 500: hid_free(&us->hid); ! 501: } ! 502: ! 503: static int usb_hid_initfn(USBDevice *dev, int kind) ! 504: { ! 505: USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); ! 506: ! 507: usb_desc_init(dev); ! 508: us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); ! 509: hid_init(&us->hid, kind, usb_hid_changed); ! 510: return 0; ! 511: } ! 512: ! 513: static int usb_tablet_initfn(USBDevice *dev) ! 514: { ! 515: return usb_hid_initfn(dev, HID_TABLET); ! 516: } ! 517: ! 518: static int usb_mouse_initfn(USBDevice *dev) ! 519: { ! 520: return usb_hid_initfn(dev, HID_MOUSE); ! 521: } ! 522: ! 523: static int usb_keyboard_initfn(USBDevice *dev) ! 524: { ! 525: return usb_hid_initfn(dev, HID_KEYBOARD); ! 526: } ! 527: ! 528: static int usb_ptr_post_load(void *opaque, int version_id) ! 529: { ! 530: USBHIDState *s = opaque; ! 531: ! 532: if (s->dev.remote_wakeup) { ! 533: hid_pointer_activate(&s->hid); ! 534: } ! 535: return 0; ! 536: } ! 537: ! 538: static const VMStateDescription vmstate_usb_ptr = { ! 539: .name = "usb-ptr", ! 540: .version_id = 1, ! 541: .minimum_version_id = 1, ! 542: .post_load = usb_ptr_post_load, ! 543: .fields = (VMStateField []) { ! 544: VMSTATE_USB_DEVICE(dev, USBHIDState), ! 545: VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState), ! 546: VMSTATE_END_OF_LIST() ! 547: } ! 548: }; ! 549: ! 550: static const VMStateDescription vmstate_usb_kbd = { ! 551: .name = "usb-kbd", ! 552: .version_id = 1, ! 553: .minimum_version_id = 1, ! 554: .fields = (VMStateField []) { ! 555: VMSTATE_USB_DEVICE(dev, USBHIDState), ! 556: VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState), ! 557: VMSTATE_END_OF_LIST() ! 558: } ! 559: }; ! 560: ! 561: static void usb_hid_class_initfn(ObjectClass *klass, void *data) ! 562: { ! 563: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 564: ! 565: uc->handle_reset = usb_hid_handle_reset; ! 566: uc->handle_control = usb_hid_handle_control; ! 567: uc->handle_data = usb_hid_handle_data; ! 568: uc->handle_destroy = usb_hid_handle_destroy; ! 569: } ! 570: ! 571: static void usb_tablet_class_initfn(ObjectClass *klass, void *data) ! 572: { ! 573: DeviceClass *dc = DEVICE_CLASS(klass); ! 574: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 575: ! 576: usb_hid_class_initfn(klass, data); ! 577: uc->init = usb_tablet_initfn; ! 578: uc->product_desc = "QEMU USB Tablet"; ! 579: uc->usb_desc = &desc_tablet; ! 580: dc->vmsd = &vmstate_usb_ptr; ! 581: } ! 582: ! 583: static TypeInfo usb_tablet_info = { ! 584: .name = "usb-tablet", ! 585: .parent = TYPE_USB_DEVICE, ! 586: .instance_size = sizeof(USBHIDState), ! 587: .class_init = usb_tablet_class_initfn, ! 588: }; ! 589: ! 590: static void usb_mouse_class_initfn(ObjectClass *klass, void *data) ! 591: { ! 592: DeviceClass *dc = DEVICE_CLASS(klass); ! 593: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 594: ! 595: usb_hid_class_initfn(klass, data); ! 596: uc->init = usb_mouse_initfn; ! 597: uc->product_desc = "QEMU USB Mouse"; ! 598: uc->usb_desc = &desc_mouse; ! 599: dc->vmsd = &vmstate_usb_ptr; ! 600: } ! 601: ! 602: static TypeInfo usb_mouse_info = { ! 603: .name = "usb-mouse", ! 604: .parent = TYPE_USB_DEVICE, ! 605: .instance_size = sizeof(USBHIDState), ! 606: .class_init = usb_mouse_class_initfn, ! 607: }; ! 608: ! 609: static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) ! 610: { ! 611: DeviceClass *dc = DEVICE_CLASS(klass); ! 612: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 613: ! 614: usb_hid_class_initfn(klass, data); ! 615: uc->init = usb_keyboard_initfn; ! 616: uc->product_desc = "QEMU USB Keyboard"; ! 617: uc->usb_desc = &desc_keyboard; ! 618: dc->vmsd = &vmstate_usb_kbd; ! 619: } ! 620: ! 621: static TypeInfo usb_keyboard_info = { ! 622: .name = "usb-kbd", ! 623: .parent = TYPE_USB_DEVICE, ! 624: .instance_size = sizeof(USBHIDState), ! 625: .class_init = usb_keyboard_class_initfn, ! 626: }; ! 627: ! 628: static void usb_hid_register_types(void) ! 629: { ! 630: type_register_static(&usb_tablet_info); ! 631: usb_legacy_register("usb-tablet", "tablet", NULL); ! 632: type_register_static(&usb_mouse_info); ! 633: usb_legacy_register("usb-mouse", "mouse", NULL); ! 634: type_register_static(&usb_keyboard_info); ! 635: usb_legacy_register("usb-kbd", "keyboard", NULL); ! 636: } ! 637: ! 638: type_init(usb_hid_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.