Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / usb / gadget / f_eem.c
index b3c3042..046c6d0 100644 (file)
  * Ethernet link.
  */
 
-struct eem_ep_descs {
-       struct usb_endpoint_descriptor  *in;
-       struct usb_endpoint_descriptor  *out;
-};
-
 struct f_eem {
        struct gether                   port;
        u8                              ctrl_id;
-
-       struct eem_ep_descs             fs;
-       struct eem_ep_descs             hs;
 };
 
 static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
        NULL,
 };
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = {
+       .bLength =              sizeof eem_ss_bulk_comp_desc,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 2 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+};
+
+static struct usb_descriptor_header *eem_ss_function[] __initdata = {
+       /* CDC EEM control descriptors */
+       (struct usb_descriptor_header *) &eem_intf,
+       (struct usb_descriptor_header *) &eem_ss_in_desc,
+       (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
+       (struct usb_descriptor_header *) &eem_ss_out_desc,
+       (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */
 
 static struct usb_string eem_string_defs[] = {
@@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        gether_disconnect(&eem->port);
                }
 
-               if (!eem->port.in) {
+               if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
                        DBG(cdev, "init eem\n");
-                       eem->port.in = ep_choose(cdev->gadget,
-                                       eem->hs.in, eem->fs.in);
-                       eem->port.out = ep_choose(cdev->gadget,
-                                       eem->hs.out, eem->fs.out);
+                       if (config_ep_by_speed(cdev->gadget, f,
+                                              eem->port.in_ep) ||
+                           config_ep_by_speed(cdev->gadget, f,
+                                              eem->port.out_ep)) {
+                               eem->port.in_ep->desc = NULL;
+                               eem->port.out_ep->desc = NULL;
+                               goto fail;
+                       }
                }
 
                /* zlps should not occur because zero-length EEM packets
@@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
        if (!f->descriptors)
                goto fail;
 
-       eem->fs.in = usb_find_endpoint(eem_fs_function,
-                       f->descriptors, &eem_fs_in_desc);
-       eem->fs.out = usb_find_endpoint(eem_fs_function,
-                       f->descriptors, &eem_fs_out_desc);
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
@@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
                f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
                if (!f->hs_descriptors)
                        goto fail;
+       }
+
+       if (gadget_is_superspeed(c->cdev->gadget)) {
+               eem_ss_in_desc.bEndpointAddress =
+                               eem_fs_in_desc.bEndpointAddress;
+               eem_ss_out_desc.bEndpointAddress =
+                               eem_fs_out_desc.bEndpointAddress;
 
-               eem->hs.in = usb_find_endpoint(eem_hs_function,
-                               f->hs_descriptors, &eem_hs_in_desc);
-               eem->hs.out = usb_find_endpoint(eem_hs_function,
-                               f->hs_descriptors, &eem_hs_out_desc);
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail;
        }
 
        DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
                        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
                        eem->port.in_ep->name, eem->port.out_ep->name);
        return 0;
@@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 fail:
        if (f->descriptors)
                usb_free_descriptors(f->descriptors);
+       if (f->hs_descriptors)
+               usb_free_descriptors(f->hs_descriptors);
 
        /* we might as well release our claims on endpoints */
-       if (eem->port.out)
+       if (eem->port.out_ep->desc)
                eem->port.out_ep->driver_data = NULL;
-       if (eem->port.in)
+       if (eem->port.in_ep->desc)
                eem->port.in_ep->driver_data = NULL;
 
        ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
@@ -306,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(c->cdev, "eem unbind\n");
 
+       if (gadget_is_superspeed(c->cdev->gadget))
+               usb_free_descriptors(f->ss_descriptors);
        if (gadget_is_dualspeed(c->cdev->gadget))
                usb_free_descriptors(f->hs_descriptors);
        usb_free_descriptors(f->descriptors);