summaryrefslogtreecommitdiff
path: root/src/jtag
diff options
context:
space:
mode:
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2006-06-02 10:36:31 +0000
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2006-06-02 10:36:31 +0000
commit8b4e882a1630d63bbc9840fa3f968e36b6ac3702 (patch)
treee8f8ab1ba76fc7bef013fed6e5fea28e1cb7a554 /src/jtag
downloadopenocd+libswd-8b4e882a1630d63bbc9840fa3f968e36b6ac3702.tar.gz
openocd+libswd-8b4e882a1630d63bbc9840fa3f968e36b6ac3702.tar.bz2
openocd+libswd-8b4e882a1630d63bbc9840fa3f968e36b6ac3702.tar.xz
openocd+libswd-8b4e882a1630d63bbc9840fa3f968e36b6ac3702.zip
- prepare OpenOCD for branching, created ./trunk/
git-svn-id: svn://svn.berlios.de/openocd/trunk@64 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src/jtag')
-rw-r--r--src/jtag/Makefile.am50
-rw-r--r--src/jtag/amt_jtagaccel.c510
-rw-r--r--src/jtag/bitbang.c219
-rw-r--r--src/jtag/bitbang.h36
-rw-r--r--src/jtag/ep93xx.c236
-rw-r--r--src/jtag/ftd2xx.c1004
-rw-r--r--src/jtag/ftdi2232.c630
-rw-r--r--src/jtag/jtag.c1585
-rw-r--r--src/jtag/jtag.h270
-rw-r--r--src/jtag/parport.c351
10 files changed, 4891 insertions, 0 deletions
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
new file mode 100644
index 00000000..a3a06606
--- /dev/null
+++ b/src/jtag/Makefile.am
@@ -0,0 +1,50 @@
+
+if FTD2XXDIR
+FTD2XXINC = -I@WITH_FTD2XX@/
+else
+FTD2XXINC =
+endif
+
+INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libjtag.a
+
+if BITBANG
+BITBANGFILES = bitbang.c
+else
+BITBANGFILES =
+endif
+
+if PARPORT
+PARPORTFILES = parport.c
+else
+PARPORTFILES =
+endif
+
+if FTDI2232
+FTDI2232FILES = ftdi2232.c
+else
+FTDI2232FILES =
+endif
+
+if FTD2XX
+FTD2XXFILES = ftd2xx.c
+else
+FTD2XXFILES =
+endif
+
+if AMTJTAGACCEL
+AMTJTAGACCELFILES = amt_jtagaccel.c
+else
+AMTJTAGACCELFILES =
+endif
+
+if EP93XX
+EP93XXFILES = ep93xx.c
+else
+EP93XXFILES =
+endif
+
+libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(FTDI2232FILES) $(FTD2XXFILES) $(AMTJTAGACCELFILES) $(EP93XXFILES)
+
+noinst_HEADERS = bitbang.h jtag.h
diff --git a/src/jtag/amt_jtagaccel.c b/src/jtag/amt_jtagaccel.c
new file mode 100644
index 00000000..42f8bc36
--- /dev/null
+++ b/src/jtag/amt_jtagaccel.c
@@ -0,0 +1,510 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "config.h"
+#include "log.h"
+#include "jtag.h"
+
+/* system includes */
+#include <sys/io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+#if PARPORT_USE_PPDEV == 1
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#endif
+
+/* configuration */
+unsigned long amt_jtagaccel_port;
+
+/* interface variables
+ */
+static u8 aw_control_rst = 0x00;
+static u8 aw_control_fsm = 0x10;
+static u8 aw_control_baudrate = 0x20;
+
+static int rtck_enabled = 0;
+
+#if PARPORT_USE_PPDEV == 1
+static int device_handle;
+int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR ;
+int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA ;
+#define AMT_AW(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); write(device_handle, &val, 1); } while (0)
+#define AMT_AR(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); read(device_handle, &val, 1); } while (0)
+#define AMT_DW(val) do { ioctl(device_handle, PPSETMODE, &data_mode); write(device_handle, &val, 1); } while (0)
+#define AMT_DR(val) do { ioctl(device_handle, PPSETMODE, &data_mode); read(device_handle, &val, 1); } while (0)
+#else
+#define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0)
+#define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0)
+#define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0)
+#define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0)
+#endif
+
+int amt_jtagaccel_execute_queue(void);
+int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx);
+int amt_jtagaccel_speed(int speed);
+int amt_jtagaccel_init(void);
+int amt_jtagaccel_quit(void);
+
+int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* tap_move[i][j]: tap movement command to go from state i to state j
+ * 0: Test-Logic-Reset
+ * 1: Run-Test/Idle
+ * 2: Shift-DR
+ * 3: Pause-DR
+ * 4: Shift-IR
+ * 5: Pause-IR
+ */
+u8 amt_jtagaccel_tap_move[6][6][2] =
+{
+ /* TLR RTI SD PD SI PI */
+ {{0x1f, 0x00}, {0x0f, 0x00}, {0x8a, 0x04}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00}}, /* TLR */
+ {{0x1f, 0x00}, {0x00, 0x00}, {0x85, 0x08}, {0x05, 0x00}, {0x8b, 0x08}, {0x0b, 0x00}}, /* RTI */
+ {{0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* SD */
+ {{0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* PD */
+ {{0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00}}, /* SI */
+ {{0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00}}, /* PI */
+};
+
+jtag_interface_t amt_jtagaccel_interface =
+{
+ .name = "amt_jtagaccel",
+
+ .execute_queue = amt_jtagaccel_execute_queue,
+
+ .support_statemove = 0,
+
+ .speed = amt_jtagaccel_speed,
+ .register_commands = amt_jtagaccel_register_commands,
+ .init = amt_jtagaccel_init,
+ .quit = amt_jtagaccel_quit,
+};
+
+int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "parport_port", amt_jtagaccel_handle_parport_port_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "rtck", amt_jtagaccel_handle_rtck_command,
+ COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+void amt_jtagaccel_reset(int trst, int srst)
+{
+ if (trst == 1)
+ aw_control_rst |= 0x4;
+ else if (trst == 0)
+ aw_control_rst &= ~0x4;
+
+ if (srst == 1)
+ aw_control_rst |= 0x1;
+ else if (srst == 0)
+ aw_control_rst &= ~0x1;
+
+ AMT_AW(aw_control_rst);
+}
+
+int amt_jtagaccel_speed(int speed)
+{
+ aw_control_baudrate &= 0xf0;
+ aw_control_baudrate |= speed & 0x0f;
+ AMT_AW(aw_control_baudrate);
+
+ return ERROR_OK;
+}
+
+void amt_jtagaccel_end_state(state)
+{
+ if (tap_move_map[state] != -1)
+ end_state = state;
+ else
+ {
+ ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+void amt_wait_scan_busy()
+{
+ int timeout = 4096;
+ u8 ar_status;
+
+ AMT_AR(ar_status);
+ while (((ar_status) & 0x80) && (timeout-- > 0))
+ AMT_AR(ar_status);
+
+ if (ar_status & 0x80)
+ {
+ ERROR("amt_jtagaccel timed out while waiting for end of scan, rtck was %s", (rtck_enabled) ? "enabled" : "disabled");
+ exit(-1);
+ }
+}
+
+void amt_jtagaccel_state_move(void)
+{
+ u8 aw_scan_tms_5;
+ u8 tms_scan[2];
+
+ tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
+ tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
+
+ aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
+ AMT_AW(aw_scan_tms_5);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if (tms_scan[0] & 0x80)
+ {
+ aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f);
+ AMT_AW(aw_scan_tms_5);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+ }
+
+ cur_state = end_state;
+}
+
+void amt_jtagaccel_runtest(int num_cycles)
+{
+ int i = 0;
+ u8 aw_scan_tms_5;
+ u8 aw_scan_tms_1to4;
+
+ enum tap_state saved_end_state = end_state;
+
+ /* only do a state_move when we're not already in RTI */
+ if (cur_state != TAP_RTI)
+ {
+ amt_jtagaccel_end_state(TAP_RTI);
+ amt_jtagaccel_state_move();
+ }
+
+ while (num_cycles - i >= 5)
+ {
+ aw_scan_tms_5 = 0x40;
+ AMT_AW(aw_scan_tms_5);
+ i += 5;
+ }
+
+ if (num_cycles - i > 0)
+ {
+ aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4;
+ AMT_AW(aw_scan_tms_1to4);
+ }
+
+ amt_jtagaccel_end_state(saved_end_state);
+ if (cur_state != end_state)
+ amt_jtagaccel_state_move();
+}
+
+void amt_jtagaccel_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
+{
+ int bits_left = scan_size;
+ int bit_count = 0;
+ enum tap_state saved_end_state = end_state;
+ u8 aw_tdi_option;
+ u8 dw_tdi_scan;
+ u8 dr_tdo;
+ u8 aw_tms_scan;
+ u8 tms_scan[2];
+
+ if (ir_scan)
+ amt_jtagaccel_end_state(TAP_SI);
+ else
+ amt_jtagaccel_end_state(TAP_SD);
+
+ amt_jtagaccel_state_move();
+ amt_jtagaccel_end_state(saved_end_state);
+
+ /* handle unaligned bits at the beginning */
+ if ((scan_size - 1) % 8)
+ {
+ aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1);
+ AMT_AW(aw_tdi_option);
+
+ dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff;
+ AMT_DW(dw_tdi_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8));
+ buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo);
+ }
+
+ bit_count += (scan_size - 1) % 8;
+ bits_left -= (scan_size - 1) % 8;
+ }
+
+ while (bits_left - 1 >= 8)
+ {
+ dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff;
+ AMT_DW(dw_tdi_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ buf_set_u32(buffer, bit_count, 8, dr_tdo);
+ }
+
+ bit_count += 8;
+ bits_left -= 8;
+ }
+
+ tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
+ tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
+ aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5);
+ AMT_AW(aw_tms_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ dr_tdo = dr_tdo >> 7;
+ buf_set_u32(buffer, bit_count, 1, dr_tdo);
+ }
+
+ if (tms_scan[0] & 0x80)
+ {
+ aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f);
+ AMT_AW(aw_tms_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+ }
+ cur_state = end_state;
+}
+
+int amt_jtagaccel_execute_queue(void)
+{
+ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
+ int scan_size;
+ enum scan_type type;
+ u8 *buffer;
+
+ while (cmd)
+ {
+ switch (cmd->type)
+ {
+ case JTAG_END_STATE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
+#endif
+ if (cmd->cmd.end_state->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.end_state->end_state);
+ break;
+ case JTAG_RESET:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+#endif
+ if (cmd->cmd.reset->trst == 1)
+ {
+ cur_state = TAP_TLR;
+ }
+ amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ break;
+ case JTAG_RUNTEST:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
+#endif
+ if (cmd->cmd.runtest->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.runtest->end_state);
+ amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles);
+ break;
+ case JTAG_STATEMOVE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
+#endif
+ if (cmd->cmd.statemove->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.statemove->end_state);
+ amt_jtagaccel_state_move();
+ break;
+ case JTAG_SCAN:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("scan end in %i", cmd->cmd.scan->end_state);
+#endif
+ if (cmd->cmd.scan->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.scan->end_state);
+ scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
+ type = jtag_scan_type(cmd->cmd.scan);
+ amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
+ if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
+ return ERROR_JTAG_QUEUE_FAILED;
+ if (buffer)
+ free(buffer);
+ break;
+ case JTAG_SLEEP:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("sleep", cmd->cmd.sleep->us);
+#endif
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+ cmd = cmd->next;
+ }
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_init(void)
+{
+#if PARPORT_USE_PPDEV == 1
+ char buffer[256];
+ int i = 0;
+ u8 control_port;
+#else
+ u8 status_port;
+#endif
+
+#if PARPORT_USE_PPDEV == 1
+ if (device_handle > 0)
+ {
+ ERROR("device is already opened");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port);
+ device_handle = open(buffer, O_RDWR);
+
+ if (device_handle < 0)
+ {
+ ERROR("cannot open device. check it exists and that user read and write rights are set");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = ioctl(device_handle, PPCLAIM);
+ if (i < 0)
+ {
+ ERROR("cannot claim device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = IEEE1284_MODE_EPP;
+ i = ioctl(device_handle, PPSETMODE, & i);
+ if (i < 0)
+ {
+ ERROR(" cannot set compatible mode to device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ control_port = 0x00;
+ i = ioctl(device_handle, PPWCONTROL, &control_port);
+
+ control_port = 0x04;
+ i = ioctl(device_handle, PPWCONTROL, &control_port);
+
+#else
+ if (amt_jtagaccel_port == 0)
+ {
+ amt_jtagaccel_port = 0x378;
+ WARNING("No parport port specified, using default '0x378' (LPT1)");
+ }
+
+ if (ioperm(amt_jtagaccel_port, 5, 1) != 0) {
+ ERROR("missing privileges for direct i/o");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* prepare epp port */
+ /* clear timeout */
+ status_port = inb(amt_jtagaccel_port + 1);
+ outb(status_port | 0x1, amt_jtagaccel_port + 1);
+
+ /* reset epp port */
+ outb(0x00, amt_jtagaccel_port + 2);
+ outb(0x04, amt_jtagaccel_port + 2);
+#endif
+
+ /* enable JTAG port */
+ aw_control_fsm |= 0x04;
+ AMT_AW(aw_control_fsm);
+
+ amt_jtagaccel_speed(jtag_speed);
+
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ aw_control_rst &= ~0x8;
+ else
+ aw_control_rst |= 0x8;
+
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ aw_control_rst &= ~0x2;
+ else
+ aw_control_rst |= 0x2;
+
+ amt_jtagaccel_reset(0, 0);
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_quit(void)
+{
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ return ERROR_OK;
+
+ /* only if the port wasn't overwritten by cmdline */
+ if (amt_jtagaccel_port == 0)
+ amt_jtagaccel_port = strtoul(args[0], NULL, 0);
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ {
+ command_print(cmd_ctx, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled");
+ return ERROR_OK;
+ }
+ else
+ {
+ if (strcmp(args[0], "enabled") == 0)
+ {
+ rtck_enabled = 1;
+
+ /* set RTCK enable bit */
+ aw_control_fsm |= 0x02;
+ AMT_AW(aw_control_fsm);
+ }
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/jtag/bitbang.c b/src/jtag/bitbang.c
new file mode 100644
index 00000000..d6ff2898
--- /dev/null
+++ b/src/jtag/bitbang.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include "bitbang.h"
+
+/* project specific includes */
+#include "log.h"
+#include "types.h"
+#include "jtag.h"
+#include "configuration.h"
+
+/* system includes */
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+bitbang_interface_t *bitbang_interface;
+
+int bitbang_execute_queue(void);
+
+void bitbang_end_state(enum tap_state state)
+{
+ if (tap_move_map[state] != -1)
+ end_state = state;
+ else
+ {
+ ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+void bitbang_state_move(void) {
+
+ int i=0, tms=0;
+ u8 tms_scan = TAP_MOVE(cur_state, end_state);
+
+ for (i = 0; i < 7; i++)
+ {
+ tms = (tms_scan >> i) & 1;
+ bitbang_interface->write(0, tms, 0);
+ bitbang_interface->write(1, tms, 0);
+ }
+ bitbang_interface->write(0, tms, 0);
+
+ cur_state = end_state;
+}
+
+void bitbang_runtest(int num_cycles)
+{
+ int i;
+
+ enum tap_state saved_end_state = end_state;
+
+ /* only do a state_move when we're not already in RTI */
+ if (cur_state != TAP_RTI)
+ {
+ bitbang_end_state(TAP_RTI);
+ bitbang_state_move();
+ }
+
+ /* execute num_cycles */
+ bitbang_interface->write(0, 0, 0);
+ for (i = 0; i < num_cycles; i++)
+ {
+ bitbang_interface->write(1, 0, 0);
+ bitbang_interface->write(0, 0, 0);
+ }
+
+ /* finish in end_state */
+ bitbang_end_state(saved_end_state);
+ if (cur_state != end_state)
+ bitbang_state_move();
+}
+
+void bitbang_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
+{
+ enum tap_state saved_end_state = end_state;
+ int bit_cnt;
+
+ if (ir_scan)
+ bitbang_end_state(TAP_SI);
+ else
+ bitbang_end_state(TAP_SD);
+
+ bitbang_state_move();
+ bitbang_end_state(saved_end_state);
+
+ for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++)
+ {
+ if ((buffer[bit_cnt/8] >> (bit_cnt % 8)) & 0x1) {
+ bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 1);
+ bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 1);
+ } else {
+ bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 0);
+ bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 0);
+ }
+
+ if (type != SCAN_OUT)
+ {
+ if (bitbang_interface->read())
+ buffer[(bit_cnt)/8] |= 1 << ((bit_cnt) % 8);
+ else
+ buffer[(bit_cnt)/8] &= ~(1 << ((bit_cnt) % 8));
+ }
+ }
+
+ /* Exit1 -> Pause */
+ bitbang_interface->write(0, 0, 0);
+ bitbang_interface->write(1, 0, 0);
+
+ if (ir_scan)
+ cur_state = TAP_PI;
+ else
+ cur_state = TAP_PD;
+
+ if (cur_state != end_state)
+ bitbang_state_move();
+}
+
+int bitbang_execute_queue(void)
+{
+ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
+ int scan_size;
+ enum scan_type type;
+ u8 *buffer;
+
+ if (!bitbang_interface)
+ {
+ ERROR("BUG: Bitbang interface called, but not yet initialized");
+ exit(-1);
+ }
+
+ while (cmd)
+ {
+ switch (cmd->type)
+ {
+ case JTAG_END_STATE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
+#endif
+ if (cmd->cmd.end_state->end_state != -1)
+ bitbang_end_state(cmd->cmd.end_state->end_state);
+ break;
+ case JTAG_RESET:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+#endif
+ if (cmd->cmd.reset->trst == 1)
+ {
+ cur_state = TAP_TLR;
+ }
+ bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ break;
+ case JTAG_RUNTEST:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
+#endif
+ if (cmd->cmd.runtest->end_state != -1)
+ bitbang_end_state(cmd->cmd.runtest->end_state);
+ bitbang_runtest(cmd->cmd.runtest->num_cycles);
+ break;
+ case JTAG_STATEMOVE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
+#endif
+ if (cmd->cmd.statemove->end_state != -1)
+ bitbang_end_state(cmd->cmd.statemove->end_state);
+ bitbang_state_move();
+ break;
+ case JTAG_SCAN:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("scan end in %i", cmd->cmd.scan->end_state);
+#endif
+ if (cmd->cmd.scan->end_state != -1)
+ bitbang_end_state(cmd->cmd.scan->end_state);
+ scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
+ type = jtag_scan_type(cmd->cmd.scan);
+ bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
+ if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
+ return ERROR_JTAG_QUEUE_FAILED;
+ if (buffer)
+ free(buffer);
+ break;
+ case JTAG_SLEEP:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("sleep", cmd->cmd.sleep->us);
+#endif
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+ cmd = cmd->next;
+ }
+
+ return ERROR_OK;
+}
+
diff --git a/src/jtag/bitbang.h b/src/jtag/bitbang.h
new file mode 100644
index 00000000..7049f435
--- /dev/null
+++ b/src/jtag/bitbang.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef BITBANG_H
+#define BITBANG_H
+
+typedef struct bitbang_interface_s
+{
+ /* low level callbacks (for bitbang)
+ */
+ int (*read)(void);
+ void (*write)(int tck, int tms, int tdi);
+ void (*reset)(int trst, int srst);
+} bitbang_interface_t;
+
+extern bitbang_interface_t *bitbang_interface;
+
+extern int bitbang_execute_queue(void);
+
+#endif /* BITBANG_H */
diff --git a/src/jtag/ep93xx.c b/src/jtag/ep93xx.c
new file mode 100644
index 00000000..9c24dba4
--- /dev/null
+++ b/src/jtag/ep93xx.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "config.h"
+#include "log.h"
+#include "jtag.h"
+#include "bitbang.h"
+
+#define TDO_BIT 1
+#define TDI_BIT 2
+#define TCK_BIT 4
+#define TMS_BIT 8
+#define TRST_BIT 16
+#define SRST_BIT 32
+#define VCC_BIT 64
+
+/* system includes */
+#include <sys/io.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static u8 output_value = 0x0;
+static int dev_mem_fd;
+static void *gpio_controller;
+static volatile u8 *gpio_data_register;
+static volatile u8 *gpio_data_direction_register;
+
+/* low level command set
+ */
+int ep93xx_read(void);
+void ep93xx_write(int tck, int tms, int tdi);
+void ep93xx_reset(int trst, int srst);
+
+int ep93xx_speed(int speed);
+int ep93xx_register_commands(struct command_context_s *cmd_ctx);
+int ep93xx_init(void);
+int ep93xx_quit(void);
+
+struct timespec ep93xx_zzzz;
+
+jtag_interface_t ep93xx_interface =
+{
+ .name = "ep93xx",
+
+ .execute_queue = bitbang_execute_queue,
+
+ .support_statemove = 0,
+
+ .speed = ep93xx_speed,
+ .register_commands = ep93xx_register_commands,
+ .init = ep93xx_init,
+ .quit = ep93xx_quit,
+};
+
+bitbang_interface_t ep93xx_bitbang =
+{
+ .read = ep93xx_read,
+ .write = ep93xx_write,
+ .reset = ep93xx_reset
+};
+
+int ep93xx_read(void)
+{
+ return !!(*gpio_data_register & TDO_BIT);
+}
+
+void ep93xx_write(int tck, int tms, int tdi)
+{
+ if (tck)
+ output_value |= TCK_BIT;
+ else
+ output_value &= TCK_BIT;
+
+ if (tms)
+ output_value |= TMS_BIT;
+ else
+ output_value &= TMS_BIT;
+
+ if (tdi)
+ output_value |= TDI_BIT;
+ else
+ output_value &= TDI_BIT;
+
+ *gpio_data_register = output_value;
+ nanosleep(ep93xx_zzzz);
+}
+
+/* (1) assert or (0) deassert reset lines */
+void ep93xx_reset(int trst, int srst)
+{
+ if (trst == 0)
+ output_value |= TRST_BIT;
+ else if (trst == 1)
+ output_value &= TRST_BIT;
+
+ if (srst == 0)
+ output_value |= SRST_BIT;
+ else if (srst == 1)
+ output_value &= SRST_BIT;
+
+ *gpio_data_register = output_value;
+ nanosleep(ep93xx_zzzz);
+}
+
+int ep93xx_speed(int speed)
+{
+
+ return ERROR_OK;
+}
+
+int ep93xx_register_commands(struct command_context_s *cmd_ctx)
+{
+
+ return ERROR_OK;
+}
+
+static int set_gonk_mode(void)
+{
+ void *syscon;
+ u32 devicecfg;
+
+ syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+ MAP_SHARED, dev_mem_fd, 0x80930000);
+ if (syscon == MAP_FAILED) {
+ perror("mmap");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ devicecfg = *((volatile int *)(syscon + 0x80));
+ *((volatile int *)(syscon + 0xc0)) = 0xaa;
+ *((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000;
+
+ munmap(syscon, 4096);
+
+ return ERROR_OK;
+}
+
+int ep93xx_init(void)
+{
+ int ret;
+
+ bitbang_interface = &ep93xx_bitbang;
+
+ ep93xx_zzzz.tv_sec = 0;
+ ep93xx_zzzz.tv_nsec = 10000000;
+
+ dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
+ if (dev_mem_fd < 0) {
+ perror("open");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+ MAP_SHARED, dev_mem_fd, 0x80840000);
+ if (gpio_controller == MAP_FAILED) {
+ perror("mmap");
+ close(dev_mem_fd);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ ret = set_gonk_mode();
+ if (ret != ERROR_OK) {
+ munmap(gpio_controller, 4096);
+ close(dev_mem_fd);
+ return ret;
+ }
+
+#if 0
+ /* Use GPIO port A. */
+ gpio_data_register = gpio_controller + 0x00;
+ gpio_data_direction_register = gpio_controller + 0x10;
+
+
+ /* Use GPIO port B. */
+ gpio_data_register = gpio_controller + 0x04;
+ gpio_data_direction_register = gpio_controller + 0x14;
+
+ /* Use GPIO port C. */
+ gpio_data_register = gpio_controller + 0x08;
+ gpio_data_direction_register = gpio_controller + 0x18;
+
+ /* Use GPIO port D. */
+ gpio_data_register = gpio_controller + 0x0c;
+ gpio_data_direction_register = gpio_controller + 0x1c;
+#endif
+
+ /* Use GPIO port C. */
+ gpio_data_register = gpio_controller + 0x08;
+ gpio_data_direction_register = gpio_controller + 0x18;
+
+ printf("gpio_data_register = %08x\n", gpio_data_register);
+ printf("gpio_data_direction_reg = %08x\n", gpio_data_direction_register);
+ /*
+ * Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK
+ * TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and
+ * TMS/TRST/SRST high.
+ */
+ output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
+ *gpio_data_register = output_value;
+ nanosleep(ep93xx_zzzz);
+
+ /*
+ * Configure the direction register. 1 = output, 0 = input.
+ */
+ *gpio_data_direction_register =
+ TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
+
+ nanosleep(ep93xx_zzzz);
+ return ERROR_OK;
+}
+
+int ep93xx_quit(void)
+{
+
+ return ERROR_OK;
+}
diff --git a/src/jtag/ftd2xx.c b/src/jtag/ftd2xx.c
new file mode 100644
index 00000000..c73c8d58
--- /dev/null
+++ b/src/jtag/ftd2xx.c
@@ -0,0 +1,1004 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "config.h"
+#if IS_CYGWIN == 1
+#include "windows.h"
+#undef ERROR
+#endif
+
+/* project specific includes */
+#include "log.h"
+#include "types.h"
+#include "jtag.h"
+#include "configuration.h"
+
+/* system includes */
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ftd2xx.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+/* enable this to debug io latency
+ */
+#if 0
+#define _DEBUG_USB_IO_
+#endif
+
+/* enable this to debug communication
+ */
+#if 0
+#define _DEBUG_USB_COMMS_
+#endif
+
+/* enable this to work around ftd2xx deadlock
+ */
+#if 0
+#define _FTD2XX_QUEUE_DELAY_
+#endif
+
+int ftd2xx_execute_queue(void);
+
+int ftd2xx_speed(int speed);
+int ftd2xx_register_commands(struct command_context_s *cmd_ctx);
+int ftd2xx_init(void);
+int ftd2xx_quit(void);
+
+int ftd2xx_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int ftd2xx_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int ftd2xx_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+char *ftd2xx_device_desc = NULL;
+char *ftd2xx_layout = NULL;
+u16 ftd2xx_vid = 0x0403;
+u16 ftd2xx_pid = 0x6010;
+
+typedef struct ftd2xx_layout_s
+{
+ char* name;
+ int(*init)(void);
+ void(*reset)(int trst, int srst);
+} ftd2xx_layout_t;
+
+int usbjtag_init(void);
+int jtagkey_init(void);
+void usbjtag_reset(int trst, int srst);
+void jtagkey_reset(int trst, int srst);
+
+ftd2xx_layout_t ftd2xx_layouts[] =
+{
+ {"usbjtag", usbjtag_init, usbjtag_reset},
+ {"jtagkey", jtagkey_init, jtagkey_reset},
+ {"jtagkey_prototype_v1", jtagkey_init, jtagkey_reset},
+ {NULL, NULL, NULL},
+};
+
+static u8 nTRST, nTRSTnOE, nSRST, nSRSTnOE;
+
+static ftd2xx_layout_t *layout;
+static u8 low_output = 0x0;
+static u8 low_direction = 0x0;
+static u8 high_output = 0x0;
+static u8 high_direction = 0x0;
+static FT_HANDLE ftdih = NULL;
+
+static u8 *ftd2xx_buffer = NULL;
+static int ftd2xx_buffer_size = 0;
+static int ftd2xx_read_pointer = 0;
+static int ftd2xx_expect_read = 0;
+#define FTD2XX_BUFFER_SIZE 131072
+#define BUFFER_ADD ftd2xx_buffer[ftd2xx_buffer_size++]
+#define BUFFER_READ ftd2xx_buffer[ftd2xx_read_pointer++]
+
+jtag_interface_t ftd2xx_interface =
+{
+
+ .name = "ftd2xx",
+
+ .execute_queue = ftd2xx_execute_queue,
+
+ .support_statemove = 1,
+
+ .speed = ftd2xx_speed,
+ .register_commands = ftd2xx_register_commands,
+ .init = ftd2xx_init,
+ .quit = ftd2xx_quit,
+};
+
+int ftd2xx_speed(int speed)
+{
+ u8 buf[3];
+ FT_STATUS status;
+ DWORD bytes_written;
+
+ buf[0] = 0x86; /* command "set divisor" */
+ buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
+ buf[2] = (speed >> 8) & 0xff; /* valueH */
+
+ DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+ if (((status = FT_Write(ftdih, buf, 3, &bytes_written)) != FT_OK) || (bytes_written != 3))
+ {
+ ERROR("couldn't write to ftdi device: %i", status);
+ return status;
+ }
+
+ return ERROR_OK;
+}
+
+int ftd2xx_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "ftd2xx_device_desc", ftd2xx_handle_device_desc_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "ftd2xx_layout", ftd2xx_handle_layout_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "ftd2xx_vid_pid", ftd2xx_handle_vid_pid_command,
+ COMMAND_CONFIG, NULL);
+ return ERROR_OK;
+}
+
+void ftd2xx_end_state(state)
+{
+ if (tap_move_map[state] != -1)
+ end_state = state;
+ else
+ {
+ ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+void ftd2xx_read_scan(enum scan_type type, u8* buffer, int scan_size)
+{
+ int num_bytes = ((scan_size + 7) / 8);
+ int bits_left = scan_size;
+ int cur_byte = 0;
+
+ while(num_bytes-- > 1)
+ {
+ buffer[cur_byte] = BUFFER_READ;
+ cur_byte++;
+ bits_left -= 8;
+ }
+
+ buffer[cur_byte] = 0x0;
+
+ if (bits_left > 1)
+ {
+ buffer[cur_byte] = BUFFER_READ >> 1;
+ }
+
+ buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
+
+}
+
+void ftd2xx_debug_dump_buffer(void)
+{
+ int i;
+ char line[256];
+ char *line_p = line;
+
+ for (i = 0; i < ftd2xx_buffer_size; i++)
+ {
+ line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ftd2xx_buffer[i]);
+ if (i % 16 == 15)
+ {
+ DEBUG("%s", line);
+ line_p = line;
+ }
+ }
+
+ if (line_p != line)
+ DEBUG("%s", line);
+}
+
+int ftd2xx_send_and_recv(jtag_command_t *first, jtag_command_t *last)
+{
+ jtag_command_t *cmd;
+ u8 *buffer;
+ int scan_size;
+ enum scan_type type;
+ FT_STATUS status;
+ DWORD bytes_written;
+ DWORD bytes_read;
+
+#ifdef _DEBUG_USB_IO_
+ struct timeval start, inter, inter2, end;
+#endif
+
+#ifdef _DEBUG_USB_COMMS_
+ DEBUG("write buffer (size %i):", ftd2xx_buffer_size);
+ ftd2xx_debug_dump_buffer();
+#endif
+
+#ifdef _DEBUG_USB_IO_
+ gettimeofday(&start, NULL);
+#endif
+
+ if ((status = FT_Write(ftdih, ftd2xx_buffer, ftd2xx_buffer_size, &bytes_written)) != FT_OK)
+ {
+ ERROR("couldn't write to ftdi device: %i", status);
+ exit(-1);
+ }
+
+#ifdef _DEBUG_USB_IO_
+ gettimeofday(&inter, NULL);
+#endif
+
+ if (ftd2xx_expect_read)
+ {
+ int timeout = 100;
+ ftd2xx_buffer_size = 0;
+
+#ifdef _FTD2XX_QUEUE_DELAY_
+ DWORD inrxqueue = 0;
+ while (inrxqueue < ftd2xx_expect_read)
+ {
+ FT_GetQueueStatus(ftdih, &inrxqueue);
+ if (inrxqueue >= ftd2xx_expect_read)
+ break;
+ usleep(1000);
+ };
+#endif
+
+#ifdef _DEBUG_USB_IO_
+ gettimeofday(&inter2, NULL);
+#endif
+
+ if ((status = FT_Read(ftdih, ftd2xx_buffer, ftd2xx_expect_read, &bytes_read)) != FT_OK)
+ {
+ ERROR("couldn't read from ftdi device: %i", status);
+ exit(-1);
+ }
+
+#ifdef _DEBUG_USB_IO_
+ gettimeofday(&end, NULL);
+
+ INFO("inter: %i.%i, inter2: %i.%i end: %i.%i", inter.tv_sec - start.tv_sec, inter.tv_usec - start.tv_usec,
+ inter2.tv_sec - start.tv_sec, inter2.tv_usec - start.tv_usec,
+ end.tv_sec - start.tv_sec, end.tv_usec - start.tv_usec);
+#endif
+
+
+ ftd2xx_buffer_size = bytes_read;
+
+ if (ftd2xx_expect_read != ftd2xx_buffer_size)
+ {
+ ERROR("ftd2xx_expect_read (%i) != ftd2xx_buffer_size (%i) (%i retries)", ftd2xx_expect_read, ftd2xx_buffer_size, 100 - timeout);
+ ftd2xx_debug_dump_buffer();
+
+ exit(-1);
+ }
+
+#ifdef _DEBUG_USB_COMMS_
+ DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftd2xx_buffer_size);
+ ftd2xx_debug_dump_buffer();
+#endif
+ }
+
+ ftd2xx_expect_read = 0;
+ ftd2xx_read_pointer = 0;
+
+ cmd = first;
+ while (cmd != last)
+ {
+ switch (cmd->type)
+ {
+ case JTAG_SCAN:
+ type = jtag_scan_type(cmd->cmd.scan);
+ if (type != SCAN_OUT)
+ {
+ scan_size = jtag_scan_size(cmd->cmd.scan);
+ buffer = calloc(CEIL(scan_size, 8), 1);
+ ftd2xx_read_scan(type, buffer, scan_size);
+ jtag_read_buffer(buffer, cmd->cmd.scan);
+ free(buffer);
+ }
+ break;
+ default:
+ break;
+ }
+ cmd = cmd->next;
+ }
+
+ ftd2xx_buffer_size = 0;
+
+ return ERROR_OK;
+}
+
+void ftd2xx_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
+{
+ int num_bytes = (scan_size + 7) / 8;
+ int bits_left = scan_size;
+ int cur_byte = 0;
+ int last_bit;
+
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ if (ir_scan)
+ {
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
+ cur_state = TAP_SI;
+ }
+ else
+ {
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
+ cur_state = TAP_SD;
+ }
+ //DEBUG("added TMS scan (no read)");
+
+ /* add command for complete bytes */
+ if (num_bytes > 1)
+ {
+ if (type == SCAN_IO)
+ {
+ /* Clock Data Bytes In and Out LSB First */
+ BUFFER_ADD = 0x39;
+ //DEBUG("added TDI bytes (io %i)", num_bytes);
+ }
+ else if (type == SCAN_OUT)
+ {
+ /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
+ BUFFER_ADD = 0x19;
+ //DEBUG("added TDI bytes (o)");
+ }
+ else if (type == SCAN_IN)
+ {
+ /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
+ BUFFER_ADD = 0x28;
+ //DEBUG("added TDI bytes (i %i)", num_bytes);
+ }
+ BUFFER_ADD = (num_bytes-2) & 0xff;
+ BUFFER_ADD = (num_bytes >> 8) & 0xff;
+ }
+ if (type != SCAN_IN)
+ {
+ /* add complete bytes */
+ while(num_bytes-- > 1)
+ {
+ BUFFER_ADD = buffer[cur_byte];
+ cur_byte++;
+ bits_left -= 8;
+ }
+ }
+ if (type == SCAN_IN)
+ {
+ bits_left -= 8 * (num_bytes - 1);
+ }
+
+ /* the most signifcant bit is scanned during TAP movement */
+ if (type != SCAN_IN)
+ last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
+ else
+ last_bit = 0;
+
+ /* process remaining bits but the last one */
+ if (bits_left > 1)
+ {
+ if (type == SCAN_IO)
+ {
+ /* Clock Data Bits In and Out LSB First */
+ BUFFER_ADD = 0x3b;
+ //DEBUG("added TDI bits (io) %i", bits_left - 1);
+ }
+ else if (type == SCAN_OUT)
+ {
+ /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
+ BUFFER_ADD = 0x1b;
+ //DEBUG("added TDI bits (o)");
+ }
+ else if (type == SCAN_IN)
+ {
+ /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
+ BUFFER_ADD = 0x2a;
+ //DEBUG("added TDI bits (i %i)", bits_left - 1);
+ }
+ BUFFER_ADD = bits_left - 2;
+ if (type != SCAN_IN)
+ BUFFER_ADD = buffer[cur_byte];
+ }
+
+ /* move from Shift-IR/DR to end state */
+ if (type != SCAN_OUT)
+ {
+ /* Clock Data to TMS/CS Pin with Read */
+ BUFFER_ADD = 0x6b;
+ //DEBUG("added TMS scan (read)");
+ }
+ else
+ {
+ /* Clock Data to TMS/CS Pin (no Read) */
+ BUFFER_ADD = 0x4b;
+ //DEBUG("added TMS scan (no read)");
+ }
+ BUFFER_ADD = 0x6;
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
+ cur_state = end_state;
+
+}
+
+int ftd2xx_predict_scan_out(int scan_size, enum scan_type type)
+{
+ int predicted_size = 6;
+ if (type == SCAN_IN) /* only from device to host */
+ {
+ predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
+ predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
+ }
+ else /* host to device, or bidirectional */
+ {
+ predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
+ predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
+ }
+
+ return predicted_size;
+}
+
+int ftd2xx_predict_scan_in(int scan_size, enum scan_type type)
+{
+ int predicted_size = 0;
+
+ if (type != SCAN_OUT)
+ {
+ /* complete bytes */
+ predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
+ /* remaining bits - 1 */
+ predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
+ /* last bit (from TMS scan) */
+ predicted_size += 1;
+ }
+
+ //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
+
+ return predicted_size;
+}
+
+void usbjtag_reset(int trst, int srst)
+{
+ if (trst == 1)
+ {
+ cur_state = TAP_TLR;
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ low_direction |= nTRSTnOE; /* switch to output pin (output is low) */
+ else
+ low_output &= ~nTRST; /* switch output low */
+ }
+ else if (trst == 0)
+ {
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */
+ else
+ low_output |= nTRST; /* switch output high */
+ }
+
+ if (srst == 1)
+ {
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ low_output &= ~nSRST; /* switch output low */
+ else
+ low_direction |= nSRSTnOE; /* switch to output pin (output is low) */
+ }
+ else if (srst == 0)
+ {
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ low_output |= nSRST; /* switch output high */
+ else
+ low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */
+ }
+
+ /* command "set data bits low byte" */
+ BUFFER_ADD = 0x80;
+ BUFFER_ADD = low_output;
+ BUFFER_ADD = low_direction;
+
+}
+
+void jtagkey_reset(int trst, int srst)
+{
+ if (trst == 1)
+ {
+ cur_state = TAP_TLR;
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ high_output &= ~nTRSTnOE;
+ else
+ high_output &= ~nTRST;
+ }
+ else if (trst == 0)
+ {
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ high_output |= nTRSTnOE;
+ else
+ high_output |= nTRST;
+ }
+
+ if (srst == 1)
+ {
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ high_output &= ~nSRST;
+ else
+ high_output &= ~nSRSTnOE;
+ }
+ else if (srst == 0)
+ {
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ high_output |= nSRST;
+ else
+ high_output |= nSRSTnOE;
+ }
+
+ /* command "set data bits high byte" */
+ BUFFER_ADD = 0x82;
+ BUFFER_ADD = high_output;
+ BUFFER_ADD = high_direction;
+ DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
+}
+
+int ftd2xx_execute_queue()
+{
+ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
+ jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
+ u8 *buffer;
+ int scan_size; /* size of IR or DR scan */
+ enum scan_type type;
+ int i;
+ int predicted_size = 0;
+ int require_send = 0;
+
+ ftd2xx_buffer_size = 0;
+ ftd2xx_expect_read = 0;
+
+ while (cmd)
+ {
+ switch(cmd->type)
+ {
+ case JTAG_END_STATE:
+ if (cmd->cmd.end_state->end_state != -1)
+ ftd2xx_end_state(cmd->cmd.end_state->end_state);
+ break;
+ case JTAG_RESET:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 3;
+ if (ftd2xx_buffer_size + predicted_size + 1 > FTD2XX_BUFFER_SIZE)
+ {
+ ftd2xx_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+
+ layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ require_send = 1;
+
+ break;
+ case JTAG_RUNTEST:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 0;
+ if (cur_state != TAP_RTI)
+ predicted_size += 3;
+ predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
+ if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
+ predicted_size += 3;
+ if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
+ predicted_size += 3;
+ if (ftd2xx_buffer_size + predicted_size + 1 > FTD2XX_BUFFER_SIZE)
+ {
+ ftd2xx_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ if (cur_state != TAP_RTI)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
+ cur_state = TAP_RTI;
+ require_send = 1;
+ }
+ i = cmd->cmd.runtest->num_cycles;
+ while (i > 0)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = (i > 7) ? 6 : (i - 1);
+ /* TMS data bits */
+ BUFFER_ADD = 0x0;
+ cur_state = TAP_RTI;
+ i -= (i > 7) ? 7 : i;
+ //DEBUG("added TMS scan (no read)");
+ }
+ if (cmd->cmd.runtest->end_state != -1)
+ ftd2xx_end_state(cmd->cmd.runtest->end_state);
+ if (cur_state != end_state)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state);
+ cur_state = end_state;
+ //DEBUG("added TMS scan (no read)");
+ }
+ require_send = 1;
+ break;
+ case JTAG_STATEMOVE:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 3;
+ if (ftd2xx_buffer_size + predicted_size + 1 > FTD2XX_BUFFER_SIZE)
+ {
+ ftd2xx_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ if (cmd->cmd.statemove->end_state != -1)
+ ftd2xx_end_state(cmd->cmd.statemove->end_state);
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state);
+ //DEBUG("added TMS scan (no read)");
+ cur_state = end_state;
+ require_send = 1;
+ break;
+ case JTAG_SCAN:
+ scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
+ type = jtag_scan_type(cmd->cmd.scan);
+ predicted_size = ftd2xx_predict_scan_out(scan_size, type);
+ if (ftd2xx_buffer_size + predicted_size + 1 > FTD2XX_BUFFER_SIZE)
+ {
+ DEBUG("ftd2xx buffer size reached, sending queued commands (first_unsent: %x, cmd: %x)", first_unsent, cmd);
+ ftd2xx_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ ftd2xx_expect_read += ftd2xx_predict_scan_in(scan_size, type);
+ //DEBUG("new read size: %i", ftd2xx_expect_read);
+ if (cmd->cmd.scan->end_state != -1)
+ ftd2xx_end_state(cmd->cmd.scan->end_state);
+ ftd2xx_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
+ require_send = 1;
+ if (buffer)
+ free(buffer);
+ break;
+ case JTAG_SLEEP:
+ ftd2xx_send_and_recv(first_unsent, cmd);
+ first_unsent = cmd->next;
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+ cmd = cmd->next;
+ }
+
+ if (require_send > 0)
+ ftd2xx_send_and_recv(first_unsent, cmd);
+
+ return ERROR_OK;
+}
+
+int ftd2xx_init(void)
+{
+ u8 latency_timer;
+ FT_STATUS status;
+ DWORD num_devices;
+
+ ftd2xx_layout_t *cur_layout = ftd2xx_layouts;
+
+ if ((ftd2xx_layout == NULL) || (ftd2xx_layout[0] == 0))
+ {
+ ftd2xx_layout = "usbjtag";
+ WARNING("No ftd2xx layout specified, using default 'usbjtag'");
+ }
+
+ while (cur_layout->name)
+ {
+ if (strcmp(cur_layout->name, ftd2xx_layout) == 0)
+ {
+ layout = cur_layout;
+ break;
+ }
+ cur_layout++;
+ }
+
+ if (!layout)
+ {
+ ERROR("No matching layout found for %s", ftd2xx_layout);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftd2xx_device_desc == NULL)
+ {
+ WARNING("no ftd2xx device description specified, using default 'Dual RS232'");
+ ftd2xx_device_desc = "Dual RS232";
+ }
+
+#if IS_CYGWIN != 1
+ /* Add JTAGkey Vid/Pid to the linux driver */
+ if ((status = FT_SetVIDPID(ftd2xx_vid, ftd2xx_pid)) != FT_OK)
+ {
+ WARNING("couldn't add %4.4x:%4.4x", ftd2xx_vid, ftd2xx_pid);
+ }
+#endif
+
+ if ((status = FT_OpenEx(ftd2xx_device_desc, FT_OPEN_BY_DESCRIPTION, &ftdih)) != FT_OK)
+ {
+ ERROR("unable to open ftdi device: %i", status);
+ status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
+ if (status == FT_OK)
+ {
+ char **desc_array = malloc(sizeof(char*) * (num_devices + 1));
+ int i;
+
+ for (i = 0; i < num_devices; i++)
+ desc_array[i] = malloc(64);
+ desc_array[num_devices] = NULL;
+
+ status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
+
+ if (status == FT_OK)
+ {
+ ERROR("ListDevices: %d\n", num_devices);
+ for (i = 0; i < num_devices; i++)
+ ERROR("%i: %s", i, desc_array[i]);
+ }
+
+ for (i = 0; i < num_devices; i++)
+ free(desc_array[i]);
+ free(desc_array);
+ }
+ else
+ {
+ printf("ListDevices: NONE\n");
+ }
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if ((status = FT_SetLatencyTimer(ftdih, 2)) != FT_OK)
+ {
+ ERROR("unable to set latency timer: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK)
+ {
+ ERROR("unable to get latency timer: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ else
+ {
+ DEBUG("current latency timer: %i", latency_timer);
+ }
+
+ if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK)
+ {
+ ERROR("unable to enable bit i/o mode: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ ftd2xx_buffer_size = 0;
+ ftd2xx_buffer = malloc(FTD2XX_BUFFER_SIZE);
+
+ if (layout->init() != ERROR_OK)
+ return ERROR_JTAG_INIT_FAILED;
+
+ ftd2xx_speed(jtag_speed);
+
+ if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
+ {
+ ERROR("error purging ftd2xx device: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int usbjtag_init(void)
+{
+ u8 buf[3];
+ FT_STATUS status;
+ DWORD bytes_written;
+
+ low_output = 0x08;
+ low_direction = 0x0b;
+
+ nTRST = 0x10;
+ nTRSTnOE = 0x10;
+ nSRST = 0x40;
+ nSRSTnOE = 0x40;
+
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ {
+ low_direction &= ~nTRSTnOE; /* nTRST input */
+ low_output &= ~nTRST; /* nTRST = 0 */
+ }
+ else
+ {
+ low_direction |= nTRSTnOE; /* nTRST output */
+ low_output |= nTRST; /* nTRST = 1 */
+ }
+
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ {
+ low_direction |= nSRSTnOE; /* nSRST output */
+ low_output |= nSRST; /* nSRST = 1 */
+ }
+ else
+ {
+ low_direction &= ~nSRSTnOE; /* nSRST input */
+ low_output &= ~nSRST; /* nSRST = 0 */
+ }
+
+ /* initialize low byte for jtag */
+ buf[0] = 0x80; /* command "set data bits low byte" */
+ buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
+ buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
+ DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+ if (((FT_Write(ftdih, buf, 3, &bytes_written)) != FT_OK) || (bytes_written != 3))
+ {
+ ERROR("couldn't write to ftdi device: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int jtagkey_init(void)
+{
+ u8 buf[3];
+ FT_STATUS status;
+ DWORD bytes_written;
+
+ low_output = 0x08;
+ low_direction = 0x1b;
+
+ /* initialize low byte for jtag */
+ buf[0] = 0x80; /* command "set data bits low byte" */
+ buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
+ buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
+ DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+ if (((FT_Write(ftdih, buf, 3, &bytes_written)) != FT_OK) || (bytes_written != 3))
+ {
+ ERROR("couldn't write to ftdi device: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (strcmp(layout->name, "jtagkey") == 0)
+ {
+ nTRST = 0x01;
+ nTRSTnOE = 0x4;
+ nSRST = 0x02;
+ nSRSTnOE = 0x08;
+ }
+ else if (strcmp(layout->name, "jtagkey_prototype_v1") == 0)
+ {
+ nTRST = 0x02;
+ nTRSTnOE = 0x1;
+ nSRST = 0x08;
+ nSRSTnOE = 0x04;
+ }
+ else
+ {
+ ERROR("BUG: jtagkey_init called for non jtagkey layout");
+ exit(-1);
+ }
+
+ high_output = 0x0;
+ high_direction = 0x0f;
+
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ {
+ high_output |= nTRSTnOE;
+ high_output &= ~nTRST;
+ }
+ else
+ {
+ high_output &= ~nTRSTnOE;
+ high_output |= nTRST;
+ }
+
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ {
+ high_output &= ~nSRSTnOE;
+ high_output |= nSRST;
+ }
+ else
+ {
+ high_output |= nSRSTnOE;
+ high_output &= ~nSRST;
+ }
+
+ /* initialize high port */
+ buf[0] = 0x82; /* command "set data bits low byte" */
+ buf[1] = high_output; /* value */
+ buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
+ DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+
+ if (((FT_Write(ftdih, buf, 3, &bytes_written)) != FT_OK) || (bytes_written != 3))
+ {
+ ERROR("couldn't write to ftdi device: %i", status);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int ftd2xx_quit(void)
+{
+ FT_STATUS status;
+
+ status = FT_Close(ftdih);
+
+ free(ftd2xx_buffer);
+
+ return ERROR_OK;
+}
+
+int ftd2xx_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 1)
+ {
+ ftd2xx_device_desc = strdup(args[0]);
+ }
+ else
+ {
+ ERROR("expected exactly one argument to ftd2xx_device_desc <description>");
+ }
+
+ return ERROR_OK;
+}
+
+int ftd2xx_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ return ERROR_OK;
+
+ ftd2xx_layout = malloc(strlen(args[0]));
+ strcpy(ftd2xx_layout, args[0]);
+
+ return ERROR_OK;
+}
+
+int ftd2xx_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc >= 2)
+ {
+ ftd2xx_vid = strtol(args[0], NULL, 0);
+ ftd2xx_pid = strtol(args[1], NULL, 0);
+ }
+ else
+ {
+ WARNING("incomplete ftd2xx_vid_pid configuration directive");
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/jtag/ftdi2232.c b/src/jtag/ftdi2232.c
new file mode 100644
index 00000000..efd528c3
--- /dev/null
+++ b/src/jtag/ftdi2232.c
@@ -0,0 +1,630 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+/* project specific includes */
+#include "log.h"
+#include "types.h"
+#include "jtag.h"
+#include "configuration.h"
+#include "command.h"
+
+/* system includes */
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <usb.h>
+#include <ftdi.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+/* enable this to debug io latency
+ */
+#if 0
+#define _DEBUG_USB_IO_
+#endif
+
+int ftdi2232_execute_queue(void);
+
+int ftdi2232_speed(int speed);
+int ftdi2232_register_commands(struct command_context_s *cmd_ctx);
+int ftdi2232_init(void);
+int ftdi2232_quit(void);
+
+enum { FTDI2232_TRST = 0x10, FTDI2232_SRST = 0x40 };
+static u8 discrete_output = 0x0 | FTDI2232_TRST | FTDI2232_SRST;
+static struct ftdi_context ftdic;
+
+static u8 *ftdi2232_buffer = NULL;
+static int ftdi2232_buffer_size = 0;
+static int ftdi2232_read_pointer = 0;
+static int ftdi2232_expect_read = 0;
+#define FTDI2232_BUFFER_SIZE 131072
+#define BUFFER_ADD ftdi2232_buffer[ftdi2232_buffer_size++]
+#define BUFFER_READ ftdi2232_buffer[ftdi2232_read_pointer++]
+
+#define FTDI2232_SAVE_SIZE 1024
+
+int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+static u16 ftdi2232_vid = 0x0403;
+static u16 ftdi2232_pid = 0x6010;
+
+jtag_interface_t ftdi2232_interface =
+{
+
+ .name = "ftdi2232",
+
+ .execute_queue = ftdi2232_execute_queue,
+
+ .support_statemove = 1,
+
+ .speed = ftdi2232_speed,
+ .register_commands = ftdi2232_register_commands,
+ .init = ftdi2232_init,
+ .quit = ftdi2232_quit,
+};
+
+int ftdi2232_speed(int speed)
+{
+ u8 buf[3];
+
+ buf[0] = 0x86; /* command "set divisor" */
+ buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
+ buf[2] = (speed >> 8) & 0xff; /* valueH */
+
+ DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
+ ftdi_write_data(&ftdic, buf, 3);
+
+ return ERROR_OK;
+}
+
+int ftdi2232_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "ftdi2232_vid_pid", ftdi2232_handle_vid_pid_command,
+ COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+void ftdi2232_end_state(state)
+{
+ if (tap_move_map[state] != -1)
+ end_state = state;
+ else
+ {
+ ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+void ftdi2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
+{
+ int num_bytes = ((scan_size + 7) / 8);
+ int bits_left = scan_size;
+ int cur_byte = 0;
+
+ while(num_bytes-- > 1)
+ {
+ buffer[cur_byte] = BUFFER_READ;
+ cur_byte++;
+ bits_left -= 8;
+ }
+
+ buffer[cur_byte] = 0x0;
+
+ if (bits_left > 1)
+ {
+ buffer[cur_byte] = BUFFER_READ >> 1;
+ }
+
+ buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
+
+}
+
+void ftdi2232_debug_dump_buffer(void)
+{
+ int i;
+ for (i = 0; i < ftdi2232_buffer_size; i++)
+ {
+ printf("%2.2x ", ftdi2232_buffer[i]);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+int ftdi2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
+{
+ jtag_command_t *cmd;
+ u8 *buffer;
+ int scan_size;
+ enum scan_type type;
+ int retval;
+
+ BUFFER_ADD = 0x87; /* send immediate command */
+
+ if (ftdi2232_buffer_size > FTDI2232_SAVE_SIZE)
+ {
+ ERROR("BUG: ftdi2232_buffer grew beyond %i byte (%i) - this is going to fail", FTDI2232_SAVE_SIZE, ftdi2232_buffer_size);
+ }
+
+#ifdef _DEBUG_USB_IO_
+ DEBUG("write buffer (size %i):", ftdi2232_buffer_size);
+ ftdi2232_debug_dump_buffer();
+#endif
+
+ if ((retval = ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size)) < 0)
+ {
+ ERROR("ftdi_write_data returned %i", retval);
+ exit(-1);
+ }
+
+ if (ftdi2232_expect_read)
+ {
+ int timeout = 100;
+ ftdi2232_buffer_size = 0;
+
+ while ((ftdi2232_buffer_size < ftdi2232_expect_read) && timeout)
+ {
+ ftdi2232_buffer_size += ftdi_read_data(&ftdic, ftdi2232_buffer + ftdi2232_buffer_size, FTDI2232_BUFFER_SIZE - ftdi2232_buffer_size);
+ timeout--;
+ }
+
+ if (ftdi2232_expect_read != ftdi2232_buffer_size)
+ {
+ ERROR("ftdi2232_expect_read (%i) != ftdi2232_buffer_size (%i) (%i retries)", ftdi2232_expect_read, ftdi2232_buffer_size, 100 - timeout);
+ ftdi2232_debug_dump_buffer();
+
+ exit(-1);
+ }
+
+#ifdef _DEBUG_USB_IO_
+ DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftdi2232_buffer_size);
+ ftdi2232_debug_dump_buffer();
+#endif
+ }
+
+ ftdi2232_expect_read = 0;
+ ftdi2232_read_pointer = 0;
+
+ cmd = first;
+ while (cmd != last)
+ {
+ switch (cmd->type)
+ {
+ case JTAG_SCAN:
+ type = jtag_scan_type(cmd->cmd.scan);
+ if (type != SCAN_OUT)
+ {
+ scan_size = jtag_scan_size(cmd->cmd.scan);
+ buffer = calloc(CEIL(scan_size, 8), 1);
+ ftdi2232_read_scan(type, buffer, scan_size);
+ jtag_read_buffer(buffer, cmd->cmd.scan);
+ free(buffer);
+ }
+ break;
+ default:
+ break;
+ }
+ cmd = cmd->next;
+ }
+
+ ftdi2232_buffer_size = 0;
+
+ return ERROR_OK;
+}
+
+void ftdi2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
+{
+ int num_bytes = (scan_size + 7) / 8;
+ int bits_left = scan_size;
+ int cur_byte = 0;
+ int last_bit;
+
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ if (ir_scan)
+ {
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
+ cur_state = TAP_SI;
+ }
+ else
+ {
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
+ cur_state = TAP_SD;
+ }
+ //DEBUG("added TMS scan (no read)");
+
+ /* add command for complete bytes */
+ if (num_bytes > 1)
+ {
+ if (type == SCAN_IO)
+ {
+ /* Clock Data Bytes In and Out LSB First */
+ BUFFER_ADD = 0x39;
+ //DEBUG("added TDI bytes (io %i)", num_bytes);
+ }
+ else if (type == SCAN_OUT)
+ {
+ /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
+ BUFFER_ADD = 0x19;
+ //DEBUG("added TDI bytes (o)");
+ }
+ else if (type == SCAN_IN)
+ {
+ /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
+ BUFFER_ADD = 0x28;
+ //DEBUG("added TDI bytes (i %i)", num_bytes);
+ }
+ BUFFER_ADD = (num_bytes-2) & 0xff;
+ BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
+ }
+ if (type != SCAN_IN)
+ {
+ /* add complete bytes */
+ while(num_bytes-- > 1)
+ {
+ BUFFER_ADD = buffer[cur_byte];
+ cur_byte++;
+ bits_left -= 8;
+ }
+ }
+ if (type == SCAN_IN)
+ {
+ bits_left -= 8 * (num_bytes - 1);
+ }
+
+ /* the most signifcant bit is scanned during TAP movement */
+ if (type != SCAN_IN)
+ last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
+ else
+ last_bit = 0;
+
+ /* process remaining bits but the last one */
+ if (bits_left > 1)
+ {
+ if (type == SCAN_IO)
+ {
+ /* Clock Data Bits In and Out LSB First */
+ BUFFER_ADD = 0x3b;
+ //DEBUG("added TDI bits (io) %i", bits_left - 1);
+ }
+ else if (type == SCAN_OUT)
+ {
+ /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
+ BUFFER_ADD = 0x1b;
+ //DEBUG("added TDI bits (o)");
+ }
+ else if (type == SCAN_IN)
+ {
+ /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
+ BUFFER_ADD = 0x2a;
+ //DEBUG("added TDI bits (i %i)", bits_left - 1);
+ }
+ BUFFER_ADD = bits_left - 2;
+ if (type != SCAN_IN)
+ BUFFER_ADD = buffer[cur_byte];
+ }
+
+ /* move from Shift-IR/DR to end state */
+ if (type != SCAN_OUT)
+ {
+ /* Clock Data to TMS/CS Pin with Read */
+ BUFFER_ADD = 0x6b;
+ //DEBUG("added TMS scan (read)");
+ }
+ else
+ {
+ /* Clock Data to TMS/CS Pin (no Read) */
+ BUFFER_ADD = 0x4b;
+ //DEBUG("added TMS scan (no read)");
+ }
+ BUFFER_ADD = 0x6;
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
+ cur_state = end_state;
+
+}
+
+int ftdi2232_predict_scan_out(int scan_size, enum scan_type type)
+{
+ int predicted_size = 6;
+ if (type == SCAN_IN) /* only from device to host */
+ {
+ predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
+ predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
+ }
+ else /* host to device, or bidirectional */
+ {
+ predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
+ predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
+ }
+
+ return predicted_size;
+}
+
+int ftdi2232_predict_scan_in(int scan_size, enum scan_type type)
+{
+ int predicted_size = 0;
+
+ if (type != SCAN_OUT)
+ {
+ /* complete bytes */
+ predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
+ /* remaining bits - 1 */
+ predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
+ /* last bit (from TMS scan) */
+ predicted_size += 1;
+ }
+
+ //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
+
+ return predicted_size;
+}
+
+int ftdi2232_execute_queue()
+{
+ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
+ jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
+ u8 *buffer;
+ int scan_size; /* size of IR or DR scan */
+ enum scan_type type;
+ int i;
+ int predicted_size = 0;
+ int require_send = 0;
+
+ ftdi2232_buffer_size = 0;
+ ftdi2232_expect_read = 0;
+
+ while (cmd)
+ {
+ switch(cmd->type)
+ {
+ case JTAG_END_STATE:
+ if (cmd->cmd.end_state->end_state != -1)
+ ftdi2232_end_state(cmd->cmd.end_state->end_state);
+ break;
+ case JTAG_RESET:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 3;
+ if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
+ {
+ ftdi2232_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+
+ if (cmd->cmd.reset->trst == 1)
+ {
+ cur_state = TAP_TLR;
+ discrete_output &= ~FTDI2232_TRST;
+ }
+ else if (cmd->cmd.reset->trst == 0)
+ {
+ discrete_output |= FTDI2232_TRST;
+ }
+
+ if (cmd->cmd.reset->srst == 1)
+ discrete_output &= ~FTDI2232_SRST;
+ else if (cmd->cmd.reset->srst == 0)
+ discrete_output |= FTDI2232_SRST;
+ /* command "set data bits low byte" */
+ BUFFER_ADD = 0x80;
+ /* value (TMS=1,TCK=0, TDI=0, TRST/SRST */
+ BUFFER_ADD = 0x08 | discrete_output;
+ /* dir (output=1), TCK/TDI/TMS=out, TDO=in, TRST/SRST=out */
+ BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST;
+ require_send = 1;
+ break;
+ case JTAG_RUNTEST:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 0;
+ if (cur_state != TAP_RTI)
+ predicted_size += 3;
+ predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
+ if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
+ predicted_size += 3;
+ if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
+ predicted_size += 3;
+ if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
+ {
+ ftdi2232_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ if (cur_state != TAP_RTI)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
+ cur_state = TAP_RTI;
+ require_send = 1;
+ }
+ i = cmd->cmd.runtest->num_cycles;
+ while (i > 0)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = (i > 7) ? 6 : (i - 1);
+ /* TMS data bits */
+ BUFFER_ADD = 0x0;
+ cur_state = TAP_RTI;
+ i -= (i > 7) ? 7 : i;
+ //DEBUG("added TMS scan (no read)");
+ }
+ if (cmd->cmd.runtest->end_state != -1)
+ ftdi2232_end_state(cmd->cmd.runtest->end_state);
+ if (cur_state != end_state)
+ {
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state);
+ cur_state = end_state;
+ //DEBUG("added TMS scan (no read)");
+ }
+ require_send = 1;
+ break;
+ case JTAG_STATEMOVE:
+ /* only send the maximum buffer size that FT2232C can handle */
+ predicted_size = 3;
+ if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
+ {
+ ftdi2232_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ if (cmd->cmd.statemove->end_state != -1)
+ ftdi2232_end_state(cmd->cmd.statemove->end_state);
+ /* command "Clock Data to TMS/CS Pin (no Read)" */
+ BUFFER_ADD = 0x4b;
+ /* scan 7 bit */
+ BUFFER_ADD = 0x6;
+ /* TMS data bits */
+ BUFFER_ADD = TAP_MOVE(cur_state, end_state);
+ //DEBUG("added TMS scan (no read)");
+ cur_state = end_state;
+ require_send = 1;
+ break;
+ case JTAG_SCAN:
+ scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
+ type = jtag_scan_type(cmd->cmd.scan);
+ predicted_size = ftdi2232_predict_scan_out(scan_size, type);
+ if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
+ {
+ ftdi2232_send_and_recv(first_unsent, cmd);
+ require_send = 0;
+ first_unsent = cmd;
+ }
+ ftdi2232_expect_read += ftdi2232_predict_scan_in(scan_size, type);
+ //DEBUG("new read size: %i", ftdi2232_expect_read);
+ if (cmd->cmd.scan->end_state != -1)
+ ftdi2232_end_state(cmd->cmd.scan->end_state);
+ ftdi2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
+ require_send = 1;
+ if (buffer)
+ free(buffer);
+ break;
+ case JTAG_SLEEP:
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+ cmd = cmd->next;
+ }
+
+ if (require_send > 0)
+ ftdi2232_send_and_recv(first_unsent, cmd);
+
+ return ERROR_OK;
+}
+
+int ftdi2232_init(void)
+{
+ if (ftdi_init(&ftdic) < 0)
+ return ERROR_JTAG_INIT_FAILED;
+
+ /* context, vendor id, product id */
+ if (ftdi_usb_open(&ftdic, ftdi2232_vid, ftdi2232_pid) < 0)
+ {
+ ERROR("unable to open ftdi device: %s", ftdic.error_str);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_usb_reset(&ftdic) < 0)
+ {
+ ERROR("unable to reset ftdi device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (ftdi_set_latency_timer(&ftdic, 1) < 0)
+ {
+ ERROR("unable to set latency timer");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ ftdi2232_buffer_size = 0;
+ ftdi2232_buffer = malloc(FTDI2232_BUFFER_SIZE);
+
+ ftdic.bitbang_mode = 0; /* Reset controller */
+ ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
+
+ ftdic.bitbang_mode = 2; /* MPSSE mode */
+ ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
+
+ if (ftdi_usb_purge_buffers(&ftdic) < 0)
+ {
+ ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* initialize low byte for jtag */
+ BUFFER_ADD = 0x80; /* command "set data bits low byte" */
+ BUFFER_ADD = 0x08 | FTDI2232_SRST | FTDI2232_TRST; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
+ BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
+ BUFFER_ADD = 0x85; /* command "Disconnect TDI/DO to TDO/DI for Loopback" */
+ ftdi2232_debug_dump_buffer();
+ if (ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size) != 4)
+ return ERROR_JTAG_INIT_FAILED;
+
+ ftdi2232_speed(jtag_speed);
+
+ return ERROR_OK;
+}
+
+int ftdi2232_quit(void)
+{
+ ftdi_disable_bitbang(&ftdic);
+
+ ftdi_usb_close(&ftdic);
+
+ ftdi_deinit(&ftdic);
+
+ free(ftdi2232_buffer);
+
+ return ERROR_OK;
+}
+
+int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc >= 2)
+ {
+ ftdi2232_vid = strtol(args[0], NULL, 0);
+ ftdi2232_pid = strtol(args[1], NULL, 0);
+ }
+ else
+ {
+ WARNING("incomplete ftdi2232_vid_pid configuration directive");
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c
new file mode 100644
index 00000000..e306b0a2
--- /dev/null
+++ b/src/jtag/jtag.c
@@ -0,0 +1,1585 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "config.h"
+#include "jtag.h"
+
+#include "command.h"
+#include "log.h"
+#include "interpreter.h"
+
+#include "stdlib.h"
+#include "string.h"
+#include <unistd.h>
+
+char* tap_state_strings[16] =
+{
+ "tlr",
+ "sds", "cd", "sd", "e1d", "pd", "e2d", "ud",
+ "rti",
+ "sis", "ci", "si", "e1i", "pi", "e2i", "ui"
+};
+
+typedef struct cmd_queue_page_s
+{
+ void *address;
+ size_t used;
+ struct cmd_queue_page_s *next;
+} cmd_queue_page_t;
+
+#define CMD_QUEUE_PAGE_SIZE (1024 * 1024)
+static cmd_queue_page_t *cmd_queue_pages = NULL;
+
+/* tap_move[i][j]: tap movement command to go from state i to state j
+ * 0: Test-Logic-Reset
+ * 1: Run-Test/Idle
+ * 2: Shift-DR
+ * 3: Pause-DR
+ * 4: Shift-IR
+ * 5: Pause-IR
+ */
+u8 tap_move[6][6] =
+{
+/* TLR RTI SD PD SI PI */
+ {0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16}, /* TLR */
+ {0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b}, /* RTI */
+ {0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f}, /* SD */
+ {0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f}, /* PD */
+ {0x7f, 0x31, 0x07, 0x17, 0x00, 0x01}, /* SI */
+ {0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f} /* PI */
+};
+
+int tap_move_map[16] = {
+ 0, -1, -1, 2, -1, 3, -1, -1,
+ 1, -1, -1, 4, -1, 5, -1, -1
+};
+
+tap_transition_t tap_transitions[16] =
+{
+ {TAP_TLR, TAP_RTI}, /* TLR */
+ {TAP_SIS, TAP_CD}, /* SDS */
+ {TAP_E1D, TAP_SD}, /* CD */
+ {TAP_E1D, TAP_SD}, /* SD */
+ {TAP_UD, TAP_PD}, /* E1D */
+ {TAP_E2D, TAP_PD}, /* PD */
+ {TAP_UD, TAP_SD}, /* E2D */
+ {TAP_SDS, TAP_RTI}, /* UD */
+ {TAP_SDS, TAP_RTI}, /* RTI */
+ {TAP_TLR, TAP_CI}, /* SIS */
+ {TAP_E1I, TAP_SI}, /* CI */
+ {TAP_E1I, TAP_SI}, /* SI */
+ {TAP_UI, TAP_PI}, /* E1I */
+ {TAP_E2I, TAP_PI}, /* PI */
+ {TAP_UI, TAP_SI}, /* E2I */
+ {TAP_SDS, TAP_RTI} /* UI */
+};
+
+enum tap_state end_state = TAP_TLR;
+enum tap_state cur_state = TAP_TLR;
+int jtag_trst = 0;
+int jtag_srst = 0;
+
+jtag_command_t *jtag_command_queue = NULL;
+jtag_command_t **last_comand_pointer = &jtag_command_queue;
+jtag_device_t *jtag_devices = NULL;
+int jtag_num_devices = 0;
+int jtag_ir_scan_size = 0;
+enum reset_types jtag_reset_config = RESET_NONE;
+enum tap_state cmd_queue_end_state = TAP_TLR;
+enum tap_state cmd_queue_cur_state = TAP_TLR;
+
+int jtag_verify_capture_ir = 1;
+
+/* callbacks to inform high-level handlers about JTAG state changes */
+jtag_event_callback_t *jtag_event_callbacks;
+
+/* jtag interfaces (parport, FTDI-USB, TI-USB, ...)
+ */
+#if BUILD_PARPORT == 1
+ extern jtag_interface_t parport_interface;
+#endif
+
+#if BUILD_FTDI2232 == 1
+ extern jtag_interface_t ftdi2232_interface;
+#endif
+
+#if BUILD_FTD2XX == 1
+ extern jtag_interface_t ftd2xx_interface;
+#endif
+
+#if BUILD_AMTJTAGACCEL == 1
+ extern jtag_interface_t amt_jtagaccel_interface;
+#endif
+
+#if BUILD_EP93XX == 1
+ extern jtag_interface_t ep93xx_interface;
+#endif
+
+jtag_interface_t *jtag_interfaces[] = {
+#if BUILD_PARPORT == 1
+ &parport_interface,
+#endif
+#if BUILD_FTDI2232 == 1
+ &ftdi2232_interface,
+#endif
+#if BUILD_FTD2XX == 1
+ &ftd2xx_interface,
+#endif
+#if BUILD_AMTJTAGACCEL == 1
+ &amt_jtagaccel_interface,
+#endif
+#if BUILD_EP93XX == 1
+ &ep93xx_interface,
+#endif
+ NULL,
+};
+
+jtag_interface_t *jtag = NULL;
+
+/* configuration */
+char* jtag_interface = NULL;
+int jtag_speed = -1;
+
+/* forward declarations */
+
+/* jtag commands */
+int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv)
+{
+ jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ if (*callbacks_p)
+ {
+ while ((*callbacks_p)->next)
+ callbacks_p = &((*callbacks_p)->next);
+ callbacks_p = &((*callbacks_p)->next);
+ }
+
+ (*callbacks_p) = malloc(sizeof(jtag_event_callback_t));
+ (*callbacks_p)->callback = callback;
+ (*callbacks_p)->priv = priv;
+ (*callbacks_p)->next = NULL;
+
+ return ERROR_OK;
+}
+
+int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv))
+{
+ jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
+
+ if (callback == NULL)
+ {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ while (*callbacks_p)
+ {
+ jtag_event_callback_t **next = &((*callbacks_p)->next);
+ if ((*callbacks_p)->callback == callback)
+ {
+ free(*callbacks_p);
+ *callbacks_p = *next;
+ }
+ callbacks_p = next;
+ }
+
+ return ERROR_OK;
+}
+
+int jtag_call_event_callbacks(enum jtag_event event)
+{
+ jtag_event_callback_t *callback = jtag_event_callbacks;
+
+ DEBUG("jtag event: %i", event);
+
+ while (callback)
+ {
+ callback->callback(event, callback->priv);
+ callback = callback->next;
+ }
+
+ return ERROR_OK;
+}
+
+/* returns a pointer to the pointer of the last command in queue
+ * this may be a pointer to the root pointer (jtag_command_queue)
+ * or to the next member of the last but one command
+ */
+jtag_command_t** jtag_get_last_command_p(void)
+{
+/* jtag_command_t *cmd = jtag_command_queue;
+
+ if (cmd)
+ while (cmd->next)
+ cmd = cmd->next;
+ else
+ return &jtag_command_queue;
+
+ return &cmd->next;*/
+
+ return last_comand_pointer;
+}
+
+/* returns a pointer to the n-th device in the scan chain */
+jtag_device_t* jtag_get_device(int num)
+{
+ jtag_device_t *device = jtag_devices;
+ int i = 0;
+
+ while (device)
+ {
+ if (num == i)
+ return device;
+ device = device->next;
+ i++;
+ }
+
+ return NULL;
+}
+
+void* cmd_queue_alloc(size_t size)
+{
+ cmd_queue_page_t **p_page = &cmd_queue_pages;
+ int offset;
+
+ if (*p_page)
+ {
+ while ((*p_page)->next)
+ p_page = &((*p_page)->next);
+ if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size)
+ p_page = &((*p_page)->next);
+ }
+
+ if (!*p_page)
+ {
+ *p_page = malloc(sizeof(cmd_queue_page_t));
+ (*p_page)->used = 0;
+ (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE);
+ (*p_page)->next = NULL;
+ }
+
+ offset = (*p_page)->used;
+ (*p_page)->used += size;
+
+ return ((*p_page)->address) + offset;
+}
+
+void cmd_queue_free()
+{
+ cmd_queue_page_t *page = cmd_queue_pages;
+
+ while (page)
+ {
+ cmd_queue_page_t *last = page;
+ free(page->address);
+ page = page->next;
+ free(last);
+ }
+
+ cmd_queue_pages = NULL;
+}
+
+int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+ jtag_command_t **last_cmd;
+ jtag_device_t *device;
+ int i, j;
+ int scan_size = 0;
+ /* int changed = 0; */
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /*
+ for (i=0; i<num_fields; i++)
+ {
+ device = jtag_get_device(fields[i].device);
+ if (device)
+ {
+ if (buf_cmp(device->cur_instr, fields[i].out_value, device->ir_length))
+ changed = 1;
+ }
+ else
+ {
+ ERROR("inexistant device specified for ir scan");
+ return ERROR_INVALID_ARGUMENTS;
+ }
+ }
+
+ if (!changed)
+ return ERROR_OK;
+ */
+
+ last_cmd = jtag_get_last_command_p();
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_SCAN;
+
+ /* allocate memory for ir scan command */
+ (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
+ (*last_cmd)->cmd.scan->ir_scan = 1;
+ (*last_cmd)->cmd.scan->num_fields = jtag_num_devices; /* one field per device */
+ (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t));
+ (*last_cmd)->cmd.scan->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ for (i=0; i < jtag_num_devices; i++)
+ {
+ int found = 0;
+ device = jtag_get_device(i);
+ scan_size = device->ir_length;
+ (*last_cmd)->cmd.scan->fields[i].device = i;
+ (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size;
+ (*last_cmd)->cmd.scan->fields[i].in_value = NULL;
+ if (jtag_verify_capture_ir)
+ {
+ (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(device->expected, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(device->expected_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ }
+ else
+ {
+ (*last_cmd)->cmd.scan->fields[i].in_check_value = NULL;
+ (*last_cmd)->cmd.scan->fields[i].in_check_mask = NULL;
+ }
+ (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
+ (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
+
+ /* search the list */
+ for (j=0; j < num_fields; j++)
+ {
+ if (i == fields[j].device)
+ {
+ found = 1;
+ (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+
+ device->bypass = 0;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* if a device isn't listed, set it to BYPASS */
+ (*last_cmd)->cmd.scan->fields[i].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[i].out_mask = NULL;
+ device->bypass = 1;
+
+ }
+
+ /* update device information */
+ buf_cpy((*last_cmd)->cmd.scan->fields[i].out_value, jtag_get_device(i)->cur_instr, scan_size);
+ }
+
+ return ERROR_OK;
+}
+
+int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+ jtag_command_t **last_cmd;
+ int i;
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ last_cmd = jtag_get_last_command_p();
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_SCAN;
+
+ /* allocate memory for ir scan command */
+ (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
+ (*last_cmd)->cmd.scan->ir_scan = 1;
+ (*last_cmd)->cmd.scan->num_fields = num_fields;
+ (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t));
+ (*last_cmd)->cmd.scan->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ for (i = 0; i < num_fields; i++)
+ {
+ int num_bits = fields[i].num_bits;
+ int num_bytes = CEIL(fields[i].num_bits, 8);
+ (*last_cmd)->cmd.scan->fields[i].device = fields[i].device;
+ (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits;
+ (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
+ (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(fields[i].in_check_value, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(fields[i].in_check_mask, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
+ (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
+ }
+ return ERROR_OK;
+}
+
+int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+ int i, j;
+ int bypass_devices = 0;
+ int field_count = 0;
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+ jtag_device_t *device = jtag_devices;
+ int scan_size;
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /* count devices in bypass */
+ while (device)
+ {
+ if (device->bypass)
+ bypass_devices++;
+ device = device->next;
+ }
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->next = NULL;
+ (*last_cmd)->type = JTAG_SCAN;
+
+ /* allocate memory for dr scan command */
+ (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
+ (*last_cmd)->cmd.scan->ir_scan = 0;
+ (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices;
+ (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t));
+ (*last_cmd)->cmd.scan->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ for (i=0; i < jtag_num_devices; i++)
+ {
+ int found = 0;
+ (*last_cmd)->cmd.scan->fields[field_count].device = i;
+
+ for (j=0; j < num_fields; j++)
+ {
+ if (i == fields[j].device)
+ {
+ found = 1;
+ scan_size = fields[j].num_bits;
+ (*last_cmd)->cmd.scan->fields[field_count].num_bits = scan_size;
+ (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value;
+ (*last_cmd)->cmd.scan->fields[field_count].in_check_value = buf_cpy(fields[j].in_check_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = buf_cpy(fields[j].in_check_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+ (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler;
+ (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv;
+ }
+ }
+ if (!found)
+ {
+ /* if a device isn't listed, the BYPASS register should be selected */
+ if (!jtag_get_device(i)->bypass)
+ {
+ ERROR("BUG: no scan data for a device not in BYPASS");
+ exit(-1);
+ }
+
+ /* program the scan field to 1 bit length, and ignore it's value */
+ (*last_cmd)->cmd.scan->fields[field_count].num_bits = 1;
+ (*last_cmd)->cmd.scan->fields[field_count].out_value = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count].out_mask = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count].in_value = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count].in_check_value = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count].in_handler = NULL;
+ (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = NULL;
+ }
+ else
+ {
+ /* if a device is listed, the BYPASS register must not be selected */
+ if (jtag_get_device(i)->bypass)
+ {
+ ERROR("BUG: scan data for a device in BYPASS");
+ exit(-1);
+ }
+ }
+ }
+ return ERROR_OK;
+}
+
+int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+ int i;
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->next = NULL;
+ (*last_cmd)->type = JTAG_SCAN;
+
+ /* allocate memory for scan command */
+ (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
+ (*last_cmd)->cmd.scan->ir_scan = 0;
+ (*last_cmd)->cmd.scan->num_fields = num_fields;
+ (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t));
+ (*last_cmd)->cmd.scan->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ for (i = 0; i < num_fields; i++)
+ {
+ int num_bits = fields[i].num_bits;
+ int num_bytes = CEIL(fields[i].num_bits, 8);
+ (*last_cmd)->cmd.scan->fields[i].device = fields[i].device;
+ (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits;
+ (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
+ (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(fields[i].in_check_value, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(fields[i].in_check_mask, cmd_queue_alloc(num_bytes), num_bits);
+ (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler;
+ (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv;
+ }
+
+ return ERROR_OK;
+}
+int jtag_add_statemove(enum tap_state state)
+{
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->next = NULL;
+ (*last_cmd)->type = JTAG_STATEMOVE;
+
+ (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t));
+ (*last_cmd)->cmd.statemove->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ return ERROR_OK;
+}
+
+int jtag_add_pathmove(int num_states, enum tap_state *path)
+{
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+ int i;
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /* the last state has to be a stable state */
+ if (tap_move_map[path[num_states - 1]] == -1)
+ {
+ ERROR("TAP path doesn't finish in a stable state");
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+ }
+
+ if (jtag->support_statemove)
+ {
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->next = NULL;
+ (*last_cmd)->type = JTAG_RUNTEST;
+
+ (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t));
+ (*last_cmd)->cmd.pathmove->num_states = num_states;
+ (*last_cmd)->cmd.pathmove->path = cmd_queue_alloc(sizeof(enum tap_state) * num_states);
+
+ for (i = 0; i < num_states; i++)
+ (*last_cmd)->cmd.pathmove->path[i] = path[i];
+ }
+ else
+ {
+ /* validate the desired path, and see if it fits a default path */
+ int begin = 0;
+ int end = 0;
+ int j;
+
+ for (i = 0; i < num_states; i++)
+ {
+ for (j = i; j < num_states; j++)
+ {
+ if (tap_move_map[path[j]] != -1)
+ {
+ end = j;
+ break;
+ }
+ }
+
+ if (begin - end <= 7) /* a default path spans no more than 7 states */
+ {
+ jtag_add_statemove(path[end]);
+ }
+ else
+ {
+ ERROR("encountered a TAP path that can't be fulfilled by default paths");
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+ }
+
+ i = end;
+ }
+ }
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = path[num_states - 1];
+
+ return ERROR_OK;
+}
+
+int jtag_add_runtest(int num_cycles, enum tap_state state)
+{
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ if (jtag_trst == 1)
+ {
+ WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+ return ERROR_JTAG_TRST_ASSERTED;
+ }
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_RUNTEST;
+
+ (*last_cmd)->cmd.runtest = cmd_queue_alloc(sizeof(runtest_command_t));
+ (*last_cmd)->cmd.runtest->num_cycles = num_cycles;
+ (*last_cmd)->cmd.runtest->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_RELEASED);
+
+ if (cmd_queue_end_state == TAP_TLR)
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+
+ cmd_queue_cur_state = cmd_queue_end_state;
+
+ return ERROR_OK;
+}
+
+int jtag_add_reset(int req_trst, int req_srst)
+{
+ int trst_with_tms = 0;
+
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ if (req_trst == -1)
+ req_trst = jtag_trst;
+
+ if (req_srst == -1)
+ req_srst = jtag_srst;
+
+ /* Make sure that jtag_reset_config allows the requested reset */
+ /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */
+ if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (req_trst == 0))
+ return ERROR_JTAG_RESET_WOULD_ASSERT_TRST;
+
+ /* if TRST pulls SRST, we reset with TAP T-L-R */
+ if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_trst == 1)) && (req_srst == 0))
+ {
+ req_trst = 0;
+ trst_with_tms = 1;
+ }
+
+ if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
+ return ERROR_JTAG_RESET_CANT_SRST;
+
+ if (req_trst && !(jtag_reset_config & RESET_HAS_TRST))
+ {
+ req_trst = 0;
+ trst_with_tms = 1;
+ }
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_RESET;
+
+ (*last_cmd)->cmd.reset = cmd_queue_alloc(sizeof(reset_command_t));
+ (*last_cmd)->cmd.reset->trst = req_trst;
+ (*last_cmd)->cmd.reset->srst = req_srst;
+
+ jtag_trst = req_trst;
+ jtag_srst = req_srst;
+
+ if (jtag_srst)
+ jtag_call_event_callbacks(JTAG_SRST_ASSERTED);
+ else
+ jtag_call_event_callbacks(JTAG_SRST_RELEASED);
+
+ if (trst_with_tms)
+ {
+ last_cmd = &((*last_cmd)->next);
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_STATEMOVE;
+
+ (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t));
+ (*last_cmd)->cmd.statemove->end_state = TAP_TLR;
+
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+ cmd_queue_cur_state = TAP_TLR;
+ cmd_queue_end_state = TAP_TLR;
+
+ return ERROR_OK;
+ }
+ else
+ {
+ if (jtag_trst)
+ {
+ cmd_queue_cur_state = TAP_TLR;
+ jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int jtag_add_end_state(enum tap_state state)
+{
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_END_STATE;
+
+ (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t));
+ (*last_cmd)->cmd.end_state->end_state = state;
+
+ if (state != -1)
+ cmd_queue_end_state = state;
+
+ return ERROR_OK;
+}
+
+int jtag_add_sleep(u32 us)
+{
+ jtag_command_t **last_cmd = jtag_get_last_command_p();
+
+ /* allocate memory for a new list member */
+ *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
+ (*last_cmd)->next = NULL;
+ last_comand_pointer = &((*last_cmd)->next);
+ (*last_cmd)->type = JTAG_SLEEP;
+
+ (*last_cmd)->cmd.sleep = cmd_queue_alloc(sizeof(sleep_command_t));
+ (*last_cmd)->cmd.sleep->us = us;
+
+ return ERROR_OK;
+}
+
+int jtag_scan_size(scan_command_t *cmd)
+{
+ int bit_count = 0;
+ int i;
+
+ /* count bits in scan command */
+ for (i=0; i<cmd->num_fields; i++)
+ {
+ bit_count += cmd->fields[i].num_bits;
+ }
+
+ return bit_count;
+}
+
+int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
+{
+ int bit_count = 0;
+ int i;
+
+ bit_count = jtag_scan_size(cmd);
+ *buffer = malloc(CEIL(bit_count, 8));
+
+ bit_count = 0;
+
+ for (i = 0; i < cmd->num_fields; i++)
+ {
+ if (cmd->fields[i].out_value)
+ {
+ char* char_buf = buf_to_char(cmd->fields[i].out_value, cmd->fields[i].num_bits);
+ buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("fields[%i].out_value: %s", i, char_buf);
+#endif
+ free(char_buf);
+ }
+
+ bit_count += cmd->fields[i].num_bits;
+ }
+
+ return bit_count;
+
+}
+
+int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
+{
+ int i;
+ int bit_count = 0;
+ int retval = ERROR_OK;
+
+ for (i=0; i < cmd->num_fields; i++)
+ {
+ /* if neither in_value nor in_check_value are specified we don't have to examine this field */
+ if (cmd->fields[i].in_value || cmd->fields[i].in_check_value)
+ {
+ int num_bits = cmd->fields[i].num_bits;
+
+ if (cmd->fields[i].in_value)
+ {
+ char *char_buf;
+ buf_set_buf(buffer, bit_count, cmd->fields[i].in_value, 0, num_bits);
+ char_buf = buf_to_char(cmd->fields[i].in_value, num_bits);
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("fields[%i].in_value: %s", i, char_buf);
+#endif
+ free(char_buf);
+ if (cmd->fields[i].in_handler)
+ {
+ if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv) != ERROR_OK)
+ {
+ /* TODO: error reporting */
+ WARNING("in_handler reported a failed check");
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ }
+ }
+ }
+
+ if (cmd->fields[i].in_check_value)
+ {
+ u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits);
+ if ((cmd->fields[i].in_check_mask && buf_cmp_mask(captured, cmd->fields[i].in_check_value, cmd->fields[i].in_check_mask, num_bits))
+ || (!cmd->fields[i].in_check_mask && buf_cmp(captured, cmd->fields[i].in_check_mask, num_bits)))
+ {
+ char *captured_char = buf_to_char(captured, num_bits);
+ char *in_check_value_char = buf_to_char(cmd->fields[i].in_check_value, num_bits);
+ char *in_check_mask_char = buf_to_char(cmd->fields[i].in_check_mask, num_bits);
+ /* TODO: error reporting */
+ WARNING("value captured during scan didn't pass the requested check: captured: %s check_value: %s check_mask: %s", captured_char, in_check_value_char, in_check_mask_char);
+ retval = ERROR_JTAG_QUEUE_FAILED;
+ free(captured_char);
+ free(in_check_value_char);
+ free(in_check_mask_char);
+ }
+ free(captured);
+ }
+ }
+ bit_count += cmd->fields[i].num_bits;
+ }
+
+ return retval;
+}
+
+enum scan_type jtag_scan_type(scan_command_t *cmd)
+{
+ int i;
+ int type = 0;
+
+ for (i=0; i < cmd->num_fields; i++)
+ {
+ if (cmd->fields[i].in_check_value || cmd->fields[i].in_value)
+ type |= SCAN_IN;
+ if (cmd->fields[i].out_value)
+ type |= SCAN_OUT;
+ }
+
+ return type;
+}
+
+int jtag_execute_queue(void)
+{
+ int retval;
+
+ retval = jtag->execute_queue();
+
+ cmd_queue_free();
+
+ jtag_command_queue = NULL;
+ last_comand_pointer = &jtag_command_queue;
+
+ return retval;
+}
+
+int jtag_cancel_queue(void)
+{
+ cmd_queue_free();
+ jtag_command_queue = NULL;
+ last_comand_pointer = &jtag_command_queue;
+
+ return ERROR_OK;
+}
+
+int jtag_reset_callback(enum jtag_event event, void *priv)
+{
+ jtag_device_t *device = priv;
+
+ DEBUG("");
+
+ if (event == JTAG_TRST_ASSERTED)
+ {
+ buf_set_ones(device->cur_instr, device->ir_length);
+ device->bypass = 1;
+ }
+
+ return ERROR_OK;
+}
+
+void jtag_sleep(u32 us)
+{
+ usleep(us);
+}
+
+int jtag_validate_chain()
+{
+ jtag_device_t *device = jtag_devices;
+ int total_ir_length = 0;
+ u8 *ir_test = NULL;
+ scan_field_t field;
+ int chain_pos = 0;
+
+ while (device)
+ {
+ total_ir_length += device->ir_length;
+ device = device->next;
+ }
+
+ total_ir_length += 2;
+ ir_test = malloc(CEIL(total_ir_length, 8));
+ buf_set_ones(ir_test, total_ir_length);
+
+ field.device = 0;
+ field.num_bits = total_ir_length;
+ field.out_value = ir_test;
+ field.out_mask = NULL;
+ field.in_value = ir_test;
+ field.in_check_value = NULL;
+ field.in_check_mask = NULL;
+ field.in_handler = NULL;
+ field.in_handler_priv = NULL;
+
+ jtag_add_plain_ir_scan(1, &field, TAP_TLR);
+ jtag_execute_queue();
+
+ device = jtag_devices;
+ while (device)
+ {
+ if (buf_get_u32(ir_test, chain_pos, 2) != 0x1)
+ {
+ ERROR("Error validating JTAG scan chain, IR mismatch");
+ exit(-1);
+ }
+ chain_pos += device->ir_length;
+ device = device->next;
+ }
+
+ if (buf_get_u32(ir_test, chain_pos, 2) != 0x3)
+ {
+ ERROR("Error validating JTAG scan chain, IR mismatch");
+ exit(-1);
+ }
+
+ free(ir_test);
+
+ return ERROR_OK;
+}
+
+int jtag_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "interface", handle_interface_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command,
+ COMMAND_ANY, "set jtag speed (if supported) <speed>");
+ register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
+ COMMAND_CONFIG, NULL);
+
+ register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command,
+ COMMAND_EXEC, "print current scan chain configuration");
+
+ register_command(cmd_ctx, NULL, "endstate", handle_endstate_command,
+ COMMAND_EXEC, "finish JTAG operations in <tap_state>");
+ register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command,
+ COMMAND_EXEC, "toggle reset lines <trst> <srst>");
+ register_command(cmd_ctx, NULL, "runtest", handle_runtest_command,
+ COMMAND_EXEC, "move to Run-Test/Idle, and execute <num_cycles>");
+ register_command(cmd_ctx, NULL, "statemove", handle_statemove_command,
+ COMMAND_EXEC, "move to current endstate or [tap_state]");
+ register_command(cmd_ctx, NULL, "irscan", handle_irscan_command,
+ COMMAND_EXEC, "execute IR scan <device> <instr> [dev2] [instr2] ...");
+ register_command(cmd_ctx, NULL, "drscan", handle_drscan_command,
+ COMMAND_EXEC, "execute DR scan <device> <var> [dev2] [var2] ...");
+
+ register_command(cmd_ctx, NULL, "verify_ircapture", handle_verify_ircapture_command,
+ COMMAND_ANY, "verify value captured during Capture-IR <enable|disable>");
+ return ERROR_OK;
+}
+
+int jtag_init(struct command_context_s *cmd_ctx)
+{
+ int i;
+
+ DEBUG("");
+
+ if (jtag_speed == -1)
+ jtag_speed = 0;
+
+ if (jtag_interface && (jtag_interface[0] != 0))
+ /* configuration var 'jtag_interface' is set, and not empty */
+ for (i = 0; jtag_interfaces[i]; i++)
+ {
+ if (strcmp(jtag_interface, jtag_interfaces[i]->name) == 0)
+ {
+ jtag_device_t *device;
+ device = jtag_devices;
+
+ if (jtag_interfaces[i]->init() != ERROR_OK)
+ return ERROR_JTAG_INIT_FAILED;
+ jtag = jtag_interfaces[i];
+
+ jtag_ir_scan_size = 0;
+ jtag_num_devices = 0;
+ while (device != NULL)
+ {
+ jtag_ir_scan_size += device->ir_length;
+ jtag_num_devices++;
+ device = device->next;
+ }
+
+ jtag_add_statemove(TAP_TLR);
+ jtag_execute_queue();
+
+ jtag_validate_chain();
+
+ return ERROR_OK;
+ }
+ }
+
+ /* no valid interface was found (i.e. the configuration option,
+ * didn't match one of the compiled-in interfaces
+ */
+ ERROR("No valid jtag interface found (%s)", jtag_interface);
+ jtag = NULL;
+ return ERROR_JTAG_INVALID_INTERFACE;
+}
+
+int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int i;
+
+ /* only if the configuration var isn't overwritten from cmdline */
+ if (!jtag_interface)
+ {
+ if (args[0] && (args[0][0] != 0))
+ {
+ for (i=0; jtag_interfaces[i]; i++)
+ {
+ if (strcmp(args[0], jtag_interfaces[i]->name) == 0)
+ {
+ if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK)
+ exit(-1);
+
+ jtag_interface = jtag_interfaces[i]->name;
+
+ return ERROR_OK;
+ }
+ }
+ }
+
+ /* remember the requested interface name, so we can complain about it later */
+ jtag_interface = strdup(args[0]);
+ DEBUG("'interface' command didn't specify a valid interface");
+ }
+
+ return ERROR_OK;
+}
+
+int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ jtag_device_t **last_device_p = &jtag_devices;
+
+ if (*last_device_p)
+ {
+ while ((*last_device_p)->next)
+ last_device_p = &((*last_device_p)->next);
+ last_device_p = &((*last_device_p)->next);
+ }
+
+ if (argc < 3)
+ return ERROR_OK;
+
+ *last_device_p = malloc(sizeof(jtag_device_t));
+ (*last_device_p)->ir_length = strtoul(args[0], NULL, 0);
+
+ (*last_device_p)->expected = malloc((*last_device_p)->ir_length);
+ buf_set_u32((*last_device_p)->expected, 0, (*last_device_p)->ir_length, strtoul(args[1], NULL, 0));
+ (*last_device_p)->expected_mask = malloc((*last_device_p)->ir_length);
+ buf_set_u32((*last_device_p)->expected_mask, 0, (*last_device_p)->ir_length, strtoul(args[2], NULL, 0));
+
+ (*last_device_p)->cur_instr = malloc((*last_device_p)->ir_length);
+ (*last_device_p)->bypass = 1;
+ buf_set_ones((*last_device_p)->cur_instr, (*last_device_p)->ir_length);
+
+ (*last_device_p)->next = NULL;
+
+ jtag_register_event_callback(jtag_reset_callback, (*last_device_p));
+
+ jtag_num_devices++;
+
+ return ERROR_OK;
+}
+
+int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ jtag_device_t *device = jtag_devices;
+ int device_count = 0;
+
+ while (device)
+ {
+ u32 expected, expected_mask, cur_instr;
+ expected = buf_get_u32(device->expected, 0, device->ir_length);
+ expected_mask = buf_get_u32(device->expected_mask, 0, device->ir_length);
+ cur_instr = buf_get_u32(device->cur_instr, 0, device->ir_length);
+ command_print(cmd_ctx, "%i: idcode: 0x%8.8x ir length %i, ir capture 0x%x, ir mask 0x%x, current instruction 0x%x", device_count, device->idcode, device->ir_length, expected, expected_mask, cur_instr);
+ device = device->next;
+ device_count++;
+ }
+
+ return ERROR_OK;
+}
+
+int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc >= 1)
+ {
+ if (strcmp(args[0], "none") == 0)
+ jtag_reset_config = RESET_NONE;
+ else if (strcmp(args[0], "trst_only") == 0)
+ jtag_reset_config = RESET_HAS_TRST;
+ else if (strcmp(args[0], "srst_only") == 0)
+ jtag_reset_config = RESET_HAS_SRST;
+ else if (strcmp(args[0], "trst_and_srst") == 0)
+ jtag_reset_config = RESET_TRST_AND_SRST;
+ else
+ {
+ ERROR("invalid reset_config argument");
+ exit(-1);
+ }
+ }
+
+ if (argc >= 2)
+ {
+ if (strcmp(args[1], "srst_pulls_trst") == 0)
+ jtag_reset_config |= RESET_SRST_PULLS_TRST;
+ else if (strcmp(args[1], "trst_pulls_srst") == 0)
+ jtag_reset_config |= RESET_TRST_PULLS_SRST;
+ else if (strcmp(args[1], "combined") == 0)
+ jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST;
+ else if (strcmp(args[1], "separate") == 0)
+ jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST);
+ else
+ {
+ ERROR("invalid reset_config argument");
+ exit(-1);
+ }
+ }
+
+ if (argc >= 3)
+ {
+ if (strcmp(args[2], "trst_open_drain") == 0)
+ jtag_reset_config |= RESET_TRST_OPEN_DRAIN;
+ else if (strcmp(args[2], "trst_push_pull") == 0)
+ jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN;
+ else
+ {
+ ERROR("invalid reset_config argument");
+ exit(-1);
+ }
+ }
+
+ if (argc >= 4)
+ {
+ if (strcmp(args[3], "srst_push_pull") == 0)
+ jtag_reset_config |= RESET_SRST_PUSH_PULL;
+ else if (strcmp(args[3], "srst_open_drain") == 0)
+ jtag_reset_config &= ~RESET_SRST_PUSH_PULL;
+ else
+ {
+ ERROR("invalid reset_config argument");
+ exit(-1);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ command_print(cmd_ctx, "jtag_speed: %i", jtag_speed);
+
+ if (argc > 0)
+ {
+ /* this command can be called during CONFIG,
+ * in which case jtag isn't initialized */
+ if (jtag)
+ jtag->speed(strtoul(args[0], NULL, 0));
+ else
+ jtag_speed = strtoul(args[0], NULL, 0);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ enum tap_state state;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "usage: endstate <tap_state>");
+ return ERROR_OK;
+ }
+
+ for (state = 0; state < 16; state++)
+ {
+ if (strcmp(args[0], tap_state_strings[state]) == 0)
+ {
+ jtag_add_end_state(state);
+ jtag_execute_queue();
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int trst = -1;
+ int srst = -1;
+ char *usage = "usage: jtag_reset <trst> <srst>";
+ int retval;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, usage);
+ return ERROR_OK;
+ }
+
+ if (args[0][0] == '1')
+ trst = 1;
+ else if (args[0][0] == '0')
+ trst = 0;
+ else
+ {
+ command_print(cmd_ctx, usage);
+ return ERROR_OK;
+ }
+
+ if (args[1][0] == '1')
+ srst = 1;
+ else if (args[1][0] == '0')
+ srst = 0;
+ else
+ {
+ command_print(cmd_ctx, usage);
+ return ERROR_OK;
+ }
+
+ if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_JTAG_RESET_WOULD_ASSERT_TRST:
+ command_print(cmd_ctx, "requested reset would assert trst\nif this is acceptable, use jtag_reset 1 %c", args[1][0]);
+ break;
+ case ERROR_JTAG_RESET_CANT_SRST:
+ command_print(cmd_ctx, "can't assert srst because the current reset_config doesn't support it");
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error");
+ }
+ }
+ jtag_execute_queue();
+
+ return ERROR_OK;
+}
+
+int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "usage: runtest <num_cycles>");
+ return ERROR_OK;
+ }
+
+ jtag_add_runtest(strtol(args[0], NULL, 0), -1);
+ jtag_execute_queue();
+
+ return ERROR_OK;
+
+}
+
+int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ enum tap_state state;
+
+ state = -1;
+ if (argc == 1)
+ {
+ for (state = 0; state < 16; state++)
+ {
+ if (strcmp(args[0], tap_state_strings[state]) == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ jtag_add_statemove(state);
+ jtag_execute_queue();
+
+ return ERROR_OK;
+
+}
+
+int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int i;
+ scan_field_t *fields;
+
+ if ((argc < 2) || (argc % 2))
+ {
+ command_print(cmd_ctx, "usage: irscan <device> <instr> [dev2] [instr2] ...");
+ return ERROR_OK;
+ }
+
+ fields = malloc(sizeof(scan_field_t) * argc / 2);
+
+ for (i = 0; i < argc / 2; i++)
+ {
+ int device = strtoul(args[i*2], NULL, 0);
+ int field_size = jtag_get_device(device)->ir_length;
+ fields[i].device = device;
+ fields[i].out_value = malloc(CEIL(field_size, 8));
+ buf_set_u32(fields[i].out_value, 0, field_size, strtoul(args[i*2+1], NULL, 0));
+ fields[i].out_mask = NULL;
+ fields[i].in_value = NULL;
+ fields[i].in_check_mask = NULL;
+ fields[i].in_handler = NULL;
+ fields[i].in_handler_priv = NULL;
+ }
+
+ jtag_add_ir_scan(argc / 2, fields, -1);
+ jtag_execute_queue();
+
+ for (i = 0; i < argc / 2; i++)
+ free(fields[i].out_value);
+
+ free (fields);
+
+ return ERROR_OK;
+}
+
+int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ scan_field_t *fields;
+ int num_fields = 0;
+ int field_count = 0;
+ var_t *var;
+ int i, j;
+
+ if ((argc < 2) || (argc % 2))
+ {
+ command_print(cmd_ctx, "usage: drscan <device> <var> [dev2] [var2]");
+ return ERROR_OK;
+ }
+
+ for (i = 0; i < argc; i+=2)
+ {
+ var = get_var_by_namenum(args[i+1]);
+ if (var)
+ {
+ num_fields += var->num_fields;
+ }
+ else
+ {
+ command_print(cmd_ctx, "variable %s doesn't exist", args[i+1]);
+ return ERROR_OK;
+ }
+ }
+
+ fields = malloc(sizeof(scan_field_t) * num_fields);
+
+ for (i = 0; i < argc; i+=2)
+ {
+ var = get_var_by_namenum(args[i+1]);
+
+ for (j = 0; j < var->num_fields; j++)
+ {
+ fields[field_count].device = strtol(args[i], NULL, 0);
+ fields[field_count].num_bits = var->fields[j].num_bits;
+ fields[field_count].out_value = malloc(CEIL(var->fields[j].num_bits, 8));
+ buf_set_u32(fields[field_count].out_value, 0, var->fields[j].num_bits, var->fields[j].value);
+ fields[field_count].out_mask = NULL;
+ fields[field_count].in_value = fields[field_count].out_value;
+ fields[field_count].in_check_mask = NULL;
+ fields[field_count].in_check_value = NULL;
+ fields[field_count].in_handler = field_le_to_host;
+ fields[field_count++].in_handler_priv = &(var->fields[j]);
+ }
+ }
+
+ jtag_add_dr_scan(num_fields, fields, -1);
+ jtag_execute_queue();
+
+ for (i = 0; i < argc / 2; i++)
+ free(fields[i].out_value);
+
+ free(fields);
+
+ return ERROR_OK;
+}
+
+int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ {
+ command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled");
+ return ERROR_OK;
+ }
+
+ if (strcmp(args[0], "enable") == 0)
+ {
+ jtag_verify_capture_ir = 1;
+ }
+ else if (strcmp(args[0], "disable") == 0)
+ {
+ jtag_verify_capture_ir = 0;
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
new file mode 100644
index 00000000..124150ce
--- /dev/null
+++ b/src/jtag/jtag.h
@@ -0,0 +1,270 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef JTAG_H
+#define JTAG_H
+
+#include "types.h"
+#include "binarybuffer.h"
+
+#include "command.h"
+
+#if 0
+#define _DEBUG_JTAG_IO_
+#endif
+
+/* Tap States
+ * TLR - Test-Logic-Reset, RTI - Run-Test/Idle,
+ * SDS - Select-DR-Scan, CD - Capture-DR, SD - Shift-DR, E1D - Exit1-DR,
+ * PD - Pause-DR, E2D - Exit2-DR, UD - Update-DR,
+ * SIS - Select-IR-Scan, CI - Capture-IR, SI - Shift-IR, E1I - Exit1-IR,
+ * PI - Pause-IR, E2I - Exit2-IR, UI - Update-IR
+ */
+enum tap_state
+{
+ TAP_TLR = 0x0, TAP_RTI = 0x8,
+ TAP_SDS = 0x1, TAP_CD = 0x2, TAP_SD = 0x3, TAP_E1D = 0x4,
+ TAP_PD = 0x5, TAP_E2D = 0x6, TAP_UD = 0x7,
+ TAP_SIS = 0x9, TAP_CI = 0xa, TAP_SI = 0xb, TAP_E1I = 0xc,
+ TAP_PI = 0xd, TAP_E2I = 0xe, TAP_UI = 0xf
+};
+
+typedef struct tap_transition_s
+{
+ enum tap_state high;
+ enum tap_state low;
+} tap_transition_t;
+
+extern char* tap_state_strings[16];
+extern int tap_move_map[16]; /* map 16 TAP states to 6 stable states */
+extern u8 tap_move[6][6]; /* value scanned to TMS to move from one of six stable states to another */
+extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */
+
+extern enum tap_state end_state; /* finish DR scans in dr_end_state */
+extern enum tap_state cur_state; /* current TAP state */
+
+#define TAP_MOVE(from, to) tap_move[tap_move_map[from]][tap_move_map[to]]
+
+typedef struct scan_field_s
+{
+ int device; /* ordinal device number this instruction refers to */
+ int num_bits; /* number of bits this field specifies (up to 32) */
+ u8 *out_value; /* value to be scanned into the device */
+ u8 *out_mask; /* only masked bits care */
+ u8 *in_value; /* pointer to a 32-bit memory location to take data scanned out */
+ u8 *in_check_value; /* used to validate scan results */
+ u8 *in_check_mask; /* check specified bits against check_value */
+ int (*in_handler)(u8 *in_value, void *priv); /* process received buffer using this handler */
+ void *in_handler_priv; /* additional information for the in_handler */
+} scan_field_t;
+
+enum scan_type
+{
+ /* IN: from device to host, OUT: from host to device */
+ SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3
+};
+
+typedef struct scan_command_s
+{
+ int ir_scan; /* instruction/not data scan */
+ int num_fields; /* number of fields in *fields array */
+ scan_field_t *fields; /* pointer to an array of data scan fields */
+ enum tap_state end_state; /* TAP state in which JTAG commands should finish */
+} scan_command_t;
+
+typedef struct statemove_command_s
+{
+ enum tap_state end_state; /* TAP state in which JTAG commands should finish */
+} statemove_command_t;
+
+typedef struct pathmove_command_s
+{
+ int num_states; /* number of states in *path */
+ enum tap_state *path; /* states that have to be passed */
+} pathmove_command_t;
+
+typedef struct runtest_command_s
+{
+ int num_cycles; /* number of cycles that should be spent in Run-Test/Idle */
+ enum tap_state end_state; /* TAP state in which JTAG commands should finish */
+} runtest_command_t;
+
+typedef struct reset_command_s
+{
+ int trst; /* trst/srst 0: deassert, 1: assert, -1: don't change */
+ int srst;
+} reset_command_t;
+
+typedef struct end_state_command_s
+{
+ enum tap_state end_state; /* TAP state in which JTAG commands should finish */
+} end_state_command_t;
+
+typedef struct sleep_command_s
+{
+ u32 us; /* number of microseconds to sleep */
+} sleep_command_t;
+
+typedef union jtag_command_container_u
+{
+ scan_command_t *scan;
+ statemove_command_t *statemove;
+ pathmove_command_t *pathmove;
+ runtest_command_t *runtest;
+ reset_command_t *reset;
+ end_state_command_t *end_state;
+ sleep_command_t *sleep;
+} jtag_command_container_t;
+
+enum jtag_command_type
+{
+ JTAG_SCAN = 1,
+ JTAG_STATEMOVE = 2, JTAG_RUNTEST = 3,
+ JTAG_RESET = 4, JTAG_END_STATE = 5,
+ JTAG_PATHMOVE = 6, JTAG_SLEEP = 7
+};
+
+typedef struct jtag_command_s
+{
+ jtag_command_container_t cmd;
+ enum jtag_command_type type;
+ struct jtag_command_s *next;
+} jtag_command_t;
+
+extern jtag_command_t *jtag_command_queue;
+
+typedef struct jtag_device_s
+{
+ int ir_length; /* size of instruction register */
+ u8 *expected; /* Capture-IR expected value */
+ u8 *expected_mask; /* Capture-IR expected mask */
+ u32 idcode; /* device identification code */
+ u8 *cur_instr; /* current instruction */
+ int bypass; /* bypass register selected */
+ struct jtag_device_s *next;
+} jtag_device_t;
+
+extern jtag_device_t *jtag_devices;
+extern int jtag_num_devices;
+extern int jtag_ir_scan_size;
+
+enum reset_line_mode
+{
+ LINE_OPEN_DRAIN = 0x0,
+ LINE_PUSH_PULL = 0x1,
+};
+
+typedef struct jtag_interface_s
+{
+ char* name;
+
+ /* queued command execution
+ */
+ int (*execute_queue)(void);
+
+ /* optional command support
+ */
+ int support_statemove;
+
+ /* interface initalization
+ */
+ int (*speed)(int speed);
+ int (*register_commands)(struct command_context_s *cmd_ctx);
+ int (*init)(void);
+ int (*quit)(void);
+
+} jtag_interface_t;
+
+enum jtag_event
+{
+ JTAG_SRST_ASSERTED,
+ JTAG_TRST_ASSERTED,
+ JTAG_SRST_RELEASED,
+ JTAG_TRST_RELEASED,
+};
+
+typedef struct jtag_event_callback_s
+{
+ int (*callback)(enum jtag_event event, void *priv);
+ void *priv;
+ struct jtag_event_callback_s *next;
+} jtag_event_callback_t;
+
+extern jtag_event_callback_t *jtag_event_callbacks;
+
+extern jtag_interface_t *jtag; /* global pointer to configured JTAG interface */
+extern enum tap_state end_state;
+extern enum tap_state cur_state;
+
+extern char* jtag_interface;
+extern int jtag_speed;
+
+enum reset_types
+{
+ RESET_NONE = 0x0,
+ RESET_HAS_TRST = 0x1,
+ RESET_HAS_SRST = 0x2,
+ RESET_TRST_AND_SRST = 0x3,
+ RESET_SRST_PULLS_TRST = 0x4,
+ RESET_TRST_PULLS_SRST = 0x8,
+ RESET_TRST_OPEN_DRAIN = 0x10,
+ RESET_SRST_PUSH_PULL = 0x20,
+};
+
+extern enum reset_types jtag_reset_config;
+
+/* JTAG subsystem */
+extern int jtag_init(struct command_context_s *cmd_ctx);
+extern int jtag_register_commands(struct command_context_s *cmd_ctx);
+
+/* JTAG interface */
+extern int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
+extern int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
+extern int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
+extern int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
+extern int jtag_add_statemove(enum tap_state endstate);
+extern int jtag_add_pathmove(int num_states, enum tap_state *path);
+extern int jtag_add_runtest(int num_cycles, enum tap_state endstate);
+extern int jtag_add_reset(int trst, int srst);
+extern int jtag_add_end_state(enum tap_state endstate);
+extern int jtag_add_sleep(u32 us);
+extern int jtag_execute_queue(void);
+extern int jtag_cancel_queue(void);
+
+/* JTAG support functions */
+extern enum scan_type jtag_scan_type(scan_command_t *cmd);
+extern int jtag_scan_size(scan_command_t *cmd);
+extern int jtag_read_buffer(u8 *buffer, scan_command_t *cmd);
+extern int jtag_build_buffer(scan_command_t *cmd, u8 **buffer);
+extern jtag_device_t* jtag_get_device(int num);
+extern void jtag_sleep(u32 us);
+extern int jtag_call_event_callbacks(enum jtag_event event);
+extern int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv);
+
+/* error codes
+ * JTAG subsystem uses codes between -100 and -199 */
+
+#define ERROR_JTAG_INIT_FAILED (-100)
+#define ERROR_JTAG_INVALID_INTERFACE (-101)
+#define ERROR_JTAG_NOT_IMPLEMENTED (-102)
+#define ERROR_JTAG_TRST_ASSERTED (-103)
+#define ERROR_JTAG_QUEUE_FAILED (-104)
+#define ERROR_JTAG_RESET_WOULD_ASSERT_TRST (-105)
+#define ERROR_JTAG_RESET_CANT_SRST (-106)
+#endif /* JTAG_H */
diff --git a/src/jtag/parport.c b/src/jtag/parport.c
new file mode 100644
index 00000000..8265ada8
--- /dev/null
+++ b/src/jtag/parport.c
@@ -0,0 +1,351 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * 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. *
+ ***************************************************************************/
+#include "config.h"
+#include "log.h"
+#include "jtag.h"
+#include "bitbang.h"
+
+/* system includes */
+// -ino: 060521-1036
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <machine/sysarch.h>
+#include <machine/cpufunc.h>
+#define ioperm(startport,length,enable)\
+ i386_set_ioperm((startport), (length), (enable))
+#else
+#include <sys/io.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if PARPORT_USE_PPDEV == 1
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#endif
+
+/* parallel port cable description
+ */
+typedef struct cable_s
+{
+ char* name;
+ u8 TDO_MASK; /* status port bit containing current TDO value */
+ u8 TRST_MASK; /* data port bit for TRST */
+ u8 TMS_MASK; /* data port bit for TMS */
+ u8 TCK_MASK; /* data port bit for TCK */
+ u8 TDI_MASK; /* data port bit for TDI */
+ u8 SRST_MASK; /* data port bit for SRST */
+ u8 OUTPUT_INVERT; /* data port bits that should be inverted */
+ u8 INPUT_INVERT; /* status port that should be inverted */
+ u8 PORT_INIT; /* initialize data port with this value */
+} cable_t;
+
+cable_t cables[] =
+{
+ /* name tdo trst tms tck tdi srst o_inv i_inv init */
+ { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80 },
+ { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80 },
+ { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
+ { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10 },
+ { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
+ { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+/* configuration */
+char* parport_cable;
+unsigned long parport_port;
+
+/* interface variables
+ */
+static cable_t* cable;
+static u8 dataport_value = 0x0;
+
+#if PARPORT_USE_PPDEV == 1
+static int device_handle;
+#else
+static unsigned long dataport;
+static unsigned long statusport;
+#endif
+
+/* low level command set
+ */
+int parport_read(void);
+void parport_write(int tck, int tms, int tdi);
+void parport_reset(int trst, int srst);
+
+int parport_speed(int speed);
+int parport_register_commands(struct command_context_s *cmd_ctx);
+int parport_init(void);
+int parport_quit(void);
+
+/* interface commands */
+int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+jtag_interface_t parport_interface =
+{
+ .name = "parport",
+
+ .execute_queue = bitbang_execute_queue,
+
+ .support_statemove = 0,
+
+ .speed = parport_speed,
+ .register_commands = parport_register_commands,
+ .init = parport_init,
+ .quit = parport_quit,
+};
+
+bitbang_interface_t parport_bitbang =
+{
+ .read = parport_read,
+ .write = parport_write,
+ .reset = parport_reset
+};
+
+int parport_read(void)
+{
+ int data = 0;
+
+#if PARPORT_USE_PPDEV == 1
+ ioctl(device_handle, PPRSTATUS, & data);
+#else
+ data = inb(statusport);
+#endif
+
+ if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
+ return 1;
+ else
+ return 0;
+}
+
+void parport_write(int tck, int tms, int tdi)
+{
+ u8 output;
+ int i = jtag_speed + 1;
+
+ if (tck)
+ dataport_value |= cable->TCK_MASK;
+ else
+ dataport_value &= ~cable->TCK_MASK;
+
+ if (tms)
+ dataport_value |= cable->TMS_MASK;
+ else
+ dataport_value &= ~cable->TMS_MASK;
+
+ if (tdi)
+ dataport_value |= cable->TDI_MASK;
+ else
+ dataport_value &= ~cable->TDI_MASK;
+
+ output = dataport_value ^ cable->OUTPUT_INVERT;
+
+ while (i-- > 0)
+#if PARPORT_USE_PPDEV == 1
+ ioctl(device_handle, PPWDATA, &output);
+#else
+#ifdef __FreeBSD__
+ outb(dataport, output);
+#else
+ outb(output, dataport);
+#endif
+#endif
+}
+
+/* (1) assert or (0) deassert reset lines */
+void parport_reset(int trst, int srst)
+{
+ u8 output;
+ DEBUG("trst: %i, srst: %i", trst, srst);
+
+ if (trst == 0)
+ dataport_value |= cable->TRST_MASK;
+ else if (trst == 1)
+ dataport_value &= ~cable->TRST_MASK;
+
+ if (srst == 0)
+ dataport_value |= cable->SRST_MASK;
+ else if (srst == 1)
+ dataport_value &= ~cable->SRST_MASK;
+
+ output = dataport_value ^ cable->OUTPUT_INVERT;
+
+#if PARPORT_USE_PPDEV == 1
+ ioctl(device_handle, PPWDATA, &output);
+#else
+#ifdef __FreeBSD__
+ outb(dataport, output);
+#else
+ outb(output, dataport);
+#endif
+#endif
+
+}
+
+int parport_speed(int speed)
+{
+ jtag_speed = speed;
+
+ return ERROR_OK;
+}
+
+int parport_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
+ COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+int parport_init(void)
+{
+ cable_t *cur_cable;
+#if PARPORT_USE_PPDEV == 1
+ char buffer[256];
+ int i = 0;
+#endif
+
+ cur_cable = cables;
+
+ if ((parport_cable == NULL) || (parport_cable[0] == 0))
+ {
+ parport_cable = "wiggler";
+ WARNING("No parport cable specified, using default 'wiggler'");
+ }
+
+ while (cur_cable->name)
+ {
+ if (strcmp(cur_cable->name, parport_cable) == 0)
+ {
+ cable = cur_cable;
+ break;
+ }
+ cur_cable++;
+ }
+
+ if (!cable)
+ {
+ ERROR("No matching cable found for %s", parport_cable);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ dataport_value = cable->PORT_INIT;
+
+#if PARPORT_USE_PPDEV == 1
+ if (device_handle>0)
+ {
+ ERROR("device is already opened");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ snprintf(buffer, 256, "/dev/parport%d", parport_port);
+ device_handle = open(buffer, O_WRONLY);
+
+ if (device_handle<0)
+ {
+ ERROR("cannot open device. check it exists and that user read and write rights are set");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i=ioctl(device_handle, PPCLAIM);
+ if (i<0)
+ {
+ ERROR("cannot claim device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = PARPORT_MODE_COMPAT;
+ i= ioctl(device_handle, PPSETMODE, & i);
+ if (i<0)
+ {
+ ERROR(" cannot set compatible mode to device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = IEEE1284_MODE_COMPAT;
+ i = ioctl(device_handle, PPNEGOT, & i);
+ if (i<0)
+ {
+ ERROR("cannot set compatible 1284 mode to device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+#else
+ if (parport_port == 0)
+ {
+ parport_port = 0x378;
+ WARNING("No parport port specified, using default '0x378' (LPT1)");
+ }
+
+ dataport = parport_port;
+ statusport = parport_port + 1;
+
+ if (ioperm(dataport, 3, 1) != 0) {
+ ERROR("missing privileges for direct i/o");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+#endif
+
+ parport_reset(0, 0);
+ parport_write(0, 0, 0);
+
+ bitbang_interface = &parport_bitbang;
+
+ return ERROR_OK;
+}
+
+int parport_quit(void)
+{
+
+ return ERROR_OK;
+}
+
+int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ return ERROR_OK;
+
+ /* only if the port wasn't overwritten by cmdline */
+ if (parport_port == 0)
+ parport_port = strtoul(args[0], NULL, 0);
+
+ return ERROR_OK;
+}
+
+int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ return ERROR_OK;
+
+ /* only if the cable name wasn't overwritten by cmdline */
+ if (parport_cable == 0)
+ {
+ parport_cable = malloc(strlen(args[0]) + sizeof(char));
+ strcpy(parport_cable, args[0]);
+ }
+
+ return ERROR_OK;
+}