summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2022-03-18 18:04:25 +0700
committerhathach <[email protected]>2022-03-18 18:04:25 +0700
commit9ae0304b1ecd8d10f96a39c5c88a43d6b7c43681 (patch)
treeaf7f7bce60709a836d2772dce47a0b6fd0f1ea7e /src
parent8750e3b57756e4377bb737c578e2742b653c314c (diff)
move code around
Diffstat (limited to 'src')
-rw-r--r--src/host/usbh.c819
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);
}
//--------------------------------------------------------------------+