This is an automated email from Gerrit.

Robert Jarzmik ([email protected]) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/1502

-- gerrit

commit d27ba65fa3db2bcb0e6892b701e5c0a35ae27290
Author: Robert Jarzmik <[email protected]>
Date:   Sat Jul 13 11:56:08 2013 +0200

    jtag/drivers: [UGLY] [WIP] usb_blaster exploratory commit for performance
    
    This is an exploration commit to assess possible performance
    of usb_blaster. It relies on :
     - an asynchronous usb read/write (inspired by MPSEE driver)
     - folding of jtag SCAN and PATHMOVES before issuing USB
     commands to the usb blaster
    
    The performance is not significant on dump_image (from
    10kBi/s to 10kBi/s with an XScale PX270), and from 2kBi/s to
    12kBi/s on load_image.
    
    The most relevant test is :
     - ./configure --enable-maintainer-mode --enable-verbose
        --enable-usb_blaster_libftdi --enable-usb_blaster
     - make
     - in openocd.cfg, don't forget "usb_blaster_lowlevel_driver
     libusb"
     - make the benchmarking
    
    Change-Id: I06e08afb4376a8450774657f7ec93bbee1965fe2
    Signed-off-by: Robert Jarzmik <[email protected]>

diff --git a/configure.ac b/configure.ac
index 87f95d5..eba4d4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -397,6 +397,10 @@ AC_ARG_ENABLE([usb_blaster_ftd2xx],
   AS_HELP_STRING([--enable-usb_blaster_ftd2xx], [Enable building support for 
the Altera USB-Blaster using the FTD2XX driver from ftdichip.com]),
   [build_usb_blaster_ftd2xx=$enableval], [build_usb_blaster_ftd2xx=no])
 
+AC_ARG_ENABLE([usb_blaster_libusb],
+  AS_HELP_STRING([--enable-usb_blaster_libusb], [Enable building support for 
the Alterra USB-Blaster using libusb-1.0 in asynchronous mode]),
+  [build_usb_blaster_libusb=$enableval], [build_usb_blaster_libusb=no])
+
 AC_ARG_ENABLE([amtjtagaccel],
   AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec 
JTAG-Accelerator driver]),
   [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
@@ -732,6 +736,12 @@ else
   AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [0], [0 if you don't want ftd2xx 
usb_blaster.])
 fi
 
+if test $build_usb_blaster_libusb = yes; then
+  AC_DEFINE([BUILD_USB_BLASTER_LIBUSB], [1], [1 if you want libusb 
usb_blaster.])
+else
+  AC_DEFINE([BUILD_USB_BLASTER_LIBUSB], [0], [0 if you don't want libusb 
usb_blaster.])
+fi
+
 if test $build_amtjtagaccel = yes; then
   AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec 
JTAG-Accelerator driver.])
 else
@@ -1192,7 +1202,7 @@ fi
 # check if some driver requires libusb-1.x
 need_usb_ng=no
 if test $build_ftdi = yes -o $build_hladapter_icdi = yes -o \
-        $build_hladapter_stlink = yes; then
+        $build_hladapter_stlink = yes -o $build_usb_blaster_libusb = yes; then
   need_usb_ng=yes
 fi
 
@@ -1240,6 +1250,7 @@ AM_CONDITIONAL([FT2232_DRIVER], [test 
$build_ft2232_ftd2xx = yes -o $build_ft223
 AM_CONDITIONAL([FTDI_DRIVER], [test $build_ftdi = yes])
 AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes])
 AM_CONDITIONAL([USB_BLASTER_FTD2XX], [test $build_usb_blaster_ftd2xx = yes])
+AM_CONDITIONAL([USB_BLASTER_LIBUSB], [test $build_usb_blaster_libusb = yes])
 AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o 
$build_usb_blaster_libftdi = yes])
 AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes])
 AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes])
diff --git a/src/jtag/drivers/usb_blaster/Makefile.am 
b/src/jtag/drivers/usb_blaster/Makefile.am
index 1cf7ba9..f450056 100644
--- a/src/jtag/drivers/usb_blaster/Makefile.am
+++ b/src/jtag/drivers/usb_blaster/Makefile.am
@@ -3,7 +3,7 @@ include $(top_srcdir)/common.mk
 noinst_LTLIBRARIES = libocdusbblaster.la
 libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC)
 
-USB_BLASTER_SRC = usb_blaster.c
+USB_BLASTER_SRC = usb_blaster.c ublast_access_common.c
 
 if USB_BLASTER_LIBFTDI
 USB_BLASTER_SRC += ublast_access_ftdi.c
@@ -13,6 +13,10 @@ if USB_BLASTER_FTD2XX
 USB_BLASTER_SRC += ublast_access_ftd2xx.c
 endif
 
+if USB_BLASTER_LIBUSB
+USB_BLASTER_SRC += ublast_access_libusb.c
+endif
+
 noinst_HEADERS = ublast_access.h
 
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h 
b/src/jtag/drivers/usb_blaster/ublast_access.h
index e0eb059..4e38567 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access.h
+++ b/src/jtag/drivers/usb_blaster/ublast_access.h
@@ -26,10 +26,11 @@ struct ublast_lowlevel {
        uint16_t ublast_pid;
        char *ublast_device_desc;
 
-       int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size,
-                    uint32_t *bytes_written);
-       int (*read)(struct ublast_lowlevel *low, uint8_t *buf, unsigned size,
-                   uint32_t *bytes_read);
+       int (*queue_write)(struct ublast_lowlevel *low, uint8_t *buf,
+                          int size, uint32_t *bytes_written);
+       int (*queue_read)(struct ublast_lowlevel *low, uint8_t *buf,
+                         unsigned size, uint32_t *bytes_read);
+       void (*flush)(struct ublast_lowlevel *low);
        int (*open)(struct ublast_lowlevel *low);
        int (*close)(struct ublast_lowlevel *low);
        int (*speed)(struct ublast_lowlevel *low, int speed);
