Remove FSF address from GPL notices
[openocd.git] / src / jtag / drivers / versaloon / versaloon.c
1 /***************************************************************************
2 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <libusb.h>
25
26 #include "versaloon_include.h"
27 #include "versaloon.h"
28 #include "versaloon_internal.h"
29 #include "usbtoxxx/usbtoxxx.h"
30
31 uint8_t *versaloon_buf;
32 uint8_t *versaloon_cmd_buf;
33 uint16_t versaloon_buf_size;
34
35 struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
36 uint16_t versaloon_pending_idx;
37
38 libusb_device_handle *versaloon_usb_device_handle;
39 static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
40
41 RESULT versaloon_init(void);
42 RESULT versaloon_fini(void);
43 RESULT versaloon_get_target_voltage(uint16_t *voltage);
44 RESULT versaloon_set_target_voltage(uint16_t voltage);
45 RESULT versaloon_delay_ms(uint16_t ms);
46 RESULT versaloon_delay_us(uint16_t us);
47
48 struct versaloon_interface_t versaloon_interface = {
49 .init = versaloon_init,
50 .fini = versaloon_fini,
51 { /* adaptors */
52 { /* target_voltage */
53 .get = versaloon_get_target_voltage,
54 .set = versaloon_set_target_voltage,
55 },
56 { /* gpio */
57 .init = usbtogpio_init,
58 .fini = usbtogpio_fini,
59 .config = usbtogpio_config,
60 .out = usbtogpio_out,
61 .in = usbtogpio_in,
62 },
63 { /* delay */
64 .delayms = versaloon_delay_ms,
65 .delayus = versaloon_delay_us,
66 },
67 { /* swd */
68 .init = usbtoswd_init,
69 .fini = usbtoswd_fini,
70 .config = usbtoswd_config,
71 .seqout = usbtoswd_seqout,
72 .seqin = usbtoswd_seqin,
73 .transact = usbtoswd_transact,
74 },
75 { /* jtag_raw */
76 .init = usbtojtagraw_init,
77 .fini = usbtojtagraw_fini,
78 .config = usbtojtagraw_config,
79 .execute = usbtojtagraw_execute,
80 },
81 .peripheral_commit = usbtoxxx_execute_command,
82 },
83 { /* usb_setting */
84 .vid = VERSALOON_VID,
85 .pid = VERSALOON_PID,
86 .ep_out = VERSALOON_OUTP,
87 .ep_in = VERSALOON_INP,
88 .interface = VERSALOON_IFACE,
89 .serialstring = NULL,
90 .buf_size = 256,
91 }
92 };
93
94 /* programmer_cmd */
95 static uint32_t versaloon_pending_id;
96 static versaloon_callback_t versaloon_callback;
97 static void *versaloon_extra_data;
98 static struct versaloon_want_pos_t *versaloon_want_pos;
99
100 void versaloon_set_pending_id(uint32_t id)
101 {
102 versaloon_pending_id = id;
103 }
104 void versaloon_set_callback(versaloon_callback_t callback)
105 {
106 versaloon_callback = callback;
107 }
108 void versaloon_set_extra_data(void *p)
109 {
110 versaloon_extra_data = p;
111 }
112
113 void versaloon_free_want_pos(void)
114 {
115 uint16_t i;
116 struct versaloon_want_pos_t *tmp, *free_tmp;
117
118 tmp = versaloon_want_pos;
119 while (tmp != NULL) {
120 free_tmp = tmp;
121 tmp = tmp->next;
122 free(free_tmp);
123 }
124 versaloon_want_pos = NULL;
125
126 for (i = 0; i < dimof(versaloon_pending); i++) {
127 tmp = versaloon_pending[i].pos;
128 while (tmp != NULL) {
129 free_tmp = tmp;
130 tmp = tmp->next;
131 free(free_tmp);
132 }
133 versaloon_pending[i].pos = NULL;
134 }
135 }
136
137 RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
138 {
139 struct versaloon_want_pos_t *new_pos = NULL;
140
141 new_pos = malloc(sizeof(*new_pos));
142 if (NULL == new_pos) {
143 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
144 return ERRCODE_NOT_ENOUGH_MEMORY;
145 }
146 new_pos->offset = offset;
147 new_pos->size = size;
148 new_pos->buff = buff;
149 new_pos->next = NULL;
150
151 if (NULL == versaloon_want_pos)
152 versaloon_want_pos = new_pos;
153 else {
154 struct versaloon_want_pos_t *tmp = versaloon_want_pos;
155
156 while (tmp->next != NULL)
157 tmp = tmp->next;
158 tmp->next = new_pos;
159 }
160
161 return ERROR_OK;
162 }
163
164 RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
165 uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
166 {
167 #if PARAM_CHECK
168 if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) {
169 LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
170 "versaloon pending data");
171 return ERROR_FAIL;
172 }
173 #endif
174
175 versaloon_pending[versaloon_pending_idx].type = type;
176 versaloon_pending[versaloon_pending_idx].cmd = cmd;
177 versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
178 versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
179 versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
180 versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
181 versaloon_pending[versaloon_pending_idx].collect = collect;
182 versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
183 versaloon_pending_id = 0;
184 versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
185 versaloon_extra_data = NULL;
186 versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
187 versaloon_callback = NULL;
188 versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
189 versaloon_want_pos = NULL;
190 versaloon_pending_idx++;
191
192 return ERROR_OK;
193 }
194
195 RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
196 {
197 int ret;
198 int transferred;
199
200 #if PARAM_CHECK
201 if (NULL == versaloon_buf) {
202 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
203 return ERRCODE_INVALID_BUFFER;
204 }
205 if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size)) {
206 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
207 return ERRCODE_INVALID_PARAMETER;
208 }
209 #endif
210
211 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
212 versaloon_interface.usb_setting.ep_out,
213 versaloon_buf, out_len, &transferred, versaloon_usb_to);
214 if (0 != ret || transferred != out_len) {
215 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data");
216 return ERRCODE_FAILURE_OPERATION;
217 }
218
219 if (inlen != NULL) {
220 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
221 versaloon_interface.usb_setting.ep_in,
222 versaloon_buf, versaloon_interface.usb_setting.buf_size,
223 &transferred, versaloon_usb_to);
224 if (0 == ret) {
225 *inlen = (uint16_t)transferred;
226 return ERROR_OK;
227 } else {
228 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data");
229 return ERROR_FAIL;
230 }
231 } else
232 return ERROR_OK;
233 }
234
235 #define VERSALOON_RETRY_CNT 10
236 RESULT versaloon_init(void)
237 {
238 uint16_t ret = 0;
239 uint8_t retry;
240 uint32_t timeout_tmp;
241
242 /* malloc temporary buffer */
243 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
244 if (NULL == versaloon_buf) {
245 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
246 return ERRCODE_NOT_ENOUGH_MEMORY;
247 }
248
249 /* connect to versaloon */
250 timeout_tmp = versaloon_usb_to;
251 /* not output error message when connectting */
252 /* 100ms delay when connect */
253 versaloon_usb_to = 100;
254 for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) {
255 versaloon_buf[0] = VERSALOON_GET_INFO;
256 if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3))
257 break;
258 }
259 versaloon_usb_to = timeout_tmp;
260 if (VERSALOON_RETRY_CNT == retry) {
261 versaloon_fini();
262 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
263 return ERRCODE_FAILURE_OPERATION;
264 }
265
266 versaloon_buf[ret] = 0;
267 versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
268 versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
269 LOG_INFO("%s", versaloon_buf + 2);
270
271 /* free temporary buffer */
272 free(versaloon_buf);
273 versaloon_buf = NULL;
274
275 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
276 if (NULL == versaloon_buf) {
277 versaloon_fini();
278 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
279 return ERRCODE_NOT_ENOUGH_MEMORY;
280 }
281 versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3);
282 if (NULL == versaloon_cmd_buf) {
283 versaloon_fini();
284 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
285 return ERRCODE_NOT_ENOUGH_MEMORY;
286 }
287 if (ERROR_OK != usbtoxxx_init()) {
288 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
289 return ERROR_FAIL;
290 }
291 return versaloon_get_target_voltage(&ret);
292 }
293
294 RESULT versaloon_fini(void)
295 {
296 if (versaloon_usb_device_handle != NULL) {
297 usbtoxxx_fini();
298 versaloon_free_want_pos();
299
300 versaloon_usb_device_handle = NULL;
301
302 if (versaloon_buf != NULL) {
303 free(versaloon_buf);
304 versaloon_buf = NULL;
305 }
306 if (versaloon_cmd_buf != NULL) {
307 free(versaloon_cmd_buf);
308 versaloon_cmd_buf = NULL;
309 }
310 }
311
312 return ERROR_OK;
313 }
314
315 RESULT versaloon_set_target_voltage(uint16_t voltage)
316 {
317 usbtopwr_init(0);
318 usbtopwr_config(0);
319 usbtopwr_output(0, voltage);
320 usbtopwr_fini(0);
321
322 return usbtoxxx_execute_command();
323 }
324
325 RESULT versaloon_get_target_voltage(uint16_t *voltage)
326 {
327 uint16_t inlen;
328
329 #if PARAM_CHECK
330 if (NULL == versaloon_buf) {
331 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
332 return ERRCODE_INVALID_BUFFER;
333 }
334 if (NULL == voltage) {
335 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
336 return ERRCODE_INVALID_PARAMETER;
337 }
338 #endif
339
340 versaloon_buf[0] = VERSALOON_GET_TVCC;
341
342 if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) {
343 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
344 return ERRCODE_FAILURE_OPERATION;
345 } else {
346 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
347 return ERROR_OK;
348 }
349 }
350
351 RESULT versaloon_delay_ms(uint16_t ms)
352 {
353 return usbtodelay_delay(ms | 0x8000);
354 }
355
356 RESULT versaloon_delay_us(uint16_t us)
357 {
358 return usbtodelay_delay(us & 0x7FFF);
359 }

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)