jtag_add_shift() fn - minidriver work in progress.
[openocd.git] / src / jtag / jtag.c
index 5ae7462163f4b5c2c8d2b7575b6439fcba032954..985cf8c2df6337040f1930da5749dd9544284cb4 100644 (file)
 #include "string.h"
 #include <unistd.h>
 
+#ifndef MINIDRIVER
+/* this allows JTAG devices to implement the entire jtag_xxx() layer in hw/sw */
+#define MINIDRIVER(a) a
+#endif
+
+
+/* note that this is not marked as static as it must be available from outside jtag.c for those 
+   that implement the jtag_xxx() minidriver layer 
+*/
+int jtag_error=ERROR_OK; 
+
+
 char* tap_state_strings[16] =
 {
        "tlr", 
@@ -58,6 +70,8 @@ static cmd_queue_page_t *cmd_queue_pages = NULL;
  * 3: Pause-DR
  * 4: Shift-IR
  * 5: Pause-IR
+ * 
+ * SD->SD and SI->SI have to be caught in interface specific code
  */
 u8 tap_move[6][6] =
 {
@@ -95,6 +109,14 @@ tap_transition_t tap_transitions[16] =
        {TAP_SDS, TAP_RTI}              /* UI  */
 };
 
+char* jtag_event_strings[] =
+{
+       "SRST asserted",
+       "TRST asserted",
+       "SRST released",
+       "TRST released"
+};
+
 enum tap_state end_state = TAP_TLR;
 enum tap_state cur_state = TAP_TLR;
 int jtag_trst = 0;
@@ -115,6 +137,10 @@ int jtag_verify_capture_ir = 1;
 int jtag_nsrst_delay = 0; /* default to no nSRST delay */
 int jtag_ntrst_delay = 0; /* default to no nTRST delay */ 
 
+/* maximum number of JTAG devices expected in the chain
+ */
+#define JTAG_MAX_CHAIN_SIZE 20 
+
 /* callbacks to inform high-level handlers about JTAG state changes */
 jtag_event_callback_t *jtag_event_callbacks;
 
@@ -144,6 +170,18 @@ jtag_event_callback_t *jtag_event_callbacks;
        extern jtag_interface_t at91rm9200_interface;
 #endif
 
+#if BUILD_GW16012 == 1
+       extern jtag_interface_t gw16012_interface;
+#endif
+
+#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
+       extern jtag_interface_t presto_interface;
+#endif
+
+#if BUILD_USBPROG == 1
+       extern jtag_interface_t usbprog_interface;
+#endif
+
 jtag_interface_t *jtag_interfaces[] = {
 #if BUILD_PARPORT == 1
        &parport_interface,
@@ -162,6 +200,15 @@ jtag_interface_t *jtag_interfaces[] = {
 #endif
 #if BUILD_AT91RM9200 == 1
        &at91rm9200_interface,
+#endif
+#if BUILD_GW16012 == 1
+       &gw16012_interface,
+#endif
+#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
+       &presto_interface,
+#endif
+#if BUILD_USBPROG == 1
+       &usbprog_interface,
 #endif
        NULL,
 };
@@ -169,10 +216,19 @@ jtag_interface_t *jtag_interfaces[] = {
 jtag_interface_t *jtag = NULL;
 
 /* configuration */
-char* jtag_interface = NULL;
-int jtag_speed = -1;
+jtag_interface_t *jtag_interface = NULL;
+int jtag_speed = 0;
+
 
 /* forward declarations */
+int jtag_add_statemove(enum tap_state endstate);
+int jtag_add_pathmove(int num_states, enum tap_state *path);
+int jtag_add_runtest(int num_cycles, enum tap_state endstate);
+int jtag_add_reset(int trst, int srst);
+int jtag_add_end_state(enum tap_state endstate);
+int jtag_add_sleep(u32 us);
+int jtag_execute_queue(void);
+int jtag_cancel_queue(void);
 
 /* jtag commands */
 int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -244,7 +300,7 @@ int jtag_call_event_callbacks(enum jtag_event event)
 {
        jtag_event_callback_t *callback = jtag_event_callbacks;
        
-       DEBUG("jtag event: %i", event);
+       DEBUG("jtag event: %s", jtag_event_strings[event]);
        
        while (callback)
        {
@@ -287,8 +343,9 @@ jtag_device_t* jtag_get_device(int num)
                device = device->next;
                i++;
        }
-
-       return NULL;
+       
+       ERROR("jtag device number %d not defined", num);
+       exit(-1);
 }
 
 void* cmd_queue_alloc(size_t size)
@@ -315,7 +372,8 @@ void* cmd_queue_alloc(size_t size)
        offset = (*p_page)->used;
        (*p_page)->used += size;
        
-       return ((*p_page)->address) + offset;
+       u8 *t=(u8 *)((*p_page)->address);
+       return t + offset;
 }
 
 void cmd_queue_free()
@@ -335,38 +393,38 @@ void cmd_queue_free()
 
 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)");
+               jtag_error=ERROR_JTAG_TRST_ASSERTED;
                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 (state != -1)
+               cmd_queue_end_state = state;
 
-       if (!changed)
-               return ERROR_OK;
-       */
+       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;
+       
+       int retval=interface_jtag_add_ir_scan(num_fields, fields, state);
+       if (retval!=ERROR_OK)
+               jtag_error=retval;
+       return retval;
+}
+
+int MINIDRIVER(interface_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;
+
+
        last_cmd = jtag_get_last_command_p();
        
        /* allocate memory for a new list member */
@@ -381,19 +439,8 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        (*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++)
+       for (i = 0; i < jtag_num_devices; i++)
        {
                int found = 0;
                device = jtag_get_device(i);
@@ -401,27 +448,30 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                (*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;
+               (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;     /* disable verification by default */
 
                /* search the list */
-               for (j=0; j < num_fields; j++)
+               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);
+                       
+                               if (jtag_verify_capture_ir)
+                               {
+                                       if (fields[j].in_handler==NULL)
+                                       {
+                                               jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL);
+                                       } else
+                                       {
+                                               (*last_cmd)->cmd.scan->fields[i].in_handler = fields[j].in_handler;
+                                               (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[j].in_handler_priv;
+                                               (*last_cmd)->cmd.scan->fields[i].in_check_value = device->expected; 
+                                               (*last_cmd)->cmd.scan->fields[i].in_check_mask = device->expected_mask;
+                                       }
+                               }
                                
                                device->bypass = 0;
                                break;
@@ -446,15 +496,31 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
 
 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;
+               return jtag_error=ERROR_JTAG_TRST_ASSERTED;
        }
 
+       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 interface_jtag_add_plain_ir_scan(num_fields, fields, state);
+}
+
+int MINIDRIVER(interface_jtag_add_plain_ir_scan)(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+       int i;
+       jtag_command_t **last_cmd;
+       
        last_cmd = jtag_get_last_command_p();
        
        /* allocate memory for a new list member */
@@ -470,17 +536,6 @@ int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state
        (*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;
@@ -490,8 +545,8 @@ int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state
                (*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_check_value = fields[i].in_check_value;
+               (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
                (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
                (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
        }
@@ -499,19 +554,36 @@ int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state
 }
 
 int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+{
+       if (jtag_trst == 1)
+       {
+               WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+               return jtag_error=ERROR_JTAG_TRST_ASSERTED;
+       }
+
+       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 interface_jtag_add_dr_scan(num_fields, fields, state);
+}
+
+int MINIDRIVER(interface_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;
-       }
+       jtag_command_t **last_cmd = jtag_get_last_command_p();
+       jtag_device_t *device = jtag_devices;
 
        /* count devices in bypass */
        while (device)
@@ -533,24 +605,13 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        (*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++)
+       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++)
+               for (j = 0; j < num_fields; j++)
                {
                        if (i == fields[j].device)
                        {
@@ -560,8 +621,8 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                                (*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_check_value = fields[j].in_check_value;
+                               (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask;
                                (*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;
                        }
@@ -590,25 +651,41 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                        /* 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);
+                               WARNING("scan data for a device in BYPASS");
                        }
                }
        }
        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;
+               return jtag_error=ERROR_JTAG_TRST_ASSERTED;
        }
 
+       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 interface_jtag_add_plain_dr_scan(num_fields, fields, state);
+}
+
+int MINIDRIVER(interface_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();
+       
        /* allocate memory for a new list member */
        *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
        last_comand_pointer = &((*last_cmd)->next);
@@ -622,17 +699,6 @@ int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state
        (*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;
@@ -642,8 +708,8 @@ int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state
                (*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_check_value = fields[i].in_check_value;
+               (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
                (*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;
        }
@@ -652,23 +718,12 @@ int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state
 }
 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;
+               return jtag_error=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;
 
@@ -679,75 +734,42 @@ int jtag_add_statemove(enum tap_state state)
                jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
                        
        cmd_queue_cur_state = cmd_queue_end_state;
+
+       return interface_jtag_add_statemove(state);
+}
+
+int MINIDRIVER(interface_jtag_add_statemove)(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_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;
+       
        
        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;
+               return jtag_error=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;
+               return jtag_error=ERROR_JTAG_NOT_IMPLEMENTED;
        }
        
-       if (jtag->support_pathmove)
-       {
-               /* 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);
        
@@ -755,20 +777,36 @@ int jtag_add_pathmove(int num_states, enum tap_state *path)
                jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
        
        cmd_queue_cur_state = path[num_states - 1];
+
+       return interface_jtag_add_pathmove(num_states, path);
+}
+
+
+int MINIDRIVER(interface_jtag_add_pathmove)(int num_states, enum tap_state *path)
+{
+       jtag_command_t **last_cmd = jtag_get_last_command_p();
+       int i;
+       
+       /* 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_PATHMOVE;
+
+       (*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];
        
        return ERROR_OK;
 }
 
-int jtag_add_runtest(int num_cycles, enum tap_state state)
+int MINIDRIVER(interface_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;
@@ -779,6 +817,18 @@ int jtag_add_runtest(int num_cycles, enum tap_state state)
        (*last_cmd)->cmd.runtest->num_cycles = num_cycles;
        (*last_cmd)->cmd.runtest->end_state = state;
        
+       return ERROR_OK;
+}
+
+int jtag_add_runtest(int num_cycles, enum tap_state state)
+{
+       if (jtag_trst == 1)
+       {
+               jtag_error=ERROR_JTAG_QUEUE_FAILED;
+               WARNING("JTAG command queued, while TRST is low (TAP in reset)");
+               return ERROR_JTAG_TRST_ASSERTED;
+       }
+       
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -790,14 +840,14 @@ int jtag_add_runtest(int num_cycles, enum tap_state state)
                        
        cmd_queue_cur_state = cmd_queue_end_state;
        
-       return ERROR_OK;
+       /* executed by sw or hw fifo */
+       return interface_jtag_add_runtest(num_cycles, state);
 }
 
 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();
+       int retval;
        
        if (req_trst == -1)
                req_trst = jtag_trst;
@@ -808,7 +858,9 @@ int jtag_add_reset(int req_trst, int req_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;
+       {
+               return jtag_error=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))
@@ -820,7 +872,7 @@ int jtag_add_reset(int req_trst, int req_srst)
        if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
        {
                ERROR("requested nSRST assertion, but the current configuration doesn't support this");
-               return ERROR_JTAG_RESET_CANT_SRST;
+               return jtag_error=ERROR_JTAG_RESET_CANT_SRST;
        }
        
        if (req_trst && !(jtag_reset_config & RESET_HAS_TRST))
@@ -828,20 +880,17 @@ int jtag_add_reset(int req_trst, int req_srst)
                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;
 
+       retval = interface_jtag_add_reset(req_trst, req_srst);
+       if (retval!=ERROR_OK)
+       {
+               jtag_error=retval;
+               return retval;
+       }
+
        if (jtag_srst)
        {
                jtag_call_event_callbacks(JTAG_SRST_ASSERTED);
@@ -855,47 +904,53 @@ int jtag_add_reset(int req_trst, int req_srst)
        
        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;
+               jtag_add_end_state(TAP_TLR);
+               jtag_add_statemove(TAP_TLR);
                
                return ERROR_OK;
        }
+       
+       if (jtag_trst)
+       {
+               /* we just asserted nTRST, so we're now in Test-Logic-Reset,
+                * and inform possible listeners about this
+                */
+               cmd_queue_cur_state = TAP_TLR;
+               jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+       }
        else
        {
-               if (jtag_trst)
-               {
-                       /* we just asserted nTRST, so we're now in Test-Logic-Reset,
-                        * and inform possible listeners about this
-                        */
-                       cmd_queue_cur_state = TAP_TLR;
-                       jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-               }
-               else
-               {
-                       /* the nTRST line got deasserted, so we're still in Test-Logic-Reset,
-                        * but we might want to add a delay to give the TAP time to settle
-                        */
-                       if (jtag_ntrst_delay)
-                               jtag_add_sleep(jtag_ntrst_delay * 1000);
-               }
+               /* the nTRST line got deasserted, so we're still in Test-Logic-Reset,
+                * but we might want to add a delay to give the TAP time to settle
+                */
+               if (jtag_ntrst_delay)
+                       jtag_add_sleep(jtag_ntrst_delay * 1000);
        }
+       
+       return retval;
+       
+}
+
+int MINIDRIVER(interface_jtag_add_reset)(int req_trst, int req_srst)
+{
+       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_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;
 
+       
        return ERROR_OK;
 }
 
-int jtag_add_end_state(enum tap_state state)
+int MINIDRIVER(interface_jtag_add_end_state)(enum tap_state state)
 {
        jtag_command_t **last_cmd = jtag_get_last_command_p();
        
@@ -908,13 +963,18 @@ int jtag_add_end_state(enum tap_state state)
        (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t));
        (*last_cmd)->cmd.end_state->end_state = state;
 
+       return ERROR_OK;
+}
+
+int jtag_add_end_state(enum tap_state state)
+{
+       int retval = interface_jtag_add_end_state(state);
        if (state != -1)
                cmd_queue_end_state = state;
-       
-       return ERROR_OK;
+       return retval;
 }
 
-int jtag_add_sleep(u32 us)
+int MINIDRIVER(interface_jtag_add_sleep)(u32 us)
 {
        jtag_command_t **last_cmd = jtag_get_last_command_p();
        
@@ -930,13 +990,18 @@ int jtag_add_sleep(u32 us)
        return ERROR_OK;
 }
 
+int jtag_add_sleep(u32 us)
+{
+       return interface_jtag_add_sleep(us); 
+}
+
 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++)
+       for (i = 0; i < cmd->num_fields; i++)
        {
                bit_count += cmd->fields[i].num_bits;
        }
@@ -959,7 +1024,7 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
                if (cmd->fields[i].out_value)
                {
 #ifdef _DEBUG_JTAG_IO_
-                       char* char_buf = buf_to_str(cmd->fields[i].out_value, cmd->fields[i].num_bits, 16);
+                       char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : cmd->fields[i].num_bits, 16);
 #endif
                        buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
 #ifdef _DEBUG_JTAG_IO_
@@ -979,25 +1044,28 @@ 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++)
+       int retval;
+       
+       /* we return ERROR_OK, unless a check fails, or a handler reports a problem */
+       retval = ERROR_OK;
+       
+       for (i = 0; i < cmd->num_fields; i++)
        {
-               /* if neither in_value, in_check_value nor in_handler
+               /* if neither in_value nor in_handler
                 * are specified we don't have to examine this field
                 */
-               if (cmd->fields[i].in_value || cmd->fields[i].in_check_value || cmd->fields[i].in_handler)
+               if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
                {
                        int num_bits = cmd->fields[i].num_bits;
                        u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits);
-                       #ifdef _DEBUG_JTAG_IO_
-                               char *char_buf;
-
-                               char_buf = buf_to_str(captured, num_bits, 16);
-                               DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
-                               free(char_buf);
-                       #endif
+                       
+#ifdef _DEBUG_JTAG_IO_
+                       char *char_buf;
 
+                       char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
+                       DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
+                       free(char_buf);
+#endif
                        
                        if (cmd->fields[i].in_value)
                        {
@@ -1005,9 +1073,8 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                                
                                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)
+                                       if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK)
                                        {
-                                               /* TODO: error reporting */
                                                WARNING("in_handler reported a failed check");
                                                retval = ERROR_JTAG_QUEUE_FAILED;
                                        }
@@ -1017,32 +1084,16 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                        /* no in_value specified, but a handler takes care of the scanned data */
                        if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value))
                        {
-                               if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv) != ERROR_OK)
+                               if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK)
                                {
-                                       /* TODO: error reporting */
+                                       /* We're going to call the error:handler later, but if the in_handler
+                                        * reported an error we report this failure upstream
+                                        */
                                        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_str(captured, num_bits, 16);
-                                       char *in_check_value_char = buf_to_str(cmd->fields[i].in_check_value, num_bits, 16);
-                                       char *in_check_mask_char = buf_to_str(cmd->fields[i].in_check_mask, num_bits, 16);
-                                       /* TODO: error reporting */
-                                       WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%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;
@@ -1051,14 +1102,74 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
        return retval;
 }
 
+int jtag_check_value(u8 *captured, void *priv, scan_field_t *field)
+{
+       int retval = ERROR_OK;
+       int num_bits = field->num_bits;
+       
+       int compare_failed = 0;
+       
+       if (field->in_check_mask)
+               compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits);
+       else
+               compare_failed = buf_cmp(captured, field->in_check_value, num_bits);
+       
+       if (compare_failed)
+               {
+               /* An error handler could have caught the failing check
+                * only report a problem when there wasn't a handler, or if the handler
+                * acknowledged the error
+                */ 
+               if (compare_failed)
+               {
+                       char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
+                       char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16);
+
+                       if (field->in_check_mask)
+                       {
+                               char *in_check_mask_char;
+                               in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16);
+                               WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char);
+                               free(in_check_mask_char);
+                       }
+                       else
+                       {
+                               WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char);
+                       }
+
+                       free(captured_char);
+                       free(in_check_value_char);
+                       
+                       retval = ERROR_JTAG_QUEUE_FAILED;
+               }
+               
+       }
+       return retval;
+}
+
+/* 
+  set up checking of this field using the in_handler. The values passed in must be valid until
+  after jtag_execute() has completed.
+ */
+void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler)
+{
+       if (value)
+               field->in_handler = jtag_check_value;
+       else
+               field->in_handler = NULL;       /* No check, e.g. embeddedice uses value==NULL to indicate no check */
+       field->in_handler_priv = NULL;  /* this will be filled in at the invocation site to point to the field duplicate */ 
+       field->in_check_value = value;
+       field->in_check_mask = mask;
+}
+
 enum scan_type jtag_scan_type(scan_command_t *cmd)
 {
        int i;
        int type = 0;
        
-       for (i=0; i < cmd->num_fields; i++)
+       for (i = 0; i < cmd->num_fields; i++)
        {
-               if (cmd->fields[i].in_check_value || cmd->fields[i].in_value || cmd->fields[i].in_handler)
+               if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
                        type |= SCAN_IN;
                if (cmd->fields[i].out_value)
                        type |= SCAN_OUT;
@@ -1067,7 +1178,7 @@ enum scan_type jtag_scan_type(scan_command_t *cmd)
        return type;
 }
 
-int jtag_execute_queue(void)
+int MINIDRIVER(interface_jtag_execute_queue)(void)
 {
        int retval;
 
@@ -1078,23 +1189,26 @@ int jtag_execute_queue(void)
        jtag_command_queue = NULL;
        last_comand_pointer = &jtag_command_queue;
 
+       jtag_error=ERROR_OK;
+
        return retval;
 }
 
-int jtag_cancel_queue(void)
+int jtag_execute_queue(void)
 {
-       cmd_queue_free();
-       jtag_command_queue = NULL;
-       last_comand_pointer = &jtag_command_queue;
-
-       return ERROR_OK;
+       int retval=interface_jtag_execute_queue();
+       if (retval!=ERROR_OK)
+               return retval;
+       retval=jtag_error;
+       jtag_error=ERROR_OK;
+       return retval;
 }
 
 int jtag_reset_callback(enum jtag_event event, void *priv)
 {
        jtag_device_t *device = priv;
 
-       DEBUG("");
+       DEBUG("-");
        
        if (event == JTAG_TRST_ASSERTED)
        {
@@ -1110,6 +1224,102 @@ void jtag_sleep(u32 us)
        usleep(us);
 }
 
+/* Try to examine chain layout according to IEEE 1149.1 Â§12
+ */
+int jtag_examine_chain()
+{
+       jtag_device_t *device = jtag_devices;
+       scan_field_t field;
+       u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
+       int i;
+       int bit_count;
+       int device_count = 0;
+       u8 zero_check = 0x0;
+       u8 one_check = 0xff;
+       
+       field.device = 0;
+       field.num_bits = sizeof(idcode_buffer) * 8;
+       field.out_value = idcode_buffer;
+       field.out_mask = NULL;
+       field.in_value = idcode_buffer;
+       field.in_check_value = NULL;
+       field.in_check_mask = NULL;
+       field.in_handler = NULL;
+       field.in_handler_priv = NULL;
+       
+       for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
+       {
+               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
+       }
+       
+       jtag_add_plain_dr_scan(1, &field, TAP_TLR);
+       jtag_execute_queue();
+       
+       for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++)
+       {
+               zero_check |= idcode_buffer[i];
+               one_check &= idcode_buffer[i];
+       }
+       
+       /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */
+       if ((zero_check == 0x00) || (one_check == 0xff))
+       {
+               ERROR("JTAG communication failure, check connection, JTAG interface, target power etc.");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
+       {
+               u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+               if ((idcode & 1) == 0)
+               {
+                       /* LSB must not be 0, this indicates a device in bypass */
+                       device_count++;
+                       
+                       bit_count += 1;
+               }
+               else
+               {
+                       u32 manufacturer;
+                       u32 part;
+                       u32 version;
+                       
+                       if (idcode == 0x000000FF)
+                       {
+                               /* End of chain (invalid manufacturer ID) */
+                               break;
+                       }
+                       
+                       if (device)
+                       {
+                               device->idcode = idcode;
+                               device = device->next;
+                       }
+                       device_count++;
+                       
+                       manufacturer = (idcode & 0xffe) >> 1;
+                       part = (idcode & 0xffff000) >> 12;
+                       version = (idcode & 0xf0000000) >> 28;
+
+                       INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)", 
+                               idcode, manufacturer, part, version);
+                       
+                       bit_count += 32;
+               }
+       }
+       
+       /* see if number of discovered devices matches configuration */
+       if (device_count != jtag_num_devices)
+       {
+               ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", 
+                       device_count, jtag_num_devices);
+               ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
 int jtag_validate_chain()
 {
        jtag_device_t *device = jtag_devices;
@@ -1149,7 +1359,8 @@ int jtag_validate_chain()
                        char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
                        ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
                        free(cbuf);
-                       exit(-1);
+                       free(ir_test);
+                       return ERROR_JTAG_INIT_FAILED;
                }
                chain_pos += device->ir_length;
                device = device->next;
@@ -1160,7 +1371,8 @@ int jtag_validate_chain()
                char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
                ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
                free(cbuf);
-               exit(-1);
+               free(ir_test);
+               return ERROR_JTAG_INIT_FAILED;
        }
        
        free(ir_test);
