summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-03-03 23:22:23 +0700
committerhathach <[email protected]>2025-03-03 23:22:23 +0700
commit5f447b76ad23e8c977a5167b0b4dce93cd2980de (patch)
tree70f0c1a6e0a180628cbbfacbd3bad0ba0bc3daf4 /src
parent93ff3daa116471e41615b85cd7d466cc48bc2148 (diff)
- add tuh_descriptor_get_string_langid() API
- host enumeration always get language id, manufacturer, product and serial string. Which is required by some device such as 8bitdo
Diffstat (limited to 'src')
-rw-r--r--src/common/tusb_types.h2
-rw-r--r--src/host/hub.c5
-rw-r--r--src/host/usbh.c95
-rw-r--r--src/host/usbh.h13
4 files changed, 91 insertions, 24 deletions
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index 42ce5fc12..71af132af 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -462,7 +462,7 @@ TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes
uint8_t bDescriptorType ; ///< Descriptor Type
- uint16_t unicode_string[];
+ uint16_t utf16le[];
} tusb_desc_string_t;
// USB Binary Device Object Store (BOS)
diff --git a/src/host/hub.c b/src/host/hub.c
index 93b4a3a84..61efa8ba5 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -46,7 +46,7 @@ typedef struct {
// from hub descriptor
uint8_t bNbrPorts;
- uint8_t bPwrOn2PwrGood; // port power on to good, in 2ms unit
+ uint8_t bPwrOn2PwrGood_2ms; // port power on to good, in 2ms unit
// uint16_t wHubCharacteristics;
hub_port_status_response_t port_status;
@@ -279,7 +279,7 @@ static void config_set_port_power (tuh_xfer_t* xfer) {
// only use number of ports in hub descriptor
hub_desc_cs_t const* desc_hub = (hub_desc_cs_t const*) p_epbuf->ctrl_buf;
p_hub->bNbrPorts = desc_hub->bNbrPorts;
- p_hub->bPwrOn2PwrGood = desc_hub->bPwrOn2PwrGood;
+ p_hub->bPwrOn2PwrGood_2ms = desc_hub->bPwrOn2PwrGood;
// May need to GET_STATUS
@@ -301,7 +301,6 @@ static void config_port_power_complete (tuh_xfer_t* xfer) {
TU_MESS_FAILED();
TU_BREAKPOINT();
}
- // delay bPwrOn2PwrGood * 2 ms before set configuration complete
usbh_driver_set_config_complete(daddr, p_hub->itf_num);
} else {
// power next port
diff --git a/src/host/usbh.c b/src/host/usbh.c
index c7a9a868f..dcd22ee31 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -1282,13 +1282,17 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
} else {
// Invoke callback before closing driver (maybe call it later ?)
- if (tuh_umount_cb) tuh_umount_cb(daddr);
+ if (tuh_umount_cb) {
+ tuh_umount_cb(daddr);
+ }
}
// Close class driver
for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
usbh_class_driver_t const* driver = get_driver(drv_id);
- if (driver) driver->close(daddr);
+ if (driver) {
+ driver->close(daddr);
+ }
}
hcd_device_close(rhport, daddr);
@@ -1345,8 +1349,11 @@ enum {
ENUM_HUB_GET_STATUS_2,
ENUM_HUB_CLEAR_RESET_2,
ENUM_SET_ADDR,
-
ENUM_GET_DEVICE_DESC,
+ ENUM_GET_STRING_LANGUAGE_ID,
+ ENUM_GET_STRING_MANUFACTURER,
+ ENUM_GET_STRING_PRODUCT,
+ ENUM_GET_STRING_SERIAL,
ENUM_GET_9BYTE_CONFIG_DESC,
ENUM_GET_FULL_CONFIG_DESC,
ENUM_SET_CONFIG,
@@ -1359,25 +1366,25 @@ static void enum_full_complete(void);
// process device enumeration
static void process_enumeration(tuh_xfer_t* xfer) {
- // Retry a few times with transfers in enumeration since device can be unstable when starting up
- enum {
- ATTEMPT_COUNT_MAX = 3,
- ATTEMPT_DELAY_MS = 100
- };
+ // Retry a few times while enumerating since device can be unstable when starting up
static uint8_t failed_count = 0;
+ if (XFER_RESULT_FAILED == xfer->result) {
+ enum {
+ ATTEMPT_COUNT_MAX = 3,
+ ATTEMPT_DELAY_MS = 100
+ };
- if (XFER_RESULT_SUCCESS != xfer->result) {
// retry if not reaching max attempt
+ failed_count++;
bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX);
- if ( retry ) {
- failed_count++;
+ if (retry) {
tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit
- TU_LOG1("Enumeration attempt %u\r\n", failed_count);
+ TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX);
retry = tuh_control_xfer(xfer);
}
if (!retry) {
- enum_full_complete();
+ enum_full_complete(); // complete as failed
}
return;
@@ -1386,6 +1393,8 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const daddr = xfer->daddr;
uintptr_t const state = xfer->user_data;
+ usbh_device_t* dev = get_device(daddr);
+ uint16_t langid = 0x0409; // default is English
switch (state) {
#if CFG_TUH_HUB
@@ -1476,7 +1485,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
tusb_time_delay_ms_api(2);
const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
-
usbh_device_t* new_dev = get_device(new_addr);
TU_ASSERT(new_dev,);
new_dev->addressed = 1;
@@ -1490,21 +1498,69 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// Get full device descriptor
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
- process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC),);
+ process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),);
break;
}
- case ENUM_GET_9BYTE_CONFIG_DESC: {
- tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
- usbh_device_t* dev = get_device(daddr);
+ case ENUM_GET_STRING_LANGUAGE_ID: {
+ // save the received device descriptor
TU_ASSERT(dev,);
-
+ tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
dev->vid = desc_device->idVendor;
dev->pid = desc_device->idProduct;
dev->i_manufacturer = desc_device->iManufacturer;
dev->i_product = desc_device->iProduct;
dev->i_serial = desc_device->iSerialNumber;
+ tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
+ process_enumeration, ENUM_GET_STRING_MANUFACTURER);
+ break;
+ }
+
+ case ENUM_GET_STRING_MANUFACTURER: {
+ TU_ASSERT(dev,);
+ const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl;
+ if (desc_langid->bLength >= 4) {
+ langid = tu_le16toh(desc_langid->utf16le[0]);
+ }
+ if (dev->i_manufacturer != 0) {
+ tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
+ process_enumeration, ENUM_GET_STRING_PRODUCT);
+ break;
+ } else {
+ TU_ATTR_FALLTHROUGH;
+ }
+ }
+
+ case ENUM_GET_STRING_PRODUCT: {
+ TU_ASSERT(dev,);
+ if (state == ENUM_GET_STRING_PRODUCT) {
+ langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
+ }
+ if (dev->i_product != 0) {
+ tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
+ process_enumeration, ENUM_GET_STRING_SERIAL);
+ break;
+ } else {
+ TU_ATTR_FALLTHROUGH;
+ }
+ }
+
+ case ENUM_GET_STRING_SERIAL: {
+ TU_ASSERT(dev,);
+ if (state == ENUM_GET_STRING_SERIAL) {
+ langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
+ }
+ if (dev->i_serial != 0) {
+ tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
+ process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
+ break;
+ } else {
+ TU_ATTR_FALLTHROUGH;
+ }
+ }
+
+ case ENUM_GET_9BYTE_CONFIG_DESC: {
// Get 9-byte for total length
uint8_t const config_idx = CONFIG_NUM - 1;
TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n");
@@ -1537,7 +1593,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n");
- usbh_device_t* dev = get_device(daddr);
TU_ASSERT(dev,);
dev->configured = 1;
diff --git a/src/host/usbh.h b/src/host/usbh.h
index c8b137173..0fbe39743 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -265,6 +265,13 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_
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);
+// Get language id string descriptor (control transfer)
+TU_ATTR_ALWAYS_INLINE static inline
+bool tuh_descriptor_get_string_langid(uint8_t daddr, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ return tuh_descriptor_get_string(daddr, 0, 0, buffer, len, complete_cb, user_data);
+}
+
// 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,
@@ -304,6 +311,12 @@ uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8
// 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);
+// Sync (blocking) version of tuh_descriptor_get_string_langid()
+TU_ATTR_ALWAYS_INLINE static inline
+uint8_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
+ return tuh_descriptor_get_string_sync(daddr, 0, 0, buffer, len);
+}
+
// 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);