From bcdeb386cc4d3afb3d7213c961e4611e511c4e97 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Mar 2022 21:57:55 +0700 Subject: 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 --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/cdc_host.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/class') 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); } -- cgit v1.3.1 From ec28593ce56a9a1726cfe8a43f6a8c421fd3916b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Mar 2022 22:13:57 +0700 Subject: 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(-) (limited to 'src/class') 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); -- cgit v1.3.1 From 2929afe2fa2fc8425dcd1390cb3119bb1bd3b42b Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Mar 2022 17:45:46 +0700 Subject: 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(-) (limited to 'src/class') 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) //-------------------------------------------------------------------- -- cgit v1.3.1