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