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:
@@ -52,21 +52,25 @@ enum {
|
|||||||
// Weak stubs: invoked if no strong implementation is available
|
// Weak stubs: invoked if no strong implementation is available
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
|
TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
|
||||||
(void) rhport;
|
(void) rhport; return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
|
TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
|
||||||
(void) rhport;
|
(void) rhport; (void) cfg_id; (void) cfg_param;
|
||||||
(void) cfg_id;
|
|
||||||
(void) cfg_param;
|
|
||||||
return false;
|
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) {
|
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
|
||||||
(void) rhport;
|
(void) rhport; (void) eventid; (void) in_isr;
|
||||||
(void) eventid;
|
|
||||||
(void) in_isr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) {
|
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_manufacturer;
|
||||||
uint8_t i_product;
|
uint8_t i_product;
|
||||||
uint8_t i_serial;
|
uint8_t i_serial;
|
||||||
|
uint8_t bNumConfigurations;
|
||||||
|
|
||||||
// Configuration Descriptor
|
// Configuration Descriptor
|
||||||
// uint8_t interface_count; // bNumInterfaces alias
|
// 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 { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
|
||||||
enum { CONFIG_NUM = 1 }; // default to use configuration 1
|
|
||||||
|
|
||||||
// Additional class drivers implemented by application
|
// Additional class drivers implemented by application
|
||||||
tu_static usbh_class_driver_t const * _app_driver = NULL;
|
tu_static usbh_class_driver_t const * _app_driver = NULL;
|
||||||
@@ -1372,8 +1376,8 @@ enum {
|
|||||||
ENUM_CONFIG_DRIVER
|
ENUM_CONFIG_DRIVER
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool enum_request_set_addr(void);
|
static bool enum_request_set_addr(tusb_desc_device_t const* desc_device);
|
||||||
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);
|
||||||
static void enum_full_complete(void);
|
static void enum_full_complete(void);
|
||||||
|
|
||||||
// process device enumeration
|
// process device enumeration
|
||||||
@@ -1489,7 +1493,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case ENUM_SET_ADDR:
|
case ENUM_SET_ADDR:
|
||||||
enum_request_set_addr();
|
enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ENUM_GET_DEVICE_DESC: {
|
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_manufacturer = desc_device->iManufacturer;
|
||||||
dev->i_product = desc_device->iProduct;
|
dev->i_product = desc_device->iProduct;
|
||||||
dev->i_serial = desc_device->iSerialNumber;
|
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,
|
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
|
||||||
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
|
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
|
||||||
@@ -1574,8 +1581,8 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
|
|
||||||
case ENUM_GET_9BYTE_CONFIG_DESC: {
|
case ENUM_GET_9BYTE_CONFIG_DESC: {
|
||||||
// Get 9-byte for total length
|
// Get 9-byte for total length
|
||||||
uint8_t const config_idx = CONFIG_NUM - 1;
|
uint8_t const config_idx = 0;
|
||||||
TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n");
|
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,
|
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
|
||||||
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
|
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
|
||||||
break;
|
break;
|
||||||
@@ -1585,25 +1592,32 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
uint8_t const* desc_config = _usbh_epbuf.ctrl;
|
uint8_t const* desc_config = _usbh_epbuf.ctrl;
|
||||||
|
|
||||||
// Use offsetof to avoid pointer to the odd/misaligned address
|
// Use offsetof to avoid pointer to the odd/misaligned address
|
||||||
uint16_t const total_len = tu_le16toh(
|
uint16_t const total_len = tu_le16toh(tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
|
||||||
tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
|
|
||||||
|
|
||||||
// TODO not enough buffer to hold configuration descriptor
|
// TODO not enough buffer to hold configuration descriptor
|
||||||
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE,);
|
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE,);
|
||||||
|
|
||||||
// Get full configuration descriptor
|
// Get full configuration descriptor
|
||||||
uint8_t const config_idx = CONFIG_NUM - 1;
|
uint8_t const config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||||
TU_LOG_USBH("Get Configuration[0] Descriptor\r\n");
|
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,
|
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len,
|
||||||
process_enumeration, ENUM_SET_CONFIG),);
|
process_enumeration, ENUM_SET_CONFIG),);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ENUM_SET_CONFIG:
|
case ENUM_SET_CONFIG: {
|
||||||
// tuh_desc_configuration_cb(daddr, CONFIG_NUM-1, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl);
|
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_NUM, process_enumeration, ENUM_CONFIG_DRIVER),);
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ENUM_CONFIG_DRIVER: {
|
case ENUM_CONFIG_DRIVER: {
|
||||||
TU_LOG_USBH("Device configured\r\n");
|
TU_LOG_USBH("Device configured\r\n");
|
||||||
@@ -1613,7 +1627,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||||||
|
|
||||||
// Parse configuration & set up drivers
|
// Parse configuration & set up drivers
|
||||||
// driver_open() must not make any usb transfer
|
// 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)
|
// 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.
|
// 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:
|
default:
|
||||||
// stop enumeration if unknown state
|
enum_full_complete(); // stop enumeration if unknown state
|
||||||
enum_full_complete();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool enum_new_device(hcd_event_t* event) {
|
static bool enum_new_device(hcd_event_t* event) {
|
||||||
_dev0.rhport = event->rhport;
|
_dev0.rhport = event->rhport;
|
||||||
_dev0.hub_addr = event->connection.hub_addr;
|
_dev0.hub_addr = event->connection.hub_addr;
|
||||||
@@ -1701,9 +1712,7 @@ static uint8_t get_new_address(bool is_hub) {
|
|||||||
return 0; // invalid address
|
return 0; // invalid address
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool enum_request_set_addr(void) {
|
static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) {
|
||||||
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
|
|
||||||
|
|
||||||
// Get new address
|
// Get new address
|
||||||
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
||||||
TU_ASSERT(new_addr != 0);
|
TU_ASSERT(new_addr != 0);
|
||||||
@@ -1741,7 +1750,7 @@ static bool enum_request_set_addr(void) {
|
|||||||
return true;
|
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);
|
usbh_device_t* dev = get_device(dev_addr);
|
||||||
uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength);
|
uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength);
|
||||||
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len;
|
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);
|
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
|
||||||
}else {
|
}else {
|
||||||
// Invoke callback if available
|
// Invoke callback if available
|
||||||
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
if (tuh_mount_cb) {
|
||||||
|
tuh_mount_cb(dev_addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -100,10 +100,13 @@ typedef union {
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
// Invoked when enumeration get device descriptor
|
// 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
|
// 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)
|
// Invoked when a device is mounted (configured)
|
||||||
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
|
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
|
||||||
|
Reference in New Issue
Block a user