This is an automated email from Gerrit.

"Patrick Dussud <phdus...@hotmail.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7344

-- gerrit

commit 43eaff583c979046643c483f9685ab506ac591c4
Author: phdussud <phdus...@users.noreply.github.com>
Date:   Tue Nov 8 15:39:45 2022 -0800

    Support for the DirtyJTAG probe
    
    It is a low cost probe build on top of STM32F1 boards
    (like blue pill and such) and RP Pico boards.
    see https://github.com/phdussud/pico-dirtyJtag and 
https://github.com/jeanthom/DirtyJTAG
    Signed-off-by: phdussud <phdus...@users.noreply.github.com>
    Change-Id: I941607982c24f99b19e921952fd288471a3d3a4d

diff --git a/configure.ac b/configure.ac
index 503e791695..8619459d7d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,7 +123,8 @@ m4_define([USB1_ADAPTERS],
        [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]],
        [[xds110], [TI XDS110 Debug Probe], [XDS110]],
        [[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]],
-       [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
+  [[dirtyjtag], [DirtyJTAG], [DIRTYJTAG]],
+  [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
        [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]],
        [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]],
        [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]],
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index 6410f37545..b11e147c3e 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -193,6 +193,9 @@ endif
 if AM335XGPIO
 DRIVERFILES += %D%/am335xgpio.c
 endif
+if DIRTYJTAG
+DRIVERFILES += %D%/dirtyjtag.c
+endif
 
 DRIVERHEADERS = \
        %D%/bitbang.h \