@@ -1175,7 +1387,7 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
        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);
+               COMMAND_CONFIG, "jtag_device <ir_length> <ir_expected> <ir_mask>");
        register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
                COMMAND_CONFIG, NULL);
        register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command,
@@ -1204,89 +1416,106 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
        return ERROR_OK;
 }
 
+int jtag_interface_init(struct command_context_s *cmd_ctx)
+{
+       if (!jtag_interface)
+       {
+               /* nothing was previously specified by "interface" command */
+               ERROR("JTAG interface has to be specified, see \"interface\" command");
+               return ERROR_JTAG_INVALID_INTERFACE;
+       }
+
+       if (jtag_interface->init() != ERROR_OK)
+               return ERROR_JTAG_INIT_FAILED;
+
+       jtag = jtag_interface;
+       return ERROR_OK;
+}
+
 int jtag_init(struct command_context_s *cmd_ctx)
 {
-       int i;
-       
-       DEBUG("");
+       int validate_tries = 0;
+       jtag_device_t *device;
 
-       if (jtag_speed == -1)
-               jtag_speed = 0;
+       DEBUG("-");
        
-       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];
+       if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK)
+               return ERROR_JTAG_INIT_FAILED;
 
-                               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;
-                       }
-               }
+       device = jtag_devices;
+       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;
+       }
        
