Просмотр исходного кода

Hub: Handle hub device status change interrupt

Ryzee119 3 лет назад
Родитель
Сommit
3c7b5dcaff
1 измененных файлов с 51 добавлено и 8 удалено
  1. 51 8
      src/host/hub.c

+ 51 - 8
src/host/hub.c

@@ -44,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];
@@ -314,6 +315,7 @@ static void config_port_power_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);
 
@@ -326,19 +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 ( tu_bit_test(p_hub->status_change, port) )
+    if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false)
     {
-      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);
+    }
+  }
+  else
+  {
+    // Hub bits 1 to n are hub port events
+    for (uint8_t port=1; port <= p_hub->port_count; port++)
+    {
+      if ( tu_bit_test(p_hub->status_change, port) )
       {
-        //Hub status control transfer failed, retry
-        hub_edpt_status_xfer(dev_addr);
+        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;
       }
-      break;
     }
   }
 
@@ -347,6 +361,35 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
   return true;
 }
 
+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, );