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