usb: gadget: Allow a non-SuperSpeed gadget to support LPM
authorJohn Youn <johnyoun@synopsys.com>
Fri, 28 Apr 2017 08:55:20 +0000 (12:55 +0400)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Fri, 2 Jun 2017 08:22:32 +0000 (11:22 +0300)
This commit allows a gadget that does not support SuperSpeed to indicate
that it supports LPM. It does this by setting the 'lpm_capable' flag in
the gadget structure.

If a gadget sets this, the composite gadget framework will set the
bcdUSB to 0x0201 to indicate that this supports BOS descriptors, and
also return a USB 2.0 Extension descriptor as part of the BOS descriptor
set.

See USB 2.0 LPM ECN Section 3.

Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Sevak Arakelyan <sevaka@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/gadget/composite.c
include/linux/usb/gadget.h

index abec93ab81ee144f9f1b75f3d3e890e0186925da..d62f53d7f4188b43231e1eeb7996b3f45a8563ab 100644 (file)
@@ -1608,7 +1608,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);
@@ -1639,7 +1642,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);
                        }
index fbc22a39e7bc6898f3cc17cbc49b8b3f458697b0..3ee5f2a7c0b4dc9bb08dff732e5136e8ec56db14 100644 (file)
@@ -352,6 +352,8 @@ struct usb_gadget_ops {
  * @deactivated: True if gadget is deactivated - in deactivated state it cannot
  *     be connected.
  * @connected: True if gadget is connected.
+ * @lpm_capable: If the gadget max_speed is FULL or HIGH, this flag
+ *     indicates that it supports LPM as per the LPM ECN & errata.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -404,6 +406,7 @@ struct usb_gadget {
        unsigned                        is_selfpowered:1;
        unsigned                        deactivated:1;
        unsigned                        connected:1;
+       unsigned                        lpm_capable:1;
 };
 #define work_to_gadget(w)      (container_of((w), struct usb_gadget, work))