subsys: usb: validate and update endpoint address

Add the routine to validate endpoint address and update the endpoint
descriptors and usb_ep_cfg_data at runtime.

Signed-off-by: Johann Fischer <j.fischer@phytec.de>
This commit is contained in:
Johann Fischer 2018-04-17 11:49:18 +02:00 committed by Carles Cufí
commit bf332d0004
2 changed files with 100 additions and 0 deletions

View file

@ -167,6 +167,8 @@ struct usb_cfg_data {
* http://www.beyondlogic.org/usbnutshell/usb5.shtml#DeviceDescriptors
*/
const u8_t *usb_device_description;
/** Pointer to interface descriptor */
const void *interface_descriptor;
/** Callback to be notified on USB connection status change */
usb_status_callback cb_usb_status;
/** USB interface (Class) handler and storage space */

View file

@ -35,6 +35,8 @@
/* Linker-defined symbols bound the USB descriptor structs */
extern struct usb_desc_header __usb_descriptor_start[];
extern struct usb_desc_header __usb_descriptor_end[];
extern struct usb_cfg_data __usb_data_start[];
extern struct usb_cfg_data __usb_data_end[];
/* Structure representing the global USB description */
struct common_descriptor {
@ -172,6 +174,82 @@ static void ascii7_to_utf16le(void *descriptor)
}
}
/*
* Validate endpoint address and Update the endpoint descriptors at runtime,
* the result depends on the capabilities of the driver and the number and
* type of endpoints.
* The default endpoint address is stored in endpoint descriptor and
* usb_ep_cfg_data, so both variables bEndpointAddress and ep_addr need
* to be updated.
*/
static int usb_validate_ep_cfg_data(struct usb_ep_descriptor * const ep_descr,
struct usb_cfg_data * const cfg_data,
u32_t *requested_ep)
{
for (int i = 0; i < cfg_data->num_endpoints; i++) {
struct usb_ep_cfg_data *ep_data = cfg_data->endpoint;
/*
* Trying to find the right entry in the usb_ep_cfg_data.
*/
if (ep_descr->bEndpointAddress != ep_data[i].ep_addr) {
continue;
}
for (u8_t idx = 1; idx < 16; idx++) {
struct usb_dc_ep_cfg_data ep_cfg;
ep_cfg.ep_type = ep_descr->bmAttributes;
ep_cfg.ep_mps = ep_descr->wMaxPacketSize;
ep_cfg.ep_addr = ep_descr->bEndpointAddress;
if (ep_cfg.ep_addr & USB_EP_DIR_IN) {
if ((*requested_ep & (1 << (idx + 16)))) {
continue;
}
ep_cfg.ep_addr = (USB_EP_DIR_IN | idx);
} else {
if ((*requested_ep & (1 << (idx)))) {
continue;
}
ep_cfg.ep_addr = idx;
}
if (!usb_dc_ep_check_cap(&ep_cfg)) {
ep_descr->bEndpointAddress = ep_cfg.ep_addr;
ep_data[i].ep_addr = ep_cfg.ep_addr;
if (ep_cfg.ep_addr & USB_EP_DIR_IN) {
*requested_ep |= (1 << (idx + 16));
} else {
*requested_ep |= (1 << idx);
}
SYS_LOG_DBG("endpoint 0x%x",
ep_data[i].ep_addr);
return 0;
}
}
}
return -1;
}
/*
* The interface descriptor of a USB function must be assigned to the
* usb_cfg_data so that usb_ep_cfg_data and matching endpoint descriptor
* can be found.
*/
static struct usb_cfg_data *usb_get_cfg_data(struct usb_if_descriptor *iface)
{
size_t length = (__usb_data_end - __usb_data_start);
for (size_t i = 0; i < length; i++) {
if (__usb_data_start[i].interface_descriptor == iface) {
return &__usb_data_start[i];
}
}
return NULL;
}
/*
* The entire descriptor, placed in the .usb.descriptor section,
* needs to be fixed before use. Currently, only the length of the
@ -186,8 +264,11 @@ static int usb_fix_descriptor(struct usb_desc_header *head)
{
struct usb_cfg_descriptor *cfg_descr = NULL;
struct usb_if_descriptor *if_descr = NULL;
struct usb_cfg_data *cfg_data = NULL;
struct usb_ep_descriptor *ep_descr = NULL;
u8_t numof_ifaces = 0;
u8_t str_descr_idx = 0;
u32_t requested_ep = BIT(16) | BIT(0);
while (head->bLength != 0) {
switch (head->bDescriptorType) {
@ -206,10 +287,27 @@ static int usb_fix_descriptor(struct usb_desc_header *head)
break;
}
if (if_descr->bInterfaceNumber == 0) {
cfg_data = usb_get_cfg_data(if_descr);
if (!cfg_data) {
SYS_LOG_ERR("There is no usb_cfg_data "
"for %p", head);
return -1;
}
}
numof_ifaces++;
break;
case USB_ENDPOINT_DESC:
SYS_LOG_DBG("Endpoint descriptor %p", head);
ep_descr = (struct usb_ep_descriptor *)head;
if (usb_validate_ep_cfg_data(ep_descr,
cfg_data,
&requested_ep)) {
SYS_LOG_ERR("Failed to validate endpoints");
return -1;
}
break;
case 0:
case USB_STRING_DESC: