@@ -1100,6 +1100,12 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i
11001100//
11011101//--------------------------------------------------------------------+
11021102
1103+ TU_ATTR_ALWAYS_INLINE
1104+ static inline bool is_hub_addr (uint8_t daddr )
1105+ {
1106+ return (CFG_TUH_HUB > 0 ) && (daddr > CFG_TUH_DEVICE_MAX );
1107+ }
1108+
11031109// a device unplugged from rhport:hub_addr:hub_port
11041110static void process_device_unplugged (uint8_t rhport , uint8_t hub_addr , uint8_t hub_port )
11051111{
@@ -1112,14 +1118,23 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
11121118
11131119 // TODO Hub multiple level
11141120 if (dev -> rhport == rhport &&
1115- (hub_addr == 0 || dev -> hub_addr == hub_addr ) && // hub_addr == 0 & hub_port == 0 means roothub
1116- (hub_port == 0 || dev -> hub_port == hub_port ) &&
1121+ (hub_addr == 0 || dev -> hub_addr == hub_addr ) && // hub_addr = 0 means roothub
1122+ (hub_port == 0 || dev -> hub_port == hub_port ) && // hub_port = 0 means all devices of downstream hub
11171123 dev -> connected )
11181124 {
11191125 TU_LOG2 (" Address = %u\r\n" , dev_addr );
11201126
1121- // Invoke callback before close driver
1122- if (tuh_umount_cb ) tuh_umount_cb (dev_addr );
1127+ if (is_hub_addr (dev_addr ))
1128+ {
1129+ TU_LOG (USBH_DBG_LVL , "HUB address = %u is unmounted\r\n" , dev_addr );
1130+ // If the device itself is a usb hub, unplug downstream devices.
1131+ // FIXME un-roll recursive calls to prevent potential stack overflow
1132+ process_device_unplugged (rhport , dev_addr , 0 );
1133+ }else
1134+ {
1135+ // Invoke callback before closing driver
1136+ if (tuh_umount_cb ) tuh_umount_cb (dev_addr );
1137+ }
11231138
11241139 // Close class driver
11251140 for (uint8_t drv_id = 0 ; drv_id < USBH_CLASS_DRIVER_COUNT ; drv_id ++ )
@@ -1402,12 +1417,6 @@ static bool enum_new_device(hcd_event_t* event)
14021417 return true;
14031418}
14041419
1405- TU_ATTR_ALWAYS_INLINE
1406- static inline bool is_hub_addr (uint8_t daddr )
1407- {
1408- return daddr > CFG_TUH_DEVICE_MAX ;
1409- }
1410-
14111420static uint8_t get_new_address (bool is_hub )
14121421{
14131422 uint8_t start ;
@@ -1520,40 +1529,31 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
15201529 uint16_t const drv_len = tu_desc_get_interface_total_len (desc_itf , assoc_itf_count , desc_end - p_desc );
15211530 TU_ASSERT (drv_len >= sizeof (tusb_desc_interface_t ));
15221531
1523- if (desc_itf -> bInterfaceClass == TUSB_CLASS_HUB && dev -> hub_addr != 0 )
1532+ // Find driver for this interface
1533+ uint8_t drv_id ;
1534+ for (drv_id = 0 ; drv_id < USBH_CLASS_DRIVER_COUNT ; drv_id ++ )
15241535 {
1525- // TODO Attach hub to Hub is not currently supported
1526- // skip this interface
1527- TU_LOG (USBH_DBG_LVL , "Only 1 level of HUB is supported\r\n" );
1528- }
1529- else
1530- {
1531- // Find driver for this interface
1532- uint8_t drv_id ;
1533- for (drv_id = 0 ; drv_id < USBH_CLASS_DRIVER_COUNT ; drv_id ++ )
1536+ usbh_class_driver_t const * driver = & usbh_class_drivers [drv_id ];
1537+
1538+ if ( driver -> open (dev -> rhport , dev_addr , desc_itf , drv_len ) )
15341539 {
1535- usbh_class_driver_t const * driver = & usbh_class_drivers [drv_id ];
1540+ // open successfully
1541+ TU_LOG2 (" %s opened\r\n" , driver -> name );
15361542
1537- if ( driver -> open (dev -> rhport , dev_addr , desc_itf , drv_len ) )
1543+ // bind (associated) interfaces to found driver
1544+ for (uint8_t i = 0 ; i < assoc_itf_count ; i ++ )
15381545 {
1539- // open successfully
1540- TU_LOG2 (" %s opened\r\n" , driver -> name );
1541-
1542- // bind (associated) interfaces to found driver
1543- for (uint8_t i = 0 ; i < assoc_itf_count ; i ++ )
1544- {
1545- uint8_t const itf_num = desc_itf -> bInterfaceNumber + i ;
1546+ uint8_t const itf_num = desc_itf -> bInterfaceNumber + i ;
15461547
1547- // Interface number must not be used already
1548- TU_ASSERT ( DRVID_INVALID == dev -> itf2drv [itf_num ] );
1549- dev -> itf2drv [itf_num ] = drv_id ;
1550- }
1548+ // Interface number must not be used already
1549+ TU_ASSERT ( DRVID_INVALID == dev -> itf2drv [itf_num ] );
1550+ dev -> itf2drv [itf_num ] = drv_id ;
1551+ }
15511552
1552- // bind all endpoints to found driver
1553- tu_edpt_bind_driver (dev -> ep2drv , desc_itf , drv_len , drv_id );
1553+ // bind all endpoints to found driver
1554+ tu_edpt_bind_driver (dev -> ep2drv , desc_itf , drv_len , drv_id );
15541555
1555- break ; // exit driver find loop
1556- }
1556+ break ; // exit driver find loop
15571557 }
15581558
15591559 if ( drv_id >= USBH_CLASS_DRIVER_COUNT )
@@ -1593,10 +1593,10 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
15931593 {
15941594 enum_full_complete ();
15951595
1596- # if CFG_TUH_HUB
1597- // skip device mount callback for hub
1598- if ( ! is_hub_addr ( dev_addr ) )
1599- #endif
1596+ if ( is_hub_addr ( dev_addr ))
1597+ {
1598+ TU_LOG ( USBH_DBG_LVL , "HUB address = %u is mounted\r\n" , dev_addr );
1599+ } else
16001600 {
16011601 // Invoke callback if available
16021602 if (tuh_mount_cb ) tuh_mount_cb (dev_addr );
0 commit comments