host: add tuh_enum_descriptor_device_cb() and tuh_enum_descriptor_configuration_cb() callback

host: support device with multiple configurations
This commit is contained in:
hathach
2025-03-24 22:55:04 +07:00
parent e54753814b
commit 9f541a3d96
2 changed files with 48 additions and 34 deletions

View File

@@ -52,21 +52,25 @@ enum {
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
(void) rhport;
return false;
(void) rhport; return false;
}
TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
(void) rhport;
(void) cfg_id;
(void) cfg_param;
(void) rhport; (void) cfg_id; (void) cfg_param;
return false;
}
TU_ATTR_WEAK void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device) {
(void) daddr; (void) desc_device;
}
TU_ATTR_WEAK bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config) {
(void) daddr; (void) cfg_index; (void) desc_config;
return true;
}
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
(void) rhport;
(void) eventid;
(void) in_isr;
(void) rhport; (void) eventid; (void) in_isr;
}
TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) {
@@ -126,6 +130,7 @@ typedef struct {
uint8_t i_manufacturer;
uint8_t i_product;
uint8_t i_serial;
uint8_t bNumConfigurations;
// Configuration Descriptor
// uint8_t interface_count; // bNumInterfaces alias
@@ -230,7 +235,6 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
};
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
enum { CONFIG_NUM = 1 }; // default to use configuration 1
// Additional class drivers implemented by application
tu_static usbh_class_driver_t const * _app_driver = NULL;
@@ -1372,8 +1376,8 @@ enum {
ENUM_CONFIG_DRIVER
};
static bool enum_request_set_addr(void);
static bool _parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
static bool enum_request_set_addr(tusb_desc_device_t const* desc_device);
static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
static void enum_full_complete(void);
// process device enumeration
@@ -1489,7 +1493,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
#endif
case ENUM_SET_ADDR:
enum_request_set_addr();
enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl);
break;
case ENUM_GET_DEVICE_DESC: {
@@ -1523,6 +1527,9 @@ static void process_enumeration(tuh_xfer_t* xfer) {
dev->i_manufacturer = desc_device->iManufacturer;
dev->i_product = desc_device->iProduct;
dev->i_serial = desc_device->iSerialNumber;
dev->bNumConfigurations = desc_device->bNumConfigurations;
tuh_enum_descriptor_device_cb(daddr, desc_device); // callback
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
@@ -1574,8 +1581,8 @@ static void process_enumeration(tuh_xfer_t* xfer) {
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");
uint8_t const config_idx = 0;
TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx);
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
break;
@@ -1585,25 +1592,32 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const* desc_config = _usbh_epbuf.ctrl;
// Use offsetof to avoid pointer to the odd/misaligned address
uint16_t const total_len = tu_le16toh(
tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
uint16_t const total_len = tu_le16toh(tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
// TODO not enough buffer to hold configuration descriptor
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE,);
// Get full configuration descriptor
uint8_t const config_idx = CONFIG_NUM - 1;
TU_LOG_USBH("Get Configuration[0] Descriptor\r\n");
uint8_t const config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex);
TU_LOG_USBH("Get Configuration[%u] Descriptor\r\n", config_idx);
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len,
process_enumeration, ENUM_SET_CONFIG),);
break;
}
case ENUM_SET_CONFIG:
// tuh_desc_configuration_cb(daddr, CONFIG_NUM-1, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl);
TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),);
case ENUM_SET_CONFIG: {
uint8_t config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex);
if (tuh_enum_descriptor_configuration_cb(daddr, config_idx, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl)) {
TU_ASSERT(tuh_configuration_set(daddr, config_idx+1, process_enumeration, ENUM_CONFIG_DRIVER),);
} else {
config_idx++;
TU_ASSERT(config_idx < dev->bNumConfigurations,);
TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx);
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
}
break;
}
case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n");
@@ -1613,7 +1627,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// Parse configuration & set up drivers
// driver_open() must not make any usb transfer
TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
TU_ASSERT(enum_parse_configuration_desc(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
// Start the Set Configuration process for interfaces (itf = TUSB_INDEX_INVALID_8)
// Since driver can perform control transfer within its set_config, this is done asynchronously.
@@ -1624,14 +1638,11 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
default:
// stop enumeration if unknown state
enum_full_complete();
enum_full_complete(); // stop enumeration if unknown state
break;
}
}
static bool enum_new_device(hcd_event_t* event) {
_dev0.rhport = event->rhport;
_dev0.hub_addr = event->connection.hub_addr;
@@ -1701,9 +1712,7 @@ static uint8_t get_new_address(bool is_hub) {
return 0; // invalid address
}
static bool enum_request_set_addr(void) {
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) {
// Get new address
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
TU_ASSERT(new_addr != 0);
@@ -1741,7 +1750,7 @@ static bool enum_request_set_addr(void) {
return true;
}
static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) {
static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) {
usbh_device_t* dev = get_device(dev_addr);
uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength);
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len;
@@ -1858,7 +1867,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
}else {
// Invoke callback if available
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
if (tuh_mount_cb) {
tuh_mount_cb(dev_addr);
}
}
}
}

View File

@@ -100,10 +100,13 @@ typedef union {
//--------------------------------------------------------------------+
// Invoked when enumeration get device descriptor
// TU_ATTR_WEAK void tuh_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device);
// Device is not ready to communicate yet, application can copy the descriptor if needed
void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device);
// Invoked when enumeration get configuration descriptor
// TU_ATTR_WEAK void tuh_desc_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config);
// For multi-configuration device return false to skip, true to proceed with this configuration (may not be implemented yet)
// Device is not ready to communicate yet, application can copy the descriptor if needed
bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config);
// Invoked when a device is mounted (configured)
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);