/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include LOG_MODULE_REGISTER(test_main, LOG_LEVEL_DBG); /* 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 defined(CONFIG_USB_DC_HAS_HS_SUPPORT) #define TEST_BULK_EP_MPS 512 #else #define TEST_BULK_EP_MPS 64 #endif #if defined(CONFIG_USB_CONFIGURATION_STRING_DESC_ENABLE) #define TEST_DESCRIPTOR_TABLE_SPAN 201 #else #define TEST_DESCRIPTOR_TABLE_SPAN 157 #endif #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; usb_set_config(usb_get_device_descriptor()); 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);