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>
This commit is contained in:
parent
d52f76f9e1
commit
1174308df8
8 changed files with 247 additions and 121 deletions
|
@ -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)
|
||||
|
|
9
samples/subsys/tracing/Kconfig
Normal file
9
samples/subsys/tracing/Kconfig
Normal file
|
@ -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"
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/usb/usb_device.h>
|
||||
#include <sample_usbd.h>
|
||||
#include <zephyr/tracing/tracing.h>
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/__assert.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_buffer.h>
|
||||
#include <tracing_backend.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
static volatile int transfer_state;
|
||||
static enum usb_dc_status_code usb_device_status = USB_DC_UNKNOWN;
|
||||
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;
|
||||
};
|
||||
|
||||
USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = {
|
||||
/*
|
||||
* Interface descriptor 0
|
||||
*/
|
||||
#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);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
|
||||
/* 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,
|
||||
},
|
||||
|
||||
/* 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,
|
||||
},
|
||||
};
|
||||
|
||||
static void dev_status_cb(struct usb_cfg_data *cfg,
|
||||
enum usb_dc_status_code status,
|
||||
const uint8_t *param)
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
struct net_buf *tracing_func_buf_alloc(struct usbd_class_data *const c_data)
|
||||
{
|
||||
ARG_UNUSED(cfg);
|
||||
ARG_UNUSED(param);
|
||||
struct udc_buf_info *bi;
|
||||
struct net_buf *buf;
|
||||
|
||||
usb_device_status = status;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
usb_read(ep, NULL, 0, &bytes_to_read);
|
||||
|
||||
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);
|
||||
|
||||
bytes_to_read -= length;
|
||||
}
|
||||
buf = net_buf_alloc(&tracing_data_pool, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* send ZLP to sync with host receive thread
|
||||
*/
|
||||
usb_write(TRACING_IF_IN_EP_ADDR, NULL, 0, NULL);
|
||||
bi = udc_get_buf_info(buf);
|
||||
bi->ep = tracing_func_get_bulk_in(c_data);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void tracing_ep_in_cb(uint8_t ep, enum usb_dc_ep_cb_status_code ep_status)
|
||||
{
|
||||
ARG_UNUSED(ep);
|
||||
ARG_UNUSED(ep_status);
|
||||
|
||||
transfer_state = USB_TRANSFER_FREE;
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
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
|
||||
* packet and ZLP
|
||||
*/
|
||||
ret = usb_write(TRACING_IF_IN_EP_ADDR, data,
|
||||
length >= CONFIG_TRACING_USB_MPS ?
|
||||
CONFIG_TRACING_USB_MPS - 1 : length, &bytes);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue