1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/usb/usb_device.h>
11 #include <zephyr/usb/bos.h>
12 #include <zephyr/usb/msos_desc.h>
13 #include <zephyr/net_buf.h>
14 
15 #include <usb_descriptor.h>
16 #include <cmsis_dap.h>
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(dap_sample, LOG_LEVEL_INF);
20 
21 NET_BUF_POOL_FIXED_DEFINE(dapusb_rx_pool, CONFIG_CMSIS_DAP_PACKET_COUNT,
22 			  CONFIG_CMSIS_DAP_PACKET_SIZE, 0, NULL);
23 
24 static uint8_t rx_buf[CONFIG_CMSIS_DAP_PACKET_SIZE];
25 static uint8_t tx_buf[CONFIG_CMSIS_DAP_PACKET_SIZE];
26 
27 static K_FIFO_DEFINE(dap_rx_queue);
28 
29 #define DAP_IFACE_STR_DESC		"CMSIS-DAP v2"
30 
31 struct dap_iface_descriptor {
32 	uint8_t bLength;
33 	uint8_t bDescriptorType;
34 	uint8_t bString[USB_BSTRING_LENGTH(DAP_IFACE_STR_DESC)];
35 } __packed;
36 
37 USBD_STRING_DESCR_USER_DEFINE(primary) struct dap_iface_descriptor dap_iface_desc = {
38 	.bLength = USB_STRING_DESCRIPTOR_LENGTH(DAP_IFACE_STR_DESC),
39 	.bDescriptorType = USB_DESC_STRING,
40 	.bString = DAP_IFACE_STR_DESC
41 };
42 
43 #define DAP_USB_EP_IN		0x81
44 #define DAP_USB_EP_OUT		0x01
45 #define DAP_USB_EP_IN_IDX	0
46 #define DAP_USB_EP_OUT_IDX	1
47 
48 #define WEBUSB_VENDOR_CODE	0x21
49 #define WINUSB_VENDOR_CODE	0x20
50 
51 /* {CDB3B5AD-293B-4663-AA36-1AAE46463776} */
52 #define CMSIS_DAP_V2_DEVICE_INTERFACE_GUID \
53 	'{', 0x00, 'C', 0x00, 'D', 0x00, 'B', 0x00, '3', 0x00, 'B', 0x00, \
54 	'5', 0x00, 'A', 0x00, 'D', 0x00, '-', 0x00, '2', 0x00, '9', 0x00, \
55 	'3', 0x00, 'B', 0x00, '-', 0x00, '4', 0x00, '6', 0x00, '6', 0x00, \
56 	'3', 0x00, '-', 0x00, 'A', 0x00, 'A', 0x00, '3', 0x00, '6', 0x00, \
57 	'-', 0x00, '1', 0x00, 'A', 0x00, 'A', 0x00, 'E', 0x00, '4', 0x00, \
58 	'6', 0x00, '4', 0x00, '6', 0x00, '3', 0x00, '7', 0x00, '7', 0x00, \
59 	'6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
60 
61 #define COMPATIBLE_ID_WINUSB \
62 	'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00
63 
64 static struct msosv2_descriptor {
65 	struct msosv2_descriptor_set_header header;
66 #if defined(CONFIG_USB_COMPOSITE_DEVICE)
67 	struct msosv2_function_subset_header subset_header;
68 #endif
69 	struct msosv2_compatible_id compatible_id;
70 	struct msosv2_guids_property guids_property;
71 } __packed msosv2_cmsis_dap_desc = {
72 	/*
73 	 * Microsoft OS 2.0 descriptor set. This tells Windows what kind
74 	 * of device this is and to install the WinUSB driver.
75 	 */
76 	.header = {
77 		.wLength = sizeof(struct msosv2_descriptor_set_header),
78 		.wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR,
79 		.dwWindowsVersion = 0x06030000,
80 		.wTotalLength = sizeof(struct msosv2_descriptor),
81 	},
82 #if defined(CONFIG_USB_COMPOSITE_DEVICE)
83 	.subset_header = {
84 		.wLength = sizeof(struct msosv2_function_subset_header),
85 		.wDescriptorType = MS_OS_20_SUBSET_HEADER_FUNCTION,
86 		.wSubsetLength = sizeof(struct msosv2_function_subset_header)
87 			+ sizeof(struct msosv2_compatible_id)
88 			+ sizeof(struct msosv2_guids_property),
89 	},
90 #endif
91 	.compatible_id = {
92 		.wLength = sizeof(struct msosv2_compatible_id),
93 		.wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID,
94 		.CompatibleID = {COMPATIBLE_ID_WINUSB},
95 	},
96 	.guids_property = {
97 		.wLength = sizeof(struct msosv2_guids_property),
98 		.wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY,
99 		.wPropertyDataType = MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ,
100 		.wPropertyNameLength = 42,
101 		.PropertyName = {DEVICE_INTERFACE_GUIDS_PROPERTY_NAME},
102 		.wPropertyDataLength = 80,
103 		.bPropertyData = {CMSIS_DAP_V2_DEVICE_INTERFACE_GUID},
104 	},
105 };
106 
107 USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_msosv2_desc {
108 	struct usb_bos_platform_descriptor platform;
109 	struct usb_bos_capability_msos cap;
110 } __packed bos_cap_msosv2 = {
111 	/* Microsoft OS 2.0 Platform Capability Descriptor */
112 	.platform = {
113 		.bLength = sizeof(struct usb_bos_platform_descriptor)
114 			+ sizeof(struct usb_bos_capability_msos),
115 		.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
116 		.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM,
117 		.bReserved = 0,
118 		.PlatformCapabilityUUID = {
119 			/**
120 			 * MS OS 2.0 Platform Capability ID
121 			 * D8DD60DF-4589-4CC7-9CD2-659D9E648A9F
122 			 */
123 			0xDF, 0x60, 0xDD, 0xD8,
124 			0x89, 0x45,
125 			0xC7, 0x4C,
126 			0x9C, 0xD2,
127 			0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
128 		},
129 	},
130 	.cap = {
131 		/* Windows version (8.1) (0x06030000) */
132 		.dwWindowsVersion = sys_cpu_to_le32(0x06030000),
133 		.wMSOSDescriptorSetTotalLength =
134 			sys_cpu_to_le16(sizeof(msosv2_cmsis_dap_desc)),
135 		.bMS_VendorCode = WINUSB_VENDOR_CODE,
136 		.bAltEnumCode = 0x00
137 	},
138 };
139 
140 USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_webusb_desc {
141 	struct usb_bos_platform_descriptor platform;
142 	struct usb_bos_capability_webusb cap;
143 } __packed bos_cap_webusb = {
144 	/* WebUSB Platform Capability Descriptor:
145 	 * https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
146 	 */
147 	.platform = {
148 		.bLength = sizeof(struct usb_bos_platform_descriptor)
149 			 + sizeof(struct usb_bos_capability_webusb),
150 		.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
151 		.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM,
152 		.bReserved = 0,
153 		/* WebUSB Platform Capability UUID
154 		 * 3408b638-09a9-47a0-8bfd-a0768815b665
155 		 */
156 		.PlatformCapabilityUUID = {
157 			0x38, 0xB6, 0x08, 0x34,
158 			0xA9, 0x09,
159 			0xA0, 0x47,
160 			0x8B, 0xFD,
161 			0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65,
162 		},
163 	},
164 	.cap = {
165 		.bcdVersion = sys_cpu_to_le16(0x0100),
166 		.bVendorCode = WEBUSB_VENDOR_CODE,
167 		.iLandingPage = 0x01
168 	}
169 };
170 
171 /* URL Descriptor: https://wicg.github.io/webusb/#url-descriptor */
172 static const uint8_t webusb_origin_url[] = {
173 	/* Length, DescriptorType, Scheme */
174 	24, 0x03, 0x01,
175 	'w', 'w', 'w', '.',
176 	'z', 'e', 'p', 'h', 'y', 'r', 'p', 'r', 'o', 'j', 'e', 'c', 't', '.',
177 	'o', 'r', 'g', '/',
178 };
179 
msosv2_vendor_handle_req(struct usb_setup_packet * setup,int32_t * len,uint8_t ** data)180 static int msosv2_vendor_handle_req(struct usb_setup_packet *setup,
181 				    int32_t *len, uint8_t **data)
182 {
183 	if (usb_reqtype_is_to_device(setup)) {
184 		return -ENOTSUP;
185 	}
186 
187 	if (setup->bRequest == WEBUSB_VENDOR_CODE && setup->wIndex == 0x02) {
188 		*data = (uint8_t *)(&webusb_origin_url);
189 		*len = sizeof(webusb_origin_url);
190 
191 		LOG_DBG("Get URL request");
192 
193 		return 0;
194 	}
195 
196 	if (setup->bRequest == WINUSB_VENDOR_CODE &&
197 	    setup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
198 		*data = (uint8_t *)(&msosv2_cmsis_dap_desc);
199 		*len = sizeof(msosv2_cmsis_dap_desc);
200 
201 		LOG_DBG("Get MS OS Descriptors v2");
202 
203 		return 0;
204 	}
205 
206 	return -ENOTSUP;
207 }
208 
209 USBD_CLASS_DESCR_DEFINE(primary, 0) struct {
210 	struct usb_if_descriptor if0;
211 	struct usb_ep_descriptor if0_out_ep;
212 	struct usb_ep_descriptor if0_in_ep;
213 } __packed dapusb_desc = {
214 	.if0 = {
215 		.bLength = sizeof(struct usb_if_descriptor),
216 		.bDescriptorType = USB_DESC_INTERFACE,
217 		.bInterfaceNumber = 0,
218 		.bAlternateSetting = 0,
219 		.bNumEndpoints = 2,
220 		.bInterfaceClass = USB_BCC_VENDOR,
221 		.bInterfaceSubClass = 0,
222 		.bInterfaceProtocol = 0,
223 		.iInterface = 0,
224 	},
225 	.if0_out_ep = {
226 		.bLength = sizeof(struct usb_ep_descriptor),
227 		.bDescriptorType = USB_DESC_ENDPOINT,
228 		.bEndpointAddress = DAP_USB_EP_OUT,
229 		.bmAttributes = USB_DC_EP_BULK,
230 		.wMaxPacketSize = sys_cpu_to_le16(CONFIG_CMSIS_DAP_PACKET_SIZE),
231 		.bInterval = 0,
232 	},
233 	.if0_in_ep = {
234 		.bLength = sizeof(struct usb_ep_descriptor),
235 		.bDescriptorType = USB_DESC_ENDPOINT,
236 		.bEndpointAddress = DAP_USB_EP_IN,
237 		.bmAttributes = USB_DC_EP_BULK,
238 		.wMaxPacketSize = sys_cpu_to_le16(CONFIG_CMSIS_DAP_PACKET_SIZE),
239 		.bInterval = 0,
240 	},
241 };
242 
243 static struct usb_ep_cfg_data dapusb_ep_data[] = {
244 	{
245 		.ep_cb	= usb_transfer_ep_callback,
246 		.ep_addr = DAP_USB_EP_OUT
247 	},
248 	{
249 		.ep_cb = usb_transfer_ep_callback,
250 		.ep_addr = DAP_USB_EP_IN
251 	}
252 };
253 
iface_string_desc_init(struct usb_cfg_data * bulk_cfg)254 static void iface_string_desc_init(struct usb_cfg_data *bulk_cfg)
255 {
256 	struct usb_if_descriptor *bulk_if = bulk_cfg->interface_descriptor;
257 
258 	bulk_if->iInterface = usb_get_str_descriptor_idx(&dap_iface_desc);
259 }
260 
dapusb_read_cb(uint8_t ep,int size,void * priv)261 static void dapusb_read_cb(uint8_t ep, int size, void *priv)
262 {
263 	struct usb_cfg_data *cfg = priv;
264 	struct net_buf *buf;
265 
266 	LOG_DBG("cfg %p ep %x size %u", cfg, ep, size);
267 
268 	if (size <= 0) {
269 		goto read_cb_done;
270 	}
271 
272 	buf = net_buf_alloc(&dapusb_rx_pool, K_FOREVER);
273 	net_buf_add_mem(buf, rx_buf, MIN(size, CONFIG_CMSIS_DAP_PACKET_SIZE));
274 	k_fifo_put(&dap_rx_queue, buf);
275 
276 read_cb_done:
277 	usb_transfer(ep, rx_buf, sizeof(rx_buf), USB_TRANS_READ, dapusb_read_cb, cfg);
278 }
279 
dapusb_dev_status_cb(struct usb_cfg_data * cfg,enum usb_dc_status_code status,const uint8_t * param)280 static void dapusb_dev_status_cb(struct usb_cfg_data *cfg,
281 				 enum usb_dc_status_code status,
282 				 const uint8_t *param)
283 {
284 	ARG_UNUSED(param);
285 
286 	if (status == USB_DC_CONFIGURED) {
287 		dapusb_read_cb(cfg->endpoint[DAP_USB_EP_IN_IDX].ep_addr, 0, cfg);
288 	}
289 }
290 
dapusb_interface_config(struct usb_desc_header * head,uint8_t bInterfaceNumber)291 static void dapusb_interface_config(struct usb_desc_header *head,
292 				    uint8_t bInterfaceNumber)
293 {
294 	ARG_UNUSED(head);
295 
296 	dapusb_desc.if0.bInterfaceNumber = bInterfaceNumber;
297 #if defined(CONFIG_USB_COMPOSITE_DEVICE)
298 	msosv2_cmsis_dap_desc.subset_header.bFirstInterface = bInterfaceNumber;
299 #endif
300 }
301 
302 USBD_DEFINE_CFG_DATA(dapusb_config) = {
303 	.usb_device_description = NULL,
304 	.interface_config = dapusb_interface_config,
305 	.interface_descriptor = &dapusb_desc.if0,
306 	.cb_usb_status = dapusb_dev_status_cb,
307 	.interface = {
308 		.class_handler = NULL,
309 		.custom_handler = NULL,
310 		.vendor_handler = msosv2_vendor_handle_req,
311 	},
312 	.num_endpoints = ARRAY_SIZE(dapusb_ep_data),
313 	.endpoint = dapusb_ep_data
314 };
315 
dap_usb_process(void)316 static int dap_usb_process(void)
317 {
318 	uint8_t ep = dapusb_config.endpoint[DAP_USB_EP_OUT_IDX].ep_addr;
319 	struct net_buf *buf;
320 	size_t len;
321 	int err;
322 
323 	buf = k_fifo_get(&dap_rx_queue, K_FOREVER);
324 
325 	len = dap_execute_cmd(buf->data, tx_buf);
326 	LOG_DBG("response length %u, starting with [0x%02X, 0x%02X]",
327 		len, tx_buf[0], tx_buf[1]);
328 	net_buf_unref(buf);
329 
330 	err = usb_transfer_sync(ep, tx_buf, len, USB_TRANS_WRITE | USB_TRANS_NO_ZLP);
331 	if (err < 0 || err != len) {
332 		LOG_ERR("usb_transfer_sync failed, %d", err);
333 		return -EIO;
334 	}
335 
336 	return 0;
337 }
338 
main(void)339 int main(void)
340 {
341 	const struct device *const swd_dev = DEVICE_DT_GET_ONE(zephyr_swdp_gpio);
342 	int ret;
343 
344 	if (!device_is_ready(swd_dev)) {
345 		LOG_ERR("SWD device is not ready");
346 		return -ENODEV;
347 	}
348 
349 	ret = dap_setup(swd_dev);
350 	if (ret) {
351 		LOG_ERR("Failed to initialize DAP controller, %d", ret);
352 		return ret;
353 	}
354 
355 	/* Add MS OS 2.0 BOS descriptor to BOS structure */
356 	usb_bos_register_cap((void *)&bos_cap_msosv2);
357 	/* Point interface index to string descriptor */
358 	iface_string_desc_init(&dapusb_config);
359 
360 	ret = usb_enable(NULL);
361 	if (ret != 0) {
362 		LOG_ERR("Failed to enable USB");
363 		return 0;
364 	}
365 
366 	while (!dap_usb_process()) {
367 	}
368 
369 	return usb_disable();
370 }
371