thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone
9ae3a8
From b907cc56cbbb6b979d97aa0c64eb08c1fe7b6f1e Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Mon, 3 Feb 2014 16:30:30 +0100
9ae3a8
Subject: [PATCH 06/28] usb: add support for microsoft os descriptors
9ae3a8
9ae3a8
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Message-id: <1391445032-5540-4-git-send-email-kraxel@redhat.com>
9ae3a8
Patchwork-id: 57075
9ae3a8
O-Subject: [RHEL-7 qemu-kvm PATCH 3/5] usb: add support for microsoft os descriptors
9ae3a8
Bugzilla: 1039530
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Juan Quintela <quintela@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
This patch adds support for special usb descriptors used by microsoft
9ae3a8
windows.  They allow more fine-grained control over driver binding and
9ae3a8
adding entries to the registry for configuration.
9ae3a8
9ae3a8
As this is a guest-visible change the "msos-desc" compat property
9ae3a8
has been added to turn this off for 1.7 + older
9ae3a8
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit 5319dc7b42610575cbd3a33f4340c1fb4f19b939)
9ae3a8
9ae3a8
Conflicts:
9ae3a8
	hw/i386/pc_piix.c        [ 1.7 compat properties ]
9ae3a8
	include/hw/i386/pc.h     [ likewise              ]
9ae3a8
---
9ae3a8
 hw/usb/Makefile.objs |   2 +-
9ae3a8
 hw/usb/bus.c         |   2 +
9ae3a8
 hw/usb/desc-msos.c   | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++
9ae3a8
 hw/usb/desc.c        |  37 +++++++-
9ae3a8
 hw/usb/desc.h        |  11 ++-
9ae3a8
 include/hw/usb.h     |   3 +
9ae3a8
 trace-events         |   1 +
9ae3a8
 7 files changed, 284 insertions(+), 6 deletions(-)
9ae3a8
 create mode 100644 hw/usb/desc-msos.c
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/usb/Makefile.objs |    2 +-
9ae3a8
 hw/usb/bus.c         |    2 +
9ae3a8
 hw/usb/desc-msos.c   |  234 ++++++++++++++++++++++++++++++++++++++++++++++++++
9ae3a8
 hw/usb/desc.c        |   37 +++++++-
9ae3a8
 hw/usb/desc.h        |   11 ++-
9ae3a8
 include/hw/usb.h     |    3 +
9ae3a8
 trace-events         |    1 +
9ae3a8
 7 files changed, 284 insertions(+), 6 deletions(-)
9ae3a8
 create mode 100644 hw/usb/desc-msos.c
9ae3a8
9ae3a8
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
9ae3a8
index a3eac3e..97b4575 100644
9ae3a8
--- a/hw/usb/Makefile.objs
9ae3a8
+++ b/hw/usb/Makefile.objs
9ae3a8
@@ -1,5 +1,5 @@
9ae3a8
 # usb subsystem core
9ae3a8
-common-obj-y += core.o combined-packet.o bus.o desc.o
9ae3a8
+common-obj-y += core.o combined-packet.o bus.o desc.o desc-msos.o
9ae3a8
 common-obj-y += libhw.o
9ae3a8
 
9ae3a8
 # usb host adapters
9ae3a8
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
9ae3a8
index ade9abc..fe6bd13 100644
9ae3a8
--- a/hw/usb/bus.c
9ae3a8
+++ b/hw/usb/bus.c
9ae3a8
@@ -16,6 +16,8 @@ static Property usb_props[] = {
9ae3a8
     DEFINE_PROP_STRING("serial", USBDevice, serial),
9ae3a8
     DEFINE_PROP_BIT("full-path", USBDevice, flags,
9ae3a8
                     USB_DEV_FLAG_FULL_PATH, true),
9ae3a8
+    DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
9ae3a8
+                    USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
9ae3a8
     DEFINE_PROP_END_OF_LIST()
9ae3a8
 };
9ae3a8
 
