[PATCH] usb: gadget: add SS descriptors to Ethernet gadget

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This has been lightly tested using a Linux host. I was able to ssh from
device to host and host to device, no obvious problems seen.

Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>
---

Hi Felipe,

In the spirit of the other gadget patches that have appeared lately, here
is one to add SS descriptors to the Ethernet gadget. Hope you find it
useful.

-Paul


 drivers/usb/gadget/f_ecm.c          |   92 +++++++++++++++++++++++++++++++++--
 drivers/usb/gadget/f_eem.c          |   54 ++++++++++++++++++++-
 drivers/usb/gadget/f_ncm.c          |    8 ++-
 drivers/usb/gadget/f_rndis.c        |   93 +++++++++++++++++++++++++++++++++--
 drivers/usb/gadget/f_subset.c       |   62 +++++++++++++++++++++++-

diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index ddedbc8..b54e2ac 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -77,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ecm_bitrate(struct usb_gadget *g)
 {
-       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-               return 13 * 512 * 8 * 1000 * 8;
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return 13 *  512 * 8 * 1000 * 8;
        else
-               return 19 *  64 * 1 * 1000 * 8;
+               return 19 *   64 * 1 * 1000 * 8;
 }

 /*-------------------------------------------------------------------------*/
@@ -231,6 +233,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
        .wMaxPacketSize =       cpu_to_le16(ECM_STATUS_BYTECOUNT),
        .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
 };
+
 static struct usb_endpoint_descriptor hs_ecm_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -265,6 +268,71 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
        NULL,
 };

