Skip to content

Commit d7b579a

Browse files
authored
Merge pull request hathach#1480 from Ryzee119/multihub_rebase
Host: Add support for multi-level usb hubs
2 parents eb7d359 + 2036a0b commit d7b579a

File tree

5 files changed

+53
-51
lines changed

5 files changed

+53
-51
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Host Stack
8282

8383
- Human Interface Device (HID): Keyboard, Mouse, Generic
8484
- Mass Storage Class (MSC)
85-
- Hub currently only supports 1 level of hub (due to my laziness)
85+
- Hub with multiple-level support
8686

8787
OS Abstraction layer
8888
====================

examples/host/cdc_msc_hid/src/tusb_config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
// Size of buffer to hold descriptors and other data used for enumeration
9090
#define CFG_TUH_ENUMERATION_BUFSIZE 256
9191

92-
#define CFG_TUH_HUB 1
92+
#define CFG_TUH_HUB 1 // number of supported hubs
9393
#define CFG_TUH_CDC 1
9494
#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
9595
#define CFG_TUH_MSC 1

src/host/hcd.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,11 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred
207207
.rhport = 0, // TODO correct rhport
208208
.event_id = HCD_EVENT_XFER_COMPLETE,
209209
.dev_addr = dev_addr,
210-
.xfer_complete =
211-
{
212-
.ep_addr = ep_addr,
213-
.result = result,
214-
.len = xferred_bytes
215-
}
216210
};
211+
event.xfer_complete.ep_addr = ep_addr;
212+
event.xfer_complete.result = result;
213+
event.xfer_complete.len = xferred_bytes;
214+
217215

218216
hcd_event_handler(&event, in_isr);
219217
}

src/host/hub.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
169169
};
170170

171171
TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
172-
TU_ASSERT( tuh_control_xfer(&xfer) );
172+
TU_VERIFY( tuh_control_xfer(&xfer) );
173173
return true;
174174
}
175175

@@ -332,7 +332,11 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
332332
{
333333
if ( tu_bit_test(p_hub->status_change, port) )
334334
{
335-
hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete, 0);
335+
if (hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete, 0) == false)
336+
{
337+
//Hub status control transfer failed, retry
338+
hub_edpt_status_xfer(dev_addr);
339+
}
336340
break;
337341
}
338342
}

src/host/usbh.c

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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
11041110
static 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-
14111420
static 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

Comments
 (0)