diff --git a/src/jtag/drivers/dirtyjtag.c b/src/jtag/drivers/dirtyjtag.c
new file mode 100644
index 0000000000..2c882b0151
--- /dev/null
+++ b/src/jtag/drivers/dirtyjtag.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0-or-laterswitch
+
+/***************************************************************************
+ *      Copyright (C) 2020 Jean THOMAS                                         
                                        *
+ *      p...@git.jeanthomas.me                                                 
                                                *
+ *                                                                             
                                                                        *
+ *      This program is free software; you can redistribute it and/or modify   
*
+ *      it under the terms of the GNU General Public License as published by   
*
+ *      the Free Software Foundation; either version 2 of the License, or      
        *
+ *      (at your option) any later version.                                    
                                *
+ *                                                                             
                                                                        *
+ *      This program is distributed in the hope that it will be useful,        
        *
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of         
        *
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the         
        *
+ *      GNU General Public License for more details.                           
                        *
+ *                                                                             
                                                                        *
+ *      You should have received a copy of the GNU General Public License      
        *
+ *      along with this program.       If not, see 
<http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* project specific includes */
+#include <helper/bits.h>
+#include <helper/time_support.h>
+#include <jtag/jtag.h>
+#include <jtag/commands.h>
+#include <jtag/interface.h>
+
+#include "libusb_helper.h"
+
+/**
+ * USB settings
+ */
+static unsigned int dirtyjtag_ep_write = 0x01;
+static unsigned int dirtyjtag_ep_read = 0x82;
+#define DIRTYJTAG_USB_TIMEOUT 100
+static const uint16_t dirtyjtag_vid = 0x1209;
+static const uint16_t dirtyjtag_pid = 0xC0CA;
+
+enum dirtyjtag_cmd {
+       CMD_STOP = 0x00,
+       CMD_INFO = 0x01,
+       CMD_FREQ = 0x02,
+       CMD_XFER = 0x03,
+       CMD_SETSIG = 0x04,
+       CMD_GETSIG = 0x05,
+       CMD_CLK = 0x06
+};
+
+// Modifiers applicable only to DirtyJTAG2
+enum command_modifier { EXTEND_LENGTH = 0x40, NO_READ = 0x80, READOUT = 0x80 };
+
+struct version_specific {
+       uint8_t no_read;                // command modifier for xfer no read
+       uint16_t max_bits;      // max bit count that can be transferred
+};
+
+static struct version_specific dirtyjtag_v_options[3] = {
+               {0, 240}, {0, 240}, {NO_READ, 496}};
+static int dirtyjtag_version;
+enum dirtyjtag_signal {
+       SIG_TCK = (1 << 1),
+       SIG_TDI = (1 << 2),
+       SIG_TDO = (1 << 3),
+       SIG_TMS = (1 << 4),
+       SIG_TRST = (1 << 5),
+       SIG_SRST = (1 << 6)
+};
+
+static struct libusb_device_handle *usb_handle;
+
+/**
+ * Utils
+
+static int min(int a, int b)
+{
+       return (a < b) ? a : b;
+}
+*/
+static unsigned char swap_bits(unsigned char x)
+{
+       const unsigned char lut[16] = {0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+                                0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf};
+
+       return lut[x & 0xF] << 4 | lut[x >> 4];
+}
+
+/*
+ * DirtyJTAG command buffer code
+ */
+#define DIRTYJTAG_BUFFER_SIZE 64
+static const size_t dirtyjtag_buffer_size = DIRTYJTAG_BUFFER_SIZE;
+static uint8_t dirtyjtag_buffer[DIRTYJTAG_BUFFER_SIZE];
+static size_t dirtyjtag_buffer_use;
+
+static void dirtyjtag_buffer_flush(void)
+{
+       size_t sent = 0, res;
+
+       if (dirtyjtag_buffer_use == 0)
+               return;
+
+       dirtyjtag_buffer[dirtyjtag_buffer_use] = CMD_STOP;
+
+       res = jtag_libusb_bulk_write(usb_handle, dirtyjtag_ep_write, (char 
*)dirtyjtag_buffer,
+                                                                
dirtyjtag_buffer_use + 1, DIRTYJTAG_USB_TIMEOUT, (int *)&sent);
+       assert(res == ERROR_OK);
+       assert(sent == dirtyjtag_buffer_use + 1);
+
+       dirtyjtag_buffer_use = 0;
+}
+
+static void dirtyjtag_buffer_append(const uint8_t *command, size_t length)
+{
+       assert(length < dirtyjtag_buffer_size);
+       assert(command);
+
+       if ((dirtyjtag_buffer_use + length + 1) > dirtyjtag_buffer_size)
+               dirtyjtag_buffer_flush();
+
+       memcpy(&dirtyjtag_buffer[dirtyjtag_buffer_use], command, length);
+       dirtyjtag_buffer_use += length;
+}
+
+/**
+ * Add one TCK/TMS/TDI sample to send buffer.
+ */
+static void dirtyjtag_write(int tck, int tms, int tdi)
+{
+       uint8_t command[] = {
+                       CMD_SETSIG, SIG_TCK | SIG_TMS | SIG_TDI,
+                       (tck ? SIG_TCK : 0) | (tms ? SIG_TMS : 0) | (tdi ? 
SIG_TDI : 0)};
+       dirtyjtag_buffer_append(command, ARRAY_SIZE(command));
+}
+
+/**
+ * Read TDO pin
+ */
+static bool dirtyjtag_get_tdo(void)
+{
+       int res, read = 0;
+       char state;
+       uint8_t command[] = {CMD_GETSIG};
+
+       dirtyjtag_buffer_append(command, ARRAY_SIZE(command));
+       dirtyjtag_buffer_flush();
+
+       res = jtag_libusb_bulk_read(usb_handle, dirtyjtag_ep_read, &state, 1,
+                                               DIRTYJTAG_USB_TIMEOUT, &read);
+       assert(res == ERROR_OK);
+       assert(read == 1);
+
+       return !!(state & SIG_TDO);
+}
+
+/**
+ * Send bunch of clock pulses
+ */
+static void dirtyjtag_clk(int num_cycles, int tms, int tdi)
+{
+       uint8_t command[] = {CMD_CLK, (tms ? SIG_TMS : 0) | (tdi ? SIG_TDI : 
0), 0};
+
+       /*
+        * We can only do 255 clock pulses in one command, so we need
+        * to send multiple clock commands.
+        */
+       while (num_cycles > 0) {
+               command[2] = MIN(255, num_cycles);
+               num_cycles -= MIN(255, num_cycles);
+               dirtyjtag_buffer_append(command, ARRAY_SIZE(command));
+       }
+}
+
+/**
+ * Control /TRST and /SYSRST pins.
+ * Perform immediate bitbang transaction.
+ */
+static int dirtyjtag_reset(int trst, int srst)
+{
+       uint8_t command[] = {CMD_SETSIG, SIG_TRST | SIG_SRST,
+                                        (trst ? 0 : SIG_TRST) | (srst ? 0 : 
SIG_SRST)};
+
+       LOG_DEBUG("%s(%d,%d)", __func__, trst, srst);
+       dirtyjtag_buffer_append(command, ARRAY_SIZE(command));
+       dirtyjtag_buffer_flush();
+       return ERROR_OK;
+}
+
+static int dirtyjtag_speed(int divisor)
+{
+       uint8_t command[] = {CMD_FREQ, divisor >> 8, divisor};
+
+       dirtyjtag_buffer_append(command, ARRAY_SIZE(command));
+
+       return ERROR_OK;
+}
+static int dirtyjtag_getversion(void)
+{
+       int actual_length;
+       int res;
+       uint8_t buf[] = {CMD_INFO, CMD_STOP};
+       uint8_t rx_buf[64];
+       res = jtag_libusb_bulk_write(usb_handle, dirtyjtag_ep_write, (char 
*)buf, 2,
+                                                DIRTYJTAG_USB_TIMEOUT, 
&actual_length);
+       assert(res == ERROR_OK);
+       if (res) {
+               LOG_ERROR("%s: usb bulk write failed", __func__);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       do {
+               res = jtag_libusb_bulk_read(usb_handle, dirtyjtag_ep_read, 
(char *)rx_buf,
+                               64, DIRTYJTAG_USB_TIMEOUT, &actual_length);
+               if (res) {
+                       LOG_ERROR("%s: usb bulk read failed", __func__);
+                       return ERROR_JTAG_INIT_FAILED;
+               }
+       } while (actual_length == 0);
+       if (!strncmp("DJTAG1\n", (char *)rx_buf, 7)) {
+               dirtyjtag_version = 1;
+       } else if (!strncmp("DJTAG2\n", (char *)rx_buf, 7)) {
+               dirtyjtag_version = 2;
+       } else {
+               LOG_INFO("dirtyJtag version unknown");
+               dirtyjtag_version = 0;
+       }
+       LOG_INFO("dirtyjtag version %d", dirtyjtag_version);
+       return ERROR_OK;
+}
+
+static int dirtyjtag_init(void)
+{
+       uint16_t avids[] = {dirtyjtag_vid, 0};
+       uint16_t apids[] = {dirtyjtag_pid, 0};
+       int res;
+       if (jtag_libusb_open(avids, apids, &usb_handle, NULL)) {
+               LOG_ERROR("dirtyjtag not found: vid=%04x, pid=%04x\n", 
dirtyjtag_vid,
+                               dirtyjtag_pid);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       if (jtag_libusb_choose_interface(usb_handle, &dirtyjtag_ep_read,
+                                        &dirtyjtag_ep_write, -1, -1, 0,
+                                        LIBUSB_TRANSFER_TYPE_BULK)) {
+               LOG_ERROR("unable to claim interface");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       res = dirtyjtag_getversion();
+       if (res != ERROR_OK)
+               return ERROR_JTAG_INIT_FAILED;
+       dirtyjtag_buffer_use = 0;
+       return ERROR_OK;
+}
+
+static int dirtyjtag_quit(void)
+{
+       if (libusb_release_interface(usb_handle, 0) != 0)
+               LOG_ERROR("usb release interface failed");
+
+       jtag_libusb_close(usb_handle);
+
+       return ERROR_OK;
+}
+
+static int dirtyjtag_speed_div(int divisor, int *khz)
+{
+       *khz = divisor;
+       return ERROR_OK;
+}
+
+static int dirtyjtag_khz(int khz, int *divisor)
+{
+       if (khz == 0) {
+               LOG_DEBUG("RCLK not supported");
+               return ERROR_FAIL;
+       }
+
+       *divisor = (khz < 65535) ? khz : 65535;
+       return ERROR_OK;
+}
+
+static const struct command_registration dirtyjtag_command_handlers[] = {
+               COMMAND_REGISTRATION_DONE};
+
+static void syncbb_end_state(tap_state_t state)
+{
+       assert(tap_is_state_stable(state));
+       tap_set_end_state(state);
+}
+
+static void syncbb_state_move(int skip)
+{
+       int i = 0, tms = 0;
+       uint8_t tms_scan = tap_get_tms_path(tap_get_state(), 
tap_get_end_state());
+       int tms_count = tap_get_tms_path_len(tap_get_state(), 
tap_get_end_state());
+
+       for (i = skip; i < tms_count; i++) {
+               tms = (tms_scan >> i) & 1;
+               dirtyjtag_clk(1, tms, 0);
+       }
+
+       tap_set_state(tap_get_end_state());
+}
+
+/**
+ * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG
+ * (or SWD) state machine.
+ */
+static int syncbb_execute_tms(struct jtag_command *cmd)
+{
+       unsigned int num_bits = cmd->cmd.tms->num_bits;
+       const uint8_t *bits = cmd->cmd.tms->bits;
+
+       LOG_DEBUG_IO("TMS: %d bits", num_bits);
+
+       int tms = 0;
+       for (unsigned int i = 0; i < num_bits; i++) {
+               tms = ((bits[i / 8] >> (i % 8)) & 1);
+               dirtyjtag_clk(1, tms, 0);
+       }
+
+       return ERROR_OK;
+}
+
+static void syncbb_path_move(struct pathmove_command *cmd)
+{
+       int num_states = cmd->num_states;
+       int state_count;
+       int tms = 0;
+
+       state_count = 0;
+       while (num_states) {
+               if (tap_state_transition(tap_get_state(), false) ==
+       cmd->path[state_count]) {
+                       tms = 0;
+               } else if (tap_state_transition(tap_get_state(), true) ==
+                                cmd->path[state_count]) {
+                       tms = 1;
+               } else {
+                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
+               tap_state_name(tap_get_state()),
+               tap_state_name(cmd->path[state_count]));
+                       exit(-1);
+               }
+
+               dirtyjtag_clk(1, tms, 0);
+               tap_set_state(cmd->path[state_count]);
+               state_count++;
+               num_states--;
+       }
+       tap_set_end_state(tap_get_state());
+}
+
+static void syncbb_runtest(int num_cycles)
+{
+       tap_state_t saved_end_state = tap_get_end_state();
+
+       /* only do a state_move when we're not already in IDLE */
+       if (tap_get_state() != TAP_IDLE) {
+               syncbb_end_state(TAP_IDLE);
+               syncbb_state_move(0);
+       }
+
+       dirtyjtag_clk(num_cycles, 0, 0);
+
+       /* finish in end_state */
+       syncbb_end_state(saved_end_state);
+       if (tap_get_state() != tap_get_end_state())
+               syncbb_state_move(0);
+}
+
+/**
+ * CMD_XFER:
+ *      Read TDO
+ *      Set TDI
+ *      Set TCK high
+ *      Set TCK low
+ *
+ * Bitbang:
+ *      Read TDO
+ *      Set TDI, TMS, TCK low
+ *      Set TCK high
+ *
+ */
+static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
+                                               int scan_size)
+{
+       tap_state_t saved_end_state = tap_get_end_state();
+       int sent_bits, sent_bytes, read, written, res;
+       size_t i, buffer_pos = 0;
+       uint8_t xfer_rx[512], xfer_tx[512] = {CMD_XFER, 0};
+       int pos_last_byte = (scan_size - 1) / 8;
+       int pos_last_bit = (scan_size - 1) % 8;
+       bool last_bit = !!(buffer[pos_last_byte] & (1 << pos_last_bit));
+
+       // printf("\n*** syncbb_scan 
****************************************\n");
+       // printf("TX\t");
+       // const size_t xfer_bytes = (scan_size + 7) / 8;
+       // for (i = 0; i < xfer_bytes; i++)
+       // {
+       //      printf("%02x", buffer[i]);
+       // }
+       // printf("\n");
+
+       assert(scan_size > 0);
+       scan_size--;
+
+       if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) ||
+       (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) {
+               if (ir_scan)
+                       syncbb_end_state(TAP_IRSHIFT);
+               else
+                       syncbb_end_state(TAP_DRSHIFT);
+               syncbb_state_move(0);
+               syncbb_end_state(saved_end_state);
+       }
+
+       dirtyjtag_buffer_flush();
+
+       if (type != SCAN_OUT)
+               xfer_tx[0] |= dirtyjtag_v_options->no_read;
+       while (scan_size > 0) {
+               sent_bits = MIN(dirtyjtag_v_options->max_bits, scan_size);
+               sent_bytes = (sent_bits + 7) / 8;
+               if (sent_bits > 255) {
+                       xfer_tx[0] |= EXTEND_LENGTH;
+                       xfer_tx[1] = sent_bits - 256;
+               } else {
+                       xfer_tx[0] &= ~EXTEND_LENGTH;
+                       xfer_tx[1] = sent_bits;
+               }
+               if (type != SCAN_IN) {
+                       memcpy(&xfer_tx[2], &buffer[buffer_pos], sent_bytes);
+                       for (i = 2; i < (2 + (size_t)sent_bytes); i++)
+                               xfer_tx[i] = swap_bits(xfer_tx[i]);
+               } else {
+                       /* Set TDO to 0 */
+                       memset(&xfer_tx[2], 0, sent_bytes);
+               }
+
+               res =
+       jtag_libusb_bulk_write(usb_handle, dirtyjtag_ep_write, (char *)xfer_tx,
+                                                sent_bytes + 2, 
DIRTYJTAG_USB_TIMEOUT, &written);
+
+               if (!dirtyjtag_v_options->no_read || (type != SCAN_OUT)) {
+                       read = 0;
+                       res = jtag_libusb_bulk_read(usb_handle, 
dirtyjtag_ep_read, (char *)xfer_rx,
+                                                                               
(sent_bits > 255) ? sent_bytes : 32, DIRTYJTAG_USB_TIMEOUT, &read);
+                       assert(res == ERROR_OK);
+                       assert(read >= sent_bytes);
+               }
+
+               if (type != SCAN_OUT) {
+                       for (i = 0; i < 32; i++)
+                               xfer_rx[i] = swap_bits(xfer_rx[i]);
+                       memcpy(&buffer[buffer_pos], xfer_rx, sent_bytes);
+               }
+
+               scan_size -= sent_bits;
+               buffer_pos += sent_bytes;       // equivalent to 
CEIL(sent_bits/8)
+       }
+
+       dirtyjtag_write(0, 1, last_bit);
+       dirtyjtag_write(1, 1, last_bit);
+       if (type != SCAN_OUT) {
+               buffer[pos_last_byte] = (buffer[pos_last_byte] & ~(1 << 
pos_last_bit)) |
+                                       (dirtyjtag_get_tdo() << pos_last_bit);
+       }
+       dirtyjtag_write(0, 1, last_bit);
+
+       if (tap_get_state() != tap_get_end_state()) {
+               /* we *KNOW* the above loop transitioned out of
+                * the shift state, so we skip the first state
+                * and move directly to the end state.
+                */
+               syncbb_state_move(1);
+       }
+}
+
+static int syncbb_execute_queue(void)
+{
+       struct jtag_command *cmd =
+       jtag_command_queue; /* currently processed command */
+       int scan_size;
+       enum scan_type type;
+       uint8_t *buffer;
+       int retval;
+
+       /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
+        * that wasn't handled by a caller-provided error handler
+        */
+       retval = ERROR_OK;
+
+       while (cmd) {
+               switch (cmd->type) {
+                       case JTAG_RESET:
+                               LOG_DEBUG_IO("reset trst: %i srst %i", 
cmd->cmd.reset->trst,
+                                                        cmd->cmd.reset->srst);
+                               if ((cmd->cmd.reset->trst == 1) ||
+                                       (cmd->cmd.reset->srst &&
+                                       (jtag_get_reset_config() & 
RESET_SRST_PULLS_TRST)))
+                                       tap_set_state(TAP_RESET);
+                               dirtyjtag_reset(cmd->cmd.reset->trst, 
cmd->cmd.reset->srst);
+                               break;
+
+                       case JTAG_RUNTEST:
+                               LOG_DEBUG_IO("runtest %i cycles, end in %s",
+                                                        
cmd->cmd.runtest->num_cycles,
+                                                        
tap_state_name(cmd->cmd.runtest->end_state));
+
+                               syncbb_end_state(cmd->cmd.runtest->end_state);
+                               syncbb_runtest(cmd->cmd.runtest->num_cycles);
+                               break;
+
+                       case JTAG_STABLECLOCKS:
+                               dirtyjtag_clk(cmd->cmd.stableclocks->num_cycles,
+                                               (tap_get_state() == TAP_RESET ? 
SIG_TMS : 0), 0);
+               break;
+
+                       case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */
+                               LOG_DEBUG_IO("statemove end in %s",
+                                                        
tap_state_name(cmd->cmd.statemove->end_state));
+
+                               syncbb_end_state(cmd->cmd.statemove->end_state);
+                               syncbb_state_move(0);
+                               break;
+
+                       case JTAG_PATHMOVE:
+                               LOG_DEBUG_IO("pathmove: %i states, end in %s", 
cmd->cmd.pathmove->num_states,
+                                                        
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
+                               syncbb_path_move(cmd->cmd.pathmove);
+                               break;
+
+                       case JTAG_SCAN:
+                               LOG_DEBUG_IO("%s scan end in %s",
+                                                        
(cmd->cmd.scan->ir_scan) ? "IR" : "DR",
+                                                        
tap_state_name(cmd->cmd.scan->end_state));
+                               syncbb_end_state(cmd->cmd.scan->end_state);
+                               scan_size = jtag_build_buffer(cmd->cmd.scan, 
&buffer);
+                               type = jtag_scan_type(cmd->cmd.scan);
+                               syncbb_scan(cmd->cmd.scan->ir_scan, type, 
buffer, scan_size);
+                               if (jtag_read_buffer(buffer, cmd->cmd.scan) != 
ERROR_OK)
+                                       retval = ERROR_JTAG_QUEUE_FAILED;
+                               if (buffer)
+                                       free(buffer);
+                               break;
+
+                       case JTAG_SLEEP:
+                               dirtyjtag_buffer_flush();
+                               jtag_sleep(cmd->cmd.sleep->us);
+                               break;
+
+                       case JTAG_TMS:
+                               retval = syncbb_execute_tms(cmd);
+                               break;
+                       default:
+                               LOG_ERROR("BUG: unknown JTAG command type 
encountered");
+                               exit(-1);
+               }
+               cmd = cmd->next;
+       }
+
+       dirtyjtag_buffer_flush();
+
+       return retval;
+}
+
+static struct jtag_interface dirtyjtag_interface = {
+       .supported = DEBUG_CAP_TMS_SEQ,
+       .execute_queue = syncbb_execute_queue,
+};
+
+struct adapter_driver dirtyjtag_adapter_driver = {
+       .name = "dirtyjtag",
+       .transports = jtag_only,
+       .commands = dirtyjtag_command_handlers,
+
+       .init = dirtyjtag_init,
+       .quit = dirtyjtag_quit,
+       .reset = dirtyjtag_reset,
+       .speed = dirtyjtag_speed,
+       .khz = dirtyjtag_khz,
+       .speed_div = dirtyjtag_speed_div,
+
+       .jtag_ops = &dirtyjtag_interface,
+};
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 67bbb3b366..38f30d2b74 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -145,6 +145,9 @@ extern struct adapter_driver rshim_dap_adapter_driver;
 #if BUILD_AM335XGPIO == 1
 extern struct adapter_driver am335xgpio_adapter_driver;
 #endif
+#if BUILD_DIRTYJTAG == 1
+extern struct adapter_driver dirtyjtag_adapter_driver;
+#endif
 
 /**
  * The list of built-in JTAG interfaces, containing entries for those
@@ -264,6 +267,9 @@ struct adapter_driver *adapter_drivers[] = {
 #endif
 #if BUILD_AM335XGPIO == 1
                &am335xgpio_adapter_driver,
+#endif
+#if BUILD_DIRTYJTAG == 1
+               &dirtyjtag_adapter_driver,
 #endif
                NULL,
        };
diff --git a/tcl/interface/dirtyjtag.cfg b/tcl/interface/dirtyjtag.cfg
new file mode 100644
index 0000000000..152cfe10c6
--- /dev/null
+++ b/tcl/interface/dirtyjtag.cfg
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# DirtyJTAG USB adapter
+#
+#
+#
+adapter driver dirtyjtag
+adapter speed 1000
\ No newline at end of file

-- 

Reply via email to