-       /* 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);
-       ERROR("compiled-in jtag interfaces:");
-       for (i = 0; jtag_interfaces[i]; i++)
+       jtag_add_statemove(TAP_TLR);
+       jtag_execute_queue();
+
+       /* examine chain first, as this could discover the real chain layout */
+       if (jtag_examine_chain() != ERROR_OK)
        {
-               ERROR("%i: %s", i, jtag_interfaces[i]->name);
+               ERROR("trying to validate configured JTAG chain anyway...");
        }
        
-       jtag = NULL;
-       return ERROR_JTAG_INVALID_INTERFACE;
+       while (jtag_validate_chain() != ERROR_OK)
+       {
+               validate_tries++;
+               if (validate_tries > 5)
+               {
+                       ERROR("Could not validate JTAG chain, exit");
+                       jtag = NULL;
+                       return ERROR_JTAG_INVALID_INTERFACE;
+               }
+               usleep(10000);
+       }
+
+       return ERROR_OK;
 }
 
 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)
+
+       /* check whether the interface is already configured */
+       if (jtag_interface)
+       {
+               WARNING("Interface already configured, ignoring");
+               return ERROR_OK;
+       }
+
+       /* interface name is a mandatory argument */
+       if (argc < 1 || args[0][0] == '\0')
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       for (i=0; jtag_interfaces[i]; i++)
        {
-               if (args[0] && (args[0][0] != 0))
+               if (strcmp(args[0], jtag_interfaces[i]->name) == 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;
-                               }
-                       }
+                       if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK)
+                               exit(-1);
+
+                       jtag_interface = jtag_interfaces[i];
+                       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;
+
+       /* 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)", args[0]);
+       ERROR("compiled-in jtag interfaces:");
+       for (i = 0; jtag_interfaces[i]; i++)
+       {
+               ERROR("%i: %s", i, jtag_interfaces[i]->name);
+       }
+
+       return ERROR_JTAG_INVALID_INTERFACE;
 }
 
 int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -1357,8 +1586,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config = RESET_TRST_AND_SRST;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
@@ -1374,8 +1604,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST);
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
@@ -1387,8 +1618,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
 
@@ -1400,8 +1632,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~RESET_SRST_PUSH_PULL;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
@@ -1462,18 +1695,20 @@ int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char *
 
        if (argc < 1)
        {
-               command_print(cmd_ctx, "usage: endstate <tap_state>");
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
-
-       for (state = 0; state < 16; state++)
+       else
        {
-               if (strcmp(args[0], tap_state_strings[state]) == 0)
+               for (state = 0; state < 16; state++)
                {
-                       jtag_add_end_state(state);
-                       jtag_execute_queue();
+                       if (strcmp(args[0], tap_state_strings[state]) == 0)
+                       {
+                               jtag_add_end_state(state);
+                               jtag_execute_queue();
+                       }
                }
        }
+       command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]);
        
        return ERROR_OK;
 }
@@ -1482,13 +1717,12 @@ int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char
 {
        int trst = -1;
        int srst = -1;
-       char *usage = "usage: jtag_reset <trst> <srst>";
        int retval;
        
-       if (argc < 1)
+       if (argc < 2)
        {
-               command_print(cmd_ctx, usage);
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
        }
 
        if (args[0][0] == '1')
@@ -1497,8 +1731,7 @@ int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char
                trst = 0;
        else
        {
-               command_print(cmd_ctx, usage);
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        if (args[1][0] == '1')
@@ -1507,10 +1740,12 @@ int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char
                srst = 0;
        else
        {
-               command_print(cmd_ctx, usage);
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
+       if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK)
+               return ERROR_JTAG_INIT_FAILED;
+
        if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK)
        {
                switch (retval)
@@ -1534,8 +1769,7 @@ int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **
 {
        if (argc < 1)
        {
-               command_print(cmd_ctx, "usage: runtest <num_cycles>");
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        jtag_add_runtest(strtol(args[0], NULL, 0), -1);
@@ -1575,8 +1809,7 @@ int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **a
        
        if ((argc < 2) || (argc % 2))
        {
-               command_print(cmd_ctx, "usage: irscan <device> <instr> [dev2] [instr2] ...");
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        fields = malloc(sizeof(scan_field_t) * argc / 2);
@@ -1616,8 +1849,7 @@ int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **a
        
        if ((argc < 2) || (argc % 2))
        {
-               command_print(cmd_ctx, "usage: drscan <device> <var> [dev2] [var2]");
-               return ERROR_OK;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        for (i = 0; i < argc; i+=2)
@@ -1666,22 +1898,64 @@ int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **a
        return ERROR_OK;
 }
 
-int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+
+
+int MINIDRIVER(interface_jtag_add_shift)(const enum tap_state shift_state, const enum tap_state end_state, int num_bits, u32 value)
 {
-       if (argc == 0)
-       {
-               command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled");
-               return ERROR_OK;
-       }
+       u8 out_buf[4];
+       buf_set_u32(out_buf, 0, 32, flip_u32(value, 32));
+
+       /* allocate memory for a new list member */
+       jtag_command_t **last_cmd;
+       last_cmd = jtag_get_last_command_p();
+       *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 = (shift_state==TAP_SI);
+       (*last_cmd)->cmd.scan->num_fields = 1;
+       (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(1 * sizeof(scan_field_t));
+       (*last_cmd)->cmd.scan->end_state = end_state;
+               
+       int num_bytes = CEIL(num_bits, 8);
+       int i=0;
+       (*last_cmd)->cmd.scan->fields[i].device = 0; /* not used by any drivers */
+       (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits;
+       (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(out_buf, cmd_queue_alloc(num_bytes), num_bits);
+       (*last_cmd)->cmd.scan->fields[i].out_mask = NULL;
+       (*last_cmd)->cmd.scan->fields[i].in_value = NULL;
+       (*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;
        
-       if (strcmp(args[0], "enable") == 0)
+       return ERROR_OK;
+}
+
+int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc == 1)
        {
-               jtag_verify_capture_ir = 1;
-       }
-       else if (strcmp(args[0], "disable") == 0)
+               if (strcmp(args[0], "enable") == 0)
+               {
+                       jtag_verify_capture_ir = 1;
+               }
+               else if (strcmp(args[0], "disable") == 0)
+               {
+                       jtag_verify_capture_ir = 0;
+               } else
+               {
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+       } else if (argc != 0)
        {
-               jtag_verify_capture_ir = 0;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
        
+       command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled");
+       
        return ERROR_OK;
 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)