@@ -50,3 +51,4 @@ struct ublast_lowlevel {
  */
 extern struct ublast_lowlevel *ublast_register_ftdi(void);
 extern struct ublast_lowlevel *ublast_register_ftd2xx(void);
+extern struct ublast_lowlevel *ublast_register_libusb(void);
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_common.c 
b/src/jtag/drivers/usb_blaster/ublast_access_common.c
new file mode 100644
index 0000000..5b9c52e
--- /dev/null
+++ b/src/jtag/drivers/usb_blaster/ublast_access_common.c
@@ -0,0 +1,114 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <jtag/interface.h>
+
+#include "ublast_access.h"
+#include "ublast_access_common.h"
+
+static int get_bytes_of_reqs(struct list_head *reqs)
+{
+       struct rw_req *req;
+       int nb = 0;
+
+       list_for_each_entry(req, reqs, list)
+               nb += req->nb;
+       return nb;
+}
+
+static void xfer_reqs_to_buf(unsigned char *buf, struct list_head *reqs)
+{
+       struct rw_req *req;
+
+       list_for_each_entry(req, reqs, list) {
+               memmove(buf, req->buf, req->nb);
+               buf += req->nb;
+       }
+}
+
+static void xfer_buf_to_reqs(unsigned char *buf, struct list_head *reqs)
+{
+       struct rw_req *req;
+
+       list_for_each_entry(req, reqs, list) {
+               memmove(req->buf, buf, req->nb);
+               buf += req->nb;
+       }
+}
+
+int ublast_common_flush(struct ublast_lowlevel *low,
+                       struct list_head *read_reqs,
+                       struct list_head *write_reqs,
+                       int(*read)(struct ublast_lowlevel*, uint8_t*, unsigned),
+                       int(*write)(struct ublast_lowlevel*, uint8_t*, int))
+{
+       int retval = 0, nb_read, nb_write;
+       struct rw_req *req, *tmp;
+       unsigned char *buf_read = NULL, *buf_write = NULL;
+
+       nb_read = get_bytes_of_reqs(read_reqs);
+       nb_write = get_bytes_of_reqs(write_reqs);
+       buf_read = malloc(nb_read);
+       buf_write = malloc(nb_write);
+       if (!buf_read || !buf_write) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       xfer_reqs_to_buf(buf_read, read_reqs);
+       xfer_reqs_to_buf(buf_write, write_reqs);
+
+       retval = write(low, buf_write, nb_write);
+       if (retval < 0) {
+               LOG_ERROR("error_write_data: %d", retval);
+               goto out;
+       }
+       retval = read(low, buf_read, nb_read);
+       if (retval < 0) {
+               LOG_ERROR("error read data: %d", retval);
+               goto out;
+       }
+out:
+       xfer_buf_to_reqs(buf_read, read_reqs);
+       list_for_each_entry_safe(req, tmp, write_reqs, list) {
+               list_del(&req->list);
+               free(req->buf);
+               free(req);
+       }
+       list_for_each_entry_safe(req, tmp, read_reqs, list) {
+               list_del(&req->list);
+               free(req);
+       }
+       return retval;
+}
+
+int ublast_common_queue_read(struct list_head *read_reqs,
+                            uint8_t *buf, unsigned int size)
+{
+       struct rw_req *req = malloc(sizeof(*req));
+
+       if (!req)
+               return -ENOMEM;
+       req->buf = buf;
+       req->nb = size;
+       list_add_tail(&req->list, read_reqs);
+       return size;
+}
+
+int ublast_common_queue_write(struct list_head *write_reqs,
+                             uint8_t *buf, unsigned int size)
+{
+       struct rw_req *req = malloc(sizeof(*req));
+
+       if (!req)
+               return -ENOMEM;
+       req->buf = malloc(size);
+       if (!req->buf) {
+               free(req);
+               return -ENOMEM;
+       }
+       memcpy(req->buf, buf, size);
+       req->nb = size;
+       list_add_tail(&req->list, write_reqs);
+       return size;
+}
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_common.h 
b/src/jtag/drivers/usb_blaster/ublast_access_common.h
new file mode 100644
index 0000000..f183180
--- /dev/null
+++ b/src/jtag/drivers/usb_blaster/ublast_access_common.h
@@ -0,0 +1,34 @@
+/*
+ *   Driver for USB-JTAG, Altera USB-Blaster and compatibles
+ *
+ *
+ *   Copyright (C) 2012 Robert Jarzmik [email protected]
+ *
+ *   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.
+ *
+ */
+
+struct rw_req {
+       void *buf;
+       int nb;
+       struct list_head list;
+};
+
+extern int ublast_common_flush(struct ublast_lowlevel *low,
+                              struct list_head *read_reqs,
+                              struct list_head *write_reqs,
+                              int(*read)(struct ublast_lowlevel*, uint8_t*, 
unsigned),
+                              int(*write)(struct ublast_lowlevel*, uint8_t*, 
int));
+extern int ublast_common_queue_read(struct list_head *read_reqs,
+                                   uint8_t *buf, unsigned int size);
+extern int ublast_common_queue_write(struct list_head *write_reqs,
+                                    uint8_t *buf, unsigned int size);
+
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c 
b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c
index e350650..998c741 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c
+++ b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c
@@ -28,17 +28,34 @@
 #include <jtag/commands.h>
 
 #include "ublast_access.h"
+#include "ublast_access_common.h"
 
 #include <ftd2xx.h>
 #include "jtag/drivers/ftd2xx_common.h"
 
+static LIST_HEAD(read_reqs);
+static LIST_HEAD(write_reqs);
+
 static FT_HANDLE *ublast_getftdih(struct ublast_lowlevel *low)
 {
        return low->priv;
 }
 
-static int ublast_ftd2xx_write(struct ublast_lowlevel *low, uint8_t *buf, int 
size,
-                             uint32_t *bytes_written)
+static int ublast_ftd2xx_queue_read(struct ublast_lowlevel *low, uint8_t *buf,
+                                   unsigned size, uint32_t *bytes_read)
+{
+       *bytes_read = size;
+       return ublast_common_queue_read(&read_reqs, buf, size);
+}
+
+static int ublast_ftd2xx_queue_write(struct ublast_lowlevel *low, uint8_t *buf,
+                                    int size, uint32_t *bytes_written)
+{
+       *bytes_written = size;
+       return ublast_common_queue_write(&write_reqs, buf, (unsigned int)size);
+}
+
+static int ublast_ftd2xx_do_write(struct ublast_lowlevel *low, uint8_t *buf, 
int size)
 {
        FT_STATUS status;
        DWORD dw_bytes_written;
@@ -46,16 +63,14 @@ static int ublast_ftd2xx_write(struct ublast_lowlevel *low, 
uint8_t *buf, int si
 
        status = FT_Write(*ftdih, buf, size, &dw_bytes_written);
        if (status != FT_OK) {
-               *bytes_written = dw_bytes_written;
                LOG_ERROR("FT_Write returned: %s", 
ftd2xx_status_string(status));
                return ERROR_JTAG_DEVICE_ERROR;
        }
-       *bytes_written = dw_bytes_written;
-       return ERROR_OK;
+       return dw_bytes_written;
 }
 
-static int ublast_ftd2xx_read(struct ublast_lowlevel *low, uint8_t *buf,
-                            unsigned size, uint32_t *bytes_read)
+static int ublast_ftd2xx_do_read(struct ublast_lowlevel *low, uint8_t *buf,
+                                unsigned size)
 {
        DWORD dw_bytes_read;
        FT_STATUS status;
@@ -63,12 +78,21 @@ static int ublast_ftd2xx_read(struct ublast_lowlevel *low, 
uint8_t *buf,
 
        status = FT_Read(*ftdih, buf, size, &dw_bytes_read);
        if (status != FT_OK) {
-               *bytes_read = dw_bytes_read;
                LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status));
                return ERROR_JTAG_DEVICE_ERROR;
        }
-       *bytes_read = dw_bytes_read;
-       return ERROR_OK;
+       return dw_bytes_read;
+}
+
+static void ublast_ftd2xx_flush(struct ublast_lowlevel *low)
+{
+       int retval;
+
+       retval = ublast_common_flush(low, &read_reqs, &write_reqs,
+                                    ublast_ftd2xx_do_read,
+                                    ublast_ftd2xx_do_write);
+       if (retval < 0)
+               LOG_ERROR("FT  returned: %s", ftd2xx_status_string(retval));
 }
 
 static int ublast_ftd2xx_init(struct ublast_lowlevel *low)
@@ -167,8 +191,9 @@ static struct ublast_lowlevel_priv {
 static struct ublast_lowlevel low = {
        .open = ublast_ftd2xx_init,
        .close = ublast_ftd2xx_quit,
-       .read = ublast_ftd2xx_read,
-       .write = ublast_ftd2xx_write,
+       .queue_read = ublast_ftd2xx_queue_read,
+       .queue_write = ublast_ftd2xx_queue_write,
+       .flush = ublast_ftd2xx_flush,
        .priv = &info,
 };
 
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c 
b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
index 23893e1..e958699 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
+++ b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
@@ -28,50 +28,89 @@
 #include <jtag/commands.h>
 
 #include "ublast_access.h"
+#include "ublast_access_common.h"
 #include <ftdi.h>
 
+static LIST_HEAD(read_reqs);
+static LIST_HEAD(write_reqs);
+
 static struct ftdi_context *ublast_getftdic(struct ublast_lowlevel *low)
 {
        return low->priv;
 }
 
-static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf,
-                           unsigned size, uint32_t *bytes_read)
+static char *hexdump(uint8_t *buf, unsigned int size)
+{
+       unsigned int i;
+       char *str = calloc(size * 2 + 1, 1);
+
+       for (i = 0; i < size; i++)
+               sprintf(str + 2*i, "%02x", buf[i]);
+       return str;
+}
+
+static int ublast_ftdi_queue_read(struct ublast_lowlevel *low, uint8_t *buf,
+                                 unsigned size, uint32_t *bytes_read)
+{
+       *bytes_read = size;
+       return ublast_common_queue_read(&read_reqs, buf, size);
+}
+
+static int ublast_ftdi_queue_write(struct ublast_lowlevel *low, uint8_t *buf,
+                                  int size, uint32_t *bytes_written)
+{
+       *bytes_written = size;
+       return ublast_common_queue_write(&write_reqs, buf, (unsigned int)size);
+}
+
+static int ublast_ftdi_do_read(struct ublast_lowlevel *low, uint8_t *buf,
+                              unsigned size)
 {
        int retval;
+       uint32_t bytes_read;
        int timeout = 100;
        struct ftdi_context *ftdic = ublast_getftdic(low);
+       char *str;
 
-       *bytes_read = 0;
-       while ((*bytes_read < size) && timeout--) {
-               retval = ftdi_read_data(ftdic, buf + *bytes_read,
-                               size - *bytes_read);
+       bytes_read = 0;
+       while ((bytes_read < size) && timeout--) {
+               retval = ftdi_read_data(ftdic, buf + bytes_read,
+                                       size - bytes_read);
                if (retval < 0) {
-                       *bytes_read = 0;
+                       bytes_read = 0;
                        LOG_ERROR("ftdi_read_data: %s",
                                        ftdi_get_error_string(ftdic));
                        return ERROR_JTAG_DEVICE_ERROR;
                }
-               *bytes_read += retval;
+               bytes_read += retval;
+               str = retval < 0 ? NULL : hexdump(buf + bytes_read, retval);
+               DEBUG_JTAG_IO("USB actual read %d bytes : [%s]", retval, str);
+               free(str);
        }
-       return ERROR_OK;
+       return bytes_read;
 }
 
-static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int 
size,
-                            uint32_t *bytes_written)
+static int ublast_ftdi_do_write(struct ublast_lowlevel *low, uint8_t *buf, int 
size)
+{
+       struct ftdi_context *ftdic = ublast_getftdic(low);
+       char *str;
+
+       str = hexdump(buf, size);
+       DEBUG_JTAG_IO("USB actual write %d bytes : [%s]", size, str);
+       free(str);
+       return ftdi_write_data(ftdic, buf, size);
+}
+
+static void ublast_ftdi_flush(struct ublast_lowlevel *low)
 {
        int retval;
        struct ftdi_context *ftdic = ublast_getftdic(low);
 
-       retval = ftdi_write_data(ftdic, buf, size);
-       if (retval < 0) {
-               *bytes_written = 0;
-               LOG_ERROR("ftdi_write_data: %s",
+       retval = ublast_common_flush(low, &read_reqs, &write_reqs,
+                                    ublast_ftdi_do_read, ublast_ftdi_do_write);
+       if (retval < 0)
+               LOG_ERROR("ftdi flush: %s",
                          ftdi_get_error_string(ftdic));
-               return ERROR_JTAG_DEVICE_ERROR;
-       }
-       *bytes_written = retval;
-       return ERROR_OK;
 }
 
 static int ublast_ftdi_init(struct ublast_lowlevel *low)
@@ -125,8 +164,9 @@ static struct ublast_lowlevel_priv {
 static struct ublast_lowlevel low = {
        .open = ublast_ftdi_init,
        .close = ublast_ftdi_quit,
-       .read = ublast_ftdi_read,
-       .write = ublast_ftdi_write,
+       .queue_read = ublast_ftdi_queue_read,
+       .queue_write = ublast_ftdi_queue_write,
+       .flush = ublast_ftdi_flush,
        .priv = &info,
 };
 
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_libusb.c 
b/src/jtag/drivers/usb_blaster/ublast_access_libusb.c
new file mode 100644
index 0000000..de82f3e
--- /dev/null
+++ b/src/jtag/drivers/usb_blaster/ublast_access_libusb.c
@@ -0,0 +1,422 @@
+/*
+ *   Driver for simple USB buffering access layer
+ *
+ *   Copyright (C) 2012 Robert Jarzmik [email protected]
+ *
+ *   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.
+ *
+ * This simple access layer does :
+ *  - buffering : nothing is actually send over USB before an explicit flush()
+ *  - streaming : all read/writes are supposed to be a stream, the USB packet
+ *    semantics are lost
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <jtag/interface.h>
+#include <jtag/commands.h>
+
+#include "ublast_access.h"
+#include "helper/log.h"
+#include <libusb-1.0/libusb.h>
+
+#define FTDI_DEVICE_OUT_REQTYPE (LIBUSB_REQUEST_TYPE_VENDOR | 
LIBUSB_RECIPIENT_DEVICE)
+#define FTDI_DEVICE_IN_REQTYPE (0x80 | LIBUSB_REQUEST_TYPE_VENDOR | 
LIBUSB_RECIPIENT_DEVICE
+#define SIO_RESET_REQUEST             0x00
+#define SIO_RESET_SIO 0
+#define SIO_RESET_PURGE_RX 1
+#define SIO_RESET_PURGE_TX 2
+
+struct usb_ctx {
+       libusb_context *usb_ctx;
+       libusb_device_handle *dev;
+       int interface;
+       uint8_t ep_in;
+       uint8_t ep_out;
+       int timeout;
+       struct list_head read_reqs;
+       struct list_head write_reqs;
+};
+
+struct rw_req {
+       void *buf;
+       int nb;
+       struct list_head list;
+};
+
+struct transfer_result {
+       int nb_sumitted;
+       int nb_finished;
+};
+
+/** Port interface for chips with multiple interfaces */
+enum ftdi_interface
+{
+    INTERFACE_ANY = 0,
+    INTERFACE_A   = 1,
+    INTERFACE_B   = 2,
+    INTERFACE_C   = 3,
+    INTERFACE_D   = 4
+};
+
+static void usb_reset(struct usb_ctx *ctx)
+{
+       int rc;
+
+       rc = libusb_control_transfer(ctx->dev, FTDI_DEVICE_OUT_REQTYPE,
+                                    SIO_RESET_REQUEST, SIO_RESET_SIO,
+                                    INTERFACE_A, NULL, 0, ctx->timeout);
+       if (rc)
+               LOG_INFO("control transfer failed : %d\n", rc);
+}
+
+
+static struct usb_ctx* usb_open(const uint16_t vid, const uint16_t pid,
+                                const int usb_interface, const uint8_t ep_in,
+                                const uint8_t ep_out)
+{
+       int rc;
+       struct usb_ctx *ctx;
+
+       ctx = calloc(1, sizeof(*ctx));
+       if (!ctx)
+               goto err_mem;
+       rc = libusb_init(&ctx->usb_ctx);
+       if (rc < 0)
+               goto err_init;
+       ctx->dev = libusb_open_device_with_vid_pid(ctx->usb_ctx, vid, pid);
+       if (!ctx->dev)
+               goto err_open;
+       ctx->interface = usb_interface;
+       rc = libusb_claim_interface(ctx->dev, ctx->interface);
+       if (rc != LIBUSB_SUCCESS) {
+               LOG_ERROR("libusb_claim_interface() failed with %d", rc);
+               goto err_interface;
+       }
+       usb_reset(ctx);
+       ctx->ep_in = ep_in;
+       ctx->ep_out = ep_out;
+       INIT_LIST_HEAD(&ctx->read_reqs);
+       INIT_LIST_HEAD(&ctx->write_reqs);
+
+       ctx->timeout = 0;
+       return ctx;
+
+err_interface:
+       libusb_close(ctx->dev);
+err_open:
+       libusb_exit(ctx->usb_ctx);
+err_init:
+       free(ctx);
+err_mem:
+       return NULL;
+}
+
+static void usb_close(struct usb_ctx *ctx)
+{
+       libusb_close(ctx->dev);
+       libusb_exit(ctx->usb_ctx);
+       free(ctx);
+}
+
+static int usb_queue_read(struct usb_ctx *ctx, void *buf, int nb)
+{
+       struct rw_req *req = malloc(sizeof(*req));
+
+       if (!req)
+               return -ENOMEM;
+       req->buf = buf;
+       req->nb = nb;
+       list_add_tail(&req->list, &ctx->read_reqs);
+       return nb;
+}
+
+static int usb_queue_write(struct usb_ctx *ctx, void *buf, int nb, bool copy)
+{
+       struct rw_req *req = malloc(sizeof(*req));
+
+       if (!req)
+               return -ENOMEM;
+       if (copy)
+               req->buf = malloc(nb);
+       else
+               req->buf = buf;
+       if (!req->buf) {
+               free(req);
+               return -ENOMEM;
+       }
+       req->nb = nb;
+       memcpy(req->buf, buf, nb);
+       list_add_tail(&req->list, &ctx->write_reqs);
+       return nb;
+}
+
+static void read_cb(struct libusb_transfer *transfer)
+{
+       struct transfer_result *result = transfer->user_data;
+
+       DEBUG_JTAG_IO("status=%d, transferred %d+%d=%d",
+                     transfer->status,
+                     result->nb_finished,
+                     transfer->actual_length,
+                     result->nb_finished + transfer->actual_length);
+       if (transfer->actual_length >= 2) {
+               memmove(transfer->buffer, transfer->buffer + 2,
+                       transfer->actual_length - 2);
+               result->nb_finished += transfer->actual_length - 2;
+
+               if (result->nb_finished < result->nb_sumitted) {
+                       transfer->length -= (transfer->actual_length - 2);
+                       transfer->buffer += (transfer->actual_length - 2);
+                       if (libusb_submit_transfer(transfer))
+                               result->nb_finished = result->nb_sumitted;
+               }
+       }
+}
+
+static void write_cb(struct libusb_transfer *transfer)
+{
+       struct transfer_result *result = transfer->user_data;
+
+       DEBUG_JTAG_IO("status=%d, transferred %d+%d=%d",
+                     transfer->status,
+                     result->nb_finished,
+                     transfer->actual_length,
+                     result->nb_finished + transfer->actual_length);
+       result->nb_finished += transfer->actual_length;
+
+       if (result->nb_finished < result->nb_sumitted) {
+               transfer->length -= transfer->actual_length;
+               transfer->buffer += transfer->actual_length;
+               if (libusb_submit_transfer(transfer))
+                       result->nb_finished = result->nb_sumitted;
+       }
+}
+
+static int get_bytes_of_reqs(struct list_head *reqs)
+{
+       struct rw_req *req;
+       int nb = 0;
+
+       list_for_each_entry(req, reqs, list)
+               nb += req->nb;
+       return nb;
+}
+
+static void xfer_reqs_to_buf(unsigned char *buf, struct list_head *reqs)
+{
+       struct rw_req *req;
+
+       list_for_each_entry(req, reqs, list) {
+               memmove(buf, req->buf, req->nb);
+               buf += req->nb;
+       }
+}
+
+static char *hexdump(uint8_t *buf, unsigned int size)
+{
+       unsigned int i;
+       char *str = calloc(size * 2 + 1, 1);
+
+       for (i = 0; i < size; i++)
+               sprintf(str + 2*i, "%02x", buf[i]);
+       return str;
+}
+
+static void xfer_buf_to_reqs(unsigned char *buf, struct list_head *reqs)
+{
+       struct rw_req *req;
+       char *str;
+
+       list_for_each_entry(req, reqs, list) {
+               str = hexdump(buf, req->nb);
+               free(str);
+
+               memmove(req->buf, buf, req->nb);
+               buf += req->nb;
+       }
+}
+
+static int usb_flush(struct usb_ctx *ctx)
+{
+       int nb_read, nb_read_align, nb_write, rc = 0;
+       unsigned char *buf_read = NULL, *buf_write = NULL;
+       struct libusb_transfer *read_transfer, *write_transfer;
+       struct transfer_result read_result = { .nb_finished = 0 };
+       struct transfer_result write_result = { .nb_finished = 0 };
+
+       nb_read = get_bytes_of_reqs(&ctx->read_reqs);
+       nb_read_align = (((nb_read + 2)/ 64) + 1) * 64;
+       nb_write = get_bytes_of_reqs(&ctx->write_reqs);
+       DEBUG_JTAG_IO("write %d, read %d", nb_write, nb_read);
+
+       if (nb_read == 0 && nb_write == 0)
+               return 0;
+       read_result.nb_sumitted = nb_read;
+       write_result.nb_sumitted = nb_write;
+
+       buf_read = malloc(nb_read_align);
+       buf_write = malloc(nb_write);
+       if (!buf_read || !buf_write) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       xfer_reqs_to_buf(buf_read, &ctx->read_reqs);
+       xfer_reqs_to_buf(buf_write, &ctx->write_reqs);
+
+       char *str = hexdump(buf_write, nb_write);
+       DEBUG_JTAG_IO("actual write %d bytes [%s]", nb_write, str);
+       free(str);
+
+       read_transfer = libusb_alloc_transfer(0);
+       write_transfer = libusb_alloc_transfer(0);
+       libusb_fill_bulk_transfer(read_transfer, ctx->dev, ctx->ep_in,
+                                 buf_read, nb_read_align,
+                                 read_cb, &read_result, ctx->timeout);
+       libusb_fill_bulk_transfer(write_transfer, ctx->dev, ctx->ep_out,
+                                 buf_write, nb_write,
+                                 write_cb, &write_result, ctx->timeout);
+       if (nb_write)
+               rc = libusb_submit_transfer(write_transfer);
+       if (!rc && nb_read)
+               rc = libusb_submit_transfer(read_transfer);
+
+       /* Polling loop, more or less taken from libftdi */
+       while ((read_result.nb_finished < nb_read ||
+               write_result.nb_finished < nb_write) && !rc) {
+               rc = libusb_handle_events(ctx->usb_ctx);
+
+               keep_alive();
+               if (!rc)
+                       continue;
+               if (nb_write)
+                       libusb_cancel_transfer(write_transfer);
+               if (nb_read)
+                       libusb_cancel_transfer(read_transfer);
+               rc = 0;
+               while (!rc && nb_write &&
+                      write_transfer->status != LIBUSB_TRANSFER_CANCELLED)
+                       rc = libusb_handle_events(ctx->usb_ctx);
+               while (!rc && nb_read &&
+                      read_transfer->status != LIBUSB_TRANSFER_CANCELLED)
+                       rc = libusb_handle_events(ctx->usb_ctx);
+       }
+
+       if (rc) {
+               LOG_ERROR("libusb_handle_events() failed with %d", rc);
+               rc = -EIO;
+       } else if (nb_write && write_result.nb_finished < nb_write) {
+               LOG_ERROR("usb device did not accept all data: %d, tried %d",
+                         write_result.nb_finished, nb_write);
+               rc = -EIO;
+       } else if (nb_read && read_result.nb_finished < nb_read) {
+               LOG_ERROR("usb device did not return all data: %d, expected %d",
+                         read_result.nb_finished, nb_read);
+               rc = -EIO;;
+       } else {
+               rc = 0;
+               xfer_buf_to_reqs(buf_read, &ctx->read_reqs);
+               xfer_buf_to_reqs(buf_write, &ctx->write_reqs);
+               str = hexdump(buf_read, nb_read);
+               DEBUG_JTAG_IO("actual read %d bytes [%s]", nb_read, str);
+               free(str);
+       }
+       INIT_LIST_HEAD(&ctx->read_reqs);
+       INIT_LIST_HEAD(&ctx->write_reqs);
+
+       if (nb_write)
+               libusb_free_transfer(write_transfer);
+       if (nb_read)
+               libusb_free_transfer(read_transfer);
+       /* if (rc) */
+       /*      usb_purge(ctx); */
+
+out:
+       if (buf_read)
+               free(buf_read);
+       if (buf_write)
+               free(buf_write);
+       return rc;
+}
+
+/*
+ * This is the ublast_access specific part
+ */
+static struct usb_ctx *ublast_getctx(struct ublast_lowlevel *low)
+{
+       return low->priv;
+}
+
+static int ublast_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
+                             unsigned size, uint32_t *bytes_read)
+{
+       struct usb_ctx *ctx = ublast_getctx(low);
+       int rc;
+
+       rc = usb_queue_read(ctx, buf, size);
+       *bytes_read = size;
+       return rc < 0 ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK;
+}
+
+static int ublast_libusb_write(struct ublast_lowlevel *low, uint8_t *buf, int 
size,
+                              uint32_t *bytes_written)
+{
+       struct usb_ctx *ctx = ublast_getctx(low);
+       int rc;
+
+       rc = usb_queue_write(ctx, buf, size, true);
+       *bytes_written = size;
+       return rc < 0 ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK;
+}
+
+static void ublast_libusb_flush(struct ublast_lowlevel *low)
+{
+       struct usb_ctx *ctx = ublast_getctx(low);
+
+       usb_flush(ctx);
+}
+
+static int ublast_libusb_init(struct ublast_lowlevel *low)
+{
+       struct usb_ctx *ctx;
+
+       LOG_INFO("usb blaster interface using libusb");
+       ctx = usb_open(low->ublast_vid, low->ublast_pid, 0, 0x81, 0x02);
+       if (!ctx)
+               return ERROR_JTAG_INIT_FAILED;
+       low->priv = ctx;
+
+       return ERROR_OK;
+}
+
+static int ublast_libusb_quit(struct ublast_lowlevel *low)
+{
+       struct usb_ctx *ctx = ublast_getctx(low);
+
+       usb_close(ctx);
+       return ERROR_OK;
+};
+
+static struct ublast_lowlevel low = {
+       .open = ublast_libusb_init,
+       .close = ublast_libusb_quit,
+       .queue_read = ublast_libusb_read,
+       .queue_write = ublast_libusb_write,
+       .flush = ublast_libusb_flush,
+       .priv = NULL,
+};
+
+struct ublast_lowlevel *ublast_register_libusb(void)
+{
+       return &low;
+}
diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c 
b/src/jtag/drivers/usb_blaster/usb_blaster.c
index ccbed0e..af33490 100644
--- a/src/jtag/drivers/usb_blaster/usb_blaster.c
+++ b/src/jtag/drivers/usb_blaster/usb_blaster.c
@@ -71,6 +71,7 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <time.h>
+#include <list.h>
 
 /* Size of USB endpoint max packet size, ie. 64 bytes */
 #define MAX_PACKET_SIZE 64
@@ -82,6 +83,15 @@
  */
 #define BUF_LEN 4096
 
+struct ublast_readback_request {
+       int nb_byteshift;
+       int nb_bitbang;
+       unsigned char *tdos;
+       struct list_head list;
+       struct scan_command *scan_cmd;
+};
+LIST_HEAD(readback_reqs);
+
 enum gpio_steer {
        FIXED_0 = 0,
        FIXED_1,
@@ -96,8 +106,6 @@ struct ublast_info {
        int tdi;
        bool trst_asserted;
        bool srst_asserted;
-       uint8_t buf[BUF_LEN];
-       int bufidx;
 
        char *lowlevel_name;
        struct ublast_lowlevel *drv;
@@ -133,9 +141,14 @@ static struct drvs_map lowlevel_drivers_map[] = {
 #if BUILD_USB_BLASTER_FTD2XX
        { .name = "ftd2xx", .drv_register = ublast_register_ftd2xx },
 #endif
+#if BUILD_USB_BLASTER_LIBUSB
+       { .name = "libusb", .drv_register = ublast_register_libusb },
+#endif
        { NULL, NULL },
 };
 
+static int ublast_handle_readbacks(void);
+
 /*
  * Access functions to lowlevel driver, agnostic of libftdi/libftdxx
  */
@@ -151,18 +164,14 @@ static char *hexdump(uint8_t *buf, unsigned int size)
 
 static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read)
 {
-       int ret = info.drv->read(info.drv, buf, size, bytes_read);
-       char *str = hexdump(buf, *bytes_read);
+       int ret = info.drv->queue_read(info.drv, buf, size, bytes_read);
 
-       DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str,
-                     *bytes_read);
-       free(str);
        return ret;
 }
 
 static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written)
 {
-       int ret = info.drv->write(info.drv, buf, size, bytes_written);
+       int ret = info.drv->queue_write(info.drv, buf, size, bytes_written);
        char *str = hexdump(buf, *bytes_written);
 
        DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str,
@@ -171,22 +180,26 @@ static int ublast_buf_write(uint8_t *buf, int size, 
uint32_t *bytes_written)
        return ret;
 }
 
-static int nb_buf_remaining(void)
+static void ublast_flush(void)
 {
-       return BUF_LEN - info.bufidx;
+       DEBUG_JTAG_IO("underway");
+       info.drv->flush(info.drv);
+       ublast_handle_readbacks();
 }
 
-static void ublast_flush_buffer(void)
-{
-       unsigned int retlen;
-       int nb = info.bufidx, ret = ERROR_OK;
+/* static int ublast_flush_buffer(void) */
+/* { */
+/*     unsigned int retlen; */
+/*     int nb = info.bufidx, ret = ERROR_OK; */
 
-       while (ret == ERROR_OK && nb > 0) {
-               ret = ublast_buf_write(info.buf, nb, &retlen);
-               nb -= retlen;
-       }
-       info.bufidx = 0;
-}
+/*     while (ret == ERROR_OK && nb > 0) { */
+/*             ret = ublast_buf_write(info.buf, nb, &retlen); */
+/*             nb -= retlen; */
+/*     } */
+/*     ret = info.bufidx; */
+/*     info.bufidx = 0; */
+/*     return ret; */
+/* } */
 
 /*
  * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 
data
@@ -231,6 +244,8 @@ static void ublast_flush_buffer(void)
 #define SHMODE         (1 << 7)
 #define READ_TDO       (1 << 0)
 
+#define MAX_BYTESHIFT_NB       (63)    /* bit7 and bit6 busy, others free*/
+
 /**
  * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster
  * @abyte: the byte to queue
@@ -241,12 +256,17 @@ static void ublast_flush_buffer(void)
  */
 static void ublast_queue_byte(uint8_t abyte)
 {
-       if (nb_buf_remaining() < 1)
-               ublast_flush_buffer();
-       info.buf[info.bufidx++] = abyte;
-       if (nb_buf_remaining() == 0)
-               ublast_flush_buffer();
-       DEBUG_JTAG_IO("(byte=0x%02x)", abyte);
+       unsigned int retlen;
+
+       if (abyte & SHMODE)
+               DEBUG_JTAG_IO("(byte=0x%02x: shiftmode=%d, readback=%d)",
+                             abyte, !!(abyte & SHMODE), !!(abyte & READ_TDO));
+       else
+               DEBUG_JTAG_IO("(byte=0x%02x: shiftmode=%d, readback=%d, 
pin6=%d, pin8=%d, tms=%d, tdi=%d, tck=%d)",
+                             abyte, !!(abyte & SHMODE), !!(abyte & READ_TDO),
+                             !!(abyte & NCE), !!(abyte & NCS), !!(abyte & TMS),
+                             !!(abyte & TDI), !!(abyte & TCK));
+       ublast_buf_write(&abyte, 1, &retlen);
 }
 
 /**
@@ -304,7 +324,6 @@ static void ublast_reset(int trst, int srst)
        info.srst_asserted = srst;
        out_value = ublast_build_out(SCAN_OUT);
        ublast_queue_byte(out_value);
-       ublast_flush_buffer();
 }
 
 /**
@@ -332,6 +351,7 @@ static void ublast_clock_tms(int tms)
  */
 static void ublast_idle_clock(void)
 {
+       info.tms = 0;
        uint8_t out = ublast_build_out(SCAN_OUT);
 
        DEBUG_JTAG_IO(".");
@@ -402,23 +422,20 @@ static void ublast_clock_tdi_flip_tms(int tdi, enum 
scan_type type)
  * Queues bytes to be sent to the USB Blaster. The bytes are not
  * actually sent, but stored in a buffer. The write is performed once
  * the buffer is filled, or if an explicit ublast_flush_buffer() is called.
+ *
+ * Returns the number of bytes actually send to lowlevel driver (ie. a non-zero
+ * value implies that a flush happened).
+ *
  */
-static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
+static int ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
 {
-       if (info.bufidx + nb_bytes > BUF_LEN) {
-               LOG_ERROR("buggy code, should never queue more that %d bytes",
-                         info.bufidx + nb_bytes);
-               exit(-1);
-       }
+       int ret = 0;
+       unsigned int bytes_written;
+
        DEBUG_JTAG_IO("(nb_bytes=%d, bytes=[0x%02x, ...])", nb_bytes,
                      bytes ? bytes[0] : 0);
-       if (bytes)
-               memcpy(&info.buf[info.bufidx], bytes, nb_bytes);
-       else
-               memset(&info.buf[info.bufidx], 0, nb_bytes);
-       info.bufidx += nb_bytes;
-       if (nb_buf_remaining() == 0)
-               ublast_flush_buffer();
+       ublast_buf_write(bytes, nb_bytes, &bytes_written);
+       return ret;
 }
 
 /**
@@ -450,6 +467,7 @@ static void ublast_tms(struct tms_command *cmd)
 {
        DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits);
        ublast_tms_seq(cmd->bits, cmd->num_bits);
+       ublast_flush();
 }
 
 /**
@@ -502,7 +520,8 @@ static void ublast_state_move(tap_state_t state)
 
 /**
  * ublast_read_byteshifted_tdos - read TDO of byteshift writes
- * @buf: the buffer to store the bits
+ * @dst: the buffer to store the bits
+ * @src: the raw byte stream
  * @nb_bits: the number of bits
  *
  * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. 
eight
@@ -510,28 +529,19 @@ static void ublast_state_move(tap_state_t state)
  *
  * As the USB blaster stores the TDO bits in LSB (ie. first bit in (byte0,
  * bit0), second bit in (byte0, bit1), ...), which is what we want to return,
- * simply read bytes from USB interface and store them.
- *
- * Returns ERROR_OK if OK, ERROR_xxx if a read error occured
+ * do nothing ...
  */
-static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes)
+static void ublast_read_byteshifted_tdos(uint8_t *dst, uint8_t *src, int 
nb_bytes)
 {
-       unsigned int retlen;
-       int ret = ERROR_OK;
-
-       DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bytes * 8);
-       ublast_flush_buffer();
-       while (ret == ERROR_OK && nb_bytes > 0) {
-               ret = ublast_buf_read(buf, nb_bytes, &retlen);
-               nb_bytes -= retlen;
-       }
-       return ret;
+       DEBUG_JTAG_IO("buf=%p, num_bits=%d", src, nb_bytes * 8);
+       return;
 }
 
 /**
  * ublast_read_bitbang_tdos - read TDO of bitbang writes
- * @buf: the buffer to store the bits
- * @nb_bits: the number of bits
+ * @dst: the buffer to store the bits
+ * @src: the raw byte stream
+ * @nb_bits: the number of bits (between 1 and 9 included)
  *
  * Reads back from USB Blaster TDO bits, triggered by a 'bitbang write', ie. 
one
  * bit per received byte from USB interface, and store them in buffer, where :
@@ -544,27 +554,20 @@ static int ublast_read_byteshifted_tdos(uint8_t *buf, int 
nb_bytes)
  *
  * Returns ERROR_OK if OK, ERROR_xxx if a read error occured
  */
