Adds support for buspirate jtag interface.

diff --git a/configure.in b/configure.in
index 3b0a06d..d93b21a 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 61e39b2..bcf06e7 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -386,6 +386,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}
 @end itemize
 
 @section IBM PC Parallel Printer Port Based
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index d6113c6..0588126 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 0000000..9b7d67e
--- /dev/null
+++ b/src/jtag/drivers/buspirate.c
@@ -0,0 +1,981 @@
+/***************************************************************************
+ *   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 = 0;
+static int buspirate_pullup = 0;
+static char* buspirate_port = NULL;
+
+
+/* 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 :(", 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)
+{
+	struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
+	int scan_size;
+	enum scan_type type;
+	uint8_t *buffer;
+
+	while (cmd)
+	{
+		switch (cmd->type)
+		{
+			case JTAG_RUNTEST:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state));
+#endif
+				buspirate_end_state(cmd->cmd.runtest->end_state);
+				buspirate_runtest(cmd->cmd.runtest->num_cycles);
+				break;
+			case JTAG_STATEMOVE:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state));
+#endif
+				buspirate_end_state(cmd->cmd.statemove->end_state);
+				buspirate_state_move();
+				break;
+			case JTAG_PATHMOVE:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states,
+					tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
+#endif
+				buspirate_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path);
+				break;
+			case JTAG_SCAN:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("scan end in %s", tap_state_name(cmd->cmd.scan->end_state));
+#endif
+
+				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:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+#endif
+				// 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:
+#ifdef _DEBUG_JTAG_IO_
+				LOG_DEBUG("sleep %i", cmd->cmd.sleep->us);
+#endif
+				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)
+{
+	buspirate_print_buffer("", 0);
+
+	if (buspirate_port == NULL) {
+		buspirate_port = "/dev/ttyUSB0";
+	}
+
+
+	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])
+		{
+			/* LOG_INFO("1"); */
+			buspirate_tap_append(0, 0);
+		}
+		else if (tap_state_transition(tap_get_state(), true) == path[i])
+		{
+			/* LOG_INFO("2"); */
+			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);
+	}
+
+#ifdef _DEBUG_JTAG_IO_
+	LOG_DEBUG("runtest: cur_state %s end_state %s", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()));
+#endif
+
+	/* 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();
+
+
+	/* The adapter does the transition to PAUSE internally */
+	if (ir_scan)
+		tap_set_state(TAP_IRPAUSE);
+	else
+		tap_set_state(TAP_DRPAUSE);
+
+	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 char tdo_chain[BUSPIRATE_BUFFER_SIZE]; // recv
+static int tap_chain_index;
+
+typedef struct // 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;
+} pending_scan_result_t;
+
+static pending_scan_result_t 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;
+	}
+#ifdef DEBUG_SERIAL
+fprintf(stderr,"bytes writen %i:\n", ret);
+buspirate_print_buffer(tmp, bytes_to_send*2+3);
+#endif
+
+	ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + 3);
+#ifdef DEBUG_SERIAL
+fprintf(stderr,"bytes read %i should have read %i:\n", ret, bytes_to_send + 3);
+buspirate_print_buffer(tmp, bytes_to_send+3);
+#endif
+	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;
+//LOG_INFO("Parsing scan result [%i] len = %i first = %i bytes:", i, length, first); 
+
+		/* copy bits from buffer */ 
+		buf_set_buf(in_buf, first, buffer, 0, length);
+//buspirate_print_buffer((char*)buffer, (length+7)/8);
+
+		/* return buffer to higher level */
+		if (jtag_read_buffer(buffer, command) != ERROR_OK)
+		{
+			buspirate_tap_init();
+			return ERROR_JTAG_QUEUE_FAILED;
+		}
+
+		if (buffer) {
+			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 = 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;
+//fprintf(stderr,"adding scan\n");
+	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;
+	
+	buspirate_serial_write(fd, tmp, 20);
+	usleep(10000);
+
+	// reads 1 to x "BBIO1" and one "OCD1"
+	while (!done)
+	{
+		ret = buspirate_serial_read(fd, tmp, 4);
+#ifdef DEBUG_SERIAL
+fprintf(stderr,"bytes read %i:\n", ret);
+buspirate_print_buffer(tmp, ret);
+#endif
+		if (ret != 4)
+		{
+			LOG_ERROR("Buspirate did not respond :(( restart everything");
+			exit(-1);
+		}
+		if (strncmp(tmp, "BBIO", 4)==0)
+		{
+			ret = buspirate_serial_read(fd, tmp, 1);
+#ifdef DEBUG_SERIAL
+fprintf(stderr,"bytes read %i:\n", ret);
+buspirate_print_buffer(tmp, ret);
+#endif
+			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);
+#ifdef DEBUG_SERIAL
+fprintf(stderr,"bytes written %i:\n", ret);
+#endif
+			}
+		} 
+		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);
+#ifdef DEBUG_SERIAL
+//LOG_INFO("jtag_message  %i",(int)cmd[0]);
+LOG_INFO("write cmd = %i bytes %i", cmd[0], res); 
+buspirate_print_buffer(cmd, cmdlen);
+#endif
+	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)
+	{
+	//	LOG_INFO("waiting jtag_message response %i",(int)msg[0]);
+		switch (cmd[0]) {
+			case CMD_READ_ADCS:
+				len = 10; // 2+2*4
+				break;
+			case CMD_TAP_SHIFT:
+				len = cmdlen;
+				break;
+			default:
+				LOG_INFO("Wrong !");
+		}
+		res =  buspirate_serial_read(buspirate_fd, cmd, len);
+#ifdef DEBUG_SERIAL
+LOG_INFO("read bytes  %i should have read  %i", res, len); 
+buspirate_print_buffer(cmd, len);
+#endif
+		if (res > 0)
+			return (unsigned char)cmd[1];
+		else
+			return -1;
+	}
+	else
+		return -1;
+	return 0;
+}
+
+/* low level serial port */
+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);
+
+	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) 
+				return len;
+
+			continue;
+		}
+		
+		len += ret;
+	}
+
+	return len;
+}
+
+static void buspirate_print_buffer(char* buf, int size) {
+	int i;
+
+	for (i = 0 ; i < size; i++) {
+		fprintf(stderr, "%02X ", ((unsigned char)buf[i]) & 0xff);
+	}
+	fprintf(stderr, "\n");
+}
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index f6d8219..8d13a08 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 0000000..6573c3d
--- /dev/null
+++ b/tcl/interface/buspirate.cfg
@@ -0,0 +1,16 @@
+#
+# Buspirate with OpenOCD support
+#
+# http://dangerousprototypes.com/category/bus-pirate/
+#
+
+interface buspirate
+buspirate_port /dev/ttyUSB0 # adjust to your needs
+buspirate_speed normal # or fast
+#buspirate_vreg 0 # or 1
+#buspirate_mode normal # or open-drain
+#buspirate_pullup 0 # or 1
+
+# this depends on the cable, you are safe with this option
+reset_config srst_only
+
