Browse Source

tracing: port USB backend to the new USB device stack

Port USB backend to the new USB device stack.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
pull/91566/head
Johann Fischer 7 months ago committed by Henrik Brix Andersen
parent
commit
1174308df8
  1. 1
      samples/subsys/tracing/CMakeLists.txt
  2. 9
      samples/subsys/tracing/Kconfig
  3. 4
      samples/subsys/tracing/README.rst
  4. 4
      samples/subsys/tracing/prj_usb_ctf.conf
  5. 5
      samples/subsys/tracing/sample.yaml
  6. 16
      samples/subsys/tracing/src/main.c
  7. 9
      subsys/tracing/Kconfig
  8. 314
      subsys/tracing/tracing_backend_usb.c

1
samples/subsys/tracing/CMakeLists.txt

@ -9,6 +9,7 @@ endif()
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(tracing_tests) project(tracing_tests)
include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
target_sources(app PRIVATE src/main.c) target_sources(app PRIVATE src/main.c)
target_sources_ifdef(CONFIG_TRACING_GPIO app PRIVATE src/gpio_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) target_sources_ifdef(CONFIG_TRACING_USER app PRIVATE src/tracing_user.c)

9
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"

4
samples/subsys/tracing/README.rst

@ -46,7 +46,7 @@ Build a USB-tracing image with:
.. zephyr-app-commands:: .. zephyr-app-commands::
:zephyr-app: samples/subsys/tracing :zephyr-app: samples/subsys/tracing
:board: sam_e70_xplained/same70q21 :board: reel_board
:conf: "prj_usb_ctf.conf" :conf: "prj_usb_ctf.conf"
:goals: build :goals: build
:compact: :compact:
@ -65,7 +65,7 @@ run the :zephyr_file:`scripts/tracing/trace_capture_usb.py` script on the host:
.. code-block:: console .. 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. The VID and PID of USB device can be configured, just adjusting it accordingly.

4
samples/subsys/tracing/prj_usb_ctf.conf

@ -1,7 +1,5 @@
CONFIG_GPIO=y CONFIG_GPIO=y
CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_USB_DEVICE_VID=0x2FE9
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
CONFIG_TRACING=y CONFIG_TRACING=y
CONFIG_TRACING_CTF=y CONFIG_TRACING_CTF=y

5
samples/subsys/tracing/sample.yaml

@ -53,8 +53,9 @@ tests:
extra_args: CONF_FILE="prj_uart_ctf.conf" extra_args: CONF_FILE="prj_uart_ctf.conf"
filter: dt_chosen_enabled("zephyr,tracing-uart") filter: dt_chosen_enabled("zephyr,tracing-uart")
sample.tracing.transport.usb.ctf: sample.tracing.transport.usb.ctf:
platform_allow: sam_e70_xplained/same70q21 integration_platforms:
depends_on: usb_device - frdm_k64f
depends_on: usbd
extra_args: CONF_FILE="prj_usb_ctf.conf" extra_args: CONF_FILE="prj_usb_ctf.conf"
sample.tracing.transport.native: sample.tracing.transport.native:
platform_allow: platform_allow:

16
samples/subsys/tracing/src/main.c

