+COMMAND_HANDLER(handle_adapter_serial_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ free(adapter_config.serial);
+ adapter_config.serial = strdup(CMD_ARGV[0]);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_adapter_reset_de_assert)
+{
+ enum values {
+ VALUE_UNDEFINED = -1,
+ VALUE_DEASSERT = 0,
+ VALUE_ASSERT = 1,
+ };
+ enum values value;
+ enum values srst = VALUE_UNDEFINED;
+ enum values trst = VALUE_UNDEFINED;
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+ char *signal;
+
+ if (CMD_ARGC == 0) {
+ if (transport_is_jtag()) {
+ if (jtag_reset_config & RESET_HAS_TRST)
+ signal = jtag_get_trst() ? "asserted" : "deasserted";
+ else
+ signal = "not present";
+ command_print(CMD, "trst %s", signal);
+ }
+
+ if (jtag_reset_config & RESET_HAS_SRST)
+ signal = jtag_get_srst() ? "asserted" : "deasserted";
+ else
+ signal = "not present";
+ command_print(CMD, "srst %s", signal);
+
+ return ERROR_OK;
+ }
+
+ if (CMD_ARGC != 1 && CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT;
+ if (strcmp(CMD_ARGV[0], "srst") == 0)
+ srst = value;
+ else if (strcmp(CMD_ARGV[0], "trst") == 0)
+ trst = value;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 3) {
+ if (strcmp(CMD_ARGV[1], "assert") == 0)
+ value = VALUE_ASSERT;
+ else if (strcmp(CMD_ARGV[1], "deassert") == 0)
+ value = VALUE_DEASSERT;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED)
+ srst = value;
+ else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED)
+ trst = value;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (trst == VALUE_UNDEFINED) {
+ if (transport_is_jtag())
+ trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT;
+ else
+ trst = VALUE_DEASSERT; /* unused, safe value */
+ }
+
+ if (srst == VALUE_UNDEFINED) {
+ if (jtag_reset_config & RESET_HAS_SRST)
+ srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT;
+ else
+ srst = VALUE_DEASSERT; /* unused, safe value */
+ }
+
+ if (trst == VALUE_ASSERT && !transport_is_jtag()) {
+ LOG_ERROR("transport has no trst signal");
+ return ERROR_FAIL;
+ }
+
+ if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
+ LOG_ERROR("adapter has no srst signal");
+ return ERROR_FAIL;
+ }
+
+ return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT,
+ (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT);
+}
+
+static int get_gpio_index(const char *signal_name)
+{
+ for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) {
+ if (strcmp(gpio_map[i].name, signal_name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config_index gpio_idx)
+{
+ struct adapter_gpio_config *gpio_config = &adapter_config.gpios[gpio_idx];
+ const char *active_state = gpio_config->active_low ? "low" : "high";
+ const char *dir = "";
+ const char *drive = "";
+ const char *pull = "";
+ const char *init_state = "";
+
+ if (gpio_config->gpio_num == ADAPTER_GPIO_NOT_SET) {
+ command_print(CMD, "adapter gpio %s: not configured", gpio_map[gpio_idx].name);
+ return ERROR_OK;
+ }
+
+ switch (gpio_map[gpio_idx].direction) {
+ case ADAPTER_GPIO_DIRECTION_INPUT:
+ dir = "input";
+ break;
+ case ADAPTER_GPIO_DIRECTION_OUTPUT:
+ dir = "output";
+ break;
+ case ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL:
+ dir = "bidirectional";
+ break;
+ }
+
+ if (gpio_map[gpio_idx].permit_drive_option) {
+ switch (gpio_config->drive) {
+ case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
+ drive = ", push-pull";
+ break;
+ case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
+ drive = ", open-drain";
+ break;
+ case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
+ drive = ", open-source";
+ break;
+ }
+ }
+
+ switch (gpio_config->pull) {
+ case ADAPTER_GPIO_PULL_NONE:
+ pull = ", pull-none";
+ break;
+ case ADAPTER_GPIO_PULL_UP:
+ pull = ", pull-up";
+ break;
+ case ADAPTER_GPIO_PULL_DOWN:
+ pull = ", pull-down";
+ break;
+ }
+
+ if (gpio_map[gpio_idx].permit_init_state_option) {
+ switch (gpio_config->init_state) {
+ case ADAPTER_GPIO_INIT_STATE_INACTIVE:
+ init_state = ", init-state inactive";
+ break;
+ case ADAPTER_GPIO_INIT_STATE_ACTIVE:
+ init_state = ", init-state active";
+ break;
+ case ADAPTER_GPIO_INIT_STATE_INPUT:
+ init_state = ", init-state input";
+ break;
+ }
+ }
+
+ command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s",
+ gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, (int)gpio_config->chip_num, active_state,
+ drive, pull, init_state);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(helper_adapter_gpio_print_all_configs)
+{
+ for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i)
+ CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, i);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(adapter_gpio_config_handler)
+{
+ unsigned int i = 1;
+ struct adapter_gpio_config *gpio_config;
+
+ adapter_driver_gpios_init();
+
+ if (CMD_ARGC == 0) {
+ CALL_COMMAND_HANDLER(helper_adapter_gpio_print_all_configs);
+ return ERROR_OK;
+ }
+
+ int gpio_idx = get_gpio_index(CMD_ARGV[0]);
+ if (gpio_idx == -1) {
+ LOG_ERROR("adapter has no gpio named %s", CMD_ARGV[0]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (CMD_ARGC == 1) {
+ CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, gpio_idx);
+ return ERROR_OK;
+ }
+
+ gpio_config = &adapter_config.gpios[gpio_idx];
+ while (i < CMD_ARGC) {
+ LOG_DEBUG("Processing %s", CMD_ARGV[i]);
+
+ if (isdigit(*CMD_ARGV[i])) {
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], gpio_config->gpio_num);
+ ++i;
+ continue;
+ }
+
+ if (strcmp(CMD_ARGV[i], "-chip") == 0) {
+ if (CMD_ARGC - i < 2) {
+ LOG_ERROR("-chip option requires a parameter");
+ return ERROR_FAIL;
+ }
+ LOG_DEBUG("-chip arg is %s", CMD_ARGV[i + 1]);
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i + 1], gpio_config->chip_num);
+ i += 2;
+ continue;
+ }
+
+ if (strcmp(CMD_ARGV[i], "-active-high") == 0) {
+ ++i;
+ gpio_config->active_low = false;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-active-low") == 0) {
+ ++i;
+ gpio_config->active_low = true;
+ continue;
+ }
+
+ if (gpio_map[gpio_idx].permit_drive_option) {
+ if (strcmp(CMD_ARGV[i], "-push-pull") == 0) {
+ ++i;
+ gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-open-drain") == 0) {
+ ++i;
+ gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-open-source") == 0) {
+ ++i;
+ gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE;
+ continue;
+ }
+ }
+
+ if (strcmp(CMD_ARGV[i], "-pull-none") == 0) {
+ ++i;
+ gpio_config->pull = ADAPTER_GPIO_PULL_NONE;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-pull-up") == 0) {
+ ++i;
+ gpio_config->pull = ADAPTER_GPIO_PULL_UP;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-pull-down") == 0) {
+ ++i;
+ gpio_config->pull = ADAPTER_GPIO_PULL_DOWN;
+ continue;
+ }
+
+ if (gpio_map[gpio_idx].permit_init_state_option) {
+ if (strcmp(CMD_ARGV[i], "-init-inactive") == 0) {
+ ++i;
+ gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INACTIVE;
+ continue;
+ }
+ if (strcmp(CMD_ARGV[i], "-init-active") == 0) {
+ ++i;
+ gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE;
+ continue;
+ }
+
+ if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL &&
+ strcmp(CMD_ARGV[i], "-init-input") == 0) {
+ ++i;
+ gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INPUT;
+ continue;
+ }
+ }
+
+ LOG_ERROR("illegal option for adapter %s %s: %s",
+ CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ /* Force swdio_dir init state to be compatible with swdio init state */
+ if (gpio_idx == ADAPTER_GPIO_IDX_SWDIO)
+ adapter_config.gpios[ADAPTER_GPIO_IDX_SWDIO_DIR].init_state =
+ (gpio_config->init_state == ADAPTER_GPIO_INIT_STATE_INPUT) ?
+ ADAPTER_GPIO_INIT_STATE_INACTIVE :
+ ADAPTER_GPIO_INIT_STATE_ACTIVE;
+
+ return ERROR_OK;
+}
+