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

rework usbh control xfer

- change API of tuh_control_xfer and its callback
- rename tuh_control_complete_cb_t to tuh_control_xfer_cb_t
- add user argument to control callback
- migrate usbh and hub
hathach 4 лет назад
Родитель
Сommit
bcdeb386cc
7 измененных файлов с 309 добавлено и 221 удалено
  1. 8 8
      examples/host/bare_api/src/main.c
  2. 1 1
      src/class/cdc/cdc_host.c
  3. 3 3
      src/class/cdc/cdc_host.h
  4. 88 60
      src/host/hub.c
  5. 4 4
      src/host/hub.h
  6. 163 129
      src/host/usbh.c
  7. 42 16
      src/host/usbh.h

+ 8 - 8
examples/host/bare_api/src/main.c

@@ -70,9 +70,9 @@ tusb_desc_device_t desc_device;
 
 static volatile xfer_result_t _get_string_result;
 
-static bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) {
+static bool _transfer_done_cb(uint8_t daddr, tuh_control_xfer_t const *xfer, xfer_result_t result) {
     (void)daddr;
-    (void)request;
+    (void)xfer;
     _get_string_result = result;
     return true;
 }
@@ -130,9 +130,9 @@ static void _wait_and_convert(uint16_t *temp_buf, size_t buf_len) {
     ((uint8_t*) temp_buf)[utf8_len] = '\0';
 }
 
-bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * request, xfer_result_t result)
+bool print_device_descriptor(uint8_t daddr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
 
   if ( XFER_RESULT_SUCCESS != result )
   {
@@ -158,7 +158,7 @@ bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * reque
 
   printf("  iManufacturer       %u     "     , desc_device.iManufacturer);
   temp_buf[0] = 0;
-  if (tuh_descriptor_get_manufacturer_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+  if (tuh_descriptor_get_manufacturer_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb, 0)) {
     _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf));
     printf((const char*) temp_buf);
   }
@@ -167,7 +167,7 @@ bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * reque
   printf("  iProduct            %u     "     , desc_device.iProduct);
   _get_string_result = 0xff;
   temp_buf[0] = 0;
-  if (tuh_descriptor_get_product_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+  if (tuh_descriptor_get_product_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb, 0)) {
     _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf));
     printf((const char*) temp_buf);
   }
@@ -176,7 +176,7 @@ bool print_device_descriptor(uint8_t daddr, tusb_control_request_t const * reque
   printf("  iSerialNumber       %u     "     , desc_device.iSerialNumber);
   _get_string_result = 0xff;
   temp_buf[0] = 0;
-  if (tuh_descriptor_get_serial_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
+  if (tuh_descriptor_get_serial_string(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), _transfer_done_cb, 0)) {
     _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf));
     printf((const char*) temp_buf);
   }
@@ -193,7 +193,7 @@ void tuh_mount_cb (uint8_t daddr)
   printf("Device attached, address = %d\r\n", daddr);
 
   // Get Device Descriptor
-  tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor);
+  tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
 }
 
 /// Invoked when device is unmounted (bus reset/unplugged)

+ 1 - 1
src/class/cdc/cdc_host.c

@@ -120,7 +120,7 @@ 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_complete_cb_t complete_cb)
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_xfer_cb_t complete_cb)
 {
   cdch_data_t const * p_cdc = get_itf(dev_addr);
   tusb_control_request_t const request =

+ 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_complete_cb_t complete_cb);
+bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_xfer_cb_t complete_cb);
 
-static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb)
+static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_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_complete_cb_t complete_cb)
+static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_control_xfer_cb_t complete_cb)
 {
   return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
 }

+ 88 - 60
src/host/hub.c

@@ -77,71 +77,92 @@ 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_complete_cb_t complete_cb)
+bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_xfer_cb_t complete_cb)
 {
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_OTHER,
-      .type      = TUSB_REQ_TYPE_CLASS,
-      .direction = TUSB_DIR_OUT
+      .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
     },
