versaloon driver update
[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, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <stdio.h>
24 #include <string.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 = NULL;
32 uint8_t *versaloon_cmd_buf = NULL;
33 uint16_t versaloon_buf_size;
34
35 struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
36 uint16_t versaloon_pending_idx = 0;
37
38 usb_dev_handle *versaloon_usb_device_handle = NULL;
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 struct versaloon_interface_t versaloon_interface =
48 {
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 = 0;
96 static versaloon_callback_t versaloon_callback = NULL;
97 static void *versaloon_extra_data = NULL;
98 static struct versaloon_want_pos_t *versaloon_want_pos = NULL;
99 void versaloon_set_pending_id(uint32_t id)
100 {
101         versaloon_pending_id = id;
102 }
103 void versaloon_set_callback(versaloon_callback_t callback)
104 {
105         versaloon_callback = callback;
106 }
107 void versaloon_set_extra_data(void * p)
108 {
109         versaloon_extra_data = p;
110 }
111
112 void versaloon_free_want_pos(void)
113 {
114         uint16_t i;
115         struct versaloon_want_pos_t *tmp, *free_tmp;
116
117         tmp = versaloon_want_pos;
118         while (tmp != NULL)
119         {
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         {
128                 tmp = versaloon_pending[i].pos;
129                 while (tmp != NULL)
130                 {
131                         free_tmp = tmp;
132                         tmp = tmp->next;
133                         free(free_tmp);
134                 }
135                 versaloon_pending[i].pos = NULL;
136         }
137 }
138
139 RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
140 {
141         struct versaloon_want_pos_t *new_pos = NULL;
142
143         new_pos = (struct versaloon_want_pos_t *)malloc(sizeof(*new_pos));
144         if (NULL == new_pos)
145         {
146                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
147                 return ERRCODE_NOT_ENOUGH_MEMORY;
148         }
149         new_pos->offset = offset;
150         new_pos->size = size;
151         new_pos->buff = buff;
152         new_pos->next = NULL;
153
154         if (NULL == versaloon_want_pos)
155         {
156                 versaloon_want_pos = new_pos;
157         }
158         else
159         {
160                 struct versaloon_want_pos_t *tmp = versaloon_want_pos;
161
162                 while (tmp->next != NULL)
163                 {
164                         tmp = tmp->next;
165                 }
166                 tmp->next = new_pos;
167         }
168
169         return ERROR_OK;
170 }
171
172 RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
173         uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
174 {
175 #if PARAM_CHECK
176         if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)
177         {
178                 LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
179                                         "versaloon pending data");
180                 return ERROR_FAIL;
181         }
182 #endif
183
184         versaloon_pending[versaloon_pending_idx].type = type;
185         versaloon_pending[versaloon_pending_idx].cmd = cmd;
186         versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
187         versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
188         versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
189         versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
190         versaloon_pending[versaloon_pending_idx].collect = collect;
191         versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
192         versaloon_pending_id = 0;
193         versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
194         versaloon_extra_data = NULL;
195         versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
196         versaloon_callback = NULL;
197         versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
198         versaloon_want_pos = NULL;
199         versaloon_pending_idx++;
200
201         return ERROR_OK;
202 }
203
204 RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
205 {
206         int ret;
207
208 #if PARAM_CHECK
209         if (NULL == versaloon_buf)
210         {
211                 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
212                 return ERRCODE_INVALID_BUFFER;
213         }
214         if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size))
215         {
216                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
217                 return ERRCODE_INVALID_PARAMETER;
218         }
219 #endif
220
221         ret = usb_bulk_write(versaloon_usb_device_handle,
222                 versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf,
223                 out_len, versaloon_usb_to);
224         if (ret != out_len)
225         {
226                 LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data",
227                         usb_strerror());
228                 return ERRCODE_FAILURE_OPERATION;
229         }
230
231         if (inlen != NULL)
232         {
233                 ret = usb_bulk_read(versaloon_usb_device_handle,
234                         versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf,
235                         versaloon_interface.usb_setting.buf_size, versaloon_usb_to);
236                 if (ret > 0)
237                 {
238                         *inlen = (uint16_t)ret;
239                         return ERROR_OK;
240                 }
241                 else
242                 {
243                         LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data",
244                                                 usb_strerror());
245                         return ERROR_FAIL;
246                 }
247         }
248         else
249         {
250                 return ERROR_OK;
251         }
252 }
253
254 #define VERSALOON_RETRY_CNT                             10
255 RESULT versaloon_init(void)
256 {
257         uint16_t ret = 0;
258         uint8_t retry;
259         uint32_t timeout_tmp;
260
261         // malloc temporary buffer
262         versaloon_buf =
263                 (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
264         if (NULL == versaloon_buf)
265         {
266                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
267                 return ERRCODE_NOT_ENOUGH_MEMORY;
268         }
269
270         // connect to versaloon
271         timeout_tmp = versaloon_usb_to;
272         // not output error message when connectting
273         // 100ms delay when connect
274         versaloon_usb_to = 100;
275         for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++)
276         {
277                 versaloon_buf[0] = VERSALOON_GET_INFO;
278                 if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3))
279                 {
280                         break;
281                 }
282         }
283         versaloon_usb_to = timeout_tmp;
284         if (VERSALOON_RETRY_CNT == retry)
285         {
286                 versaloon_fini();
287                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
288                 return ERRCODE_FAILURE_OPERATION;
289         }
290
291         versaloon_buf[ret] = 0;
292         versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
293         versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
294         LOG_INFO("%s", versaloon_buf + 2);
295
296         // free temporary buffer
297         free(versaloon_buf);
298         versaloon_buf = NULL;
299
300         versaloon_buf =
301                 (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
302         if (NULL == versaloon_buf)
303         {
304                 versaloon_fini();
305                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
306                 return ERRCODE_NOT_ENOUGH_MEMORY;
307         }
308         versaloon_cmd_buf =
309                 (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size - 3);
310         if (NULL == versaloon_cmd_buf)
311         {
312                 versaloon_fini();
313                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
314                 return ERRCODE_NOT_ENOUGH_MEMORY;
315         }
316         if (ERROR_OK != usbtoxxx_init())
317         {
318                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
319                 return ERROR_FAIL;
320         }
321         return versaloon_get_target_voltage(&ret);
322 }
323
324 RESULT versaloon_fini(void)
325 {
326         if (versaloon_usb_device_handle != NULL)
327         {
328                 usbtoxxx_fini();
329                 versaloon_free_want_pos();
330
331                 versaloon_usb_device_handle = NULL;
332
333                 if (versaloon_buf != NULL)
334                 {
335                         free(versaloon_buf);
336                         versaloon_buf = NULL;
337                 }
338                 if (versaloon_cmd_buf != NULL)
339                 {
340                         free(versaloon_cmd_buf);
341                         versaloon_cmd_buf = NULL;
342                 }
343         }
344
345         return ERROR_OK;
346 }
347
348 RESULT versaloon_set_target_voltage(uint16_t voltage)
349 {
350         usbtopwr_init(0);
351         usbtopwr_config(0);
352         usbtopwr_output(0, voltage);
353         usbtopwr_fini(0);
354
355         return usbtoxxx_execute_command();
356 }
357
358 RESULT versaloon_get_target_voltage(uint16_t *voltage)
359 {
360         uint16_t inlen;
361
362 #if PARAM_CHECK
363         if (NULL == versaloon_buf)
364         {
365                 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
366                 return ERRCODE_INVALID_BUFFER;
367         }
368         if (NULL == voltage)
369         {
370                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
371                 return ERRCODE_INVALID_PARAMETER;
372         }
373 #endif
374
375         versaloon_buf[0] = VERSALOON_GET_TVCC;
376
377         if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2))
378         {
379                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
380                 return ERRCODE_FAILURE_OPERATION;
381         }
382         else
383         {
384                 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
385                 return ERROR_OK;
386         }
387 }
388
389 RESULT versaloon_delay_ms(uint16_t ms)
390 {
391         return usbtodelay_delay(ms | 0x8000);
392 }
393
394 RESULT versaloon_delay_us(uint16_t us)
395 {
396         return usbtodelay_delay(us & 0x7FFF);
397 }
398