-static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits)
+static int ublast_read_bitbang_tdos(uint8_t *dst, uint8_t *src, int nb_bits)
 {
        int nb1 = nb_bits;
        int i, ret = ERROR_OK;
-       unsigned int retlen;
-       uint8_t tmp[8];
-
-       DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bits);
+       uint8_t tmp[9];
 
-       /*
-        * Ensure all previous bitbang writes were issued to the dongle, so that
-        * it returns back the read values.
-        */
-       ublast_flush_buffer();
+       DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, src, nb_bits);
 
-       ret = ublast_buf_read(tmp, nb1, &retlen);
+       memcpy(tmp, src, nb1);
        for (i = 0; ret == ERROR_OK && i < nb1; i++)
                if (tmp[i] & READ_TDO)
-                       *buf |= (1 << i);
+                       dst[i /8] |= (1 << i);
                else
-                       *buf &= ~(1 << i);
+                       dst[i / 8] &= ~(1 << i);
        return ret;
 }
 
@@ -578,22 +581,28 @@ static int ublast_read_bitbang_tdos(uint8_t *buf, int 
nb_bits)
  * As a side effect, the last TDI bit is sent along a TMS=1, and triggers a 
JTAG
  * TAP state shift if input bits were non NULL.
  *
- * In order to not saturate the USB Blaster queues, this method reads back TDO
- * if the scan type requests it, and stores them back in bits.
+ * As the write is not actually done but just queued, the readback request 
queue
+ * should be added an item after calling this function. In order to not 
saturate
+ * the USB Blaster queues, this method queues the readback data on readback
+ * queue, so that ublast_flush() can rework the tdos into a bitstream
  *
  * As a side note, the state of TCK when entering this function *must* be
  * low. This is because byteshift mode outputs TDI on rising TCK and reads TDO
  * on falling TCK if and only if TCK is low before queuing byteshift mode 