-    .bRequest = HUB_REQUEST_CLEAR_FEATURE,
-    .wValue   = feature,
-    .wIndex   = hub_port,
-    .wLength  = 0
+
+    .buffer      = NULL,
+    .complete_cb = complete_cb,
+    .user_arg    = 0
   };
 
   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, &request, NULL, complete_cb) );
+  TU_ASSERT( tuh_control_xfer(hub_addr, &xfer) );
   return true;
 }
 
-bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb)
+bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_xfer_cb_t complete_cb)
 {
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_OTHER,
-      .type      = TUSB_REQ_TYPE_CLASS,
-      .direction = TUSB_DIR_OUT
+      .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
     },
-    .bRequest = HUB_REQUEST_SET_FEATURE,
-    .wValue   = feature,
-    .wIndex   = hub_port,
-    .wLength  = 0
+
+    .buffer      = NULL,
+    .complete_cb = complete_cb,
+    .user_arg    = 0
   };
 
   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, &request, NULL, complete_cb) );
+  TU_ASSERT( tuh_control_xfer(hub_addr, &xfer) );
   return true;
 }
 
-bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb)
+bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_xfer_cb_t complete_cb)
 {
   return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb);
 }
 
-bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb)
+bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_xfer_cb_t complete_cb)
 {
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_OTHER,
-      .type      = TUSB_REQ_TYPE_CLASS,
-      .direction = TUSB_DIR_IN
+      .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
     },
-    .bRequest = HUB_REQUEST_GET_STATUS,
-    .wValue   = 0,
-    .wIndex   = hub_port,
-    .wLength  = 4
+
+    .buffer      = resp,
+    .complete_cb = complete_cb,
+    .user_arg    = 0
   };
 
   TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
-  TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) );
+  TU_ASSERT( tuh_control_xfer( hub_addr, &xfer) );
   return true;
 }
 
@@ -200,8 +221,8 @@ bool hub_edpt_status_xfer(uint8_t dev_addr)
 // Set Configure
 //--------------------------------------------------------------------+
 
-static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+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);
 
 bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
 {
@@ -209,28 +230,35 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
   TU_ASSERT(itf_num == p_hub->itf_num);
 
   // Get Hub Descriptor
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_CLASS,
-      .direction = TUSB_DIR_IN
+      .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)
     },
-    .bRequest = HUB_REQUEST_GET_DESCRIPTOR,
-    .wValue   = 0,
-    .wIndex   = 0,
-    .wLength  = sizeof(descriptor_hub_desc_t)
+
+    .buffer      = _hub_buffer,
+    .complete_cb = config_set_port_power,
+    .user_arg    = 0
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_set_port_power) );
+  TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) );
 
   return true;
 }
 
-static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool config_set_port_power (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   hub_interface_t* p_hub = get_itf(dev_addr);
@@ -246,12 +274,12 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons
   return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete);
 }
 
-static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool config_port_power_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
    hub_interface_t* p_hub = get_itf(dev_addr);
 
-  if (request->wIndex == p_hub->port_count)
+  if (xfer->request.wIndex == p_hub->port_count)
   {
     // All ports are power -> queue notification status endpoint and
     // complete the SET CONFIGURATION
@@ -261,7 +289,7 @@ static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t
   }else
   {
     // power next port
-    uint8_t const hub_port = (uint8_t) (request->wIndex + 1);
+    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);
   }
 
@@ -272,9 +300,9 @@ static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t
 // Connection Changes
 //--------------------------------------------------------------------+
 
-static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+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);
 
 // 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)
@@ -302,12 +330,12 @@ 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, tusb_control_request_t const * request, xfer_result_t result)
+static bool connection_get_status_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
   TU_ASSERT(result == XFER_RESULT_SUCCESS);
 
   hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) request->wIndex;
+  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
 
   // Connection change
   if (p_hub->port_status.change.connection)
