1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
5 ***************************************************************************/
11 #include "versaloon_include.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
,
42 { /* target_voltage */
43 .get
= versaloon_get_target_voltage
,
44 .set
= versaloon_set_target_voltage
,
47 .init
= usbtogpio_init
,
48 .fini
= usbtogpio_fini
,
49 .config
= usbtogpio_config
,
54 .delayms
= versaloon_delay_ms
,
55 .delayus
= versaloon_delay_us
,
58 .init
= usbtoswd_init
,
59 .fini
= usbtoswd_fini
,
60 .config
= usbtoswd_config
,
61 .seqout
= usbtoswd_seqout
,
62 .seqin
= usbtoswd_seqin
,
63 .transact
= usbtoswd_transact
,
66 .init
= usbtojtagraw_init
,
67 .fini
= usbtojtagraw_fini
,
68 .config
= usbtojtagraw_config
,
69 .execute
= usbtojtagraw_execute
,
71 .peripheral_commit
= usbtoxxx_execute_command
,
76 .ep_out
= VERSALOON_OUTP
,
77 .ep_in
= VERSALOON_INP
,
78 .interface
= VERSALOON_IFACE
,
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)
105 struct versaloon_want_pos_t
*tmp
, *free_tmp
;
107 tmp
= versaloon_want_pos
;
113 versaloon_want_pos
= NULL
;
115 for (i
= 0; i
< ARRAY_SIZE(versaloon_pending
); i
++) {
116 tmp
= versaloon_pending
[i
].pos
;
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
));
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
;
143 struct versaloon_want_pos_t
*tmp
= versaloon_want_pos
;
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
)
157 if (versaloon_pending_idx
>= VERSALOON_MAX_PENDING_NUMBER
) {
158 LOG_BUG(ERRMSG_INVALID_INDEX
, versaloon_pending_idx
,
159 "versaloon pending data");
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
++;
184 RESULT
versaloon_send_command(uint16_t out_len
, uint16_t *inlen
)
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
;
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
;
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
);
214 *inlen
= (uint16_t)transferred
;
217 LOG_ERROR(ERRMSG_FAILURE_OPERATION
, "receive usb data");
224 #define VERSALOON_RETRY_CNT 10
225 static RESULT
versaloon_init(void)
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))
248 versaloon_usb_to
= timeout_tmp
;
249 if (retry
== VERSALOON_RETRY_CNT
) {
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 */
262 versaloon_buf
= NULL
;
264 versaloon_buf
= malloc(versaloon_interface
.usb_setting
.buf_size
);
265 if (!versaloon_buf
) {
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
) {
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");
280 return versaloon_get_target_voltage(&ret
);
283 static RESULT
versaloon_fini(void)
285 if (versaloon_usb_device_handle
) {
287 versaloon_free_want_pos();
289 versaloon_usb_device_handle
= NULL
;
292 versaloon_buf
= NULL
;
294 free(versaloon_cmd_buf
);
295 versaloon_cmd_buf
= NULL
;
301 static RESULT
versaloon_set_target_voltage(uint16_t voltage
)
305 usbtopwr_output(0, voltage
);
308 return usbtoxxx_execute_command();
311 static RESULT
versaloon_get_target_voltage(uint16_t *voltage
)
316 if (!versaloon_buf
) {
317 LOG_BUG(ERRMSG_INVALID_BUFFER
, TO_STR(versaloon_buf
));
318 return ERRCODE_INVALID_BUFFER
;
321 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
322 return ERRCODE_INVALID_PARAMETER
;
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
;
332 *voltage
= versaloon_buf
[0] + (versaloon_buf
[1] << 8);
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);