bytes.
  * If TCK was high, the USB blaster will queue TDI on falling edge, and read 
TDO
  * on rising edge !!!
+ *
+ * Return the allocated structure controlling the request
  */
-static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan)
+static struct ublast_readback_request *
+ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan)
 {
        int nb8 = nb_bits / 8;
        int nb1 = nb_bits % 8;
-       int nbfree_in_packet, i, trans = 0, read_tdos;
-       uint8_t *tdos = calloc(1, nb_bits / 8 + 1);
+       int i, trans = 0, read_tdos;
+       uint32_t retlen;
        static uint8_t byte0[BUF_LEN];
+       struct ublast_readback_request *req = NULL;
 
        /*
         * As the last TDI bit should always be output in bitbang mode in order
@@ -610,17 +619,24 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, 
enum scan_type scan)
        }
 
        read_tdos = (scan == SCAN_IN || scan == SCAN_IO);
+       if (read_tdos) {
+               req = calloc(1, sizeof(*req));
+               if (!req)
+                       return NULL;
+               req->tdos = calloc(1, nb8 + nb1);
+               if (!req->tdos)
+                       return NULL;
+               req->nb_byteshift = nb8;
+               req->nb_bitbang = nb1;
+               ublast_buf_read(req->tdos, nb8 + nb1, &retlen);
+       }
+
        for (i = 0; i < nb8; i += trans) {
-               /*
-                * Calculate number of bytes to fill USB packet of size 
MAX_PACKET_SIZE
-                */
-               nbfree_in_packet = (MAX_PACKET_SIZE - 
(info.bufidx%MAX_PACKET_SIZE));
-               trans = MIN(nbfree_in_packet - 1, nb8 - i);
+               trans = MIN(MAX_BYTESHIFT_NB, nb8 - i);
 
                /*
                 * Queue a byte-shift mode transmission, with as many bytes as
                 * is possible with regard to :
-                *  - current filling level of write buffer
                 *  - remaining bytes to write in byte-shift mode
                 */
                if (read_tdos)
@@ -631,8 +647,6 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, 
enum scan_type scan)
                        ublast_queue_bytes(&bits[i], trans);
                else
                        ublast_queue_bytes(byte0, trans);
