blob: 4961985f256b4a0b6cfeea09b458ea3637948e82 [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <ztest.h>
#include <tc_util.h>
#include <misc/byteorder.h>
#include <usb/usb_device.h>
#include <usb/usb_common.h>
#define LOG_LEVEL LOG_LEVEL_DBG
#include <logging/log.h>
LOG_MODULE_REGISTER(test_main);
#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_data_start[];
extern struct usb_cfg_data __usb_data_end[];
u8_t *usb_get_device_descriptor(void);
struct usb_loopback_config {
struct usb_if_descriptor if0;
struct usb_ep_descriptor if0_out_ep;
struct usb_ep_descriptor if0_in_ep;
struct usb_ep_descriptor if0_in2_ep;
} __packed;
#define LOOPBACK_OUT_EP_ADDR 0x01
#define LOOPBACK_IN_EP_ADDR 0x81
#define LOOPBACK_BULK_EP_MPS 64
#define INITIALIZER_IF \
{ \
.bLength = sizeof(struct usb_if_descriptor), \
.bDescriptorType = USB_INTERFACE_DESC, \
.bInterfaceNumber = 0, \
.bAlternateSetting = 0, \
.bNumEndpoints = 2, \
.bInterfaceClass = CUSTOM_CLASS, \
.bInterfaceSubClass = 0, \
.bInterfaceProtocol = 0, \
.iInterface = 0, \
}
#define INITIALIZER_IF_EP(addr, attr, mps) \
{ \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_ENDPOINT_DESC, \
.bEndpointAddress = addr, \
.bmAttributes = attr, \
.wMaxPacketSize = sys_cpu_to_le16(mps), \
.bInterval = 0x00, \
}
#define DEFINE_LOOPBACK_DESC(x, _) \
USBD_CLASS_DESCR_DEFINE(primary, x) \
struct usb_loopback_config loopback_cfg_##x = { \
.if0 = INITIALIZER_IF, \
.if0_out_ep = INITIALIZER_IF_EP(LOOPBACK_OUT_EP_ADDR, \
USB_DC_EP_BULK, \
LOOPBACK_BULK_EP_MPS), \
.if0_in_ep = INITIALIZER_IF_EP(LOOPBACK_IN_EP_ADDR, \
USB_DC_EP_BULK, \
LOOPBACK_BULK_EP_MPS), \
.if0_in2_ep = INITIALIZER_IF_EP(LOOPBACK_IN_EP_ADDR, \
USB_DC_EP_BULK, \
LOOPBACK_BULK_EP_MPS), \
};
#define DEFINE_LOOPBACK_EP_CFG(x, _) \
static struct usb_ep_cfg_data ep_cfg_##x[] = { \
{ \
.ep_cb = NULL, \
.ep_addr = LOOPBACK_OUT_EP_ADDR, \
}, \
{ \
.ep_cb = NULL, \
.ep_addr = LOOPBACK_IN_EP_ADDR, \
}, \
{ \
.ep_cb = NULL, \
.ep_addr = LOOPBACK_IN_EP_ADDR, \
}, \
};
#define DEFINE_LOOPBACK_CFG_DATA(x, _) \
USBD_CFG_DATA_DEFINE(loopback_##x) \
struct usb_cfg_data loopback_config_##x = { \
.usb_device_description = NULL, \
.interface_config = interface_config, \
.interface_descriptor = &loopback_cfg_##x.if0, \
.cb_usb_status = NULL, \
.interface = { \
.class_handler = NULL, \
.custom_handler = NULL, \
.vendor_handler = NULL, \
.vendor_data = NULL, \
.payload_data = 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,
u8_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;
}
UTIL_LISTIFY(NUM_INSTANCES, DEFINE_LOOPBACK_DESC, _)
UTIL_LISTIFY(NUM_INSTANCES, DEFINE_LOOPBACK_EP_CFG, _)
UTIL_LISTIFY(NUM_INSTANCES, DEFINE_LOOPBACK_CFG_DATA, _)
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;
}
static bool find_cfg_data_ep(const struct usb_ep_descriptor * const ep_descr,
const struct usb_cfg_data * const cfg_data)
{
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);
return true;
}
}
return false;
}
static void check_endpoint_allocation(struct usb_desc_header *head)
{
struct usb_cfg_data *cfg_data = NULL;
static u8_t interfaces;
while (head->bLength != 0) {
if (head->bDescriptorType == USB_INTERFACE_DESC) {
struct usb_if_descriptor *if_descr = (void *)head;
LOG_DBG("iface %u", if_descr->bInterfaceNumber);
/* Check that interfaces get correct numbers */
zassert_equal(if_descr->bInterfaceNumber, interfaces++,
"Interfaces numbering failed");
cfg_data = usb_get_cfg_data(if_descr);
zassert_not_null(cfg_data, "Check available cfg data");
}
if (head->bDescriptorType == USB_ENDPOINT_DESC) {
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),
"Check endpoint config in cfg_data");
}
head = (struct usb_desc_header *)((u8_t *)head + head->bLength);
}
}
static void test_desc_sections(void)
{
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 size %d\n",
(int)__usb_descriptor_end - (int)__usb_descriptor_start);
TC_PRINT("__usb_data_start %p\n", __usb_data_start);
TC_PRINT("__usb_data_end %p\n", __usb_data_end);
TC_PRINT("USB Configuration data size %d\n",
(int)__usb_data_end - (int)__usb_data_start);
TC_PRINT("sizeof usb_cfg_data %u\n", sizeof(struct usb_cfg_data));
LOG_DBG("Starting logs");
LOG_HEXDUMP_DBG((u8_t *)__usb_descriptor_start,
(int)__usb_descriptor_end - (int)__usb_descriptor_start,
"USB Descriptor table section");
LOG_HEXDUMP_DBG((u8_t *)__usb_data_start,
(int)__usb_data_end - (int)__usb_data_start,
"USB Configuratio structures section");
head = (struct usb_desc_header *)usb_get_device_descriptor();
zassert_not_null(head, NULL);
zassert_equal((int)__usb_descriptor_end - (int)__usb_descriptor_start,
133, NULL);
/* Calculate number of structures */
zassert_equal(__usb_data_end - __usb_data_start, NUM_INSTANCES, NULL);
zassert_equal((int)__usb_data_end - (int)__usb_data_start,
NUM_INSTANCES * sizeof(struct usb_cfg_data), NULL);
check_endpoint_allocation(head);
}
/*test case main entry*/
void test_main(void)
{
ztest_test_suite(test_desc,
ztest_unit_test(test_desc_sections));
ztest_run_test_suite(test_desc);
}