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, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
24 #include "../versaloon_include.h"
25 #include "../versaloon.h"
26 #include "../versaloon_internal.h"
28 #include "usbtoxxx_internal.h"
32 static const char *types_name
[96] = {
33 "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm",
34 "usbtoadc", "usbtodac",
35 "usbtomicrowire", "usbtoswim", "usbtodusi", N_A
, N_A
, N_A
, "usbtopower", "usbtodelay",
36 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
37 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
38 "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw",
39 "usbtolpcicp", "usbtoswd", "usbtojtagraw",
40 "usbtobdm", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
41 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
42 "usbtomsp430jtag", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
43 "usbtopower", "usbtodelay", "usbtopoll", N_A
, N_A
, N_A
, N_A
, N_A
,
44 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, "usbtoall"
47 uint8_t usbtoxxx_abilities
[USB_TO_XXX_ABILITIES_LEN
];
49 #define usbtoxxx_get_type_name(type) \
50 types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
51 % ARRAY_SIZE(types_name)]
53 static uint8_t type_pre
;
54 static uint16_t usbtoxxx_buffer_index
;
55 static uint16_t usbtoxxx_current_cmd_index
;
56 static uint8_t *usbtoxxx_buffer
;
58 static uint16_t collect_index
;
59 static uint8_t collect_cmd
;
60 static uint8_t poll_nesting
;
62 struct usbtoxxx_context_t
{
64 uint8_t *usbtoxxx_buffer
;
65 uint16_t usbtoxxx_current_cmd_index
;
66 uint16_t usbtoxxx_buffer_index
;
67 uint16_t versaloon_pending_idx
;
69 static struct usbtoxxx_context_t poll_context
;
71 static void usbtoxxx_save_context(struct usbtoxxx_context_t
*c
)
73 c
->type_pre
= type_pre
;
74 c
->usbtoxxx_buffer
= usbtoxxx_buffer
;
75 c
->usbtoxxx_buffer_index
= usbtoxxx_buffer_index
;
76 c
->usbtoxxx_current_cmd_index
= usbtoxxx_current_cmd_index
;
77 c
->versaloon_pending_idx
= versaloon_pending_idx
;
80 static void usbtoxxx_pop_context(struct usbtoxxx_context_t
*c
)
82 type_pre
= c
->type_pre
;
83 usbtoxxx_buffer
= c
->usbtoxxx_buffer
;
84 usbtoxxx_buffer_index
= c
->usbtoxxx_buffer_index
;
85 usbtoxxx_current_cmd_index
= c
->usbtoxxx_current_cmd_index
;
86 versaloon_pending_idx
= c
->versaloon_pending_idx
;
89 static RESULT
usbtoxxx_validate_current_command_type(void)
92 /* not the first command */
93 if (NULL
== usbtoxxx_buffer
) {
94 LOG_BUG(ERRMSG_INVALID_BUFFER
, TO_STR(usbtoxxx_buffer
));
95 return ERRCODE_INVALID_BUFFER
;
98 usbtoxxx_buffer
[0] = type_pre
;
99 SET_LE_U16(&usbtoxxx_buffer
[1], usbtoxxx_current_cmd_index
);
101 usbtoxxx_buffer_index
+= usbtoxxx_current_cmd_index
;
104 usbtoxxx_buffer_index
= 3;
107 /* prepare for next command */
108 usbtoxxx_current_cmd_index
= 3;
109 usbtoxxx_buffer
= versaloon_buf
+ usbtoxxx_buffer_index
;
117 RESULT
usbtoxxx_execute_command(void)
121 RESULT result
= ERROR_OK
;
124 LOG_BUG(ERRMSG_INVALID_USAGE
, "USB_TO_POLL");
125 versaloon_free_want_pos();
129 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
130 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
131 versaloon_free_want_pos();
132 return ERRCODE_FAILURE_OPERATION
;
134 if (3 == usbtoxxx_buffer_index
) {
135 versaloon_free_want_pos();
139 versaloon_buf
[0] = USB_TO_ALL
;
140 SET_LE_U16(&versaloon_buf
[1], usbtoxxx_buffer_index
);
142 if (ERROR_OK
!= versaloon_send_command(usbtoxxx_buffer_index
, &inlen
)) {
143 versaloon_free_want_pos();
147 /* process return data */
148 usbtoxxx_buffer_index
= 0;
149 for (i
= 0; i
< versaloon_pending_idx
; i
++) {
151 if ((0 == i
) || !((versaloon_pending
[i
].collect
)
152 && (versaloon_pending
[i
- 1].collect
)
153 && (versaloon_pending
[i
].cmd
154 == versaloon_pending
[i
- 1].cmd
))) {
155 if (USB_TO_XXX_CMD_NOT_SUPPORT
156 == versaloon_buf
[usbtoxxx_buffer_index
]) {
157 LOG_ERROR(ERRMSG_NOT_SUPPORT_BY
,
158 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
162 } else if (USB_TO_XXX_OK
!= versaloon_buf
[usbtoxxx_buffer_index
]) {
163 LOG_ERROR("%s command 0x%02x failed with 0x%02x",
164 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
165 versaloon_pending
[i
].cmd
,
166 versaloon_buf
[usbtoxxx_buffer_index
]);
170 usbtoxxx_buffer_index
++;
173 /* get result data */
174 if (versaloon_pending
[i
].pos
!= NULL
) {
175 uint8_t processed
= 0;
177 if (versaloon_pending
[i
].callback
!= NULL
) {
178 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
179 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
182 struct versaloon_want_pos_t
*tmp
;
184 tmp
= versaloon_pending
[i
].pos
;
185 while (tmp
!= NULL
) {
186 if ((tmp
->buff
!= NULL
) && (tmp
->size
> 0)) {
188 versaloon_buf
+ usbtoxxx_buffer_index
192 struct versaloon_want_pos_t
*free_tmp
;
197 versaloon_pending
[i
].pos
= NULL
;
199 } else if ((versaloon_pending
[i
].want_data_size
> 0)
200 && (versaloon_pending
[i
].data_buffer
!= NULL
)) {
201 uint8_t processed
= 0;
203 if (versaloon_pending
[i
].callback
!= NULL
) {
204 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
205 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
208 memcpy(versaloon_pending
[i
].data_buffer
,
209 versaloon_buf
+ usbtoxxx_buffer_index
210 + versaloon_pending
[i
].want_data_pos
,
211 versaloon_pending
[i
].want_data_size
);
214 usbtoxxx_buffer_index
+= versaloon_pending
[i
].actual_data_size
;
215 if (usbtoxxx_buffer_index
> inlen
) {
216 LOG_BUG("%s command 0x%02x process error",
217 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
218 versaloon_pending
[i
].cmd
);
224 /* data is not the right size */
225 if (inlen
!= usbtoxxx_buffer_index
) {
226 LOG_ERROR(ERRMSG_INVALID_TARGET
, "length of return data");
230 if (versaloon_pending_idx
> 0)
231 versaloon_pending_idx
= 0;
233 /* no receive data, avoid collision */
240 versaloon_free_want_pos();
244 RESULT
usbtoxxx_init(void)
246 versaloon_pending_idx
= 0;
248 if ((ERROR_OK
!= usbtoinfo_get_abilities(usbtoxxx_abilities
)) ||
249 (ERROR_OK
!= usbtoxxx_execute_command()))
251 LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X",
252 GET_LE_U32(&usbtoxxx_abilities
[0]),
253 GET_LE_U32(&usbtoxxx_abilities
[4]),
254 GET_LE_U32(&usbtoxxx_abilities
[8]));
258 RESULT
usbtoxxx_fini(void)
260 usbtoxxx_buffer
= NULL
;
265 bool usbtoxxx_interface_supported(uint8_t cmd
)
267 if ((cmd
< VERSALOON_USB_TO_XXX_CMD_START
) ||
268 (cmd
> VERSALOON_USB_TO_XXX_CMD_END
))
271 cmd
-= VERSALOON_USB_TO_XXX_CMD_START
;
272 return (usbtoxxx_abilities
[cmd
/ 8] & (1 << (cmd
% 8))) > 0;
275 static RESULT
usbtoxxx_ensure_buffer_size(uint16_t cmdlen
)
277 /* check free space, commit if not enough */
278 if (((usbtoxxx_buffer_index
+ usbtoxxx_current_cmd_index
+ cmdlen
)
279 >= versaloon_buf_size
)
280 || (versaloon_pending_idx
>= VERSALOON_MAX_PENDING_NUMBER
)) {
281 struct usbtoxxx_context_t context_tmp
;
282 uint8_t poll_nesting_tmp
= 0;
284 memset(&context_tmp
, 0, sizeof(context_tmp
));
286 if (0 == poll_context
.type_pre
) {
287 LOG_BUG("USB_TO_POLL toooooo long");
291 usbtoxxx_save_context(&context_tmp
);
292 usbtoxxx_pop_context(&poll_context
);
293 poll_nesting_tmp
= poll_nesting
;
297 if (usbtoxxx_execute_command() != ERROR_OK
)
300 if (poll_nesting_tmp
) {
301 uint16_t newlen
, oldlen
;
303 newlen
= context_tmp
.versaloon_pending_idx
304 - poll_context
.versaloon_pending_idx
;
305 memcpy(&versaloon_pending
[0],
306 &versaloon_pending
[poll_context
.versaloon_pending_idx
],
307 sizeof(versaloon_pending
[0]) * newlen
);
308 context_tmp
.versaloon_pending_idx
= newlen
;
309 oldlen
= poll_context
.usbtoxxx_buffer_index
310 + poll_context
.usbtoxxx_current_cmd_index
;
311 newlen
= context_tmp
.usbtoxxx_buffer_index
312 + context_tmp
.usbtoxxx_current_cmd_index
;
313 memcpy(versaloon_buf
+ 3, versaloon_buf
+ oldlen
, newlen
- oldlen
);
315 context_tmp
.usbtoxxx_buffer
-= oldlen
;
316 context_tmp
.usbtoxxx_buffer_index
-= oldlen
;
317 usbtoxxx_pop_context(&context_tmp
);
318 poll_nesting
= poll_nesting_tmp
;
324 RESULT
usbtoxxx_add_command(uint8_t type
, uint8_t cmd
, uint8_t *cmdbuf
,
325 uint16_t cmdlen
, uint16_t retlen
, uint8_t *wantbuf
,
326 uint16_t wantpos
, uint16_t wantlen
, uint8_t collect
)
330 /* 3 more bytes by usbtoxxx_validate_current_command_type */
331 /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */
332 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(cmdlen
+ 6))
335 if ((type_pre
!= type
) || (NULL
== usbtoxxx_buffer
)) {
336 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
337 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
338 return ERRCODE_FAILURE_OPERATION
;
343 if ((0 == collect_index
) || (collect_cmd
!= cmd
)) {
344 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = cmd
;
347 collect_index
= usbtoxxx_current_cmd_index
;
353 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], cmdlen
);
354 usbtoxxx_current_cmd_index
+= 2;
356 len_tmp
= GET_LE_U16(&usbtoxxx_buffer
[collect_index
]) + cmdlen
;
357 SET_LE_U16(&usbtoxxx_buffer
[collect_index
], len_tmp
);
360 if (cmdbuf
!= NULL
) {
361 memcpy(usbtoxxx_buffer
+ usbtoxxx_current_cmd_index
, cmdbuf
, cmdlen
);
362 usbtoxxx_current_cmd_index
+= cmdlen
;
365 return versaloon_add_pending(type
, cmd
, retlen
, wantpos
, wantlen
,
369 RESULT
usbtoinfo_get_abilities(uint8_t abilities
[USB_TO_XXX_ABILITIES_LEN
])
371 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3))
374 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
375 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
376 return ERRCODE_FAILURE_OPERATION
;
378 type_pre
= USB_TO_INFO
;
380 return versaloon_add_pending(USB_TO_INFO
, 0, USB_TO_XXX_ABILITIES_LEN
, 0,
381 USB_TO_XXX_ABILITIES_LEN
, abilities
, 0);
384 RESULT
usbtopoll_start(uint16_t retry_cnt
, uint16_t interval_us
)
386 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 5))
389 usbtoxxx_save_context(&poll_context
);
391 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
392 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
393 return ERRCODE_FAILURE_OPERATION
;
396 type_pre
= USB_TO_POLL
;
398 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_START
;
399 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], retry_cnt
);
400 usbtoxxx_current_cmd_index
+= 2;
401 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], interval_us
);
402 usbtoxxx_current_cmd_index
+= 2;
404 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
407 RESULT
usbtopoll_end(void)
410 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
411 return ERRCODE_FAILURE_OPERATION
;
413 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 1))
416 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
417 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
418 return ERRCODE_FAILURE_OPERATION
;
422 type_pre
= USB_TO_POLL
;
424 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_END
;
426 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
429 RESULT
usbtopoll_checkok(uint8_t equ
, uint16_t offset
, uint8_t size
,
430 uint32_t mask
, uint32_t value
)
435 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
436 return ERRCODE_INVALID_PARAMETER
;
439 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
440 return ERRCODE_FAILURE_OPERATION
;
442 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
))
445 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
446 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
447 return ERRCODE_FAILURE_OPERATION
;
450 type_pre
= USB_TO_POLL
;
452 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKOK
;
453 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
454 usbtoxxx_current_cmd_index
+= 2;
455 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
456 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
457 for (i
= 0; i
< size
; i
++)
458 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
459 for (i
= 0; i
< size
; i
++)
460 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
465 RESULT
usbtopoll_checkfail(uint8_t equ
, uint16_t offset
, uint8_t size
,
466 uint32_t mask
, uint32_t value
)
471 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
472 return ERRCODE_INVALID_PARAMETER
;
475 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
476 return ERRCODE_FAILURE_OPERATION
;
478 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
))
481 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
482 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
483 return ERRCODE_FAILURE_OPERATION
;
486 type_pre
= USB_TO_POLL
;
488 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKFAIL
;
489 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
490 usbtoxxx_current_cmd_index
+= 2;
491 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
492 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
493 for (i
= 0; i
< size
; i
++)
494 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
495 for (i
= 0; i
< size
; i
++)
496 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
501 RESULT
usbtopoll_verifybuff(uint16_t offset
, uint16_t size
, uint8_t *buff
)
504 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
505 return ERRCODE_FAILURE_OPERATION
;
507 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 5 + size
))
510 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
511 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
512 return ERRCODE_FAILURE_OPERATION
;
515 type_pre
= USB_TO_POLL
;
517 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_VERIFYBUFF
;
518 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
519 usbtoxxx_current_cmd_index
+= 2;
520 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], size
);
521 usbtoxxx_current_cmd_index
+= 2;
522 memcpy(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], buff
, size
);
523 usbtoxxx_current_cmd_index
+= size
;
528 RESULT
usbtodelay_delay(uint16_t dly
)
530 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 2))
533 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
534 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
535 return ERRCODE_FAILURE_OPERATION
;
537 type_pre
= USB_TO_DELAY
;
539 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], dly
);
540 usbtoxxx_current_cmd_index
+= 2;
542 return versaloon_add_pending(USB_TO_DELAY
, 0, 0, 0, 0, NULL
, 0);
545 RESULT
usbtodelay_delayms(uint16_t ms
)
547 return usbtodelay_delay(ms
| 0x8000);
550 RESULT
usbtodelay_delayus(uint16_t us
)
552 return usbtodelay_delay(us
& 0x7FFF);