|  | /* | 
|  | * QEMU USB HID devices | 
|  | * | 
|  | * Copyright (c) 2005 Fabrice Bellard | 
|  | * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com) | 
|  | * | 
|  | * Permission is hereby granted, free of charge, to any person obtaining a copy | 
|  | * of this software and associated documentation files (the "Software"), to deal | 
|  | * in the Software without restriction, including without limitation the rights | 
|  | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|  | * copies of the Software, and to permit persons to whom the Software is | 
|  | * furnished to do so, subject to the following conditions: | 
|  | * | 
|  | * The above copyright notice and this permission notice shall be included in | 
|  | * all copies or substantial portions of the Software. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
|  | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|  | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|  | * THE SOFTWARE. | 
|  | */ | 
|  | #include "hw/hw.h" | 
|  | #include "console.h" | 
|  | #include "hw/usb.h" | 
|  | #include "hw/usb/desc.h" | 
|  | #include "qemu-timer.h" | 
|  | #include "hw/hid.h" | 
|  |  | 
|  | /* HID interface requests */ | 
|  | #define GET_REPORT   0xa101 | 
|  | #define GET_IDLE     0xa102 | 
|  | #define GET_PROTOCOL 0xa103 | 
|  | #define SET_REPORT   0x2109 | 
|  | #define SET_IDLE     0x210a | 
|  | #define SET_PROTOCOL 0x210b | 
|  |  | 
|  | /* HID descriptor types */ | 
|  | #define USB_DT_HID    0x21 | 
|  | #define USB_DT_REPORT 0x22 | 
|  | #define USB_DT_PHY    0x23 | 
|  |  | 
|  | typedef struct USBHIDState { | 
|  | USBDevice dev; | 
|  | USBEndpoint *intr; | 
|  | HIDState hid; | 
|  | } USBHIDState; | 
|  |  | 
|  | enum { | 
|  | STR_MANUFACTURER = 1, | 
|  | STR_PRODUCT_MOUSE, | 
|  | STR_PRODUCT_TABLET, | 
|  | STR_PRODUCT_KEYBOARD, | 
|  | STR_SERIALNUMBER, | 
|  | STR_CONFIG_MOUSE, | 
|  | STR_CONFIG_TABLET, | 
|  | STR_CONFIG_KEYBOARD, | 
|  | }; | 
|  |  | 
|  | static const USBDescStrings desc_strings = { | 
|  | [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION, | 
|  | [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse", | 
|  | [STR_PRODUCT_TABLET]   = "QEMU USB Tablet", | 
|  | [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard", | 
|  | [STR_SERIALNUMBER]     = "42", /* == remote wakeup works */ | 
|  | [STR_CONFIG_MOUSE]     = "HID Mouse", | 
|  | [STR_CONFIG_TABLET]    = "HID Tablet", | 
|  | [STR_CONFIG_KEYBOARD]  = "HID Keyboard", | 
|  | }; | 
|  |  | 
|  | static const USBDescIface desc_iface_mouse = { | 
|  | .bInterfaceNumber              = 0, | 
|  | .bNumEndpoints                 = 1, | 
|  | .bInterfaceClass               = USB_CLASS_HID, | 
|  | .bInterfaceSubClass            = 0x01, /* boot */ | 
|  | .bInterfaceProtocol            = 0x02, | 
|  | .ndesc                         = 1, | 
|  | .descs = (USBDescOther[]) { | 
|  | { | 
|  | /* HID descriptor */ | 
|  | .data = (uint8_t[]) { | 
|  | 0x09,          /*  u8  bLength */ | 
|  | USB_DT_HID,    /*  u8  bDescriptorType */ | 
|  | 0x01, 0x00,    /*  u16 HID_class */ | 
|  | 0x00,          /*  u8  country_code */ | 
|  | 0x01,          /*  u8  num_descriptors */ | 
|  | USB_DT_REPORT, /*  u8  type: Report */ | 
|  | 52, 0,         /*  u16 len */ | 
|  | }, | 
|  | }, | 
|  | }, | 
|  | .eps = (USBDescEndpoint[]) { | 
|  | { | 
|  | .bEndpointAddress      = USB_DIR_IN | 0x01, | 
|  | .bmAttributes          = USB_ENDPOINT_XFER_INT, | 
|  | .wMaxPacketSize        = 4, | 
|  | .bInterval             = 0x0a, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDescIface desc_iface_tablet = { | 
|  | .bInterfaceNumber              = 0, | 
|  | .bNumEndpoints                 = 1, | 
|  | .bInterfaceClass               = USB_CLASS_HID, | 
|  | .bInterfaceProtocol            = 0x02, | 
|  | .ndesc                         = 1, | 
|  | .descs = (USBDescOther[]) { | 
|  | { | 
|  | /* HID descriptor */ | 
|  | .data = (uint8_t[]) { | 
|  | 0x09,          /*  u8  bLength */ | 
|  | USB_DT_HID,    /*  u8  bDescriptorType */ | 
|  | 0x01, 0x00,    /*  u16 HID_class */ | 
|  | 0x00,          /*  u8  country_code */ | 
|  | 0x01,          /*  u8  num_descriptors */ | 
|  | USB_DT_REPORT, /*  u8  type: Report */ | 
|  | 74, 0,         /*  u16 len */ | 
|  | }, | 
|  | }, | 
|  | }, | 
|  | .eps = (USBDescEndpoint[]) { | 
|  | { | 
|  | .bEndpointAddress      = USB_DIR_IN | 0x01, | 
|  | .bmAttributes          = USB_ENDPOINT_XFER_INT, | 
|  | .wMaxPacketSize        = 8, | 
|  | .bInterval             = 0x0a, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDescIface desc_iface_keyboard = { | 
|  | .bInterfaceNumber              = 0, | 
|  | .bNumEndpoints                 = 1, | 
|  | .bInterfaceClass               = USB_CLASS_HID, | 
|  | .bInterfaceSubClass            = 0x01, /* boot */ | 
|  | .bInterfaceProtocol            = 0x01, /* keyboard */ | 
|  | .ndesc                         = 1, | 
|  | .descs = (USBDescOther[]) { | 
|  | { | 
|  | /* HID descriptor */ | 
|  | .data = (uint8_t[]) { | 
|  | 0x09,          /*  u8  bLength */ | 
|  | USB_DT_HID,    /*  u8  bDescriptorType */ | 
|  | 0x11, 0x01,    /*  u16 HID_class */ | 
|  | 0x00,          /*  u8  country_code */ | 
|  | 0x01,          /*  u8  num_descriptors */ | 
|  | USB_DT_REPORT, /*  u8  type: Report */ | 
|  | 0x3f, 0,       /*  u16 len */ | 
|  | }, | 
|  | }, | 
|  | }, | 
|  | .eps = (USBDescEndpoint[]) { | 
|  | { | 
|  | .bEndpointAddress      = USB_DIR_IN | 0x01, | 
|  | .bmAttributes          = USB_ENDPOINT_XFER_INT, | 
|  | .wMaxPacketSize        = 8, | 
|  | .bInterval             = 0x0a, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDescDevice desc_device_mouse = { | 
|  | .bcdUSB                        = 0x0100, | 
|  | .bMaxPacketSize0               = 8, | 
|  | .bNumConfigurations            = 1, | 
|  | .confs = (USBDescConfig[]) { | 
|  | { | 
|  | .bNumInterfaces        = 1, | 
|  | .bConfigurationValue   = 1, | 
|  | .iConfiguration        = STR_CONFIG_MOUSE, | 
|  | .bmAttributes          = 0xa0, | 
|  | .bMaxPower             = 50, | 
|  | .nif = 1, | 
|  | .ifs = &desc_iface_mouse, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDescDevice desc_device_tablet = { | 
|  | .bcdUSB                        = 0x0100, | 
|  | .bMaxPacketSize0               = 8, | 
|  | .bNumConfigurations            = 1, | 
|  | .confs = (USBDescConfig[]) { | 
|  | { | 
|  | .bNumInterfaces        = 1, | 
|  | .bConfigurationValue   = 1, | 
|  | .iConfiguration        = STR_CONFIG_TABLET, | 
|  | .bmAttributes          = 0xa0, | 
|  | .bMaxPower             = 50, | 
|  | .nif = 1, | 
|  | .ifs = &desc_iface_tablet, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDescDevice desc_device_keyboard = { | 
|  | .bcdUSB                        = 0x0100, | 
|  | .bMaxPacketSize0               = 8, | 
|  | .bNumConfigurations            = 1, | 
|  | .confs = (USBDescConfig[]) { | 
|  | { | 
|  | .bNumInterfaces        = 1, | 
|  | .bConfigurationValue   = 1, | 
|  | .iConfiguration        = STR_CONFIG_KEYBOARD, | 
|  | .bmAttributes          = 0xa0, | 
|  | .bMaxPower             = 50, | 
|  | .nif = 1, | 
|  | .ifs = &desc_iface_keyboard, | 
|  | }, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static const USBDesc desc_mouse = { | 
|  | .id = { | 
|  | .idVendor          = 0x0627, | 
|  | .idProduct         = 0x0001, | 
|  | .bcdDevice         = 0, | 
|  | .iManufacturer     = STR_MANUFACTURER, | 
|  | .iProduct          = STR_PRODUCT_MOUSE, | 
|  | .iSerialNumber     = STR_SERIALNUMBER, | 
|  | }, | 
|  | .full = &desc_device_mouse, | 
|  | .str  = desc_strings, | 
|  | }; | 
|  |  | 
|  | static const USBDesc desc_tablet = { | 
|  | .id = { | 
|  | .idVendor          = 0x0627, | 
|  | .idProduct         = 0x0001, | 
|  | .bcdDevice         = 0, | 
|  | .iManufacturer     = STR_MANUFACTURER, | 
|  | .iProduct          = STR_PRODUCT_TABLET, | 
|  | .iSerialNumber     = STR_SERIALNUMBER, | 
|  | }, | 
|  | .full = &desc_device_tablet, | 
|  | .str  = desc_strings, | 
|  | }; | 
|  |  | 
|  | static const USBDesc desc_keyboard = { | 
|  | .id = { | 
|  | .idVendor          = 0x0627, | 
|  | .idProduct         = 0x0001, | 
|  | .bcdDevice         = 0, | 
|  | .iManufacturer     = STR_MANUFACTURER, | 
|  | .iProduct          = STR_PRODUCT_KEYBOARD, | 
|  | .iSerialNumber     = STR_SERIALNUMBER, | 
|  | }, | 
|  | .full = &desc_device_keyboard, | 
|  | .str  = desc_strings, | 
|  | }; | 
|  |  | 
|  | static const uint8_t qemu_mouse_hid_report_descriptor[] = { | 
|  | 0x05, 0x01,		/* Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x02,		/* Usage (Mouse) */ | 
|  | 0xa1, 0x01,		/* Collection (Application) */ | 
|  | 0x09, 0x01,		/*   Usage (Pointer) */ | 
|  | 0xa1, 0x00,		/*   Collection (Physical) */ | 
|  | 0x05, 0x09,		/*     Usage Page (Button) */ | 
|  | 0x19, 0x01,		/*     Usage Minimum (1) */ | 
|  | 0x29, 0x03,		/*     Usage Maximum (3) */ | 
|  | 0x15, 0x00,		/*     Logical Minimum (0) */ | 
|  | 0x25, 0x01,		/*     Logical Maximum (1) */ | 
|  | 0x95, 0x03,		/*     Report Count (3) */ | 
|  | 0x75, 0x01,		/*     Report Size (1) */ | 
|  | 0x81, 0x02,		/*     Input (Data, Variable, Absolute) */ | 
|  | 0x95, 0x01,		/*     Report Count (1) */ | 
|  | 0x75, 0x05,		/*     Report Size (5) */ | 
|  | 0x81, 0x01,		/*     Input (Constant) */ | 
|  | 0x05, 0x01,		/*     Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x30,		/*     Usage (X) */ | 
|  | 0x09, 0x31,		/*     Usage (Y) */ | 
|  | 0x09, 0x38,		/*     Usage (Wheel) */ | 
|  | 0x15, 0x81,		/*     Logical Minimum (-0x7f) */ | 
|  | 0x25, 0x7f,		/*     Logical Maximum (0x7f) */ | 
|  | 0x75, 0x08,		/*     Report Size (8) */ | 
|  | 0x95, 0x03,		/*     Report Count (3) */ | 
|  | 0x81, 0x06,		/*     Input (Data, Variable, Relative) */ | 
|  | 0xc0,		/*   End Collection */ | 
|  | 0xc0,		/* End Collection */ | 
|  | }; | 
|  |  | 
|  | static const uint8_t qemu_tablet_hid_report_descriptor[] = { | 
|  | 0x05, 0x01,		/* Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x01,		/* Usage (Pointer) */ | 
|  | 0xa1, 0x01,		/* Collection (Application) */ | 
|  | 0x09, 0x01,		/*   Usage (Pointer) */ | 
|  | 0xa1, 0x00,		/*   Collection (Physical) */ | 
|  | 0x05, 0x09,		/*     Usage Page (Button) */ | 
|  | 0x19, 0x01,		/*     Usage Minimum (1) */ | 
|  | 0x29, 0x03,		/*     Usage Maximum (3) */ | 
|  | 0x15, 0x00,		/*     Logical Minimum (0) */ | 
|  | 0x25, 0x01,		/*     Logical Maximum (1) */ | 
|  | 0x95, 0x03,		/*     Report Count (3) */ | 
|  | 0x75, 0x01,		/*     Report Size (1) */ | 
|  | 0x81, 0x02,		/*     Input (Data, Variable, Absolute) */ | 
|  | 0x95, 0x01,		/*     Report Count (1) */ | 
|  | 0x75, 0x05,		/*     Report Size (5) */ | 
|  | 0x81, 0x01,		/*     Input (Constant) */ | 
|  | 0x05, 0x01,		/*     Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x30,		/*     Usage (X) */ | 
|  | 0x09, 0x31,		/*     Usage (Y) */ | 
|  | 0x15, 0x00,		/*     Logical Minimum (0) */ | 
|  | 0x26, 0xff, 0x7f,	/*     Logical Maximum (0x7fff) */ | 
|  | 0x35, 0x00,		/*     Physical Minimum (0) */ | 
|  | 0x46, 0xff, 0x7f,	/*     Physical Maximum (0x7fff) */ | 
|  | 0x75, 0x10,		/*     Report Size (16) */ | 
|  | 0x95, 0x02,		/*     Report Count (2) */ | 
|  | 0x81, 0x02,		/*     Input (Data, Variable, Absolute) */ | 
|  | 0x05, 0x01,		/*     Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x38,		/*     Usage (Wheel) */ | 
|  | 0x15, 0x81,		/*     Logical Minimum (-0x7f) */ | 
|  | 0x25, 0x7f,		/*     Logical Maximum (0x7f) */ | 
|  | 0x35, 0x00,		/*     Physical Minimum (same as logical) */ | 
|  | 0x45, 0x00,		/*     Physical Maximum (same as logical) */ | 
|  | 0x75, 0x08,		/*     Report Size (8) */ | 
|  | 0x95, 0x01,		/*     Report Count (1) */ | 
|  | 0x81, 0x06,		/*     Input (Data, Variable, Relative) */ | 
|  | 0xc0,		/*   End Collection */ | 
|  | 0xc0,		/* End Collection */ | 
|  | }; | 
|  |  | 
|  | static const uint8_t qemu_keyboard_hid_report_descriptor[] = { | 
|  | 0x05, 0x01,		/* Usage Page (Generic Desktop) */ | 
|  | 0x09, 0x06,		/* Usage (Keyboard) */ | 
|  | 0xa1, 0x01,		/* Collection (Application) */ | 
|  | 0x75, 0x01,		/*   Report Size (1) */ | 
|  | 0x95, 0x08,		/*   Report Count (8) */ | 
|  | 0x05, 0x07,		/*   Usage Page (Key Codes) */ | 
|  | 0x19, 0xe0,		/*   Usage Minimum (224) */ | 
|  | 0x29, 0xe7,		/*   Usage Maximum (231) */ | 
|  | 0x15, 0x00,		/*   Logical Minimum (0) */ | 
|  | 0x25, 0x01,		/*   Logical Maximum (1) */ | 
|  | 0x81, 0x02,		/*   Input (Data, Variable, Absolute) */ | 
|  | 0x95, 0x01,		/*   Report Count (1) */ | 
|  | 0x75, 0x08,		/*   Report Size (8) */ | 
|  | 0x81, 0x01,		/*   Input (Constant) */ | 
|  | 0x95, 0x05,		/*   Report Count (5) */ | 
|  | 0x75, 0x01,		/*   Report Size (1) */ | 
|  | 0x05, 0x08,		/*   Usage Page (LEDs) */ | 
|  | 0x19, 0x01,		/*   Usage Minimum (1) */ | 
|  | 0x29, 0x05,		/*   Usage Maximum (5) */ | 
|  | 0x91, 0x02,		/*   Output (Data, Variable, Absolute) */ | 
|  | 0x95, 0x01,		/*   Report Count (1) */ | 
|  | 0x75, 0x03,		/*   Report Size (3) */ | 
|  | 0x91, 0x01,		/*   Output (Constant) */ | 
|  | 0x95, 0x06,		/*   Report Count (6) */ | 
|  | 0x75, 0x08,		/*   Report Size (8) */ | 
|  | 0x15, 0x00,		/*   Logical Minimum (0) */ | 
|  | 0x25, 0xff,		/*   Logical Maximum (255) */ | 
|  | 0x05, 0x07,		/*   Usage Page (Key Codes) */ | 
|  | 0x19, 0x00,		/*   Usage Minimum (0) */ | 
|  | 0x29, 0xff,		/*   Usage Maximum (255) */ | 
|  | 0x81, 0x00,		/*   Input (Data, Array) */ | 
|  | 0xc0,		/* End Collection */ | 
|  | }; | 
|  |  | 
|  | static void usb_hid_changed(HIDState *hs) | 
|  | { | 
|  | USBHIDState *us = container_of(hs, USBHIDState, hid); | 
|  |  | 
|  | usb_wakeup(us->intr); | 
|  | } | 
|  |  | 
|  | static void usb_hid_handle_reset(USBDevice *dev) | 
|  | { | 
|  | USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); | 
|  |  | 
|  | hid_reset(&us->hid); | 
|  | } | 
|  |  | 
|  | static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, | 
|  | int request, int value, int index, int length, uint8_t *data) | 
|  | { | 
|  | USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); | 
|  | HIDState *hs = &us->hid; | 
|  | int ret; | 
|  |  | 
|  | ret = usb_desc_handle_control(dev, p, request, value, index, length, data); | 
|  | if (ret >= 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ret = 0; | 
|  | switch (request) { | 
|  | /* hid specific requests */ | 
|  | case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: | 
|  | switch (value >> 8) { | 
|  | case 0x22: | 
|  | if (hs->kind == HID_MOUSE) { | 
|  | memcpy(data, qemu_mouse_hid_report_descriptor, | 
|  | sizeof(qemu_mouse_hid_report_descriptor)); | 
|  | ret = sizeof(qemu_mouse_hid_report_descriptor); | 
|  | } else if (hs->kind == HID_TABLET) { | 
|  | memcpy(data, qemu_tablet_hid_report_descriptor, | 
|  | sizeof(qemu_tablet_hid_report_descriptor)); | 
|  | ret = sizeof(qemu_tablet_hid_report_descriptor); | 
|  | } else if (hs->kind == HID_KEYBOARD) { | 
|  | memcpy(data, qemu_keyboard_hid_report_descriptor, | 
|  | sizeof(qemu_keyboard_hid_report_descriptor)); | 
|  | ret = sizeof(qemu_keyboard_hid_report_descriptor); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | goto fail; | 
|  | } | 
|  | break; | 
|  | case GET_REPORT: | 
|  | if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { | 
|  | ret = hid_pointer_poll(hs, data, length); | 
|  | } else if (hs->kind == HID_KEYBOARD) { | 
|  | ret = hid_keyboard_poll(hs, data, length); | 
|  | } | 
|  | break; | 
|  | case SET_REPORT: | 
|  | if (hs->kind == HID_KEYBOARD) { | 
|  | ret = hid_keyboard_write(hs, data, length); | 
|  | } else { | 
|  | goto fail; | 
|  | } | 
|  | break; | 
|  | case GET_PROTOCOL: | 
|  | if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { | 
|  | goto fail; | 
|  | } | 
|  | ret = 1; | 
|  | data[0] = hs->protocol; | 
|  | break; | 
|  | case SET_PROTOCOL: | 
|  | if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { | 
|  | goto fail; | 
|  | } | 
|  | ret = 0; | 
|  | hs->protocol = value; | 
|  | break; | 
|  | case GET_IDLE: | 
|  | ret = 1; | 
|  | data[0] = hs->idle; | 
|  | break; | 
|  | case SET_IDLE: | 
|  | hs->idle = (uint8_t) (value >> 8); | 
|  | hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); | 
|  | if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { | 
|  | hid_pointer_activate(hs); | 
|  | } | 
|  | ret = 0; | 
|  | break; | 
|  | default: | 
|  | fail: | 
|  | ret = USB_RET_STALL; | 
|  | break; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) | 
|  | { | 
|  | USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); | 
|  | HIDState *hs = &us->hid; | 
|  | uint8_t buf[p->iov.size]; | 
|  | int ret = 0; | 
|  |  | 
|  | switch (p->pid) { | 
|  | case USB_TOKEN_IN: | 
|  | if (p->ep->nr == 1) { | 
|  | int64_t curtime = qemu_get_clock_ns(vm_clock); | 
|  | if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { | 
|  | hid_pointer_activate(hs); | 
|  | } | 
|  | if (!hid_has_events(hs) && | 
|  | (!hs->idle || hs->next_idle_clock - curtime > 0)) { | 
|  | return USB_RET_NAK; | 
|  | } | 
|  | hid_set_next_idle(hs, curtime); | 
|  | if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { | 
|  | ret = hid_pointer_poll(hs, buf, p->iov.size); | 
|  | } else if (hs->kind == HID_KEYBOARD) { | 
|  | ret = hid_keyboard_poll(hs, buf, p->iov.size); | 
|  | } | 
|  | usb_packet_copy(p, buf, ret); | 
|  | } else { | 
|  | goto fail; | 
|  | } | 
|  | break; | 
|  | case USB_TOKEN_OUT: | 
|  | default: | 
|  | fail: | 
|  | ret = USB_RET_STALL; | 
|  | break; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void usb_hid_handle_destroy(USBDevice *dev) | 
|  | { | 
|  | USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); | 
|  |  | 
|  | hid_free(&us->hid); | 
|  | } | 
|  |  | 
|  | static int usb_hid_initfn(USBDevice *dev, int kind) | 
|  | { | 
|  | USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); | 
|  |  | 
|  | usb_desc_init(dev); | 
|  | us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); | 
|  | hid_init(&us->hid, kind, usb_hid_changed); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int usb_tablet_initfn(USBDevice *dev) | 
|  | { | 
|  | return usb_hid_initfn(dev, HID_TABLET); | 
|  | } | 
|  |  | 
|  | static int usb_mouse_initfn(USBDevice *dev) | 
|  | { | 
|  | return usb_hid_initfn(dev, HID_MOUSE); | 
|  | } | 
|  |  | 
|  | static int usb_keyboard_initfn(USBDevice *dev) | 
|  | { | 
|  | return usb_hid_initfn(dev, HID_KEYBOARD); | 
|  | } | 
|  |  | 
|  | static int usb_ptr_post_load(void *opaque, int version_id) | 
|  | { | 
|  | USBHIDState *s = opaque; | 
|  |  | 
|  | if (s->dev.remote_wakeup) { | 
|  | hid_pointer_activate(&s->hid); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const VMStateDescription vmstate_usb_ptr = { | 
|  | .name = "usb-ptr", | 
|  | .version_id = 1, | 
|  | .minimum_version_id = 1, | 
|  | .post_load = usb_ptr_post_load, | 
|  | .fields = (VMStateField []) { | 
|  | VMSTATE_USB_DEVICE(dev, USBHIDState), | 
|  | VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState), | 
|  | VMSTATE_END_OF_LIST() | 
|  | } | 
|  | }; | 
|  |  | 
|  | static const VMStateDescription vmstate_usb_kbd = { | 
|  | .name = "usb-kbd", | 
|  | .version_id = 1, | 
|  | .minimum_version_id = 1, | 
|  | .fields = (VMStateField []) { | 
|  | VMSTATE_USB_DEVICE(dev, USBHIDState), | 
|  | VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState), | 
|  | VMSTATE_END_OF_LIST() | 
|  | } | 
|  | }; | 
|  |  | 
|  | static void usb_hid_class_initfn(ObjectClass *klass, void *data) | 
|  | { | 
|  | USBDeviceClass *uc = USB_DEVICE_CLASS(klass); | 
|  |  | 
|  | uc->handle_reset   = usb_hid_handle_reset; | 
|  | uc->handle_control = usb_hid_handle_control; | 
|  | uc->handle_data    = usb_hid_handle_data; | 
|  | uc->handle_destroy = usb_hid_handle_destroy; | 
|  | } | 
|  |  | 
|  | static void usb_tablet_class_initfn(ObjectClass *klass, void *data) | 
|  | { | 
|  | DeviceClass *dc = DEVICE_CLASS(klass); | 
|  | USBDeviceClass *uc = USB_DEVICE_CLASS(klass); | 
|  |  | 
|  | usb_hid_class_initfn(klass, data); | 
|  | uc->init           = usb_tablet_initfn; | 
|  | uc->product_desc   = "QEMU USB Tablet"; | 
|  | uc->usb_desc       = &desc_tablet; | 
|  | dc->vmsd = &vmstate_usb_ptr; | 
|  | } | 
|  |  | 
|  | static TypeInfo usb_tablet_info = { | 
|  | .name          = "usb-tablet", | 
|  | .parent        = TYPE_USB_DEVICE, | 
|  | .instance_size = sizeof(USBHIDState), | 
|  | .class_init    = usb_tablet_class_initfn, | 
|  | }; | 
|  |  | 
|  | static void usb_mouse_class_initfn(ObjectClass *klass, void *data) | 
|  | { | 
|  | DeviceClass *dc = DEVICE_CLASS(klass); | 
|  | USBDeviceClass *uc = USB_DEVICE_CLASS(klass); | 
|  |  | 
|  | usb_hid_class_initfn(klass, data); | 
|  | uc->init           = usb_mouse_initfn; | 
|  | uc->product_desc   = "QEMU USB Mouse"; | 
|  | uc->usb_desc       = &desc_mouse; | 
|  | dc->vmsd = &vmstate_usb_ptr; | 
|  | } | 
|  |  | 
|  | static TypeInfo usb_mouse_info = { | 
|  | .name          = "usb-mouse", | 
|  | .parent        = TYPE_USB_DEVICE, | 
|  | .instance_size = sizeof(USBHIDState), | 
|  | .class_init    = usb_mouse_class_initfn, | 
|  | }; | 
|  |  | 
|  | static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) | 
|  | { | 
|  | DeviceClass *dc = DEVICE_CLASS(klass); | 
|  | USBDeviceClass *uc = USB_DEVICE_CLASS(klass); | 
|  |  | 
|  | usb_hid_class_initfn(klass, data); | 
|  | uc->init           = usb_keyboard_initfn; | 
|  | uc->product_desc   = "QEMU USB Keyboard"; | 
|  | uc->usb_desc       = &desc_keyboard; | 
|  | dc->vmsd = &vmstate_usb_kbd; | 
|  | } | 
|  |  | 
|  | static TypeInfo usb_keyboard_info = { | 
|  | .name          = "usb-kbd", | 
|  | .parent        = TYPE_USB_DEVICE, | 
|  | .instance_size = sizeof(USBHIDState), | 
|  | .class_init    = usb_keyboard_class_initfn, | 
|  | }; | 
|  |  | 
|  | static void usb_hid_register_types(void) | 
|  | { | 
|  | type_register_static(&usb_tablet_info); | 
|  | usb_legacy_register("usb-tablet", "tablet", NULL); | 
|  | type_register_static(&usb_mouse_info); | 
|  | usb_legacy_register("usb-mouse", "mouse", NULL); | 
|  | type_register_static(&usb_keyboard_info); | 
|  | usb_legacy_register("usb-kbd", "keyboard", NULL); | 
|  | } | 
|  |  | 
|  | type_init(usb_hid_register_types) |