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

Merge pull request #1403 from hathach/host-edpt-xfer

Host edpt xfer
Ha Thach 4 лет назад
Родитель
Сommit
ae531a79f6

+ 286 - 74
examples/host/bare_api/src/main.c

@@ -35,11 +35,28 @@
 #include "bsp/board.h"
 #include "tusb.h"
 
+// English
+#define LANGUAGE_ID 0x0409
+#define BUF_COUNT   4
+
+
+tusb_desc_device_t desc_device;
+
+uint8_t buf_pool[BUF_COUNT][64];
+uint8_t buf_owner[BUF_COUNT] = { 0 }; // device address that owns buffer
+
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF PROTYPES
 //--------------------------------------------------------------------+
 void led_blinking_task(void);
 
+static void print_utf16(uint16_t *temp_buf, size_t buf_len);
+void print_device_descriptor(tuh_xfer_t* xfer);
+void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
+
+uint8_t* get_hid_buf(uint8_t daddr);
+void free_hid_buf(uint8_t daddr);
+
 /*------------- MAIN -------------*/
 int main(void)
 {
@@ -58,73 +75,39 @@ int main(void)
   return 0;
 }
 
-//--------------------------------------------------------------------+
-// TinyUSB Callbacks
-//--------------------------------------------------------------------+
-
-// English
-#define LANGUAGE_ID 0x0409
-
-//uint8_t usb_buf[256] TU_ATTR_ALIGNED(4);
-TU_ATTR_ALIGNED(4)
-tusb_desc_device_t desc_device;
+/*------------- TinyUSB Callbacks -------------*/
 
-static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
-    // TODO: Check for runover.
-    (void)utf8_len;
-    // Get the UTF-16 length out of the data itself.
+// Invoked when device is mounted (configured)
+void tuh_mount_cb (uint8_t daddr)
+{
+  printf("Device attached, address = %d\r\n", daddr);
 
-    for (size_t i = 0; i < utf16_len; i++) {
-        uint16_t chr = utf16[i];
-        if (chr < 0x80) {
-            *utf8++ = chr & 0xff;
-        } else if (chr < 0x800) {
-            *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
-        } else {
-            // TODO: Verify surrogate.
-            *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
-            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
-        }
-        // TODO: Handle UTF-16 code points that take two entries.
-    }
+  // Get Device Descriptor sync API
+  // TODO: invoking control trannsfer now has issue with mounting hub with multiple devices attached, fix later
+  tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
 }
 
-// Count how many bytes a utf-16-le encoded string will take in utf-8.
-static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
-    size_t total_bytes = 0;
-    for (size_t i = 0; i < len; i++) {
-        uint16_t chr = buf[i];
-        if (chr < 0x80) {
-            total_bytes += 1;
-        } else if (chr < 0x800) {
-            total_bytes += 2;
-        } else {
-            total_bytes += 3;
-        }
-        // TODO: Handle UTF-16 code points that take two entries.
-    }
-    return total_bytes;
+/// Invoked when device is unmounted (bus reset/unplugged)
+void tuh_umount_cb(uint8_t daddr)
+{
+  printf("Device removed, address = %d\r\n", daddr);
+  free_hid_buf(daddr);
 }
 
-static void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
-    size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
-    size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
-    _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
-    ((uint8_t*) temp_buf)[utf8_len] = '\0';
-}
+//--------------------------------------------------------------------+
+// Device Descriptor
+//--------------------------------------------------------------------+
 
-bool print_device_descriptor(uint8_t daddr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+void print_device_descriptor(tuh_xfer_t* xfer)
 {
-  (void) xfer;
-
-  if ( XFER_RESULT_SUCCESS != result )
+  if ( XFER_RESULT_SUCCESS != xfer->result )
   {
     printf("Failed to get device descriptor\r\n");
-    return false;
+    return;
   }
 
+  uint8_t const daddr = xfer->daddr;
+
   printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
   printf("Device Descriptor:\r\n");
   printf("  bLength             %u\r\n"     , desc_device.bLength);
@@ -138,51 +121,228 @@ bool print_device_descriptor(uint8_t daddr, tuh_control_xfer_t const * xfer, xfe
   printf("  idProduct           0x%04x\r\n" , desc_device.idProduct);
   printf("  bcdDevice           %04x\r\n"   , desc_device.bcdDevice);
 
-  uint32_t timeout_ms = 10;
+  // Get String descriptor using Sync API
   uint16_t temp_buf[128];
 
   printf("  iManufacturer       %u     "     , desc_device.iManufacturer);
-  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms) )
+  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
   {
-    utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf));
-    printf((const char*) temp_buf);
+    print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
   }
   printf("\r\n");
 
   printf("  iProduct            %u     "     , desc_device.iProduct);
-  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms))
+  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
   {
-    utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf));
-    printf((const char*) temp_buf);
+    print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
   }
   printf("\r\n");
 
   printf("  iSerialNumber       %u     "     , desc_device.iSerialNumber);
-  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms))
+  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
   {
-    utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf));
-    printf((const char*) temp_buf);
+    print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
   }
   printf("\r\n");
 
   printf("  bNumConfigurations  %u\r\n"     , desc_device.bNumConfigurations);
 
-  return true;
+  // Get configuration descriptor with sync API
+  if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(daddr, 0, temp_buf, sizeof(temp_buf)))
+  {
+    parse_config_descriptor(daddr, (tusb_desc_configuration_t*) temp_buf);
+  }
 }
 
