helper: types: rework h_u32_to_le() and similar for sparse
[openocd.git] / src / server / ipdbg.c
blob69d0f57553d775746fd4e2b06c8f77294ead0f04
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <helper/bits.h>
9 #include <helper/time_support.h>
10 #include <jtag/jtag.h>
11 #include <server/server.h>
12 #include <target/target.h>
14 #include "ipdbg.h"
16 #define IPDBG_BUFFER_SIZE 16384
17 #define IPDBG_MIN_NUM_OF_OPTIONS 4
18 #define IPDBG_MAX_NUM_OF_OPTIONS 14
19 #define IPDBG_MIN_DR_LENGTH 11
20 #define IPDBG_MAX_DR_LENGTH 13
21 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
23 /* private connection data for IPDBG */
24 struct ipdbg_fifo {
25 size_t count;
26 size_t rd_idx;
27 char buffer[IPDBG_BUFFER_SIZE];
30 struct ipdbg_connection {
31 struct ipdbg_fifo dn_fifo;
32 struct ipdbg_fifo up_fifo;
33 bool closed;
36 struct ipdbg_service {
37 struct ipdbg_hub *hub;
38 struct ipdbg_service *next;
39 uint16_t port;
40 struct ipdbg_connection connection;
41 uint8_t tool;
44 struct ipdbg_virtual_ir_info {
45 uint32_t instruction;
46 uint32_t length;
47 uint32_t value;
50 struct ipdbg_hub {
51 uint32_t user_instruction;
52 uint32_t max_tools;
53 uint32_t active_connections;
54 uint32_t active_services;
55 uint32_t valid_mask;
56 uint32_t xoff_mask;
57 uint32_t tool_mask;
58 uint32_t last_dn_tool;
59 struct ipdbg_hub *next;
60 struct jtag_tap *tap;
61 struct connection **connections;
62 uint8_t data_register_length;
63 uint8_t dn_xoff;
64 struct ipdbg_virtual_ir_info *virtual_ir;
67 static struct ipdbg_hub *ipdbg_first_hub;
69 static struct ipdbg_service *ipdbg_first_service;
71 static void ipdbg_init_fifo(struct ipdbg_fifo *fifo)
73 fifo->count = 0;
74 fifo->rd_idx = 0;
77 static bool ipdbg_fifo_is_empty(struct ipdbg_fifo *fifo)
79 return fifo->count == 0;
82 static bool ipdbg_fifo_is_full(struct ipdbg_fifo *fifo)
84 return fifo->count == IPDBG_BUFFER_SIZE;
87 static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo)
89 if (fifo->rd_idx == 0)
90 return;
92 size_t ri = fifo->rd_idx;
93 for (size_t idx = 0; idx < fifo->count; ++idx)
94 fifo->buffer[idx] = fifo->buffer[ri++];
95 fifo->rd_idx = 0;
98 static void ipdbg_append_to_fifo(struct ipdbg_fifo *fifo, char data)
100 if (ipdbg_fifo_is_full(fifo))
101 return;
103 ipdbg_zero_rd_idx(fifo);
104 fifo->buffer[fifo->count++] = data;
107 static char ipdbg_get_from_fifo(struct ipdbg_fifo *fifo)
109 if (ipdbg_fifo_is_empty(fifo))
110 return 0;
112 fifo->count--;
113 return fifo->buffer[fifo->rd_idx++];
116 static int ipdbg_move_buffer_to_connection(struct connection *conn, struct ipdbg_fifo *fifo)
118 if (ipdbg_fifo_is_empty(fifo))
119 return ERROR_OK;
121 struct ipdbg_connection *connection = conn->priv;
122 if (connection->closed)
123 return ERROR_SERVER_REMOTE_CLOSED;
125 ipdbg_zero_rd_idx(fifo);
126 size_t bytes_written = connection_write(conn, fifo->buffer, fifo->count);
127 if (bytes_written != fifo->count) {
128 LOG_ERROR("error during write: %zu != %zu", bytes_written, fifo->count);
129 connection->closed = true;
130 return ERROR_SERVER_REMOTE_CLOSED;
133 fifo->count -= bytes_written;
135 return ERROR_OK;
138 static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_length)
140 int max_tools = 1;
141 data_register_length -= 10; /* 8 bit payload, 1 xoff-flag, 1 valid-flag; remaining bits used to select tool*/
142 while (data_register_length--)
143 max_tools *= 2;
145 /* last tool is used to reset JtagCDC and transfer "XON" to host*/
146 return max_tools - 1;
149 static struct ipdbg_service *ipdbg_find_service(struct ipdbg_hub *hub, uint8_t tool)
151 struct ipdbg_service *service;
152 for (service = ipdbg_first_service; service; service = service->next) {
153 if (service->hub == hub && service->tool == tool)
154 break;
156 return service;
159 static void ipdbg_add_service(struct ipdbg_service *service)
161 struct ipdbg_service *iservice;
162 if (ipdbg_first_service) {
163 for (iservice = ipdbg_first_service; iservice->next; iservice = iservice->next)
165 iservice->next = service;
166 } else
167 ipdbg_first_service = service;
170 static int ipdbg_create_service(struct ipdbg_hub *hub, uint8_t tool, struct ipdbg_service **service, uint16_t port)
172 *service = calloc(1, sizeof(struct ipdbg_service));
173 if (!*service) {
174 LOG_ERROR("Out of memory");
175 return ERROR_FAIL;
178 (*service)->hub = hub;
179 (*service)->tool = tool;
180 (*service)->port = port;
182 return ERROR_OK;
185 static int ipdbg_remove_service(struct ipdbg_service *service)
187 if (!ipdbg_first_service)
188 return ERROR_FAIL;
190 if (service == ipdbg_first_service) {
191 ipdbg_first_service = ipdbg_first_service->next;
192 return ERROR_OK;
195 for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) {
196 if (service == iservice->next) {
197 iservice->next = service->next;
198 return ERROR_OK;
201 return ERROR_FAIL;
204 static struct ipdbg_hub *ipdbg_find_hub(struct jtag_tap *tap,
205 uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir)
207 struct ipdbg_hub *hub = NULL;
208 for (hub = ipdbg_first_hub; hub; hub = hub->next) {
209 if (hub->tap == tap && hub->user_instruction == user_instruction) {
210 if ((!virtual_ir && !hub->virtual_ir) ||
211 (virtual_ir && hub->virtual_ir &&
212 virtual_ir->instruction == hub->virtual_ir->instruction &&
213 virtual_ir->length == hub->virtual_ir->length &&
214 virtual_ir->value == hub->virtual_ir->value)) {
215 break;
219 return hub;
222 static void ipdbg_add_hub(struct ipdbg_hub *hub)
224 struct ipdbg_hub *ihub;
225 if (ipdbg_first_hub) {
226 for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
228 ihub->next = hub;
229 } else
230 ipdbg_first_hub = hub;
233 static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length,
234 struct ipdbg_virtual_ir_info *virtual_ir, struct ipdbg_hub **hub)
236 *hub = NULL;
237 struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub));
238 if (!new_hub) {
239 free(virtual_ir);
240 LOG_ERROR("Out of memory");
241 return ERROR_FAIL;
244 new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
245 new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *));
246 if (!new_hub->connections) {
247 free(virtual_ir);
248 free(new_hub);
249 LOG_ERROR("Out of memory");
250 return ERROR_FAIL;
252 new_hub->tap = tap;
253 new_hub->user_instruction = user_instruction;
254 new_hub->data_register_length = data_register_length;
255 new_hub->valid_mask = BIT(data_register_length - 1);
256 new_hub->xoff_mask = BIT(data_register_length - 2);
257 new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8;
258 new_hub->last_dn_tool = new_hub->tool_mask;
259 new_hub->virtual_ir = virtual_ir;
261 *hub = new_hub;
263 return ERROR_OK;
266 static void ipdbg_free_hub(struct ipdbg_hub *hub)
268 if (!hub)
269 return;
270 free(hub->connections);
271 free(hub->virtual_ir);
272 free(hub);
275 static int ipdbg_remove_hub(struct ipdbg_hub *hub)
277 if (!ipdbg_first_hub)
278 return ERROR_FAIL;
279 if (hub == ipdbg_first_hub) {
280 ipdbg_first_hub = ipdbg_first_hub->next;
281 return ERROR_OK;
284 for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) {
285 if (hub == ihub->next) {
286 ihub->next = hub->next;
287 return ERROR_OK;
291 return ERROR_FAIL;
294 static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value)
296 fields->check_mask = NULL;
297 fields->check_value = NULL;
298 fields->in_value = in_value;
299 fields->num_bits = num_bits;
300 fields->out_value = out_value;
303 static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr)
305 if (!hub)
306 return ERROR_FAIL;
308 struct jtag_tap *tap = hub->tap;
309 if (!tap)
310 return ERROR_FAIL;
312 if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == instr) {
313 /* there is already the requested instruction in the ir */
314 return ERROR_OK;
317 uint8_t *ir_out_val = calloc(DIV_ROUND_UP(tap->ir_length, 8), 1);
318 if (!ir_out_val) {
319 LOG_ERROR("Out of memory");
320 return ERROR_FAIL;
322 buf_set_u32(ir_out_val, 0, tap->ir_length, instr);
324 struct scan_field fields;
325 ipdbg_init_scan_field(&fields, NULL, tap->ir_length, ir_out_val);
326 jtag_add_ir_scan(tap, &fields, TAP_IDLE);
327 int retval = jtag_execute_queue();
329 free(ir_out_val);
331 return retval;
334 static int ipdbg_shift_vir(struct ipdbg_hub *hub)
336 if (!hub)
337 return ERROR_FAIL;
339 if (!hub->virtual_ir)
340 return ERROR_OK;
342 int retval = ipdbg_shift_instr(hub, hub->virtual_ir->instruction);
343 if (retval != ERROR_OK)
344 return retval;
346 struct jtag_tap *tap = hub->tap;
347 if (!tap)
348 return ERROR_FAIL;
350 uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->virtual_ir->length, 8), 1);
351 if (!dr_out_val) {
352 LOG_ERROR("Out of memory");
353 return ERROR_FAIL;
355 buf_set_u32(dr_out_val, 0, hub->virtual_ir->length, hub->virtual_ir->value);
357 struct scan_field fields;
358 ipdbg_init_scan_field(&fields, NULL, hub->virtual_ir->length, dr_out_val);
359 jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE);
360 retval = jtag_execute_queue();
362 free(dr_out_val);
364 return retval;
367 static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *up_data)
369 if (!hub)
370 return ERROR_FAIL;
372 struct jtag_tap *tap = hub->tap;
373 if (!tap)
374 return ERROR_FAIL;
376 uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1);
377 if (!dr_out_val) {
378 LOG_ERROR("Out of memory");
379 return ERROR_FAIL;
381 buf_set_u32(dr_out_val, 0, hub->data_register_length, dn_data);
383 uint8_t *dr_in_val = NULL;
384 if (up_data) {
385 dr_in_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1);
386 if (!dr_in_val) {
387 LOG_ERROR("Out of memory");
388 free(dr_out_val);
389 return ERROR_FAIL;
393 struct scan_field fields;
394 ipdbg_init_scan_field(&fields, dr_in_val, hub->data_register_length, dr_out_val);
395 jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE);
396 int retval = jtag_execute_queue();
398 if (up_data && retval == ERROR_OK)
399 *up_data = buf_get_u32(dr_in_val, 0, hub->data_register_length);
401 free(dr_out_val);
402 free(dr_in_val);
404 return retval;
407 static int ipdbg_distribute_data_from_hub(struct ipdbg_hub *hub, uint32_t up)
409 const bool valid_up_data = up & hub->valid_mask;
410 if (!valid_up_data)
411 return ERROR_OK;
413 const size_t tool = (up >> 8) & hub->tool_mask;
414 if (tool == hub->tool_mask) {
415 const uint8_t xon_cmd = up & 0x00ff;
416 hub->dn_xoff &= ~xon_cmd;
417 LOG_INFO("received xon cmd: %d\n", xon_cmd);
418 return ERROR_OK;
421 struct connection *conn = hub->connections[tool];
422 if (conn) {
423 struct ipdbg_connection *connection = conn->priv;
424 if (ipdbg_fifo_is_full(&connection->up_fifo)) {
425 int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo);
426 if (retval != ERROR_OK)
427 return retval;
429 ipdbg_append_to_fifo(&connection->up_fifo, up);
431 return ERROR_OK;
434 static int ipdbg_jtag_transfer_byte(struct ipdbg_hub *hub, size_t tool, struct ipdbg_connection *connection)
436 uint32_t dn = hub->valid_mask | ((tool & hub->tool_mask) << 8) |
437 (0x00fful & ipdbg_get_from_fifo(&connection->dn_fifo));
438 uint32_t up = 0;
439 int ret = ipdbg_shift_data(hub, dn, &up);
440 if (ret != ERROR_OK)
441 return ret;
443 ret = ipdbg_distribute_data_from_hub(hub, up);
444 if (ret != ERROR_OK)
445 return ret;
447 if ((up & hub->xoff_mask) && (hub->last_dn_tool != hub->max_tools)) {
448 hub->dn_xoff |= BIT(hub->last_dn_tool);
449 LOG_INFO("tool %d sent xoff", hub->last_dn_tool);
452 hub->last_dn_tool = tool;
454 return ERROR_OK;
457 static int ipdbg_polling_callback(void *priv)
459 struct ipdbg_hub *hub = priv;
461 int ret = ipdbg_shift_vir(hub);
462 if (ret != ERROR_OK)
463 return ret;
465 ret = ipdbg_shift_instr(hub, hub->user_instruction);
466 if (ret != ERROR_OK)
467 return ret;
469 /* transfer dn buffers to jtag-hub */
470 unsigned int num_transfers = 0;
471 for (size_t tool = 0; tool < hub->max_tools; ++tool) {
472 struct connection *conn = hub->connections[tool];
473 if (conn && conn->priv) {
474 struct ipdbg_connection *connection = conn->priv;
475 while (((hub->dn_xoff & BIT(tool)) == 0) && !ipdbg_fifo_is_empty(&connection->dn_fifo)) {
476 ret = ipdbg_jtag_transfer_byte(hub, tool, connection);
477 if (ret != ERROR_OK)
478 return ret;
479 ++num_transfers;
484 /* some transfers to get data from jtag-hub in case there is no dn data */
485 while (num_transfers++ < hub->max_tools) {
486 uint32_t dn = 0;
487 uint32_t up = 0;
489 int retval = ipdbg_shift_data(hub, dn, &up);
490 if (retval != ERROR_OK)
491 return ret;
493 retval = ipdbg_distribute_data_from_hub(hub, up);
494 if (retval != ERROR_OK)
495 return ret;
498 /* write from up fifos to sockets */
499 for (size_t tool = 0; tool < hub->max_tools; ++tool) {
500 struct connection *conn = hub->connections[tool];
501 if (conn && conn->priv) {
502 struct ipdbg_connection *connection = conn->priv;
503 int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo);
504 if (retval != ERROR_OK)
505 return retval;
509 return ERROR_OK;
512 static int ipdbg_start_polling(struct ipdbg_service *service, struct connection *connection)
514 struct ipdbg_hub *hub = service->hub;
515 hub->connections[service->tool] = connection;
516 hub->active_connections++;
517 if (hub->active_connections > 1) {
518 /* hub is already initialized */
519 return ERROR_OK;
522 const uint32_t reset_hub = hub->valid_mask | ((hub->max_tools) << 8);
524 int ret = ipdbg_shift_vir(hub);
525 if (ret != ERROR_OK)
526 return ret;
528 ret = ipdbg_shift_instr(hub, hub->user_instruction);
529 if (ret != ERROR_OK)
530 return ret;
532 ret = ipdbg_shift_data(hub, reset_hub, NULL);
533 hub->last_dn_tool = hub->tool_mask;
534 hub->dn_xoff = 0;
535 if (ret != ERROR_OK)
536 return ret;
538 LOG_INFO("IPDBG start_polling");
540 const int time_ms = 20;
541 const int periodic = 1;
542 return target_register_timer_callback(ipdbg_polling_callback, time_ms, periodic, hub);
545 static int ipdbg_stop_polling(struct ipdbg_service *service)
547 struct ipdbg_hub *hub = service->hub;
548 hub->connections[service->tool] = NULL;
549 hub->active_connections--;
550 if (hub->active_connections == 0) {
551 LOG_INFO("IPDBG stop_polling");
553 return target_unregister_timer_callback(ipdbg_polling_callback, hub);
556 return ERROR_OK;
559 static int ipdbg_on_new_connection(struct connection *connection)
561 struct ipdbg_service *service = connection->service->priv;
562 connection->priv = &service->connection;
563 /* initialize ipdbg connection information */
564 ipdbg_init_fifo(&service->connection.up_fifo);
565 ipdbg_init_fifo(&service->connection.dn_fifo);
567 int retval = ipdbg_start_polling(service, connection);
568 if (retval != ERROR_OK) {
569 LOG_ERROR("BUG: ipdbg_start_polling failed");
570 return retval;
573 struct ipdbg_connection *conn = connection->priv;
574 conn->closed = false;
576 LOG_INFO("New IPDBG Connection");
578 return ERROR_OK;
581 static int ipdbg_on_connection_input(struct connection *connection)
583 struct ipdbg_connection *conn = connection->priv;
584 struct ipdbg_fifo *fifo = &conn->dn_fifo;
586 if (ipdbg_fifo_is_full(fifo))
587 return ERROR_OK;
589 ipdbg_zero_rd_idx(fifo);
590 int bytes_read = connection_read(connection, fifo->buffer + fifo->count, IPDBG_BUFFER_SIZE - fifo->count);
591 if (bytes_read <= 0) {
592 if (bytes_read < 0)
593 LOG_ERROR("error during read: %s", strerror(errno));
594 return ERROR_SERVER_REMOTE_CLOSED;
597 fifo->count += bytes_read;
599 return ERROR_OK;
602 static int ipdbg_on_connection_closed(struct connection *connection)
604 struct ipdbg_connection *conn = connection->priv;
605 conn->closed = true;
606 LOG_INFO("Closed IPDBG Connection");
608 return ipdbg_stop_polling(connection->service->priv);
611 static const struct service_driver ipdbg_service_driver = {
612 .name = "ipdbg",
613 .new_connection_during_keep_alive_handler = NULL,
614 .new_connection_handler = ipdbg_on_new_connection,
615 .input_handler = ipdbg_on_connection_input,
616 .connection_closed_handler = ipdbg_on_connection_closed,
617 .keep_client_alive_handler = NULL,
620 static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction,
621 uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
623 LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
625 struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
626 if (hub) {
627 free(virtual_ir);
628 if (hub->data_register_length != data_register_length) {
629 LOG_DEBUG("hub must have the same data_register_length for all tools");
630 return ERROR_FAIL;
632 } else {
633 int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub);
634 if (retval != ERROR_OK) {
635 free(virtual_ir);
636 return retval;
640 struct ipdbg_service *service = NULL;
641 int retval = ipdbg_create_service(hub, tool, &service, port);
643 if (retval != ERROR_OK || !service) {
644 if (hub->active_services == 0 && hub->active_connections == 0)
645 ipdbg_free_hub(hub);
646 return ERROR_FAIL;
649 char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
650 snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port);
651 retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service);
652 if (retval == ERROR_OK) {
653 ipdbg_add_service(service);
654 if (hub->active_services == 0 && hub->active_connections == 0)
655 ipdbg_add_hub(hub);
656 hub->active_services++;
657 } else {
658 if (hub->active_services == 0 && hub->active_connections == 0)
659 ipdbg_free_hub(hub);
660 free(service);
663 return retval;
666 static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction,
667 struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
669 struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
670 free(virtual_ir);
671 if (!hub)
672 return ERROR_FAIL;
674 struct ipdbg_service *service = ipdbg_find_service(hub, tool);
675 if (!service)
676 return ERROR_FAIL;
678 int retval = ipdbg_remove_service(service);
679 if (retval != ERROR_OK) {
680 LOG_ERROR("BUG: ipdbg_remove_service failed");
681 return retval;
684 char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
685 snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", service->port);
686 retval = remove_service("ipdbg", port_str_buffer);
687 /* The ipdbg_service structure is freed by server.c:remove_service().
688 There the "priv" pointer is freed.*/
689 if (retval != ERROR_OK) {
690 LOG_ERROR("BUG: remove_service failed");
691 return retval;
693 hub->active_services--;
694 if (hub->active_connections == 0 && hub->active_services == 0) {
695 retval = ipdbg_remove_hub(hub);
696 if (retval != ERROR_OK) {
697 LOG_ERROR("BUG: ipdbg_remove_hub failed");
698 return retval;
700 ipdbg_free_hub(hub);
702 return ERROR_OK;
705 COMMAND_HANDLER(handle_ipdbg_command)
707 struct jtag_tap *tap = NULL;
708 uint16_t port = 4242;
709 uint8_t tool = 1;
710 uint32_t user_instruction = 0x00;
711 uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
712 bool start = true;
713 bool hub_configured = false;
714 bool has_virtual_ir = false;
715 uint32_t virtual_ir_instruction = 0x00e;
716 uint32_t virtual_ir_length = 5;
717 uint32_t virtual_ir_value = 0x11;
718 struct ipdbg_virtual_ir_info *virtual_ir = NULL;
720 if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS))
721 return ERROR_COMMAND_SYNTAX_ERROR;
723 for (unsigned int i = 0; i < CMD_ARGC; ++i) {
724 if (strcmp(CMD_ARGV[i], "-tap") == 0) {
725 if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') {
726 command_print(CMD, "no TAP given");
727 return ERROR_FAIL;
729 tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
730 if (!tap) {
731 command_print(CMD, "Tap %s unknown", CMD_ARGV[i + 1]);
732 return ERROR_FAIL;
734 ++i;
735 } else if (strcmp(CMD_ARGV[i], "-hub") == 0) {
736 COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub");
737 hub_configured = true;
738 COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length);
739 if (data_register_length < IPDBG_MIN_DR_LENGTH ||
740 data_register_length > IPDBG_MAX_DR_LENGTH) {
741 command_print(CMD, "length of \"user\"-data register must be at least %d and at most %d.",
742 IPDBG_MIN_DR_LENGTH, IPDBG_MAX_DR_LENGTH);
743 return ERROR_FAIL;
745 } else if (strcmp(CMD_ARGV[i], "-vir") == 0) {
746 COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_value);
747 COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length);
748 COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
749 has_virtual_ir = true;
750 } else if (strcmp(CMD_ARGV[i], "-port") == 0) {
751 COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number");
752 } else if (strcmp(CMD_ARGV[i], "-tool") == 0) {
753 COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
754 } else if (strcmp(CMD_ARGV[i], "-stop") == 0) {
755 start = false;
756 } else if (strcmp(CMD_ARGV[i], "-start") == 0) {
757 start = true;
758 } else {
759 command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
760 return ERROR_FAIL;
764 if (!tap) {
765 command_print(CMD, "no valid tap selected");
766 return ERROR_FAIL;
769 if (!hub_configured) {
770 command_print(CMD, "hub not configured correctly");
771 return ERROR_FAIL;
774 if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) {
775 command_print(CMD, "Tool: %d is invalid", tool);
776 return ERROR_FAIL;
779 if (has_virtual_ir) {
780 virtual_ir = calloc(1, sizeof(struct ipdbg_virtual_ir_info));
781 if (!virtual_ir) {
782 LOG_ERROR("Out of memory");
783 return ERROR_FAIL;
785 virtual_ir->instruction = virtual_ir_instruction;
786 virtual_ir->length = virtual_ir_length;
787 virtual_ir->value = virtual_ir_value;
790 if (start)
791 return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool);
792 else
793 return ipdbg_stop(tap, user_instruction, virtual_ir, tool);
796 static const struct command_registration ipdbg_command_handlers[] = {
798 .name = "ipdbg",
799 .handler = handle_ipdbg_command,
800 .mode = COMMAND_EXEC,
801 .help = "Starts or stops an IPDBG JTAG-Host server.",
802 .usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]"
803 " [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
805 COMMAND_REGISTRATION_DONE
808 int ipdbg_register_commands(struct command_context *cmd_ctx)
810 return register_commands(cmd_ctx, NULL, ipdbg_command_handlers);