diff options
| author | hathach <[email protected]> | 2022-03-18 18:04:25 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2022-03-18 18:04:25 +0700 |
| commit | 9ae0304b1ecd8d10f96a39c5c88a43d6b7c43681 (patch) | |
| tree | af7f7bce60709a836d2772dce47a0b6fd0f1ea7e /src | |
| parent | 8750e3b57756e4377bb737c578e2742b653c314c (diff) | |
move code around
Diffstat (limited to 'src')
| -rw-r--r-- | src/host/usbh.c | 819 |
1 files changed, 408 insertions, 411 deletions
diff --git a/src/host/usbh.c b/src/host/usbh.c index 36774d3dc..8aa9c4a16 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -110,14 +110,7 @@ typedef struct { tu_edpt_state_t ep_status[CFG_TUH_ENDPOINT_MAX][2]; #if CFG_TUH_API_EDPT_XFER -// struct -// { -// uint8_t* buffer; -// tuh_xfer_cb_t complete_cb; -// uintptr_t user_data; -// uint16_t buflen; -// volatile uint16_t actual_len; -// }ep_xfer[[]]; + // ep_xfer[]; #endif } usbh_device_t; @@ -316,226 +309,6 @@ void osal_task_delay(uint32_t msec) #endif //--------------------------------------------------------------------+ -// Descriptors Async -//--------------------------------------------------------------------+ - -// generic helper to get a descriptor -// if blocking, user_data could be pointed to xfer_result -static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - tusb_control_request_t const 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(type, index) ), - .wIndex = tu_htole16(language_id), - .wLength = tu_htole16(len) - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = buffer, - .complete_cb = complete_cb, - .user_data = user_data - }; - - bool const ret = tuh_control_xfer(&xfer); - - // if blocking, user_data could be pointed to xfer_result - if ( !complete_cb && user_data ) - { - *((xfer_result_t*) user_data) = xfer.result; - } - - return ret; -} - -bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return _get_descriptor(daddr, type, index, 0x0000, buffer, len, complete_cb, user_data); -} - -bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - len = tu_min16(len, sizeof(tusb_desc_device_t)); - return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb, user_data); -} - -bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb, user_data); -} - -//------------- String Descriptor -------------// - -bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data); -} - -// Get manufacturer string descriptor -bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_manufacturer); - return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_data); -} - -// Get product string descriptor -bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_product); - return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_data); -} - -// Get serial string descriptor -bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - usbh_device_t const* dev = get_device(daddr); - TU_VERIFY(dev && dev->i_serial); - return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, buffer, len, complete_cb, user_data); -} - -// Get HID report descriptor -// if blocking, user_data could be pointed to xfer_result -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_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG2("HID Get Report Descriptor\r\n"); - tusb_control_request_t const request = - { - .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, index)), - .wIndex = tu_htole16((uint16_t) itf_num), - .wLength = len - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = buffer, - .complete_cb = complete_cb, - .user_data = user_data - }; - - bool const ret = tuh_control_xfer(&xfer); - - // if blocking, user_data could be pointed to xfer_result - if ( !complete_cb && user_data ) - { - *((xfer_result_t*) user_data) = xfer.result; - } - - return ret; -} - -bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - TU_LOG2("Set Configuration = %d\r\n", config_num); - - tusb_control_request_t const request = - { - .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 - }; - - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; - - return tuh_control_xfer(&xfer); -} - -//--------------------------------------------------------------------+ -// Descriptor Sync -//--------------------------------------------------------------------+ - -#define _CONTROL_SYNC_API(_async_func, ...) \ - xfer_result_t result = XFER_RESULT_INVALID;\ - 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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len); -} - -uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len); -} - -uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len); -} - -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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, 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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_string, 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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, 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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_product_string, 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) -{ - _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len); -} - -//--------------------------------------------------------------------+ // CLASS-USBD API (don't require to verify parameters) //--------------------------------------------------------------------+ @@ -695,109 +468,208 @@ void tuh_task(void) } //--------------------------------------------------------------------+ -// USBH API For Class Driver +// Control transfer //--------------------------------------------------------------------+ -uint8_t usbh_get_rhport(uint8_t dev_addr) +static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { - usbh_device_t* dev = get_device(dev_addr); - return dev ? dev->rhport : _dev0.rhport; + // update result + *((xfer_result_t*) xfer->user_data) = xfer->result; } -uint8_t* usbh_get_enum_buf(void) +// TODO timeout_ms is not supported yet +bool tuh_control_xfer (tuh_xfer_t* xfer) { - return _usbh_ctrl_buf; -} + // EP0 with setup packet + TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); -void usbh_int_set(bool enabled) -{ - // TODO all host controller - if (enabled) - { - hcd_int_enable(TUH_OPT_RHPORT); - }else + // pre-check to help reducing mutex lock + TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE); + + uint8_t const daddr = xfer->daddr; + + // TODO probably better to use semaphore as resource management than mutex + usbh_lock(); + + bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); + if (is_idle) { - hcd_int_disable(TUH_OPT_RHPORT); + _ctrl_xfer.stage = CONTROL_STAGE_SETUP; + _ctrl_xfer.daddr = daddr; + _ctrl_xfer.actual_len = 0; + + _ctrl_xfer.request = (*xfer->setup); + _ctrl_xfer.buffer = xfer->buffer; + _ctrl_xfer.complete_cb = xfer->complete_cb; + _ctrl_xfer.user_data = xfer->user_data; } -} -//--------------------------------------------------------------------+ -// HCD Event Handler -//--------------------------------------------------------------------+ + usbh_unlock(); -void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) -{ - usbh_device_t const* dev = get_device(dev_addr); + TU_VERIFY(is_idle); + const uint8_t rhport = usbh_get_rhport(daddr); - if (dev) + TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request"); + TU_LOG2_VAR(&xfer->setup); + TU_LOG2("\r\n"); + + if (xfer->complete_cb) { - devtree_info->rhport = dev->rhport; - devtree_info->hub_addr = dev->hub_addr; - devtree_info->hub_port = dev->hub_port; - devtree_info->speed = dev->speed; + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) ); }else { - devtree_info->rhport = _dev0.rhport; - devtree_info->hub_addr = _dev0.hub_addr; - devtree_info->hub_port = _dev0.hub_port; - devtree_info->speed = _dev0.speed; + // blocking if complete callback is not provided + // change callback to internal blocking, and result as user argument + volatile xfer_result_t result = XFER_RESULT_INVALID; + + // use user_data to point to xfer_result_t + _ctrl_xfer.user_data = (uintptr_t) &result; + _ctrl_xfer.complete_cb = _control_blocking_complete_cb; + + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_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 + } + + // update transfer result + xfer->result = result; + xfer->actual_len = _ctrl_xfer.actual_len; } + + return true; } -void hcd_event_handler(hcd_event_t const* event, bool in_isr) +TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) { - switch (event->event_id) + usbh_lock(); + _ctrl_xfer.stage = stage; + usbh_unlock(); +} + +static void _xfer_complete(uint8_t daddr, xfer_result_t result) +{ + TU_LOG2("\r\n"); + + // duplicate xfer since user can execute control transfer within callback + tusb_control_request_t const request = _ctrl_xfer.request; + tuh_xfer_t xfer_temp = { - default: - osal_queue_send(_usbh_q, event, in_isr); - break; + .daddr = daddr, + .ep_addr = 0, + .result = result, + .setup = &request, + .actual_len = (uint32_t) _ctrl_xfer.actual_len, + .buffer = _ctrl_xfer.buffer, + .complete_cb = _ctrl_xfer.complete_cb, + .user_data = _ctrl_xfer.user_data + }; + + usbh_lock(); + _ctrl_xfer.stage = CONTROL_STAGE_IDLE; + usbh_unlock(); + + if (xfer_temp.complete_cb) + { + xfer_temp.complete_cb(&xfer_temp); } } -void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) +static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - hcd_event_t event = + (void) ep_addr; + + const uint8_t rhport = usbh_get_rhport(dev_addr); + tusb_control_request_t const * request = &_ctrl_xfer.request; + + if (XFER_RESULT_SUCCESS != result) { - .rhport = 0, // TODO correct rhport - .event_id = HCD_EVENT_XFER_COMPLETE, - .dev_addr = dev_addr, - .xfer_complete = + TU_LOG2("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED"); + + // terminate transfer if any stage failed + _xfer_complete(dev_addr, result); + }else + { + switch(_ctrl_xfer.stage) { - .ep_addr = ep_addr, - .result = result, - .len = xferred_bytes + case CONTROL_STAGE_SETUP: + if (request->wLength) + { + // DATA stage: initial data toggle is always 1 + _set_control_xfer_stage(CONTROL_STAGE_DATA); + return hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength); + } + __attribute__((fallthrough)); + + case CONTROL_STAGE_DATA: + if (xferred_bytes) + { + TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr); + TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2); + } + + _ctrl_xfer.actual_len = xferred_bytes; + + // ACK stage: toggle is always 1 + _set_control_xfer_stage(CONTROL_STAGE_ACK); + hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); + break; + + case CONTROL_STAGE_ACK: + _xfer_complete(dev_addr, result); + break; + + default: return false; } - }; + } - hcd_event_handler(&event, in_isr); + return true; } -void hcd_event_device_attach(uint8_t rhport, bool in_isr) +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +bool tuh_edpt_xfer(tuh_xfer_t* xfer) { - hcd_event_t event = - { - .rhport = rhport, - .event_id = HCD_EVENT_DEVICE_ATTACH - }; + TU_VERIFY(xfer->daddr && xfer->ep_addr); - event.connection.hub_addr = 0; - event.connection.hub_port = 0; - hcd_event_handler(&event, in_isr); + + return true; } -void hcd_event_device_remove(uint8_t hostid, bool in_isr) +//--------------------------------------------------------------------+ +// USBH API For Class Driver +//--------------------------------------------------------------------+ + +uint8_t usbh_get_rhport(uint8_t dev_addr) { - hcd_event_t event = - { - .rhport = hostid, - .event_id = HCD_EVENT_DEVICE_REMOVE - }; + usbh_device_t* dev = get_device(dev_addr); + return dev ? dev->rhport : _dev0.rhport; +} - event.connection.hub_addr = 0; - event.connection.hub_port = 0; +uint8_t* usbh_get_enum_buf(void) +{ + return _usbh_ctrl_buf; +} - hcd_event_handler(&event, in_isr); +void usbh_int_set(bool enabled) +{ + // TODO all host controller + if (enabled) + { + hcd_int_enable(TUH_OPT_RHPORT); + }else + { + hcd_int_disable(TUH_OPT_RHPORT); + } } //--------------------------------------------------------------------+ @@ -807,13 +679,14 @@ void hcd_event_device_remove(uint8_t hostid, bool in_isr) // TODO has some duplication code with device, refactor later bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr) { - usbh_device_t* dev = get_device(dev_addr); + usbh_device_t* dev = get_device(dev_addr); // addr0 only use tuh_control_xfer TU_ASSERT(dev); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir]; #if TUSB_OPT_MUTEX @@ -909,178 +782,302 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) } //--------------------------------------------------------------------+ -// Control transfer +// HCD Event Handler //--------------------------------------------------------------------+ -static void _control_blocking_complete_cb(tuh_xfer_t* xfer) +void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) { - // update result - *((xfer_result_t*) xfer->user_data) = xfer->result; + usbh_device_t const* dev = get_device(dev_addr); + + if (dev) + { + devtree_info->rhport = dev->rhport; + devtree_info->hub_addr = dev->hub_addr; + devtree_info->hub_port = dev->hub_port; + devtree_info->speed = dev->speed; + }else + { + devtree_info->rhport = _dev0.rhport; + devtree_info->hub_addr = _dev0.hub_addr; + devtree_info->hub_port = _dev0.hub_port; + devtree_info->speed = _dev0.speed; + } } -// TODO timeout_ms is not supported yet -bool tuh_control_xfer (tuh_xfer_t* xfer) +void hcd_event_handler(hcd_event_t const* event, bool in_isr) { - // EP0 with setup packet - TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); + switch (event->event_id) + { + default: + osal_queue_send(_usbh_q, event, in_isr); + break; + } +} - // pre-check to help reducing mutex lock - TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE); +void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) +{ + hcd_event_t event = + { + .rhport = 0, // TODO correct rhport + .event_id = HCD_EVENT_XFER_COMPLETE, + .dev_addr = dev_addr, + .xfer_complete = + { + .ep_addr = ep_addr, + .result = result, + .len = xferred_bytes + } + }; - uint8_t const daddr = xfer->daddr; + hcd_event_handler(&event, in_isr); +} - // TODO probably better to use semaphore as resource management than mutex - usbh_lock(); +void hcd_event_device_attach(uint8_t rhport, bool in_isr) +{ + hcd_event_t event = + { + .rhport = rhport, + .event_id = HCD_EVENT_DEVICE_ATTACH + }; - bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); - if (is_idle) + event.connection.hub_addr = 0; + event.connection.hub_port = 0; + + hcd_event_handler(&event, in_isr); +} + +void hcd_event_device_remove(uint8_t hostid, bool in_isr) +{ + hcd_event_t event = { - _ctrl_xfer.stage = CONTROL_STAGE_SETUP; - _ctrl_xfer.daddr = daddr; - _ctrl_xfer.actual_len = 0; + .rhport = hostid, + .event_id = HCD_EVENT_DEVICE_REMOVE + }; - _ctrl_xfer.request = (*xfer->setup); - _ctrl_xfer.buffer = xfer->buffer; - _ctrl_xfer.complete_cb = xfer->complete_cb; - _ctrl_xfer.user_data = xfer->user_data; - } + event.connection.hub_addr = 0; + event.connection.hub_port = 0; - usbh_unlock(); + hcd_event_handler(&event, in_isr); +} - TU_VERIFY(is_idle); - const uint8_t rhport = usbh_get_rhport(daddr); +//--------------------------------------------------------------------+ +// Descriptors Async +//--------------------------------------------------------------------+ - TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request"); - TU_LOG2_VAR(&xfer->setup); - TU_LOG2("\r\n"); +// generic helper to get a descriptor +// if blocking, user_data could be pointed to xfer_result +static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + tusb_control_request_t const 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(type, index) ), + .wIndex = tu_htole16(language_id), + .wLength = tu_htole16(len) + }; - if (xfer->complete_cb) + tuh_xfer_t xfer = { - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) ); - }else + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = buffer, + .complete_cb = complete_cb, + .user_data = user_data + }; + + bool const ret = tuh_control_xfer(&xfer); + + // if blocking, user_data could be pointed to xfer_result + if ( !complete_cb && user_data ) { - // blocking if complete callback is not provided - // change callback to internal blocking, and result as user argument - volatile xfer_result_t result = XFER_RESULT_INVALID; + *((xfer_result_t*) user_data) = xfer.result; + } - // use user_data to point to xfer_result_t - _ctrl_xfer.user_data = (uintptr_t) &result; - _ctrl_xfer.complete_cb = _control_blocking_complete_cb; + return ret; +} - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) ); +bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return _get_descriptor(daddr, type, index, 0x0000, buffer, len, complete_cb, user_data); +} - 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 +bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + len = tu_min16(len, sizeof(tusb_desc_device_t)); + return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb, user_data); +} - // TODO probably some timeout to prevent hanged - } +bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb, user_data); +} - // update transfer result - xfer->result = result; - xfer->actual_len = _ctrl_xfer.actual_len; - } +//------------- String Descriptor -------------// - return true; +bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data); } -TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) +// Get manufacturer string descriptor +bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - usbh_lock(); - _ctrl_xfer.stage = stage; - usbh_unlock(); + usbh_device_t const* dev = get_device(daddr); + TU_VERIFY(dev && dev->i_manufacturer); + return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_data); } -static void _xfer_complete(uint8_t daddr, xfer_result_t result) +// Get product string descriptor +bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG2("\r\n"); + usbh_device_t const* dev = get_device(daddr); + TU_VERIFY(dev && dev->i_product); + return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_data); +} - // duplicate xfer since user can execute control transfer within callback - tusb_control_request_t const request = _ctrl_xfer.request; - tuh_xfer_t xfer_temp = +// Get serial string descriptor +bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + usbh_device_t const* dev = get_device(daddr); + TU_VERIFY(dev && dev->i_serial); + return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, buffer, len, complete_cb, user_data); +} + +// Get HID report descriptor +// if blocking, user_data could be pointed to xfer_result +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_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_LOG2("HID Get Report Descriptor\r\n"); + tusb_control_request_t const request = + { + .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, index)), + .wIndex = tu_htole16((uint16_t) itf_num), + .wLength = len + }; + + tuh_xfer_t xfer = { .daddr = daddr, .ep_addr = 0, - .result = result, .setup = &request, - .actual_len = (uint32_t) _ctrl_xfer.actual_len, - .buffer = _ctrl_xfer.buffer, - .complete_cb = _ctrl_xfer.complete_cb, - .user_data = _ctrl_xfer.user_data + .buffer = buffer, + .complete_cb = complete_cb, + .user_data = user_data }; - usbh_lock(); - _ctrl_xfer.stage = CONTROL_STAGE_IDLE; - usbh_unlock(); + bool const ret = tuh_control_xfer(&xfer); - if (xfer_temp.complete_cb) + // if blocking, user_data could be pointed to xfer_result + if ( !complete_cb && user_data ) { - xfer_temp.complete_cb(&xfer_temp); + *((xfer_result_t*) user_data) = xfer.result; } + + return ret; } -static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) ep_addr; - - const uint8_t rhport = usbh_get_rhport(dev_addr); - tusb_control_request_t const * request = &_ctrl_xfer.request; + TU_LOG2("Set Configuration = %d\r\n", config_num); - if (XFER_RESULT_SUCCESS != result) + tusb_control_request_t const request = { - TU_LOG2("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED"); + .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 + }; - // terminate transfer if any stage failed - _xfer_complete(dev_addr, result); - }else + tuh_xfer_t xfer = { - switch(_ctrl_xfer.stage) - { - case CONTROL_STAGE_SETUP: - if (request->wLength) - { - // DATA stage: initial data toggle is always 1 - _set_control_xfer_stage(CONTROL_STAGE_DATA); - return hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength); - } - __attribute__((fallthrough)); + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data + }; - case CONTROL_STAGE_DATA: - if (xferred_bytes) - { - TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr); - TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2); - } + return tuh_control_xfer(&xfer); +} - _ctrl_xfer.actual_len = xferred_bytes; +//--------------------------------------------------------------------+ +// Descriptor Sync +//--------------------------------------------------------------------+ - // ACK stage: toggle is always 1 - _set_control_xfer_stage(CONTROL_STAGE_ACK); - hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); - break; +#define _CONTROL_SYNC_API(_async_func, ...) \ + xfer_result_t result = XFER_RESULT_INVALID;\ + TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \ + return (uint8_t) result - case CONTROL_STAGE_ACK: - _xfer_complete(dev_addr, result); - break; +uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) +{ + _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len); +} - default: return false; - } - } +uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len); +} - return true; +uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len); } -//--------------------------------------------------------------------+ -// -//--------------------------------------------------------------------+ +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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len); +} -bool tuh_edpt_xfer(tuh_xfer_t* xfer) +uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) { - (void) xfer; - return true; + _CONTROL_SYNC_API(tuh_descriptor_get_string, 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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, 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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_product_string, 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) +{ + _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len); } //--------------------------------------------------------------------+ |