+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(ECM_STATUS_BYTECOUNT),
+       .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = {
+       .bLength =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    cpu_to_le16(ECM_STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_ecm_in_desc = {
+       .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 ss_ecm_out_desc = {
+       .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 ss_ecm_bulk_comp_desc = {
+       .bLength =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    0,
+};
+
+static struct usb_descriptor_header *ecm_ss_function[] = {
+       /* CDC ECM control descriptors */
+       (struct usb_descriptor_header *) &ecm_control_intf,
+       (struct usb_descriptor_header *) &ecm_header_desc,
+       (struct usb_descriptor_header *) &ecm_union_desc,
+       (struct usb_descriptor_header *) &ecm_desc,
+       /* NOTE: status endpoint might need to be removed */
+       (struct usb_descriptor_header *) &ss_ecm_notify_desc,
+       (struct usb_descriptor_header *) &ss_ecm_intr_comp_desc,
+       /* data interface, altsettings 0 and 1 */
+       (struct usb_descriptor_header *) &ecm_data_nop_intf,
+       (struct usb_descriptor_header *) &ecm_data_intf,
+       (struct usb_descriptor_header *) &ss_ecm_in_desc,
+       (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_ecm_out_desc,
+       (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */

 static struct usb_string ecm_string_defs[] = {
@@ -677,6 +745,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
                f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
                if (!f->hs_descriptors)
                        goto fail;
+
+               ss_ecm_in_desc.bEndpointAddress =
+                               hs_ecm_in_desc.bEndpointAddress;
+               ss_ecm_out_desc.bEndpointAddress =
+                               hs_ecm_out_desc.bEndpointAddress;
+               ss_ecm_notify_desc.bEndpointAddress =
+                               hs_ecm_notify_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail;
        }

        /* NOTE:  all that is done without knowing or caring about
@@ -696,6 +776,8 @@ ecm_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);

        if (ecm->notify_req) {
                kfree(ecm->notify_req->buf);
@@ -722,8 +804,10 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)

        DBG(c->cdev, "ecm unbind\n");

-       if (gadget_is_dualspeed(c->cdev->gadget))
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
                usb_free_descriptors(f->hs_descriptors);
+               usb_free_descriptors(f->ss_descriptors);
+       }
        usb_free_descriptors(f->descriptors);

        kfree(ecm->notify_req->buf);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index 3e41274..a22a3a8 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -115,6 +115,44 @@ 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 =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    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[] = {
@@ -263,6 +301,16 @@ 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;
+
+               eem_ss_in_desc.bEndpointAddress =
+                               eem_hs_in_desc.bEndpointAddress;
+               eem_ss_out_desc.bEndpointAddress =
+                               eem_hs_out_desc.bEndpointAddress;
+
+               /* 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",
@@ -273,6 +321,8 @@ 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_ep->desc)
@@ -292,8 +342,10 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)

        DBG(c->cdev, "eem unbind\n");

-       if (gadget_is_dualspeed(c->cdev->gadget))
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
                usb_free_descriptors(f->hs_descriptors);
+               usb_free_descriptors(f->ss_descriptors);
+       }
        usb_free_descriptors(f->descriptors);
        kfree(eem);
 }
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index ae69ed7..37712c9 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -83,10 +83,12 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ncm_bitrate(struct usb_gadget *g)
 {
-       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-               return 13 * 512 * 8 * 1000 * 8;
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return 13 *  512 * 8 * 1000 * 8;
        else
-               return 19 *  64 * 1 * 1000 * 8;
+               return 19 *   64 * 1 * 1000 * 8;
 }

 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index b324efa..8e8b1f9 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -95,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static unsigned int bitrate(struct usb_gadget *g)
 {
-       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-               return 13 * 512 * 8 * 1000 * 8;
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return 13 *  512 * 8 * 1000 * 8;
        else
-               return 19 *  64 * 1 * 1000 * 8;
+               return 19 *   64 * 1 * 1000 * 8;
 }

 /*-------------------------------------------------------------------------*/
@@ -241,6 +243,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
        .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
        .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
 };
+
 static struct usb_endpoint_descriptor hs_in_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -275,6 +278,71 @@ static struct usb_descriptor_header *eth_hs_function[] = {
        NULL,
 };

+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
+       .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
+       .bLength =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_in_desc = {
+       .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 ss_out_desc = {
+       .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 ss_bulk_comp_desc = {
+       .bLength =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    0,
+};
+
+static struct usb_descriptor_header *eth_ss_function[] = {
+       (struct usb_descriptor_header *) &rndis_iad_descriptor,
+       /* control interface matches ACM, not Ethernet */
+       (struct usb_descriptor_header *) &rndis_control_intf,
+       (struct usb_descriptor_header *) &header_desc,
+       (struct usb_descriptor_header *) &call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &rndis_acm_descriptor,
+       (struct usb_descriptor_header *) &rndis_union_desc,
+       (struct usb_descriptor_header *) &ss_notify_desc,
+       (struct usb_descriptor_header *) &ss_intr_comp_desc,
+       /* data interface has no altsetting */
+       (struct usb_descriptor_header *) &rndis_data_intf,
+       (struct usb_descriptor_header *) &ss_in_desc,
+       (struct usb_descriptor_header *) &ss_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_out_desc,
+       (struct usb_descriptor_header *) &ss_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */

 static struct usb_string rndis_string_defs[] = {
@@ -670,9 +738,20 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)

                /* copy descriptors, and track endpoint copies */
                f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
-
                if (!f->hs_descriptors)
                        goto fail;
+
+               ss_in_desc.bEndpointAddress =
+                               hs_in_desc.bEndpointAddress;
+               ss_out_desc.bEndpointAddress =
+                               hs_out_desc.bEndpointAddress;
+               ss_notify_desc.bEndpointAddress =
+                               hs_notify_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail;
        }

        rndis->port.open = rndis_open;
@@ -705,6 +784,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;

 fail:
+       if (gadget_is_dualspeed(c->cdev->gadget) && f->ss_descriptors)
+               usb_free_descriptors(f->ss_descriptors);
        if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
                usb_free_descriptors(f->hs_descriptors);
        if (f->descriptors)
@@ -736,8 +817,10 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
        rndis_deregister(rndis->config);
        rndis_exit();

-       if (gadget_is_dualspeed(c->cdev->gadget))
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
+               usb_free_descriptors(f->ss_descriptors);
                usb_free_descriptors(f->hs_descriptors);
+       }
        usb_free_descriptors(f->descriptors);

        kfree(rndis->notify_req->buf);
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 93bf676..2bee58f 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -201,6 +201,45 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {
        NULL,
 };

+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
+       .bLength =              6,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         0,
+       .wBytesPerInterval =    0,
+};
+
+static struct usb_descriptor_header *ss_eth_function[] __initdata = {
+       (struct usb_descriptor_header *) &subset_data_intf,
+       (struct usb_descriptor_header *) &mdlm_header_desc,
+       (struct usb_descriptor_header *) &mdlm_desc,
+       (struct usb_descriptor_header *) &mdlm_detail_desc,
+       (struct usb_descriptor_header *) &ether_desc,
+       (struct usb_descriptor_header *) &ss_subset_in_desc,
+       (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_subset_out_desc,
+       (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */

 static struct usb_string geth_string_defs[] = {
@@ -290,6 +329,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)

        /* copy descriptors, and track endpoint copies */
        f->descriptors = usb_copy_descriptors(fs_eth_function);
+       if (!f->descriptors)
+               goto fail;

        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
@@ -303,6 +344,18 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)

                /* copy descriptors, and track endpoint copies */
                f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
+               if (!f->hs_descriptors)
+                       goto fail;
+
+               ss_subset_in_desc.bEndpointAddress =
+                               hs_subset_in_desc.bEndpointAddress;
+               ss_subset_out_desc.bEndpointAddress =
+                               hs_subset_out_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(ss_eth_function);
+               if (!f->ss_descriptors)
+                       goto fail;
        }

        /* NOTE:  all that is done without knowing or caring about
@@ -316,6 +369,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;

 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 (geth->port.out_ep->desc)
                geth->port.out_ep->driver_data = NULL;
@@ -330,8 +388,10 @@ fail:
 static void
 geth_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-       if (gadget_is_dualspeed(c->cdev->gadget))
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
                usb_free_descriptors(f->hs_descriptors);
+               usb_free_descriptors(f->ss_descriptors);
+       }
        usb_free_descriptors(f->descriptors);
        geth_string_defs[1].s = NULL;
        kfree(func_to_geth(f));
--


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux