summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Demin <michaldemin@gmail.com>2010-03-08 13:45:14 +0100
committerDavid Brownell <dbrownell@users.sourceforge.net>2010-03-11 11:35:50 -0800
commit24e1e3dd2699b817fa72a7843d36197abcd9e3a3 (patch)
tree47504221c471e548bb37db01b47058fb2f2083b2
parent591e0bbab957e86c8b2c6e19420a8cd9f89993cd (diff)
downloadopenocd+libswd-24e1e3dd2699b817fa72a7843d36197abcd9e3a3.tar.gz
openocd+libswd-24e1e3dd2699b817fa72a7843d36197abcd9e3a3.tar.bz2
openocd+libswd-24e1e3dd2699b817fa72a7843d36197abcd9e3a3.tar.xz
openocd+libswd-24e1e3dd2699b817fa72a7843d36197abcd9e3a3.zip
Add support for Bus Pirate as a JTAG adapter.
This includes a driver and matching config file. This support needs to be enabled through the initial "configure" (use "--enable-buspirate"). Signed-off-by: Michal Demin <michaldemin@gmail.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r--NEWS1
-rw-r--r--configure.in11
-rw-r--r--doc/openocd.texi3
-rw-r--r--src/jtag/drivers/Makefile.am3
-rw-r--r--src/jtag/drivers/buspirate.c969
-rw-r--r--src/jtag/interfaces.c6
-rw-r--r--tcl/interface/buspirate.cfg26
7 files changed, 1019 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 4fef5b2a..77435e12 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ history for details about what changed, including bugfixes
and other issues not mentioned here.
JTAG Layer:
+ New driver for "Bus Pirate"
Boundary Scan:
diff --git a/configure.in b/configure.in
index 3b0a06d3..d93b21ad 100644
--- a/configure.in
+++ b/configure.in
@@ -474,6 +474,10 @@ AC_ARG_ENABLE(arm-jtag-ew,
AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]),
[build_armjtagew=$enableval], [build_armjtagew=no])
+AC_ARG_ENABLE(buspirate,
+ AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]),
+ [build_buspirate=$enableval], [build_buspirate=no])
+
AC_ARG_ENABLE(minidriver_dummy,
AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]),
[build_minidriver_dummy=$enableval], [build_minidriver_dummy=no])
@@ -741,6 +745,12 @@ else
AC_DEFINE(BUILD_ARMJTAGEW, 0, [0 if you don't want the ARM-JTAG-EW JTAG driver.])
fi
+if test $build_buspirate = yes; then
+ AC_DEFINE(BUILD_BUSPIRATE, 1, [1 if you want the Buspirate JTAG driver.])
+else
+ AC_DEFINE(BUILD_BUSPIRATE, 0, [0 if you don't want the Buspirate JTAG driver.])
+fi
+
#-- Deal with MingW/Cygwin FTD2XX issues
if test $is_win32 = yes; then
@@ -1035,6 +1045,7 @@ AM_CONDITIONAL(JLINK, test $build_jlink = yes)
AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
+AM_CONDITIONAL(BUSPIRATE, test $build_buspirate = yes)
AM_CONDITIONAL(USB, test $build_usb = yes)
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 33c442f6..93757d48 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -432,6 +432,9 @@ Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form o
@item @b{ARM-JTAG-EW}
@* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html}
+
+@item @b{Buspirate}
+@* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/}
@end itemize
@section IBM PC Parallel Printer Port Based
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index d6113c60..05881265 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -64,6 +64,9 @@ endif
if ARMJTAGEW
DRIVERFILES += arm-jtag-ew.c
endif
+if BUSPIRATE
+DRIVERFILES += buspirate.c
+endif
noinst_HEADERS = \
bitbang.h \
diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c
new file mode 100644
index 00000000..99210d26
--- /dev/null
+++ b/src/jtag/drivers/buspirate.c
@@ -0,0 +1,969 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Michal Demin *
+ * based on usbprog.c and arm-jtag-ew.c *
+ * *
+ * 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/interface.h>
+#include <jtag/commands.h>
+
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#undef DEBUG_SERIAL
+/*#define DEBUG_SERIAL */
+static int buspirate_execute_queue(void);
+static int buspirate_speed(int speed);
+static int buspirate_khz(int khz, int *jtag_speed);
+static int buspirate_init(void);
+static int buspirate_quit(void);
+
+static void buspirate_end_state(tap_state_t state);
+static void buspirate_state_move(void);
+static void buspirate_path_move(int num_states, tap_state_t *path);
+static void buspirate_runtest(int num_cycles);
+static void buspirate_scan(bool ir_scan, enum scan_type type,
+ uint8_t *buffer, int scan_size, struct scan_command *command);
+
+
+#define CMD_UNKOWN 0x00
+#define CMD_PORT_MODE 0x01
+#define CMD_FEATURE 0x02
+#define CMD_READ_ADCS 0x03
+/*#define CMD_TAP_SHIFT 0x04 // old protocol */
+#define CMD_TAP_SHIFT 0x05
+#define CMD_ENTER_OOCD 0x06
+#define CMD_UART_SPEED 0x07
+#define CMD_JTAG_SPEED 0x08
+
+enum {
+ MODE_HIZ = 0,
+ MODE_JTAG = 1, /* push-pull outputs */
+ MODE_JTAG_OD = 2, /* open-drain outputs */
+};
+
+enum {
+ FEATURE_LED = 0x01,
+ FEATURE_VREG = 0x02,
+ FEATURE_TRST = 0x04,
+ FEATURE_SRST = 0x08,
+ FEATURE_PULLUP = 0x10
+};
+
+enum {
+ ACTION_DISABLE = 0,
+ ACTION_ENABLE = 1
+};
+
+enum {
+ SERIAL_NORMAL = 0,
+ SERIAL_FAST = 1
+};
+
+
+static int buspirate_fd = -1;
+static int buspirate_pinmode = MODE_JTAG_OD;
+static int buspirate_baudrate = SERIAL_NORMAL;
+static int buspirate_vreg;
+static int buspirate_pullup;
+static char *buspirate_port;
+
+
+/* TAP interface */
+static void buspirate_tap_init(void);
+static int buspirate_tap_execute(void);
+static void buspirate_tap_append(int tms, int tdi);
+static void buspirate_tap_append_scan(int length, uint8_t *buffer,
+ struct scan_command *command);
+static void buspirate_tap_make_space(int scan, int bits);
+
+static void buspirate_reset(int trst, int srst);
+
+/* low level interface */
+static void buspirate_jtag_reset(int);
+static void buspirate_jtag_enable(int);
+static unsigned char buspirate_jtag_command(int, char *, int);
+static void buspirate_jtag_set_speed(int, char);
+static void buspirate_jtag_set_mode(int, char);
+static void buspirate_jtag_set_feature(int, char, char);
+static void buspirate_jtag_get_adcs(int);
+
+/* low level HW communication interface */
+static int buspirate_serial_setspeed(int fd, speed_t speed);
+static int buspirate_serial_write(int fd, char *buf, int size);
+static int buspirate_serial_read(int fd, char *buf, int size);
+static void buspirate_print_buffer(char *buf, int size);
+
+static int buspirate_speed(int speed)
+{
+ /* TODO */
+ LOG_INFO("Want to set speed to %dkHz, but not implemented yet", speed);
+ return ERROR_OK;
+}
+
+static int buspirate_khz(int khz, int *jtag_speed)
+{
+ *jtag_speed = khz;
+ return ERROR_OK;
+}
+
+static int buspirate_execute_queue(void)
+{
+ /* currently processed command */
+ struct jtag_command *cmd = jtag_command_queue;
+ int scan_size;
+ enum scan_type type;
+ uint8_t *buffer;
+
+ while (cmd) {
+ switch (cmd->type) {
+ case JTAG_RUNTEST:
+ DEBUG_JTAG_IO("runtest %i cycles, end in %s",
+ cmd->cmd.runtest->num_cycles,
+ tap_state_name(cmd->cmd.runtest
+ ->end_state));
+ buspirate_end_state(cmd->cmd.runtest
+ ->end_state);
+ buspirate_runtest(cmd->cmd.runtest
+ ->num_cycles);
+ break;
+ case JTAG_STATEMOVE:
+ DEBUG_JTAG_IO("statemove end in %s",
+ tap_state_name(cmd->cmd.statemove
+ ->end_state));
+ buspirate_end_state(cmd->cmd.statemove
+ ->end_state);
+ buspirate_state_move();
+ break;
+ case JTAG_PATHMOVE:
+ DEBUG_JTAG_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]));
+ buspirate_path_move(cmd->cmd.pathmove
+ ->num_states,
+ cmd->cmd.pathmove->path);
+ break;
+ case JTAG_SCAN:
+ DEBUG_JTAG_IO("scan end in %s",
+ tap_state_name(cmd->cmd.scan
+ ->end_state));
+
+ buspirate_end_state(cmd->cmd.scan
+ ->end_state);
+
+ scan_size = jtag_build_buffer(cmd->cmd.scan,
+ &buffer);
+ type = jtag_scan_type(cmd->cmd.scan);
+ buspirate_scan(cmd->cmd.scan->ir_scan, type,
+ buffer, scan_size, cmd->cmd.scan);
+
+ break;
+ case JTAG_RESET:
+ DEBUG_JTAG_IO("reset trst: %i srst %i",
+ cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+
+ /* flush buffers, so we can reset */
+ buspirate_tap_execute();
+
+ if (cmd->cmd.reset->trst == 1)
+ tap_set_state(TAP_RESET);
+ buspirate_reset(cmd->cmd.reset->trst,
+ cmd->cmd.reset->srst);
+ break;
+ case JTAG_SLEEP:
+ DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us);
+ buspirate_tap_execute();
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ LOG_ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+
+ cmd = cmd->next;
+ }
+
+ return buspirate_tap_execute();
+}
+
+static int buspirate_init(void)
+{
+ if (buspirate_port == NULL) {
+ LOG_ERROR("You need to specify port !");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ buspirate_fd = open(buspirate_port, O_RDWR | O_NOCTTY);
+ if (buspirate_fd == -1) {
+ LOG_ERROR("Could not open serial port.");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ buspirate_serial_setspeed(buspirate_fd, B115200);
+
+ buspirate_jtag_enable(buspirate_fd);
+
+ if (buspirate_baudrate != SERIAL_NORMAL)
+ buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST);
+
+ LOG_INFO("Buspirate Interface ready!");
+
+ buspirate_tap_init();
+ buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode);
+ buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG,
+ (buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE);
+ buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP,
+ (buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE);
+ buspirate_reset(0, 0);
+
+ return ERROR_OK;
+}
+
+static int buspirate_quit(void)
+{
+ LOG_INFO("Shuting down buspirate ");
+ buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ);
+
+ buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL);
+ buspirate_jtag_reset(buspirate_fd);
+ if (buspirate_port) {
+ free(buspirate_port);
+ buspirate_port = NULL;
+ }
+ return ERROR_OK;
+}
+
+/* openocd command interface */
+COMMAND_HANDLER(buspirate_handle_adc_command)
+{
+ if (CMD_ARGC != 0) {
+ LOG_ERROR("usage: buspirate_adc");
+ return ERROR_OK;
+ }
+
+ if (buspirate_fd == -1)
+ return ERROR_OK;
+
+ /* send the command */
+ buspirate_jtag_get_adcs(buspirate_fd);
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_vreg_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_vreg <1|0>");
+ return ERROR_OK;
+ }
+
+ if (atoi(CMD_ARGV[0]) == 1)
+ buspirate_vreg = 1;
+ else
+ buspirate_vreg = 0;
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_pullup_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_pullup <1|0>");
+ return ERROR_OK;
+ }
+
+ if (atoi(CMD_ARGV[0]) == 1)
+ buspirate_pullup = 1;
+ else
+ buspirate_pullup = 0;
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_led_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_led <1|0>");
+ return ERROR_OK;
+ }
+
+ if (atoi(CMD_ARGV[0]) == 1) {
+ /* enable led */
+ buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED,
+ ACTION_ENABLE);
+ } else {
+ /* disable led */
+ buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED,
+ ACTION_DISABLE);
+ }
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_mode_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_mode <normal|open-drain>");
+ return ERROR_OK;
+ }
+
+ if (CMD_ARGV[0][0] == 'n')
+ buspirate_pinmode = MODE_JTAG;
+ else if (CMD_ARGV[0][0] == 'o')
+ buspirate_pinmode = MODE_JTAG_OD;
+ else
+ LOG_ERROR("usage: buspirate_mode <normal|open-drain>");
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_speed_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_speed <normal|fast>");
+ return ERROR_OK;
+ }
+
+ if (CMD_ARGV[0][0] == 'n')
+ buspirate_baudrate = SERIAL_NORMAL;
+ else if (CMD_ARGV[0][0] == 'f')
+ buspirate_baudrate = SERIAL_FAST;
+ else
+ LOG_ERROR("usage: buspirate_speed <normal|fast>");
+
+ return ERROR_OK;
+
+}
+
+COMMAND_HANDLER(buspirate_handle_port_command)
+{
+ if (CMD_ARGC != 1) {
+ LOG_ERROR("usage: buspirate_port /dev/ttyUSB0");
+ return ERROR_OK;
+ }
+
+ if (buspirate_port == 0)
+ buspirate_port = strdup(CMD_ARGV[0]);
+
+ return ERROR_OK;
+
+}
+
+static const struct command_registration buspirate_command_handlers[] = {
+ {
+ .name = "buspirate_adc",
+ .handler = &buspirate_handle_adc_command,
+ .mode = COMMAND_EXEC,
+ .help = "reads voltages on adc pins",
+ },
+ {
+ .name = "buspirate_vreg",
+ .handler = &buspirate_handle_vreg_command,
+ .mode = COMMAND_CONFIG,
+ .help = "changes the state of voltage regulators",
+ },
+ {
+ .name = "buspirate_pullup",
+ .handler = &buspirate_handle_pullup_command,
+ .mode = COMMAND_CONFIG,
+ .help = "changes the state of pullup",
+ },
+ {
+ .name = "buspirate_led",
+ .handler = &buspirate_handle_led_command,
+ .mode = COMMAND_EXEC,
+ .help = "changes the state of led",
+ },
+ {
+ .name = "buspirate_speed",
+ .handler = &buspirate_handle_speed_command,
+ .mode = COMMAND_CONFIG,
+ .help = "speed of the interface",
+ },
+ {
+ .name = "buspirate_mode",
+ .handler = &buspirate_handle_mode_command,
+ .mode = COMMAND_CONFIG,
+ .help = "pin mode of the interface",
+ },
+ {
+ .name = "buspirate_port",
+ .handler = &buspirate_handle_port_command,
+ .mode = COMMAND_CONFIG,
+ .help = "name of the serial port to open",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct jtag_interface buspirate_interface = {
+ .name = "buspirate",
+ .execute_queue = buspirate_execute_queue,
+ .speed = buspirate_speed,
+ .khz = buspirate_khz,
+ .commands = buspirate_command_handlers,
+ .init = buspirate_init,
+ .quit = buspirate_quit
+};
+
+/*************** jtag execute commands **********************/
+static void buspirate_end_state(tap_state_t state)
+{
+ if (tap_is_state_stable(state))
+ tap_set_end_state(state);
+ else {
+ LOG_ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+static void buspirate_state_move(void)
+{
+ 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 = 0; i < tms_count; i++) {
+ tms = (tms_scan >> i) & 1;
+ buspirate_tap_append(tms, 0);
+ }
+
+ tap_set_state(tap_get_end_state());
+}
+
+static void buspirate_path_move(int num_states, tap_state_t *path)
+{
+ int i;
+
+ for (i = 0; i < num_states; i++) {
+ if (tap_state_transition(tap_get_state(), false) == path[i]) {
+ buspirate_tap_append(0, 0);
+ } else if (tap_state_transition(tap_get_state(), true)
+ == path[i]) {
+ buspirate_tap_append(1, 0);
+ } else {
+ LOG_ERROR("BUG: %s -> %s isn't a valid "
+ "TAP transition",
+ tap_state_name(tap_get_state()),
+ tap_state_name(path[i]));
+ exit(-1);
+ }
+
+ tap_set_state(path[i]);
+ }
+
+ tap_set_end_state(tap_get_state());
+}
+
+static void buspirate_runtest(int num_cycles)
+{
+ int i;
+
+ 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) {
+ buspirate_end_state(TAP_IDLE);
+ buspirate_state_move();
+ }
+
+ for (i = 0; i < num_cycles; i++)
+ buspirate_tap_append(0, 0);
+
+ DEBUG_JTAG_IO("runtest: cur_state %s end_state %s",
+ tap_state_name(tap_get_state()),
+ tap_state_name(tap_get_end_state()));
+
+ /* finish in end_state */
+ buspirate_end_state(saved_end_state);
+ if (tap_get_state() != tap_get_end_state())
+ buspirate_state_move();
+}
+
+static void buspirate_scan(bool ir_scan, enum scan_type type,
+ uint8_t *buffer, int scan_size, struct scan_command *command)
+{
+ tap_state_t saved_end_state;
+
+ buspirate_tap_make_space(1, scan_size+8);
+ /* is 8 correct ? (2 moves = 16) */
+
+ saved_end_state = tap_get_end_state();
+
+ buspirate_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
+ buspirate_state_move();
+
+ buspirate_tap_append_scan(scan_size, buffer, command);
+
+ /* move to PAUSE */
+ buspirate_tap_append(0, 0);
+
+ /* restore the saved state */
+ buspirate_end_state(saved_end_state);
+ tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
+
+ if (tap_get_state() != tap_get_end_state())
+ buspirate_state_move();
+}
+
+
+/************************* TAP related stuff **********/
+
+#define BUSPIRATE_BUFFER_SIZE 1024
+#define BUSPIRATE_MAX_PENDING_SCANS 32
+
+static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
+static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
+static int tap_chain_index;
+
+struct pending_scan_result /* this was stolen from arm-jtag-ew */
+{
+ int first; /* First bit position in tdo_buffer to read */
+ int length; /* Number of bits to read */
+ struct scan_command *command; /* Corresponding scan command */
+ uint8_t *buffer;
+};
+
+static struct pending_scan_result
+tap_pending_scans[BUSPIRATE_MAX_PENDING_SCANS];
+static int tap_pending_scans_num;
+
+static void buspirate_tap_init(void)
+{
+ tap_chain_index = 0;
+ tap_pending_scans_num = 0;
+}
+
+static int buspirate_tap_execute(void)
+{
+ char tmp[4096];
+ uint8_t *in_buf;
+ int i;
+ int fill_index = 0;
+ int ret;
+ int bytes_to_send;
+
+ if (tap_chain_index <= 0)
+ return ERROR_OK;
+
+ LOG_DEBUG("executing tap num bits = %i scans = %i",
+ tap_chain_index, tap_pending_scans_num);
+
+ bytes_to_send = (tap_chain_index+7) / 8;
+
+ tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */
+ tmp[1] = (char)(tap_chain_index >> 8); /* high */
+ tmp[2] = (char)(tap_chain_index); /* low */
+
+ fill_index = 3;
+ for (i = 0; i < bytes_to_send; i++) {
+ tmp[fill_index] = tdi_chain[i];
+ fill_index++;
+ tmp[fill_index] = tms_chain[i];
+ fill_index++;
+ }
+
+ ret = buspirate_serial_write(buspirate_fd, tmp, 3 + bytes_to_send*2);
+ if (ret != bytes_to_send*2+3) {
+ LOG_ERROR("error writing :(");
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+
+ ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + 3);
+ in_buf = (uint8_t *)(&tmp[3]);
+
+ /* parse the scans */
+ for (i = 0; i < tap_pending_scans_num; i++) {
+ uint8_t *buffer = tap_pending_scans[i].buffer;
+ int length = tap_pending_scans[i].length;
+ int first = tap_pending_scans[i].first;
+ struct scan_command *command = tap_pending_scans[i].command;
+
+ /* copy bits from buffer */
+ buf_set_buf(in_buf, first, buffer, 0, length);
+
+ /* return buffer to higher level */
+ if (jtag_read_buffer(buffer, command) != ERROR_OK) {
+ buspirate_tap_init();
+ return ERROR_JTAG_QUEUE_FAILED;
+ }
+
+ free(buffer);
+ }
+ tap_pending_scans_num = 0;
+ tap_chain_index = 0;
+ return ERROR_OK;
+}
+
+static void buspirate_tap_make_space(int scans, int bits)
+{
+ int have_scans = BUSPIRATE_MAX_PENDING_SCANS - tap_pending_scans_num;
+ int have_bits = BUSPIRATE_BUFFER_SIZE * 8 - tap_chain_index;
+
+ if ((have_scans < scans) || (have_bits < bits))
+ buspirate_tap_execute();
+}
+
+static void buspirate_tap_append(int tms, int tdi)
+{
+ int index;
+
+ buspirate_tap_make_space(0, 1);
+ index = tap_chain_index / 8;
+
+ if (index < BUSPIRATE_BUFFER_SIZE) {
+ int bit_index = tap_chain_index % 8;
+ uint8_t bit = 1 << bit_index;
+
+ if (tms)
+ tms_chain[index] |= bit;
+ else
+ tms_chain[index] &= ~bit;
+
+ if (tdi)
+ tdi_chain[index] |= bit;
+ else
+ tdi_chain[index] &= ~bit;
+
+ tap_chain_index++;
+ } else
+ LOG_ERROR("tap_chain overflow, Bad things will happen");
+
+}
+
+static void buspirate_tap_append_scan(int length, uint8_t *buffer,
+ struct scan_command *command)
+{
+ int i;
+ tap_pending_scans[tap_pending_scans_num].length = length;
+ tap_pending_scans[tap_pending_scans_num].buffer = buffer;
+ tap_pending_scans[tap_pending_scans_num].command = command;
+ tap_pending_scans[tap_pending_scans_num].first = tap_chain_index;
+
+ for (i = 0; i < length; i++) {
+ int tms = (i < length-1 ? 0 : 1);
+ int tdi = (buffer[i/8] >> (i%8)) & 1;
+ buspirate_tap_append(tms, tdi);
+ }
+ tap_pending_scans_num++;
+}
+
+/*************** jtag wrapper functions *********************/
+
+/* (1) assert or (0) deassert reset lines */
+static void buspirate_reset(int trst, int srst)
+{
+ LOG_DEBUG("trst: %i, srst: %i", trst, srst);
+
+ if (trst)
+ buspirate_jtag_set_feature(buspirate_fd,
+ FEATURE_TRST, ACTION_DISABLE);
+ else
+ buspirate_jtag_set_feature(buspirate_fd,
+ FEATURE_TRST, ACTION_ENABLE);
+
+ if (srst)
+ buspirate_jtag_set_feature(buspirate_fd,
+ FEATURE_SRST, ACTION_DISABLE);
+ else
+ buspirate_jtag_set_feature(buspirate_fd,
+ FEATURE_SRST, ACTION_ENABLE);
+}
+
+/*************** jtag lowlevel functions ********************/
+static void buspirate_jtag_enable(int fd)
+{
+ int ret;
+ char tmp[21] = { [0 ... 20] = 0x00 };
+ int done = 0;
+ int cmd_sent = 0;
+
+ LOG_DEBUG("Entering binary mode");
+ buspirate_serial_write(fd, tmp, 20);
+ usleep(10000);
+
+ /* reads 1 to n "BBIO1"s and one "OCD1" */
+ while (!done) {
+ ret = buspirate_serial_read(fd, tmp, 4);
+ if (ret != 4) {
+ LOG_ERROR("Buspirate did not respond :"
+ "( restart everything");
+ exit(-1);
+ }
+ LOG_DEBUG("TUI");
+ if (strncmp(tmp, "BBIO", 4) == 0) {
+ ret = buspirate_serial_read(fd, tmp, 1);
+ if (ret != 1) {
+ LOG_ERROR("Buspirate did not respond well :"
+ "( restart everything");
+ exit(-1);
+ }
+ if (tmp[0] != '1') {
+ LOG_ERROR("Unsupported binary protocol ");
+ exit(-1);
+ }
+ if (cmd_sent == 0) {
+ cmd_sent = 1;
+ tmp[0] = CMD_ENTER_OOCD;
+ ret = buspirate_serial_write(fd, tmp, 1);
+ }
+ } else if (strncmp(tmp, "OCD1", 4) == 0)
+ done = 1;
+ else {
+ LOG_ERROR("Buspirate did not respond :"
+ "( restart everything");
+ exit(-1);
+ }
+ }
+
+}
+
+static void buspirate_jtag_reset(int fd)
+{
+ int ret;
+ char tmp[5];
+
+ tmp[0] = 0x00; /* exit OCD1 mode */
+ buspirate_serial_write(fd, tmp, 1);
+ usleep(10000);
+ ret = buspirate_serial_read(fd, tmp, 5);
+ if (strncmp(tmp, "BBIO1", 5) == 0) {
+ tmp[0] = 0x0F; /* reset BP */
+ buspirate_serial_write(fd, tmp, 1);
+ } else
+ LOG_ERROR("Bad reply :( Please restart manually");
+}
+
+static void buspirate_jtag_set_speed(int fd, char speed)
+{
+ int ret;
+ char tmp[2];
+ char ack[2];
+ speed_t baudrate = B115200;
+
+ ack[0] = 0xAA;
+ ack[1] = 0x55;
+
+ tmp[0] = CMD_UART_SPEED;
+ tmp[1] = speed;
+ buspirate_jtag_command(fd, tmp, 2);
+
+ /* here the adapter changes speed, we need follow */
+ if (speed == SERIAL_FAST)
+ baudrate = B1000000;
+
+ buspirate_serial_setspeed(fd, baudrate);
+
+ buspirate_serial_write(fd, ack, 2);
+ ret = buspirate_serial_read(fd, tmp, 2);
+ if (ret != 2) {
+ LOG_ERROR("Buspirate did not respond :"
+ "( restart everything");
+ exit(-1);
+ }
+ if ((tmp[0] != CMD_UART_SPEED) || (tmp[1] != speed)) {
+ LOG_ERROR("Buspirate didn't reply as expected :"
+ "( restart everything");
+ exit(-1);
+ }
+ LOG_INFO("Buspirate switched to %s mode",
+ (speed == SERIAL_NORMAL) ? "normal" : "FAST");
+}
+
+
+static void buspirate_jtag_set_mode(int fd, char mode)
+{
+ char tmp[2];
+ tmp[0] = CMD_PORT_MODE;
+ tmp[1] = mode;
+ buspirate_jtag_command(fd, tmp, 2);
+}
+
+static void buspirate_jtag_set_feature(int fd, char feat, char action)
+{
+ char tmp[3];
+ tmp[0] = CMD_FEATURE;
+ tmp[1] = feat; /* what */
+ tmp[2] = action; /* action */
+ buspirate_jtag_command(fd, tmp, 3);
+}
+
+static void buspirate_jtag_get_adcs(int fd)
+{
+ uint8_t tmp[10];
+ uint16_t a, b, c, d;
+ tmp[0] = CMD_READ_ADCS;
+ buspirate_jtag_command(fd, (char *)tmp, 1);
+ a = tmp[2] << 8 | tmp[3];
+ b = tmp[4] << 8 | tmp[5];
+ c = tmp[6] << 8 | tmp[7];
+ d = tmp[8] << 8 | tmp[9];
+
+ LOG_INFO("ADC: ADC_Pin = %.02f VPullup = %.02f V33 = %.02f "
+ "V50 = %.02f",
+ ((float)a)/155.1515, ((float)b)/155.1515,
+ ((float)c)/155.1515, ((float)d)/155.1515);
+}
+
+static unsigned char buspirate_jtag_command(int buspirate_fd,
+ char *cmd, int cmdlen)
+{
+ int res;
+ int len = 0;
+
+ res = buspirate_serial_write(buspirate_fd, cmd, cmdlen);
+
+ if ((cmd[0] == CMD_UART_SPEED)
+ || (cmd[0] == CMD_PORT_MODE)
+ || (cmd[0] == CMD_FEATURE)
+ || (cmd[0] == CMD_JTAG_SPEED))
+ return 1;
+
+ if (res == cmdlen) {
+ switch (cmd[0]) {
+ case CMD_READ_ADCS:
+ len = 10; /* 2*sizeof(char)+4*sizeof(uint16_t) */
+ break;
+ case CMD_TAP_SHIFT:
+ len = cmdlen;
+ break;
+ default:
+ LOG_INFO("Wrong !");
+ }
+ res = buspirate_serial_read(buspirate_fd, cmd, len);
+ if (res > 0)
+ return (unsigned char)cmd[1];
+ else
+ return -1;
+ } else
+ return -1;
+ return 0;
+}
+
+/* low level serial port */
+/* TODO add support for WIN32 and others ! */
+static int buspirate_serial_setspeed(int fd, speed_t speed)
+{
+ struct termios t_opt;
+
+ /* set the serial port parameters */
+ fcntl(buspirate_fd, F_SETFL, 0);
+ tcgetattr(buspirate_fd, &t_opt);
+ cfsetispeed(&t_opt, speed);
+ cfsetospeed(&t_opt, speed);
+ t_opt.c_cflag |= (CLOCAL | CREAD);
+ t_opt.c_cflag &= ~PARENB;
+ t_opt.c_cflag &= ~CSTOPB;
+ t_opt.c_cflag &= ~CSIZE;
+ t_opt.c_cflag |= CS8;
+ t_opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ t_opt.c_iflag &= ~(IXON | IXOFF | IXANY);
+ t_opt.c_oflag &= ~OPOST;
+ t_opt.c_cc[VMIN] = 0;
+ t_opt.c_cc[VTIME] = 10;
+ tcflush(buspirate_fd, TCIFLUSH);
+ tcsetattr(buspirate_fd, TCSANOW, &t_opt);
+
+ return 0;
+}
+
+static int buspirate_serial_write(int fd, char *buf, int size)
+{
+ int ret = 0;
+
+ ret = write(fd, buf, size);
+
+ LOG_DEBUG("size = %d ret = %d", size, ret);
+ buspirate_print_buffer(buf, size);
+
+ if (ret != size)
+ LOG_ERROR("Error sending data");
+
+ return ret;
+}
+
+static int buspirate_serial_read(int fd, char *buf, int size)
+{
+ int len = 0;
+ int ret = 0;
+ int timeout = 0;
+
+ while (len < size) {
+ ret = read(fd, buf+len, size-len);
+ if (ret == -1)
+ return -1;
+
+ if (ret == 0) {
+ timeout++;
+
+ if (timeout >= 10)
+ break;
+
+ continue;
+ }
+
+ len += ret;
+ }
+
+ LOG_DEBUG("should have read = %d actual size = %d", size, len);
+ buspirate_print_buffer(buf, len);
+
+ if (len != size)
+ LOG_ERROR("Error sending data");
+
+ return len;
+}
+
+#define LINE_SIZE 81
+#define BYTES_PER_LINE 16
+static void buspirate_print_buffer(char *buf, int size)
+{
+ char line[LINE_SIZE];
+ char tmp[10];
+ int offset = 0;
+
+ line[0] = 0;
+ while (offset < size) {
+ snprintf(tmp, 5, "%02x ", (uint8_t)buf[offset]);
+ offset++;
+
+ strcat(line, tmp);
+
+ if (offset % BYTES_PER_LINE == 0) {
+ LOG_DEBUG("%s", line);
+ line[0] = 0;
+ }
+ }
+
+ if (line[0] != 0) {
+ LOG_DEBUG("%s", line);
+ }
+}
+
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index f6d82195..8d13a086 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -91,6 +91,9 @@ extern struct jtag_interface rlink_interface;
#if BUILD_ARMJTAGEW == 1
extern struct jtag_interface armjtagew_interface;
#endif
+#if BUILD_BUSPIRATE == 1
+extern struct jtag_interface buspirate_interface;
+#endif
#endif // standard drivers
/**
@@ -151,6 +154,9 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_ARMJTAGEW == 1
&armjtagew_interface,
#endif
+#if BUILD_BUSPIRATE == 1
+ &buspirate_interface,
+#endif
#endif // standard drivers
NULL,
};
diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg
new file mode 100644
index 00000000..9c7e0e70
--- /dev/null
+++ b/tcl/interface/buspirate.cfg
@@ -0,0 +1,26 @@
+#
+# Buspirate with OpenOCD support
+#
+# http://dangerousprototypes.com/bus-pirate-manual/
+#
+
+interface buspirate
+
+# you need to specify port on which BP lives
+#buspirate_port /dev/ttyUSB0
+
+# communication speed setting
+buspirate_speed normal # or fast
+
+# voltage regulator Enabled = 1 Disabled = 0
+#buspirate_vreg 0
+
+# pin mode normal or open-drain
+#buspirate_mode normal
+
+# pullup state Enabled = 1 Disabled = 0
+#buspirate_pullup 0
+
+# this depends on the cable, you are safe with this option
+reset_config srst_only
+