9ae3a8
diff --git a/hw/usb/desc-msos.c b/hw/usb/desc-msos.c
9ae3a8
new file mode 100644
9ae3a8
index 0000000..ed8d62c
9ae3a8
--- /dev/null
9ae3a8
+++ b/hw/usb/desc-msos.c
9ae3a8
@@ -0,0 +1,234 @@
9ae3a8
+#include "hw/usb.h"
9ae3a8
+#include "hw/usb/desc.h"
9ae3a8
+
9ae3a8
+/*
9ae3a8
+ * Microsoft OS Descriptors
9ae3a8
+ *
9ae3a8
+ * Windows tries to fetch some special descriptors with informations
9ae3a8
+ * specifically for windows.  Presence is indicated using a special
9ae3a8
+ * string @ index 0xee.  There are two kinds of descriptors:
9ae3a8
+ *
9ae3a8
+ * compatid descriptor
9ae3a8
+ *   Used to bind drivers, if usb class isn't specific enougth.
9ae3a8
+ *   Used for PTP/MTP for example (both share the same usb class).
9ae3a8
+ *
9ae3a8
+ * properties descriptor
9ae3a8
+ *   Does carry registry entries.  They show up in
9ae3a8
+ *   HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
9ae3a8
+ *
9ae3a8
+ * Note that Windows caches the stuff it got in the registry, so when
9ae3a8
+ * playing with this you have to delete registry subtrees to make
9ae3a8
+ * windows query the device again:
9ae3a8
+ *   HLM\SYSTEM\CurrentControlSet\Control\usbflags
9ae3a8
+ *   HLM\SYSTEM\CurrentControlSet\Enum\USB
9ae3a8
+ * Windows will complain it can't delete entries on the second one.
9ae3a8
+ * It has deleted everything it had permissions too, which is enouth
9ae3a8
+ * as this includes "Device Parameters".
9ae3a8
+ *
9ae3a8
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
9ae3a8
+ *
9ae3a8
+ */
9ae3a8
+
9ae3a8
+/* ------------------------------------------------------------------ */
9ae3a8
+
9ae3a8
+typedef struct msos_compat_hdr {
9ae3a8
+    uint32_t dwLength;
9ae3a8
+    uint8_t  bcdVersion_lo;
9ae3a8
+    uint8_t  bcdVersion_hi;
9ae3a8
+    uint8_t  wIndex_lo;
9ae3a8
+    uint8_t  wIndex_hi;
9ae3a8
+    uint8_t  bCount;
9ae3a8
+    uint8_t  reserved[7];
9ae3a8
+} QEMU_PACKED msos_compat_hdr;
9ae3a8
+
9ae3a8
+typedef struct msos_compat_func {
9ae3a8
+    uint8_t  bFirstInterfaceNumber;
9ae3a8
+    uint8_t  reserved_1;
9ae3a8
+    uint8_t  compatibleId[8];
9ae3a8
+    uint8_t  subCompatibleId[8];
9ae3a8
+    uint8_t  reserved_2[6];
9ae3a8
+} QEMU_PACKED msos_compat_func;
9ae3a8
+
9ae3a8
+static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
9ae3a8
+{
9ae3a8
+    msos_compat_hdr *hdr = (void *)dest;
9ae3a8
+    msos_compat_func *func;
9ae3a8
+    int length = sizeof(*hdr);
9ae3a8
+    int count = 0;
9ae3a8
+
9ae3a8
+    func = (void *)(dest + length);
9ae3a8
+    func->bFirstInterfaceNumber = 0;
9ae3a8
+    func->reserved_1 = 0x01;
9ae3a8
+    length += sizeof(*func);
9ae3a8
+    count++;
9ae3a8
+
9ae3a8
+    hdr->dwLength      = cpu_to_le32(length);
9ae3a8
+    hdr->bcdVersion_lo = 0x00;
9ae3a8
+    hdr->bcdVersion_hi = 0x01;
9ae3a8
+    hdr->wIndex_lo     = 0x04;
9ae3a8
+    hdr->wIndex_hi     = 0x00;
9ae3a8
+    hdr->bCount        = count;
9ae3a8
+    return length;
9ae3a8
+}
9ae3a8
+
9ae3a8
+/* ------------------------------------------------------------------ */
9ae3a8
+
9ae3a8
+typedef struct msos_prop_hdr {
9ae3a8
+    uint32_t dwLength;
9ae3a8
+    uint8_t  bcdVersion_lo;
9ae3a8
+    uint8_t  bcdVersion_hi;
9ae3a8
+    uint8_t  wIndex_lo;
9ae3a8
+    uint8_t  wIndex_hi;
9ae3a8
+    uint8_t  wCount_lo;
9ae3a8
+    uint8_t  wCount_hi;
9ae3a8
+} QEMU_PACKED msos_prop_hdr;
9ae3a8
+
9ae3a8
+typedef struct msos_prop {
9ae3a8
+    uint32_t dwLength;
9ae3a8
+    uint32_t dwPropertyDataType;
9ae3a8
+    uint8_t  dwPropertyNameLength_lo;
9ae3a8
+    uint8_t  dwPropertyNameLength_hi;
9ae3a8
+    uint8_t  bPropertyName[];
9ae3a8
+} QEMU_PACKED msos_prop;
9ae3a8
+
9ae3a8
+typedef struct msos_prop_data {
9ae3a8
+    uint32_t dwPropertyDataLength;
9ae3a8
+    uint8_t  bPropertyData[];
9ae3a8
+} QEMU_PACKED msos_prop_data;
9ae3a8
+
9ae3a8
+typedef enum msos_prop_type {
9ae3a8
+    MSOS_REG_SZ        = 1,
9ae3a8
+    MSOS_REG_EXPAND_SZ = 2,
9ae3a8
+    MSOS_REG_BINARY    = 3,
9ae3a8
+    MSOS_REG_DWORD_LE  = 4,
9ae3a8
+    MSOS_REG_DWORD_BE  = 5,
9ae3a8
+    MSOS_REG_LINK      = 6,
9ae3a8
+    MSOS_REG_MULTI_SZ  = 7,
9ae3a8
+} msos_prop_type;
9ae3a8
+
9ae3a8
+static int usb_desc_msos_prop_name(struct msos_prop *prop,
9ae3a8
+                                   const wchar_t *name)
9ae3a8
+{
9ae3a8
+    int length = wcslen(name) + 1;
9ae3a8
+    int i;
9ae3a8
+
9ae3a8
+    prop->dwPropertyNameLength_lo = usb_lo(length*2);
9ae3a8
+    prop->dwPropertyNameLength_hi = usb_hi(length*2);
9ae3a8
+    for (i = 0; i < length; i++) {
9ae3a8
+        prop->bPropertyName[i*2]   = usb_lo(name[i]);
9ae3a8
+        prop->bPropertyName[i*2+1] = usb_hi(name[i]);
9ae3a8
+    }
9ae3a8
+    return length*2;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
9ae3a8
+                                  const wchar_t *name, const wchar_t *value)
9ae3a8
+{
9ae3a8
+    struct msos_prop *prop = (void *)dest;
9ae3a8
+    struct msos_prop_data *data;
9ae3a8
+    int length = sizeof(*prop);
9ae3a8
+    int i, vlen = wcslen(value) + 1;
9ae3a8
+
9ae3a8
+    prop->dwPropertyDataType = cpu_to_le32(type);
9ae3a8
+    length += usb_desc_msos_prop_name(prop, name);
9ae3a8
+    data = (void *)(dest + length);
9ae3a8
+
9ae3a8
+    data->dwPropertyDataLength = cpu_to_le32(vlen*2);
9ae3a8
+    length += sizeof(*prop);
9ae3a8
+
9ae3a8
+    for (i = 0; i < vlen; i++) {
9ae3a8
+        data->bPropertyData[i*2]   = usb_lo(value[i]);
9ae3a8
+        data->bPropertyData[i*2+1] = usb_hi(value[i]);
9ae3a8
+    }
9ae3a8
+    length += vlen*2;
9ae3a8
+
9ae3a8
+    prop->dwLength = cpu_to_le32(length);
9ae3a8
+    return length;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
9ae3a8
+                                    uint32_t value)
9ae3a8
+{
9ae3a8
+    struct msos_prop *prop = (void *)dest;
9ae3a8
+    struct msos_prop_data *data;
9ae3a8
+    int length = sizeof(*prop);
9ae3a8
+
9ae3a8
+    prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
9ae3a8
+    length += usb_desc_msos_prop_name(prop, name);
9ae3a8
+    data = (void *)(dest + length);
9ae3a8
+
9ae3a8
+    data->dwPropertyDataLength = cpu_to_le32(4);
9ae3a8
+    data->bPropertyData[0] = (value)       & 0xff;
9ae3a8
+    data->bPropertyData[1] = (value >>  8) & 0xff;
9ae3a8
+    data->bPropertyData[2] = (value >> 16) & 0xff;
9ae3a8
+    data->bPropertyData[3] = (value >> 24) & 0xff;
9ae3a8
+    length += sizeof(*prop) + 4;
9ae3a8
+
9ae3a8
+    prop->dwLength = cpu_to_le32(length);
9ae3a8
+    return length;
9ae3a8
+}
9ae3a8
+
9ae3a8
+static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
9ae3a8
+{
9ae3a8
+    msos_prop_hdr *hdr = (void *)dest;
9ae3a8
+    int length = sizeof(*hdr);
9ae3a8
+    int count = 0;
9ae3a8
+
9ae3a8
+    if (desc->msos->Label) {
9ae3a8
+        /*
9ae3a8
+         * Given as example in the specs.  Havn't figured yet where
9ae3a8
+         * this label shows up in the windows gui.
9ae3a8
+         */
9ae3a8
+        length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
9ae3a8
+                                         L"Label", desc->msos->Label);
9ae3a8
+        count++;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (desc->msos->SelectiveSuspendEnabled) {
9ae3a8
+        /*
9ae3a8
+         * Signaling remote wakeup capability in the standard usb
9ae3a8
+         * descriptors isn't enouth to make windows actually use it.
9ae3a8
+         * This is the "Yes, we really mean it" registy entry to flip
9ae3a8
+         * the switch in the windows drivers.
9ae3a8
+         */
9ae3a8
+        length += usb_desc_msos_prop_dword(dest+length,
9ae3a8
+                                           L"SelectiveSuspendEnabled", 1);
9ae3a8
+        count++;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    hdr->dwLength      = cpu_to_le32(length);
9ae3a8
+    hdr->bcdVersion_lo = 0x00;
9ae3a8
+    hdr->bcdVersion_hi = 0x01;
9ae3a8
+    hdr->wIndex_lo     = 0x05;
9ae3a8
+    hdr->wIndex_hi     = 0x00;
9ae3a8
+    hdr->wCount_lo     = usb_lo(count);
9ae3a8
+    hdr->wCount_hi     = usb_hi(count);
9ae3a8
+    return length;
9ae3a8
+}
9ae3a8
+
9ae3a8
+/* ------------------------------------------------------------------ */
9ae3a8
+
9ae3a8
+int usb_desc_msos(const USBDesc *desc,  USBPacket *p,
9ae3a8
+                  int index, uint8_t *dest, size_t len)
9ae3a8
+{
9ae3a8
+    void *buf = g_malloc0(4096);
9ae3a8
+    int length = 0;
9ae3a8
+
9ae3a8
+    switch (index) {
9ae3a8
+    case 0x0004:
9ae3a8
+        length = usb_desc_msos_compat(desc, buf);
9ae3a8
+        break;
9ae3a8
+    case 0x0005:
9ae3a8
+        length = usb_desc_msos_prop(desc, buf);
9ae3a8
+        break;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (length > len) {
9ae3a8
+        length = len;
9ae3a8
+    }
9ae3a8
+    memcpy(dest, buf, length);
9ae3a8
+    free(buf);
9ae3a8
+
9ae3a8
+    p->actual_length = length;
9ae3a8
+    return 0;
9ae3a8
+}
9ae3a8
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
9ae3a8
index 3e560cd..5a954c6 100644
9ae3a8
--- a/hw/usb/desc.c
9ae3a8
+++ b/hw/usb/desc.c
9ae3a8
@@ -7,7 +7,7 @@
9ae3a8
 /* ------------------------------------------------------------------ */
9ae3a8
 
9ae3a8
 int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
9ae3a8
-                    uint8_t *dest, size_t len)
9ae3a8
+                    bool msos, uint8_t *dest, size_t len)
9ae3a8
 {
9ae3a8
     uint8_t bLength = 0x12;
9ae3a8
     USBDescriptor *d = (void *)dest;
9ae3a8
@@ -19,8 +19,18 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
9ae3a8
     d->bLength                     = bLength;
9ae3a8
     d->bDescriptorType             = USB_DT_DEVICE;
9ae3a8
 
9ae3a8
-    d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
9ae3a8
-    d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
9ae3a8
+    if (msos && dev->bcdUSB < 0x0200) {
9ae3a8
+        /*
9ae3a8
+         * Version 2.0+ required for microsoft os descriptors to work.
9ae3a8
+         * Done this way so msos-desc compat property will handle both
9ae3a8
+         * the version and the new descriptors being present.
9ae3a8
+         */
9ae3a8
+        d->u.device.bcdUSB_lo          = usb_lo(0x0200);
9ae3a8
+        d->u.device.bcdUSB_hi          = usb_hi(0x0200);
9ae3a8
+    } else {
9ae3a8
+        d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
9ae3a8
+        d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
9ae3a8
+    }
9ae3a8
     d->u.device.bDeviceClass       = dev->bDeviceClass;
9ae3a8
     d->u.device.bDeviceSubClass    = dev->bDeviceSubClass;
9ae3a8
     d->u.device.bDeviceProtocol    = dev->bDeviceProtocol;
9ae3a8
@@ -497,6 +507,10 @@ void usb_desc_init(USBDevice *dev)
9ae3a8
     if (desc->super) {
9ae3a8
         dev->speedmask |= USB_SPEED_MASK_SUPER;
9ae3a8
     }
9ae3a8
+    if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) {
9ae3a8
+        dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE);
9ae3a8
+        usb_desc_set_string(dev, 0xee, "MSFT100Q");
9ae3a8
+    }
9ae3a8
     usb_desc_setdefaults(dev);
