1 /***************************************************************************
2 * Copyright (C) 2018 by Mickaël Thomas *
5 * Copyright (C) 2016 by Maksym Hilliaka *
6 * oter@frozen-team.com *
8 * Copyright (C) 2016 by Phillip Pearson *
11 * Copyright (C) 2014 by Paul Fertser *
12 * fercerpav@gmail.com *
14 * Copyright (C) 2013 by mike brown *
15 * mike@theshedworks.org.uk *
17 * Copyright (C) 2013 by Spencer Oliver *
18 * spen@spen-soft.co.uk *
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. *
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. *
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 ***************************************************************************/
39 #include <helper/log.h>
41 #include "cmsis_dap.h"
43 struct cmsis_dap_backend_data
{
44 libusb_context
*usb_ctx
;
45 libusb_device_handle
*dev_handle
;
51 static int cmsis_dap_usb_interface
= -1;
53 static int cmsis_dap_usb_open(struct cmsis_dap
*dap
, uint16_t vids
[], uint16_t pids
[], char *serial
)
57 libusb_device
**device_list
;
59 err
= libusb_init(&ctx
);
61 LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err
));
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
));
72 for (int i
= 0; i
< num_devices
; i
++) {
73 libusb_device
*dev
= device_list
[i
];
74 struct libusb_device_descriptor dev_desc
;
76 err
= libusb_get_device_descriptor(dev
, &dev_desc
);
78 LOG_ERROR("could not get device descriptor for device %d: %s", i
, libusb_strerror(err
));
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
];
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])
100 libusb_device_handle
*dev_handle
= NULL
;
101 err
= libusb_open(dev
, &dev_handle
);
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
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
));
110 LOG_DEBUG("could not open device 0x%04x:0x%04x: %s",
111 dev_desc
.idVendor
, dev_desc
.idProduct
, libusb_strerror(err
));
116 /* Match serial number */
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
));
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) {
134 libusb_close(dev_handle
);
138 /* Find the CMSIS-DAP string in product string */
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
));
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;
155 /* Find the CMSIS-DAP interface */
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
);
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
));
166 int config_num
= config_desc
->bConfigurationValue
;
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
;
172 /* Skip this interface if another one was requested explicitly */
173 if (cmsis_dap_usb_interface
!= -1 && cmsis_dap_usb_interface
!= interface_num
)
176 /* CMSIS-DAP v2 spec says:
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.
181 * The WinUSB configuration requires custom class support with the interface setting
182 * Class Code: 0xFF (Vendor specific)
184 * Protocol code: 0x00
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).
193 if (intf_desc
->bNumEndpoints
< 2)
196 if ((intf_desc
->endpoint
[0].bmAttributes
& 3) != LIBUSB_TRANSFER_TYPE_BULK
||
197 (intf_desc
->endpoint
[0].bEndpointAddress
& 0x80) != LIBUSB_ENDPOINT_OUT
)
200 if ((intf_desc
->endpoint
[1].bmAttributes
& 3) != LIBUSB_TRANSFER_TYPE_BULK
||
201 (intf_desc
->endpoint
[1].bEndpointAddress
& 0x80) != LIBUSB_ENDPOINT_IN
)
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)
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)
215 char interface_str
[256] = {0};
217 err
= libusb_get_string_descriptor_ascii(
218 dev_handle
, intf_desc
->iInterface
,
219 (uint8_t *)interface_str
, sizeof(interface_str
));
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
));
224 } else if (!strstr(interface_str
, "CMSIS-DAP")) {
227 LOG_DEBUG("CMSIS-DAP found in interface string");
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
;
236 /* That's the one! */
237 libusb_free_config_descriptor(config_desc
);
238 libusb_free_device_list(device_list
, true);
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
);
244 err
= libusb_get_configuration(dev_handle
, ¤t_config
);
246 LOG_ERROR("could not find current configuration: %s", libusb_strerror(err
));
247 libusb_close(dev_handle
);
252 if (config_num
!= current_config
) {
253 err
= libusb_set_configuration(dev_handle
, config_num
);
255 LOG_ERROR("could not set configuration: %s", libusb_strerror(err
));
256 libusb_close(dev_handle
);
262 err
= libusb_claim_interface(dev_handle
, interface_num
);
264 LOG_WARNING("could not claim interface: %s", libusb_strerror(err
));
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
);
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
;
284 libusb_free_config_descriptor(config_desc
);
287 libusb_close(dev_handle
);
290 libusb_free_device_list(device_list
, true);
296 static void cmsis_dap_usb_close(struct cmsis_dap
*dap
)
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
);
305 static int cmsis_dap_usb_read(struct cmsis_dap
*dap
, int timeout_ms
)
310 err
= libusb_bulk_transfer(dap
->bdata
->dev_handle
, dap
->bdata
->ep_in
,
311 dap
->packet_buffer
, dap
->packet_size
, &transferred
, timeout_ms
);
313 if (err
== LIBUSB_ERROR_TIMEOUT
) {
314 return ERROR_TIMEOUT_REACHED
;
316 LOG_ERROR("error reading data: %s", libusb_strerror(err
));
321 memset(&dap
->packet_buffer
[transferred
], 0, dap
->packet_size
- transferred
);
326 static int cmsis_dap_usb_write(struct cmsis_dap
*dap
, int txlen
, int timeout_ms
)
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
);
335 if (err
== LIBUSB_ERROR_TIMEOUT
) {
336 return ERROR_TIMEOUT_REACHED
;
338 LOG_ERROR("error writing data: %s", libusb_strerror(err
));
346 COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command
)
349 cmsis_dap_usb_interface
= strtoul(CMD_ARGV
[0], NULL
, 10);
351 LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface <interface_number>");
356 const struct command_registration cmsis_dap_usb_subcommand_handlers
[] = {
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>",
364 COMMAND_REGISTRATION_DONE
367 const struct cmsis_dap_backend cmsis_dap_usb_backend
= {
369 .open
= cmsis_dap_usb_open
,
370 .close
= cmsis_dap_usb_close
,
371 .read
= cmsis_dap_usb_read
,
372 .write
= cmsis_dap_usb_write
,
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)