1 /***************************************************************************
2 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
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. *
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. *
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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
18 ***************************************************************************/
28 #include "versaloon_include.h"
29 #include "versaloon.h"
30 #include "versaloon_internal.h"
31 #include "usbtoxxx/usbtoxxx.h"
33 uint8_t *versaloon_buf;
34 uint8_t *versaloon_cmd_buf;
35 uint16_t versaloon_buf_size;
37 struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
38 uint16_t versaloon_pending_idx;
40 libusb_device_handle *versaloon_usb_device_handle;
41 static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
43 RESULT versaloon_init(void);
44 RESULT versaloon_fini(void);
45 RESULT versaloon_get_target_voltage(uint16_t *voltage);
46 RESULT versaloon_set_target_voltage(uint16_t voltage);
47 RESULT versaloon_delay_ms(uint16_t ms);
48 RESULT versaloon_delay_us(uint16_t us);
50 struct versaloon_interface_t versaloon_interface = {
51 .init = versaloon_init,
52 .fini = versaloon_fini,
54 { /* target_voltage */
55 .get = versaloon_get_target_voltage,
56 .set = versaloon_set_target_voltage,
59 .init = usbtogpio_init,
60 .fini = usbtogpio_fini,
61 .config = usbtogpio_config,
66 .delayms = versaloon_delay_ms,
67 .delayus = versaloon_delay_us,
70 .init = usbtoswd_init,
71 .fini = usbtoswd_fini,
72 .config = usbtoswd_config,
73 .seqout = usbtoswd_seqout,
74 .seqin = usbtoswd_seqin,
75 .transact = usbtoswd_transact,
78 .init = usbtojtagraw_init,
79 .fini = usbtojtagraw_fini,
80 .config = usbtojtagraw_config,
81 .execute = usbtojtagraw_execute,
83 .peripheral_commit = usbtoxxx_execute_command,
88 .ep_out = VERSALOON_OUTP,
89 .ep_in = VERSALOON_INP,
90 .interface = VERSALOON_IFACE,
97 static uint32_t versaloon_pending_id;
98 static versaloon_callback_t versaloon_callback;
99 static void *versaloon_extra_data;
100 static struct versaloon_want_pos_t *versaloon_want_pos;
102 void versaloon_set_pending_id(uint32_t id)
104 versaloon_pending_id = id;
106 void versaloon_set_callback(versaloon_callback_t callback)
108 versaloon_callback = callback;
110 void versaloon_set_extra_data(void *p)
112 versaloon_extra_data = p;
115 void versaloon_free_want_pos(void)
118 struct versaloon_want_pos_t *tmp, *free_tmp;
120 tmp = versaloon_want_pos;
121 while (tmp != NULL) {
126 versaloon_want_pos = NULL;
128 for (i = 0; i < dimof(versaloon_pending); i++) {
129 tmp = versaloon_pending[i].pos;
130 while (tmp != NULL) {
135 versaloon_pending[i].pos = NULL;
139 RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
141 struct versaloon_want_pos_t *new_pos = NULL;
143 new_pos = malloc(sizeof(*new_pos));
144 if (NULL == new_pos) {
145 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
146 return ERRCODE_NOT_ENOUGH_MEMORY;
148 new_pos->offset = offset;
149 new_pos->size = size;
150 new_pos->buff = buff;
151 new_pos->next = NULL;
153 if (NULL == versaloon_want_pos)
154 versaloon_want_pos = new_pos;
156 struct versaloon_want_pos_t *tmp = versaloon_want_pos;
158 while (tmp->next != NULL)
166 RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
167 uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
170 if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) {
171 LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
172 "versaloon pending data");
177 versaloon_pending[versaloon_pending_idx].type = type;
178 versaloon_pending[versaloon_pending_idx].cmd = cmd;
179 versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
180 versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
181 versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
182 versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
183 versaloon_pending[versaloon_pending_idx].collect = collect;
184 versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
185 versaloon_pending_id = 0;
186 versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
187 versaloon_extra_data = NULL;
188 versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
189 versaloon_callback = NULL;
190 versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
191 versaloon_want_pos = NULL;
192 versaloon_pending_idx++;
197 RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
203 if (NULL == versaloon_buf) {
204 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
205 return ERRCODE_INVALID_BUFFER;
207 if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size)) {
208 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
209 return ERRCODE_INVALID_PARAMETER;
213 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
214 versaloon_interface.usb_setting.ep_out,
215 versaloon_buf, out_len, &transferred, versaloon_usb_to);
216 if (0 != ret || transferred != out_len) {
217 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data");
218 return ERRCODE_FAILURE_OPERATION;
222 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
223 versaloon_interface.usb_setting.ep_in,
224 versaloon_buf, versaloon_interface.usb_setting.buf_size,
225 &transferred, versaloon_usb_to);
227 *inlen = (uint16_t)transferred;
230 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data");
237 #define VERSALOON_RETRY_CNT 10
238 RESULT versaloon_init(void)
242 uint32_t timeout_tmp;
244 /* malloc temporary buffer */
245 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
246 if (NULL == versaloon_buf) {
247 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
248 return ERRCODE_NOT_ENOUGH_MEMORY;
251 /* connect to versaloon */
252 timeout_tmp = versaloon_usb_to;
253 /* not output error message when connectting */
254 /* 100ms delay when connect */
255 versaloon_usb_to = 100;
256 for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) {
257 versaloon_buf[0] = VERSALOON_GET_INFO;
258 if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3))
261 versaloon_usb_to = timeout_tmp;
262 if (VERSALOON_RETRY_CNT == retry) {
264 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
265 return ERRCODE_FAILURE_OPERATION;
268 versaloon_buf[ret] = 0;
269 versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
270 versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
271 LOG_INFO("%s", versaloon_buf + 2);
273 /* free temporary buffer */
275 versaloon_buf = NULL;
277 versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
278 if (NULL == versaloon_buf) {
280 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
281 return ERRCODE_NOT_ENOUGH_MEMORY;
283 versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3);
284 if (NULL == versaloon_cmd_buf) {
286 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
287 return ERRCODE_NOT_ENOUGH_MEMORY;
289 if (ERROR_OK != usbtoxxx_init()) {
290 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
293 return versaloon_get_target_voltage(&ret);
296 RESULT versaloon_fini(void)
298 if (versaloon_usb_device_handle != NULL) {
300 versaloon_free_want_pos();
302 versaloon_usb_device_handle = NULL;
304 if (versaloon_buf != NULL) {
306 versaloon_buf = NULL;
308 if (versaloon_cmd_buf != NULL) {
309 free(versaloon_cmd_buf);
310 versaloon_cmd_buf = NULL;
317 RESULT versaloon_set_target_voltage(uint16_t voltage)
321 usbtopwr_output(0, voltage);
324 return usbtoxxx_execute_command();
327 RESULT versaloon_get_target_voltage(uint16_t *voltage)
332 if (NULL == versaloon_buf) {
333 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
334 return ERRCODE_INVALID_BUFFER;
336 if (NULL == voltage) {
337 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
338 return ERRCODE_INVALID_PARAMETER;
342 versaloon_buf[0] = VERSALOON_GET_TVCC;
344 if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) {
345 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
346 return ERRCODE_FAILURE_OPERATION;
348 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
353 RESULT versaloon_delay_ms(uint16_t ms)
355 return usbtodelay_delay(ms | 0x8000);
358 RESULT versaloon_delay_us(uint16_t us)
360 return usbtodelay_delay(us & 0x7FFF);