qemu/hw/usb/dev-hid.c
<<
>>
Prefs
   1/*
   2 * QEMU USB HID devices
   3 *
   4 * Copyright (c) 2005 Fabrice Bellard
   5 * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
   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 "ui/console.h"
  27#include "hw/usb.h"
  28#include "hw/usb/desc.h"
  29#include "qemu/timer.h"
  30#include "hw/input/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
  45typedef struct USBHIDState {
  46    USBDevice dev;
  47    USBEndpoint *intr;
  48    HIDState hid;
  49    uint32_t usb_version;
  50} USBHIDState;
  51
  52enum {
  53    STR_MANUFACTURER = 1,
  54    STR_PRODUCT_MOUSE,
  55    STR_PRODUCT_TABLET,
  56    STR_PRODUCT_KEYBOARD,
  57    STR_SERIALNUMBER,
  58    STR_CONFIG_MOUSE,
  59    STR_CONFIG_TABLET,
  60    STR_CONFIG_KEYBOARD,
  61};
  62
  63static const USBDescStrings desc_strings = {
  64    [STR_MANUFACTURER]     = "QEMU",
  65    [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse",
  66    [STR_PRODUCT_TABLET]   = "QEMU USB Tablet",
  67    [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
  68    [STR_SERIALNUMBER]     = "42", /* == remote wakeup works */
  69    [STR_CONFIG_MOUSE]     = "HID Mouse",
  70    [STR_CONFIG_TABLET]    = "HID Tablet",
  71    [STR_CONFIG_KEYBOARD]  = "HID Keyboard",
  72};
  73
  74static const USBDescIface desc_iface_mouse = {
  75    .bInterfaceNumber              = 0,
  76    .bNumEndpoints                 = 1,
  77    .bInterfaceClass               = USB_CLASS_HID,
  78    .bInterfaceSubClass            = 0x01, /* boot */
  79    .bInterfaceProtocol            = 0x02,
  80    .ndesc                         = 1,
  81    .descs = (USBDescOther[]) {
  82        {
  83            /* HID descriptor */
  84            .data = (uint8_t[]) {
  85                0x09,          /*  u8  bLength */
  86                USB_DT_HID,    /*  u8  bDescriptorType */
  87                0x01, 0x00,    /*  u16 HID_class */
  88                0x00,          /*  u8  country_code */
  89                0x01,          /*  u8  num_descriptors */
  90                USB_DT_REPORT, /*  u8  type: Report */
  91                52, 0,         /*  u16 len */
  92            },
  93        },
  94    },
  95    .eps = (USBDescEndpoint[]) {
  96        {
  97            .bEndpointAddress      = USB_DIR_IN | 0x01,
  98            .bmAttributes          = USB_ENDPOINT_XFER_INT,
  99            .wMaxPacketSize        = 4,
 100            .bInterval             = 0x0a,
 101        },
 102    },
 103};
 104
 105static const USBDescIface desc_iface_tablet = {
 106    .bInterfaceNumber              = 0,
 107    .bNumEndpoints                 = 1,
 108    .bInterfaceClass               = USB_CLASS_HID,
 109    .bInterfaceProtocol            = 0x02,
 110    .ndesc                         = 1,
 111    .descs = (USBDescOther[]) {
 112        {
 113            /* HID descriptor */
 114            .data = (uint8_t[]) {
 115                0x09,          /*  u8  bLength */
 116                USB_DT_HID,    /*  u8  bDescriptorType */
 117                0x01, 0x00,    /*  u16 HID_class */
 118                0x00,          /*  u8  country_code */
 119                0x01,          /*  u8  num_descriptors */
 120                USB_DT_REPORT, /*  u8  type: Report */
 121                74, 0,         /*  u16 len */
 122            },
 123        },
 124    },
 125    .eps = (USBDescEndpoint[]) {
 126        {
 127            .bEndpointAddress      = USB_DIR_IN | 0x01,
 128            .bmAttributes          = USB_ENDPOINT_XFER_INT,
 129            .wMaxPacketSize        = 8,
 130            .bInterval             = 0x0a,
 131        },
 132    },
 133};
 134
 135static const USBDescIface desc_iface_tablet2 = {
 136    .bInterfaceNumber              = 0,
 137    .bNumEndpoints                 = 1,
 138    .bInterfaceClass               = USB_CLASS_HID,
 139    .bInterfaceProtocol            = 0x02,
 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                0x01, 0x00,    /*  u16 HID_class */
 148                0x00,          /*  u8  country_code */
 149                0x01,          /*  u8  num_descriptors */
 150                USB_DT_REPORT, /*  u8  type: Report */
 151                74, 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             = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
 161        },
 162    },
 163};
 164
 165static const USBDescIface desc_iface_keyboard = {
 166    .bInterfaceNumber              = 0,
 167    .bNumEndpoints                 = 1,
 168    .bInterfaceClass               = USB_CLASS_HID,
 169    .bInterfaceSubClass            = 0x01, /* boot */
 170    .bInterfaceProtocol            = 0x01, /* keyboard */
 171    .ndesc                         = 1,
 172    .descs = (USBDescOther[]) {
 173        {
 174            /* HID descriptor */
 175            .data = (uint8_t[]) {
 176                0x09,          /*  u8  bLength */
 177                USB_DT_HID,    /*  u8  bDescriptorType */
 178                0x11, 0x01,    /*  u16 HID_class */
 179                0x00,          /*  u8  country_code */
 180                0x01,          /*  u8  num_descriptors */
 181                USB_DT_REPORT, /*  u8  type: Report */
 182                0x3f, 0,       /*  u16 len */
 183            },
 184        },
 185    },
 186    .eps = (USBDescEndpoint[]) {
 187        {
 188            .bEndpointAddress      = USB_DIR_IN | 0x01,
 189            .bmAttributes          = USB_ENDPOINT_XFER_INT,
 190            .wMaxPacketSize        = 8,
 191            .bInterval             = 0x0a,
 192        },
 193    },
 194};
 195
 196static const USBDescDevice desc_device_mouse = {
 197    .bcdUSB                        = 0x0100,
 198    .bMaxPacketSize0               = 8,
 199    .bNumConfigurations            = 1,
 200    .confs = (USBDescConfig[]) {
 201        {
 202            .bNumInterfaces        = 1,
 203            .bConfigurationValue   = 1,
 204            .iConfiguration        = STR_CONFIG_MOUSE,
 205            .bmAttributes          = 0xa0,
 206            .bMaxPower             = 50,
 207            .nif = 1,
 208            .ifs = &desc_iface_mouse,
 209        },
 210    },
 211};
 212
 213static const USBDescDevice desc_device_tablet = {
 214    .bcdUSB                        = 0x0100,
 215    .bMaxPacketSize0               = 8,
 216    .bNumConfigurations            = 1,
 217    .confs = (USBDescConfig[]) {
 218        {
 219            .bNumInterfaces        = 1,
 220            .bConfigurationValue   = 1,
 221            .iConfiguration        = STR_CONFIG_TABLET,
 222            .bmAttributes          = 0xa0,
 223            .bMaxPower             = 50,
 224            .nif = 1,
 225            .ifs = &desc_iface_tablet,
 226        },
 227    },
 228};
 229
 230static const USBDescDevice desc_device_tablet2 = {
 231    .bcdUSB                        = 0x0200,
 232    .bMaxPacketSize0               = 64,
 233    .bNumConfigurations            = 1,
 234    .confs = (USBDescConfig[]) {
 235        {
 236            .bNumInterfaces        = 1,
 237            .bConfigurationValue   = 1,
 238            .iConfiguration        = STR_CONFIG_TABLET,
 239            .bmAttributes          = 0x80,
 240            .bMaxPower             = 50,
 241            .nif = 1,
 242            .ifs = &desc_iface_tablet2,
 243        },
 244    },
 245};
 246
 247static const USBDescDevice desc_device_keyboard = {
 248    .bcdUSB                        = 0x0100,
 249    .bMaxPacketSize0               = 8,
 250    .bNumConfigurations            = 1,
 251    .confs = (USBDescConfig[]) {
 252        {
 253            .bNumInterfaces        = 1,
 254            .bConfigurationValue   = 1,
 255            .iConfiguration        = STR_CONFIG_KEYBOARD,
 256            .bmAttributes          = 0xa0,
 257            .bMaxPower             = 50,
 258            .nif = 1,
 259            .ifs = &desc_iface_keyboard,
 260        },
 261    },
 262};
 263
 264static const USBDesc desc_mouse = {
 265    .id = {
 266        .idVendor          = 0x0627,
 267        .idProduct         = 0x0001,
 268        .bcdDevice         = 0,
 269        .iManufacturer     = STR_MANUFACTURER,
 270        .iProduct          = STR_PRODUCT_MOUSE,
 271        .iSerialNumber     = STR_SERIALNUMBER,
 272    },
 273    .full = &desc_device_mouse,
 274    .str  = desc_strings,
 275};
 276
 277static const USBDesc desc_tablet = {
 278    .id = {
 279        .idVendor          = 0x0627,
 280        .idProduct         = 0x0001,
 281        .bcdDevice         = 0,
 282        .iManufacturer     = STR_MANUFACTURER,
 283        .iProduct          = STR_PRODUCT_TABLET,
 284        .iSerialNumber     = STR_SERIALNUMBER,
 285    },
 286    .full = &desc_device_tablet,
 287    .str  = desc_strings,
 288};
 289
 290static const USBDesc desc_tablet2 = {
 291    .id = {
 292        .idVendor          = 0x0627,
 293        .idProduct         = 0x0001,
 294        .bcdDevice         = 0,
 295        .iManufacturer     = STR_MANUFACTURER,
 296        .iProduct          = STR_PRODUCT_TABLET,
 297        .iSerialNumber     = STR_SERIALNUMBER,
 298    },
 299    .full = &desc_device_tablet,
 300    .high = &desc_device_tablet2,
 301    .str  = desc_strings,
 302};
 303
 304static const USBDesc desc_keyboard = {
 305    .id = {
 306        .idVendor          = 0x0627,
 307        .idProduct         = 0x0001,
 308        .bcdDevice         = 0,
 309        .iManufacturer     = STR_MANUFACTURER,
 310        .iProduct          = STR_PRODUCT_KEYBOARD,
 311        .iSerialNumber     = STR_SERIALNUMBER,
 312    },
 313    .full = &desc_device_keyboard,
 314    .str  = desc_strings,
 315};
 316
 317static const uint8_t qemu_mouse_hid_report_descriptor[] = {
 318    0x05, 0x01,         /* Usage Page (Generic Desktop) */
 319    0x09, 0x02,         /* Usage (Mouse) */
 320    0xa1, 0x01,         /* Collection (Application) */
 321    0x09, 0x01,         /*   Usage (Pointer) */
 322    0xa1, 0x00,         /*   Collection (Physical) */
 323    0x05, 0x09,         /*     Usage Page (Button) */
 324    0x19, 0x01,         /*     Usage Minimum (1) */
 325    0x29, 0x03,         /*     Usage Maximum (3) */
 326    0x15, 0x00,         /*     Logical Minimum (0) */
 327    0x25, 0x01,         /*     Logical Maximum (1) */
 328    0x95, 0x03,         /*     Report Count (3) */
 329    0x75, 0x01,         /*     Report Size (1) */
 330    0x81, 0x02,         /*     Input (Data, Variable, Absolute) */
 331    0x95, 0x01,         /*     Report Count (1) */
 332    0x75, 0x05,         /*     Report Size (5) */
 333    0x81, 0x01,         /*     Input (Constant) */
 334    0x05, 0x01,         /*     Usage Page (Generic Desktop) */
 335    0x09, 0x30,         /*     Usage (X) */
 336    0x09, 0x31,         /*     Usage (Y) */
 337    0x09, 0x38,         /*     Usage (Wheel) */
 338    0x15, 0x81,         /*     Logical Minimum (-0x7f) */
 339    0x25, 0x7f,         /*     Logical Maximum (0x7f) */
 340    0x75, 0x08,         /*     Report Size (8) */
 341    0x95, 0x03,         /*     Report Count (3) */
 342    0x81, 0x06,         /*     Input (Data, Variable, Relative) */
 343    0xc0,               /*   End Collection */
 344    0xc0,               /* End Collection */
 345};
 346
 347static const uint8_t qemu_tablet_hid_report_descriptor[] = {
 348    0x05, 0x01,         /* Usage Page (Generic Desktop) */
 349    0x09, 0x01,         /* Usage (Pointer) */
 350    0xa1, 0x01,         /* Collection (Application) */
 351    0x09, 0x01,         /*   Usage (Pointer) */
 352    0xa1, 0x00,         /*   Collection (Physical) */
 353    0x05, 0x09,         /*     Usage Page (Button) */
 354    0x19, 0x01,         /*     Usage Minimum (1) */
 355    0x29, 0x03,         /*     Usage Maximum (3) */
 356    0x15, 0x00,         /*     Logical Minimum (0) */
 357    0x25, 0x01,         /*     Logical Maximum (1) */
 358    0x95, 0x03,         /*     Report Count (3) */
 359    0x75, 0x01,         /*     Report Size (1) */
 360    0x81, 0x02,         /*     Input (Data, Variable, Absolute) */
 361    0x95, 0x01,         /*     Report Count (1) */
 362    0x75, 0x05,         /*     Report Size (5) */
 363    0x81, 0x01,         /*     Input (Constant) */
 364    0x05, 0x01,         /*     Usage Page (Generic Desktop) */
 365    0x09, 0x30,         /*     Usage (X) */
 366    0x09, 0x31,         /*     Usage (Y) */
 367    0x15, 0x00,         /*     Logical Minimum (0) */
 368    0x26, 0xff, 0x7f,   /*     Logical Maximum (0x7fff) */
 369    0x35, 0x00,         /*     Physical Minimum (0) */
 370    0x46, 0xff, 0x7f,   /*     Physical Maximum (0x7fff) */
 371    0x75, 0x10,         /*     Report Size (16) */
 372    0x95, 0x02,         /*     Report Count (2) */
 373    0x81, 0x02,         /*     Input (Data, Variable, Absolute) */
 374    0x05, 0x01,         /*     Usage Page (Generic Desktop) */
 375    0x09, 0x38,         /*     Usage (Wheel) */
 376    0x15, 0x81,         /*     Logical Minimum (-0x7f) */
 377    0x25, 0x7f,         /*     Logical Maximum (0x7f) */
 378    0x35, 0x00,         /*     Physical Minimum (same as logical) */
 379    0x45, 0x00,         /*     Physical Maximum (same as logical) */
 380    0x75, 0x08,         /*     Report Size (8) */
 381    0x95, 0x01,         /*     Report Count (1) */
 382    0x81, 0x06,         /*     Input (Data, Variable, Relative) */
 383    0xc0,               /*   End Collection */
 384    0xc0,               /* End Collection */
 385};
 386
 387static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
 388    0x05, 0x01,         /* Usage Page (Generic Desktop) */
 389    0x09, 0x06,         /* Usage (Keyboard) */
 390    0xa1, 0x01,         /* Collection (Application) */
 391    0x75, 0x01,         /*   Report Size (1) */
 392    0x95, 0x08,         /*   Report Count (8) */
 393    0x05, 0x07,         /*   Usage Page (Key Codes) */
 394    0x19, 0xe0,         /*   Usage Minimum (224) */
 395    0x29, 0xe7,         /*   Usage Maximum (231) */
 396    0x15, 0x00,         /*   Logical Minimum (0) */
 397    0x25, 0x01,         /*   Logical Maximum (1) */
 398    0x81, 0x02,         /*   Input (Data, Variable, Absolute) */
 399    0x95, 0x01,         /*   Report Count (1) */
 400    0x75, 0x08,         /*   Report Size (8) */
 401    0x81, 0x01,         /*   Input (Constant) */
 402    0x95, 0x05,         /*   Report Count (5) */
 403    0x75, 0x01,         /*   Report Size (1) */
 404    0x05, 0x08,         /*   Usage Page (LEDs) */
 405    0x19, 0x01,         /*   Usage Minimum (1) */
 406    0x29, 0x05,         /*   Usage Maximum (5) */
 407    0x91, 0x02,         /*   Output (Data, Variable, Absolute) */
 408    0x95, 0x01,         /*   Report Count (1) */
 409    0x75, 0x03,         /*   Report Size (3) */
 410    0x91, 0x01,         /*   Output (Constant) */
 411    0x95, 0x06,         /*   Report Count (6) */
 412    0x75, 0x08,         /*   Report Size (8) */
 413    0x15, 0x00,         /*   Logical Minimum (0) */
 414    0x25, 0xff,         /*   Logical Maximum (255) */
 415    0x05, 0x07,         /*   Usage Page (Key Codes) */
 416    0x19, 0x00,         /*   Usage Minimum (0) */
 417    0x29, 0xff,         /*   Usage Maximum (255) */
 418    0x81, 0x00,         /*   Input (Data, Array) */
 419    0xc0,               /* End Collection */
 420};
 421
 422static void usb_hid_changed(HIDState *hs)
 423{
 424    USBHIDState *us = container_of(hs, USBHIDState, hid);
 425
 426    usb_wakeup(us->intr, 0);
 427}
 428
 429static void usb_hid_handle_reset(USBDevice *dev)
 430{
 431    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 432
 433    hid_reset(&us->hid);
 434}
 435
 436static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
 437               int request, int value, int index, int length, uint8_t *data)
 438{
 439    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 440    HIDState *hs = &us->hid;
 441    int ret;
 442
 443    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
 444    if (ret >= 0) {
 445        return;
 446    }
 447
 448    switch (request) {
 449        /* hid specific requests */
 450    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
 451        switch (value >> 8) {
 452        case 0x22:
 453            if (hs->kind == HID_MOUSE) {
 454                memcpy(data, qemu_mouse_hid_report_descriptor,
 455                       sizeof(qemu_mouse_hid_report_descriptor));
 456                p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
 457            } else if (hs->kind == HID_TABLET) {
 458                memcpy(data, qemu_tablet_hid_report_descriptor,
 459                       sizeof(qemu_tablet_hid_report_descriptor));
 460                p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
 461            } else if (hs->kind == HID_KEYBOARD) {
 462                memcpy(data, qemu_keyboard_hid_report_descriptor,
 463                       sizeof(qemu_keyboard_hid_report_descriptor));
 464                p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
 465            }
 466            break;
 467        default:
 468            goto fail;
 469        }
 470        break;
 471    case GET_REPORT:
 472        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
 473            p->actual_length = hid_pointer_poll(hs, data, length);
 474        } else if (hs->kind == HID_KEYBOARD) {
 475            p->actual_length = hid_keyboard_poll(hs, data, length);
 476        }
 477        break;
 478    case SET_REPORT:
 479        if (hs->kind == HID_KEYBOARD) {
 480            p->actual_length = hid_keyboard_write(hs, data, length);
 481        } else {
 482            goto fail;
 483        }
 484        break;
 485    case GET_PROTOCOL:
 486        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
 487            goto fail;
 488        }
 489        data[0] = hs->protocol;
 490        p->actual_length = 1;
 491        break;
 492    case SET_PROTOCOL:
 493        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
 494            goto fail;
 495        }
 496        hs->protocol = value;
 497        break;
 498    case GET_IDLE:
 499        data[0] = hs->idle;
 500        p->actual_length = 1;
 501        break;
 502    case SET_IDLE:
 503        hs->idle = (uint8_t) (value >> 8);
 504        hid_set_next_idle(hs);
 505        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
 506            hid_pointer_activate(hs);
 507        }
 508        break;
 509    default:
 510    fail:
 511        p->status = USB_RET_STALL;
 512        break;
 513    }
 514}
 515
 516static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 517{
 518    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 519    HIDState *hs = &us->hid;
 520    uint8_t buf[p->iov.size];
 521    int len = 0;
 522
 523    switch (p->pid) {
 524    case USB_TOKEN_IN:
 525        if (p->ep->nr == 1) {
 526            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
 527                hid_pointer_activate(hs);
 528            }
 529            if (!hid_has_events(hs)) {
 530                p->status = USB_RET_NAK;
 531                return;
 532            }
 533            hid_set_next_idle(hs);
 534            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
 535                len = hid_pointer_poll(hs, buf, p->iov.size);
 536            } else if (hs->kind == HID_KEYBOARD) {
 537                len = hid_keyboard_poll(hs, buf, p->iov.size);
 538            }
 539            usb_packet_copy(p, buf, len);
 540        } else {
 541            goto fail;
 542        }
 543        break;
 544    case USB_TOKEN_OUT:
 545    default:
 546    fail:
 547        p->status = USB_RET_STALL;
 548        break;
 549    }
 550}
 551
 552static void usb_hid_handle_destroy(USBDevice *dev)
 553{
 554    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 555
 556    hid_free(&us->hid);
 557}
 558
 559static int usb_hid_initfn(USBDevice *dev, int kind)
 560{
 561    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 562
 563    if (dev->serial) {
 564        usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial);
 565    }
 566    usb_desc_init(dev);
 567    us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
 568    hid_init(&us->hid, kind, usb_hid_changed);
 569    return 0;
 570}
 571
 572static int usb_tablet_initfn(USBDevice *dev)
 573{
 574    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 575
 576    switch (us->usb_version) {
 577    case 1:
 578        dev->usb_desc = &desc_tablet;
 579        break;
 580    case 2:
 581        dev->usb_desc = &desc_tablet2;
 582        break;
 583    default:
 584        error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)",
 585                     us->usb_version);
 586        return -1;
 587    }
 588
 589    return usb_hid_initfn(dev, HID_TABLET);
 590}
 591
 592static int usb_mouse_initfn(USBDevice *dev)
 593{
 594    return usb_hid_initfn(dev, HID_MOUSE);
 595}
 596
 597static int usb_keyboard_initfn(USBDevice *dev)
 598{
 599    return usb_hid_initfn(dev, HID_KEYBOARD);
 600}
 601
 602static int usb_ptr_post_load(void *opaque, int version_id)
 603{
 604    USBHIDState *s = opaque;
 605
 606    if (s->dev.remote_wakeup) {
 607        hid_pointer_activate(&s->hid);
 608    }
 609    return 0;
 610}
 611
 612static const VMStateDescription vmstate_usb_ptr = {
 613    .name = "usb-ptr",
 614    .version_id = 1,
 615    .minimum_version_id = 1,
 616    .post_load = usb_ptr_post_load,
 617    .fields = (VMStateField []) {
 618        VMSTATE_USB_DEVICE(dev, USBHIDState),
 619        VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
 620        VMSTATE_END_OF_LIST()
 621    }
 622};
 623
 624static const VMStateDescription vmstate_usb_kbd = {
 625    .name = "usb-kbd",
 626    .version_id = 1,
 627    .minimum_version_id = 1,
 628    .fields = (VMStateField []) {
 629        VMSTATE_USB_DEVICE(dev, USBHIDState),
 630        VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
 631        VMSTATE_END_OF_LIST()
 632    }
 633};
 634
 635static void usb_hid_class_initfn(ObjectClass *klass, void *data)
 636{
 637    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 638
 639    uc->handle_reset   = usb_hid_handle_reset;
 640    uc->handle_control = usb_hid_handle_control;
 641    uc->handle_data    = usb_hid_handle_data;
 642    uc->handle_destroy = usb_hid_handle_destroy;
 643    uc->handle_attach  = usb_desc_attach;
 644}
 645
 646static Property usb_tablet_properties[] = {
 647        DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
 648        DEFINE_PROP_END_OF_LIST(),
 649};
 650
 651static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
 652{
 653    DeviceClass *dc = DEVICE_CLASS(klass);
 654    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 655
 656    usb_hid_class_initfn(klass, data);
 657    uc->init           = usb_tablet_initfn;
 658    uc->product_desc   = "QEMU USB Tablet";
 659    dc->vmsd = &vmstate_usb_ptr;
 660    dc->props = usb_tablet_properties;
 661    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 662}
 663
 664static const TypeInfo usb_tablet_info = {
 665    .name          = "usb-tablet",
 666    .parent        = TYPE_USB_DEVICE,
 667    .instance_size = sizeof(USBHIDState),
 668    .class_init    = usb_tablet_class_initfn,
 669};
 670
 671static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
 672{
 673    DeviceClass *dc = DEVICE_CLASS(klass);
 674    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 675
 676    usb_hid_class_initfn(klass, data);
 677    uc->init           = usb_mouse_initfn;
 678    uc->product_desc   = "QEMU USB Mouse";
 679    uc->usb_desc       = &desc_mouse;
 680    dc->vmsd = &vmstate_usb_ptr;
 681    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 682}
 683
 684static const TypeInfo usb_mouse_info = {
 685    .name          = "usb-mouse",
 686    .parent        = TYPE_USB_DEVICE,
 687    .instance_size = sizeof(USBHIDState),
 688    .class_init    = usb_mouse_class_initfn,
 689};
 690
 691static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
 692{
 693    DeviceClass *dc = DEVICE_CLASS(klass);
 694    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 695
 696    usb_hid_class_initfn(klass, data);
 697    uc->init           = usb_keyboard_initfn;
 698    uc->product_desc   = "QEMU USB Keyboard";
 699    uc->usb_desc       = &desc_keyboard;
 700    dc->vmsd = &vmstate_usb_kbd;
 701    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 702}
 703
 704static const TypeInfo usb_keyboard_info = {
 705    .name          = "usb-kbd",
 706    .parent        = TYPE_USB_DEVICE,
 707    .instance_size = sizeof(USBHIDState),
 708    .class_init    = usb_keyboard_class_initfn,
 709};
 710
 711static void usb_hid_register_types(void)
 712{
 713    type_register_static(&usb_tablet_info);
 714    usb_legacy_register("usb-tablet", "tablet", NULL);
 715    type_register_static(&usb_mouse_info);
 716    usb_legacy_register("usb-mouse", "mouse", NULL);
 717    type_register_static(&usb_keyboard_info);
 718    usb_legacy_register("usb-kbd", "keyboard", NULL);
 719}
 720
 721type_init(usb_hid_register_types)
 722