diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c
index 6f7845b5d72ee5507a149e2981d41770e8421a44..bf8e039d8ec87955e3dd33f05fca1691529138da 100644
--- a/src/jtag/jtag.c
+++ b/src/jtag/jtag.c
@@ -76,6 +76,24 @@ const Jim_Nvp nvp_jtag_tap_event[] = {
 int jtag_trst = 0;
 int jtag_srst = 0;
 
+#ifndef HAVE_JTAG_MINIDRIVER_H
+struct jtag_callback_entry
+{
+	struct jtag_callback_entry *next;
+
+	jtag_callback_t callback;
+	u8 *in;
+	jtag_callback_data_t data1;
+	jtag_callback_data_t data2;
+
+};
+
+
+static struct jtag_callback_entry *jtag_callback_queue_head = NULL;
+static struct jtag_callback_entry *jtag_callback_queue_tail = NULL;
+#endif
+
+
 jtag_command_t *jtag_command_queue = NULL;
 jtag_command_t **last_comand_pointer = &jtag_command_queue;
 static jtag_tap_t *jtag_all_taps = NULL;
@@ -1434,7 +1452,46 @@ enum scan_type jtag_scan_type(scan_command_t *cmd)
 	return type;
 }
 
-int MINIDRIVER(interface_jtag_execute_queue)(void)
+
+#ifndef HAVE_JTAG_MINIDRIVER_H
+/* add callback to end of queue */
+void jtag_add_callback3(jtag_callback_t callback, u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2)
+{
+	struct jtag_callback_entry *entry=cmd_queue_alloc(sizeof(struct jtag_callback_entry));
+
+	entry->next=NULL;
+	entry->callback=callback;
+	entry->in=in;
+	entry->data1=data1;
+	entry->data2=data2;
+
+	if (jtag_callback_queue_head==NULL)
+	{
+		jtag_callback_queue_head=entry;
+		jtag_callback_queue_tail=entry;
+	} else
+	{
+		jtag_callback_queue_tail->next=entry;
+		jtag_callback_queue_tail=entry;
+	}
+}
+
+
+static int jtag_convert_to_callback3(u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2)
+{
+	((jtag_callback1_t)data1)(in);
+	return ERROR_OK;
+}
+
+void jtag_add_callback(jtag_callback1_t callback, u8 *in)
+{
+	jtag_add_callback3(jtag_convert_to_callback3, in, (jtag_callback_data_t)callback, 0);
+}
+#endif
+
+#ifndef HAVE_JTAG_MINIDRIVER_H
+
+int interface_jtag_execute_queue(void)
 {
 	int retval;
 
@@ -1446,13 +1503,28 @@ int MINIDRIVER(interface_jtag_execute_queue)(void)
 
 	retval = jtag->execute_queue();
 
+	if (retval == ERROR_OK)
+	{
+		struct jtag_callback_entry *entry;
+		for (entry=jtag_callback_queue_head; entry!=NULL; entry=entry->next)
+		{
+			retval=entry->callback(entry->in, entry->data1, entry->data2);
+			if (retval!=ERROR_OK)
+				break;
+		}
+	}
+
 	cmd_queue_free();
 
+	jtag_callback_queue_head = NULL;
+	jtag_callback_queue_tail = NULL;
+
 	jtag_command_queue = NULL;
 	last_comand_pointer = &jtag_command_queue;
 
 	return retval;
 }
+#endif
 
 void jtag_execute_queue_noclear(void)
 {
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index dc6ef36c38e6e9c0cc883ff554f45fe97438cff9..d5ed4f5807493b5a597d51bf1292c7bac85dd6f5 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -568,6 +568,70 @@ extern int  interface_jtag_add_plain_ir_scan(int num_fields, scan_field_t* field
 extern void jtag_add_plain_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
 extern int  interface_jtag_add_plain_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
 
+
+/* Simplest/typical callback - do some conversion on the data clocked in.
+ * This callback is for such conversion that can not fail.
+ * For conversion types or checks that can
+ * fail, use the jtag_callback_t variant */
+typedef void (*jtag_callback1_t)(u8 *in);
+
+#ifndef HAVE_JTAG_MINIDRIVER_H
+/* A simpler version of jtag_add_callback3 */
+extern void jtag_add_callback(jtag_callback1_t, u8 *in);
+#else
+/* implemented by minidriver */
+#endif
+
+/* This type can store an integer safely by a normal cast on 64 and
+ * 32 bit systems. */
+typedef void *jtag_callback_data_t;
+
+/* The generic callback mechanism.
+ *
+ * The callback is invoked with three arguments. The first argument is
+ * the pointer to the data clocked in.
+ */
+typedef int (*jtag_callback_t)(u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2);
+
+
+/* This callback can be executed immediately the queue has been flushed. Note that
+ * the JTAG queue can either be executed synchronously or asynchronously. Typically
+ * for USB the queue is executed asynchronously. For low latency interfaces, the
+ * queue may be executed synchronously.
+ *
+ * These callbacks are typically executed *after* the *entire* JTAG queue has been
+ * executed for e.g. USB interfaces.
+ *
+ * The callbacks are guaranteeed to be invoked in the order that they were queued.
+ *
+ * The strange name is due to C's lack of overloading using function arguments
+ *
+ * The callback mechansim is very general and does not really make any assumptions
+ * about what the callback does and what the arguments are.
+ *
+ * in - typically used to point to the data to operate on. More often than not
+ * this will be the data clocked in during a shift operation
+ *
+ * data1 - an integer that is big enough to be used either as an 'int' or
+ * cast to/from a pointer
+ *
+ * data2 - an integer that is big enough to be used either as an 'int' or
+ * cast to/from a pointer
+ *
+ * Why stop at 'data2' for arguments? Somewhat historical reasons. This is
+ * sufficient to implement the jtag_check_value_mask(), besides the
+ * line is best drawn somewhere...
+ *
+ * If the execution of the queue fails before the callbacks, then the
+ * callbacks may or may not be invoked depending on driver implementation.
+ */
+#ifndef HAVE_JTAG_MINIDRIVER_H
+extern void jtag_add_callback3(jtag_callback_t, u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2);
+#else
+/* implemented by minidriver */
+#endif
+
+
 /* run a TAP_RESET reset. End state is TAP_RESET, regardless
  * of start state.
  */