1 /*
2  * $Id$
3  *
4  * Copyright (C) 2003 ETC s.r.o.
5  * Copyright (C) 2005 Hein Roehrig,
6  * Copyright (C) 2008 Kolja Waschk
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  * 02111-1307, USA.
22  *
23  * Written by Marcel Telka <marcel@telka.sk>, 2003;
24  * Busy loop waiting (*freq* functions) Hein Roehrig, 2005;
25  * JTAG activity queuing and API (*defer* functions) K. Waschk, 2008
26  *
27  */
28 
29 #include <sysdep.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <stdint.h>
36 #include <string.h>
37 
38 #include <urjtag/log.h>
39 #include <urjtag/error.h>
40 #include <urjtag/bus.h>
41 #include <urjtag/bus_driver.h>
42 #include <urjtag/chain.h>
43 #include <urjtag/tap.h>
44 #include <urjtag/cable.h>
45 
46 #include "cable.h"
47 
48 const urj_cable_driver_t * const urj_tap_cable_drivers[] = {
49 #define _URJ_CABLE(cable) &urj_tap_cable_##cable##_driver,
50 #include "cable_list.h"
51     NULL                        /* last must be NULL */
52 };
53 
54 const urj_cable_driver_t *
urj_tap_cable_find(const char * cname)55 urj_tap_cable_find (const char *cname)
56 {
57     size_t i;
58 
59     for (i = 0; urj_tap_cable_drivers[i]; ++i)
60         if (strcasecmp (cname, urj_tap_cable_drivers[i]->name) == 0)
61             break;
62 
63     return urj_tap_cable_drivers[i];
64 }
65 
66 void
urj_tap_cable_free(urj_cable_t * cable)67 urj_tap_cable_free (urj_cable_t *cable)
68 {
69     cable->driver->cable_free (cable);
70 }
71 
72 int
urj_tap_cable_init(urj_cable_t * cable)73 urj_tap_cable_init (urj_cable_t *cable)
74 {
75     cable->delay = 0;
76     cable->frequency = 0;
77 
78     cable->todo.max_items = 128;
79     cable->todo.num_items = 0;
80     cable->todo.next_item = 0;
81     cable->todo.next_free = 0;
82     cable->todo.data =
83         malloc (cable->todo.max_items * sizeof (urj_cable_queue_t));
84 
85     cable->done.max_items = 128;
86     cable->done.num_items = 0;
87     cable->done.next_item = 0;
88     cable->done.next_free = 0;
89     cable->done.data =
90         malloc (cable->done.max_items * sizeof (urj_cable_queue_t));
91 
92     if (cable->todo.data == NULL || cable->done.data == NULL)
93     {
94         urj_error_set (URJ_ERROR_OUT_OF_MEMORY,
95                        _("malloc(%zd)/malloc(%zd) fails"),
96                        cable->todo.max_items * sizeof (urj_cable_queue_t),
97                        cable->done.max_items * sizeof (urj_cable_queue_t));
98         if (cable->todo.data != NULL)
99             free (cable->todo.data);
100         if (cable->done.data != NULL)
101             free (cable->done.data);
102         return URJ_STATUS_FAIL;
103     }
104 
105     return cable->driver->init (cable);
106 }
107 
108 void
urj_tap_cable_flush(urj_cable_t * cable,urj_cable_flush_amount_t how_much)109 urj_tap_cable_flush (urj_cable_t *cable, urj_cable_flush_amount_t how_much)
110 {
111     cable->driver->flush (cable, how_much);
112 }
113 
114 void
urj_tap_cable_done(urj_cable_t * cable)115 urj_tap_cable_done (urj_cable_t *cable)
116 {
117     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
118     if (cable->todo.data != NULL)
119     {
120         free (cable->todo.data);
121         free (cable->done.data);
122     }
123     cable->driver->done (cable);
124 }
125 
126 int
urj_tap_cable_add_queue_item(urj_cable_t * cable,urj_cable_queue_info_t * q)127 urj_tap_cable_add_queue_item (urj_cable_t *cable, urj_cable_queue_info_t *q)
128 {
129     int i, j;
130     if (q->num_items >= q->max_items)   /* queue full? */
131     {
132         int new_max_items;
133         urj_cable_queue_t *resized;
134 
135         urj_log (URJ_LOG_LEVEL_DETAIL,
136             "Queue %p needs resizing; n(%d) >= max(%d); free=%d, next=%d\n",
137              q, q->num_items, q->max_items, q->next_free, q->next_item);
138 
139         new_max_items = q->max_items + 128;
140         resized = realloc (q->data, new_max_items * sizeof (urj_cable_queue_t));
141         if (resized == NULL)
142         {
143             urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "realloc(%s,%zd) fails",
144                            "q->data",
145                            new_max_items * sizeof (urj_cable_queue_t));
146             return -1;          /* report failure */
147         }
148         urj_log (URJ_LOG_LEVEL_DETAIL,
149                  _("(Resized JTAG activity queue to hold max %d items)\n"),
150                  new_max_items);
151         q->data = resized;
152 
153         /* The queue was full. Except for the special case when next_item is 0,
154          * resizing just introduced a gap between old and new max, which has to
155          * be filled; either by moving data from next_item .. max_items, or
156          * from 0 .. next_free (whatever is smaller). */
157 
158 #define CHOOSE_SMALLEST_AREA_TO_MOVE 1
159 
160         if (q->next_item != 0)
161         {
162             int added_space = new_max_items - q->max_items;
163             int num_to_move = q->max_items - q->next_item;
164 
165 #ifdef CHOOSE_SMALLEST_AREA_TO_MOVE
166             if (num_to_move <= q->next_free)
167 #endif /* def CHOOSE_SMALLEST_AREA_TO_MOVE */
168             {
169                 /* Move queue items at end of old array
170                  * towards end of new array: 345612__ -> 3456__12 */
171 
172                 int dest = new_max_items - num_to_move;
173                 urj_log (URJ_LOG_LEVEL_DETAIL,
174                     "Resize: Move %d items towards end of queue memory (%d > %d)\n",
175                     num_to_move, q->next_item, dest);
176                 memmove (&q->data[dest], &q->data[q->next_item],
177                          num_to_move * sizeof (urj_cable_queue_t));
178 
179                 q->next_item = dest;
180             }
181 #ifdef CHOOSE_SMALLEST_AREA_TO_MOVE
182             else
183             {
184                 if (q->next_free <= added_space)
185                 {
186                     /* Relocate queue items at beginning of old array
187                      * to end of new array: 561234__ -> __123456 */
188 
189                     urj_log (URJ_LOG_LEVEL_DETAIL,
190                              "Resize: Move %d items from start to end\n",
191                              q->next_free);
192                     memcpy (&q->data[q->max_items], &q->data[0],
193                             q->next_free * sizeof (urj_cable_queue_t));
194 
195                 }
196                 else
197                 {
198                     /* Same as above, but for the case if new space
199                      * isn't large enough to hold all relocated items */
200 
201                     /* Step 1: 456123__ -> __612345 */
202 
203                     urj_log (URJ_LOG_LEVEL_DETAIL,
204                              "Resize.A: Move %d items from start to end\n",
205                             added_space);
206 
207                     memcpy (&q->data[q->max_items], &q->data[0],
208                             added_space * sizeof (urj_cable_queue_t));
209 
210                     /* Step 2: __612345 -> 6__12345 */
211 
212                     urj_log (URJ_LOG_LEVEL_DETAIL,
213                          "Resize.B: Move %d items towards start (offset %d)\n",
214                          (q->next_free - added_space), added_space);
215 
216                     memmove (&q->data[0], &q->data[added_space],
217                              (q->next_free -
218                               added_space) * sizeof (urj_cable_queue_t));
219                 }
220             }
221 #endif /* def CHOOSE_SMALLEST_AREA_TO_MOVE */
222         }
223         q->max_items = new_max_items;
224         q->next_free = q->next_item + q->num_items;
225         if (q->next_free >= new_max_items)
226             q->next_free -= new_max_items;
227 
228         urj_log (URJ_LOG_LEVEL_DETAIL,
229              "Queue %p after resizing; n(%d) >= max(%d); free=%d, next=%d\n",
230              q, q->num_items, q->max_items, q->next_free, q->next_item);
231     }
232 
233     i = q->next_free;
234     j = i + 1;
235     if (j >= q->max_items)
236         j = 0;
237     q->next_free = j;
238     q->num_items++;
239 
240     // urj_log (URJ_LOG_LEVEL_DEBUG, "add_queue_item to %p: %d\n", q, i);
241     return i;
242 }
243 
244 int
urj_tap_cable_get_queue_item(urj_cable_t * cable,urj_cable_queue_info_t * q)245 urj_tap_cable_get_queue_item (urj_cable_t *cable, urj_cable_queue_info_t *q)
246 {
247     if (q->num_items > 0)
248     {
249         int i = q->next_item;
250         int j = i + 1;
251         if (j >= q->max_items)
252             j = 0;
253         q->next_item = j;
254         q->num_items--;
255         // urj_log (URJ_LOG_LEVEL_DEBUG, "get_queue_item from %p: %d\n", q, i);
256         return i;
257     }
258 
259     urj_error_set (URJ_ERROR_NOTFOUND, "queue is empty");
260     // urj_log (URJ_LOG_LEVEL_DEBUG, "get_queue_item from %p: %d\n", q, -1);
261     return -1;
262 }
263 
264 void
urj_tap_cable_purge_queue(urj_cable_queue_info_t * q,int io)265 urj_tap_cable_purge_queue (urj_cable_queue_info_t *q, int io)
266 {
267     while (q->num_items > 0)
268     {
269         int i = q->next_item;
270         if (q->data[i].action == URJ_TAP_CABLE_TRANSFER)
271         {
272             if (io == 0)        /* todo queue */
273             {
274                 if (q->data[i].arg.transfer.in != NULL)
275                     free (q->data[i].arg.transfer.in);
276                 if (q->data[i].arg.transfer.out != NULL)
277                     free (q->data[i].arg.transfer.out);
278             }
279             else                /* done queue */
280             {
281                 if (q->data[i].arg.xferred.out != NULL)
282                     free (q->data[i].arg.xferred.out);
283             }
284         }
285 
286         i++;
287         if (i >= q->max_items)
288             i = 0;
289         q->num_items--;
290     }
291 
292     q->num_items = 0;
293     q->next_item = 0;
294     q->next_free = 0;
295 }
296 
297 void
urj_tap_cable_clock(urj_cable_t * cable,int tms,int tdi,int n)298 urj_tap_cable_clock (urj_cable_t *cable, int tms, int tdi, int n)
299 {
300     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
301     cable->driver->clock (cable, tms, tdi, n);
302 }
303 
304 int
urj_tap_cable_defer_clock(urj_cable_t * cable,int tms,int tdi,int n)305 urj_tap_cable_defer_clock (urj_cable_t *cable, int tms, int tdi, int n)
306 {
307     int i = urj_tap_cable_add_queue_item (cable, &cable->todo);
308     if (i < 0)
309         return URJ_STATUS_FAIL;               /* report failure */
310     cable->todo.data[i].action = URJ_TAP_CABLE_CLOCK;
311     cable->todo.data[i].arg.clock.tms = tms;
312     cable->todo.data[i].arg.clock.tdi = tdi;
313     cable->todo.data[i].arg.clock.n = n;
314     urj_tap_cable_flush (cable, URJ_TAP_CABLE_OPTIONALLY);
315     return URJ_STATUS_OK;                   /* success */
316 }
317 
318 int
urj_tap_cable_get_tdo(urj_cable_t * cable)319 urj_tap_cable_get_tdo (urj_cable_t *cable)
320 {
321     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
322     return cable->driver->get_tdo (cable);
323 }
324 
325 int
urj_tap_cable_get_tdo_late(urj_cable_t * cable)326 urj_tap_cable_get_tdo_late (urj_cable_t *cable)
327 {
328     int i;
329     urj_tap_cable_flush (cable, URJ_TAP_CABLE_TO_OUTPUT);
330     i = urj_tap_cable_get_queue_item (cable, &cable->done);
331     if (i >= 0)
332     {
333         if (cable->done.data[i].action != URJ_TAP_CABLE_GET_TDO)
334         {
335             urj_warning (
336                  _("Internal error: Got wrong type of result from queue (%d? %p.%d)\n"),
337                  cable->done.data[i].action, &cable->done, i);
338             urj_tap_cable_purge_queue (&cable->done, 1);
339         }
340         else
341         {
342             return cable->done.data[i].arg.value.val;
343         }
344     }
345     return cable->driver->get_tdo (cable);
346 }
347 
348 int
urj_tap_cable_defer_get_tdo(urj_cable_t * cable)349 urj_tap_cable_defer_get_tdo (urj_cable_t *cable)
350 {
351     int i = urj_tap_cable_add_queue_item (cable, &cable->todo);
352     if (i < 0)
353         return URJ_STATUS_FAIL;               /* report failure */
354     cable->todo.data[i].action = URJ_TAP_CABLE_GET_TDO;
355     urj_tap_cable_flush (cable, URJ_TAP_CABLE_OPTIONALLY);
356     return URJ_STATUS_OK;                   /* success */
357 }
358 
359 int
urj_tap_cable_set_signal(urj_cable_t * cable,int mask,int val)360 urj_tap_cable_set_signal (urj_cable_t *cable, int mask, int val)
361 {
362     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
363     return cable->driver->set_signal (cable, mask, val);
364 }
365 
366 int
urj_tap_cable_defer_set_signal(urj_cable_t * cable,int mask,int val)367 urj_tap_cable_defer_set_signal (urj_cable_t *cable, int mask, int val)
368 {
369     int i = urj_tap_cable_add_queue_item (cable, &cable->todo);
370     if (i < 0)
371         return URJ_STATUS_FAIL;               /* report failure */
372     cable->todo.data[i].action = URJ_TAP_CABLE_SET_SIGNAL;
373     cable->todo.data[i].arg.value.mask = mask;
374     cable->todo.data[i].arg.value.val = val;
375     urj_tap_cable_flush (cable, URJ_TAP_CABLE_OPTIONALLY);
376     return URJ_STATUS_OK;                   /* success */
377 }
378 
379 int
urj_tap_cable_get_signal(urj_cable_t * cable,urj_pod_sigsel_t sig)380 urj_tap_cable_get_signal (urj_cable_t *cable, urj_pod_sigsel_t sig)
381 {
382     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
383     return cable->driver->get_signal (cable, sig);
384 }
385 
386 int
urj_tap_cable_get_signal_late(urj_cable_t * cable,urj_pod_sigsel_t sig)387 urj_tap_cable_get_signal_late (urj_cable_t *cable, urj_pod_sigsel_t sig)
388 {
389     int i;
390     urj_tap_cable_flush (cable, URJ_TAP_CABLE_TO_OUTPUT);
391     i = urj_tap_cable_get_queue_item (cable, &cable->done);
392     if (i >= 0)
393     {
394         if (cable->done.data[i].action != URJ_TAP_CABLE_GET_SIGNAL)
395         {
396             urj_warning (
397                  _("Internal error: Got wrong type of result from queue (%d? %p.%d)\n"),
398                 cable->done.data[i].action, &cable->done, i);
399             urj_tap_cable_purge_queue (&cable->done, 1);
400         }
401         else if (cable->done.data[i].arg.value.sig != sig)
402         {
403             urj_warning (
404                  _("Internal error: Got wrong signal's value from queue (%d? %p.%d)\n"),
405                 cable->done.data[i].action, &cable->done, i);
406             urj_tap_cable_purge_queue (&cable->done, 1);
407         }
408         else
409         {
410             return cable->done.data[i].arg.value.val;
411         }
412     }
413     return cable->driver->get_signal (cable, sig);
414 }
415 
416 int
urj_tap_cable_defer_get_signal(urj_cable_t * cable,urj_pod_sigsel_t sig)417 urj_tap_cable_defer_get_signal (urj_cable_t *cable, urj_pod_sigsel_t sig)
418 {
419     int i = urj_tap_cable_add_queue_item (cable, &cable->todo);
420     if (i < 0)
421         return URJ_STATUS_FAIL;               /* report failure */
422     cable->todo.data[i].action = URJ_TAP_CABLE_GET_SIGNAL;
423     cable->todo.data[i].arg.value.sig = sig;
424     urj_tap_cable_flush (cable, URJ_TAP_CABLE_OPTIONALLY);
425     return URJ_STATUS_OK;                   /* success */
426 }
427 
428 int
urj_tap_cable_transfer(urj_cable_t * cable,int len,char * in,char * out)429 urj_tap_cable_transfer (urj_cable_t *cable, int len, char *in, char *out)
430 {
431     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
432     return cable->driver->transfer (cable, len, in, out);
433 }
434 
435 int
urj_tap_cable_transfer_late(urj_cable_t * cable,char * out)436 urj_tap_cable_transfer_late (urj_cable_t *cable, char *out)
437 {
438     int i;
439     urj_tap_cable_flush (cable, URJ_TAP_CABLE_TO_OUTPUT);
440     i = urj_tap_cable_get_queue_item (cable, &cable->done);
441 
442     if (i >= 0 && cable->done.data[i].action == URJ_TAP_CABLE_TRANSFER)
443     {
444 #if 0
445         urj_log (URJ_LOG_LEVEL_DEBUG, "Got queue item (%p.%d) len=%d out=%p\n",
446                 &cable->done, i,
447                 cable->done.data[i].arg.xferred.len,
448                 cable->done.data[i].arg.xferred.out);
449 #endif
450         if (out)
451             memcpy (out,
452                     cable->done.data[i].arg.xferred.out,
453                     cable->done.data[i].arg.xferred.len);
454         free (cable->done.data[i].arg.xferred.out);
455         return cable->done.data[i].arg.xferred.res;
456     }
457 
458     if (cable->done.data[i].action != URJ_TAP_CABLE_TRANSFER)
459     {
460         urj_warning (
461              _("Internal error: Got wrong type of result from queue (#%d %p.%d)\n"),
462              cable->done.data[i].action, &cable->done, i);
463         urj_tap_cable_purge_queue (&cable->done, 1);
464     }
465     else
466     {
467         urj_warning (
468              _("Internal error: Wanted transfer result but none was queued\n"));
469     }
470     return 0;
471 }
472 
473 int
urj_tap_cable_defer_transfer(urj_cable_t * cable,int len,char * in,char * out)474 urj_tap_cable_defer_transfer (urj_cable_t *cable, int len, char *in,
475                               char *out)
476 {
477     char *ibuf, *obuf = NULL;
478     int i;
479 
480     ibuf = malloc (len);
481     if (ibuf == NULL)
482     {
483         urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "malloc(%zd) fails",
484                        (size_t) len);
485         return URJ_STATUS_FAIL;
486     }
487 
488     if (out)
489     {
490         obuf = malloc (len);
491         if (obuf == NULL)
492         {
493             free (ibuf);
494             urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "malloc(%zd) fails",
495                            (size_t) len);
496             return URJ_STATUS_FAIL;
497         }
498     }
499 
500     i = urj_tap_cable_add_queue_item (cable, &cable->todo);
501     if (i < 0)
502     {
503         free (ibuf);
504         if (obuf)
505             free (obuf);
506         return URJ_STATUS_FAIL;               /* report failure */
507     }
508 
509     cable->todo.data[i].action = URJ_TAP_CABLE_TRANSFER;
510     cable->todo.data[i].arg.transfer.len = len;
511     if (in)
512         memcpy (ibuf, in, len);
513     cable->todo.data[i].arg.transfer.in = ibuf;
514     cable->todo.data[i].arg.transfer.out = obuf;
515     urj_tap_cable_flush (cable, URJ_TAP_CABLE_OPTIONALLY);
516     return URJ_STATUS_OK;                   /* success */
517 }
518 
519 void
urj_tap_cable_set_frequency(urj_cable_t * cable,uint32_t new_frequency)520 urj_tap_cable_set_frequency (urj_cable_t *cable, uint32_t new_frequency)
521 {
522     urj_tap_cable_flush (cable, URJ_TAP_CABLE_COMPLETELY);
523     cable->driver->set_frequency (cable, new_frequency);
524 }
525 
526 uint32_t
urj_tap_cable_get_frequency(urj_cable_t * cable)527 urj_tap_cable_get_frequency (urj_cable_t *cable)
528 {
529     return cable->frequency;
530 }
531 
532 void
urj_tap_cable_wait(urj_cable_t * cable)533 urj_tap_cable_wait (urj_cable_t *cable)
534 {
535     int i;
536     volatile int j;
537 
538     j = 0;
539     for (i = 0; i < cable->delay; ++i)
540         j = i;
541 
542     /* Avoid gcc set-but-unused warnings */
543     cable->delay = j + 1;
544 }
545 
546 static urj_cable_t *
urj_tap_cable_create(urj_chain_t * chain,const urj_cable_driver_t * driver)547 urj_tap_cable_create (urj_chain_t *chain, const urj_cable_driver_t *driver)
548 {
549     urj_cable_t *cable;
550 
551     if (urj_bus)
552         urj_bus_buses_delete (urj_bus);
553 
554     urj_tap_chain_disconnect (chain);
555 
556     cable = calloc (1, sizeof (urj_cable_t));
557     if (!cable)
558     {
559         urj_error_set (URJ_ERROR_OUT_OF_MEMORY, "calloc(%zd,%zd) fails",
560                        (size_t) 1, sizeof (urj_cable_t));
561         return NULL;
562     }
563 
564     cable->driver = driver;
565 
566     return cable;
567 }
568 
569 static int
urj_tap_cable_start(urj_chain_t * chain,urj_cable_t * cable)570 urj_tap_cable_start (urj_chain_t *chain, urj_cable_t *cable)
571 {
572     chain->cable = cable;
573 
574     if (urj_tap_cable_init (chain->cable) != URJ_STATUS_OK)
575     {
576         urj_tap_chain_disconnect (chain);
577         return URJ_STATUS_FAIL;
578     }
579 
580     urj_tap_trst_reset (chain);
581 
582     return URJ_STATUS_OK;
583 }
584 
585 urj_cable_t *
urj_tap_cable_parport_connect(urj_chain_t * chain,const urj_cable_driver_t * driver,urj_cable_parport_devtype_t devtype,const char * devname,const urj_param_t * params[])586 urj_tap_cable_parport_connect (urj_chain_t *chain, const urj_cable_driver_t *driver,
587                                urj_cable_parport_devtype_t devtype,
588                                const char *devname, const urj_param_t *params[])
589 {
590     urj_cable_t *cable;
591 
592     if (driver->device_type != URJ_CABLE_DEVICE_PARPORT)
593     {
594         urj_error_set (URJ_ERROR_INVALID,
595                        "parport cable needs parport_connect");
596         return NULL;
597     }
598 
599     cable = urj_tap_cable_create (chain, driver);
600     if (cable == NULL)
601         return NULL;
602 
603     if (cable->driver->connect.parport (cable, devtype, devname,
604                                         params) != URJ_STATUS_OK)
605     {
606         free (cable);
607         return NULL;
608     }
609 
610     if (urj_tap_cable_start (chain, cable) != URJ_STATUS_OK)
611         return NULL;
612 
613     return cable;
614 }
615 
616 urj_cable_t *
urj_tap_cable_usb_connect(urj_chain_t * chain,const urj_cable_driver_t * driver,const urj_param_t * params[])617 urj_tap_cable_usb_connect (urj_chain_t *chain, const urj_cable_driver_t *driver,
618                            const urj_param_t *params[])
619 {
620     urj_cable_t *cable;
621 
622     if (driver->device_type != URJ_CABLE_DEVICE_USB)
623     {
624         urj_error_set (URJ_ERROR_INVALID, "USB cable needs usb_connect");
625         return NULL;
626     }
627 
628     cable = urj_tap_cable_create (chain, driver);
629     if (cable == NULL)
630         return NULL;
631 
632     if (cable->driver->connect.usb (cable, params) != URJ_STATUS_OK)
633     {
634         free (cable);
635         return NULL;
636     }
637 
638     if (urj_tap_cable_start (chain, cable) != URJ_STATUS_OK)
639         return NULL;
640 
641     return cable;
642 }
643 
644 urj_cable_t *
urj_tap_cable_other_connect(urj_chain_t * chain,const urj_cable_driver_t * driver,const urj_param_t * params[])645 urj_tap_cable_other_connect (urj_chain_t *chain, const urj_cable_driver_t *driver,
646                              const urj_param_t *params[])
647 {
648     urj_cable_t *cable;
649 
650     if (driver->device_type != URJ_CABLE_DEVICE_OTHER)
651     {
652         urj_error_set (URJ_ERROR_INVALID, "'other' cable needs other_connect");
653         return NULL;
654     }
655 
656     cable = urj_tap_cable_create (chain, driver);
657     if (cable == NULL)
658         return NULL;
659 
660     if (cable->driver->connect.other (cable, params) != URJ_STATUS_OK)
661     {
662         free (cable);
663         return NULL;
664     }
665 
666     if (urj_tap_cable_start (chain, cable) != URJ_STATUS_OK)
667         return NULL;
668 
669     return cable;
670 }
671 
672 static const urj_param_descr_t cable_param[] =
673 {
674     { URJ_CABLE_PARAM_KEY_PID,          URJ_PARAM_TYPE_LU,      "pid", },
675     { URJ_CABLE_PARAM_KEY_VID,          URJ_PARAM_TYPE_LU,      "vid", },
676     { URJ_CABLE_PARAM_KEY_DESC,         URJ_PARAM_TYPE_STRING,  "desc", },
677     { URJ_CABLE_PARAM_KEY_DRIVER,       URJ_PARAM_TYPE_STRING,  "driver", },
678     { URJ_CABLE_PARAM_KEY_BITMAP,       URJ_PARAM_TYPE_STRING,  "bitmap", },
679     { URJ_CABLE_PARAM_KEY_TDI,          URJ_PARAM_TYPE_LU,      "tdi", },
680     { URJ_CABLE_PARAM_KEY_TDO,          URJ_PARAM_TYPE_LU,      "tdo", },
681     { URJ_CABLE_PARAM_KEY_TMS,          URJ_PARAM_TYPE_LU,      "tms", },
682     { URJ_CABLE_PARAM_KEY_TCK,          URJ_PARAM_TYPE_LU,      "tck", },
683     { URJ_CABLE_PARAM_KEY_INTERFACE,    URJ_PARAM_TYPE_LU,      "interface", },
684     { URJ_CABLE_PARAM_KEY_FIRMWARE,     URJ_PARAM_TYPE_STRING,  "firmware", },
685     { URJ_CABLE_PARAM_KEY_INDEX,        URJ_PARAM_TYPE_LU,      "index", },
686     { URJ_CABLE_PARAM_KEY_TRST,         URJ_PARAM_TYPE_LU,      "trst", },
687     { URJ_CABLE_PARAM_KEY_RESET,        URJ_PARAM_TYPE_LU,      "reset", },
688 };
689 
690 const urj_param_list_t urj_cable_param_list =
691 {
692     .list = cable_param,
693     .n    = ARRAY_SIZE (cable_param),
694 };
695