-// Invoked when device is mounted (configured)
-void tuh_mount_cb (uint8_t daddr)
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+// count total length of an interface
+uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
+
+void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+
+// simple configuration parser to open and listen to HID Endpoint IN
+void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
 {
-  printf("Device attached, address = %d\r\n", daddr);
+  uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+  uint8_t const* p_desc   = tu_desc_next(desc_cfg);
 
-  // Get Device Descriptor using asynchronous API
-  tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
+  // parse each interfaces
+  while( p_desc < desc_end )
+  {
+    uint8_t assoc_itf_count = 1;
+
+    // Class will always starts with Interface Association (if any) and then Interface descriptor
+    if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
+    {
+      tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+      assoc_itf_count = desc_iad->bInterfaceCount;
+
+      p_desc = tu_desc_next(p_desc); // next to Interface
+    }
+
+    // must be interface from now
+    if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return;
+    tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+
+    uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, desc_end-p_desc);
+
+    // probably corrupted descriptor
+    if(drv_len < sizeof(tusb_desc_interface_t)) return;
+
+    // only open and listen to HID endpoint IN
+    if (desc_itf->bInterfaceClass == TUSB_CLASS_HID)
+    {
+      open_hid_interface(dev_addr, desc_itf, drv_len);
+    }
+
+    // next Interface or IAD descriptor
+    p_desc += drv_len;
+  }
 }
 
-/// Invoked when device is unmounted (bus reset/unplugged)
-void tuh_umount_cb(uint8_t daddr)
+uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
 {
-  printf("Device removed, address = %d\r\n", daddr);
+  uint8_t const* p_desc = (uint8_t const*) desc_itf;
+  uint16_t len = 0;
+
+  while (itf_count--)
+  {
+    // Next on interface desc
+    len += tu_desc_len(desc_itf);
+    p_desc = tu_desc_next(p_desc);
+
+    while (len < max_len)
+    {
+      // return on IAD regardless of itf count
+      if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
+
+      if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
+           ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
+      {
+        break;
+      }
+
+      len += tu_desc_len(p_desc);
+      p_desc = tu_desc_next(p_desc);
+    }
+  }
+
+  return len;
+}
+
+//--------------------------------------------------------------------+
+// HID Interface
+//--------------------------------------------------------------------+
+
+void hid_report_received(tuh_xfer_t* xfer);
+
+void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
+{
+  // len = interface + hid + n*endpoints
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+
+  // corrupted descriptor
+  if (max_len < drv_len) return;
+
+  uint8_t const *p_desc = (uint8_t const *) desc_itf;
+
+  // HID descriptor
+  p_desc = tu_desc_next(p_desc);
+  tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
+  if(HID_DESC_TYPE_HID != desc_hid->bDescriptorType) return;
+
+  // Endpoint descriptor
+  p_desc = tu_desc_next(p_desc);
+  tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+
+  for(int i = 0; i < desc_itf->bNumEndpoints; i++)
+  {
+    if (TUSB_DESC_ENDPOINT != desc_ep->bDescriptorType) return;
+
+    if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
+    {
+      // skip if failed to open endpoint
+      if ( ! tuh_edpt_open(daddr, desc_ep) ) return;
+
+      uint8_t* buf = get_hid_buf(daddr);
+      if (!buf) return; // out of memory
+
+      tuh_xfer_t xfer =
+      {
+        .daddr       = daddr,
+        .ep_addr     = desc_ep->bEndpointAddress,
+        .buflen      = 64,
+        .buffer      = buf,
+        .complete_cb = hid_report_received,
+        .user_data   = (uintptr_t) buf, // since buffer is not available in callback, use user data to store the buffer
+      };
+
+      // submit transfer for this EP
+      tuh_edpt_xfer(&xfer);
+
+      printf("Listen to [dev %u: ep %02x]\r\n", daddr, desc_ep->bEndpointAddress);
+    }
+
+    p_desc = tu_desc_next(p_desc);
+    desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+  }
+}
+
+void hid_report_received(tuh_xfer_t* xfer)
+{
+  // Note: not all field in xfer is available for use (i.e filled by tinyusb stack) in callback to save sram
+  // For instance, xfer->buffer is NULL. We have used user_data to store buffer when submitted callback
+  uint8_t* buf = (uint8_t*) xfer->user_data;
+
+  if (xfer->result == XFER_RESULT_SUCCESS)
+  {
+    printf("[dev %u: ep %02x] HID Report:", xfer->daddr, xfer->ep_addr);
+    for(uint32_t i=0; i<xfer->actual_len; i++)
+    {
+      if (i%16 == 0) printf("\r\n  ");
+      printf("%02X ", buf[i]);
+    }
+    printf("\r\n");
+  }
+
+  // continue to submit transfer, with updated buffer
+  // other field remain the same
+  xfer->buflen = 64;
+  xfer->buffer = buf;
+
+  tuh_edpt_xfer(xfer);
+}
+
+//--------------------------------------------------------------------+
+// Buffer helper
+//--------------------------------------------------------------------+
+
+// get an buffer from pool
+uint8_t* get_hid_buf(uint8_t daddr)
+{
+  for(size_t i=0; i<BUF_COUNT; i++)
+  {
+    if (buf_owner[i] == 0)
+    {
+      buf_owner[i] = daddr;
+      return buf_pool[i];
+    }
+  }
+
+  // out of memory, increase BUF_COUNT
+  return NULL;
+}
+
+// free all buffer owned by device
+void free_hid_buf(uint8_t daddr)
+{
+  for(size_t i=0; i<BUF_COUNT; i++)
+  {
+    if (buf_owner[i] == daddr) buf_owner[i] = 0;
+  }
 }
 
 //--------------------------------------------------------------------+
@@ -202,3 +362,55 @@ void led_blinking_task(void)
   board_led_write(led_state);
   led_state = 1 - led_state; // toggle
 }
+
+//--------------------------------------------------------------------+
+// String Descriptor Helper
+//--------------------------------------------------------------------+
+
+static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
+    // TODO: Check for runover.
+    (void)utf8_len;
+    // Get the UTF-16 length out of the data itself.
+
+    for (size_t i = 0; i < utf16_len; i++) {
+        uint16_t chr = utf16[i];
+        if (chr < 0x80) {
+            *utf8++ = chr & 0xff;
+        } else if (chr < 0x800) {
+            *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        } else {
+            // TODO: Verify surrogate.
+            *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
+            *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
+        }
+        // TODO: Handle UTF-16 code points that take two entries.
+    }
+}
+
+// Count how many bytes a utf-16-le encoded string will take in utf-8.
+static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
+    size_t total_bytes = 0;
+    for (size_t i = 0; i < len; i++) {
+        uint16_t chr = buf[i];
+        if (chr < 0x80) {
+            total_bytes += 1;
+        } else if (chr < 0x800) {
+            total_bytes += 2;
+        } else {
+            total_bytes += 3;
+        }
+        // TODO: Handle UTF-16 code points that take two entries.
+    }
+    return total_bytes;
+}
+
+static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
+    size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
+    size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
+    _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
+    ((uint8_t*) temp_buf)[utf8_len] = '\0';
+
+    printf((char*)temp_buf);
+}

+ 4 - 4
examples/host/bare_api/src/tusb_config.h

@@ -81,11 +81,11 @@
 // 1 hub typically has 4 ports
 #define CFG_TUH_DEVICE_MAX          (CFG_TUH_HUB ? 4 : 1)
 
-#define CFG_TUH_ENDPOINT_MAX       8
+// Max endpoint per device
+#define CFG_TUH_ENDPOINT_MAX        8
 
-//------------- HID -------------//
-
-#define CFG_TUH_HID_EP_BUFSIZE      64
+// Enable tuh_edpt_xfer() API
+#define CFG_TUH_API_EDPT_XFER       1
 
 #ifdef __cplusplus
  }

+ 21 - 17
src/class/cdc/cdc_host.c

@@ -120,32 +120,35 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is
   return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length);
 }
 
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_xfer_cb_t complete_cb)
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
 {
   cdch_data_t const * p_cdc = get_itf(dev_addr);
 
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
-      .wValue   = (rts ? 2 : 0) | (dtr ? 1 : 0),
-      .wIndex   = p_cdc->itf_num,
-      .wLength  = 0
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
     },
+    .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
+    .wValue   = (rts ? 2 : 0) | (dtr ? 1 : 0),
+    .wIndex   = p_cdc->itf_num,
+    .wLength  = 0
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = NULL,
     .complete_cb = complete_cb,
-    .user_arg    = 0
+    .user_data    = 0
   };
 
-  return tuh_control_xfer(dev_addr, &xfer);
+  return tuh_control_xfer(&xfer);
 }
 
 //--------------------------------------------------------------------+
@@ -158,6 +161,7 @@ void cdch_init(void)
 
 bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
 {
+  (void) rhport;
   (void) max_len;
 
   // Only support ACM subclass
@@ -193,7 +197,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
     // notification endpoint
     tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
 
-    TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
+    TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
     p_cdc->ep_notif = desc_ep->bEndpointAddress;
 
     drv_len += tu_desc_len(p_desc);
@@ -214,7 +218,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
       tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
       TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
 
-      TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
+      TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
 
       if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
       {

+ 3 - 3
src/class/cdc/cdc_host.h

@@ -42,14 +42,14 @@
  * \defgroup   CDC_Serial_Host Host
  * @{ */
 
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_xfer_cb_t complete_cb);
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb);
 
-static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_xfer_cb_t complete_cb)
+static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
 {
   return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb);
 }
 
-static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_control_xfer_cb_t complete_cb)
+static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
 {
   return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
 }

+ 1 - 1
src/class/hid/hid.h

@@ -43,7 +43,7 @@
 /** \defgroup ClassDriver_HID_Common Common Definitions
  *  @{ */
 
- /// USB HID Descriptor
+/// USB HID Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength;         /**< Numeric expression that is the total size of the HID descriptor */

+ 168 - 149
src/class/hid/hid_host.c

@@ -103,70 +103,80 @@ uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
   return hid_itf->protocol_mode;
 }
 
-static bool set_protocol_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
+static void set_protocol_complete(tuh_xfer_t* xfer)
 {
-  uint8_t const itf_num     = (uint8_t) xfer->request.wIndex;
-  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
-  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  uint8_t const itf_num     = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+  uint8_t const daddr       = xfer->daddr;
+  uint8_t const instance    = get_instance_id_by_itfnum(daddr, itf_num);
+  hidh_interface_t* hid_itf = get_instance(daddr, instance);
 
-  if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) xfer->request.wValue;
+  if (XFER_RESULT_SUCCESS == xfer->result)
+  {
+    hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue);
+  }
 
   if (tuh_hid_set_protocol_complete_cb)
   {
-    tuh_hid_set_protocol_complete_cb(dev_addr, instance, hid_itf->protocol_mode);
+    tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode);
   }
-
-  return true;
 }
 
-bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
-{
-  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
-  TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
 
+static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
   TU_LOG2("HID Set Protocol = %d\r\n", protocol);
 
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
-      .wValue   = protocol,
-      .wIndex   = hid_itf->itf_num,
-      .wLength  = 0
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
     },
+    .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
+    .wValue   = protocol,
+    .wIndex   = itf_num,
+    .wLength  = 0
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = NULL,
-    .complete_cb = set_protocol_complete,
-    .user_arg    = 0
+    .complete_cb = complete_cb,
+    .user_data   = user_data
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) );
+  TU_ASSERT( tuh_control_xfer(&xfer) );
   return true;
 }
 
-static bool set_report_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
+bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
+{
+  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
+
+  return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0);
+}
+
+static void set_report_complete(tuh_xfer_t* xfer)
 {
   TU_LOG2("HID Set Report complete\r\n");
 
   if (tuh_hid_set_report_complete_cb)
   {
-    uint8_t const itf_num     = (uint8_t) xfer->request.wIndex;
-    uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
+    uint8_t const itf_num     = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+    uint8_t const instance    = get_instance_id_by_itfnum(xfer->daddr, itf_num);
 
-    uint8_t const report_type = tu_u16_high(xfer->request.wValue);
-    uint8_t const report_id   = tu_u16_low(xfer->request.wValue);
+    uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
+    uint8_t const report_id   = tu_u16_low(xfer->setup->wValue);
 
-    tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? xfer->request.wLength : 0);
+    tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type,
+                                   (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
   }
-
-  return true;
 }
 
 bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len)
@@ -174,28 +184,64 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
   hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
   TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
 
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HID_REQ_CONTROL_SET_REPORT,
-      .wValue   = tu_u16(report_type, report_id),
-      .wIndex   = hid_itf->itf_num,
-      .wLength  = len
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
     },
+    .bRequest = HID_REQ_CONTROL_SET_REPORT,
+    .wValue   = tu_u16(report_type, report_id),
+    .wIndex   = hid_itf->itf_num,
+    .wLength  = len
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = report,
     .complete_cb = set_report_complete,
-    .user_arg    = 0
+    .user_data   = 0
+  };
+
+  TU_ASSERT( tuh_control_xfer(&xfer) );
+  return true;
+}
+
+static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+  // SET IDLE request, device can stall if not support this request
+  TU_LOG2("HID Set Idle \r\n");
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = HID_REQ_CONTROL_SET_IDLE,
+    .wValue   = idle_rate,
+    .wIndex   = itf_num,
+    .wLength  = 0
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) );
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
+    .buffer      = NULL,
+    .complete_cb = complete_cb,
+    .user_data   = user_data
+  };
+
+  TU_ASSERT( tuh_control_xfer(&xfer) );
+
   return true;
 }
 
@@ -210,7 +256,13 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
   // claim endpoint
   TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) );
 
-  return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size);
+  if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) )
+  {
+    usbh_edpt_claim(dev_addr, hid_itf->ep_in);
+    return false;
+  }
+
+  return true;
 }
 
 //bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
@@ -270,14 +322,9 @@ void hidh_close(uint8_t dev_addr)
 // Enumeration
 //--------------------------------------------------------------------+
 
-static bool config_set_protocol             (uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result);
-static bool config_get_report_desc          (uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result);
-static bool config_get_report_desc_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result);
-
-static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
-
 bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
 {
+  (void) rhport;
   (void) max_len;
 
   TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
@@ -309,7 +356,7 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
   for(int i = 0; i < desc_itf->bNumEndpoints; i++)
   {
     TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
-    TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
+    TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
 
     if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
     {
@@ -341,121 +388,93 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
   return true;
 }
 
-bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
-{
-  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
-  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
-
-  // Idle rate = 0 mean only report when there is changes
-  uint16_t const idle_rate = 0;
-
-  // SET IDLE request, device can stall if not support this request
-  TU_LOG2("HID Set Idle \r\n");
-  tuh_control_xfer_t const xfer =
-  {
-    .request =
-    {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HID_REQ_CONTROL_SET_IDLE,
-      .wValue   = idle_rate,
-      .wIndex   = itf_num,
-      .wLength  = 0
-    },
-
-    .buffer      = NULL,
-    .complete_cb = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc,
-    .user_arg    = 0
-  };
+//--------------------------------------------------------------------+
+// Set Configure
+//--------------------------------------------------------------------+
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) );
+enum {
+  CONFG_SET_IDLE,
+  CONFIG_SET_PROTOCOL,
+  CONFIG_GET_REPORT_DESC,
+  CONFIG_COMPLETE
+};
 
-  return true;
-}
+static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
+static void process_set_config(tuh_xfer_t* xfer);
 
-// Force device to work in BOOT protocol
-static bool config_set_protocol(uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
+bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
 {
-  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
-  (void) result;
-
-  uint8_t const itf_num     = (uint8_t) xfer->request.wIndex;
-  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
-  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  tusb_control_request_t request;
+  request.wIndex = tu_htole16((uint16_t) itf_num);
 
-  TU_LOG2("HID Set Protocol to Boot Mode\r\n");
-  hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
-  tuh_control_xfer_t const new_xfer =
-  {
-    .request =
-    {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
-      .wValue   = HID_PROTOCOL_BOOT,
-      .wIndex   = hid_itf->itf_num,
-      .wLength  = 0
-    },
+  tuh_xfer_t xfer;
+  xfer.daddr     = dev_addr;
+  xfer.result    = XFER_RESULT_SUCCESS;
+  xfer.setup     = &request;
+  xfer.user_data = CONFG_SET_IDLE;
 
-    .buffer      = NULL,
-    .complete_cb = config_get_report_desc,
-    .user_arg    = 0
-  };
+  // fake request to kick-off the set config process
+  process_set_config(&xfer);
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &new_xfer) );
   return true;
 }
 
