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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
26 #include "../versaloon_include.h"
27 #include "../versaloon.h"
28 #include "../versaloon_internal.h"
30 #include "usbtoxxx_internal.h"
34 const char *types_name
[96] = {
35 "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm",
36 "usbtoadc", "usbtodac",
37 "usbtomicrowire", "usbtoswim", "usbtodusi", N_A
, N_A
, N_A
, "usbtopower", "usbtodelay",
38 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
39 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
40 "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw",
41 "usbtolpcicp", "usbtoswd", "usbtojtagraw",
42 "usbtobdm", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
43 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
44 "usbtomsp430jtag", N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
,
45 "usbtopower", "usbtodelay", "usbtopoll", N_A
, N_A
, N_A
, N_A
, N_A
,
46 N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, N_A
, "usbtoall"
49 uint8_t usbtoxxx_abilities
[USB_TO_XXX_ABILITIES_LEN
];
51 #define usbtoxxx_get_type_name(type) \
52 types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
53 % (sizeof(types_name) / sizeof(types_name[0]))]
55 static uint8_t type_pre
;
56 static uint16_t usbtoxxx_buffer_index
;
57 static uint16_t usbtoxxx_current_cmd_index
;
58 static uint8_t *usbtoxxx_buffer
;
60 uint16_t collect_index
;
62 static uint8_t poll_nesting
;
64 struct usbtoxxx_context_t
{
66 uint8_t *usbtoxxx_buffer
;
67 uint16_t usbtoxxx_current_cmd_index
;
68 uint16_t usbtoxxx_buffer_index
;
69 uint16_t versaloon_pending_idx
;
71 static struct usbtoxxx_context_t poll_context
;
73 static void usbtoxxx_save_context(struct usbtoxxx_context_t
*c
)
75 c
->type_pre
= type_pre
;
76 c
->usbtoxxx_buffer
= usbtoxxx_buffer
;
77 c
->usbtoxxx_buffer_index
= usbtoxxx_buffer_index
;
78 c
->usbtoxxx_current_cmd_index
= usbtoxxx_current_cmd_index
;
79 c
->versaloon_pending_idx
= versaloon_pending_idx
;
82 static void usbtoxxx_pop_context(struct usbtoxxx_context_t
*c
)
84 type_pre
= c
->type_pre
;
85 usbtoxxx_buffer
= c
->usbtoxxx_buffer
;
86 usbtoxxx_buffer_index
= c
->usbtoxxx_buffer_index
;
87 usbtoxxx_current_cmd_index
= c
->usbtoxxx_current_cmd_index
;
88 versaloon_pending_idx
= c
->versaloon_pending_idx
;
91 RESULT
usbtoxxx_validate_current_command_type(void)
94 /* not the first command */
95 if (NULL
== usbtoxxx_buffer
) {
96 LOG_BUG(ERRMSG_INVALID_BUFFER
, TO_STR(usbtoxxx_buffer
));
97 return ERRCODE_INVALID_BUFFER
;
100 usbtoxxx_buffer
[0] = type_pre
;
101 SET_LE_U16(&usbtoxxx_buffer
[1], usbtoxxx_current_cmd_index
);
103 usbtoxxx_buffer_index
+= usbtoxxx_current_cmd_index
;
106 usbtoxxx_buffer_index
= 3;
109 /* prepare for next command */
110 usbtoxxx_current_cmd_index
= 3;
111 usbtoxxx_buffer
= versaloon_buf
+ usbtoxxx_buffer_index
;
119 RESULT
usbtoxxx_execute_command(void)
123 RESULT result
= ERROR_OK
;
126 LOG_BUG(ERRMSG_INVALID_USAGE
, "USB_TO_POLL");
127 versaloon_free_want_pos();
131 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
132 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
133 versaloon_free_want_pos();
134 return ERRCODE_FAILURE_OPERATION
;
136 if (3 == usbtoxxx_buffer_index
) {
137 versaloon_free_want_pos();
141 versaloon_buf
[0] = USB_TO_ALL
;
142 SET_LE_U16(&versaloon_buf
[1], usbtoxxx_buffer_index
);
144 if (ERROR_OK
!= versaloon_send_command(usbtoxxx_buffer_index
, &inlen
)) {
145 versaloon_free_want_pos();
149 /* process return data */
150 usbtoxxx_buffer_index
= 0;
151 for (i
= 0; i
< versaloon_pending_idx
; i
++) {
153 if ((0 == i
) || !((versaloon_pending
[i
].collect
)
154 && (versaloon_pending
[i
- 1].collect
)
155 && (versaloon_pending
[i
].cmd
156 == versaloon_pending
[i
- 1].cmd
))) {
157 if (USB_TO_XXX_CMD_NOT_SUPPORT
158 == versaloon_buf
[usbtoxxx_buffer_index
]) {
159 LOG_ERROR(ERRMSG_NOT_SUPPORT_BY
,
160 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
164 } else if (USB_TO_XXX_OK
!= versaloon_buf
[usbtoxxx_buffer_index
]) {
165 LOG_ERROR("%s command 0x%02x failed with 0x%02x",
166 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
167 versaloon_pending
[i
].cmd
,
168 versaloon_buf
[usbtoxxx_buffer_index
]);
172 usbtoxxx_buffer_index
++;
175 /* get result data */
176 if (versaloon_pending
[i
].pos
!= NULL
) {
177 uint8_t processed
= 0;
179 if (versaloon_pending
[i
].callback
!= NULL
) {
180 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
181 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
184 struct versaloon_want_pos_t
*tmp
;
186 tmp
= versaloon_pending
[i
].pos
;
187 while (tmp
!= NULL
) {
188 if ((tmp
->buff
!= NULL
) && (tmp
->size
> 0)) {
190 versaloon_buf
+ usbtoxxx_buffer_index
194 struct versaloon_want_pos_t
*free_tmp
;
199 versaloon_pending
[i
].pos
= NULL
;
201 } else if ((versaloon_pending
[i
].want_data_size
> 0)
202 && (versaloon_pending
[i
].data_buffer
!= NULL
)) {
203 uint8_t processed
= 0;
205 if (versaloon_pending
[i
].callback
!= NULL
) {
206 versaloon_pending
[i
].callback(&versaloon_pending
[i
],
207 versaloon_buf
+ usbtoxxx_buffer_index
, &processed
);
210 memcpy(versaloon_pending
[i
].data_buffer
,
211 versaloon_buf
+ usbtoxxx_buffer_index
212 + versaloon_pending
[i
].want_data_pos
,
213 versaloon_pending
[i
].want_data_size
);
216 usbtoxxx_buffer_index
+= versaloon_pending
[i
].actual_data_size
;
217 if (usbtoxxx_buffer_index
> inlen
) {
218 LOG_BUG("%s command 0x%02x process error",
219 usbtoxxx_get_type_name(versaloon_pending
[i
].type
),
220 versaloon_pending
[i
].cmd
);
226 /* data is not the right size */
227 if (inlen
!= usbtoxxx_buffer_index
) {
228 LOG_ERROR(ERRMSG_INVALID_TARGET
, "length of return data");
232 if (versaloon_pending_idx
> 0)
233 versaloon_pending_idx
= 0;
235 /* no receive data, avoid collision */
242 versaloon_free_want_pos();
246 RESULT
usbtoxxx_init(void)
248 versaloon_pending_idx
= 0;
250 if ((ERROR_OK
!= usbtoinfo_get_abilities(usbtoxxx_abilities
)) ||
251 (ERROR_OK
!= usbtoxxx_execute_command()))
253 LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X",
254 GET_LE_U32(&usbtoxxx_abilities
[0]),
255 GET_LE_U32(&usbtoxxx_abilities
[4]),
256 GET_LE_U32(&usbtoxxx_abilities
[8]));
260 RESULT
usbtoxxx_fini(void)
262 usbtoxxx_buffer
= NULL
;
267 bool usbtoxxx_interface_supported(uint8_t cmd
)
269 if ((cmd
< VERSALOON_USB_TO_XXX_CMD_START
) ||
270 (cmd
> VERSALOON_USB_TO_XXX_CMD_END
))
273 cmd
-= VERSALOON_USB_TO_XXX_CMD_START
;
274 return (usbtoxxx_abilities
[cmd
/ 8] & (1 << (cmd
% 8))) > 0;
277 RESULT
usbtoxxx_ensure_buffer_size(uint16_t cmdlen
)
279 /* check free space, commit if not enough */
280 if (((usbtoxxx_buffer_index
+ usbtoxxx_current_cmd_index
+ cmdlen
)
281 >= versaloon_buf_size
)
282 || (versaloon_pending_idx
>= VERSALOON_MAX_PENDING_NUMBER
)) {
283 struct usbtoxxx_context_t context_tmp
;
284 uint8_t poll_nesting_tmp
= 0;
286 memset(&context_tmp
, 0, sizeof(context_tmp
));
288 if (0 == poll_context
.type_pre
) {
289 LOG_BUG("USB_TO_POLL toooooo long");
293 usbtoxxx_save_context(&context_tmp
);
294 usbtoxxx_pop_context(&poll_context
);
295 poll_nesting_tmp
= poll_nesting
;
299 if (usbtoxxx_execute_command() != ERROR_OK
)
302 if (poll_nesting_tmp
) {
303 uint16_t newlen
, oldlen
;
305 newlen
= context_tmp
.versaloon_pending_idx
306 - poll_context
.versaloon_pending_idx
;
307 memcpy(&versaloon_pending
[0],
308 &versaloon_pending
[poll_context
.versaloon_pending_idx
],
309 sizeof(versaloon_pending
[0]) * newlen
);
310 context_tmp
.versaloon_pending_idx
= newlen
;
311 oldlen
= poll_context
.usbtoxxx_buffer_index
312 + poll_context
.usbtoxxx_current_cmd_index
;
313 newlen
= context_tmp
.usbtoxxx_buffer_index
314 + context_tmp
.usbtoxxx_current_cmd_index
;
315 memcpy(versaloon_buf
+ 3, versaloon_buf
+ oldlen
, newlen
- oldlen
);
317 context_tmp
.usbtoxxx_buffer
-= oldlen
;
318 context_tmp
.usbtoxxx_buffer_index
-= oldlen
;
319 usbtoxxx_pop_context(&context_tmp
);
320 poll_nesting
= poll_nesting_tmp
;
326 RESULT
usbtoxxx_add_command(uint8_t type
, uint8_t cmd
, uint8_t *cmdbuf
,
327 uint16_t cmdlen
, uint16_t retlen
, uint8_t *wantbuf
,
328 uint16_t wantpos
, uint16_t wantlen
, uint8_t collect
)
332 /* 3 more bytes by usbtoxxx_validate_current_command_type */
333 /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */
334 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(cmdlen
+ 6))
337 if ((type_pre
!= type
) || (NULL
== usbtoxxx_buffer
)) {
338 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
339 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
340 return ERRCODE_FAILURE_OPERATION
;
345 if ((0 == collect_index
) || (collect_cmd
!= cmd
)) {
346 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = cmd
;
349 collect_index
= usbtoxxx_current_cmd_index
;
355 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], cmdlen
);
356 usbtoxxx_current_cmd_index
+= 2;
358 len_tmp
= GET_LE_U16(&usbtoxxx_buffer
[collect_index
]) + cmdlen
;
359 SET_LE_U16(&usbtoxxx_buffer
[collect_index
], len_tmp
);
362 if (cmdbuf
!= NULL
) {
363 memcpy(usbtoxxx_buffer
+ usbtoxxx_current_cmd_index
, cmdbuf
, cmdlen
);
364 usbtoxxx_current_cmd_index
+= cmdlen
;
367 return versaloon_add_pending(type
, cmd
, retlen
, wantpos
, wantlen
,
371 RESULT
usbtoinfo_get_abilities(uint8_t abilities
[USB_TO_XXX_ABILITIES_LEN
])
373 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3))
376 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
377 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
378 return ERRCODE_FAILURE_OPERATION
;
380 type_pre
= USB_TO_INFO
;
382 return versaloon_add_pending(USB_TO_INFO
, 0, USB_TO_XXX_ABILITIES_LEN
, 0,
383 USB_TO_XXX_ABILITIES_LEN
, abilities
, 0);
386 RESULT
usbtopoll_start(uint16_t retry_cnt
, uint16_t interval_us
)
388 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 5))
391 usbtoxxx_save_context(&poll_context
);
393 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
394 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
395 return ERRCODE_FAILURE_OPERATION
;
398 type_pre
= USB_TO_POLL
;
400 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_START
;
401 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], retry_cnt
);
402 usbtoxxx_current_cmd_index
+= 2;
403 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], interval_us
);
404 usbtoxxx_current_cmd_index
+= 2;
406 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
409 RESULT
usbtopoll_end(void)
412 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
413 return ERRCODE_FAILURE_OPERATION
;
415 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 1))
418 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
419 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
420 return ERRCODE_FAILURE_OPERATION
;
424 type_pre
= USB_TO_POLL
;
426 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_END
;
428 return versaloon_add_pending(USB_TO_POLL
, 0, 0, 0, 0, NULL
, 0);
431 RESULT
usbtopoll_checkok(uint8_t equ
, uint16_t offset
, uint8_t size
,
432 uint32_t mask
, uint32_t value
)
437 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
438 return ERRCODE_INVALID_PARAMETER
;
441 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
442 return ERRCODE_FAILURE_OPERATION
;
444 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
))
447 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
448 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
449 return ERRCODE_FAILURE_OPERATION
;
452 type_pre
= USB_TO_POLL
;
454 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKOK
;
455 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
456 usbtoxxx_current_cmd_index
+= 2;
457 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
458 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
459 for (i
= 0; i
< size
; i
++)
460 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
461 for (i
= 0; i
< size
; i
++)
462 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
467 RESULT
usbtopoll_checkfail(uint8_t equ
, uint16_t offset
, uint8_t size
,
468 uint32_t mask
, uint32_t value
)
473 LOG_BUG(ERRMSG_INVALID_PARAMETER
, __func__
);
474 return ERRCODE_INVALID_PARAMETER
;
477 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
478 return ERRCODE_FAILURE_OPERATION
;
480 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size
))
483 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
484 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
485 return ERRCODE_FAILURE_OPERATION
;
488 type_pre
= USB_TO_POLL
;
490 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_CHECKFAIL
;
491 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
492 usbtoxxx_current_cmd_index
+= 2;
493 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = size
;
494 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = equ
;
495 for (i
= 0; i
< size
; i
++)
496 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (mask
>> (8 * i
)) & 0xFF;
497 for (i
= 0; i
< size
; i
++)
498 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = (value
>> (8 * i
)) & 0xFF;
503 RESULT
usbtopoll_verifybuff(uint16_t offset
, uint16_t size
, uint8_t *buff
)
506 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "check poll nesting");
507 return ERRCODE_FAILURE_OPERATION
;
509 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 5 + size
))
512 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
513 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
514 return ERRCODE_FAILURE_OPERATION
;
517 type_pre
= USB_TO_POLL
;
519 usbtoxxx_buffer
[usbtoxxx_current_cmd_index
++] = USB_TO_POLL_VERIFYBUFF
;
520 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], offset
);
521 usbtoxxx_current_cmd_index
+= 2;
522 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], size
);
523 usbtoxxx_current_cmd_index
+= 2;
524 memcpy(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], buff
, size
);
525 usbtoxxx_current_cmd_index
+= size
;
530 RESULT
usbtodelay_delay(uint16_t dly
)
532 if (ERROR_OK
!= usbtoxxx_ensure_buffer_size(3 + 2))
535 if (ERROR_OK
!= usbtoxxx_validate_current_command_type()) {
536 LOG_BUG(ERRMSG_FAILURE_OPERATION
, "validate previous commands");
537 return ERRCODE_FAILURE_OPERATION
;
539 type_pre
= USB_TO_DELAY
;
541 SET_LE_U16(&usbtoxxx_buffer
[usbtoxxx_current_cmd_index
], dly
);
542 usbtoxxx_current_cmd_index
+= 2;
544 return versaloon_add_pending(USB_TO_DELAY
, 0, 0, 0, 0, NULL
, 0);
547 RESULT
usbtodelay_delayms(uint16_t ms
)
549 return usbtodelay_delay(ms
| 0x8000);
552 RESULT
usbtodelay_delayus(uint16_t us
)
554 return usbtodelay_delay(us
& 0x7FFF);