9ae3a8
 }
9ae3a8
 
9ae3a8
@@ -624,6 +638,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
9ae3a8
 int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
9ae3a8
                             int value, uint8_t *dest, size_t len)
9ae3a8
 {
9ae3a8
+    bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
9ae3a8
     const USBDesc *desc = usb_device_get_usb_desc(dev);
9ae3a8
     const USBDescDevice *other_dev;
9ae3a8
     uint8_t buf[256];
9ae3a8
@@ -644,7 +659,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
9ae3a8
 
9ae3a8
     switch(type) {
9ae3a8
     case USB_DT_DEVICE:
9ae3a8
-        ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
9ae3a8
+        ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf));
9ae3a8
         trace_usb_desc_device(dev->addr, len, ret);
9ae3a8
         break;
9ae3a8
     case USB_DT_CONFIG:
9ae3a8
@@ -701,6 +716,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
9ae3a8
 int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
9ae3a8
         int request, int value, int index, int length, uint8_t *data)
9ae3a8
 {
9ae3a8
+    bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
9ae3a8
     const USBDesc *desc = usb_device_get_usb_desc(dev);
9ae3a8
     int ret = -1;
9ae3a8
 
9ae3a8
@@ -780,6 +796,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
9ae3a8
         trace_usb_set_interface(dev->addr, index, value, ret);
9ae3a8
         break;
9ae3a8
 
9ae3a8
+    case VendorDeviceRequest | 'Q':
9ae3a8
+        if (msos) {
9ae3a8
+            ret = usb_desc_msos(desc, p, index, data, length);
9ae3a8
+            trace_usb_desc_msos(dev->addr, index, length, ret);
9ae3a8
+        }
9ae3a8
+        break;
9ae3a8
+    case VendorInterfaceRequest | 'Q':
9ae3a8
+        if (msos) {
9ae3a8
+            ret = usb_desc_msos(desc, p, index, data, length);
9ae3a8
+            trace_usb_desc_msos(dev->addr, index, length, ret);
9ae3a8
+        }
9ae3a8
+        break;
9ae3a8
+
9ae3a8
     }
