blob: e0efa4e11525aea9c3543b3dfff46a2f6660c42f [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/tc_util.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/usb/usb_device.h>
#include <usb_descriptor.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(test_main, LOG_LEVEL_DBG);
#ifdef CONFIG_USB_COMPOSITE_DEVICE
#error Do not use composite configuration
#endif
/* 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_cfg_data_list_start[];
extern struct usb_cfg_data _usb_cfg_data_list_end[];
uint8_t *usb_get_device_descriptor(void);
struct usb_test_config {
struct usb_if_descriptor if0;
struct usb_ep_descriptor if0_out_ep;
struct usb_ep_descriptor if0_in1_ep;
struct usb_ep_descriptor if0_in2_ep;
} __packed;
#if IS_ENABLED(CONFIG_USB_DC_HAS_HS_SUPPORT)
#define TEST_BULK_EP_MPS 512
#else
#define TEST_BULK_EP_MPS 64
#endif
#define TEST_DESCRIPTOR_TABLE_SPAN 157
#define INITIALIZER_IF \
{ \
.bLength = sizeof(struct usb_if_descriptor), \
.bDescriptorType = USB_DESC_INTERFACE, \
.bInterfaceNumber = 0, \
.bAlternateSetting = 0, \
.bNumEndpoints = 3, \
.bInterfaceClass = USB_BCC_VENDOR, \
.bInterfaceSubClass = 0, \
.bInterfaceProtocol = 0, \
.iInterface = 0, \
}
#define INITIALIZER_IF_EP(addr, attr, mps) \
{ \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = addr, \
.bmAttributes = attr, \
.wMaxPacketSize = sys_cpu_to_le16(mps), \
.bInterval = 0x00, \
}
#define DEFINE_TEST_DESC(x, _) \
USBD_CLASS_DESCR_DEFINE(primary, x) \
struct usb_test_config test_cfg_##x = { \
.if0 = INITIALIZER_IF, \
.if0_out_ep = INITIALIZER_IF_EP(AUTO_EP_OUT, \
USB_DC_EP_BULK, \
TEST_BULK_EP_MPS), \
.if0_in1_ep = INITIALIZER_IF_EP(AUTO_EP_IN, \
USB_DC_EP_BULK, \
TEST_BULK_EP_MPS), \
.if0_in2_ep = INITIALIZER_IF_EP(AUTO_EP_IN, \
USB_DC_EP_BULK, \
TEST_BULK_EP_MPS), \
}
#define INITIALIZER_EP_DATA(cb, addr) \
{ \
.ep_cb = cb, \
.ep_addr = addr, \
}
#define DEFINE_TEST_EP_CFG(x, _) \
static struct usb_ep_cfg_data ep_cfg_##x[] = { \
INITIALIZER_EP_DATA(NULL, AUTO_EP_OUT), \
INITIALIZER_EP_DATA(NULL, AUTO_EP_IN), \
INITIALIZER_EP_DATA(NULL, AUTO_EP_IN), \
}
#define DEFINE_TEST_CFG_DATA(x, _) \
USBD_DEFINE_CFG_DATA(test_config_##x) = { \
.usb_device_description = NULL, \
.interface_config = interface_config, \
.interface_descriptor = &test_cfg_##x.if0, \
.cb_usb_status = NULL, \
.interface = { \
.class_handler = NULL, \
.custom_handler = NULL, \
.vendor_handler = NULL, \
}, \
.num_endpoints = ARRAY_SIZE(ep_cfg_##x), \
.endpoint = ep_cfg_##x, \
}
#define NUM_INSTANCES 2
static void interface_config(struct usb_desc_header *head,
uint8_t iface_num)
{
struct usb_if_descriptor *if_desc = (struct usb_if_descriptor *)head;
LOG_DBG("head %p iface_num %u", head, iface_num);
if_desc->bInterfaceNumber = iface_num;
}
LISTIFY(NUM_INSTANCES, DEFINE_TEST_DESC, (;), _);
LISTIFY(NUM_INSTANCES, DEFINE_TEST_EP_CFG, (;), _);
LISTIFY(NUM_INSTANCES, DEFINE_TEST_CFG_DATA, (;), _);
static struct usb_cfg_data *usb_get_cfg_data(struct usb_if_descriptor *iface)
{
STRUCT_SECTION_FOREACH(usb_cfg_data, cfg_data) {
if (cfg_data->interface_descriptor == iface) {
return cfg_data;
}
}
return NULL;
}
static bool find_cfg_data_ep(const struct usb_ep_descriptor * const ep_descr,
const struct usb_cfg_data * const cfg_data,
uint8_t ep_count)
{
for (int i = 0; i < cfg_data->num_endpoints; i++) {
if (cfg_data->endpoint[i].ep_addr ==
ep_descr->bEndpointAddress) {
LOG_DBG("found ep[%d] %x", i,
ep_descr->bEndpointAddress);
if (ep_count != i) {
LOG_ERR("EPs are assigned in wrong order");
return false;
}
return true;
}
}
return false;
}
static void check_endpoint_allocation(struct usb_desc_header *head)
{
struct usb_cfg_data *cfg_data = NULL;
static uint8_t interfaces;
uint8_t ep_count = 0;
while (head->bLength != 0) {
if (head->bDescriptorType == USB_DESC_INTERFACE) {
struct usb_if_descriptor *if_descr = (void *)head;
ep_count = 0;
LOG_DBG("iface %u", if_descr->bInterfaceNumber);
/* Check that interfaces get correct numbers */
zassert_equal(if_descr->bInterfaceNumber, interfaces,
"Interfaces numbering failed");
interfaces++;
cfg_data = usb_get_cfg_data(if_descr);
zassert_not_null(cfg_data, "Check available cfg data");
}
if (head->bDescriptorType == USB_DESC_ENDPOINT) {
struct usb_ep_descriptor *ep_descr =
(struct usb_ep_descriptor *)head;
/* Check that we get iface desc before */
zassert_not_null(cfg_data, "Check available cfg data");
zassert_true(find_cfg_data_ep(ep_descr, cfg_data,
ep_count),
"Check endpoint config in cfg_data");
ep_count++;
}
head = (struct usb_desc_header *)((uint8_t *)head + head->bLength);
}
}
/* Determine the number of bytes spanned between two linker-defined
* symbols that are normally interpreted as pointers.
*/
#define SYMBOL_SPAN(_ep, _sp) (int)(intptr_t)((uintptr_t)(_ep) - (uintptr_t)(_sp))
ZTEST(desc_sections, test_desc_sections)
{
struct usb_desc_header *head;
TC_PRINT("__usb_descriptor_start %p\n", __usb_descriptor_start);
TC_PRINT("__usb_descriptor_end %p\n", __usb_descriptor_end);
TC_PRINT("USB Descriptor table span %d\n",
SYMBOL_SPAN(__usb_descriptor_end, __usb_descriptor_start));
TC_PRINT("_usb_cfg_data_list_start %p\n", _usb_cfg_data_list_start);
TC_PRINT("_usb_cfg_data_list_end %p\n", _usb_cfg_data_list_end);
TC_PRINT("USB Configuration data span %d\n",
SYMBOL_SPAN(_usb_cfg_data_list_end, _usb_cfg_data_list_start));
TC_PRINT("sizeof usb_cfg_data %zu\n", sizeof(struct usb_cfg_data));
LOG_DBG("Starting logs");
LOG_HEXDUMP_DBG((uint8_t *)__usb_descriptor_start,
SYMBOL_SPAN(__usb_descriptor_end, __usb_descriptor_start),
"USB Descriptor table section");
LOG_HEXDUMP_DBG((uint8_t *)_usb_cfg_data_list_start,
SYMBOL_SPAN(_usb_cfg_data_list_end, _usb_cfg_data_list_start),
"USB Configuration structures section");
head = (struct usb_desc_header *)__usb_descriptor_start;
zassert_not_null(head, NULL);
zassert_equal(SYMBOL_SPAN(__usb_descriptor_end, __usb_descriptor_start),
TEST_DESCRIPTOR_TABLE_SPAN, NULL);
/* Calculate number of structures */
zassert_equal(_usb_cfg_data_list_end - _usb_cfg_data_list_start,
NUM_INSTANCES, NULL);
zassert_equal(SYMBOL_SPAN(_usb_cfg_data_list_end, _usb_cfg_data_list_start),
NUM_INSTANCES * sizeof(struct usb_cfg_data), NULL);
check_endpoint_allocation(head);
}
/*test case main entry*/
ZTEST_SUITE(desc_sections, NULL, NULL, NULL, NULL, NULL);