usb: gadget: storage: add superspeed support
authorFelipe Balbi <balbi@ti.com>
Wed, 3 Aug 2011 11:33:27 +0000 (14:33 +0300)
committerFelipe Balbi <balbi@ti.com>
Thu, 13 Oct 2011 17:39:59 +0000 (20:39 +0300)
this patch adds superspeed descriptors for the
storage gadgets.

Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/mass_storage.c
drivers/usb/gadget/storage_common.c

index 927ee88..52583a2 100644 (file)
@@ -3023,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
                }
        }
 
+       if (gadget_is_superspeed(gadget)) {
+               unsigned        max_burst;
+
+               /* Calculate bMaxBurst, we know packet size is 1024 */
+               max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+               fsg_ss_bulk_in_desc.bEndpointAddress =
+                       fsg_fs_bulk_in_desc.bEndpointAddress;
+               fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+               fsg_ss_bulk_out_desc.bEndpointAddress =
+                       fsg_fs_bulk_out_desc.bEndpointAddress;
+               fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+               f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+               if (unlikely(!f->ss_descriptors)) {
+                       usb_free_descriptors(f->hs_descriptors);
+                       usb_free_descriptors(f->descriptors);
+                       return -ENOMEM;
+               }
+       }
+
        return 0;
 
 autoconf_fail:
index a230009..5779549 100644 (file)
@@ -586,7 +586,19 @@ dev_qualifier = {
        .bNumConfigurations =   1,
 };
 
+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
+{
+       memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
+       buf += USB_DT_BOS_SIZE;
+
+       memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
+       buf += USB_DT_USB_EXT_CAP_SIZE;
 
+       memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
+
+       return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+               + USB_DT_USB_EXT_CAP_SIZE;
+}
 
 /*
  * Config descriptors must agree with the code that sets configurations
@@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        break;
                case USB_DT_DEVICE_QUALIFIER:
                        VDBG(fsg, "get device qualifier\n");
-                       if (!gadget_is_dualspeed(fsg->gadget))
+                       if (!gadget_is_dualspeed(fsg->gadget) ||
+                                       fsg->gadget->speed == USB_SPEED_SUPER)
                                break;
                        /*
                         * Assume ep0 uses the same maxpacket value for both
@@ -948,7 +961,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
                case USB_DT_OTHER_SPEED_CONFIG:
                        VDBG(fsg, "get other-speed config descriptor\n");
-                       if (!gadget_is_dualspeed(fsg->gadget))
+                       if (!gadget_is_dualspeed(fsg->gadget) ||
+                                       fsg->gadget->speed == USB_SPEED_SUPER)
                                break;
                        goto get_config;
                case USB_DT_CONFIG:
@@ -967,7 +981,15 @@ get_config:
                        value = usb_gadget_get_string(&fsg_stringtab,
                                        w_value & 0xff, req->buf);
                        break;
+
+               case USB_DT_BOS:
+                       VDBG(fsg, "get bos descriptor\n");
+
+                       if (gadget_is_superspeed(fsg->gadget))
+                               value = populate_bos(fsg, req->buf);
+                       break;
                }
+
                break;
 
        /* One config, two speeds */
@@ -2777,13 +2799,15 @@ reset:
 
        /* Enable the endpoints */
        d = fsg_ep_desc(fsg->gadget,
-                       &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+                       &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+                       &fsg_ss_bulk_in_desc);
        if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
                goto reset;
        fsg->bulk_in_enabled = 1;
 
        d = fsg_ep_desc(fsg->gadget,
-                       &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+                       &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+                       &fsg_ss_bulk_out_desc);
        if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
                goto reset;
        fsg->bulk_out_enabled = 1;
@@ -2792,7 +2816,8 @@ reset:
 
        if (transport_is_cbi()) {
                d = fsg_ep_desc(fsg->gadget,
-                               &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
+                               &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
+                               &fsg_ss_intr_in_desc);
                if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
                        goto reset;
                fsg->intr_in_enabled = 1;
@@ -3424,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
                        fsg_fs_intr_in_desc.bEndpointAddress;
        }
 
+       if (gadget_is_superspeed(gadget)) {
+               unsigned                max_burst;
+
+               fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+               /* Calculate bMaxBurst, we know packet size is 1024 */
+               max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
+
+               /* Assume endpoint addresses are the same for both speeds */
+               fsg_ss_bulk_in_desc.bEndpointAddress =
+                       fsg_fs_bulk_in_desc.bEndpointAddress;
+               fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+               fsg_ss_bulk_out_desc.bEndpointAddress =
+                       fsg_fs_bulk_out_desc.bEndpointAddress;
+               fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+       }
+
        if (gadget_is_otg(gadget))
                fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
 
@@ -3540,11 +3583,7 @@ static void fsg_resume(struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver                fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       .speed          = USB_SPEED_HIGH,
-#else
-       .speed          = USB_SPEED_FULL,
-#endif
+       .speed          = USB_SPEED_SUPER,
        .function       = (char *) fsg_string_product,
        .unbind         = fsg_unbind,
        .disconnect     = fsg_disconnect,
index d2a9dcb..e24f72f 100644 (file)
@@ -160,7 +160,7 @@ static struct usb_composite_driver msg_driver = {
        .name           = "g_mass_storage",
        .dev            = &msg_device_desc,
        .iProduct       = DRIVER_DESC,
-       .max_speed      = USB_SPEED_HIGH,
+       .max_speed      = USB_SPEED_SUPER,
        .needs_serial   = 1,
 };
 
index 5236262..c7f291a 100644 (file)
@@ -515,12 +515,128 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
        NULL,
 };
 
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /*.bMaxBurst =          DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /*.bMaxBurst =          DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(2),
+       .bInterval =            9,      /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       .wBytesPerInterval =    cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES       2
+#else
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES       1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+       .bLength =              USB_DT_USB_EXT_CAP_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE_CAPABILITY,
+       .bDevCapabilityType =   USB_CAP_TYPE_EXT,
+
+       .bmAttributes =         cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+       .bLength =              USB_DT_USB_SS_CAP_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE_CAPABILITY,
+       .bDevCapabilityType =   USB_SS_CAP_TYPE,
+
+       /* .bmAttributes = LTM is not supported yet */
+
+       .wSpeedSupported =      cpu_to_le16(USB_LOW_SPEED_OPERATION
+               | USB_FULL_SPEED_OPERATION
+               | USB_HIGH_SPEED_OPERATION
+               | USB_5GBPS_OPERATION),
+       .bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+       .bU1devExitLat =        USB_DEFAULT_U1_DEV_EXIT_LAT,
+       .bU2DevExitLat =        USB_DEFAULT_U2_DEV_EXIT_LAT,
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+       .bLength =              USB_DT_BOS_SIZE,
+       .bDescriptorType =      USB_DT_BOS,
+
+       .wTotalLength =         USB_DT_BOS_SIZE
+                               + USB_DT_USB_EXT_CAP_SIZE
+                               + USB_DT_USB_SS_CAP_SIZE,
+
+       .bNumDeviceCaps =       2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+       (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+       (struct usb_descriptor_header *) &fsg_intf_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+       (struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+       (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+       NULL,
+};
+
 /* Maxpacket and other transfer characteristics vary by speed. */
 static __maybe_unused struct usb_endpoint_descriptor *
 fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
-               struct usb_endpoint_descriptor *hs)
+               struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *ss)
 {
-       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+       if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+               return ss;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
                return hs;
        return fs;
 }