diff --git a/samples/subsys/tracing/CMakeLists.txt b/samples/subsys/tracing/CMakeLists.txt index 518530b6713..0938d47668f 100644 --- a/samples/subsys/tracing/CMakeLists.txt +++ b/samples/subsys/tracing/CMakeLists.txt @@ -9,6 +9,7 @@ endif() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(tracing_tests) +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) target_sources(app PRIVATE src/main.c) target_sources_ifdef(CONFIG_TRACING_GPIO app PRIVATE src/gpio_main.c) target_sources_ifdef(CONFIG_TRACING_USER app PRIVATE src/tracing_user.c) diff --git a/samples/subsys/tracing/Kconfig b/samples/subsys/tracing/Kconfig new file mode 100644 index 00000000000..825eba9059d --- /dev/null +++ b/samples/subsys/tracing/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + +source "Kconfig.zephyr" diff --git a/samples/subsys/tracing/README.rst b/samples/subsys/tracing/README.rst index 532660bcfce..97ac09dff96 100644 --- a/samples/subsys/tracing/README.rst +++ b/samples/subsys/tracing/README.rst @@ -46,7 +46,7 @@ Build a USB-tracing image with: .. zephyr-app-commands:: :zephyr-app: samples/subsys/tracing - :board: sam_e70_xplained/same70q21 + :board: reel_board :conf: "prj_usb_ctf.conf" :goals: build :compact: @@ -65,7 +65,7 @@ run the :zephyr_file:`scripts/tracing/trace_capture_usb.py` script on the host: .. code-block:: console - sudo python3 trace_capture_usb.py -v 0x2FE9 -p 0x100 -o channel0_0 + sudo python3 trace_capture_usb.py -v 0x2FE3 -p 0x0001 -o channel0_0 The VID and PID of USB device can be configured, just adjusting it accordingly. diff --git a/samples/subsys/tracing/prj_usb_ctf.conf b/samples/subsys/tracing/prj_usb_ctf.conf index c4b51c0b6fe..d1de19087b2 100644 --- a/samples/subsys/tracing/prj_usb_ctf.conf +++ b/samples/subsys/tracing/prj_usb_ctf.conf @@ -1,7 +1,5 @@ CONFIG_GPIO=y -CONFIG_USB_DEVICE_STACK=y -CONFIG_USB_DEVICE_VID=0x2FE9 -CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n +CONFIG_USB_DEVICE_STACK_NEXT=y CONFIG_TRACING=y CONFIG_TRACING_CTF=y diff --git a/samples/subsys/tracing/sample.yaml b/samples/subsys/tracing/sample.yaml index 078aa5ddd3f..760a64758bb 100644 --- a/samples/subsys/tracing/sample.yaml +++ b/samples/subsys/tracing/sample.yaml @@ -53,8 +53,9 @@ tests: extra_args: CONF_FILE="prj_uart_ctf.conf" filter: dt_chosen_enabled("zephyr,tracing-uart") sample.tracing.transport.usb.ctf: - platform_allow: sam_e70_xplained/same70q21 - depends_on: usb_device + integration_platforms: + - frdm_k64f + depends_on: usbd extra_args: CONF_FILE="prj_usb_ctf.conf" sample.tracing.transport.native: platform_allow: diff --git a/samples/subsys/tracing/src/main.c b/samples/subsys/tracing/src/main.c index cc3a25fc1e0..dcdb08080a0 100644 --- a/samples/subsys/tracing/src/main.c +++ b/samples/subsys/tracing/src/main.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include /* @@ -93,15 +93,19 @@ void threadA(void *dummy1, void *dummy2, void *dummy3) ARG_UNUSED(dummy2); ARG_UNUSED(dummy3); -#if defined(CONFIG_USB_DEVICE_STACK) - int ret; +#if defined(CONFIG_USB_DEVICE_STACK_NEXT) + struct usbd_context *sample_usbd = sample_usbd_init_device(NULL); - ret = usb_enable(NULL); - if (ret) { + if (sample_usbd == NULL) { + printk("Failed to initialize USB device"); + return; + } + + if (usbd_enable(sample_usbd)) { printk("usb backend enable failed"); return; } -#endif /* CONFIG_USB_DEVICE_STACK */ +#endif /* CONFIG_USB_DEVICE_STACK_NEXT */ /* spawn threadB */ k_tid_t tid = k_thread_create(&threadB_data, threadB_stack_area, diff --git a/subsys/tracing/Kconfig b/subsys/tracing/Kconfig index 30be8d5955b..ec86baba8fe 100644 --- a/subsys/tracing/Kconfig +++ b/subsys/tracing/Kconfig @@ -142,7 +142,7 @@ config TRACING_BACKEND_UART config TRACING_BACKEND_USB bool "USB backend" - depends on USB_DEVICE_STACK + depends on USB_DEVICE_STACK_NEXT depends on TRACING_ASYNC help Use USB to output tracing data. @@ -178,13 +178,6 @@ config RAM_TRACING_BUFFER_SIZE Size of the RAM trace buffer. Trace will be discarded if the length is exceeded. -config TRACING_USB_MPS - int "USB backend max packet size" - default 64 - depends on TRACING_BACKEND_USB - help - USB tracing backend max packet size(endpoint MPS). - config TRACING_HANDLE_HOST_CMD bool "Host command handle" select UART_INTERRUPT_DRIVEN if TRACING_BACKEND_UART diff --git a/subsys/tracing/tracing_backend_usb.c b/subsys/tracing/tracing_backend_usb.c index 95ec1cb5cbd..e931fd63e1d 100644 --- a/subsys/tracing/tracing_backend_usb.c +++ b/subsys/tracing/tracing_backend_usb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Intel corporation + * Copyright The Zephyr Project Contributors * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,30 +13,160 @@ #include #include #include -#include +#include +#include #include #include #include -#define USB_TRANSFER_ONGOING 1 -#define USB_TRANSFER_FREE 0 +/* Single bounce buffer for bulk IN transfer */ +UDC_BUF_POOL_DEFINE(tracing_data_pool, 1, CONFIG_TRACING_BUFFER_SIZE, + sizeof(struct udc_buf_info), NULL); -#define TRACING_IF_IN_EP_ADDR 0x81 -#define TRACING_IF_OUT_EP_ADDR 0x01 - -struct usb_device_desc { +struct tracing_func_desc { struct usb_if_descriptor if0; struct usb_ep_descriptor if0_in_ep; struct usb_ep_descriptor if0_out_ep; -} __packed; + struct usb_ep_descriptor if0_hs_out_ep; + struct usb_ep_descriptor if0_hs_in_ep; +}; + +struct tracing_func_data { + struct tracing_func_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + struct k_sem sync_sem; + atomic_t state; +}; + +#define TRACING_FUNCTION_ENABLED 0 + +static uint8_t tracing_func_get_bulk_out(struct usbd_class_data *const c_data) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct tracing_func_desc *desc = data->desc; + + if (USBD_SUPPORTS_HIGH_SPEED && + usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_out_ep.bEndpointAddress; + } + + return desc->if0_out_ep.bEndpointAddress; +} + +static uint8_t tracing_func_get_bulk_in(struct usbd_class_data *const c_data) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct tracing_func_desc *desc = data->desc; + + if (USBD_SUPPORTS_HIGH_SPEED && + usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + return desc->if0_hs_in_ep.bEndpointAddress; + } + + return desc->if0_in_ep.bEndpointAddress; +} + +static void tracing_func_out_next(struct usbd_class_data *const c_data) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct net_buf *buf; + uint8_t ep; + + if (!atomic_test_bit(&data->state, TRACING_FUNCTION_ENABLED)) { + return; + } + + ep = tracing_func_get_bulk_out(c_data); + if (USBD_SUPPORTS_HIGH_SPEED && + usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) { + buf = usbd_ep_buf_alloc(c_data, ep, 512); + } else { + buf = usbd_ep_buf_alloc(c_data, ep, 64); + } + + if (buf == NULL) { + return; + } + + if (usbd_ep_enqueue(c_data, buf)) { + net_buf_unref(buf); + } +} + +static int tracing_func_request_handler(struct usbd_class_data *const c_data, + struct net_buf *const buf, const int err) +{ + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct tracing_func_data *data = usbd_class_get_private(c_data); + struct udc_buf_info *bi = NULL; + + bi = (struct udc_buf_info *)net_buf_user_data(buf); + + if (bi->ep == tracing_func_get_bulk_out(c_data)) { + if (!err) { + tracing_cmd_handle(buf->data, buf->len); + } + + usbd_ep_buf_free(uds_ctx, buf); + tracing_func_out_next(c_data); + } + + if (bi->ep == tracing_func_get_bulk_in(c_data)) { + usbd_ep_buf_free(uds_ctx, buf); + k_sem_give(&data->sync_sem); + } + + return 0; +} + +static void *tracing_func_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); + + if (USBD_SUPPORTS_HIGH_SPEED && speed == USBD_SPEED_HS) { + return data->hs_desc; + } + + return data->fs_desc; +} + +static void tracing_func_enable(struct usbd_class_data *const c_data) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); -static volatile int transfer_state; -static enum usb_dc_status_code usb_device_status = USB_DC_UNKNOWN; + if (!atomic_test_and_set_bit(&data->state, TRACING_FUNCTION_ENABLED)) { + tracing_func_out_next(c_data); + } +} + +static void tracing_func_disable(struct usbd_class_data *const c_data) +{ + struct tracing_func_data *data = usbd_class_get_private(c_data); + + atomic_clear_bit(&data->state, TRACING_FUNCTION_ENABLED); +} + +static int tracing_func_init(struct usbd_class_data *c_data) +{ + ARG_UNUSED(c_data); + + return 0; +} + +struct usbd_class_api tracing_func_api = { + .request = tracing_func_request_handler, + .get_desc = tracing_func_get_desc, + .enable = tracing_func_enable, + .disable = tracing_func_disable, + .init = tracing_func_init, +}; -USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = { - /* - * Interface descriptor 0 - */ +static struct tracing_func_desc func_desc = { .if0 = { .bLength = sizeof(struct usb_if_descriptor), .bDescriptorType = USB_DESC_INTERFACE, @@ -49,124 +179,114 @@ USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = { .iInterface = 0, }, - /* - * Data Endpoint IN - */ .if0_in_ep = { .bLength = sizeof(struct usb_ep_descriptor), .bDescriptorType = USB_DESC_ENDPOINT, - .bEndpointAddress = TRACING_IF_IN_EP_ADDR, - .bmAttributes = USB_DC_EP_BULK, - .wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS), + .bEndpointAddress = 0x81, + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = sys_cpu_to_le16(64), .bInterval = 0x00, }, - /* - * Data Endpoint OUT - */ .if0_out_ep = { .bLength = sizeof(struct usb_ep_descriptor), .bDescriptorType = USB_DESC_ENDPOINT, - .bEndpointAddress = TRACING_IF_OUT_EP_ADDR, - .bmAttributes = USB_DC_EP_BULK, - .wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS), + .bEndpointAddress = 0x01, + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = sys_cpu_to_le16(64), .bInterval = 0x00, }, -}; - -static void dev_status_cb(struct usb_cfg_data *cfg, - enum usb_dc_status_code status, - const uint8_t *param) -{ - ARG_UNUSED(cfg); - ARG_UNUSED(param); - usb_device_status = status; -} + /* High-speed Endpoint IN */ + .if0_hs_in_ep = { + .bLength = sizeof(struct usb_ep_descriptor), + .bDescriptorType = USB_DESC_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = sys_cpu_to_le16(512), + .bInterval = 0x00, + }, -static void tracing_ep_out_cb(uint8_t ep, enum usb_dc_ep_cb_status_code ep_status) -{ - uint8_t *cmd = NULL; - uint32_t bytes_to_read, length; + /* High-speed Endpoint OUT */ + .if0_hs_out_ep = { + .bLength = sizeof(struct usb_ep_descriptor), + .bDescriptorType = USB_DESC_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_EP_TYPE_BULK, + .wMaxPacketSize = sys_cpu_to_le16(512), + .bInterval = 0x00, + }, +}; - usb_read(ep, NULL, 0, &bytes_to_read); +const static struct usb_desc_header *tracing_func_fs_desc[] = { + (struct usb_desc_header *) &func_desc.if0, + (struct usb_desc_header *) &func_desc.if0_in_ep, + (struct usb_desc_header *) &func_desc.if0_out_ep, + NULL, +}; - while (bytes_to_read) { - length = tracing_cmd_buffer_alloc(&cmd); - if (cmd) { - length = MIN(length, bytes_to_read); - usb_read(ep, cmd, length, NULL); - tracing_cmd_handle(cmd, length); +const static __maybe_unused struct usb_desc_header *tracing_func_hs_desc[] = { + (struct usb_desc_header *) &func_desc.if0, + (struct usb_desc_header *) &func_desc.if0_hs_in_ep, + (struct usb_desc_header *) &func_desc.if0_hs_out_ep, + NULL, +}; - bytes_to_read -= length; - } - } +static struct tracing_func_data func_data = { + .desc = &func_desc, + .fs_desc = tracing_func_fs_desc, + .hs_desc = COND_CODE_1(USBD_SUPPORTS_HIGH_SPEED, (tracing_func_hs_desc), (NULL,)) + .sync_sem = Z_SEM_INITIALIZER(func_data.sync_sem, 0, 1), +}; - /* - * send ZLP to sync with host receive thread - */ - usb_write(TRACING_IF_IN_EP_ADDR, NULL, 0, NULL); -} +USBD_DEFINE_CLASS(tracing_func, &tracing_func_api, &func_data, NULL); -static void tracing_ep_in_cb(uint8_t ep, enum usb_dc_ep_cb_status_code ep_status) +struct net_buf *tracing_func_buf_alloc(struct usbd_class_data *const c_data) { - ARG_UNUSED(ep); - ARG_UNUSED(ep_status); + struct udc_buf_info *bi; + struct net_buf *buf; - transfer_state = USB_TRANSFER_FREE; -} + buf = net_buf_alloc(&tracing_data_pool, K_NO_WAIT); + if (!buf) { + return NULL; + } -static struct usb_ep_cfg_data ep_cfg[] = { - { - .ep_cb = tracing_ep_out_cb, - .ep_addr = TRACING_IF_OUT_EP_ADDR, - }, - { - .ep_cb = tracing_ep_in_cb, - .ep_addr = TRACING_IF_IN_EP_ADDR, - }, -}; + bi = udc_get_buf_info(buf); + bi->ep = tracing_func_get_bulk_in(c_data); -USBD_DEFINE_CFG_DATA(tracing_backend_usb_config) = { - .usb_device_description = NULL, - .interface_descriptor = &dev_desc.if0, - .cb_usb_status = dev_status_cb, - .interface = { - .class_handler = NULL, - .custom_handler = NULL, - .vendor_handler = NULL, - }, - .num_endpoints = ARRAY_SIZE(ep_cfg), - .endpoint = ep_cfg, -}; + return buf; +} static void tracing_backend_usb_output(const struct tracing_backend *backend, uint8_t *data, uint32_t length) { int ret = 0; uint32_t bytes; + struct net_buf *buf; while (length > 0) { - transfer_state = USB_TRANSFER_ONGOING; - - /* - * make sure every USB transfer no need ZLP at all - * because we are in lowest priority thread content - * there are no deterministic time between real USB - * packet and ZLP - */ - ret = usb_write(TRACING_IF_IN_EP_ADDR, data, - length >= CONFIG_TRACING_USB_MPS ? - CONFIG_TRACING_USB_MPS - 1 : length, &bytes); + if (!atomic_test_bit(&func_data.state, TRACING_FUNCTION_ENABLED) || + !is_tracing_enabled()) { + return; + } + + buf = tracing_func_buf_alloc(&tracing_func); + if (buf == NULL) { + return; + } + + bytes = MIN(length, net_buf_tailroom(buf)); + net_buf_add_mem(buf, data, bytes); + + ret = usbd_ep_enqueue(&tracing_func, buf); if (ret) { + net_buf_unref(buf); continue; } data += bytes; length -= bytes; - - while (transfer_state == USB_TRANSFER_ONGOING) { - } + k_sem_take(&func_data.sync_sem, K_FOREVER); } }