@@ -330,12 +358,12 @@ static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_reque
   return true;
 }
 
-static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, 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)
 {
   TU_ASSERT(result == XFER_RESULT_SUCCESS);
 
   hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) request->wIndex;
+  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
 
   if ( p_hub->port_status.status.connection )
   {
@@ -361,12 +389,12 @@ static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_contro
   return true;
 }
 
-static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool connection_port_reset_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
   TU_ASSERT(result == XFER_RESULT_SUCCESS);
 
   // hub_interface_t* p_hub = get_itf(dev_addr);
-  uint8_t const port_num = (uint8_t) request->wIndex;
+  uint8_t const port_num = (uint8_t) xfer->request.wIndex;
 
   // submit attach event
   hcd_event_t event =

+ 4 - 4
src/host/hub.h

@@ -171,11 +171,11 @@ typedef struct {
 
 TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
 
-bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb);
-bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb);
+bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_xfer_cb_t complete_cb);
+bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_xfer_cb_t complete_cb);
 
-bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb);
-bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb);
+bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_xfer_cb_t complete_cb);
+bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_xfer_cb_t complete_cb);
 bool hub_edpt_status_xfer(uint8_t dev_addr);
 
 //--------------------------------------------------------------------+

+ 163 - 129
src/host/usbh.c

@@ -111,15 +111,6 @@ typedef struct {
 
 } usbh_device_t;
 
-typedef struct
-{
-  tusb_control_request_t request TU_ATTR_ALIGNED(4);
-  uint8_t* buffer;
-  tuh_control_complete_cb_t complete_cb;
-
-  uint8_t daddr;
-} usbh_control_xfer_t;
-
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
@@ -250,7 +241,8 @@ static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
 // We will only execute control transfer one at a time.
 struct
 {
-  usbh_control_xfer_t xfer;
+  tuh_control_xfer_t xfer;
+  uint8_t daddr;  // device address that is transferring
   uint8_t stage;
 }_ctrl_xfer;
 
@@ -308,132 +300,165 @@ void osal_task_delay(uint32_t msec)
 // Descriptors
 //--------------------------------------------------------------------+
 
-bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+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)
 {
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
+      .bmRequestType_bit =
+      {
+        .recipient = TUSB_REQ_RCPT_DEVICE,
+        .type      = TUSB_REQ_TYPE_STANDARD,
+        .direction = TUSB_DIR_IN
+      },
+      .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+      .wValue   = tu_htole16( TU_U16(type, index) ),
+      .wIndex   = 0,
+      .wLength  = tu_htole16(len)
     },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = tu_htole16( TU_U16(type, index) ),
-    .wIndex   = 0,
-    .wLength  = tu_htole16(len)
-  };
 
-  TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
+    .buffer      = buffer,
+    .complete_cb = complete_cb,
+    .user_arg    = user_arg
+  };
 
-  return true;
+  return tuh_control_xfer(daddr, &xfer);
 }
 
-bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
+                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
 {
   len = tu_min16(len, sizeof(tusb_desc_device_t));
-  return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb);
+  return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb, user_arg);
 }
 
-bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+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)
 {
-  return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb);
+  return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb, user_arg);
 }
 
-bool tuh_descriptor_get_string(uint8_t daddr, uint16_t language_id, uint8_t index,
-                               void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+bool tuh_descriptor_get_string(uint8_t daddr, uint16_t language_id, uint8_t index, void* buffer, uint16_t len,
+                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
 {
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
+      .bmRequestType_bit =
+      {
+        .recipient = TUSB_REQ_RCPT_DEVICE,
+        .type      = TUSB_REQ_TYPE_STANDARD,
+        .direction = TUSB_DIR_IN
+      },
+      .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+      .wValue   = tu_htole16( TU_U16(TUSB_DESC_STRING, index) ),
+      .wIndex   = tu_htole16(language_id),
+      .wLength  = tu_htole16(len)
     },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = tu_htole16( TU_U16(TUSB_DESC_STRING, index) ),
-    .wIndex   = tu_htole16(language_id),
-    .wLength  = tu_htole16(len)
+
+    .buffer      = buffer,
+    .complete_cb = complete_cb,
+    .user_arg    = user_arg
   };
 
-  TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
-  return true;
+  return tuh_control_xfer(daddr, &xfer);
 }
 
 // Get manufacturer string descriptor
-bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+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)
 {
   TU_VERIFY(tuh_mounted(daddr));
   usbh_device_t const* dev = get_device(daddr);
   if (dev->i_manufacturer == 0) {
     return false;
   }
-  return tuh_descriptor_get_string(daddr, language_id, dev->i_manufacturer, buffer, len, complete_cb);
+  return tuh_descriptor_get_string(daddr, language_id, dev->i_manufacturer, buffer, len, complete_cb, user_arg);
 }
 
 // Get product string descriptor
-bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+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)
 {
   TU_VERIFY(tuh_mounted(daddr));
   usbh_device_t const* dev = get_device(daddr);
   if (dev->i_product == 0) {
     return false;
   }
-  return tuh_descriptor_get_string(daddr, language_id, dev->i_product, buffer, len, complete_cb);
+  return tuh_descriptor_get_string(daddr, language_id, dev->i_product, buffer, len, complete_cb, user_arg);
 }
 
 // Get serial string descriptor
-bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+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)
 {
   TU_VERIFY(tuh_mounted(daddr));
   usbh_device_t const* dev = get_device(daddr);
   if (dev->i_serial == 0) {
     return false;
   }
-  return tuh_descriptor_get_string(daddr, language_id, dev->i_serial, buffer, len, complete_cb);
+  return tuh_descriptor_get_string(daddr, language_id, dev->i_serial, buffer, len, complete_cb, user_arg);
 }
 
 // Get HID report descriptor
-bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, void* buffer, uint16_t len,
+                                   tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
 {
   TU_LOG2("HID Get Report Descriptor\r\n");
-  tusb_control_request_t const request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_INTERFACE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
+      .bmRequestType_bit =
+      {
+        .recipient = TUSB_REQ_RCPT_INTERFACE,
+        .type      = TUSB_REQ_TYPE_STANDARD,
+        .direction = TUSB_DIR_IN
+      },
+      .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+      .wValue   = tu_htole16(TU_U16(desc_type, 0)),
+      .wIndex   = itf_num,
+      .wLength  = len
     },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = tu_htole16(TU_U16(desc_type, 0)),
-    .wIndex   = itf_num,
-    .wLength  = len
+
+    .buffer      = buffer,
+    .complete_cb = complete_cb,
+    .user_arg    = user_arg
   };
 
-  return tuh_control_xfer(daddr, &request, buffer, complete_cb);
+  return tuh_control_xfer(daddr, &xfer);
 }
 
-bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb)
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
+                           tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg)
 {
   TU_LOG2("Set Configuration = %d\r\n", config_num);
-  tusb_control_request_t const request =
+
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_OUT
+      .bmRequestType_bit =
+      {
+        .recipient = TUSB_REQ_RCPT_DEVICE,
+        .type      = TUSB_REQ_TYPE_STANDARD,
+        .direction = TUSB_DIR_OUT
+      },
+      .bRequest = TUSB_REQ_SET_CONFIGURATION,
+      .wValue   = tu_htole16(config_num),
+      .wIndex   = 0,
+      .wLength  = 0
     },
-    .bRequest = TUSB_REQ_SET_CONFIGURATION,
-    .wValue   = tu_htole16(config_num),
-    .wIndex   = 0,
-    .wLength  = 0
+
+    .buffer      = NULL,
+    .complete_cb = complete_cb,
+    .user_arg    = user_arg
   };
 
-  TU_ASSERT( tuh_control_xfer(daddr, &request, NULL, complete_cb) );
-  return true;
+  return tuh_control_xfer(daddr, &xfer);
 }
 
 //--------------------------------------------------------------------+
@@ -460,7 +485,7 @@ bool tuh_init(uint8_t rhport)
   TU_LOG2("USBH init\r\n");
   TU_LOG2_INT(sizeof(usbh_device_t));
   TU_LOG2_INT(sizeof(hcd_event_t));
-  TU_LOG2_INT(sizeof(usbh_control_xfer_t));
+  TU_LOG2_INT(sizeof(tuh_control_xfer_t));
 
   // Event queue
   _usbh_q = osal_queue_create( &_usbh_qdef );
@@ -808,7 +833,7 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
 // Control transfer
 //--------------------------------------------------------------------+
 
-bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb)
+bool tuh_control_xfer (uint8_t daddr, tuh_control_xfer_t const* xfer)
 {
   // pre-check to help reducing mutex lock
   TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
@@ -824,16 +849,13 @@ bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, voi
 
   const uint8_t rhport = usbh_get_rhport(daddr);
 
-  TU_LOG2("[%u:%u] %s: ", rhport, daddr, request->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[request->bRequest] : "Unknown Request");
-  TU_LOG2_VAR(request);
+  TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->request.bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->request.bRequest] : "Unknown Request");
+  TU_LOG2_VAR(&xfer->request);
   TU_LOG2("\r\n");
 
-  _ctrl_xfer.xfer.request     = (*request);
-  _ctrl_xfer.xfer.buffer      = buffer;
-  _ctrl_xfer.xfer.complete_cb = complete_cb;
-  _ctrl_xfer.xfer.daddr       = daddr;
-
-  return hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.xfer.request);
+  _ctrl_xfer.daddr = daddr;
+  _ctrl_xfer.xfer = (*xfer);
+  return hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.xfer.request);
 }
 
 TU_ATTR_ALWAYS_INLINE static inline void set_control_xfer_stage(uint8_t stage)
@@ -851,7 +873,12 @@ static void _xfer_complete(uint8_t dev_addr, xfer_result_t result)
   _ctrl_xfer.stage = CONTROL_STAGE_IDLE;
   usbh_unlock();
 
-  if (_ctrl_xfer.xfer.complete_cb) _ctrl_xfer.xfer.complete_cb(dev_addr, &_ctrl_xfer.xfer.request, result);
+  if (_ctrl_xfer.xfer.complete_cb)
+  {
+    // duplicate xfer since user can execute control transfer within callback
+    tuh_control_xfer_t const xfer_temp = _ctrl_xfer.xfer;
+    _ctrl_xfer.xfer.complete_cb(dev_addr, &xfer_temp, result);
+  }
 }
 
 static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -939,7 +966,7 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
       hcd_device_close(rhport, dev_addr);
       clear_device(dev);
       // abort on-going control xfer if any
-      if (_ctrl_xfer.xfer.daddr == dev_addr) set_control_xfer_stage(CONTROL_STAGE_IDLE);
+      if (_ctrl_xfer.daddr == dev_addr) set_control_xfer_stage(CONTROL_STAGE_IDLE);
     }
   }
 }
@@ -954,14 +981,14 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
 //--------------------------------------------------------------------+
 
 static bool enum_request_addr0_device_desc(void);
-static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
 
 static bool enum_request_set_addr(void);
