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