From bcdeb386cc4d3afb3d7213c961e4611e511c4e97 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Mar 2022 21:57:55 +0700 Subject: [PATCH 1/6] 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 --- examples/host/bare_api/src/main.c | 16 +- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/cdc_host.h | 6 +- src/host/hub.c | 148 +++++++++------ src/host/hub.h | 8 +- src/host/usbh.c | 292 +++++++++++++++++------------- src/host/usbh.h | 70 ++++--- 7 files changed, 315 insertions(+), 227 deletions(-) diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c index 73e97c390..6888d13a2 100644 --- a/examples/host/bare_api/src/main.c +++ b/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) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2787cd201..6a29f3f43 100644 --- a/src/class/cdc/cdc_host.c +++ b/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 = diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 0d435138b..67162a0ca 100644 --- a/src/class/cdc/cdc_host.h +++ b/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); } diff --git a/src/host/hub.c b/src/host/hub.c index 4c375c290..a0cf7b7e5 100644 --- a/src/host/hub.c +++ b/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 = diff --git a/src/host/hub.h b/src/host/hub.h index 6d81f6773..a5d8704d3 100644 --- a/src/host/hub.h +++ b/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); //--------------------------------------------------------------------+ diff --git a/src/host/usbh.c b/src/host/usbh.c index 617aff79a..a8692c8e5 100644 --- a/src/host/usbh.c +++ b/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) + + .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); } -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"); diff --git a/src/host/usbh.h b/src/host/usbh.h index eec2ed702..d836d9593 100644 --- a/src/host/usbh.h +++ b/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); - -// 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); - -// 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); - -// 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); - -// 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_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_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); + +// 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_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_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_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_xfer_cb_t complete_cb, uintptr_t user_arg); //--------------------------------------------------------------------+ // APPLICATION CALLBACK From ec28593ce56a9a1726cfe8a43f6a8c421fd3916b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Mar 2022 22:13:57 +0700 Subject: [PATCH 2/6] update hid,msc to new usbh control API --- examples/host/cdc_msc_hid/src/main.c | 27 +++-- src/class/cdc/cdc_host.c | 29 ++++-- src/class/hid/hid_host.c | 148 ++++++++++++++++----------- src/class/msc/msc_host.c | 33 +++--- 4 files changed, 139 insertions(+), 98 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index a14be05ea..0fc7ef146 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -71,20 +71,6 @@ int main(void) #if CFG_TUH_CDC CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 }; -void tuh_mount_cb(uint8_t dev_addr) -{ - // application set-up - printf("A device with address %d is mounted\r\n", dev_addr); - - tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // schedule first transfer -} - -void tuh_umount_cb(uint8_t dev_addr) -{ - // application tear-down - printf("A device with address %d is unmounted \r\n", dev_addr); -} - // invoked ISR context void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes) { @@ -109,6 +95,19 @@ void cdc_task(void) // TinyUSB Callbacks //--------------------------------------------------------------------+ +void tuh_mount_cb(uint8_t dev_addr) +{ + // application set-up + printf("A device with address %d is mounted\r\n", dev_addr); +} + +void tuh_umount_cb(uint8_t dev_addr) +{ + // application tear-down + printf("A device with address %d is unmounted \r\n", dev_addr); +} + + //--------------------------------------------------------------------+ // Blinking Task //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 6a29f3f43..8ca3dfbcb 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -123,22 +123,29 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is 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 = + + tuh_control_xfer_t const xfer = { - .bmRequestType_bit = + .request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT + .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 }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = (rts ? 2 : 0) | (dtr ? 1 : 0), - .wIndex = p_cdc->itf_num, - .wLength = 0 + + .buffer = NULL, + .complete_cb = complete_cb, + .user_arg = 0 }; - TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) ); - return true; + return tuh_control_xfer(dev_addr, &xfer); } //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 323debe69..4de3551c2 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -103,13 +103,13 @@ 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, tusb_control_request_t const * request, xfer_result_t result) +static bool set_protocol_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { - uint8_t const itf_num = (uint8_t) request->wIndex; + 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); - if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) request->wValue; + if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) xfer->request.wValue; if (tuh_hid_set_protocol_complete_cb) { @@ -126,37 +126,44 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol) TU_LOG2("HID Set Protocol = %d\r\n", protocol); - tusb_control_request_t const request = + tuh_control_xfer_t const xfer = { - .bmRequestType_bit = + .request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT + .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 }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = protocol, - .wIndex = hid_itf->itf_num, - .wLength = 0 + + .buffer = NULL, + .complete_cb = set_protocol_complete, + .user_arg = 0 }; - TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, set_protocol_complete) ); + TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) ); return true; } -static bool set_report_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool set_report_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { TU_LOG2("HID Set Report complete\r\n"); if (tuh_hid_set_report_complete_cb) { - uint8_t const itf_num = (uint8_t) request->wIndex; + 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 report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + uint8_t const report_type = tu_u16_high(xfer->request.wValue); + uint8_t const report_id = tu_u16_low(xfer->request.wValue); - tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? request->wLength : 0); + tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? xfer->request.wLength : 0); } return true; @@ -167,21 +174,28 @@ 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); - tusb_control_request_t const request = + tuh_control_xfer_t const xfer = { - .bmRequestType_bit = + .request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT + .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 }, - .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_u16(report_type, report_id), - .wIndex = hid_itf->itf_num, - .wLength = len + + .buffer = report, + .complete_cb = set_report_complete, + .user_arg = 0 }; - TU_ASSERT( tuh_control_xfer(dev_addr, &request, report, set_report_complete) ); + TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) ); return true; } @@ -256,9 +270,9 @@ void hidh_close(uint8_t dev_addr) // Enumeration //--------------------------------------------------------------------+ -static bool config_set_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); -static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); -static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +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); @@ -337,65 +351,79 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) // SET IDLE request, device can stall if not support this request TU_LOG2("HID Set Idle \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_CLASS, - .direction = TUSB_DIR_OUT + .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 }, - .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 }; - TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) ); + TU_ASSERT( tuh_control_xfer(dev_addr, &xfer) ); return true; } // Force device to work in BOOT protocol -static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool config_set_protocol(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { // Stall is a valid response for SET_IDLE, therefore we could ignore its result (void) result; - uint8_t const itf_num = (uint8_t) request->wIndex; + 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); TU_LOG2("HID Set Protocol to Boot Mode\r\n"); hid_itf->protocol_mode = HID_PROTOCOL_BOOT; - tusb_control_request_t const new_request = + tuh_control_xfer_t const new_xfer = { - .bmRequestType_bit = + .request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT + .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 }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = HID_PROTOCOL_BOOT, - .wIndex = hid_itf->itf_num, - .wLength = 0 + + .buffer = NULL, + .complete_cb = config_get_report_desc, + .user_arg = 0 }; - TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) ); + TU_ASSERT( tuh_control_xfer(dev_addr, &new_xfer) ); return true; } -static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool config_get_report_desc(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { // We can be here after SET_IDLE or SET_PROTOCOL (boot device) // Trigger assert if result is not successful with set protocol - if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE ) + if ( xfer->request.bRequest != HID_REQ_CONTROL_SET_IDLE ) { TU_ASSERT(result == XFER_RESULT_SUCCESS); } - uint8_t const itf_num = (uint8_t) request->wIndex; + 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); @@ -409,21 +437,21 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons config_driver_mount_complete(dev_addr, instance, NULL, 0); }else { - TU_ASSERT(tuh_descriptor_get_hid_report(dev_addr, itf_num, hid_itf->report_desc_type, usbh_get_enum_buf(), hid_itf->report_desc_len, config_get_report_desc_complete)); + TU_ASSERT(tuh_descriptor_get_hid_report(dev_addr, itf_num, hid_itf->report_desc_type, usbh_get_enum_buf(), hid_itf->report_desc_len, config_get_report_desc_complete, 0)); } return true; } -static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, 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) { TU_ASSERT(XFER_RESULT_SUCCESS == result); - uint8_t const itf_num = (uint8_t) request->wIndex; + 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* desc_report = usbh_get_enum_buf(); - uint16_t const desc_len = request->wLength; + uint16_t const desc_len = xfer->request.wLength; config_driver_mount_complete(dev_addr, instance, desc_report, desc_len); diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index e4239e375..c009e5088 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -358,7 +358,7 @@ 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, tusb_control_request_t const * request, xfer_result_t result); +static bool config_get_maxlun_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result); 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); @@ -405,27 +405,34 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) //------------- Get Max Lun -------------// TU_LOG2("MSC Get Max Lun\r\n"); - tusb_control_request_t request = + tuh_control_xfer_t const xfer = { - .bmRequestType_bit = + .request = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN + .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 }, - .bRequest = MSC_REQ_GET_MAX_LUN, - .wValue = 0, - .wIndex = itf_num, - .wLength = 1 + + .buffer = &p_msc->max_lun, + .complete_cb = config_get_maxlun_complete, + .user_arg = 0 }; - TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, config_get_maxlun_complete)); + TU_ASSERT(tuh_control_xfer(dev_addr, &xfer)); return true; } -static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool config_get_maxlun_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { - (void) request; + (void) xfer; msch_interface_t* p_msc = get_itf(dev_addr); From a5a565f7eb85c4d1ad43d74b1baf1f61dcf0a5b5 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 12 Mar 2022 14:20:57 +0700 Subject: [PATCH 3/6] rework usbh enumeration process using user arg from control transfer as state --- src/host/hub.c | 30 ++-- src/host/hub.h | 31 +++- src/host/usbh.c | 456 ++++++++++++++++++++++-------------------------- 3 files changed, 251 insertions(+), 266 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index a0cf7b7e5..c1909cb5c 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -77,7 +77,8 @@ 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) +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_control_xfer_t const xfer = { @@ -97,7 +98,7 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, .buffer = NULL, .complete_cb = complete_cb, - .user_arg = 0 + .user_arg = user_arg }; TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port); @@ -105,7 +106,8 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, 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) +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_control_xfer_t const xfer = { @@ -125,7 +127,7 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t .buffer = NULL, .complete_cb = complete_cb, - .user_arg = 0 + .user_arg = user_arg }; TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port); @@ -133,12 +135,8 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t return true; } -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_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, uintptr_t user_arg) { tuh_control_xfer_t const xfer = { @@ -158,7 +156,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con .buffer = resp, .complete_cb = complete_cb, - .user_arg = 0 + .user_arg = user_arg }; TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port); @@ -271,7 +269,7 @@ 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); + return hub_port_set_feature(dev_addr, 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) @@ -290,7 +288,7 @@ static bool config_port_power_complete (uint8_t dev_addr, tuh_control_xfer_t con { // 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); + return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0); } return true; @@ -320,7 +318,7 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 { if ( tu_bit_test(p_hub->status_change, port) ) { - hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete); + hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete, 0); break; } } @@ -344,7 +342,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); + hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0); }else { // Other changes are: Enable, Suspend, Over Current, Reset, L1 state @@ -368,7 +366,7 @@ static bool connection_clear_conn_change_complete (uint8_t dev_addr, tuh_control if ( p_hub->port_status.status.connection ) { // Reset port if attach event - hub_port_reset(dev_addr, port_num, connection_port_reset_complete); + hub_port_reset(dev_addr, port_num, connection_port_reset_complete, 0); }else { // submit detach event diff --git a/src/host/hub.h b/src/host/hub.h index a5d8704d3..30cf3dd1c 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -171,13 +171,36 @@ 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_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); +// 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); -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); +// 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); + +// 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); + +// 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) +{ + return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_arg); +} + +// 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) +{ + return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_arg); +} + + //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ diff --git a/src/host/usbh.c b/src/host/usbh.c index a8692c8e5..6c38c525e 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -974,114 +974,216 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h //--------------------------------------------------------------------+ // Enumeration Process // is a lengthy process with a series of control transfer to configure -// newly attached device. Each step is handled by a function in this -// section -// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating +// newly attached device. +// NOTE: due to the shared _usbh_ctrl_buf, we must complete enumerating // one device before enumerating another one. //--------------------------------------------------------------------+ -static bool enum_request_addr0_device_desc(void); -static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result); +enum { + ENUM_IDLE, + ENUM_RESET_1, // 1st reset when attached + //ENUM_HUB_GET_STATUS_1, + ENUM_HUB_CLEAR_RESET_1, + ENUM_ADDR0_DEVICE_DESC, + ENUM_RESET_2, // 2nd reset before set address + ENUM_HUB_GET_STATUS_2, + ENUM_HUB_CLEAR_RESET_2, + ENUM_SET_ADDR, + + ENUM_GET_DEVICE_DESC, + ENUM_GET_9BYTE_CONFIG_DESC, + ENUM_GET_FULL_CONFIG_DESC, + ENUM_SET_CONFIG, + ENUM_CONFIG_DRIVER +}; static bool enum_request_set_addr(void); -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); static void enum_full_complete(void); -#if CFG_TUH_HUB - -// Enum sequence: -// 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, 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, tuh_control_xfer_t const * xfer, xfer_result_t result) +// process device enumeration +static bool process_enumeration(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) { - (void) dev_addr; (void) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); - - if ( !port_status.status.connection ) + if (XFER_RESULT_SUCCESS != result) { - // device unplugged while delaying, nothing else to do, queue hub status + // stop enumeration, maybe we could retry this enum_full_complete(); return false; } - _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + uint32_t const state = (uint32_t) xfer->user_arg; - // Acknowledge Port Reset Change - if (port_status.change.reset) + switch(state) { - hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete); +#if CFG_TUH_HUB + //case ENUM_HUB_GET_STATUS_1: break; + + case ENUM_HUB_CLEAR_RESET_1: + { + hub_port_status_response_t port_status; + memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + + if ( !port_status.status.connection ) + { + // device unplugged while delaying, nothing else to do + enum_full_complete(); + return false; + } + + _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + + // Acknowledge Port Reset Change + if (port_status.change.reset) + { + hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC); + } + } + break; + + case ENUM_HUB_GET_STATUS_2: + osal_task_delay(RESET_DELAY); + TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2) ); + break; + + case ENUM_HUB_CLEAR_RESET_2: + { + hub_port_status_response_t port_status; + memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + + // Acknowledge Port Reset Change if Reset Successful + if (port_status.change.reset) + { + TU_ASSERT( hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_SET_ADDR) ); + } + } + break; +#endif + + case ENUM_ADDR0_DEVICE_DESC: + { + // TODO probably doesn't need to open/close each enumeration + uint8_t const addr0 = 0; + TU_ASSERT( usbh_edpt_control_open(addr0, 8) ); + + // 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, process_enumeration, ENUM_SET_ADDR)); + } + break; + + case ENUM_RESET_2: + // Reset device again before Set Address + TU_LOG2("Port reset \r\n"); + if (_dev0.hub_addr == 0) + { + // connected directly to roothub + hcd_port_reset( _dev0.rhport ); + osal_task_delay(RESET_DELAY); + + // TODO: fall through to SET ADDRESS, refactor later + } + #if CFG_TUH_HUB + else + { + // after RESET_DELAY the hub_port_reset() already complete + TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_HUB_GET_STATUS_2) ); + break; + } + __attribute__((fallthrough)); + #endif + + case ENUM_SET_ADDR: + enum_request_set_addr(); + break; + + case ENUM_GET_DEVICE_DESC: + { + uint8_t const new_addr = (uint8_t const) xfer->request.wValue; + + usbh_device_t* new_dev = get_device(new_addr); + new_dev->addressed = 1; + + // TODO close device 0, may not be needed + hcd_device_close(_dev0.rhport, 0); + + // open control pipe for new address + TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size) ); + + // 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), process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC)); + } + break; + + case ENUM_GET_9BYTE_CONFIG_DESC: + { + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + usbh_device_t* dev = get_device(dev_addr); + + dev->vid = desc_device->idVendor; + dev->pid = desc_device->idProduct; + dev->i_manufacturer = desc_device->iManufacturer; + dev->i_product = desc_device->iProduct; + dev->i_serial = desc_device->iSerialNumber; + + // if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); + + // 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, process_enumeration, ENUM_GET_FULL_CONFIG_DESC) ); + } + break; + + case ENUM_GET_FULL_CONFIG_DESC: + { + uint8_t const * desc_config = _usbh_ctrl_buf; + + // Use offsetof to avoid pointer to the odd/misaligned address + uint16_t const total_len = tu_le16toh( tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) ); + + // TODO not enough buffer to hold configuration descriptor + TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE); + + // 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, process_enumeration, ENUM_SET_CONFIG) ); + } + break; + + case ENUM_SET_CONFIG: + // 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, process_enumeration, ENUM_CONFIG_DRIVER) ); + break; + + case ENUM_CONFIG_DRIVER: + { + TU_LOG2("Device configured\r\n"); + usbh_device_t* dev = get_device(dev_addr); + dev->configured = 1; + + // Start the Set Configuration process for interfaces (itf = DRVID_INVALID) + // Since driver can perform control transfer within its set_config, this is done asynchronously. + // The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete() + // TODO use separated API instead of using DRVID_INVALID + usbh_driver_set_config_complete(dev_addr, DRVID_INVALID); + } + break; + + default: + // stop enumeration if unknown state + enum_full_complete(); + break; } return true; } -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) 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, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (void) dev_addr; (void) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - osal_task_delay(RESET_DELAY); - - TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) ); - - return true; -} - -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) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - hub_port_status_response_t port_status; - memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); - - // Acknowledge Port Reset Change if Reset Successful - if (port_status.change.reset) - { - TU_ASSERT( hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); - } - - return true; -} - -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) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - enum_request_set_addr(); - - return true; -} - -#endif // hub - static bool enum_new_device(hcd_event_t* event) { _dev0.rhport = event->rhport; @@ -1100,7 +1202,14 @@ static bool enum_new_device(hcd_event_t* event) _dev0.speed = hcd_port_speed_get(_dev0.rhport ); TU_LOG2("%s Speed\r\n", tu_str_speed[_dev0.speed]); - enum_request_addr0_device_desc(); + //enum_request_addr0_device_desc(); + tuh_control_xfer_t const xfer = + { + .complete_cb = process_enumeration, + .user_arg = ENUM_ADDR0_DEVICE_DESC + }; + process_enumeration(0, &xfer, XFER_RESULT_SUCCESS); + } #if CFG_TUH_HUB else @@ -1108,61 +1217,27 @@ static bool enum_new_device(hcd_event_t* event) // connected/disconnected via external hub // wait until device is stable osal_task_delay(RESET_DELAY); - TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) ); + + // ENUM_HUB_GET_STATUS + //TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) ); + TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_1) ); } #endif // hub return true; } -static bool enum_request_addr0_device_desc(void) +static uint8_t get_new_address(bool is_hub) { - // TODO probably doesn't need to open/close each enumeration - uint8_t const addr0 = 0; - TU_ASSERT( usbh_edpt_control_open(addr0, 8) ); + uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1; + uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX); - // 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, 0)); - return true; -} - -// After Get Device Descriptor of Address 0 -static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (void) xfer; - TU_ASSERT(0 == dev_addr); - - if (XFER_RESULT_SUCCESS != result) + for (uint8_t i=0; i < count; i++) { - // stop enumeration, maybe we could retry this - enum_full_complete(); - return false; + uint8_t const addr = start + i; + if (!get_device(addr)->connected) return addr; } - - tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - TU_ASSERT( tu_desc_type(desc_device) == TUSB_DESC_DEVICE ); - - // Reset device again before Set Address - TU_LOG2("Port reset \r\n"); - - if (_dev0.hub_addr == 0) - { - // connected directly to roothub - hcd_port_reset( _dev0.rhport ); - osal_task_delay(RESET_DELAY); - - enum_request_set_addr(); - } -#if CFG_TUH_HUB - else - { - // after RESET_DELAY the hub_port_reset() already complete - TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, enum_hub_set_reset1_complete) ); - } -#endif // hub - - return true; + return ADDR_INVALID; } static bool enum_request_set_addr(void) @@ -1201,8 +1276,8 @@ static bool enum_request_set_addr(void) }, .buffer = NULL, - .complete_cb = enum_set_address_complete, - .user_arg = 0 + .complete_cb = process_enumeration, + .user_arg = ENUM_GET_DEVICE_DESC }; uint8_t const addr0 = 0; @@ -1211,104 +1286,6 @@ static bool enum_request_set_addr(void) return true; } -// After SET_ADDRESS is complete -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) xfer->request.wValue; - - usbh_device_t* new_dev = get_device(new_addr); - new_dev->addressed = 1; - - // TODO close device 0, may not be needed - hcd_device_close(_dev0.rhport, 0); - - // open control pipe for new address - TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size) ); - - // 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, 0)); - return true; -} - -static bool enum_get_device_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (void) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - usbh_device_t* dev = get_device(dev_addr); - - dev->vid = desc_device->idVendor; - dev->pid = desc_device->idProduct; - dev->i_manufacturer = desc_device->iManufacturer; - dev->i_product = desc_device->iProduct; - dev->i_serial = desc_device->iSerialNumber; - -// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); - - // 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, 0) ); - return true; -} - -static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (void) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - // TODO not enough buffer to hold configuration descriptor - uint8_t const * desc_config = _usbh_ctrl_buf; - - // Use offsetof to avoid pointer to the odd/misaligned address - uint16_t const total_len = tu_le16toh( tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) ); - - TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE); - - // 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, 0) ); - return true; -} - -static bool enum_get_config_desc_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (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, 0) ); - return true; -} - -static bool enum_set_config_complete(uint8_t dev_addr, tuh_control_xfer_t const * xfer, xfer_result_t result) -{ - (void) xfer; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - TU_LOG2("Device configured\r\n"); - usbh_device_t* dev = get_device(dev_addr); - dev->configured = 1; - - // Start the Set Configuration process for interfaces (itf = DRVID_INVALID) - // Since driver can perform control transfer within its set_config, this is done asynchronously. - // The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete() - // TODO use separated API instead of using DRVID_INVALID - usbh_driver_set_config_complete(dev_addr, DRVID_INVALID); - - return true; -} - static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) { usbh_device_t* dev = get_device(dev_addr); @@ -1439,17 +1416,4 @@ static void enum_full_complete(void) } -static uint8_t get_new_address(bool is_hub) -{ - uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1; - uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX); - - for (uint8_t i=0; i < count; i++) - { - uint8_t const addr = start + i; - if (!get_device(addr)->connected) return addr; - } - return ADDR_INVALID; -} - #endif From ac4483a7c53cd35b61b59cf69168e31ceac977a1 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 12 Mar 2022 14:26:48 +0700 Subject: [PATCH 4/6] misplace fallthrough --- src/host/usbh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 6c38c525e..16366b33f 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1090,8 +1090,8 @@ static bool process_enumeration(uint8_t dev_addr, tuh_control_xfer_t const * xfe TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, process_enumeration, ENUM_HUB_GET_STATUS_2) ); break; } - __attribute__((fallthrough)); #endif + __attribute__((fallthrough)); case ENUM_SET_ADDR: enum_request_set_addr(); From 56695569e7d9ebf39ffb2152aba4b4b9f0801d2d Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 12 Mar 2022 14:28:24 +0700 Subject: [PATCH 5/6] minor changes --- src/host/usbh.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 16366b33f..7485bb065 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1011,8 +1011,7 @@ static bool process_enumeration(uint8_t dev_addr, tuh_control_xfer_t const * xfe return false; } - uint32_t const state = (uint32_t) xfer->user_arg; - + uintptr_t const state = xfer->user_arg; switch(state) { #if CFG_TUH_HUB From 2929afe2fa2fc8425dcd1390cb3119bb1bd3b42b Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Mar 2022 17:45:46 +0700 Subject: [PATCH 6/6] add synchronous (blocking) support for usbh control transfer - add synchronous version of all get descriptor API - update bare example to use sync API for string descriptor - change order of index, language_id in tuh_descriptor_get_string() to match similar API of libusb - add index to tuh_descriptor_get_hid_report() --- examples/host/bare_api/src/main.c | 43 +++----- src/class/hid/hid_host.c | 2 +- src/common/tusb_types.h | 2 + src/host/usbh.c | 172 +++++++++++++++++++++++------- src/host/usbh.h | 98 ++++++++++++----- src/tusb_option.h | 2 +- 6 files changed, 224 insertions(+), 95 deletions(-) diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c index 6888d13a2..9e6209991 100644 --- a/examples/host/bare_api/src/main.c +++ b/examples/host/bare_api/src/main.c @@ -66,17 +66,9 @@ int main(void) #define LANGUAGE_ID 0x0409 //uint8_t usb_buf[256] TU_ATTR_ALIGNED(4); +TU_ATTR_ALIGNED(4) tusb_desc_device_t desc_device; -static volatile xfer_result_t _get_string_result; - -static bool _transfer_done_cb(uint8_t daddr, tuh_control_xfer_t const *xfer, xfer_result_t result) { - (void)daddr; - (void)xfer; - _get_string_result = result; - return true; -} - 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; @@ -116,14 +108,7 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) { return total_bytes; } -static void _wait_and_convert(uint16_t *temp_buf, size_t buf_len) { - while (_get_string_result == 0xff) { - tuh_task(); - } - if (_get_string_result != XFER_RESULT_SUCCESS) { - temp_buf[0] = 0; - return; - } +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); @@ -153,31 +138,29 @@ 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); - _get_string_result = 0xff; + uint32_t timeout_ms = 10; uint16_t temp_buf[128]; 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, 0)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms) ) + { + utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf)); printf((const char*) temp_buf); } printf("\r\n"); 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, 0)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms)) + { + utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf)); printf((const char*) temp_buf); } printf("\r\n"); 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, 0)) { - _wait_and_convert(temp_buf, TU_ARRAY_SIZE(temp_buf)); + if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, TU_ARRAY_SIZE(temp_buf), timeout_ms)) + { + utf16_to_utf8(temp_buf, TU_ARRAY_SIZE(temp_buf)); printf((const char*) temp_buf); } printf("\r\n"); @@ -192,7 +175,7 @@ void tuh_mount_cb (uint8_t daddr) { printf("Device attached, address = %d\r\n", daddr); - // Get Device Descriptor + // Get Device Descriptor using asynchronous API tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0); } diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 4de3551c2..a825858ab 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -437,7 +437,7 @@ static bool config_get_report_desc(uint8_t dev_addr, tuh_control_xfer_t const * config_driver_mount_complete(dev_addr, instance, NULL, 0); }else { - TU_ASSERT(tuh_descriptor_get_hid_report(dev_addr, itf_num, hid_itf->report_desc_type, usbh_get_enum_buf(), hid_itf->report_desc_len, config_get_report_desc_complete, 0)); + 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)); } return true; diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index da164145b..e2fa17532 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -228,6 +228,8 @@ typedef enum XFER_RESULT_SUCCESS, XFER_RESULT_FAILED, XFER_RESULT_STALLED, + XFER_RESULT_TIMEOUT, + XFER_RESULT_INVALID }xfer_result_t; enum // TODO remove diff --git a/src/host/usbh.c b/src/host/usbh.c index 7485bb065..c7dfaddf6 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -243,7 +243,7 @@ struct { tuh_control_xfer_t xfer; uint8_t daddr; // device address that is transferring - uint8_t stage; + volatile uint8_t stage; }_ctrl_xfer; //------------- Helper Function -------------// @@ -300,8 +300,8 @@ 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_xfer_cb_t complete_cb, uintptr_t user_arg) +static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, + tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg) { tuh_control_xfer_t const xfer = { @@ -315,7 +315,7 @@ bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer }, .bRequest = TUSB_REQ_GET_DESCRIPTOR, .wValue = tu_htole16( TU_U16(type, index) ), - .wIndex = 0, + .wIndex = tu_htole16(language_id), .wLength = tu_htole16(len) }, @@ -327,6 +327,12 @@ bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer return tuh_control_xfer(daddr, &xfer); } +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) +{ + return _get_descriptor(daddr, type, index, 0x0000, buffer, len, complete_cb, user_arg); +} + bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len, tuh_control_xfer_cb_t complete_cb, uintptr_t user_arg) { @@ -340,31 +346,12 @@ bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer 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, +//------------- String Descriptor -------------// + +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_control_xfer_t const xfer = - { - .request = - { - .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) - }, - - .buffer = buffer, - .complete_cb = complete_cb, - .user_arg = user_arg - }; - - return tuh_control_xfer(daddr, &xfer); + return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_arg); } // Get manufacturer string descriptor @@ -376,7 +363,7 @@ bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, if (dev->i_manufacturer == 0) { return false; } - return tuh_descriptor_get_string(daddr, language_id, dev->i_manufacturer, buffer, len, complete_cb, user_arg); + return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_arg); } // Get product string descriptor @@ -388,7 +375,7 @@ bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void if (dev->i_product == 0) { return false; } - return tuh_descriptor_get_string(daddr, language_id, dev->i_product, buffer, len, complete_cb, user_arg); + return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_arg); } // Get serial string descriptor @@ -400,11 +387,11 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* if (dev->i_serial == 0) { return false; } - return tuh_descriptor_get_string(daddr, language_id, dev->i_serial, buffer, len, complete_cb, user_arg); + return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, 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, +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) { TU_LOG2("HID Get Report Descriptor\r\n"); @@ -419,8 +406,8 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_ .direction = TUSB_DIR_IN }, .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = tu_htole16(TU_U16(desc_type, 0)), - .wIndex = itf_num, + .wValue = tu_htole16(TU_U16(desc_type, index)), + .wIndex = tu_htole16((uint16_t) itf_num), .wLength = len }, @@ -461,6 +448,58 @@ bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, return tuh_control_xfer(daddr, &xfer); } +//--------------------------------------------------------------------+ +// Asynchronous +//--------------------------------------------------------------------+ + +#define _CONTROL_SYNC_API(_async_func, _timeout, ...) \ + (void) _timeout; \ + xfer_result_t result = XFER_RESULT_INVALID;\ + /* TODO use timeout to wait */ \ + TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \ + return (uint8_t) 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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get, timeout_ms, daddr, type, index, buffer, len); +} + +uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len, uint8_t timeout_ms) +{ + len = tu_min16(len, sizeof(tusb_desc_device_t)); + return tuh_descriptor_get_sync(daddr, TUSB_DESC_DEVICE, 0, buffer, len, timeout_ms); +} + +uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, uint8_t timeout_ms) +{ + return tuh_descriptor_get_sync(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, 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, uint8_t timeout_ms) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, timeout_ms, daddr, itf_num, desc_type, index, buffer, len); +} + +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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_string, timeout_ms, daddr, index, language_id, buffer, len); +} + +uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, timeout_ms, daddr, language_id, buffer, len); +} + +uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_product_string, timeout_ms, daddr, language_id, buffer, len); +} + +uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, uint8_t timeout_ms) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, timeout_ms, daddr, language_id, buffer, len); +} + //--------------------------------------------------------------------+ // CLASS-USBD API (don't require to verify parameters) //--------------------------------------------------------------------+ @@ -833,11 +872,22 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) // Control transfer //--------------------------------------------------------------------+ +static bool _control_blocking_complete_cb(uint8_t daddr, tuh_control_xfer_t const * xfer, xfer_result_t result) +{ + (void) daddr; + + // update result + *((xfer_result_t*) xfer->user_arg) = result; + + return true; +} + 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); + // TODO probably better to use semaphore as resource management than mutex usbh_lock(); bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); @@ -855,7 +905,52 @@ bool tuh_control_xfer (uint8_t daddr, tuh_control_xfer_t const* xfer) _ctrl_xfer.daddr = daddr; _ctrl_xfer.xfer = (*xfer); - return hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.xfer.request); + + if (xfer->complete_cb) + { + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.xfer.request) ); + }else + { + // user_arg must point to xfer_result_t to hold result + TU_VERIFY(xfer->user_arg); + + // blocking if complete callback is not provided + // change callback to internal blocking, and result as user argument + volatile xfer_result_t* result = (volatile xfer_result_t*) xfer->user_arg; + + _ctrl_xfer.xfer.complete_cb = _control_blocking_complete_cb; + *result = XFER_RESULT_INVALID; + + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.xfer.request) ); + + while ((*result) == XFER_RESULT_INVALID) + { + // only need to call task if not preempted RTOS + #if CFG_TUSB_OS == OPT_OS_NONE || CFG_TUSB_OS == OPT_OS_PICO + tuh_task(); + #endif + + // TODO probably some timeout to prevent hanged + } + } + + return true; +} + +uint8_t tuh_control_xfer_sync(uint8_t daddr, tuh_control_xfer_t const* xfer, uint32_t timeout_ms) +{ + (void) timeout_ms; + + xfer_result_t result = XFER_RESULT_INVALID; + tuh_control_xfer_t xfer_sync = (*xfer); + + xfer_sync.complete_cb = NULL; + xfer_sync.user_arg = (uintptr_t) &result; + + // TODO use timeout to wait + TU_VERIFY(tuh_control_xfer(daddr, &xfer_sync), XFER_RESULT_TIMEOUT); + + return result; } TU_ATTR_ALWAYS_INLINE static inline void set_control_xfer_stage(uint8_t stage) @@ -869,15 +964,16 @@ static void _xfer_complete(uint8_t dev_addr, xfer_result_t result) { TU_LOG2("\r\n"); + // duplicate xfer since user can execute control transfer within callback + tuh_control_xfer_t const xfer_temp = _ctrl_xfer.xfer; + usbh_lock(); _ctrl_xfer.stage = CONTROL_STAGE_IDLE; usbh_unlock(); - if (_ctrl_xfer.xfer.complete_cb) + if (xfer_temp.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); + xfer_temp.complete_cb(dev_addr, &xfer_temp, result); } } diff --git a/src/host/usbh.h b/src/host/usbh.h index d836d9593..3bd40c50d 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -52,6 +52,18 @@ struct tuh_control_xfer_s uintptr_t user_arg; }; +//--------------------------------------------------------------------+ +// APPLICATION CALLBACK +//--------------------------------------------------------------------+ + +//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device); + +// Invoked when device is mounted (configured) +TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr); + +/// Invoked when device is unmounted (bus reset/unplugged) +TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr); + //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ @@ -93,65 +105,101 @@ static inline bool tuh_ready(uint8_t daddr) } // 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 +// 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); -// 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); +// 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); -// Set Configuration +// 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); -//------------- descriptors -------------// +//--------------------------------------------------------------------+ +// Descriptors Asynchronous (non-blocking) +//--------------------------------------------------------------------+ -// Get an descriptor +// 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); -// Get device descriptor +// 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); -// Get configuration descriptor +// 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); -// 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, +// 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); -// Get string descriptor -bool tuh_descriptor_get_string(uint8_t daddr, uint16_t language_id, uint8_t index, void* buffer, uint16_t len, +// 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 +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); -// Get manufacturer string descriptor +// 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); -// Get product string descriptor +// 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); -// Get serial string descriptor +// 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); //--------------------------------------------------------------------+ -// APPLICATION CALLBACK +// Descriptors Synchronous (blocking) //--------------------------------------------------------------------+ -//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device); -// Invoked when device is mounted (configured) -TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr); +// 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); -/// Invoked when device is unmounted (bus reset/unplugged) -TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr); +// 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); + +// 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); + +// 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); + +// 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); + +// 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); + +// 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); + +// 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); #ifdef __cplusplus } diff --git a/src/tusb_option.h b/src/tusb_option.h index e5351b1c4..0352faaed 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -285,7 +285,7 @@ #define CFG_TUSB_OS_INC_PATH #endif -// mutex is only needed for RTOS +// mutex is only needed for RTOS TODO also required with multiple core MCUs #define TUSB_OPT_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) //--------------------------------------------------------------------