-static bool enum_set_address_complete           (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_device_desc_complete       (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_get_config_desc_complete       (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_set_config_complete            (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static bool enum_set_address_complete           (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_get_device_desc_complete       (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_get_config_desc_complete       (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_set_config_complete            (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
 static bool parse_configuration_descriptor      (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
 
 static uint8_t get_new_address(bool is_hub);
@@ -973,15 +1000,15 @@ static void enum_full_complete(void);
 // New device (reset on the way) -> Get Status 0 -> Clear Reset 0 -> Get 8byte Device Descriptor
 //   -> Port Reset 1 -> reset delay -> Get Status 1 -> Clear Reset 1 -> queue hub interrupt endpoint
 
-static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_hub_set_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static bool enum_hub_get_status0_complete  (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_hub_clear_reset0_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_hub_set_reset1_complete   (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_hub_get_status1_complete  (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+static bool enum_hub_clear_reset1_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result);
 
-static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_hub_get_status0_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) dev_addr; (void) request;
+  (void) dev_addr; (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   hub_port_status_response_t port_status;
@@ -1006,17 +1033,17 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request
   return true;
 }
 
-static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) dev_addr; (void) request;
+  (void) dev_addr; (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
   enum_request_addr0_device_desc();
   return true;
 }
 
-static bool enum_hub_set_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_hub_set_reset1_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) dev_addr; (void) request;
+  (void) dev_addr; (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   osal_task_delay(RESET_DELAY);
@@ -1026,9 +1053,9 @@ static bool enum_hub_set_reset1_complete(uint8_t dev_addr, tusb_control_request_
   return true;
 }
 
-static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_hub_get_status1_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) dev_addr; (void) request;
+  (void) dev_addr; (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   hub_port_status_response_t port_status;
@@ -1043,9 +1070,9 @@ static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request
   return true;
 }
 
-static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) dev_addr; (void) request;
+  (void) dev_addr; (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   enum_request_set_addr();
@@ -1096,14 +1123,14 @@ static bool enum_request_addr0_device_desc(void)
 
   // Get first 8 bytes of device descriptor for Control Endpoint size
   TU_LOG2("Get 8 byte of Device Descriptor\r\n");
-  TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, enum_get_addr0_device_desc_complete));
+  TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, enum_get_addr0_device_desc_complete, 0));
   return true;
 }
 
 // After Get Device Descriptor of Address 0
-static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(0 == dev_addr);
 
   if (XFER_RESULT_SUCCESS != result)
@@ -1157,33 +1184,40 @@ static bool enum_request_set_addr(void)
   new_dev->connected = 1;
   new_dev->ep0_size  = desc_device->bMaxPacketSize0;
 
-  tusb_control_request_t const new_request =
+  tuh_control_xfer_t const xfer =
   {
-    .bmRequestType_bit =
+    .request =
     {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_OUT
+      .bmRequestType_bit =
+      {
+        .recipient = TUSB_REQ_RCPT_DEVICE,
+        .type      = TUSB_REQ_TYPE_STANDARD,
+        .direction = TUSB_DIR_OUT
+      },
+      .bRequest = TUSB_REQ_SET_ADDRESS,
+      .wValue   = tu_htole16(new_addr),
+      .wIndex   = 0,
+      .wLength  = 0
     },
-    .bRequest = TUSB_REQ_SET_ADDRESS,
-    .wValue   = tu_htole16(new_addr),
-    .wIndex   = 0,
-    .wLength  = 0
+
+    .buffer      = NULL,
+    .complete_cb = enum_set_address_complete,
+    .user_arg    = 0
   };
 
   uint8_t const addr0 = 0;
-  TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) );
+  TU_ASSERT( tuh_control_xfer(addr0, &xfer) );
 
   return true;
 }
 
 // After SET_ADDRESS is complete
-static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_set_address_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
   TU_ASSERT(0 == dev_addr);
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
-  uint8_t const new_addr = (uint8_t const) request->wValue;
+  uint8_t const new_addr = (uint8_t const) xfer->request.wValue;
 
   usbh_device_t* new_dev = get_device(new_addr);
   new_dev->addressed = 1;
@@ -1197,13 +1231,13 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
   // Get full device descriptor
   TU_LOG2("Get Device Descriptor\r\n");
 
-  TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), enum_get_device_desc_complete));
+  TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), enum_get_device_desc_complete, 0));
   return true;
 }
 
-static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_get_device_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
@@ -1220,13 +1254,13 @@ static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request
   // Get 9-byte for total length
   uint8_t const config_idx = CONFIG_NUM - 1;
   TU_LOG2("Get Configuration[0] Descriptor (9 bytes)\r\n");
