1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> *
5 ***************************************************************************/
13 #include "../versaloon_include.h"
14 #include "../versaloon.h"
15 #include "../versaloon_internal.h"
17 #include "usbtoxxx_internal.h"
21 static const char *types_name
[96] = {
22 "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm",
23 "usbtoadc", "usbtodac",
24 "usbtomicrowire", "usbtoswim", "usbtodusi", N_A
, N_A
, N_A
, "usbtopower", "usbtodelay",
25 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
26 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
27 "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw",
28 "usbtolpcicp", "usbtoswd", "usbtojtagraw",
29 "usbtobdm", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
30 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
31 "usbtomsp430jtag", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
32 "usbtopower", "usbtodelay", "usbtopoll", N_A
, N_A
, N_A
, N_A
, N_A
,
33 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, "usbtoall"
36 uint8_t usbtoxxx_abilities
[USB_TO_XXX_ABILITIES_LEN
];
38 #define usbtoxxx_get_type_name(type) \
39 types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
40 % ARRAY_SIZE(types_name)]
42 static uint8_t type_pre
;
43 static uint16_t usbtoxxx_buffer_index
;
44 static uint16_t usbtoxxx_current_cmd_index
;
45 static uint8_t *usbtoxxx_buffer
;
47 static uint16_t collect_index
;
48 static uint8_t collect_cmd
;
49 static uint8_t poll_nesting
;
51 struct usbtoxxx_context_t
{
53 uint8_t *usbtoxxx_buffer
;
54 uint16_t usbtoxxx_current_cmd_index
;
55 uint16_t usbtoxxx_buffer_index
;
56 uint16_t versaloon_pending_idx
;
58 static struct usbtoxxx_context_t poll_context
;
60 static void usbtoxxx_save_context(struct usbtoxxx_context_t
*c
)
62 c
->type_pre
= type_pre
;
63 c
->usbtoxxx_buffer
= usbtoxxx_buffer
;
64 c
->usbtoxxx_buffer_index
= usbtoxxx_buffer_index
;
65 c
->usbtoxxx_current_cmd_index
= usbtoxxx_current_cmd_index
;
66 c
->versaloon_pending_idx
= versaloon_pending_idx
;
69 static void usbtoxxx_pop_context(struct usbtoxxx_context_t
*c
)
71 type_pre
= c
->type_pre
;
72 usbtoxxx_buffer
= c
->usbtoxxx_buffer
;
73 usbtoxxx_buffer_index
= c
->usbtoxxx_buffer_index
;
74 usbtoxxx_current_cmd_index
= c
->usbtoxxx_current_cmd_index
;
75 versaloon_pending_idx
= c
->versaloon_pending_idx
;
78 static RESULT
usbtoxxx_validate_current_command_type(void)
81 /* not the first command */
82 if (!usbtoxxx_buffer
) {
83 LOG_BUG(ERRMSG_INVALID_BUFFER
, TO_STR(usbtoxxx_buffer
));
84 return ERRCODE_INVALID_BUFFER
;
87 usbtoxxx_buffer
[0] = type_pre
;
88 SET_LE_U16(&usbtoxxx_buffer
[1], usbtoxxx_current_cmd_index
);
90 usbtoxxx_buffer_index
+= usbtoxxx_current_cmd_index
;
93 usbtoxxx_buffer_index
= 3;
96 /* prepare for next command */
97 usbtoxxx_current_cmd_index
= 3;
98 usbtoxxx_buffer
= versaloon_buf
+ usbtoxxx_buffer_index
;
106 RESULT
usbtoxxx_execute_command(void)
110 RESULT result
= ERROR_OK
;
113 LOG_BUG(ERRMSG_INVALID_USAGE
, "USB_TO_POLL");
114 versaloon_free_want_pos();
118 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
119 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
120 versaloon_free_want_pos();
121 return ERRCODE_FAILURE_OPERATION
;
123 if (usbtoxxx_buffer_index
== 3) {
124 versaloon_free_want_pos();
128 versaloon_buf
[0] = USB_TO_ALL
;
129 SET_LE_U16(&versaloon_buf
[1], usbtoxxx_buffer_index
);
131 if (versaloon_send_command(usbtoxxx_buffer_index
, &inlen
) != ERROR_OK
) {
132 versaloon_free_want_pos();
136 /* process return data */
137 usbtoxxx_buffer_index
= 0;
138 for (i
= 0; i
< versaloon_pending_idx
; i
++) {
140 if ((i
== 0) || !((versaloon_pending
[i
].collect
)
141 && (versaloon_pending
[i
- 1].collect
)
142 && (versaloon_pending
[i
].cmd
143 == versaloon_pending
[i
- 1].cmd
))) {
144 if (USB_TO_XXX_CMD_NOT_SUPPORT
145 == versaloon_buf
[usbtoxxx_buffer_index
]) {
146 LOG_ERROR(ERRMSG_NOT_SUPPORT_BY
,
147 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
151 } else if (versaloon_buf
[usbtoxxx_buffer_index
] != USB_TO_XXX_OK
) {
152 LOG_ERROR("%s command 0x%02x failed with 0x%02x",
153 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
154 versaloon_pending
[i
].cmd
,
155 versaloon_buf
[usbtoxxx_buffer_index
]);
159 usbtoxxx_buffer_index
++;
162 /* get result data */
163 if (versaloon_pending
[i
].pos
) {
164 uint8_t processed
= 0;
166 if (versaloon_pending
[i
].callback
) {
167 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
168 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
171 struct versaloon_want_pos_t
*tmp
;
173 tmp
= versaloon_pending
[i
].pos
;
175 if ((tmp
->buff
) && (tmp
->size
> 0)) {
177 versaloon_buf
+ usbtoxxx_buffer_index
181 struct versaloon_want_pos_t
*free_tmp
;
186 versaloon_pending
[i
].pos
= NULL
;
188 } else if ((versaloon_pending
[i
].want_data_size
> 0)
189 && (versaloon_pending
[i
].data_buffer
)) {
190 uint8_t processed
= 0;
192 if (versaloon_pending
[i
].callback
) {
193 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
194 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
197 memcpy(versaloon_pending
[i
].data_buffer
,
198 versaloon_buf
+ usbtoxxx_buffer_index
199 + versaloon_pending
[i
].want_data_pos
,
200 versaloon_pending
[i
].want_data_size
);
203 usbtoxxx_buffer_index
+= versaloon_pending
[i
].actual_data_size
;
204 if (usbtoxxx_buffer_index
> inlen
) {
205 LOG_BUG("%s command 0x%02x process error",
206 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
207 versaloon_pending
[i
].cmd
);
213 /* data is not the right size */
214 if (inlen
!= usbtoxxx_buffer_index
) {
215 LOG_ERROR(ERRMSG_INVALID_TARGET
, "length of return data");
219 if (versaloon_pending_idx
> 0)
220 versaloon_pending_idx
= 0;
222 /* no receive data, avoid collision */
229 versaloon_free_want_pos();
233 RESULT
usbtoxxx_init(void)
235 versaloon_pending_idx
= 0;
237 if ((usbtoinfo_get_abilities(usbtoxxx_abilities
) != ERROR_OK
) ||
238 (usbtoxxx_execute_command() != ERROR_OK
))
240 LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X",
241 GET_LE_U32(&usbtoxxx_abilities
[0]),
242 GET_LE_U32(&usbtoxxx_abilities
[4]),
243 GET_LE_U32(&usbtoxxx_abilities
[8]));
247 RESULT
usbtoxxx_fini(void)
249 usbtoxxx_buffer
= NULL
;
254 bool usbtoxxx_interface_supported(uint8_t cmd
)
256 if ((cmd
< VERSALOON_USB_TO_XXX_CMD_START
) ||
257 (cmd
> VERSALOON_USB_TO_XXX_CMD_END
))
260 cmd
-= VERSALOON_USB_TO_XXX_CMD_START
;
261 return (usbtoxxx_abilities
[cmd
/ 8] & (1 << (cmd
% 8))) > 0;
264 static RESULT
usbtoxxx_ensure_buffer_size(uint16_t cmdlen
)
266 /* check free space, commit if not enough */
267 if (((usbtoxxx_buffer_index
+ usbtoxxx_current_cmd_index
+ cmdlen
)
268 >= versaloon_buf_size
)
269 || (versaloon_pending_idx
>= VERSALOON_MAX_PENDING_NUMBER
)) {
270 struct usbtoxxx_context_t context_tmp
;
271 uint8_t poll_nesting_tmp
= 0;
273 memset(&context_tmp
, 0, sizeof(context_tmp
));
275 if (poll_context
.type_pre
== 0) {
276 LOG_BUG("USB_TO_POLL toooooo long");
280 usbtoxxx_save_context(&context_tmp
);
281 usbtoxxx_pop_context(&poll_context
);
282 poll_nesting_tmp
= poll_nesting
;
286 if (usbtoxxx_execute_command() != ERROR_OK
)
289 if (poll_nesting_tmp
) {
290 uint16_t newlen
, oldlen
;
292 newlen
= context_tmp
.versaloon_pending_idx
293 - poll_context
.versaloon_pending_idx
;
294 memcpy(&versaloon_pending
[0],
295 &versaloon_pending
[poll_context
.versaloon_pending_idx
],
296 sizeof(versaloon_pending
[0]) * newlen
);
297 context_tmp
.versaloon_pending_idx
= newlen
;
298 oldlen
= poll_context
.usbtoxxx_buffer_index
299 + poll_context
.usbtoxxx_current_cmd_index
;
300 newlen
= context_tmp
.usbtoxxx_buffer_index
301 + context_tmp
.usbtoxxx_current_cmd_index
;
302 memcpy(versaloon_buf
+ 3, versaloon_buf
+ oldlen
, newlen
- oldlen
);
304 context_tmp
.usbtoxxx_buffer
-= oldlen
;
305 context_tmp
.usbtoxxx_buffer_index
-= oldlen
;
306 usbtoxxx_pop_context(&context_tmp
);
307 poll_nesting
= poll_nesting_tmp
;
313 RESULT
usbtoxxx_add_command(uint8_t type
, uint8_t cmd
, uint8_t *cmdbuf
,
314 uint16_t cmdlen
, uint16_t retlen
, uint8_t *wantbuf
,
315 uint16_t wantpos
, uint16_t wantlen
, uint8_t collect
)
319 /* 3 more bytes by usbtoxxx_validate_current_command_type */
320 /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */
321 if (usbtoxxx_ensure_buffer_size(cmdlen
+ 6) != ERROR_OK
)
324 if ((type_pre
!= type
) || (!usbtoxxx_buffer
)) {
325 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
326 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
327 return ERRCODE_FAILURE_OPERATION
;
332 if ((collect_index
== 0) || (collect_cmd
!= cmd
)) {
333 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = cmd
;
336 collect_index
= usbtoxxx_current_cmd_index
;
342 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], cmdlen
);
343 usbtoxxx_current_cmd_index
+= 2;
345 len_tmp
= GET_LE_U16(&usbtoxxx_buffer
[collect_index
]) + cmdlen
;
346 SET_LE_U16(&usbtoxxx_buffer
[collect_index
], len_tmp
);
350 memcpy(usbtoxxx_buffer
+ usbtoxxx_current_cmd_index
, cmdbuf
, cmdlen
);
351 usbtoxxx_current_cmd_index
+= cmdlen
;
354 return versaloon_add_pending(type
, cmd
, retlen
, wantpos
, wantlen
,
358 RESULT
usbtoinfo_get_abilities(uint8_t abilities
[USB_TO_XXX_ABILITIES_LEN
])
360 if (usbtoxxx_ensure_buffer_size(3) != ERROR_OK
)
363 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
364 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
365 return ERRCODE_FAILURE_OPERATION
;
367 type_pre
= USB_TO_INFO
;
369 return versaloon_add_pending(USB_TO_INFO
, 0, USB_TO_XXX_ABILITIES_LEN
, 0,
370 USB_TO_XXX_ABILITIES_LEN
, abilities
, 0);
373 RESULT
usbtopoll_start(uint16_t retry_cnt
, uint16_t interval_us
)
375 if (usbtoxxx_ensure_buffer_size(3 + 5) != ERROR_OK
)
378 usbtoxxx_save_context(&poll_context
);
380 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
381 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
382 return ERRCODE_FAILURE_OPERATION
;
385 type_pre
= USB_TO_POLL
;
387 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_START
;
388 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], retry_cnt
);
389 usbtoxxx_current_cmd_index
+= 2;
390 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], interval_us
);
391 usbtoxxx_current_cmd_index
+= 2;
393 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
396 RESULT
usbtopoll_end(void)
399 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
400 return ERRCODE_FAILURE_OPERATION
;
402 if (usbtoxxx_ensure_buffer_size(3 + 1) != ERROR_OK
)
405 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
406 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
407 return ERRCODE_FAILURE_OPERATION
;
411 type_pre
= USB_TO_POLL
;
413 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_END
;
415 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
418 RESULT
usbtopoll_checkok(uint8_t equ
, uint16_t offset
, uint8_t size
,
419 uint32_t mask
, uint32_t value
)
424 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
425 return ERRCODE_INVALID_PARAMETER
;
428 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
429 return ERRCODE_FAILURE_OPERATION
;
431 if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
) != ERROR_OK
)
434 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
435 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
436 return ERRCODE_FAILURE_OPERATION
;
439 type_pre
= USB_TO_POLL
;
441 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKOK
;
442 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
443 usbtoxxx_current_cmd_index
+= 2;
444 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
445 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
446 for (i
= 0; i
< size
; i
++)
447 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
448 for (i
= 0; i
< size
; i
++)
449 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
454 RESULT
usbtopoll_checkfail(uint8_t equ
, uint16_t offset
, uint8_t size
,
455 uint32_t mask
, uint32_t value
)
460 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
461 return ERRCODE_INVALID_PARAMETER
;
464 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
465 return ERRCODE_FAILURE_OPERATION
;
467 if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
) != ERROR_OK
)
470 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
471 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
472 return ERRCODE_FAILURE_OPERATION
;
475 type_pre
= USB_TO_POLL
;
477 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKFAIL
;
478 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
479 usbtoxxx_current_cmd_index
+= 2;
480 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
481 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
482 for (i
= 0; i
< size
; i
++)
483 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
484 for (i
= 0; i
< size
; i
++)
485 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
490 RESULT
usbtopoll_verifybuff(uint16_t offset
, uint16_t size
, uint8_t *buff
)
493 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
494 return ERRCODE_FAILURE_OPERATION
;
496 if (usbtoxxx_ensure_buffer_size(3 + 5 + size
) != ERROR_OK
)
499 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
500 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
501 return ERRCODE_FAILURE_OPERATION
;
504 type_pre
= USB_TO_POLL
;
506 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_VERIFYBUFF
;
507 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
508 usbtoxxx_current_cmd_index
+= 2;
509 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], size
);
510 usbtoxxx_current_cmd_index
+= 2;
511 memcpy(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], buff
, size
);
512 usbtoxxx_current_cmd_index
+= size
;
517 RESULT
usbtodelay_delay(uint16_t dly
)
519 if (usbtoxxx_ensure_buffer_size(3 + 2) != ERROR_OK
)
522 if (usbtoxxx_validate_current_command_type() != ERROR_OK
) {
523 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
524 return ERRCODE_FAILURE_OPERATION
;
526 type_pre
= USB_TO_DELAY
;
528 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], dly
);
529 usbtoxxx_current_cmd_index
+= 2;
531 return versaloon_add_pending(USB_TO_DELAY
, 0, 0, 0, 0, NULL
, 0);
534 RESULT
usbtodelay_delayms(uint16_t ms
)
536 return usbtodelay_delay(ms
| 0x8000);
539 RESULT
usbtodelay_delayus(uint16_t us
)
541 return usbtodelay_delay(us
& 0x7FFF);