-static bool config_get_report_desc(uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
+static void process_set_config(tuh_xfer_t* xfer)
 {
-  // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
-  // Trigger assert if result is not successful with set protocol
-  if ( xfer->request.bRequest != HID_REQ_CONTROL_SET_IDLE )
+  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
+  if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE )
   {
-    TU_ASSERT(result == XFER_RESULT_SUCCESS);
+    TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
   }
 
-  uint8_t const itf_num     = (uint8_t) xfer->request.wIndex;
-  uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
-  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
+  uintptr_t const state = xfer->user_data;
+  uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+  uint8_t const daddr   = xfer->daddr;
 
-  // Get Report Descriptor if possible
-  // using usbh enumeration buffer since report descriptor can be very long
-  if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
-  {
-    TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
+  uint8_t const instance    = get_instance_id_by_itfnum(daddr, itf_num);
+  hidh_interface_t* hid_itf = get_instance(daddr, instance);
 
-    // Driver is mounted without report descriptor
-    config_driver_mount_complete(dev_addr, instance, NULL, 0);
-  }else
+  switch(state)
   {
-    TU_ASSERT(tuh_descriptor_get_hid_report(dev_addr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, config_get_report_desc_complete, 0));
-  }
+    case CONFG_SET_IDLE:
+    {
+      // Idle rate = 0 mean only report when there is changes
+      const uint16_t idle_rate = 0;
+      const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC;
+      _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state);
+    }
+    break;
 
-  return true;
-}
+    case CONFIG_SET_PROTOCOL:
+      _hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC);
+    break;
 
-static bool config_get_report_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
-{
-  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+    case CONFIG_GET_REPORT_DESC:
+      // Get Report Descriptor if possible
+      // using usbh enumeration buffer since report descriptor can be very long
+      if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
+      {
+        TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
 
-  uint8_t const itf_num      = (uint8_t) xfer->request.wIndex;
-  uint8_t const instance     = get_instance_id_by_itfnum(dev_addr, itf_num);
+        // Driver is mounted without report descriptor
+        config_driver_mount_complete(daddr, instance, NULL, 0);
+      }else
+      {
+        tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE);
+      }
+      break;
 
-  uint8_t const* desc_report = usbh_get_enum_buf();
-  uint16_t const desc_len    = xfer->request.wLength;
+    case CONFIG_COMPLETE:
+    {
+      uint8_t const* desc_report = usbh_get_enum_buf();
+      uint16_t const desc_len    = tu_le16toh(xfer->setup->wLength);
 
-  config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
+      config_driver_mount_complete(daddr, instance, desc_report, desc_len);
+    }
+    break;
 
-  return true;
+    default: break;
+  }
 }
 
 static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)

+ 26 - 25
src/class/msc/msc_host.c

@@ -358,13 +358,14 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
 // MSC Enumeration
 //--------------------------------------------------------------------+
 
-static bool config_get_maxlun_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result);
+static void config_get_maxlun_complete (tuh_xfer_t* xfer);
 static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 
 bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
 {
+  (void) rhport;
   TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
              MSC_PROTOCOL_BOT  == desc_itf->bInterfaceProtocol);
 
@@ -378,7 +379,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
   for(uint32_t i=0; i<2; i++)
   {
     TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
-    TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+    TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc));
 
     if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
     {
@@ -405,47 +406,47 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
 
   //------------- Get Max Lun -------------//
   TU_LOG2("MSC Get Max Lun\r\n");
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_INTERFACE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_IN
-      },
-      .bRequest = MSC_REQ_GET_MAX_LUN,
-      .wValue   = 0,
-      .wIndex   = itf_num,
-      .wLength  = 1
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
     },
+    .bRequest = MSC_REQ_GET_MAX_LUN,
+    .wValue   = 0,
+    .wIndex   = itf_num,
+    .wLength  = 1
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = &p_msc->max_lun,
     .complete_cb = config_get_maxlun_complete,
-    .user_arg    = 0
+    .user_data    = 0
   };
-  TU_ASSERT(tuh_control_xfer(dev_addr, &xfer));
+  TU_ASSERT(tuh_control_xfer(&xfer));
 
   return true;
 }
 
-static bool config_get_maxlun_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer,  xfer_result_t result)
+static void config_get_maxlun_complete (tuh_xfer_t* xfer)
 {
-  (void) xfer;
-
-  msch_interface_t* p_msc = get_itf(dev_addr);
+  uint8_t const daddr = xfer->daddr;
+  msch_interface_t* p_msc = get_itf(daddr);
 
   // STALL means zero
-  p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? _msch_buffer[0] : 0;
+  p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0;
   p_msc->max_lun++; // MAX LUN is minus 1 by specs
 
   // TODO multiple LUN support
   TU_LOG2("SCSI Test Unit Ready\r\n");
   uint8_t const lun = 0;
-  tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete);
-
-  return true;
+  tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete);
 }
 
 static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
@@ -483,7 +484,7 @@ static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw
   // Capacity response field: Block size and Last LBA are both Big-Endian
   scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer);
   p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
-  p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
+  p_msc->capacity[cbw->lun].block_size  = tu_ntohl(resp->block_size);
 
   // Mark enumeration is complete
   p_msc->mounted = true;

+ 116 - 105
src/host/hub.c

@@ -78,89 +78,98 @@ static char const* const _hub_feature_str[] =
 // HUB
 //--------------------------------------------------------------------+
 bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
-                            tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
+                            tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_OTHER,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HUB_REQUEST_CLEAR_FEATURE,
-      .wValue   = feature,
-      .wIndex   = hub_port,
-      .wLength  = 0
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
     },
+    .bRequest = HUB_REQUEST_CLEAR_FEATURE,
+    .wValue   = feature,
+    .wIndex   = hub_port,
+    .wLength  = 0
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = hub_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = NULL,
     .complete_cb = complete_cb,
