Skip to content

Commit 53c33ab

Browse files
jfischer-nokartben
authored andcommitted
dap: add DAP backend USB
The backend uses a new USB device stack and bulk endpoints. Only a single instance of the backend function is currently supported. Both DAP packet processing and the new backend are prepared to support multiple instances, but require a user interface and minor modifications. New backen has similar functionality to what is provided by the function in the sample samples/subsys/dap. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
1 parent 6fbd63b commit 53c33ab

File tree

3 files changed

+313
-0
lines changed

3 files changed

+313
-0
lines changed

subsys/dap/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR})
55

66
zephyr_library()
77
zephyr_library_sources(cmsis_dap.c)
8+
9+
zephyr_library_sources_ifdef(CONFIG_DAP_BACKEND_USB dap_backend_usb.c)

subsys/dap/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ config CMSIS_DAP_DEVICE_NAME
4141
string "Target device name"
4242
default ""
4343

44+
config DAP_BACKEND_USB
45+
bool "USB backend"
46+
depends on USB_DEVICE_STACK_NEXT
47+
help
48+
DAP USB backend using bulk endpoints.
49+
4450
module = DAP
4551
module-str = dap
4652
source "subsys/logging/Kconfig.template.log_config"

subsys/dap/dap_backend_usb.c

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/usb/usbd.h>
8+
#include <zephyr/drivers/usb/udc.h>
9+
#include <zephyr/sys/byteorder.h>
10+
11+
#include "cmsis_dap.h"
12+
13+
#include <zephyr/logging/log.h>
14+
LOG_MODULE_REGISTER(dap_usb, CONFIG_DAP_LOG_LEVEL);
15+
16+
/*
17+
* This file implements CMSIS DAP USB backend function using bulk endpoints.
18+
*/
19+
20+
static uint8_t response_buf[512];
21+
22+
NET_BUF_POOL_FIXED_DEFINE(dap_func_pool,
23+
1, 0, sizeof(struct udc_buf_info), NULL);
24+
25+
UDC_STATIC_BUF_DEFINE(dap_func_buf, 512);
26+
27+
struct dap_func_desc {
28+
struct usb_if_descriptor if0;
29+
struct usb_ep_descriptor if0_out_ep;
30+
struct usb_ep_descriptor if0_in_ep;
31+
struct usb_ep_descriptor if0_hs_out_ep;
32+
struct usb_ep_descriptor if0_hs_in_ep;
33+
struct usb_desc_header nil_desc;
34+
};
35+
36+
#define SAMPLE_FUNCTION_ENABLED 0
37+
38+
struct dap_func_data {
39+
struct dap_func_desc *const desc;
40+
const struct usb_desc_header **const fs_desc;
41+
const struct usb_desc_header **const hs_desc;
42+
struct usbd_desc_node *const iface_str_desc_nd;
43+
atomic_t state;
44+
};
45+
46+
static uint8_t dap_func_get_bulk_out(struct usbd_class_data *const c_data)
47+
{
48+
struct dap_func_data *data = usbd_class_get_private(c_data);
49+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
50+
struct dap_func_desc *desc = data->desc;
51+
52+
if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
53+
return desc->if0_hs_out_ep.bEndpointAddress;
54+
}
55+
56+
return desc->if0_out_ep.bEndpointAddress;
57+
}
58+
59+
static uint8_t dap_func_get_bulk_in(struct usbd_class_data *const c_data)
60+
{
61+
struct dap_func_data *data = usbd_class_get_private(c_data);
62+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
63+
struct dap_func_desc *desc = data->desc;
64+
65+
if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
66+
return desc->if0_hs_in_ep.bEndpointAddress;
67+
}
68+
69+
return desc->if0_in_ep.bEndpointAddress;
70+
}
71+
72+
static int dap_func_request_handler(struct usbd_class_data *c_data,
73+
struct net_buf *buf, int err)
74+
{
75+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
76+
struct dap_func_data *data = usbd_class_get_private(c_data);
77+
struct udc_buf_info *bi = NULL;
78+
79+
bi = (struct udc_buf_info *)net_buf_user_data(buf);
80+
LOG_DBG("Transfer finished %p -> ep 0x%02x, len %u, err %d",
81+
(void *)c_data, bi->ep, buf->len, err);
82+
83+
if (atomic_test_bit(&data->state, SAMPLE_FUNCTION_ENABLED) && err == 0) {
84+
uint8_t ep = bi->ep;
85+
size_t len;
86+
87+
memset(bi, 0, sizeof(struct udc_buf_info));
88+
if (ep == dap_func_get_bulk_in(c_data)) {
89+
bi->ep = dap_func_get_bulk_out(c_data);
90+
net_buf_reset(buf);
91+
} else {
92+
bi->ep = dap_func_get_bulk_in(c_data);
93+
94+
len = dap_execute_cmd(buf->data, response_buf);
95+
net_buf_reset(buf);
96+
LOG_DBG("response length %u, starting with [0x%02X, 0x%02X]",
97+
len, response_buf[0], response_buf[1]);
98+
net_buf_add_mem(buf, response_buf, MIN(len, net_buf_tailroom(buf)));
99+
}
100+
101+
if (usbd_ep_enqueue(c_data, buf)) {
102+
LOG_ERR("Failed to enqueue buffer");
103+
usbd_ep_buf_free(uds_ctx, buf);
104+
}
105+
} else {
106+
LOG_ERR("Function is disabled or transfer failed");
107+
usbd_ep_buf_free(uds_ctx, buf);
108+
}
109+
110+
return 0;
111+
}
112+
113+
static void *dap_func_get_desc(struct usbd_class_data *const c_data,
114+
const enum usbd_speed speed)
115+
{
116+
struct dap_func_data *data = usbd_class_get_private(c_data);
117+
118+
if (speed == USBD_SPEED_HS) {
119+
return data->hs_desc;
120+
}
121+
122+
return data->fs_desc;
123+
}
124+
125+
struct net_buf *dap_func_buf_alloc(struct usbd_class_data *const c_data,
126+
const uint8_t ep)
127+
{
128+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
129+
struct net_buf *buf = NULL;
130+
struct udc_buf_info *bi;
131+
size_t size;
132+
133+
if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
134+
size = 512U;
135+
} else {
136+
size = 64U;
137+
}
138+
139+
buf = net_buf_alloc_with_data(&dap_func_pool, dap_func_buf, size, K_NO_WAIT);
140+
net_buf_reset(buf);
141+
if (!buf) {
142+
return NULL;
143+
}
144+
145+
bi = udc_get_buf_info(buf);
146+
memset(bi, 0, sizeof(struct udc_buf_info));
147+
bi->ep = ep;
148+
149+
return buf;
150+
}
151+
152+
static void dap_func_enable(struct usbd_class_data *const c_data)
153+
{
154+
struct dap_func_data *data = usbd_class_get_private(c_data);
155+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
156+
struct net_buf *buf;
157+
158+
LOG_INF("Configuration enabled");
159+
160+
if (!atomic_test_and_set_bit(&data->state, SAMPLE_FUNCTION_ENABLED)) {
161+
if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
162+
dap_update_pkt_size(512);
163+
} else {
164+
dap_update_pkt_size(64);
165+
}
166+
167+
buf = dap_func_buf_alloc(c_data, dap_func_get_bulk_out(c_data));
168+
if (buf == NULL) {
169+
LOG_ERR("Failed to allocate buffer");
170+
return;
171+
}
172+
173+
if (usbd_ep_enqueue(c_data, buf)) {
174+
LOG_ERR("Failed to enqueue buffer");
175+
usbd_ep_buf_free(uds_ctx, buf);
176+
}
177+
}
178+
}
179+
180+
static void dap_func_disable(struct usbd_class_data *const c_data)
181+
{
182+
struct dap_func_data *data = usbd_class_get_private(c_data);
183+
184+
atomic_clear_bit(&data->state, SAMPLE_FUNCTION_ENABLED);
185+
LOG_INF("Configuration disabled");
186+
}
187+
188+
static int dap_func_init(struct usbd_class_data *c_data)
189+
{
190+
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
191+
struct dap_func_data *data = usbd_class_get_private(c_data);
192+
struct dap_func_desc *desc = data->desc;
193+
194+
LOG_DBG("Init class instance %p", (void *)c_data);
195+
196+
if (usbd_add_descriptor(uds_ctx, data->iface_str_desc_nd)) {
197+
LOG_ERR("Failed to add interface string descriptor");
198+
} else {
199+
desc->if0.iInterface = usbd_str_desc_get_idx(data->iface_str_desc_nd);
200+
}
201+
202+
return 0;
203+
}
204+
205+
struct usbd_class_api dap_func_api = {
206+
.request = dap_func_request_handler,
207+
.get_desc = dap_func_get_desc,
208+
.enable = dap_func_enable,
209+
.disable = dap_func_disable,
210+
.init = dap_func_init,
211+
};
212+
213+
#define DAP_FUNC_DESCRIPTOR_DEFINE(n, _) \
214+
static struct dap_func_desc dap_func_desc_##n = { \
215+
/* Interface descriptor 0 */ \
216+
.if0 = { \
217+
.bLength = sizeof(struct usb_if_descriptor), \
218+
.bDescriptorType = USB_DESC_INTERFACE, \
219+
.bInterfaceNumber = 0, \
220+
.bAlternateSetting = 0, \
221+
.bNumEndpoints = 2, \
222+
.bInterfaceClass = USB_BCC_VENDOR, \
223+
.bInterfaceSubClass = 0, \
224+
.bInterfaceProtocol = 0, \
225+
.iInterface = 0, \
226+
}, \
227+
\
228+
/* Endpoint OUT */ \
229+
.if0_out_ep = { \
230+
.bLength = sizeof(struct usb_ep_descriptor), \
231+
.bDescriptorType = USB_DESC_ENDPOINT, \
232+
.bEndpointAddress = 0x01, \
233+
.bmAttributes = USB_EP_TYPE_BULK, \
234+
.wMaxPacketSize = sys_cpu_to_le16(64U), \
235+
.bInterval = 0x00, \
236+
}, \
237+
\
238+
/* Endpoint IN */ \
239+
.if0_in_ep = { \
240+
.bLength = sizeof(struct usb_ep_descriptor), \
241+
.bDescriptorType = USB_DESC_ENDPOINT, \
242+
.bEndpointAddress = 0x81, \
243+
.bmAttributes = USB_EP_TYPE_BULK, \
244+
.wMaxPacketSize = sys_cpu_to_le16(64U), \
245+
.bInterval = 0x00, \
246+
}, \
247+
\
248+
/* High-speed Endpoint OUT */ \
249+
.if0_hs_out_ep = { \
250+
.bLength = sizeof(struct usb_ep_descriptor), \
251+
.bDescriptorType = USB_DESC_ENDPOINT, \
252+
.bEndpointAddress = 0x01, \
253+
.bmAttributes = USB_EP_TYPE_BULK, \
254+
.wMaxPacketSize = sys_cpu_to_le16(512), \
255+
.bInterval = 0x00, \
256+
}, \
257+
\
258+
/* High-speed Endpoint IN */ \
259+
.if0_hs_in_ep = { \
260+
.bLength = sizeof(struct usb_ep_descriptor), \
261+
.bDescriptorType = USB_DESC_ENDPOINT, \
262+
.bEndpointAddress = 0x81, \
263+
.bmAttributes = USB_EP_TYPE_BULK, \
264+
.wMaxPacketSize = sys_cpu_to_le16(512), \
265+
.bInterval = 0x00, \
266+
}, \
267+
\
268+
/* Termination descriptor */ \
269+
.nil_desc = { \
270+
.bLength = 0, \
271+
.bDescriptorType = 0, \
272+
}, \
273+
}; \
274+
\
275+
const static struct usb_desc_header *dap_func_fs_desc_##n[] = { \
276+
(struct usb_desc_header *) &dap_func_desc_##n.if0, \
277+
(struct usb_desc_header *) &dap_func_desc_##n.if0_out_ep, \
278+
(struct usb_desc_header *) &dap_func_desc_##n.if0_in_ep, \
279+
(struct usb_desc_header *) &dap_func_desc_##n.nil_desc, \
280+
}; \
281+
\
282+
const static struct usb_desc_header *dap_func_hs_desc_##n[] = { \
283+
(struct usb_desc_header *) &dap_func_desc_##n.if0, \
284+
(struct usb_desc_header *) &dap_func_desc_##n.if0_hs_out_ep, \
285+
(struct usb_desc_header *) &dap_func_desc_##n.if0_hs_in_ep, \
286+
(struct usb_desc_header *) &dap_func_desc_##n.nil_desc, \
287+
};
288+
289+
290+
#define DAP_FUNC_FUNCTION_DATA_DEFINE(n, _) \
291+
USBD_DESC_STRING_DEFINE(iface_str_desc_nd_##n, \
292+
"CMSIS-DAP v2", \
293+
USBD_DUT_STRING_INTERFACE); \
294+
\
295+
static struct dap_func_data dap_func_data_##n = { \
296+
.desc = &dap_func_desc_##n, \
297+
.fs_desc = dap_func_fs_desc_##n, \
298+
.hs_desc = dap_func_hs_desc_##n, \
299+
.iface_str_desc_nd = &iface_str_desc_nd_##n, \
300+
}; \
301+
\
302+
USBD_DEFINE_CLASS(dap_func_##n, &dap_func_api, &dap_func_data_##n, NULL);
303+
304+
LISTIFY(1, DAP_FUNC_DESCRIPTOR_DEFINE, ())
305+
LISTIFY(1, DAP_FUNC_FUNCTION_DATA_DEFINE, ())

0 commit comments

Comments
 (0)