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 *) ðer_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