]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/usb/desc.c
usb: accept usb3 control requests
[mirror_qemu.git] / hw / usb / desc.c
index f18a0435003a8f4442b98bfc14dbfa85459a07bf..c36bf30e4f3b69ffde89fe56b07e23098333fa87 100644 (file)
@@ -1,4 +1,4 @@
-#include <ctype.h>
+#include "qemu/osdep.h"
 
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
@@ -7,7 +7,7 @@
 /* ------------------------------------------------------------------ */
 
 int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
-                    uint8_t *dest, size_t len)
+                    bool msos, uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x12;
     USBDescriptor *d = (void *)dest;
@@ -19,8 +19,18 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
     d->bLength                     = bLength;
     d->bDescriptorType             = USB_DT_DEVICE;
 
-    d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
-    d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    if (msos && dev->bcdUSB < 0x0200) {
+        /*
+         * Version 2.0+ required for microsoft os descriptors to work.
+         * Done this way so msos-desc compat property will handle both
+         * the version and the new descriptors being present.
+         */
+        d->u.device.bcdUSB_lo          = usb_lo(0x0200);
+        d->u.device.bcdUSB_hi          = usb_hi(0x0200);
+    } else {
+        d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
+        d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    }
     d->u.device.bDeviceClass       = dev->bDeviceClass;
     d->u.device.bDeviceSubClass    = dev->bDeviceSubClass;
     d->u.device.bDeviceProtocol    = dev->bDeviceProtocol;
@@ -499,23 +509,15 @@ void usb_desc_init(USBDevice *dev)
     if (desc->super) {
         dev->speedmask |= USB_SPEED_MASK_SUPER;
     }
+    if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) {
+        dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE);
+        usb_desc_set_string(dev, 0xee, "MSFT100Q");
+    }
     usb_desc_setdefaults(dev);
 }
 
 void usb_desc_attach(USBDevice *dev)
 {
-    const USBDesc *desc = usb_device_get_usb_desc(dev);
-
-    assert(desc != NULL);
-    if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
-        dev->speed = USB_SPEED_SUPER;
-    } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
-        dev->speed = USB_SPEED_HIGH;
-    } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
-        dev->speed = USB_SPEED_FULL;
-    } else {
-        return;
-    }
     usb_desc_setdefaults(dev);
 }
 
@@ -554,9 +556,7 @@ void usb_desc_create_serial(USBDevice *dev)
     DeviceState *hcd = dev->qdev.parent_bus->parent;
     const USBDesc *desc = usb_device_get_usb_desc(dev);
     int index = desc->id.iSerialNumber;
-    char serial[64];
-    char *path;
-    int dst;
+    char *path, *serial;
 
     if (dev->serial) {
         /* 'serial' usb bus property has priority if present */
@@ -565,13 +565,16 @@ void usb_desc_create_serial(USBDevice *dev)
     }
 
     assert(index != 0 && desc->str[index] != NULL);
-    dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]);
     path = qdev_get_dev_path(hcd);
     if (path) {
-        dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path);
+        serial = g_strdup_printf("%s-%s-%s", desc->str[index],
+                                 path, dev->port->path);
+    } else {
+        serial = g_strdup_printf("%s-%s", desc->str[index], dev->port->path);
     }
-    dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path);
     usb_desc_set_string(dev, index, serial);
+    g_free(path);
+    g_free(serial);
 }
 
 const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
@@ -626,6 +629,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
 int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
                             int value, uint8_t *dest, size_t len)
 {
+    bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
     const USBDesc *desc = usb_device_get_usb_desc(dev);
     const USBDescDevice *other_dev;
     uint8_t buf[256];
@@ -646,7 +650,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
 
     switch(type) {
     case USB_DT_DEVICE:
-        ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
+        ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf));
         trace_usb_desc_device(dev->addr, len, ret);
         break;
     case USB_DT_CONFIG:
@@ -703,6 +707,7 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
 int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         int request, int value, int index, int length, uint8_t *data)
 {
+    bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
     const USBDesc *desc = usb_device_get_usb_desc(dev);
     int ret = -1;
 
@@ -743,7 +748,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
          * We return the same value that a configured device would return if
          * it used the first configuration.
          */
-        if (config->bmAttributes & 0x40) {
+        if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) {
             data[0] |= 1 << USB_DEVICE_SELF_POWERED;
         }
         if (dev->remote_wakeup) {
@@ -769,6 +774,13 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         trace_usb_set_device_feature(dev->addr, value, ret);
         break;
 
+    case DeviceOutRequest | USB_REQ_SET_SEL:
+    case DeviceOutRequest | USB_REQ_SET_ISOCH_DELAY:
+        if (dev->speed == USB_SPEED_SUPER) {
+            ret = 0;
+        }
+        break;
+
     case InterfaceRequest | USB_REQ_GET_INTERFACE:
         if (index < 0 || index >= dev->ninterfaces) {
             break;
@@ -782,6 +794,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         trace_usb_set_interface(dev->addr, index, value, ret);
         break;
 
+    case VendorDeviceRequest | 'Q':
+        if (msos) {
+            ret = usb_desc_msos(desc, p, index, data, length);
+            trace_usb_desc_msos(dev->addr, index, length, ret);
+        }
+        break;
+    case VendorInterfaceRequest | 'Q':
+        if (msos) {
+            ret = usb_desc_msos(desc, p, index, data, length);
+            trace_usb_desc_msos(dev->addr, index, length, ret);
+        }
+        break;
+
     }
     return ret;
 }