9ae3a8
     return ret;
9ae3a8
 }
9ae3a8
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
9ae3a8
index 81327b0..2b4fcda 100644
9ae3a8
--- a/hw/usb/desc.h
9ae3a8
+++ b/hw/usb/desc.h
9ae3a8
@@ -2,6 +2,7 @@
9ae3a8
 #define QEMU_HW_USB_DESC_H
9ae3a8
 
9ae3a8
 #include <inttypes.h>
9ae3a8
+#include <wchar.h>
9ae3a8
 
9ae3a8
 /* binary representation */
9ae3a8
 typedef struct USBDescriptor {
9ae3a8
@@ -182,6 +183,11 @@ struct USBDescOther {
9ae3a8
     const uint8_t             *data;
9ae3a8
 };
9ae3a8
 
9ae3a8
+struct USBDescMSOS {
9ae3a8
+    const wchar_t             *Label;
9ae3a8
+    bool                      SelectiveSuspendEnabled;
9ae3a8
+};
9ae3a8
+
9ae3a8
 typedef const char *USBDescStrings[256];
9ae3a8
 
9ae3a8
 struct USBDesc {
9ae3a8
@@ -190,6 +196,7 @@ struct USBDesc {
9ae3a8
     const USBDescDevice       *high;
9ae3a8
     const USBDescDevice       *super;
9ae3a8
     const char* const         *str;
9ae3a8
+    const USBDescMSOS         *msos;
9ae3a8
 };
9ae3a8
 
9ae3a8
 #define USB_DESC_FLAG_SUPER (1 << 1)
9ae3a8
@@ -207,7 +214,7 @@ static inline uint8_t usb_hi(uint16_t val)
9ae3a8
 
9ae3a8
 /* generate usb packages from structs */
9ae3a8
 int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
9ae3a8
-                    uint8_t *dest, size_t len);
9ae3a8
+                    bool msos, uint8_t *dest, size_t len);
9ae3a8
 int usb_desc_device_qualifier(const USBDescDevice *dev,
9ae3a8
                               uint8_t *dest, size_t len);
