605811d9523df91c37653cfff6a5fcd6b6cc5793
[fw/openocd] / src / jtag / drivers / cmsis_dap_usb_hid.c
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
33 struct cmsis_dap_backend_data {
34         hid_device *dev_handle;
35 };
36
37 static void cmsis_dap_hid_close(struct cmsis_dap *dap);
38 static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
39
40 static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial)
41 {
42         hid_device *dev = NULL;
43         int i;
44         struct hid_device_info *devs, *cur_dev;
45         unsigned short target_vid, target_pid;
46
47         target_vid = 0;
48         target_pid = 0;
49
50         if (hid_init() != 0) {
51                 LOG_ERROR("unable to open HIDAPI");
52                 return ERROR_FAIL;
53         }
54
55         /*
56          * The CMSIS-DAP specification stipulates:
57          * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
58          * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
59          */
60         devs = hid_enumerate(0x0, 0x0);
61         cur_dev = devs;
62         while (cur_dev) {
63                 bool found = false;
64
65                 if (vids[0] == 0) {
66                         if (!cur_dev->product_string) {
67                                 LOG_DEBUG("Cannot read product string of device 0x%x:0x%x",
68                                           cur_dev->vendor_id, cur_dev->product_id);
69                         } else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) {
70                                 /* if the user hasn't specified VID:PID *and*
71                                  * product string contains "CMSIS-DAP", pick it
72                                  */
73                                 found = true;
74                         }
75                 } else {
76                         /* otherwise, exhaustively compare against all VID:PID in list */
77                         for (i = 0; vids[i] || pids[i]; i++) {
78                                 if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id))
79                                         found = true;
80                         }
81                 }
82
83                 /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */
84                 if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0)
85                         found = false;
86
87                 if (found) {
88                         /* check serial number matches if given */
89                         if (!serial)
90                                 break;
91
92                         if (cur_dev->serial_number) {
93                                 size_t len = (strlen(serial) + 1) * sizeof(wchar_t);
94                                 wchar_t *wserial = malloc(len);
95                                 mbstowcs(wserial, serial, len);
96
97                                 if (wcscmp(wserial, cur_dev->serial_number) == 0) {
98                                         free(wserial);
99                                         break;
100                                 } else {
101                                         free(wserial);
102                                         wserial = NULL;
103                                 }
104                         }
105                 }
106
107                 cur_dev = cur_dev->next;
108         }
109
110         if (cur_dev) {
111                 target_vid = cur_dev->vendor_id;
112                 target_pid = cur_dev->product_id;
113         }
114
115         if (target_vid == 0 && target_pid == 0) {
116                 hid_free_enumeration(devs);
117                 return ERROR_FAIL;
118         }
119
120         dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
121         if (!dap->bdata) {
122                 LOG_ERROR("unable to allocate memory");
123                 return ERROR_FAIL;
124         }
125
126         dev = hid_open_path(cur_dev->path);
127         hid_free_enumeration(devs);
128
129         if (!dev) {
130                 LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid);
131                 return ERROR_FAIL;
132         }
133
134         /* allocate default packet buffer, may be changed later.
135          * currently with HIDAPI we have no way of getting the output report length
136          * without this info we cannot communicate with the adapter.
137          * For the moment we have to hard code the packet size */
138
139         unsigned int packet_size = 64;
140
141         /* atmel cmsis-dap uses 512 byte reports */
142         /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained
143          * board */
144         /* TODO: HID report descriptor should be parsed instead of
145          * hardcoding a match by VID */
146         if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175)
147                 packet_size = 512;
148
149         dap->bdata->dev_handle = dev;
150
151         int retval = cmsis_dap_hid_alloc(dap, packet_size);
152         if (retval != ERROR_OK) {
153                 cmsis_dap_hid_close(dap);
154                 return ERROR_FAIL;
155         }
156
157         dap->command = dap->packet_buffer + REPORT_ID_SIZE;
158         dap->response = dap->packet_buffer;
159         return ERROR_OK;
160 }
161
162 static void cmsis_dap_hid_close(struct cmsis_dap *dap)
163 {
164         hid_close(dap->bdata->dev_handle);
165         hid_exit();
166         free(dap->bdata);
167         dap->bdata = NULL;
168         free(dap->packet_buffer);
169         dap->packet_buffer = NULL;
170 }
171
172 static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms)
173 {
174         int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size, timeout_ms);
175
176         if (retval == 0) {
177                 return ERROR_TIMEOUT_REACHED;
178         } else if (retval == -1) {
179                 LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle));
180                 return ERROR_FAIL;
181         }
182
183         return retval;
184 }
185
186 static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
187 {
188         (void) timeout_ms;
189
190         dap->packet_buffer[0] = 0; /* HID report number */
191
192         /* Pad the rest of the TX buffer with 0's */
193         memset(dap->command + txlen, 0, dap->packet_size - txlen);
194
195         /* write data to device */
196         int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size);
197         if (retval == -1) {
198                 LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle));
199                 return ERROR_FAIL;
200         }
201
202         return retval;
203 }
204
205 static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
206 {
207         unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE;
208         uint8_t *buf = malloc(packet_buffer_size);
209         if (!buf) {
210                 LOG_ERROR("unable to allocate CMSIS-DAP packet buffer");
211                 return ERROR_FAIL;
212         }
213
214         dap->packet_buffer = buf;
215         dap->packet_size = pkt_sz;
216         dap->packet_buffer_size = packet_buffer_size;
217
218         dap->command = dap->packet_buffer + REPORT_ID_SIZE;
219         dap->response = dap->packet_buffer;
220
221         return ERROR_OK;
222 }
223
224 const struct cmsis_dap_backend cmsis_dap_hid_backend = {
225         .name = "hid",
226         .open = cmsis_dap_hid_open,
227         .close = cmsis_dap_hid_close,
228         .read = cmsis_dap_hid_read,
229         .write = cmsis_dap_hid_write,
230         .packet_buffer_alloc = cmsis_dap_hid_alloc,
231 };