@ -8,7 +8,7 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/sys/printk.h> #include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/usb/usb_device.h> #include <sample_usbd.h>
#include <zephyr/tracing/tracing.h> #include <zephyr/tracing/tracing.h>
/* /*
@ -93,15 +93,19 @@ void threadA(void *dummy1, void *dummy2, void *dummy3)
ARG_UNUSED(dummy2); ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3); ARG_UNUSED(dummy3);
#if defined(CONFIG_USB_DEVICE_STACK) #if defined(CONFIG_USB_DEVICE_STACK_NEXT)
int ret; struct usbd_context *sample_usbd = sample_usbd_init_device(NULL);
ret = usb_enable(NULL); if (sample_usbd == NULL) {
if (ret) { printk("Failed to initialize USB device");
return;
}
if (usbd_enable(sample_usbd)) {
printk("usb backend enable failed"); printk("usb backend enable failed");
return; return;
} }
#endif /* CONFIG_USB_DEVICE_STACK */ #endif /* CONFIG_USB_DEVICE_STACK_NEXT */
/* spawn threadB */ /* spawn threadB */
k_tid_t tid = k_thread_create(&threadB_data, threadB_stack_area, k_tid_t tid = k_thread_create(&threadB_data, threadB_stack_area,

9
subsys/tracing/Kconfig

@ -142,7 +142,7 @@ config TRACING_BACKEND_UART
config TRACING_BACKEND_USB config TRACING_BACKEND_USB
bool "USB backend" bool "USB backend"
depends on USB_DEVICE_STACK depends on USB_DEVICE_STACK_NEXT
depends on TRACING_ASYNC depends on TRACING_ASYNC
help help
Use USB to output tracing data. 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 Size of the RAM trace buffer. Trace will be discarded if the
length is exceeded. 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 config TRACING_HANDLE_HOST_CMD
bool "Host command handle" bool "Host command handle"
select UART_INTERRUPT_DRIVEN if TRACING_BACKEND_UART select UART_INTERRUPT_DRIVEN if TRACING_BACKEND_UART

314
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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,30 +13,160 @@
#include <zephyr/sys/atomic.h> #include <zephyr/sys/atomic.h>
#include <zephyr/sys/__assert.h> #include <zephyr/sys/__assert.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/usb/usb_device.h> #include <zephyr/usb/usbd.h>
#include <zephyr/drivers/usb/udc.h>
#include <tracing_core.h> #include <tracing_core.h>
#include <tracing_buffer.h> #include <tracing_buffer.h>
#include <tracing_backend.h> #include <tracing_backend.h>
#define USB_TRANSFER_ONGOING 1 /* Single bounce buffer for bulk IN transfer */
#define USB_TRANSFER_FREE 0 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 struct tracing_func_desc {
#define TRACING_IF_OUT_EP_ADDR 0x01
struct usb_device_desc {
struct usb_if_descriptor if0; struct usb_if_descriptor if0;
struct usb_ep_descriptor if0_in_ep; struct usb_ep_descriptor if0_in_ep;
struct usb_ep_descriptor if0_out_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; if (!atomic_test_and_set_bit(&data->state, TRACING_FUNCTION_ENABLED)) {
static enum usb_dc_status_code usb_device_status = USB_DC_UNKNOWN; 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 = { static struct tracing_func_desc func_desc = {
/*
* Interface descriptor 0
*/
.if0 = { .if0 = {
.bLength = sizeof(struct usb_if_descriptor), .bLength = sizeof(struct usb_if_descriptor),
.bDescriptorType = USB_DESC_INTERFACE, .bDescriptorType = USB_DESC_INTERFACE,
@ -49,124 +179,114 @@ USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = {
.iInterface = 0, .iInterface = 0,
}, },
/*
* Data Endpoint IN
*/
.if0_in_ep = { .if0_in_ep = {
.bLength = sizeof(struct usb_ep_descriptor), .bLength = sizeof(struct usb_ep_descriptor),
.bDescriptorType = USB_DESC_ENDPOINT, .bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = TRACING_IF_IN_EP_ADDR, .bEndpointAddress = 0x81,
.bmAttributes = USB_DC_EP_BULK, .bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS), .wMaxPacketSize = sys_cpu_to_le16(64),
.bInterval = 0x00, .bInterval = 0x00,
}, },
/*
* Data Endpoint OUT
*/
.if0_out_ep = { .if0_out_ep = {
.bLength = sizeof(struct usb_ep_descriptor), .bLength = sizeof(struct usb_ep_descriptor),
.bDescriptorType = USB_DESC_ENDPOINT, .bDescriptorType = USB_DESC_ENDPOINT,
.bEndpointAddress = TRACING_IF_OUT_EP_ADDR, .bEndpointAddress = 0x01,
.bmAttributes = USB_DC_EP_BULK, .bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS), .wMaxPacketSize = sys_cpu_to_le16(64),
.bInterval = 0x00, .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) /* High-speed Endpoint OUT */
{ .if0_hs_out_ep = {
uint8_t *cmd = NULL; .bLength = sizeof(struct usb_ep_descriptor),
uint32_t bytes_to_read, length; .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) { const static __maybe_unused struct usb_desc_header *tracing_func_hs_desc[] = {
length = tracing_cmd_buffer_alloc(&cmd); (struct usb_desc_header *) &func_desc.if0,
if (cmd) { (struct usb_desc_header *) &func_desc.if0_hs_in_ep,
length = MIN(length, bytes_to_read); (struct usb_desc_header *) &func_desc.if0_hs_out_ep,
usb_read(ep, cmd, length, NULL); NULL,
tracing_cmd_handle(cmd, length); };
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),
};
/* USBD_DEFINE_CLASS(tracing_func, &tracing_func_api, &func_data, NULL);
* send ZLP to sync with host receive thread
*/
usb_write(TRACING_IF_IN_EP_ADDR, NULL, 0, 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); struct udc_buf_info *bi;
ARG_UNUSED(ep_status); 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[] = { bi = udc_get_buf_info(buf);
{ bi->ep = tracing_func_get_bulk_in(c_data);
.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,
},
};
USBD_DEFINE_CFG_DATA(tracing_backend_usb_config) = { return buf;
.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,
};
static void tracing_backend_usb_output(const struct tracing_backend *backend, static void tracing_backend_usb_output(const struct tracing_backend *backend,
uint8_t *data, uint32_t length) uint8_t *data, uint32_t length)
{ {
int ret = 0; int ret = 0;
uint32_t bytes; uint32_t bytes;
struct net_buf *buf;
while (length > 0) { while (length > 0) {
transfer_state = USB_TRANSFER_ONGOING; if (!atomic_test_bit(&func_data.state, TRACING_FUNCTION_ENABLED) ||
!is_tracing_enabled()) {
/* return;
* 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 buf = tracing_func_buf_alloc(&tracing_func);
* packet and ZLP if (buf == NULL) {
*/ return;
ret = usb_write(TRACING_IF_IN_EP_ADDR, data, }
length >= CONFIG_TRACING_USB_MPS ?
CONFIG_TRACING_USB_MPS - 1 : length, &bytes); bytes = MIN(length, net_buf_tailroom(buf));
net_buf_add_mem(buf, data, bytes);
ret = usbd_ep_enqueue(&tracing_func, buf);
if (ret) { if (ret) {
net_buf_unref(buf);
continue; continue;
} }
data += bytes; data += bytes;
length -= bytes; length -= bytes;
k_sem_take(&func_data.sync_sem, K_FOREVER);
while (transfer_state == USB_TRANSFER_ONGOING) {
}
} }
} }

Loading…
Cancel
Save