-  TU_ASSERT( tuh_descriptor_get_configuration(dev_addr, config_idx, _usbh_ctrl_buf, 9, enum_get_9byte_config_desc_complete) );
+  TU_ASSERT( tuh_descriptor_get_configuration(dev_addr, config_idx, _usbh_ctrl_buf, 9, enum_get_9byte_config_desc_complete, 0) );
   return true;
 }
 
-static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   // TODO not enough buffer to hold configuration descriptor
@@ -1240,26 +1274,26 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
   // Get full configuration descriptor
   uint8_t const config_idx = CONFIG_NUM - 1;
   TU_LOG2("Get Configuration[0] Descriptor\r\n");
-  TU_ASSERT( tuh_descriptor_get_configuration(dev_addr, config_idx, _usbh_ctrl_buf, total_len, enum_get_config_desc_complete) );
+  TU_ASSERT( tuh_descriptor_get_configuration(dev_addr, config_idx, _usbh_ctrl_buf, total_len, enum_get_config_desc_complete, 0) );
   return true;
 }
 
-static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_get_config_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   // Parse configuration & set up drivers
   // Driver open aren't allowed to make any usb transfer yet
   TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
 
-  TU_ASSERT( tuh_configuration_set(dev_addr, CONFIG_NUM, enum_set_config_complete) );
+  TU_ASSERT( tuh_configuration_set(dev_addr, CONFIG_NUM, enum_set_config_complete, 0) );
   return true;
 }
 
-static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+static bool enum_set_config_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result)
 {
-  (void) request;
+  (void) xfer;
   TU_ASSERT(XFER_RESULT_SUCCESS == result);
 
   TU_LOG2("Device configured\r\n");

+ 42 - 16
src/host/usbh.h

@@ -38,7 +38,19 @@
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
 
-typedef bool (*tuh_control_complete_cb_t)(uint8_t daddr, tusb_control_request_t const * request, xfer_result_t result);
+// forward declaration
+struct tuh_control_xfer_s;
+typedef struct tuh_control_xfer_s tuh_control_xfer_t;
+
+typedef bool (*tuh_control_xfer_cb_t)(uint8_t daddr, tuh_control_xfer_t const * xfer, xfer_result_t result);
+
+struct tuh_control_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;
+};
 
 //--------------------------------------------------------------------+
 // APPLICATION API
@@ -81,40 +93,54 @@ static inline bool tuh_ready(uint8_t daddr)
 }
 
 // Carry out a control transfer
-// true on success, false if there is on-going control trasnfer
-bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
+// true on success, false if there is on-going control transfer
+// Note: function is blocking if complete callback is NULL
+bool tuh_control_xfer (uint8_t daddr, tuh_control_xfer_t const* xfer);
+
+// Carry out a control transfer
+// true on success, false if there is on-going control transfer
+// Note: function is blocking if complete callback is NULL
+//bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer,
+//                       tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
 
 // Set Configuration
 // config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
-bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb);
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
+                           tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
 
 //------------- descriptors -------------//
 
 // Get an descriptor
-bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index,
-                        void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+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);
 
 // Get device descriptor
-bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
+                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
 
 // Get configuration descriptor
-bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+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);
+
+// Get HID report descriptor
+bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, void* buffer, uint16_t len,
+                                   tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
 
 // Get string descriptor
-bool tuh_descriptor_get_string(uint8_t daddr, uint16_t language_id, uint8_t index,
-                               void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+bool tuh_descriptor_get_string(uint8_t daddr, uint16_t language_id, uint8_t index, void* buffer, uint16_t len,
+                               tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg);
 
 // Get manufacturer string descriptor
-bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+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);
 
 // Get product string descriptor
-bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+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);
 
 // Get serial string descriptor
-bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
-
-// Get HID report descriptor
-bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+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);
 
 //--------------------------------------------------------------------+
 // APPLICATION CALLBACK