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>
This commit is contained in:
Paul Zimmerman 2011-06-27 14:13:18 -07:00 committed by Felipe Balbi
parent 96fe53ef54
commit 04617db7aa
6 changed files with 324 additions and 11 deletions

View File

@ -401,7 +401,7 @@ static struct usb_composite_driver eth_driver = {
.name = "g_ether", .name = "g_ether",
.dev = &device_desc, .dev = &device_desc,
.strings = dev_strings, .strings = dev_strings,
.max_speed = USB_SPEED_HIGH, .max_speed = USB_SPEED_SUPER,
.unbind = __exit_p(eth_unbind), .unbind = __exit_p(eth_unbind),
}; };

View File

@ -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 */ /* peak (theoretical) bulk transfer rate in bits-per-second */
static inline unsigned ecm_bitrate(struct usb_gadget *g) 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; return 13 * 512 * 8 * 1000 * 8;
else 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_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_union_desc,
(struct usb_descriptor_header *) &ecm_desc, (struct usb_descriptor_header *) &ecm_desc,
/* NOTE: status endpoint might need to be removed */ /* NOTE: status endpoint might need to be removed */
(struct usb_descriptor_header *) &fs_ecm_notify_desc, (struct usb_descriptor_header *) &fs_ecm_notify_desc,
/* data interface, altsettings 0 and 1 */ /* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_nop_intf,
(struct usb_descriptor_header *) &ecm_data_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), .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
}; };
static struct usb_endpoint_descriptor hs_ecm_in_desc = { static struct usb_endpoint_descriptor hs_ecm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .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_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc, (struct usb_descriptor_header *) &ecm_union_desc,
(struct usb_descriptor_header *) &ecm_desc, (struct usb_descriptor_header *) &ecm_desc,
/* NOTE: status endpoint might need to be removed */ /* NOTE: status endpoint might need to be removed */
(struct usb_descriptor_header *) &hs_ecm_notify_desc, (struct usb_descriptor_header *) &hs_ecm_notify_desc,
/* data interface, altsettings 0 and 1 */ /* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &ecm_data_nop_intf, (struct usb_descriptor_header *) &ecm_data_nop_intf,
(struct usb_descriptor_header *) &ecm_data_intf, (struct usb_descriptor_header *) &ecm_data_intf,
@ -265,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
NULL, 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: */ /* string descriptors: */
static struct usb_string ecm_string_defs[] = { static struct usb_string ecm_string_defs[] = {
@ -679,6 +756,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
goto fail; 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 /* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code * the network link ... which is unavailable to this code
* until we're activated via set_alt(). * 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; ecm->port.close = ecm_close;
DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", 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", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->port.in_ep->name, ecm->port.out_ep->name,
ecm->notify->name); ecm->notify->name);
@ -696,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
fail: fail:
if (f->descriptors) if (f->descriptors)
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);
if (f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors);
if (ecm->notify_req) { if (ecm->notify_req) {
kfree(ecm->notify_req->buf); 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"); 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)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);

View File

@ -115,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
NULL, 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: */ /* string descriptors: */
static struct usb_string eem_string_defs[] = { static struct usb_string eem_string_defs[] = {
@ -265,7 +304,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
goto fail; 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", 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", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
eem->port.in_ep->name, eem->port.out_ep->name); eem->port.in_ep->name, eem->port.out_ep->name);
return 0; return 0;
@ -273,6 +325,8 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
fail: fail:
if (f->descriptors) if (f->descriptors)
usb_free_descriptors(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 */ /* we might as well release our claims on endpoints */
if (eem->port.out_ep->desc) 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"); 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)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);

View File

@ -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 */ /* peak (theoretical) bulk transfer rate in bits-per-second */
static unsigned int bitrate(struct usb_gadget *g) 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; return 13 * 512 * 8 * 1000 * 8;
else 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[] = { static struct usb_descriptor_header *eth_fs_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor, (struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */ /* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc, (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_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &fs_notify_desc, (struct usb_descriptor_header *) &fs_notify_desc,
/* data interface has no altsetting */ /* data interface has no altsetting */
(struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &rndis_data_intf,
(struct usb_descriptor_header *) &fs_in_desc, (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), .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
}; };
static struct usb_endpoint_descriptor hs_in_desc = { static struct usb_endpoint_descriptor hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
@ -261,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = {
static struct usb_descriptor_header *eth_hs_function[] = { static struct usb_descriptor_header *eth_hs_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor, (struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */ /* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc, (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_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &hs_notify_desc, (struct usb_descriptor_header *) &hs_notify_desc,
/* data interface has no altsetting */ /* data interface has no altsetting */
(struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &rndis_data_intf,
(struct usb_descriptor_header *) &hs_in_desc, (struct usb_descriptor_header *) &hs_in_desc,
@ -275,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = {
NULL, 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: */ /* string descriptors: */
static struct usb_string rndis_string_defs[] = { 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 */ /* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(eth_hs_function); f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
if (!f->hs_descriptors) if (!f->hs_descriptors)
goto fail; 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.open = rndis_open;
rndis->port.close = rndis_close; 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", 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", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->port.in_ep->name, rndis->port.out_ep->name,
rndis->notify->name); rndis->notify->name);
return 0; return 0;
fail: 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) if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
if (f->descriptors) if (f->descriptors)
@ -736,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_deregister(rndis->config); rndis_deregister(rndis->config);
rndis_exit(); rndis_exit();
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);

View File

@ -201,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {
NULL, 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 *) &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: */ /* string descriptors: */
static struct usb_string geth_string_defs[] = { 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 */ /* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(fs_eth_function); f->descriptors = usb_copy_descriptors(fs_eth_function);
if (!f->descriptors)
goto fail;
/* support all relevant hardware speeds... we expect that when /* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * 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 */ /* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(hs_eth_function); 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 /* 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", 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", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
geth->port.in_ep->name, geth->port.out_ep->name); geth->port.in_ep->name, geth->port.out_ep->name);
return 0; return 0;
fail: 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 */ /* we might as well release our claims on endpoints */
if (geth->port.out_ep->desc) if (geth->port.out_ep->desc)
geth->port.out_ep->driver_data = NULL; geth->port.out_ep->driver_data = NULL;
@ -330,6 +392,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
static void static void
geth_unbind(struct usb_configuration *c, struct usb_function *f) 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)) if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors); usb_free_descriptors(f->descriptors);

View File

@ -97,16 +97,17 @@ struct eth_dev {
static unsigned qmult = 5; static unsigned qmult = 5;
module_param(qmult, uint, S_IRUGO|S_IWUSR); 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) */ #else /* full speed (low speed doesn't do bulk) */
#define qmult 1 #define qmult 1
#endif #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) 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; return qmult * DEFAULT_QLEN;
else else
return DEFAULT_QLEN; return DEFAULT_QLEN;
@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
req->length = length; req->length = length;
/* throttle highspeed IRQ rate back slightly */ /* throttle high/super speed IRQ rate back slightly */
if (gadget_is_dualspeed(dev->gadget)) 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) ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
: 0; : 0;