libusb: don't use typedef's
[fw/openocd] / 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 struct libusb_device_handle *versaloon_usb_device_handle;
39 static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
40
41 static RESULT versaloon_init(void);
42 static RESULT versaloon_fini(void);
43 static RESULT versaloon_get_target_voltage(uint16_t *voltage);
44 static RESULT versaloon_set_target_voltage(uint16_t voltage);
45 static RESULT versaloon_delay_ms(uint16_t ms);
46 static 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 static 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 connecting */
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 static 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                 free(versaloon_buf);
303                 versaloon_buf = NULL;
304
305                 free(versaloon_cmd_buf);
306                 versaloon_cmd_buf = NULL;
307         }
308
309         return ERROR_OK;
310 }
311
312 static RESULT versaloon_set_target_voltage(uint16_t voltage)
313 {
314         usbtopwr_init(0);
315         usbtopwr_config(0);
316         usbtopwr_output(0, voltage);
317         usbtopwr_fini(0);
318
319         return usbtoxxx_execute_command();
320 }
321
322 static RESULT versaloon_get_target_voltage(uint16_t *voltage)
323 {
324         uint16_t inlen;
325
326 #if PARAM_CHECK
327         if (NULL == versaloon_buf) {
328                 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
329                 return ERRCODE_INVALID_BUFFER;
330         }
331         if (NULL == voltage) {
332                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
333                 return ERRCODE_INVALID_PARAMETER;
334         }
335 #endif
336
337         versaloon_buf[0] = VERSALOON_GET_TVCC;
338
339         if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) {
340                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
341                 return ERRCODE_FAILURE_OPERATION;
342         } else {
343                 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
344                 return ERROR_OK;
345         }
346 }
347
348 static RESULT versaloon_delay_ms(uint16_t ms)
349 {
350         return usbtodelay_delay(ms | 0x8000);
351 }
352
353 static RESULT versaloon_delay_us(uint16_t us)
354 {
355         return usbtodelay_delay(us & 0x7FFF);
356 }