OpenOCD
cmsis_dap_usb_hid.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2018 by MickaĆ«l Thomas *
5  * mickael9@gmail.com *
6  * *
7  * Copyright (C) 2016 by Maksym Hilliaka *
8  * oter@frozen-team.com *
9  * *
10  * Copyright (C) 2016 by Phillip Pearson *
11  * pp@myelin.co.nz *
12  * *
13  * Copyright (C) 2014 by Paul Fertser *
14  * fercerpav@gmail.com *
15  * *
16  * Copyright (C) 2013 by mike brown *
17  * mike@theshedworks.org.uk *
18  * *
19  * Copyright (C) 2013 by Spencer Oliver *
20  * spen@spen-soft.co.uk *
21  ***************************************************************************/
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <string.h>
28 #include <hidapi.h>
29 #include <helper/log.h>
30 
31 #include "cmsis_dap.h"
32 
34  hid_device *dev_handle;
35 };
36 
38  unsigned short vid;
39  unsigned short pid;
40  unsigned int report_size;
41 };
42 
43 static const struct cmsis_dap_report_size report_size_quirks[] = {
44  /* Third gen Atmel tools use a report size of 512 */
45  /* This list of PIDs comes from toolinfo.py in Microchip's pyedbglib. */
46  // Atmel JTAG-ICE 3
47  { .vid = 0x03eb, .pid = 0x2140, .report_size = 512 },
48  // Atmel-ICE
49  { .vid = 0x03eb, .pid = 0x2141, .report_size = 512 },
50  // Atmel Power Debugger
51  { .vid = 0x03eb, .pid = 0x2144, .report_size = 512 },
52  // EDBG (found on Xplained Pro boards)
53  { .vid = 0x03eb, .pid = 0x2111, .report_size = 512 },
54  // Zero (???)
55  { .vid = 0x03eb, .pid = 0x2157, .report_size = 512 },
56  // EDBG with Mass Storage (found on Xplained Pro boards)
57  { .vid = 0x03eb, .pid = 0x2169, .report_size = 512 },
58  // Commercially available EDBG (for third-party use)
59  { .vid = 0x03eb, .pid = 0x216a, .report_size = 512 },
60  // Kraken (???)
61  { .vid = 0x03eb, .pid = 0x2170, .report_size = 512 },
62 
63  { .vid = 0, .pid = 0, .report_size = 0 }
64 };
65 
66 
67 static void cmsis_dap_hid_close(struct cmsis_dap *dap);
68 static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
69 static void cmsis_dap_hid_free(struct cmsis_dap *dap);
70 
71 static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial)
72 {
73  hid_device *dev = NULL;
74  int i;
75  struct hid_device_info *devs, *cur_dev;
76  unsigned short target_vid, target_pid;
77 
78  target_vid = 0;
79  target_pid = 0;
80 
81  if (hid_init() != 0) {
82  LOG_ERROR("unable to open HIDAPI");
83  return ERROR_FAIL;
84  }
85 
86  /*
87  * The CMSIS-DAP specification stipulates:
88  * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
89  * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
90  */
91  devs = hid_enumerate(0x0, 0x0);
92  cur_dev = devs;
93  while (cur_dev) {
94  bool found = false;
95 
96  if (vids[0] == 0) {
97  if (!cur_dev->product_string) {
98  LOG_DEBUG("Cannot read product string of device 0x%x:0x%x",
99  cur_dev->vendor_id, cur_dev->product_id);
100  } else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) {
101  /* if the user hasn't specified VID:PID *and*
102  * product string contains "CMSIS-DAP", pick it
103  */
104  found = true;
105  }
106  } else {
107  /* otherwise, exhaustively compare against all VID:PID in list */
108  for (i = 0; vids[i] || pids[i]; i++) {
109  if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id))
110  found = true;
111  }
112  }
113 
114  /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */
115  if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0)
116  found = false;
117 
118  if (found) {
119  /* check serial number matches if given */
120  if (!serial)
121  break;
122 
123  if (cur_dev->serial_number) {
124  size_t len = mbstowcs(NULL, serial, 0) + 1;
125  wchar_t *wserial = malloc(len * sizeof(wchar_t));
126  if (!wserial) {
127  LOG_ERROR("unable to allocate serial number buffer");
128  return ERROR_FAIL;
129  }
130  mbstowcs(wserial, serial, len);
131 
132  if (wcscmp(wserial, cur_dev->serial_number) == 0) {
133  free(wserial);
134  break;
135  } else {
136  free(wserial);
137  wserial = NULL;
138  }
139  }
140  }
141 
142  cur_dev = cur_dev->next;
143  }
144 
145  if (cur_dev) {
146  target_vid = cur_dev->vendor_id;
147  target_pid = cur_dev->product_id;
148  }
149 
150  if (target_vid == 0 && target_pid == 0) {
151  hid_free_enumeration(devs);
152  return ERROR_FAIL;
153  }
154 
155  dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
156  if (!dap->bdata) {
157  LOG_ERROR("unable to allocate memory");
158  return ERROR_FAIL;
159  }
160 
161  dev = hid_open_path(cur_dev->path);
162  hid_free_enumeration(devs);
163 
164  if (!dev) {
165  LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid);
166  return ERROR_FAIL;
167  }
168 
169  /* allocate default packet buffer, may be changed later.
170  * currently with HIDAPI we have no way of getting the output report length
171  * without this info we cannot communicate with the adapter.
172  * For the moment we have to hard code the packet size */
173 
174  unsigned int packet_size = 64;
175 
176  /* Check for adapters that are known to have unusual report lengths. */
177  for (i = 0; report_size_quirks[i].vid != 0; i++) {
178  if (report_size_quirks[i].vid == target_vid &&
179  report_size_quirks[i].pid == target_pid) {
180  packet_size = report_size_quirks[i].report_size;
181  }
182  }
183  /* TODO: HID report descriptor should be parsed instead of
184  * hardcoding a match by VID/PID */
185 
186  dap->bdata->dev_handle = dev;
187 
188  int retval = cmsis_dap_hid_alloc(dap, packet_size);
189  if (retval != ERROR_OK) {
190  cmsis_dap_hid_close(dap);
191  return ERROR_FAIL;
192  }
193 
194  dap->command = dap->packet_buffer + REPORT_ID_SIZE;
195  dap->response = dap->packet_buffer;
196  return ERROR_OK;
197 }
198 
199 static void cmsis_dap_hid_close(struct cmsis_dap *dap)
200 {
201  hid_close(dap->bdata->dev_handle);
202  hid_exit();
203  free(dap->bdata);
204  dap->bdata = NULL;
205  cmsis_dap_hid_free(dap);
206 }
207 
208 static int cmsis_dap_hid_read(struct cmsis_dap *dap, int transfer_timeout_ms,
209  struct timeval *wait_timeout)
210 {
211  int timeout_ms;
212  if (wait_timeout)
213  timeout_ms = wait_timeout->tv_usec / 1000 + wait_timeout->tv_sec * 1000;
214  else
215  timeout_ms = transfer_timeout_ms;
216 
217  int retval = hid_read_timeout(dap->bdata->dev_handle,
219  timeout_ms);
220  if (retval == 0) {
221  return ERROR_TIMEOUT_REACHED;
222  } else if (retval == -1) {
223  LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle));
224  return ERROR_FAIL;
225  }
226 
227  return retval;
228 }
229 
230 static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
231 {
232  (void) timeout_ms;
233 
234  dap->packet_buffer[0] = 0; /* HID report number */
235 
236  /* Pad the rest of the TX buffer with 0's */
237  memset(dap->command + txlen, 0, dap->packet_size - txlen);
238 
239  /* write data to device */
240  int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size);
241  if (retval == -1) {
242  LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle));
243  return ERROR_FAIL;
244  }
245 
246  return retval;
247 }
248 
249 static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
250 {
251  unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE;
252  uint8_t *buf = malloc(packet_buffer_size);
253  if (!buf) {
254  LOG_ERROR("unable to allocate CMSIS-DAP packet buffer");
255  return ERROR_FAIL;
256  }
257 
258  dap->packet_buffer = buf;
259  dap->packet_size = pkt_sz;
260  dap->packet_usable_size = pkt_sz;
261  dap->packet_buffer_size = packet_buffer_size;
262 
263  dap->command = dap->packet_buffer + REPORT_ID_SIZE;
264  dap->response = dap->packet_buffer;
265 
266  return ERROR_OK;
267 }
268 
269 static void cmsis_dap_hid_free(struct cmsis_dap *dap)
270 {
271  free(dap->packet_buffer);
272  dap->packet_buffer = NULL;
273 }
274 
275 static void cmsis_dap_hid_cancel_all(struct cmsis_dap *dap)
276 {
277 }
278 
280  .name = "hid",
281  .open = cmsis_dap_hid_open,
282  .close = cmsis_dap_hid_close,
283  .read = cmsis_dap_hid_read,
284  .write = cmsis_dap_hid_write,
285  .packet_buffer_alloc = cmsis_dap_hid_alloc,
286  .packet_buffer_free = cmsis_dap_hid_free,
287  .cancel_all = cmsis_dap_hid_cancel_all,
288 };
char * serial
Definition: adapter.c:43
#define REPORT_ID_SIZE
Definition: cmsis_dap.h:77
static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial)
static int cmsis_dap_hid_read(struct cmsis_dap *dap, int transfer_timeout_ms, struct timeval *wait_timeout)
static void cmsis_dap_hid_close(struct cmsis_dap *dap)
static void cmsis_dap_hid_cancel_all(struct cmsis_dap *dap)
static void cmsis_dap_hid_free(struct cmsis_dap *dap)
const struct cmsis_dap_backend cmsis_dap_hid_backend
static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
static const struct cmsis_dap_report_size report_size_quirks[]
static struct libusb_device ** devs
The usb device list.
Definition: libusb_helper.c:26
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define ERROR_TIMEOUT_REACHED
Definition: log.h:173
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
struct libusb_device_handle * dev_handle
const char * name
Definition: cmsis_dap.h:62
unsigned int packet_buffer_size
Definition: cmsis_dap.h:32
unsigned int packet_usable_size
Definition: cmsis_dap.h:31
unsigned int packet_size
Definition: cmsis_dap.h:30
struct cmsis_dap_backend_data * bdata
Definition: cmsis_dap.h:28
uint8_t * response
Definition: cmsis_dap.h:35
uint8_t * command
Definition: cmsis_dap.h:34
uint8_t * packet_buffer
Definition: cmsis_dap.h:33
long tv_sec
Definition: replacements.h:46
long tv_usec
Definition: replacements.h:47
#define NULL
Definition: usb.h:16