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
dap_func_get_bulk_out(struct usbd_class_data * const c_data)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
dap_func_get_bulk_in(struct usbd_class_data * const c_data)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
dap_func_request_handler(struct usbd_class_data * c_data,struct net_buf * buf,int err)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
dap_func_get_desc(struct usbd_class_data * const c_data,const enum usbd_speed speed)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
dap_func_buf_alloc(struct usbd_class_data * const c_data,const uint8_t ep)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
dap_func_enable(struct usbd_class_data * const c_data)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
dap_func_disable(struct usbd_class_data * const c_data)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
dap_func_init(struct usbd_class_data * c_data)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, ())
306