-    .user_arg    = user_arg
+    .user_data   = user_data
   };
 
   TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
-  TU_ASSERT( tuh_control_xfer(hub_addr, &xfer) );
+  TU_ASSERT( tuh_control_xfer(&xfer) );
   return true;
 }
 
 bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
-                          tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
+                          tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_OTHER,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_OUT
-      },
-      .bRequest = HUB_REQUEST_SET_FEATURE,
-      .wValue   = feature,
-      .wIndex   = hub_port,
-      .wLength  = 0
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
     },
+    .bRequest = HUB_REQUEST_SET_FEATURE,
+    .wValue   = feature,
+    .wIndex   = hub_port,
+    .wLength  = 0
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = hub_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = NULL,
     .complete_cb = complete_cb,
-    .user_arg    = user_arg
+    .user_data   = user_data
   };
 
   TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
-  TU_ASSERT( tuh_control_xfer(hub_addr, &xfer) );
+  TU_ASSERT( tuh_control_xfer(&xfer) );
   return true;
 }
 
 bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
-                         tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
+                         tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_OTHER,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_IN
-      },
-      .bRequest = HUB_REQUEST_GET_STATUS,
-      .wValue   = 0,
-      .wIndex   = hub_port,
-      .wLength  = 4
+      .recipient = TUSB_REQ_RCPT_OTHER,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
     },
+    .bRequest = HUB_REQUEST_GET_STATUS,
+    .wValue   = 0,
+    .wIndex   = hub_port,
+    .wLength  = 4
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = hub_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = resp,
     .complete_cb = complete_cb,
-    .user_arg    = user_arg
+    .user_data   = user_data
   };
 
   TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
-  TU_ASSERT( tuh_control_xfer( hub_addr, &xfer) );
+  TU_ASSERT( tuh_control_xfer(&xfer) );
   return true;
 }
 
@@ -174,6 +183,8 @@ void hub_init(void)
 
 bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
 {
+  (void) rhport;
+
   TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
             0              == itf_desc->bInterfaceSubClass);
 
@@ -190,7 +201,7 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf
   TU_ASSERT(TUSB_DESC_ENDPOINT  == desc_ep->bDescriptorType &&
             TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
   
-  TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
+  TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
 
   hub_interface_t* p_hub = get_itf(dev_addr);
 
@@ -219,8 +230,8 @@ bool hub_edpt_status_xfer(uint8_t dev_addr)
 // Set Configure
 //--------------------------------------------------------------------+
 
-static bool config_set_port_power (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
-static bool config_port_power_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static void config_set_port_power (tuh_xfer_t* xfer);
+static void config_port_power_complete (tuh_xfer_t* xfer);
 
 bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
 {
@@ -228,38 +239,41 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
   TU_ASSERT(itf_num == p_hub->itf_num);
 
   // Get Hub Descriptor
-  tuh_control_xfer_t const xfer =
+  tusb_control_request_t const request =
   {
-    .request =
+    .bmRequestType_bit =
     {
-      .bmRequestType_bit =
-      {
-        .recipient = TUSB_REQ_RCPT_DEVICE,
-        .type      = TUSB_REQ_TYPE_CLASS,
-        .direction = TUSB_DIR_IN
-      },
-      .bRequest = HUB_REQUEST_GET_DESCRIPTOR,
-      .wValue   = 0,
-      .wIndex   = 0,
-      .wLength  = sizeof(descriptor_hub_desc_t)
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_IN
     },
+    .bRequest = HUB_REQUEST_GET_DESCRIPTOR,
+    .wValue   = 0,
+    .wIndex   = 0,
+    .wLength  = sizeof(descriptor_hub_desc_t)
+  };
 
+  tuh_xfer_t xfer =
+  {
+    .daddr       = dev_addr,
+    .ep_addr     = 0,
+    .setup       = &request,
     .buffer      = _hub_buffer,
     .complete_cb = config_set_port_power,
-    .user_arg    = 0
+    .user_data    = 0
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) );
+  TU_ASSERT( tuh_control_xfer(&xfer) );
 
   return true;
 }
 
-static bool config_set_port_power (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+static void config_set_port_power (tuh_xfer_t* xfer)
 {
-  (void) xfer;
-  TU_ASSERT(XFER_RESULT_SUCCESS == result);
+  TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
 
-  hub_interface_t* p_hub = get_itf(dev_addr);
+  uint8_t const daddr = xfer->daddr;
+  hub_interface_t* p_hub = get_itf(daddr);
 
   // only use number of ports in hub descriptor
   descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
@@ -269,38 +283,38 @@ static bool config_set_port_power (uint8_t dev_addr, tuh_control_xfer_t const *
 
   // Set Port Power to be able to detect connection, starting with port 1
   uint8_t const hub_port = 1;
-  return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
+  hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
 }
 
-static bool config_port_power_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+static void config_port_power_complete (tuh_xfer_t* xfer)
 {
-  TU_ASSERT(XFER_RESULT_SUCCESS == result);
-   hub_interface_t* p_hub = get_itf(dev_addr);
+  TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
+
+  uint8_t const daddr = xfer->daddr;
+  hub_interface_t* p_hub = get_itf(daddr);
 
-  if (xfer->request.wIndex == p_hub->port_count)
+  if (xfer->setup->wIndex == p_hub->port_count)
   {
     // All ports are power -> queue notification status endpoint and
     // complete the SET CONFIGURATION
-    TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1) );
+    TU_ASSERT( usbh_edpt_xfer(daddr, p_hub->ep_in, &p_hub->status_change, 1), );
 
-    usbh_driver_set_config_complete(dev_addr, p_hub->itf_num);
+    usbh_driver_set_config_complete(daddr, p_hub->itf_num);
   }else
   {
     // power next port
-    uint8_t const hub_port = (uint8_t) (xfer->request.wIndex + 1);
-    return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
+    uint8_t const hub_port = (uint8_t) (xfer->setup->wIndex + 1);
+    hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
   }
-
-  return true;
 }
 
 //--------------------------------------------------------------------+
 // Connection Changes
 //--------------------------------------------------------------------+
 
-static bool connection_get_status_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
-static bool connection_port_reset_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static void connection_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);
 
 // callback as response of interrupt endpoint polling
 bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -328,12 +342,13 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
   return true;
 }
 
-static bool connection_get_status_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+static void connection_get_status_complete (tuh_xfer_t* xfer)
 {
-  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
 
-  hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
+  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);
 
   // Connection change
   if (p_hub->port_status.change.connection)
@@ -342,7 +357,7 @@ static bool connection_get_status_complete (uint8_t dev_addr, tuh_control_xfer_t
     //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
 
     // Acknowledge Port Connection Change
-    hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
+    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
@@ -350,65 +365,61 @@ static bool connection_get_status_complete (uint8_t dev_addr, tuh_control_xfer_t
 
     // prepare for next hub status
     // TODO continue with status_change, or maybe we can do it again with status
-    hub_edpt_status_xfer(dev_addr);
+    hub_edpt_status_xfer(daddr);
   }
-
-  return true;
 }
 
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+static void connection_clear_conn_change_complete (tuh_xfer_t* xfer)
 {
-  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
 
-  hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
+  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);
 
   if ( p_hub->port_status.status.connection )
   {
     // Reset port if attach event
-    hub_port_reset(dev_addr, port_num, connection_port_reset_complete, 0);
+    hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
   }else
   {
     // submit detach event
     hcd_event_t event =
     {
-      .rhport     = usbh_get_rhport(dev_addr),
+      .rhport     = usbh_get_rhport(daddr),
       .event_id   = HCD_EVENT_DEVICE_REMOVE,
       .connection =
        {
-         .hub_addr = dev_addr,
+         .hub_addr = daddr,
          .hub_port = port_num
        }
     };
 
     hcd_event_handler(&event, false);
   }
-
-  return true;
 }
 
-static bool connection_port_reset_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
+static void connection_port_reset_complete (tuh_xfer_t* xfer)
 {
-  TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
 
-  // hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
+  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);
 
   // submit attach event
   hcd_event_t event =
   {
-    .rhport     = usbh_get_rhport(dev_addr),
+    .rhport     = usbh_get_rhport(daddr),
     .event_id   = HCD_EVENT_DEVICE_ATTACH,
     .connection =
     {
-      .hub_addr = dev_addr,
+      .hub_addr = daddr,
       .hub_port = port_num
     }
   };
 
   hcd_event_handler(&event, false);
-
-  return true;
 }
 
 #endif

+ 7 - 7
src/host/hub.h

@@ -173,31 +173,31 @@ TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"
 
 // Clear feature
 bool hub_port_clear_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
-                             tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                             tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Set feature
 bool hub_port_set_feature   (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
-                             tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                             tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get port status
 bool hub_port_get_status    (uint8_t hub_addr, uint8_t hub_port, void* resp,
-                             tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                             tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get status from Interrupt endpoint
 bool hub_edpt_status_xfer(uint8_t dev_addr);
 
 // Reset a port
 static inline bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port,
-                                  tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
+                                  tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {
-  return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_arg);
+  return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
 }
 
 // Clear Reset Change
 static inline bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port,
-                                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
+                                               tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {
-  return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_arg);
+  return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
 }
 
 

Разница между файлами не показана из-за своего большого размера
+ 532 - 436
src/host/usbh.c


+ 58 - 34
src/host/usbh.h

@@ -39,17 +39,34 @@
 //--------------------------------------------------------------------+
 
 // forward declaration
-struct tuh_control_xfer_s;
-typedef struct tuh_control_xfer_s tuh_control_xfer_t;
+struct tuh_xfer_s;
+typedef struct tuh_xfer_s tuh_xfer_t;
 
-typedef bool (*tuh_control_xfer_cb_t)(uint8_t daddr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
 
-struct tuh_control_xfer_s
+// Note1: layout and order of this will be changed in near future
+// it is advised to initialize it using member name
+// Note2: not all field is available/meaningful in callback, some info is not saved by
+// usbh to save SRAM
+struct tuh_xfer_s
 {
-  tusb_control_request_t request TU_ATTR_ALIGNED(4);
-  uint8_t* buffer;
-  tuh_control_xfer_cb_t complete_cb;
-  uintptr_t user_arg;
+  uint8_t daddr;
+  uint8_t ep_addr;
+
+  xfer_result_t result;
+  uint32_t actual_len;      // excluding setup packet
+
+  union
+  {
+    tusb_control_request_t const* setup; // setup packet pointer if control transfer
+    uint32_t buflen;        // expected length if not control transfer (not available in callback)
+  };
+
+  uint8_t* buffer;           // not available in callback if not control transfer
+  tuh_xfer_cb_t complete_cb;
+  uintptr_t user_data;
+
+  // uint32_t timeout_ms;    // place holder, not supported yet
 };
 
 //--------------------------------------------------------------------+
@@ -104,21 +121,28 @@ static inline bool tuh_ready(uint8_t daddr)
   return tuh_mounted(daddr) && !tuh_suspended(daddr);
 }
 
