diff options
author | Paul Zimmerman <Paul.Zimmerman@synopsys.com> | 2011-06-28 01:13:18 +0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-07-08 14:55:30 +0400 |
commit | 04617db7aa688598ebd3fce20691d31a5e778b45 (patch) | |
tree | 101ac8a5892c1fb6e9aefe2a4acffc666ace3089 /drivers/usb/gadget | |
parent | 96fe53ef5498ba130b2f054f2de38e090ddaa55f (diff) | |
download | linux-04617db7aa688598ebd3fce20691d31a5e778b45.tar.xz |
usb: gadget: add SS descriptors to Ethernet gadget
Add SuperSpeed descriptors to the Network USB
function drivers.
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@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/ether.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/f_ecm.c | 100 | ||||
-rw-r--r-- | drivers/usb/gadget/f_eem.c | 56 | ||||
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 101 | ||||
-rw-r--r-- | drivers/usb/gadget/f_subset.c | 64 | ||||
-rw-r--r-- | drivers/usb/gadget/u_ether.c | 12 |
6 files changed, 324 insertions, 11 deletions
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ac41858800a5..aafc84f33e26 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -401,7 +401,7 @@ static struct usb_composite_driver eth_driver = { .name = "g_ether", .dev = &device_desc, .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_SUPER, .unbind = __exit_p(eth_unbind), }; diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index ddedbc83bc37..3691a0cb9465 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) + if (gadget_is_superspeed(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; } /*-------------------------------------------------------------------------*/ @@ -210,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = { (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 *) &fs_ecm_notify_desc, + /* data interface, altsettings 0 and 1 */ (struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_intf, @@ -231,6 +235,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, @@ -255,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = { (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 *) &hs_ecm_notify_desc, + /* data interface, altsettings 0 and 1 */ (struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_intf, @@ -265,6 +272,76 @@ 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 = sizeof ss_ecm_intr_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .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 = sizeof ss_ecm_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 *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[] = { @@ -679,6 +756,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_ecm_in_desc.bEndpointAddress = + fs_ecm_in_desc.bEndpointAddress; + ss_ecm_out_desc.bEndpointAddress = + fs_ecm_out_desc.bEndpointAddress; + ss_ecm_notify_desc.bEndpointAddress = + fs_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 * the network link ... which is unavailable to this code * until we're activated via set_alt(). @@ -688,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->port.close = ecm_close; DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->notify->name); @@ -696,6 +788,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,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ecm 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); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 3e412740e2ef..046c6d0e6960 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -115,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[] = { @@ -265,7 +304,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f) 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; + + /* 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; @@ -273,6 +325,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,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); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index b324efa07733..8f3eae90919f 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) + if (gadget_is_superspeed(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; } /*-------------------------------------------------------------------------*/ @@ -216,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = { static struct usb_descriptor_header *eth_fs_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, @@ -223,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = { (struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &fs_notify_desc, + /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &fs_in_desc, @@ -241,6 +245,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, @@ -261,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = { static struct usb_descriptor_header *eth_hs_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, @@ -268,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = { (struct usb_descriptor_header *) &rndis_acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &hs_notify_desc, + /* data interface has no altsetting */ (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &hs_in_desc, @@ -275,6 +282,76 @@ 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 = sizeof ss_intr_comp_desc, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .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 = sizeof 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 *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,11 +747,24 @@ 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; } + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_in_desc.bEndpointAddress = + fs_in_desc.bEndpointAddress; + ss_out_desc.bEndpointAddress = + fs_out_desc.bEndpointAddress; + ss_notify_desc.bEndpointAddress = + fs_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; rndis->port.close = rndis_close; @@ -699,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) */ DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->notify->name); return 0; fail: + if (gadget_is_superspeed(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,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); + 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); diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 93bf676ef507..3dc53754ab60 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -201,6 +201,46 @@ 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 = sizeof ss_subset_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 *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 +330,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 +345,20 @@ 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; + } + + if (gadget_is_superspeed(c->cdev->gadget)) { + ss_subset_in_desc.bEndpointAddress = + fs_subset_in_desc.bEndpointAddress; + ss_subset_out_desc.bEndpointAddress = + fs_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 @@ -311,11 +367,17 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) */ DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", geth->port.in_ep->name, geth->port.out_ep->name); 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,6 +392,8 @@ fail: static void geth_unbind(struct usb_configuration *c, struct usb_function *f) { + 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); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b91363e88db7..dfed4c1d96c0 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -97,16 +97,17 @@ struct eth_dev { static unsigned qmult = 5; module_param(qmult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(qmult, "queue length multiplier at high speed"); +MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed"); #else /* full speed (low speed doesn't do bulk) */ #define qmult 1 #endif -/* for dual-speed hardware, use deeper queues at highspeed */ +/* for dual-speed hardware, use deeper queues at high/super speed */ static inline int qlen(struct usb_gadget *gadget) { - if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH || + gadget->speed == USB_SPEED_SUPER)) return qmult * DEFAULT_QLEN; else return DEFAULT_QLEN; @@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->length = length; - /* throttle highspeed IRQ rate back slightly */ + /* throttle high/super speed IRQ rate back slightly */ if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || + dev->gadget->speed == USB_SPEED_SUPER) ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) : 0; |