HACKING: add chapter on checkpatch
[fw/openocd] / src / jtag / drivers / versaloon / usbtoxxx / usbtoxxx.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com>     *
5  ***************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include <string.h>
12
13 #include "../versaloon_include.h"
14 #include "../versaloon.h"
15 #include "../versaloon_internal.h"
16 #include "usbtoxxx.h"
17 #include "usbtoxxx_internal.h"
18
19 #define N_A "n/a"
20
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"
34 };
35
36 uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN];
37
38 #define usbtoxxx_get_type_name(type)    \
39         types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \
40                    % ARRAY_SIZE(types_name)]
41
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;
46
47 static uint16_t collect_index;
48 static uint8_t collect_cmd;
49 static uint8_t poll_nesting;
50
51 struct usbtoxxx_context_t {
52         uint8_t type_pre;
53         uint8_t *usbtoxxx_buffer;
54         uint16_t usbtoxxx_current_cmd_index;
55         uint16_t usbtoxxx_buffer_index;
56         uint16_t versaloon_pending_idx;
57 };
58 static struct usbtoxxx_context_t poll_context;
59
60 static void usbtoxxx_save_context(struct usbtoxxx_context_t *c)
61 {
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;
67 }
68
69 static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c)
70 {
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;
76 }
77
78 static RESULT usbtoxxx_validate_current_command_type(void)
79 {
80         if (type_pre > 0) {
81                 /* not the first command */
82                 if (!usbtoxxx_buffer) {
83                         LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(usbtoxxx_buffer));
84                         return ERRCODE_INVALID_BUFFER;
85                 }
86
87                 usbtoxxx_buffer[0] = type_pre;
88                 SET_LE_U16(&usbtoxxx_buffer[1], usbtoxxx_current_cmd_index);
89
90                 usbtoxxx_buffer_index += usbtoxxx_current_cmd_index;
91         } else {
92                 /* first command */
93                 usbtoxxx_buffer_index = 3;
94         }
95
96         /* prepare for next command */
97         usbtoxxx_current_cmd_index = 3;
98         usbtoxxx_buffer = versaloon_buf + usbtoxxx_buffer_index;
99
100         collect_index = 0;
101         collect_cmd = 0;
102
103         return ERROR_OK;
104 }
105
106 RESULT usbtoxxx_execute_command(void)
107 {
108         uint16_t i;
109         uint16_t inlen;
110         RESULT result = ERROR_OK;
111
112         if (poll_nesting) {
113                 LOG_BUG(ERRMSG_INVALID_USAGE, "USB_TO_POLL");
114                 versaloon_free_want_pos();
115                 return ERROR_FAIL;
116         }
117
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;
122         }
123         if (usbtoxxx_buffer_index == 3) {
124                 versaloon_free_want_pos();
125                 return ERROR_OK;
126         }
127
128         versaloon_buf[0] = USB_TO_ALL;
129         SET_LE_U16(&versaloon_buf[1], usbtoxxx_buffer_index);
130
131         if (versaloon_send_command(usbtoxxx_buffer_index, &inlen) != ERROR_OK) {
132                 versaloon_free_want_pos();
133                 return ERROR_FAIL;
134         }
135
136         /* process return data */
137         usbtoxxx_buffer_index = 0;
138         for (i = 0; i < versaloon_pending_idx; i++) {
139                 /* check result */
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),
148                                         "current dongle");
149                                 result = ERROR_FAIL;
150                                 break;
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]);
156                                 result = ERROR_FAIL;
157                                 break;
158                         }
159                         usbtoxxx_buffer_index++;
160                 }
161
162                 /* get result data */
163                 if (versaloon_pending[i].pos) {
164                         uint8_t processed = 0;
165
166                         if (versaloon_pending[i].callback) {
167                                 versaloon_pending[i].callback(&versaloon_pending[i],
168                                         versaloon_buf + usbtoxxx_buffer_index, &processed);
169                         }
170                         if (!processed) {
171                                 struct versaloon_want_pos_t *tmp;
172
173                                 tmp = versaloon_pending[i].pos;
174                                 while (tmp) {
175                                         if ((tmp->buff) && (tmp->size > 0)) {
176                                                 memcpy(tmp->buff,
177                                                         versaloon_buf + usbtoxxx_buffer_index
178                                                         + tmp->offset,
179                                                         tmp->size);
180                                         }
181                                         struct versaloon_want_pos_t *free_tmp;
182                                         free_tmp = tmp;
183                                         tmp = tmp->next;
184                                         free(free_tmp);
185                                 }
186                                 versaloon_pending[i].pos = NULL;
187                         }
188                 } else if ((versaloon_pending[i].want_data_size > 0)
189                                 && (versaloon_pending[i].data_buffer)) {
190                         uint8_t processed = 0;
191
192                         if (versaloon_pending[i].callback) {
193                                 versaloon_pending[i].callback(&versaloon_pending[i],
194                                         versaloon_buf + usbtoxxx_buffer_index, &processed);
195                         }
196                         if (!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);
201                         }
202                 }
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);
208                         result = ERROR_FAIL;
209                         break;
210                 }
211         }
212
213         /* data is not the right size */
214         if (inlen != usbtoxxx_buffer_index) {
215                 LOG_ERROR(ERRMSG_INVALID_TARGET, "length of return data");
216                 result = ERROR_FAIL;
217         }
218
219         if (versaloon_pending_idx > 0)
220                 versaloon_pending_idx = 0;
221         else {
222                 /* no receive data, avoid collision */
223                 sleep_ms(10);
224         }
225
226         type_pre = 0;
227         collect_cmd = 0;
228         collect_index = 0;
229         versaloon_free_want_pos();
230         return result;
231 }
232
233 RESULT usbtoxxx_init(void)
234 {
235         versaloon_pending_idx = 0;
236
237         if ((usbtoinfo_get_abilities(usbtoxxx_abilities) != ERROR_OK) ||
238                         (usbtoxxx_execute_command() != ERROR_OK))
239                 return ERROR_FAIL;
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]));
244         return ERROR_OK;
245 }
246
247 RESULT usbtoxxx_fini(void)
248 {
249         usbtoxxx_buffer = NULL;
250         type_pre = 0;
251         return ERROR_OK;
252 }
253
254 bool usbtoxxx_interface_supported(uint8_t cmd)
255 {
256         if ((cmd < VERSALOON_USB_TO_XXX_CMD_START) ||
257                         (cmd > VERSALOON_USB_TO_XXX_CMD_END))
258                 return false;
259
260         cmd -= VERSALOON_USB_TO_XXX_CMD_START;
261         return (usbtoxxx_abilities[cmd  / 8] & (1 << (cmd % 8))) > 0;
262 }
263
264 static RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen)
265 {
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;
272
273                 memset(&context_tmp, 0, sizeof(context_tmp));
274                 if (poll_nesting) {
275                         if (poll_context.type_pre == 0) {
276                                 LOG_BUG("USB_TO_POLL toooooo long");
277                                 return ERROR_OK;
278                         }
279
280                         usbtoxxx_save_context(&context_tmp);
281                         usbtoxxx_pop_context(&poll_context);
282                         poll_nesting_tmp = poll_nesting;
283                         poll_nesting = 0;
284                 }
285
286                 if (usbtoxxx_execute_command() != ERROR_OK)
287                         return ERROR_FAIL;
288
289                 if (poll_nesting_tmp) {
290                         uint16_t newlen, oldlen;
291
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);
303                         oldlen -= 3;
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;
308                 }
309         }
310         return ERROR_OK;
311 }
312
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)
316 {
317         uint16_t len_tmp;
318
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)
322                 return ERROR_FAIL;
323
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;
328                 }
329                 type_pre = type;
330         }
331
332         if ((collect_index == 0) || (collect_cmd != cmd)) {
333                 usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = cmd;
334
335                 if (collect) {
336                         collect_index = usbtoxxx_current_cmd_index;
337                         collect_cmd = cmd;
338                 } else {
339                         collect_index = 0;
340                         collect_cmd = 0;
341                 }
342                 SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], cmdlen);
343                 usbtoxxx_current_cmd_index += 2;
344         } else {
345                 len_tmp = GET_LE_U16(&usbtoxxx_buffer[collect_index]) + cmdlen;
346                 SET_LE_U16(&usbtoxxx_buffer[collect_index], len_tmp);
347         }
348
349         if (cmdbuf) {
350                 memcpy(usbtoxxx_buffer + usbtoxxx_current_cmd_index, cmdbuf, cmdlen);
351                 usbtoxxx_current_cmd_index += cmdlen;
352         }
353
354         return versaloon_add_pending(type, cmd, retlen, wantpos, wantlen,
355                 wantbuf, collect);
356 }
357
358 RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN])
359 {
360         if (usbtoxxx_ensure_buffer_size(3) != ERROR_OK)
361                 return ERROR_FAIL;
362
363         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
364                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
365                 return ERRCODE_FAILURE_OPERATION;
366         }
367         type_pre = USB_TO_INFO;
368
369         return versaloon_add_pending(USB_TO_INFO, 0, USB_TO_XXX_ABILITIES_LEN, 0,
370                 USB_TO_XXX_ABILITIES_LEN, abilities, 0);
371 }
372
373 RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us)
374 {
375         if (usbtoxxx_ensure_buffer_size(3 + 5) != ERROR_OK)
376                 return ERROR_FAIL;
377         if (!poll_nesting)
378                 usbtoxxx_save_context(&poll_context);
379
380         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
381                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
382                 return ERRCODE_FAILURE_OPERATION;
383         }
384         poll_nesting++;
385         type_pre = USB_TO_POLL;
386
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;
392
393         return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0);
394 }
395
396 RESULT usbtopoll_end(void)
397 {
398         if (!poll_nesting) {
399                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
400                 return ERRCODE_FAILURE_OPERATION;
401         }
402         if (usbtoxxx_ensure_buffer_size(3 + 1) != ERROR_OK)
403                 return ERROR_FAIL;
404
405         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
406                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
407                 return ERRCODE_FAILURE_OPERATION;
408         }
409
410         poll_nesting--;
411         type_pre = USB_TO_POLL;
412
413         usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_END;
414
415         return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0);
416 }
417
418 RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size,
419         uint32_t mask, uint32_t value)
420 {
421         uint8_t i;
422
423         if (size > 4) {
424                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
425                 return ERRCODE_INVALID_PARAMETER;
426         }
427         if (!poll_nesting) {
428                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
429                 return ERRCODE_FAILURE_OPERATION;
430         }
431         if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK)
432                 return ERROR_FAIL;
433
434         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
435                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
436                 return ERRCODE_FAILURE_OPERATION;
437         }
438
439         type_pre = USB_TO_POLL;
440
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;
450
451         return ERROR_OK;
452 }
453
454 RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size,
455         uint32_t mask, uint32_t value)
456 {
457         uint8_t i;
458
459         if (size > 4) {
460                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
461                 return ERRCODE_INVALID_PARAMETER;
462         }
463         if (!poll_nesting) {
464                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
465                 return ERRCODE_FAILURE_OPERATION;
466         }
467         if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK)
468                 return ERROR_FAIL;
469
470         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
471                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
472                 return ERRCODE_FAILURE_OPERATION;
473         }
474
475         type_pre = USB_TO_POLL;
476
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;
486
487         return ERROR_OK;
488 }
489
490 RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff)
491 {
492         if (!poll_nesting) {
493                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting");
494                 return ERRCODE_FAILURE_OPERATION;
495         }
496         if (usbtoxxx_ensure_buffer_size(3 + 5 + size) != ERROR_OK)
497                 return ERROR_FAIL;
498
499         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
500                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
501                 return ERRCODE_FAILURE_OPERATION;
502         }
503
504         type_pre = USB_TO_POLL;
505
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;
513
514         return ERROR_OK;
515 }
516
517 RESULT usbtodelay_delay(uint16_t dly)
518 {
519         if (usbtoxxx_ensure_buffer_size(3 + 2) != ERROR_OK)
520                 return ERROR_FAIL;
521
522         if (usbtoxxx_validate_current_command_type() != ERROR_OK) {
523                 LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands");
524                 return ERRCODE_FAILURE_OPERATION;
525         }
526         type_pre = USB_TO_DELAY;
527
528         SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], dly);
529         usbtoxxx_current_cmd_index += 2;
530
531         return versaloon_add_pending(USB_TO_DELAY, 0, 0, 0, 0, NULL, 0);
532 }
533
534 RESULT usbtodelay_delayms(uint16_t ms)
535 {
536         return usbtodelay_delay(ms | 0x8000);
537 }
538
539 RESULT usbtodelay_delayus(uint16_t us)
540 {
541         return usbtodelay_delay(us & 0x7FFF);
542 }