Add CMSIS-DAP v2 support
[openocd.git] / src / jtag / drivers / cmsis_dap_usb_bulk.c
1 /***************************************************************************
2 * Copyright (C) 2018 by Mickaël Thomas *
3 * mickael9@gmail.com *
4 * *
5 * Copyright (C) 2016 by Maksym Hilliaka *
6 * oter@frozen-team.com *
7 * *
8 * Copyright (C) 2016 by Phillip Pearson *
9 * pp@myelin.co.nz *
10 * *
11 * Copyright (C) 2014 by Paul Fertser *
12 * fercerpav@gmail.com *
13 * *
14 * Copyright (C) 2013 by mike brown *
15 * mike@theshedworks.org.uk *
16 * *
17 * Copyright (C) 2013 by Spencer Oliver *
18 * spen@spen-soft.co.uk *
19 * *
20 * This program is free software; you can redistribute it and/or modify *
21 * it under the terms of the GNU General Public License as published by *
22 * the Free Software Foundation; either version 2 of the License, or *
23 * (at your option) any later version. *
24 * *
25 * This program is distributed in the hope that it will be useful, *
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
28 * GNU General Public License for more details. *
29 * *
30 * You should have received a copy of the GNU General Public License *
31 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
32 ***************************************************************************/
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <libusb.h>
39 #include <helper/log.h>
40
41 #include "cmsis_dap.h"
42
43 struct cmsis_dap_backend_data {
44 libusb_context *usb_ctx;
45 libusb_device_handle *dev_handle;
46 unsigned int ep_out;
47 unsigned int ep_in;
48 int interface;
49 };
50
51 static int cmsis_dap_usb_interface = -1;
52
53 static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
54 {
55 int err;
56 libusb_context *ctx;
57 libusb_device **device_list;
58
59 err = libusb_init(&ctx);
60 if (err) {
61 LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err));
62 return ERROR_FAIL;
63 }
64
65 int num_devices = libusb_get_device_list(ctx, &device_list);
66 if (num_devices < 0) {
67 LOG_ERROR("could not enumerate USB devices: %s", libusb_strerror(num_devices));
68 libusb_exit(ctx);
69 return ERROR_FAIL;
70 }
71
72 for (int i = 0; i < num_devices; i++) {
73 libusb_device *dev = device_list[i];
74 struct libusb_device_descriptor dev_desc;
75
76 err = libusb_get_device_descriptor(dev, &dev_desc);
77 if (err) {
78 LOG_ERROR("could not get device descriptor for device %d: %s", i, libusb_strerror(err));
79 continue;
80 }
81
82 /* Match VID/PID */
83
84 bool id_match = true; /* match if we don't enter the loop (no filter) */
85 for (int id = 0; vids[id] || pids[id]; id++) {
86 id_match = !vids[id] || dev_desc.idVendor == vids[id];
87 id_match &= !pids[id] || dev_desc.idProduct == pids[id];
88
89 if (id_match)
90 break;
91 }
92
93 if (!id_match)
94 continue;
95
96 /* Don't continue if we asked for a serial number and the device doesn't have one */
97 if (dev_desc.iSerialNumber == 0 && serial && serial[0])
98 continue;
99
100 libusb_device_handle *dev_handle = NULL;
101 err = libusb_open(dev, &dev_handle);
102 if (err) {
103 /* It's to be expected that most USB devices can't be opened
104 * so only report an error if it was explicitly selected
105 */
106 if (vids[0] || pids[0]) {
107 LOG_ERROR("could not open device 0x%04x:0x%04x: %s",
108 dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
109 } else {
110 LOG_DEBUG("could not open device 0x%04x:0x%04x: %s",
111 dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
112 }
113 continue;
114 }
115
116 /* Match serial number */
117
118 bool serial_match = (serial == NULL);
119 char dev_serial[256] = {0};
120 if (dev_desc.iSerialNumber > 0) {
121 err = libusb_get_string_descriptor_ascii(
122 dev_handle, dev_desc.iSerialNumber,
123 (uint8_t *)dev_serial, sizeof(dev_serial));
124
125 if (err < 0) {
126 LOG_ERROR("could not read serial number for device 0x%04x:0x%04x: %s",
127 dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
128 } else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) {
129 serial_match = true;
130 }
131 }
132
133 if (!serial_match) {
134 libusb_close(dev_handle);
135 continue;
136 }
137
138 /* Find the CMSIS-DAP string in product string */
139
140 bool cmsis_dap_found = false;
141 char product_string[256] = {0};
142 if (dev_desc.iProduct > 0) {
143 err = libusb_get_string_descriptor_ascii(
144 dev_handle, dev_desc.iProduct,
145 (uint8_t *)product_string, sizeof(product_string));
146 if (err < 0) {
147 LOG_ERROR("could not read product string for device 0x%04x:0x%04x: %s",
148 dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
149 } else if (strstr(product_string, "CMSIS-DAP")) {
150 LOG_DEBUG("CMSIS-DAP found in product string");
151 cmsis_dap_found = true;
152 }
153 }
154
155 /* Find the CMSIS-DAP interface */
156
157 for (int config = 0; config < dev_desc.bNumConfigurations; config++) {
158 struct libusb_config_descriptor *config_desc;
159 err = libusb_get_config_descriptor(dev, config, &config_desc);
160 if (err) {
161 LOG_ERROR("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s",
162 config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
163 continue;
164 }
165
166 int config_num = config_desc->bConfigurationValue;
167
168 for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) {
169 const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0];
170 int interface_num = intf_desc->bInterfaceNumber;
171
172 /* Skip this interface if another one was requested explicitly */
173 if (cmsis_dap_usb_interface != -1 && cmsis_dap_usb_interface != interface_num)
174 continue;
175
176 /* CMSIS-DAP v2 spec says:
177 *
178 * CMSIS-DAP with default V2 configuration uses WinUSB and is therefore faster.
179 * Optionally support for streaming SWO trace is provided via an additional USB endpoint.
180 *
181 * The WinUSB configuration requires custom class support with the interface setting
182 * Class Code: 0xFF (Vendor specific)
183 * Subclass: 0x00
184 * Protocol code: 0x00
185 *
186 * Depending on the configuration it uses the following USB endpoints which should be configured
187 * in the interface descriptor in this order:
188 * - Endpoint 1: Bulk Out – used for commands received from host PC.
189 * - Endpoint 2: Bulk In – used for responses send to host PC.
190 * - Endpoint 3: Bulk In (optional) – used for streaming SWO trace (if enabled with SWO_STREAM).
191 */
192
193 if (intf_desc->bNumEndpoints < 2)
194 continue;
195
196 if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK ||
197 (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT)
198 continue;
199
200 if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK ||
201 (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN)
202 continue;
203
204 /* Bypass the following checks if this interface was explicitly requested. */
205 if (cmsis_dap_usb_interface == -1) {
206 if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC ||
207 intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0)
208 continue;
209
210 /* Search for "CMSIS-DAP" in the interface string */
211 if (cmsis_dap_usb_interface != -1 && !cmsis_dap_found) {
212 if (intf_desc->iInterface == 0)
213 continue;
214
215 char interface_str[256] = {0};
216
217 err = libusb_get_string_descriptor_ascii(
218 dev_handle, intf_desc->iInterface,
219 (uint8_t *)interface_str, sizeof(interface_str));
220 if (err < 0) {
221 LOG_ERROR("could not read interface string for device 0x%04x:0x%04x: %s",
222 dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err));
223 continue;
224 } else if (!strstr(interface_str, "CMSIS-DAP")) {
225 continue;
226 } else {
227 LOG_DEBUG("CMSIS-DAP found in interface string");
228 }
229 }
230 }
231
232 int packet_size = intf_desc->endpoint[0].wMaxPacketSize;
233 int ep_out = intf_desc->endpoint[0].bEndpointAddress;
234 int ep_in = intf_desc->endpoint[1].bEndpointAddress;
235
236 /* That's the one! */
237 libusb_free_config_descriptor(config_desc);
238 libusb_free_device_list(device_list, true);
239
240 LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s",
241 dev_desc.idVendor, dev_desc.idProduct, dev_serial);
242
243 int current_config;
244 err = libusb_get_configuration(dev_handle, &current_config);
245 if (err) {
246 LOG_ERROR("could not find current configuration: %s", libusb_strerror(err));
247 libusb_close(dev_handle);
248 libusb_exit(ctx);
249 return ERROR_FAIL;
250 }
251
252 if (config_num != current_config) {
253 err = libusb_set_configuration(dev_handle, config_num);
254 if (err) {
255 LOG_ERROR("could not set configuration: %s", libusb_strerror(err));
256 libusb_close(dev_handle);
257 libusb_exit(ctx);
258 return ERROR_FAIL;
259 }
260 }
261
262 err = libusb_claim_interface(dev_handle, interface_num);
263 if (err)
264 LOG_WARNING("could not claim interface: %s", libusb_strerror(err));
265
266 dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
267 if (dap->bdata == NULL) {
268 LOG_ERROR("unable to allocate memory");
269 libusb_release_interface(dev_handle, interface_num);
270 libusb_close(dev_handle);
271 libusb_exit(ctx);
272 return ERROR_FAIL;
273 }
274
275 dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */
276 dap->bdata->usb_ctx = ctx;
277 dap->bdata->dev_handle = dev_handle;
278 dap->bdata->ep_out = ep_out;
279 dap->bdata->ep_in = ep_in;
280 dap->bdata->interface = interface_num;
281 return ERROR_OK;
282 }
283
284 libusb_free_config_descriptor(config_desc);
285 }
286
287 libusb_close(dev_handle);
288 }
289
290 libusb_free_device_list(device_list, true);
291
292 libusb_exit(ctx);
293 return ERROR_FAIL;
294 }
295
296 static void cmsis_dap_usb_close(struct cmsis_dap *dap)
297 {
298 libusb_release_interface(dap->bdata->dev_handle, dap->bdata->interface);
299 libusb_close(dap->bdata->dev_handle);
300 libusb_exit(dap->bdata->usb_ctx);
301 free(dap->bdata);
302 dap->bdata = NULL;
303 }
304
305 static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms)
306 {
307 int transferred = 0;
308 int err;
309
310 err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_in,
311 dap->packet_buffer, dap->packet_size, &transferred, timeout_ms);
312 if (err) {
313 if (err == LIBUSB_ERROR_TIMEOUT) {
314 return ERROR_TIMEOUT_REACHED;
315 } else {
316 LOG_ERROR("error reading data: %s", libusb_strerror(err));
317 return ERROR_FAIL;
318 }
319 }
320
321 memset(&dap->packet_buffer[transferred], 0, dap->packet_size - transferred);
322
323 return transferred;
324 }
325
326 static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
327 {
328 int transferred = 0;
329 int err;
330
331 /* skip the first byte that is only used by the HID backend */
332 err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out,
333 dap->packet_buffer + 1, txlen - 1, &transferred, timeout_ms);
334 if (err) {
335 if (err == LIBUSB_ERROR_TIMEOUT) {
336 return ERROR_TIMEOUT_REACHED;
337 } else {
338 LOG_ERROR("error writing data: %s", libusb_strerror(err));
339 return ERROR_FAIL;
340 }
341 }
342
343 return transferred;
344 }
345
346 COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command)
347 {
348 if (CMD_ARGC == 1)
349 cmsis_dap_usb_interface = strtoul(CMD_ARGV[0], NULL, 10);
350 else
351 LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface <interface_number>");
352
353 return ERROR_OK;
354 }
355
356 const struct command_registration cmsis_dap_usb_subcommand_handlers[] = {
357 {
358 .name = "interface",
359 .handler = &cmsis_dap_handle_usb_interface_command,
360 .mode = COMMAND_CONFIG,
361 .help = "set the USB interface number to use (for USB bulk backend only)",
362 .usage = "<interface_number>",
363 },
364 COMMAND_REGISTRATION_DONE
365 };
366
367 const struct cmsis_dap_backend cmsis_dap_usb_backend = {
368 .name = "usb_bulk",
369 .open = cmsis_dap_usb_open,
370 .close = cmsis_dap_usb_close,
371 .read = cmsis_dap_usb_read,
372 .write = cmsis_dap_usb_write,
373 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)