-               if (read_tdos)
-                       ublast_read_byteshifted_tdos(&tdos[i], trans);
        }
 
        /*
@@ -645,17 +659,40 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, 
enum scan_type scan)
                else
                        ublast_clock_tdi(tdi, scan);
        }
-       if (nb1 && read_tdos)
-               ublast_read_bitbang_tdos(&tdos[nb8], nb1);
-
-       if (bits)
-               memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8));
-       free(tdos);
 
        /*
         * Ensure clock is in lower state
         */
        ublast_idle_clock();
+
+       return req;
+}
+
+static int ublast_handle_readbacks(void)
+{
+       struct ublast_readback_request *req, *tmp;
+       int ret = 0, nb_bytes;
+       char *str;
+
+       list_for_each_entry_safe(req, tmp, &readback_reqs, list) {
+               nb_bytes = req->nb_byteshift + req->nb_bitbang;
+               str = hexdump(req->tdos, nb_bytes);
+               DEBUG_JTAG_IO("read back on TDO: (size=%d(%d+%d), buf=[%s])",
+                             nb_bytes, req->nb_byteshift, req->nb_bitbang, 
str);
+               free(str);
+
+               ublast_read_byteshifted_tdos(req->tdos, req->tdos,
+                                            req->nb_byteshift);
+               ublast_read_bitbang_tdos(req->tdos + req->nb_byteshift,
+                                        req->tdos + req->nb_byteshift,
+                                        req->nb_bitbang);
+
+               ret |= jtag_read_buffer(req->tdos, req->scan_cmd);
+               free(req->tdos);
+               list_del(&req->list);
+               free(req);
+       }
+       return ret;
 }
 
 static void ublast_runtest(int cycles, tap_state_t state)