-// Carry out a control transfer
-// true on success, false if there is on-going control transfer or incorrect parameters
-// Blocking if complete callback is NULL, in this case 'user_arg' must contain xfer_result_t variable
-bool tuh_control_xfer (uint8_t daddr, tuh_control_xfer_t const* xfer);
+//--------------------------------------------------------------------+
+// Transfer API
+//--------------------------------------------------------------------+
 
-// Sync (blocking) version of tuh_control_xfer()
-// return transfer result
-uint8_t tuh_control_xfer_sync(uint8_t daddr, tuh_control_xfer_t const* xfer, uint32_t timeout_ms);
+// Submit a control transfer
+//  - async: complete callback invoked when finished.
+//  - sync : blocking if complete callback is NULL.
+bool tuh_control_xfer(tuh_xfer_t* xfer);
+
+// Submit a bulk/interrupt transfer
+//  - async: complete callback invoked when finished.
+//  - sync : blocking if complete callback is NULL.
+bool tuh_edpt_xfer(tuh_xfer_t* xfer);
+
+// Open an non-control endpoint
+bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
 
 // Set Configuration (control transfer)
 // config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
 // true on success, false if there is on-going control transfer or incorrect parameters
-// Blocking if complete callback is NULL, in this case 'user_arg' must contain xfer_result_t variable
 bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
-                           tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                           tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 //--------------------------------------------------------------------+
 // Descriptors Asynchronous (non-blocking)
@@ -127,43 +151,43 @@ bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
 // Get an descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len,
-                        tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                        tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get device descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
-                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                               tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get configuration descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len,
-                                      tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                                      tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get HID report descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
-                                   tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                                   tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get string descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
-// Blocking if complete callback is NULL, in this case 'user_arg' must contain xfer_result_t variable
+// Blocking if complete callback is NULL, in this case 'user_data' must contain xfer_result_t variable
 bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
-                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                               tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get manufacturer string descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
-                                            tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                                            tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get product string descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
-                                       tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                                       tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 // Get serial string descriptor (control transfer)
 // true on success, false if there is on-going control transfer or incorrect parameters
 bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
-                                      tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
+                                      tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
 //--------------------------------------------------------------------+
 // Descriptors Synchronous (blocking)
@@ -171,35 +195,35 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void*
 
 // Sync (blocking) version of tuh_descriptor_get()
 // return transfer result
-uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_device()
 // return transfer result
-uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_configuration()
 // return transfer result
-uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_hid_report()
 // return transfer result
-uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_string()
 // return transfer result
-uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
 // return transfer result
-uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_product_string()
 // return transfer result
-uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
 
 // Sync (blocking) version of tuh_descriptor_get_serial_string()
 // return transfer result
-uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms);
+uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
 
 #ifdef __cplusplus
  }

+ 9 - 4
src/host/usbh_classdriver.h

@@ -63,11 +63,16 @@ void usbh_int_set(bool enabled);
 // USBH Endpoint API
 //--------------------------------------------------------------------+
 
-// Open an endpoint
-bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
+// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER
+bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
+                                  tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+TU_ATTR_ALWAYS_INLINE
+static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0);
+}
 
-// Submit a usb transfer
-bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
 
 // Claim an endpoint before submitting a transfer.
 // If caller does not make any transfer, it must release endpoint for others.

+ 22 - 3
src/portable/ehci/ehci.c

@@ -656,6 +656,26 @@ static void xfer_error_isr(uint8_t hostid)
   }
 }
 
+#if CFG_TUSB_DEBUG >= EHCI_DBG
+
+static inline void print_portsc(ehci_registers_t* regs)
+{
+  TU_LOG_HEX(EHCI_DBG, regs->portsc);
+  TU_LOG(EHCI_DBG, "  Current Connect Status: %u\r\n", regs->portsc_bm.current_connect_status);
+  TU_LOG(EHCI_DBG, "  Connect Status Change : %u\r\n", regs->portsc_bm.connect_status_change);
+  TU_LOG(EHCI_DBG, "  Port Enabled          : %u\r\n", regs->portsc_bm.port_enabled);
+  TU_LOG(EHCI_DBG, "  Port Enabled Change   : %u\r\n", regs->portsc_bm.port_enable_change);
+
+  TU_LOG(EHCI_DBG, "  Port Reset            : %u\r\n", regs->portsc_bm.port_reset);
+  TU_LOG(EHCI_DBG, "  Port Power            : %u\r\n", regs->portsc_bm.port_power);
+}
+
+#else
+
+#define print_portsc(_reg)
+
+#endif
+
 //------------- Host Controller Driver's Interrupt Handler -------------//
 void hcd_int_handler(uint8_t rhport)
 {
@@ -675,9 +695,8 @@ void hcd_int_handler(uint8_t rhport)
 
   if (int_status & EHCI_INT_MASK_PORT_CHANGE)
   {
-    uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
-
-    TU_LOG_HEX(EHCI_DBG, regs->portsc);
+    uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
+    print_portsc(regs);
 
     if (regs->portsc_bm.connect_status_change)
     {

+ 2 - 0
src/tusb.h

@@ -38,6 +38,8 @@
 #include "osal/osal.h"
 #include "common/tusb_fifo.h"
 
+#include "class/hid/hid.h"
+
 //------------- HOST -------------//
 #if CFG_TUH_ENABLED
   #include "host/usbh.h"

+ 4 - 0
src/tusb_option.h

@@ -392,6 +392,10 @@
 #define CFG_TUH_VENDOR 0
 #endif
 
+#ifndef CFG_TUH_API_EDPT_XFER
+#define CFG_TUH_API_EDPT_XFER 0
+#endif
+
 //------------------------------------------------------------------
 // Configuration Validation
 //------------------------------------------------------------------

Некоторые файлы не были показаны из-за большого количества измененных файлов