]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/usb/gadget/composite.c
Merge tag 'usb-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
[mirror_ubuntu-artful-kernel.git] / drivers / usb / gadget / composite.c
index 49d685ad0da90d1a1282dd9d25f31ad64db22087..dd74c99d6ce15f6a961d095f82c4a29bb560dc50 100644 (file)
@@ -315,6 +315,9 @@ void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
        list_del(&f->list);
        if (f->unbind)
                f->unbind(c, f);
+
+       if (f->bind_deactivated)
+               usb_function_activate(f);
 }
 EXPORT_SYMBOL_GPL(usb_remove_function);
 
@@ -607,7 +610,6 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 static int bos_desc(struct usb_composite_dev *cdev)
 {
        struct usb_ext_cap_descriptor   *usb_ext;
-       struct usb_ss_cap_descriptor    *ss_cap;
        struct usb_dcd_config_params    dcd_config_params;
        struct usb_bos_descriptor       *bos = cdev->req->buf;
 
@@ -633,29 +635,35 @@ static int bos_desc(struct usb_composite_dev *cdev)
         * The Superspeed USB Capability descriptor shall be implemented by all
         * SuperSpeed devices.
         */
-       ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
-       bos->bNumDeviceCaps++;
-       le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
-       ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
-       ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
-       ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
-       ss_cap->bmAttributes = 0; /* LTM is not supported yet */
-       ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
-                               USB_FULL_SPEED_OPERATION |
-                               USB_HIGH_SPEED_OPERATION |
-                               USB_5GBPS_OPERATION);
-       ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
-
-       /* Get Controller configuration */
-       if (cdev->gadget->ops->get_config_params)
-               cdev->gadget->ops->get_config_params(&dcd_config_params);
-       else {
-               dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
-               dcd_config_params.bU2DevExitLat =
-                       cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+       if (gadget_is_superspeed(cdev->gadget)) {
+               struct usb_ss_cap_descriptor *ss_cap;
+
+               ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+               bos->bNumDeviceCaps++;
+               le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+               ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+               ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+               ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+               ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+               ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+                                                     USB_FULL_SPEED_OPERATION |
+                                                     USB_HIGH_SPEED_OPERATION |
+                                                     USB_5GBPS_OPERATION);
+               ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+               /* Get Controller configuration */
+               if (cdev->gadget->ops->get_config_params) {
+                       cdev->gadget->ops->get_config_params(
+                               &dcd_config_params);
+               } else {
+                       dcd_config_params.bU1devExitLat =
+                               USB_DEFAULT_U1_DEV_EXIT_LAT;
+                       dcd_config_params.bU2DevExitLat =
+                               cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+               }
+               ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+               ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
        }
-       ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
-       ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
 
        /* The SuperSpeedPlus USB Device Capability descriptor */
        if (gadget_is_superspeed_plus(cdev->gadget)) {
@@ -956,12 +964,8 @@ static void remove_config(struct usb_composite_dev *cdev,
 
                f = list_first_entry(&config->functions,
                                struct usb_function, list);
-               list_del(&f->list);
-               if (f->unbind) {
-                       DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
-                       f->unbind(config, f);
-                       /* may free memory for "f" */
-               }
+
+               usb_remove_function(config, f);
        }
        list_del(&config->list);
        if (config->unbind) {
@@ -1603,7 +1607,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                        cdev->desc.bcdUSB = cpu_to_le16(0x0210);
                                }
                        } else {
-                               cdev->desc.bcdUSB = cpu_to_le16(0x0200);
+                               if (gadget->lpm_capable)
+                                       cdev->desc.bcdUSB = cpu_to_le16(0x0201);
+                               else
+                                       cdev->desc.bcdUSB = cpu_to_le16(0x0200);
                        }
 
                        value = min(w_length, (u16) sizeof cdev->desc);
@@ -1634,7 +1641,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                value = min(w_length, (u16) value);
                        break;
                case USB_DT_BOS:
-                       if (gadget_is_superspeed(gadget)) {
+                       if (gadget_is_superspeed(gadget) ||
+                           gadget->lpm_capable) {
                                value = bos_desc(cdev);
                                value = min(w_length, (u16) value);
                        }