Add support for Bus Pirate as a JTAG adapter.
authorMichal Demin <michaldemin@gmail.com>
Mon, 8 Mar 2010 12:45:14 +0000 (13:45 +0100)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 11 Mar 2010 19:35:50 +0000 (11:35 -0800)
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>
NEWS
configure.in
doc/openocd.texi
src/jtag/drivers/Makefile.am
src/jtag/drivers/buspirate.c [new file with mode: 0644]
src/jtag/interfaces.c
tcl/interface/buspirate.cfg [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 4fef5b2..77435e1 100644 (file)
--- 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:
 
index 3b0a06d..d93b21a 100644 (file)
@@ -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)
index 33c442f..93757d4 100644 (file)
@@ -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
index d6113c6..0588126 100644 (file)
@@ -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 (file)
index 0000000..99210d2
--- /dev/null
@@ -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);
+       }
+}
+
index f6d8219..8d13a08 100644 (file)
@@ -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 (file)
index 0000000..9c7e0e7
--- /dev/null
@@ -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
+