usb: Adding SuperSpeed support to dummy_hcd
Subsystems (2)
PATCH v6 1/1 usb: Adding SuperSpeed support to dummy_hcd
USB 3.0 hub includes 2 hubs - HS and SS ones.
Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).
--- drivers/usb/gadget/dummy_hcd.c | 488 +++++++++++++++++++++++++++++++++++++++- 1 files changed, 480 insertions(+), 8 deletions(-)
drivers/usb/gadget/dummy_hcd.c +480 -8
@@ -62,9 +62,12 @@#define POWER_BUDGET 500/* in mA; use 8 for low-power port testing */ static const char driver_name [] ="dummy_hcd" ; +static const char ss_driver_name[] ="ss_dummy_hcd" ;static const char driver_desc [] ="USB Host+Gadget Emulator" ; +static const char ss_driver_desc[] ="SS USB Host+Gadget Emulator" ;static const char gadget_name [] ="dummy_udc" ; +static const char ss_gadget_name[] ="ss_dummy_udc" ;MODULE_DESCRIPTION (DRIVER_DESC );MODULE_AUTHOR ("David Brownell" );
@@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev) }static struct dummy *the_controller; +static struct dummy *the_ss_controller;/*-------------------------------------------------------------------------*/
@@ -259,10 +263,94 @@ stop_activity (struct dummy *dum)/* driver now does any non-usb quiescing necessary */ } -/* caller must hold lock */ +/** +* set_ss_link_state() - Sets the current state of the SuperSpeed link +* @dum: pointer to the dummy_hcd structure to update the link +* state for +* +* This function updates the port_status according to the link +* state. The old status is saved befor updating. +* Note: this function should be called only for SuperSpeed +* master and the caller must hold the lock. +*/ +static void +set_ss_link_state (struct dummy *dum) +{ + dum->active =0 ; +if ((dum->port_status &USB_SS_PORT_STAT_POWER ) ==0 ) + dum->port_status =0 ; + +/* UDC suspend must cause a disconnect */ +else if (!dum->pullup || dum->udc_suspended) { + dum->port_status &= ~(USB_PORT_STAT_CONNECTION | +USB_PORT_STAT_ENABLE ); +if ((dum->old_status &USB_PORT_STAT_CONNECTION ) !=0 ) + dum->port_status |= + (USB_PORT_STAT_C_CONNECTION <<16 ); + }else { +/* device is connected and not suspended */ + dum->port_status |= (USB_PORT_STAT_CONNECTION | +USB_PORT_STAT_SUPER_SPEED ); +if ((dum->old_status &USB_PORT_STAT_CONNECTION ) ==0 ) + dum->port_status |= + (USB_PORT_STAT_C_CONNECTION <<16 ); +if ((dum->port_status &USB_PORT_STAT_ENABLE ) ==1 && + (dum->port_status &USB_SS_PORT_LS_U0 ) ==1 && + dum->rh_state !=DUMMY_RH_SUSPENDED ) + dum->active =1 ; + } + + +if ((dum->port_status &USB_PORT_STAT_ENABLE ) ==0 || dum->active) + dum->resuming =0 ; + +/* if !connected or reset */ +if ((dum->port_status &USB_PORT_STAT_CONNECTION ) ==0 || + (dum->port_status &USB_PORT_STAT_RESET ) !=0 ) { +/* +* We're connected and not reseted (reset occured now), +* and driver attached - disconnect! +*/ +if ((dum->old_status &USB_PORT_STAT_CONNECTION ) !=0 && + (dum->old_status &USB_PORT_STAT_RESET ) ==0 && + dum->driver) { +stop_activity (dum); +spin_unlock (&dum->lock); + dum->driver->disconnect (&dum->gadget); +spin_lock (&dum->lock); + } + }else if (dum->active != dum->old_active) { +if (dum->old_active && dum->driver->suspend) { +spin_unlock (&dum->lock); + dum->driver->suspend (&dum->gadget); +spin_lock (&dum->lock); + }else if (!dum->old_active && dum->driver->resume) { +spin_unlock (&dum->lock); + dum->driver->resume (&dum->gadget); +spin_lock (&dum->lock); + } + } + + dum->old_status = dum->port_status; + dum->old_active = dum->active; +} + +/** +* set_link_state() - Sets the current state of the link +* @dum: pointer to the dummy_hcd structure to update the link +* state for +* +* This function updates the port_status according to the link +* state. The old status is saved befor updating. +* Note: caller must hold the lock. +*/ static void set_link_state (struct dummy *dum) { +if (dum == the_ss_controller) { +set_ss_link_state (dum); +return ; + } dum->active =0 ;if ((dum->port_status &USB_PORT_STAT_POWER ) ==0 ) dum->port_status =0 ;
@@ -343,7 +431,13 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) dum =ep_to_dummy (ep);if (!dum->driver || !is_enabled (dum))return -ESHUTDOWN ; - max =le16_to_cpu (desc->wMaxPacketSize) &0x3ff ; + max =le16_to_cpu (desc->wMaxPacketSize) ; +/* +* For HS/FS devices only bits 0..9 of the wMaxPacketSize represent the +* maximum packet size +*/ +if (dum->gadget.speed <USB_SPEED_SUPER ) + max &=0x3ff ;/* drivers must not request bad settings, since lower levels * (hardware or its drivers) may not check. some endpoints
@@ -361,6 +455,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done; }switch (dum->gadget.speed) { +case USB_SPEED_SUPER : +if (max ==1024 ) +break ; + goto done;case USB_SPEED_HIGH :if (max ==512 )break ;
@@ -379,6 +477,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done;/* real hardware might not handle all packet sizes */ switch (dum->gadget.speed) { +case USB_SPEED_SUPER :case USB_SPEED_HIGH :if (max <=1024 )break ;
@@ -399,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto done;/* real hardware might not handle all packet sizes */ switch (dum->gadget.speed) { +case USB_SPEED_SUPER :case USB_SPEED_HIGH :if (max <=1024 )break ;
@@ -751,9 +851,14 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { - struct dummy *dum = the_controller; + struct dummy *dum;int retval, i; +if (driver->speed ==USB_SPEED_SUPER ) + dum = the_ss_controller; +else + dum = the_controller; +if (!dum)return -EINVAL ;if (dum->driver)
@@ -787,7 +892,11 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver, } dum->gadget.ep0 = &dum->ep [0 ].ep; - dum->ep [0 ].ep.maxpacket =64 ; + dum->gadget.speed = driver->speed; +if (driver->speed ==USB_SPEED_SUPER ) + dum->ep[0 ].ep.maxpacket =9 ; +else + dum->ep[0 ].ep.maxpacket =64 ;list_del_init (&dum->ep [0 ].ep.ep_list);INIT_LIST_HEAD (&dum->fifo_req.queue);
@@ -817,12 +926,20 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) { -struct dummy *dum = the_controller; +struct dummy *dum ;unsigned long flags; +if (!driver || !driver->unbind) +return -EINVAL ; + +if (driver->speed ==USB_SPEED_SUPER ) + dum = the_ss_controller; +else + dum = the_controller; +if (!dum)return -ENODEV ; -if (!driver || driver != dum->driver || !driver->unbind) +if (driver != dum->driver)return -EINVAL ; dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
@@ -899,6 +1016,34 @@ static int dummy_udc_probe (struct platform_device *pdev)return rc; } +static int dummy_ss_udc_probe (struct platform_device *pdev) +{ +struct dummy *dum = the_ss_controller; +int rc; + + dum->gadget.name = gadget_name; + dum->gadget.ops = &dummy_ops; + dum->gadget.is_dualspeed =1 ; + +/* maybe claim OTG support, though we won't complete HNP */ + dum->gadget.is_otg = (dummy_to_hcd (dum)->self.otg_port !=0 ); + +dev_set_name (&dum->gadget.dev,"ss_gadget" ); + dum->gadget.dev.parent = &pdev->dev; + dum->gadget.dev.release = dummy_gadget_release; + rc =device_register (&dum->gadget.dev); +if (rc <0 ) +return rc; + +usb_get_hcd (dummy_to_hcd (dum)); + +platform_set_drvdata (pdev, dum); + rc =device_create_file (&dum->gadget.dev, &dev_attr_function); +if (rc <0 ) +device_unregister (&dum->gadget.dev); +return rc; +} +static int dummy_udc_remove (struct platform_device *pdev) {struct dummy *dum =platform_get_drvdata (pdev);
@@ -948,6 +1093,17 @@ static struct platform_driver dummy_udc_driver = { }, }; +static struct platform_driver dummy_ss_udc_driver = { + .probe = dummy_ss_udc_probe, + .remove = dummy_udc_remove, + .suspend = dummy_udc_suspend, + .resume = dummy_udc_resume, + .driver = { + .name = (char *) ss_gadget_name, + .owner =THIS_MODULE , + }, +}; +/*-------------------------------------------------------------------------*/ /* MASTER/HOST SIDE DRIVER
@@ -1246,6 +1402,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,case USB_DEVICE_A_ALT_HNP_SUPPORT : dum->gadget.a_alt_hnp_support =1 ;break ; +case USB_DEVICE_U1_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_U1_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ; +case USB_DEVICE_U2_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_U2_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ; +case USB_DEVICE_LTM_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_LTM_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ;default : ret_val = -EOPNOTSUPP ; }
@@ -1272,6 +1446,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,case USB_DEVICE_REMOTE_WAKEUP : w_value =USB_DEVICE_REMOTE_WAKEUP ;break ; +case USB_DEVICE_U1_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_U1_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ; +case USB_DEVICE_U2_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_U2_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ; +case USB_DEVICE_LTM_ENABLE : +if (dum->gadget.speed ==USB_SPEED_SUPER ) + w_value =USB_DEV_STAT_LTM_ENABLED ; +else + ret_val = -EOPNOTSUPP ; +break ;default : ret_val = -EOPNOTSUPP ;break ;
@@ -1352,6 +1544,9 @@ static void dummy_timer (unsigned long _dum)case USB_SPEED_HIGH : total =512 /*bytes*/ *13 /*packets*/ *8 /*uframes*/ ;break ; +case USB_SPEED_SUPER : + total =400 <<20 ;/* 400MB = 400*(2^20) bytes */ +break ;default :dev_err (dummy_dev (dum),"bogus device speed\n" );return ;
@@ -1597,7 +1792,172 @@ hub_descriptor (struct usb_hub_descriptor *desc) desc->bitmap [1 ] =0xff ; } -static int dummy_hub_control ( +/** +* dummy_ss_hub_control() - handles the control requests of the dummy (ss hub) +* master. +* @hcd: pointer to the hcd to handle +* @typeReq: type of the request +* @wValue: wValue of the request +* @wIndex: wIndex of the request +* @buf: buffer for reply in case of an IN request +* @wLength: wLength of the request +* +* Return int - 0 on success, error code otherwise +* +* This function handles the control requests of the dummy (ss +* hub) master. All control requests that are part of the +* enumeration are handled by the dummy_timer +* Note: this function is used only for the SS root hub +*/ +static int dummy_ss_hub_control ( +struct usb_hcd *hcd, +u16 typeReq, +u16 wValue, +u16 wIndex, +char *buf, +u16 wLength) +{ +struct dummy *dum; +int retval =0 ; +unsigned long flags; + +if (!HCD_HW_ACCESSIBLE (hcd)) +return -ETIMEDOUT ; + + dum =hcd_to_dummy (hcd); +spin_lock_irqsave (&dum->lock, flags); +switch (typeReq) { +case ClearHubFeature: +break ; +case ClearPortFeature: +switch (wValue) { +case USB_PORT_FEAT_POWER : +if (dum->port_status &USB_SS_PORT_STAT_POWER ) +dev_dbg (dummy_dev (dum),"power-off\n" ); +/* FALLS THROUGH */ +default : + dum->port_status &= ~(1 << wValue); +set_link_state (dum); + } +break ; +case GetHubDescriptor: +hub_descriptor ((struct usb_hub_descriptor *) buf); +break ; +case GetHubStatus: +/* +* We report that no change occured in the hub status +* (power and overcurent conditions) +*/ + *(__le32 *) buf =cpu_to_le32 (0 ); +break ; +case GetPortStatus: +/* We have only one port */ +if (wIndex !=1 ) + retval = -EPIPE ; + +/* +* whoever resets or resumes must GetPortStatus to +* complete it!! +*/ +/* TODO: add support for suspend/resume */ +if ((dum->port_status &USB_PORT_STAT_RESET ) !=0 && +time_after_eq (jiffies, dum->re_timeout)) { + dum->port_status |= (USB_PORT_STAT_C_RESET <<16 ); + dum->port_status &= ~USB_PORT_STAT_RESET ; + } +if (dum->pullup) + dum->port_status |=USB_PORT_STAT_ENABLE ; + +set_link_state (dum); + + ((__le16 *) buf)[0 ] =cpu_to_le16 (dum->port_status); + ((__le16 *) buf)[1 ] =cpu_to_le16 (dum->port_status >>16 ); +break ; +case SetHubFeature: + retval = -EPIPE ; +break ; +case SetPortFeature: +switch (wValue) { +case USB_PORT_FEAT_LINK_STATE : +/* +* Since this is dummy we don't have an actual link so +* there is nothing to do for the SET_LINK_STATE cmd +*/ +break ; +case USB_PORT_FEAT_U1_TIMEOUT : +case USB_PORT_FEAT_U2_TIMEOUT : +/* TODO: add suspend/resume support! */ +break ; +case USB_PORT_FEAT_POWER : + dum->port_status |=USB_SS_PORT_STAT_POWER ; +set_link_state (dum); +break ; +case USB_PORT_FEAT_BH_PORT_RESET : +case USB_PORT_FEAT_RESET : +/* if it's already enabled, disable */ + dum->port_status =0 ; + dum->port_status = (USB_SS_PORT_STAT_POWER | +USB_PORT_STAT_CONNECTION | +USB_PORT_STAT_RESET ); +/* +* We want to reset device status. All but the +* Self powered feature +*/ + dum->devstatus &=0x0000 | + (1 <<USB_DEVICE_SELF_POWERED ); +/* +* FIXME: what is the correct reset signaling interval? +* Is it still 50msec as for HS? +*/ + dum->re_timeout = jiffies +msecs_to_jiffies (50 ); +/* FALLS THROUGH */ +default : +if ((dum->port_status & +USB_SS_PORT_STAT_POWER ) !=0 ) { + dum->port_status |= (1 << wValue); +set_link_state (dum); + } + } +break ; +case GetPortErrorCount: +/* We'll always return 0 since this is a dummy hub */ + *(__le32 *) buf =cpu_to_le32 (0 ); +break ; +case SetHubDepth: +break ; +default : +dev_dbg (dummy_dev (dum), +"hub control req%04x v%04x i%04x l%d\n" , + typeReq, wValue, wIndex, wLength); +/* "protocol stall" on error */ + retval = -EPIPE ; + } +spin_unlock_irqrestore (&dum->lock, flags); + +if ((dum->port_status &PORT_C_MASK ) !=0 ) +usb_hcd_poll_rh_status (hcd); +return retval; +} + + +/** +* dummy_hub_control() - handles the control requests of the dummy (hs hub) +* master. +* @hcd: pointer to the hcd to handle +* @typeReq: type of the request +* @wValue: wValue of the request +* @wIndex: wIndex of the request +* @buf: buffer for reply in case of an IN request +* @wLength: wLength of the request +* +* Return int - 0 on success, error code otherwise +* +* This function handles the control requests of the dummy (hs +* hub) master. All control requests that are part of the +* enumeration are handled by the dummy_timer +* Note: this function is used only for the HS root hub +*/ +static int dummy_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue,
@@ -1711,7 +2071,11 @@ static int dummy_hub_control ( dum->port_status &= ~(USB_PORT_STAT_ENABLE |USB_PORT_STAT_LOW_SPEED |USB_PORT_STAT_HIGH_SPEED ); - dum->devstatus =0 ; +/* +* We want to reset device status. All but the +* Self powered feature +*/ + dum->devstatus &= (1 <<USB_DEVICE_SELF_POWERED );/* 50msec reset signaling */ dum->re_timeout = jiffies +msecs_to_jiffies (50 );/* FALLS THROUGH */
@@ -1894,6 +2258,27 @@ static const struct hc_driver dummy_hcd = { .bus_resume = dummy_bus_resume, }; +static const struct hc_driver dummy_ss_hcd = { + .description = (char *) ss_driver_name, + .product_desc ="Dummy SS host controller" , + .hcd_priv_size =sizeof (struct dummy ), + + .flags =HCD_USB3 , + + .start = dummy_start, + .stop = dummy_stop, + + .urb_enqueue = dummy_urb_enqueue, + .urb_dequeue = dummy_urb_dequeue, + + .get_frame_number = dummy_h_get_frame, + + .hub_status_data = dummy_hub_status, + .hub_control = dummy_ss_hub_control, + .bus_suspend = dummy_bus_suspend, + .bus_resume = dummy_bus_resume, +}; +static int dummy_hcd_probe (struct platform_device *pdev) {struct usb_hcd *hcd;
@@ -1914,6 +2299,26 @@ static int dummy_hcd_probe(struct platform_device *pdev)return retval; } +static int dummy_hcd_probe_ss (struct platform_device *pdev) +{ +struct usb_hcd *hcd; +int retval; + +dev_info (&pdev->dev,"%s, driver " DRIVER_VERSION "\n" , ss_driver_desc); + + hcd =usb_create_hcd (&dummy_ss_hcd, &pdev->dev,dev_name (&pdev->dev)); +if (!hcd) +return -ENOMEM ; + the_ss_controller =hcd_to_dummy (hcd); + + retval =usb_add_hcd (hcd,0 ,0 ); +if (retval !=0 ) { +usb_put_hcd (hcd); + the_ss_controller =NULL ; + } +return retval; +} +static int dummy_hcd_remove (struct platform_device *pdev) {struct usb_hcd *hcd;
@@ -1925,6 +2330,17 @@ static int dummy_hcd_remove (struct platform_device *pdev)return 0 ; } +static int dummy_ss_hcd_remove (struct platform_device *pdev) +{ +struct usb_hcd *hcd; + + hcd =platform_get_drvdata (pdev); +usb_remove_hcd (hcd); +usb_put_hcd (hcd); + the_ss_controller =NULL ; +return 0 ; +} +static int dummy_hcd_suspend (struct platform_device *pdev,pm_message_t state) {struct usb_hcd *hcd;
@@ -1966,10 +2382,23 @@ static struct platform_driver dummy_hcd_driver = { }, }; +static struct platform_driver dummy_ss_hcd_driver = { + .probe = dummy_hcd_probe_ss, + .remove = dummy_ss_hcd_remove, + .suspend = dummy_hcd_suspend, + .resume = dummy_hcd_resume, + .driver = { + .name = (char *) ss_driver_name, + .owner =THIS_MODULE , + }, +}; +/*-------------------------------------------------------------------------*/ static struct platform_device *the_udc_pdev; +static struct platform_device *the_ss_udc_pdev;static struct platform_device *the_hcd_pdev; +static struct platform_device *the_ss_hcd_pdev;static int __init init (void ) {
@@ -1981,34 +2410,73 @@ static int __init init (void) the_hcd_pdev =platform_device_alloc (driver_name,-1 );if (!the_hcd_pdev)return retval; + + the_ss_hcd_pdev =platform_device_alloc (ss_driver_name,-1 ); +if (!the_ss_hcd_pdev) + goto err_alloc_ss_hcd; + the_udc_pdev =platform_device_alloc (gadget_name,-1 );if (!the_udc_pdev) goto err_alloc_udc; + the_ss_udc_pdev =platform_device_alloc (ss_gadget_name,-1 ); +if (!the_ss_udc_pdev) + goto err_alloc_ss_udc; + retval =platform_driver_register (&dummy_hcd_driver);if (retval <0 ) goto err_register_hcd_driver; + + retval =platform_driver_register (&dummy_ss_hcd_driver); +if (retval <0 ) + goto err_register_ss_hcd_driver; + retval =platform_driver_register (&dummy_udc_driver);if (retval <0 ) goto err_register_udc_driver; + retval =platform_driver_register (&dummy_ss_udc_driver); +if (retval <0 ) + goto err_register_ss_udc_driver; + retval =platform_device_add (the_hcd_pdev);if (retval <0 ) goto err_add_hcd; + + retval =platform_device_add (the_ss_hcd_pdev); +if (retval <0 ) + goto err_add_ss_hcd; + retval =platform_device_add (the_udc_pdev);if (retval <0 ) goto err_add_udc; + + retval =platform_device_add (the_ss_udc_pdev); +if (retval <0 ) + goto err_add_ss_udc;return retval; +err_add_ss_udc: +platform_device_unregister (the_udc_pdev); err_add_udc: +platform_device_del (the_ss_hcd_pdev); +err_add_ss_hcd:platform_device_del (the_hcd_pdev); err_add_hcd: +platform_driver_unregister (&dummy_ss_udc_driver); +err_register_ss_udc_driver:platform_driver_unregister (&dummy_udc_driver); err_register_udc_driver: +platform_driver_unregister (&dummy_ss_hcd_driver); +err_register_ss_hcd_driver:platform_driver_unregister (&dummy_hcd_driver); err_register_hcd_driver: +platform_device_put (the_ss_udc_pdev); +err_alloc_ss_udc:platform_device_put (the_udc_pdev); err_alloc_udc: +platform_device_put (the_ss_hcd_pdev); +err_alloc_ss_hcd:platform_device_put (the_hcd_pdev);return retval; }
@@ -2017,8 +2485,12 @@ module_init (init); static void __exit cleanup (void) {platform_device_unregister (the_udc_pdev); +platform_device_unregister (the_ss_udc_pdev);platform_device_unregister (the_hcd_pdev); +platform_device_unregister (the_ss_hcd_pdev);platform_driver_unregister (&dummy_udc_driver); +platform_driver_unregister (&dummy_ss_udc_driver);platform_driver_unregister (&dummy_hcd_driver); +platform_driver_unregister (&dummy_ss_hcd_driver); }module_exit (cleanup);
Signature · 4 lines
1.6.3.3 -- Sent by a consultant of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Quoted 4 lines · Tatyana Brokhman
USB 3.0 hub includes 2 hubs - HS and SS ones.
Thus, whendummy_hcdenabled it will register 2 root hubs (SS and HS).Signed-off-by Tatyana Brokhman <[email protected]>
{sigh}
This changelog entry makes absolutely no sense. Please write something that describes what you are doing, and why you are doing it, with full details (i.e. links to the tests you ran, etc.) Look at how other people write their comments for major patches like this, be descriptive and verbose. It will help when in 3 years you are asked why this patch did what it did.
I'm sorry if it feels like I'm picking on you, but I'm trying to help you get it right for this, and future contributions.
thanks,
greg k-h
Quoted 2 lines · Tatyana Brokhman
USB 3.0 hub includes 2 hubs - HS and SS ones.
Thus, whendummy_hcdenabled it will register 2 root hubs (SS and HS).
Hmm. A quick comparison with the original source shows that you neglected to add code for SuperSpeed transfers to periodic_bytes() and show_urb().
drivers/usb/gadget/dummy_hcd.c static void dummy_timer (unsigned long _dum) · line 1549
Quoted 7 lines
drivers/usb/gadget/dummy_hcd.c +3
-0@@ -1352,6 +1544,9 @@ static void dummy_timer (unsigned long _dum)case USB_SPEED_HIGH : total =512 /*bytes*/ *13 /*packets*/ *8 /*uframes*/ ;break ; +case USB_SPEED_SUPER : + total =400 <<20 ;/* 400MB = 400*(2^20) bytes */ +break ;
Somehow I doubt that SuperSpeed USB, quick though it is, can transfer 400 MB in one millisecond. Where did you get that number from?
I can't find the appropriate table in the USB-3.0 spec (it might not be there at all), but with a bus transfer rate of 500 million bytes/s it seems clear that you can't transfer more than 500000 bytes per frame. The actual limit must be lower than that, maybe something like 1024 bytes/packet * 60 packets/uframe * 8 uframes/frame = 491520 bytes/frame.
Alan Stern
Quoted 9 lines · Tatyana Brokhman
Quoted 3 lines
USB 3.0 hub includes 2 hubs - HS and SS ones.
Thus, whendummy_hcdenabled it will register 2 root hubs (SS andHS).
Hmm. A quick comparison with the original source shows that you neglected to add code for SuperSpeed transfers to
periodic_bytes()andshow_urb().
Added in the next patch that will be uploaded soon.
Quoted 13 lines
drivers/usb/gadget/dummy_hcd.c static void dummy_timer (unsigned long _dum) · line 1549
Quoted 8 lines
drivers/usb/gadget/dummy_hcd.c +3
-0@@ -1352,6 +1544,9 @@ static void dummy_timer (unsigned long _dum)case USB_SPEED_HIGH : total =512 /*bytes*/ *13 /*packets*/ *8 /*uframes*/ ;break ; +case USB_SPEED_SUPER : + total =400 <<20 ;/* 400MB = 400*(2^20) bytes */ +break ;Somehow I doubt that SuperSpeed USB, quick though it is, can transfer 400 MB in one millisecond. Where did you get that number from?
Quoted 1 line
From USB3.0 Spec section 4.4.11. My mistake was that this value (400 << 20)
is per sec and not per milisec. When we divide it by 1000 (milisec) we'll receive a value close to what you suggested bellow. Fixed.
Quoted 8 lines
I can't find the appropriate table in the USB-3.0 spec (it might not be there at all), but with a bus transfer rate of 500 million bytes/s it seems clear that you can't transfer more than 500000 bytes per frame. The actual limit must be lower than that, maybe something like 1024 bytes/packet * 60 packets/uframe * 8 uframes/frame = 491520 bytes/frame.
Alan Stern
Sorry for the poor quoting (this mail is a bit old) and the late response. Our intention was to release the unittests we used to test this implementation with the next patch version but releasing them got delayed due to legal issues.
Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum