mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-16 05:42:56 +00:00
fix enumeration issue when plugging hub with multiple devices attached
This commit is contained in:
parent
171d021ab5
commit
66c933fb61
@ -189,7 +189,7 @@ void hub_close(uint8_t dev_addr)
|
|||||||
if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
|
if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hub_status_pipe_queue(uint8_t dev_addr)
|
bool hub_edpt_status_xfer(uint8_t dev_addr)
|
||||||
{
|
{
|
||||||
hub_interface_t* hub_itf = get_itf(dev_addr);
|
hub_interface_t* hub_itf = get_itf(dev_addr);
|
||||||
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
|
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
|
||||||
@ -324,7 +324,7 @@ static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_reque
|
|||||||
|
|
||||||
// prepare for next hub status
|
// prepare for next hub status
|
||||||
// TODO continue with status_change, or maybe we can do it again with status
|
// TODO continue with status_change, or maybe we can do it again with status
|
||||||
hub_status_pipe_queue(dev_addr);
|
hub_edpt_status_xfer(dev_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -176,7 +176,7 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t
|
|||||||
|
|
||||||
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb);
|
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb);
|
||||||
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb);
|
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb);
|
||||||
bool hub_status_pipe_queue(uint8_t dev_addr);
|
bool hub_edpt_status_xfer(uint8_t dev_addr);
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Internal Class Driver API
|
// Internal Class Driver API
|
||||||
|
121
src/host/usbh.c
121
src/host/usbh.c
@ -543,7 +543,7 @@ void tuh_task(void)
|
|||||||
if ( event.connection.hub_addr != 0)
|
if ( event.connection.hub_addr != 0)
|
||||||
{
|
{
|
||||||
// done with hub, waiting for next data on status pipe
|
// done with hub, waiting for next data on status pipe
|
||||||
(void) hub_status_pipe_queue( event.connection.hub_addr );
|
(void) hub_edpt_status_xfer( event.connection.hub_addr );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -904,6 +904,10 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
// a device unplugged from rhport:hub_addr:hub_port
|
// a device unplugged from rhport:hub_addr:hub_port
|
||||||
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
|
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
|
||||||
{
|
{
|
||||||
@ -938,49 +942,6 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// INTERNAL HELPER
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
static uint8_t get_new_address(bool is_hub)
|
|
||||||
{
|
|
||||||
uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1;
|
|
||||||
uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX);
|
|
||||||
|
|
||||||
for (uint8_t i=0; i < count; i++)
|
|
||||||
{
|
|
||||||
uint8_t const addr = start + i;
|
|
||||||
if (!get_device(addr)->connected) return addr;
|
|
||||||
}
|
|
||||||
return ADDR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
|
||||||
{
|
|
||||||
usbh_device_t* dev = get_device(dev_addr);
|
|
||||||
|
|
||||||
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
|
|
||||||
{
|
|
||||||
// continue with next valid interface
|
|
||||||
// TODO skip IAD binding interface such as CDCs
|
|
||||||
uint8_t const drv_id = dev->itf2drv[itf_num];
|
|
||||||
if (drv_id != DRVID_INVALID)
|
|
||||||
{
|
|
||||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
|
||||||
TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
|
|
||||||
driver->set_config(dev_addr, itf_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// all interface are configured
|
|
||||||
if (itf_num == CFG_TUH_INTERFACE_MAX)
|
|
||||||
{
|
|
||||||
// Invoke callback if available
|
|
||||||
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Enumeration Process
|
// Enumeration Process
|
||||||
// is a lengthy process with a series of control transfer to configure
|
// is a lengthy process with a series of control transfer to configure
|
||||||
@ -991,9 +952,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
static bool enum_request_addr0_device_desc(void);
|
static bool enum_request_addr0_device_desc(void);
|
||||||
static bool enum_request_set_addr(void);
|
|
||||||
|
|
||||||
static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||||
|
|
||||||
|
static bool enum_request_set_addr(void);
|
||||||
static bool enum_set_address_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
static bool enum_set_address_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||||
static bool enum_get_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
static bool enum_get_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||||
static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||||
@ -1001,6 +962,9 @@ static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_
|
|||||||
static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||||
static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
|
static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
|
||||||
|
|
||||||
|
static uint8_t get_new_address(bool is_hub);
|
||||||
|
static void enum_full_complete(void);
|
||||||
|
|
||||||
#if CFG_TUH_HUB
|
#if CFG_TUH_HUB
|
||||||
|
|
||||||
// Enum sequence:
|
// Enum sequence:
|
||||||
@ -1015,7 +979,7 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques
|
|||||||
|
|
||||||
static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
|
static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
|
||||||
{
|
{
|
||||||
(void) dev_addr; (void) request;
|
(void) request;
|
||||||
TU_ASSERT(XFER_RESULT_SUCCESS == result);
|
TU_ASSERT(XFER_RESULT_SUCCESS == result);
|
||||||
|
|
||||||
hub_port_status_response_t port_status;
|
hub_port_status_response_t port_status;
|
||||||
@ -1024,7 +988,8 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request
|
|||||||
if ( !port_status.status.connection )
|
if ( !port_status.status.connection )
|
||||||
{
|
{
|
||||||
// device unplugged while delaying, nothing else to do, queue hub status
|
// device unplugged while delaying, nothing else to do, queue hub status
|
||||||
return hub_status_pipe_queue(dev_addr);
|
enum_full_complete();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
|
_dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
|
||||||
@ -1083,9 +1048,6 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques
|
|||||||
|
|
||||||
enum_request_set_addr();
|
enum_request_set_addr();
|
||||||
|
|
||||||
// done with hub, waiting for next data on status pipe
|
|
||||||
(void) hub_status_pipe_queue( _dev0.hub_addr );
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,11 +1106,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
|
|||||||
|
|
||||||
if (XFER_RESULT_SUCCESS != result)
|
if (XFER_RESULT_SUCCESS != result)
|
||||||
{
|
{
|
||||||
#if CFG_TUH_HUB
|
// stop enumeration, maybe we could retry this
|
||||||
// TODO remove, waiting for next data on status pipe
|
enum_full_complete();
|
||||||
if (_dev0.hub_addr != 0) hub_status_pipe_queue(_dev0.hub_addr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1407,4 +1366,54 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||||
|
{
|
||||||
|
usbh_device_t* dev = get_device(dev_addr);
|
||||||
|
|
||||||
|
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
|
||||||
|
{
|
||||||
|
// continue with next valid interface
|
||||||
|
// TODO skip IAD binding interface such as CDCs
|
||||||
|
uint8_t const drv_id = dev->itf2drv[itf_num];
|
||||||
|
if (drv_id != DRVID_INVALID)
|
||||||
|
{
|
||||||
|
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||||
|
TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||||
|
driver->set_config(dev_addr, itf_num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// all interface are configured
|
||||||
|
if (itf_num == CFG_TUH_INTERFACE_MAX)
|
||||||
|
{
|
||||||
|
enum_full_complete();
|
||||||
|
|
||||||
|
// Invoke callback if available
|
||||||
|
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enum_full_complete(void)
|
||||||
|
{
|
||||||
|
#if CFG_TUH_HUB
|
||||||
|
// get next hub status
|
||||||
|
if (_dev0.hub_addr) hub_edpt_status_xfer(_dev0.hub_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t get_new_address(bool is_hub)
|
||||||
|
{
|
||||||
|
uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1;
|
||||||
|
uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX);
|
||||||
|
|
||||||
|
for (uint8_t i=0; i < count; i++)
|
||||||
|
{
|
||||||
|
uint8_t const addr = start + i;
|
||||||
|
if (!get_device(addr)->connected) return addr;
|
||||||
|
}
|
||||||
|
return ADDR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -80,7 +80,8 @@ static inline bool tuh_ready(uint8_t daddr)
|
|||||||
return tuh_mounted(daddr) && !tuh_suspended(daddr);
|
return tuh_mounted(daddr) && !tuh_suspended(daddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carry out control transfer
|
// Carry out a control transfer
|
||||||
|
// true on success, false if there is on-going control trasnfer
|
||||||
bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
|
bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
|
||||||
|
|
||||||
// Set Configuration
|
// Set Configuration
|
||||||
|
Loading…
x
Reference in New Issue
Block a user