fix enumeration issue when plugging hub with multiple devices attached
This commit is contained in:
		@@ -189,7 +189,7 @@ void hub_close(uint8_t dev_addr)
 | 
			
		||||
  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);
 | 
			
		||||
  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
 | 
			
		||||
    // 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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_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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										121
									
								
								src/host/usbh.c
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								src/host/usbh.c
									
									
									
									
									
								
							@@ -543,7 +543,7 @@ void tuh_task(void)
 | 
			
		||||
        if ( event.connection.hub_addr != 0)
 | 
			
		||||
        {
 | 
			
		||||
          // 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
 | 
			
		||||
      break;
 | 
			
		||||
@@ -904,6 +904,10 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
//
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
// 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)
 | 
			
		||||
{
 | 
			
		||||
@@ -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
 | 
			
		||||
// 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_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_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_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);
 | 
			
		||||
@@ -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 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
 | 
			
		||||
 | 
			
		||||
// 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)
 | 
			
		||||
{
 | 
			
		||||
  (void) dev_addr; (void) request;
 | 
			
		||||
  (void) request;
 | 
			
		||||
  TU_ASSERT(XFER_RESULT_SUCCESS == result);
 | 
			
		||||
 | 
			
		||||
  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 )
 | 
			
		||||
  {
 | 
			
		||||
    // 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 :
 | 
			
		||||
@@ -1083,9 +1048,6 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques
 | 
			
		||||
 | 
			
		||||
  enum_request_set_addr();
 | 
			
		||||
 | 
			
		||||
  // done with hub, waiting for next data on status pipe
 | 
			
		||||
  (void) hub_status_pipe_queue( _dev0.hub_addr );
 | 
			
		||||
 | 
			
		||||
  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 CFG_TUH_HUB
 | 
			
		||||
    // TODO remove, waiting for next data on status pipe
 | 
			
		||||
    if (_dev0.hub_addr != 0) hub_status_pipe_queue(_dev0.hub_addr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // stop enumeration, maybe we could retry this
 | 
			
		||||
    enum_full_complete();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -1407,4 +1366,54 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
 | 
			
		||||
  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
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,8 @@ static inline bool tuh_ready(uint8_t 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);
 | 
			
		||||
 | 
			
		||||
// Set Configuration
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user