9ae3a8
 int usb_desc_config(const USBDescConfig *conf, int flags,
9ae3a8
@@ -219,6 +226,8 @@ int usb_desc_iface(const USBDescIface *iface, int flags,
9ae3a8
 int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
9ae3a8
                       uint8_t *dest, size_t len);
9ae3a8
 int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
9ae3a8
+int usb_desc_msos(const USBDesc *desc, USBPacket *p,
9ae3a8
+                  int index, uint8_t *dest, size_t len);
9ae3a8
 
9ae3a8
 /* control message emulation helpers */
9ae3a8
 void usb_desc_init(USBDevice *dev);
9ae3a8
diff --git a/include/hw/usb.h b/include/hw/usb.h
9ae3a8
index a910456..b111be0 100644
9ae3a8
--- a/include/hw/usb.h
9ae3a8
+++ b/include/hw/usb.h
9ae3a8
@@ -182,6 +182,7 @@ typedef struct USBDescIface USBDescIface;
9ae3a8
 typedef struct USBDescEndpoint USBDescEndpoint;
9ae3a8
 typedef struct USBDescOther USBDescOther;
9ae3a8
 typedef struct USBDescString USBDescString;
9ae3a8
+typedef struct USBDescMSOS USBDescMSOS;
9ae3a8
 
9ae3a8
 struct USBDescString {
9ae3a8
     uint8_t index;
9ae3a8
@@ -207,6 +208,8 @@ struct USBEndpoint {
9ae3a8
 enum USBDeviceFlags {
9ae3a8
     USB_DEV_FLAG_FULL_PATH,
9ae3a8
     USB_DEV_FLAG_IS_HOST,
9ae3a8
+    USB_DEV_FLAG_MSOS_DESC_ENABLE,
9ae3a8
+    USB_DEV_FLAG_MSOS_DESC_IN_USE,
9ae3a8
 };
9ae3a8
 
9ae3a8
 /* definition of a USB device */
9ae3a8
diff --git a/trace-events b/trace-events
9ae3a8
index dbbd25d..5d86cf3 100644
9ae3a8
--- a/trace-events
9ae3a8
+++ b/trace-events
9ae3a8
@@ -393,6 +393,7 @@ usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d,
9ae3a8
 usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
9ae3a8
 usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
9ae3a8
 usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d"
9ae3a8
+usb_desc_msos(int addr, int index, int len, int ret) "dev %d msos, index 0x%x, len %d, ret %d"
9ae3a8
 usb_set_addr(int addr) "dev %d"
9ae3a8
 usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
9ae3a8
 usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8