diff options
| author | Ha Thach <[email protected]> | 2022-11-04 15:42:50 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-11-04 15:42:50 +0700 |
| commit | b554c2ed836527296dd0b79169db04fc2f68cf5a (patch) | |
| tree | 34b25122fac701370b5883b7a878b6a7d92fd76f /src/host/hub.c | |
| parent | 35668fc523c7c972bf91f32dbb3b50ad8b4f3c74 (diff) | |
| parent | 28f49c088bb0c498d730d80943017172061cfd05 (diff) | |
Merge branch 'master' into rp2040-hcd-bulk
Diffstat (limited to 'src/host/hub.c')
| -rw-r--r-- | src/host/hub.c | 91 |
1 files changed, 78 insertions, 13 deletions
diff --git a/src/host/hub.c b/src/host/hub.c index 9e546f6f7..3da5358b2 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -28,6 +28,7 @@ #if (CFG_TUH_ENABLED && CFG_TUH_HUB) +#include "hcd.h" #include "usbh.h" #include "usbh_classdriver.h" #include "hub.h" @@ -43,6 +44,7 @@ typedef struct uint8_t status_change; // data from status change interrupt endpoint hub_port_status_response_t port_status; + hub_status_response_t hub_status; } hub_interface_t; CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB]; @@ -84,7 +86,7 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, { .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_OTHER, + .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, @@ -116,7 +118,7 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, { .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_OTHER, + .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, @@ -148,7 +150,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, { .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_OTHER, + .recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, @@ -169,7 +171,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, }; TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port); - TU_ASSERT( tuh_control_xfer(&xfer) ); + TU_VERIFY( tuh_control_xfer(&xfer) ); return true; } @@ -312,7 +314,8 @@ static void config_port_power_complete (tuh_xfer_t* xfer) // Connection Changes //--------------------------------------------------------------------+ -static void connection_get_status_complete (tuh_xfer_t* xfer); +static void hub_port_get_status_complete (tuh_xfer_t* xfer); +static void hub_get_status_complete (tuh_xfer_t* xfer); static void connection_clear_conn_change_complete (tuh_xfer_t* xfer); static void connection_port_reset_complete (tuh_xfer_t* xfer); @@ -325,15 +328,31 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 hub_interface_t* p_hub = get_itf(dev_addr); - TU_LOG2(" Port Status Change = 0x%02X\r\n", p_hub->status_change); + TU_LOG2(" Hub Status Change = 0x%02X\r\n", p_hub->status_change); - // Hub ignore bit0 in status change - for (uint8_t port=1; port <= p_hub->port_count; port++) + // Hub bit 0 is for the hub device events + if (tu_bit_test(p_hub->status_change, 0)) + { + if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false) + { + //Hub status control transfer failed, retry + hub_edpt_status_xfer(dev_addr); + } + } + else { - if ( tu_bit_test(p_hub->status_change, port) ) + // Hub bits 1 to n are hub port events + for (uint8_t port=1; port <= p_hub->port_count; port++) { - hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete, 0); - break; + if ( tu_bit_test(p_hub->status_change, port) ) + { + if (hub_port_get_status(dev_addr, port, &p_hub->port_status, hub_port_get_status_complete, 0) == false) + { + //Hub status control transfer failed, retry + hub_edpt_status_xfer(dev_addr); + } + break; + } } } @@ -342,7 +361,36 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 return true; } -static void connection_get_status_complete (tuh_xfer_t* xfer) +static void hub_clear_feature_complete_stub(tuh_xfer_t* xfer) +{ + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + hub_edpt_status_xfer(xfer->daddr); +} + +static void hub_get_status_complete (tuh_xfer_t* xfer) +{ + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + + uint8_t const daddr = xfer->daddr; + hub_interface_t* p_hub = get_itf(daddr); + uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + TU_ASSERT(port_num == 0 , ); + + TU_LOG2("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, p_hub->hub_status.change.value); + + if (p_hub->hub_status.change.local_power_source) + { + TU_LOG2("HUB Local Power Change, addr = %u\r\n", daddr); + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, hub_clear_feature_complete_stub, 0); + } + else if (p_hub->hub_status.change.over_current) + { + TU_LOG1("HUB Over Current, addr = %u\r\n", daddr); + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0); + } +} + +static void hub_port_get_status_complete (tuh_xfer_t* xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); @@ -360,7 +408,24 @@ static void connection_get_status_complete (tuh_xfer_t* xfer) hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0); }else { - // Other changes are: Enable, Suspend, Over Current, Reset, L1 state + // Clear other port status change interrupts. TODO Not currently handled - just cleared. + if (p_hub->port_status.change.port_enable) + { + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, hub_clear_feature_complete_stub, 0); + } + else if (p_hub->port_status.change.suspend) + { + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, hub_clear_feature_complete_stub, 0); + } + else if (p_hub->port_status.change.over_current) + { + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0); + } + else if (p_hub->port_status.change.reset) + { + hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, hub_clear_feature_complete_stub, 0); + } + // Other changes are: L1 state // TODO clear change // prepare for next hub status |