@@ -689,6 +726,7 @@ static int ublast_scan(struct scan_command *cmd)
        int ret = ERROR_OK;
        static const char * const type2str[] = { "", "SCAN_IN", "SCAN_OUT", 
"SCAN_IO" };
        char *log_buf = NULL;
+       struct ublast_readback_request *req = NULL;
 
        type = jtag_scan_type(cmd);
        scan_bits = jtag_build_buffer(cmd, &buf);
@@ -705,7 +743,11 @@ static int ublast_scan(struct scan_command *cmd)
                  scan_bits, log_buf, cmd->end_state);
        free(log_buf);
 
-       ublast_queue_tdi(buf, scan_bits, type);
+       req = ublast_queue_tdi(buf, scan_bits, type);
+       if (req) {
+               req->scan_cmd = cmd;
+               list_add_tail(&req->list, &readback_reqs);
+       }
 
        /*
         * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
@@ -717,17 +759,15 @@ static int ublast_scan(struct scan_command *cmd)
        else
                tap_set_state(TAP_DRPAUSE);
 
-       ret = jtag_read_buffer(buf, cmd);
-       if (buf)
-               free(buf);
        ublast_state_move(cmd->end_state);
        return ret;
 }
 
-static void ublast_msleep(int ms)
+static void ublast_msleep(int us)
 {
-       DEBUG_JTAG_IO("%s(ms=%d)",  __func__, ms);
-       jtag_sleep(ms);
+       DEBUG_JTAG_IO("%s(us=%d)",  __func__, us);
+       jtag_sleep(us);
+       ublast_flush();
 }
 
 static int ublast_execute_queue(void)
@@ -739,17 +779,21 @@ static int ublast_execute_queue(void)
             cmd = cmd->next) {
                switch (cmd->type) {
                case JTAG_RESET:
+                       ublast_flush();
                        ublast_reset(cmd->cmd.reset->trst, 
cmd->cmd.reset->srst);
+                       ublast_flush();
                        break;
                case JTAG_RUNTEST:
                        ublast_runtest(cmd->cmd.runtest->num_cycles,
                                       cmd->cmd.runtest->end_state);
+                       ublast_flush();
                        break;
                case JTAG_STABLECLOCKS:
                        ublast_stableclocks(cmd->cmd.stableclocks->num_cycles);
                        break;
                case JTAG_TLR_RESET:
                        ublast_state_move(cmd->cmd.statemove->end_state);
+                       ublast_flush();
                        break;
                case JTAG_PATHMOVE:
                        ublast_path_move(cmd->cmd.pathmove);
@@ -765,8 +809,8 @@ static int ublast_execute_queue(void)
                        break;
                }
        }
+       ublast_flush();
 
-       ublast_flush_buffer();
        return ret;
 }
 
@@ -783,6 +827,7 @@ static int ublast_execute_queue(void)
 static int ublast_init(void)
 {
        static uint8_t tms_reset = 0xff;
+       static unsigned char buf0[BUF_LEN];
        int ret, i;
 
        if (info.lowlevel_name) {
@@ -819,11 +864,16 @@ static int ublast_init(void)
                 * Flush USB-Blaster queue fifos
                 */
                uint32_t retlen;
-               ublast_buf_write(info.buf, BUF_LEN, &retlen);
+               buf0[0] = ublast_build_out(SCAN_OUT);
+               memset(buf0, buf0[0], sizeof(buf0));
+               ublast_buf_write(buf0, BUF_LEN, &retlen);
+               ublast_flush();
+
                /*
                 * Put JTAG in RESET state (five 1 on TMS)
                 */
                ublast_tms_seq(&tms_reset, 5);
+               ublast_flush();
                tap_set_state(TAP_RESET);
        }
        return ret;
@@ -935,7 +985,7 @@ COMMAND_HANDLER(ublast_handle_pin_command)
                if (info.drv) {
                        out_value = ublast_build_out(SCAN_OUT);
                        ublast_queue_byte(out_value);
-                       ublast_flush_buffer();
+                       ublast_flush();
                }
        }
        return ERROR_OK;

-- 

------------------------------------------------------------------------------
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to