Documentation: fix warning "unbalanced square brackets"
[openocd.git] / src / jtag / drivers / versaloon / versaloon.c
blob48d317436b1c204a253ddd81651c7379fb853643
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
5 ***************************************************************************/
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
11 #include "versaloon_include.h"
13 #include <stdio.h>
14 #include <string.h>
15 #include <libusb.h>
17 #include "versaloon.h"
18 #include "versaloon_internal.h"
19 #include "usbtoxxx/usbtoxxx.h"
21 uint8_t *versaloon_buf;
22 uint8_t *versaloon_cmd_buf;
23 uint16_t versaloon_buf_size;
25 struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
26 uint16_t versaloon_pending_idx;
28 struct libusb_device_handle *versaloon_usb_device_handle;
29 static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
31 static RESULT versaloon_init(void);
32 static RESULT versaloon_fini(void);
33 static RESULT versaloon_get_target_voltage(uint16_t *voltage);
34 static RESULT versaloon_set_target_voltage(uint16_t voltage);
35 static RESULT versaloon_delay_ms(uint16_t ms);
36 static RESULT versaloon_delay_us(uint16_t us);
38 struct versaloon_interface_t versaloon_interface = {
39 .init = versaloon_init,
40 .fini = versaloon_fini,
41 { /* adaptors */
42 { /* target_voltage */
43 .get = versaloon_get_target_voltage,
44 .set = versaloon_set_target_voltage,
46 { /* gpio */
47 .init = usbtogpio_init,
48 .fini = usbtogpio_fini,
49 .config = usbtogpio_config,
50 .out = usbtogpio_out,
51 .in = usbtogpio_in,
53 { /* delay */
54 .delayms = versaloon_delay_ms,
55 .delayus = versaloon_delay_us,
57 { /* swd */
58 .init = usbtoswd_init,
59 .fini = usbtoswd_fini,
60 .config = usbtoswd_config,
61 .seqout = usbtoswd_seqout,
62 .seqin = usbtoswd_seqin,
63 .transact = usbtoswd_transact,
65 { /* jtag_raw */
66 .init = usbtojtagraw_init,
67 .fini = usbtojtagraw_fini,
68 .config = usbtojtagraw_config,
69 .execute = usbtojtagraw_execute,
71 .peripheral_commit = usbtoxxx_execute_command,
73 { /* usb_setting */
74 .vid = VERSALOON_VID,
75 .pid = VERSALOON_PID,
76 .ep_out = VERSALOON_OUTP,
77 .ep_in = VERSALOON_INP,
78 .interface = VERSALOON_IFACE,
79 .buf_size = 256,
83 /* programmer_cmd */
84 static uint32_t versaloon_pending_id;
85 static versaloon_callback_t versaloon_callback;
86 static void *versaloon_extra_data;
87 static struct versaloon_want_pos_t *versaloon_want_pos;
89 void versaloon_set_pending_id(uint32_t id)
91 versaloon_pending_id = id;
93 void versaloon_set_callback(versaloon_callback_t callback)
95 versaloon_callback = callback;
97 void versaloon_set_extra_data(void *p)
99 versaloon_extra_data = p;
102 void versaloon_free_want_pos(void)
104 uint16_t i;
105 struct versaloon_want_pos_t *tmp, *free_tmp;
107 tmp = versaloon_want_pos;
108 while (tmp) {
109 free_tmp = tmp;
110 tmp = tmp->next;
111 free(free_tmp);
113 versaloon_want_pos = NULL;
115 for (i = 0; i < ARRAY_SIZE(versaloon_pending); i++) {
116 tmp = versaloon_pending[i].pos;
117 while (tmp) {
118 free_tmp = tmp;
119 tmp = tmp->next;
120 free(free_tmp);
122 versaloon_pending[i].pos = NULL;
126 RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
128 struct versaloon_want_pos_t *new_pos = NULL;
130 new_pos = malloc(sizeof(*new_pos));
131 if (!new_pos) {
132 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
133 return ERRCODE_NOT_ENOUGH_MEMORY;
135 new_pos->offset = offset;
136 new_pos->size = size;
137 new_pos->buff = buff;
138 new_pos->next = NULL;
140 if (!versaloon_want_pos)
141 versaloon_want_pos = new_pos;
142 else {
143 struct versaloon_want_pos_t *tmp = versaloon_want_pos;
145 while (tmp->next)
146 tmp = tmp->next;
147 tmp->next = new_pos;
150 return ERROR_OK;
153 RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
154 uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
156 #if PARAM_CHECK
157 if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) {
158 LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
159 "versaloon pending data");
160 return ERROR_FAIL;
162 #endif
164 versaloon_pending[versaloon_pending_idx].type = type;
165 versaloon_pending[versaloon_pending_idx].cmd = cmd;
166 versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
167 versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
168 versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
169 versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
170 versaloon_pending[versaloon_pending_idx].collect = collect;
171 versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
172 versaloon_pending_id = 0;
173 versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
174 versaloon_extra_data = NULL;
175 versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
176 versaloon_callback = NULL;
177 versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
178 versaloon_want_pos = NULL;
179 versaloon_pending_idx++;
181 return ERROR_OK;
184 RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
186 int ret;
187 int transferred;
189 #if PARAM_CHECK
190 if (!versaloon_buf) {
191 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
192 return ERRCODE_INVALID_BUFFER;
194 if ((out_len == 0) || (out_len > versaloon_interface.usb_setting.buf_size)) {
195 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
196 return ERRCODE_INVALID_PARAMETER;
198 #endif
200 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
201 versaloon_interface.usb_setting.ep_out,
202 versaloon_buf, out_len, &transferred, versaloon_usb_to);
203 if (ret != 0 || transferred != out_len) {
204 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data");
205 return ERRCODE_FAILURE_OPERATION;
208 if (inlen) {
209 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
210 versaloon_interface.usb_setting.ep_in,
211 versaloon_buf, versaloon_interface.usb_setting.buf_size,
212 &transferred, versaloon_usb_to);
213 if (ret == 0) {
214 *inlen = (uint16_t)transferred;
215 return ERROR_OK;
216 } else {
217 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data");
218 return ERROR_FAIL;
220 } else
221 return ERROR_OK;
224 #define VERSALOON_RETRY_CNT 10
225 static RESULT versaloon_init(void)
227 uint16_t ret = 0;
228 uint8_t retry;
229 uint32_t timeout_tmp;
231 /* malloc temporary buffer */
232 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
233 if (!versaloon_buf) {
234 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
235 return ERRCODE_NOT_ENOUGH_MEMORY;
238 /* connect to versaloon */
239 timeout_tmp = versaloon_usb_to;
240 /* not output error message when connecting */
241 /* 100ms delay when connect */
242 versaloon_usb_to = 100;
243 for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) {
244 versaloon_buf[0] = VERSALOON_GET_INFO;
245 if ((versaloon_send_command(1, &ret) == ERROR_OK) && (ret >= 3))
246 break;
248 versaloon_usb_to = timeout_tmp;
249 if (retry == VERSALOON_RETRY_CNT) {
250 versaloon_fini();
251 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
252 return ERRCODE_FAILURE_OPERATION;
255 versaloon_buf[ret] = 0;
256 versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
257 versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
258 LOG_INFO("%s", versaloon_buf + 2);
260 /* free temporary buffer */
261 free(versaloon_buf);
262 versaloon_buf = NULL;
264 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
265 if (!versaloon_buf) {
266 versaloon_fini();
267 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
268 return ERRCODE_NOT_ENOUGH_MEMORY;
270 versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3);
271 if (!versaloon_cmd_buf) {
272 versaloon_fini();
273 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
274 return ERRCODE_NOT_ENOUGH_MEMORY;
276 if (usbtoxxx_init() != ERROR_OK) {
277 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
278 return ERROR_FAIL;
280 return versaloon_get_target_voltage(&ret);
283 static RESULT versaloon_fini(void)
285 if (versaloon_usb_device_handle) {
286 usbtoxxx_fini();
287 versaloon_free_want_pos();
289 versaloon_usb_device_handle = NULL;
291 free(versaloon_buf);
292 versaloon_buf = NULL;
294 free(versaloon_cmd_buf);
295 versaloon_cmd_buf = NULL;
298 return ERROR_OK;
301 static RESULT versaloon_set_target_voltage(uint16_t voltage)
303 usbtopwr_init(0);
304 usbtopwr_config(0);
305 usbtopwr_output(0, voltage);
306 usbtopwr_fini(0);
308 return usbtoxxx_execute_command();
311 static RESULT versaloon_get_target_voltage(uint16_t *voltage)
313 uint16_t inlen;
315 #if PARAM_CHECK
316 if (!versaloon_buf) {
317 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
318 return ERRCODE_INVALID_BUFFER;
320 if (!voltage) {
321 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
322 return ERRCODE_INVALID_PARAMETER;
324 #endif
326 versaloon_buf[0] = VERSALOON_GET_TVCC;
328 if ((versaloon_send_command(1, &inlen) != ERROR_OK) || (inlen != 2)) {
329 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
330 return ERRCODE_FAILURE_OPERATION;
331 } else {
332 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
333 return ERROR_OK;
337 static RESULT versaloon_delay_ms(uint16_t ms)
339 return usbtodelay_delay(ms | 0x8000);
342 static RESULT versaloon_delay_us(uint16_t us)
344 return usbtodelay_delay(us & 0x7FFF);