This is an automated email from Gerrit.

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

-- gerrit

commit ea4251d5dcae8991c8c2e91a31c3b179572b097e
Author: Eric Hoffman <[email protected]>
Date:   Wed Sep 6 13:25:00 2017 -0400

    topic: USB Blaster massive speedup / handling of USB error timeout / fixes
    
    - USB blaster JTAG driver speedup by an order of magnitude
    - Proper handling of USB timeouts
    - Bug fixes
    
    USB blaster JTAG driver speedup by an order of magnitude
    --------------------------------------------------------
    This is the main item on which I worked upon.  I'm using an Altera USB 
Blaster
    (the original Blaster, not the Blaster-II) with a MIPS target.  I don't 
know if
    it's because I'm under a virtualized environment (VMWare), but I found it to
    be extremely slow.  Upon code review, I found that the OpenOCD blaster 
driver
    is very inefficient with the use of the USB stack.  For every JTAG command, 
it
    would scan out to JTAG DR, and scan in the result immediately.  So, if you 
have
    a JTAG queue with 30 commands, then this would require 30 USB turnaround to
    complete.
    
    I devised a scheme to speed up (tremendously in my case) the communication 
by
    sending and receiving USB data asynchronously.  I have checked with the
    libftdi asynchronous IO functions, but libftdi is pretty dumb regarding 
this,
    and there may be some platforms with an older libftdi which does not support
    asynchronous IO.  Even with the latest libftdi there are some issues.  For 
ex,
    you can not tell it to look for data and return if no data is yet received.
    Even though it has asynchronous functions, when you fetch from the input, if
    no data arrive within the set timeout, libftdi fail and abort.
    
    So, I finally went for a simpler method, which have the advantage that it 
does
    not need to change the functions used by the ftdi (for Blaster) and libusb 
(for
    Blaster-II) interface drivers.  I simply create a second thread when 
executing
    the JTAG queue, which does all the USB listening.  So, all the data out (PC 
to
    Blaster) is still done as before, and all inputs (Blaster to PC) is done in
    it's own thread.
    
    Here's a summary of the change:
    - In the ublast_queue_tdi() function, I removed every USB reads.  The 
function
      now only concentrate on sending data to USB Blaster (I or II).
    - The allocation of the input buffer (for USB data in) has been moved from
      ublast_queue_tdi() to ublast_execute_queue().
    - The idea is that now, instead of sending one DR scan out, reading one DR 
scan
      in, filling the appropriate JTAG queue command scan-in buffer, one by one 
for
      each of the queue scan commands, I now allocate a single buffer, with all
      of the bytes expected to be received from USB for the whole queue, and
      dispatch it to a separate thread, which listen to USB inputs and fill the
      buffer as the bytes come in.  Then, I shift the data out as before.  At 
the
      end, once I have done sending all the data to USB, and that the listening
      thread have filled in the input buffer with all the data received from 
USB,
      I then go once again parsing the JTAG queue and fill in all of the scan-in
      fields.
    
    So, as this is now done in 2 separate threads, the USB inputs and outputs 
will
    not block each other in turn.  The data sending may block because the 
Blaster
    is saturated, but at that time, the input thread will read back any data 
that
    the Blaster has queued toward the PC, and vice-versa.  There is no more
    artificial 'wait time' added (which was slowing down the communication a 
lot),
    and there is no waiting after each JTAG scan-out, to wait for scan-in.
    Everything output (PC->Blaster) is done in a single shot, which will go as 
fast
    as the Blaster can take it (and as efficient as the USB stack can pack the
    data bursts), throttling when needed, and the receiving thread will read out
    any inputs (Blaster-->PC) as fast as the Blaster send them (and also in the
    most efficient way the USB stack can handle bursts).
    
    In my setup, this have effectively reduced long commands chains that took
    almost a full second to a few tens of milliseconds.
    
    !!!!!!!!!!!!!!!!!!!!!
    IMPORTANT NOTE: make distclean
    
    That fix required the use of pthread, so pthread functionality had to be 
added
    to OpenOCD.  That means addition to configure.ac and Makefile.am, plus the
    addition of the file ax_pthread.m4.
    
    As a consequence, after applying this patch, *IT IS REQUIRED* to perform
    a make distclean, followed by ./bootstrap and .configure again, to update 
the
    autogenerated configure/Makefile.in/Makefile.  OpenOCD does not properly 
detect
    changes in the autoconf/automake files and propagate the dependencies down 
to
    the source files.  Otherwise you may get compile error such as undefined
    references to pthread functions and/or failing to compile the source with
    re-entrancy support.
    
    Actually, for now, only USB Blaster is using pthread, for the efficient USB
    communication.  I don't know how the other dongles are programmed, but my 
guess
    is that they could certainly benefit from a similar scheme :-)
    !!!!!!!!!!!!!!!!!!!!!
    
    Proper handling of USB timeouts
    -------------------------------
    This is something that I had to fix when designing the above.  There was a
    generalized issue regarding the way the libusb interface driver handled the
    timeouts and errors from libusb itself (and the same for the ftdi 
counterpart).
    
    For example, it was not possible to distinguish between a timeout (let's say
    you want to read up to 100 bytes, and 50 bytes arrive and you get a 
timeout).
    Then that was treated the same way as an error, returning 0 bytes, and 
flushing
    those 50 received bytes to the deep emptiness of the void...
    
    So, for the USB blaster interface driver, I now check and treat timeouts and
    errors in a separate way.  When an error with libusb (or libftdi) occurs, 
then
    the interface function return the error.  When a timeout occur, it return 
the
    number of bytes actually transferred so far, which could be zero or higher.
    That is effectively the same way most of the socket IO functions works.  A 
read
    or write will return negative value on error, 0 or more on success.  Timeout
    can be detected by checking that number of bytes transferred is equal to 
number
    of bytes that you wanted to transfer.
    
    In the libusb0/libusb1 driver files, I now return proper error code instead 
of
    dumbly converting error codes to 0 for the USB control transfer function.  I
    had to make a few very minor modifications to some of the other JTAG drivers
    for this fix (very minor).
    
    Also, the libusb1 driver read/write functions will return proper error 
codes.
    Finally, the libusb1 will convert the libusb1 error codes constants to
    generic system errors, to save as libusb0 was doing.  The goal is that when 
you
    include libusb-common.h (and use either libusb0 or libusb1 depending on your
    environment), the returned error codes are the same.  That makes error 
handling
    much more generic.
    
    Finally, the USB Blaster adaptation layer between libusb/libftdi and the
    blaster driver (mainly the ublast2_access_libusb.c and ublast_access_ftdi.c
    files) did not publish the timeout parameter at all.  It hardcoded some
    timeouts.  Now it expose the timeout parameter, and the usb_blaster.c file
    can select desired timeout.
    
    Bug fixes
    ---------
    - The usb_flush_buffer() function was doing a loop until the complete buffer
      was flushed out, so there was a reasonable possibility that the data could
      get sent in 2 separate chunks (in 2 separate calls of the USB write
      function).  However, the flush function did not advance the buffer pointer
      after a partial write.  So, if you had 100 bytes to flush out, and only 60
      bytes get flushed on first loop, the second loop would try to send the 40
      remaining bytes from the initial pointer location instead of the buffer at
      position 60.
    - openjtag.c function openjtag_buf_write_standard() added the number of 
bytes
      written to the uninitialized *bytes_written parameter instead of simply
      setting *bytes_written to the number of bytes transferred.  The caller 
does
      not actually look at this parameter.  It should, I have not fixed that, as
      this caller does not handle any error, and simply return void.  So that
      bug never really manifested itself.  But at least this initial issue is
      fixed.
    
    Change-Id: Ie51336d97d9a4f3c1df619b08ccd1831f67fe9c0
    Signed-off-by: Eric Hoffman <[email protected]>

diff --git a/Makefile.am b/Makefile.am
index 930a307..54c05b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,9 +30,10 @@ DIST_SUBDIRS += jimtcl
 endif
 
 # common flags used in openocd build
-AM_CFLAGS = $(GCC_WARNINGS)
+AM_CFLAGS = $(GCC_WARNINGS) $(PTHREAD_CFLAGS)
 
 AM_CPPFLAGS = $(HOST_CPPFLAGS)\
+                         $(PTHREAD_CFLAGS) \
                          -I$(top_srcdir)/src \
                          -I$(top_builddir)/src \
                          -I$(top_srcdir)/src/helper \
@@ -43,6 +44,11 @@ if INTERNAL_JIMTCL
 AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \
                           -I$(top_builddir)/jimtcl
 endif
+
+AM_LDFLAGS = $(PTHREAD_LDFLAGS)
+
+CC = $(PTHREAD_CC)
+
 EXTRA_DIST += \
        BUGS \
        HACKING \
diff --git a/ax_pthread.m4 b/ax_pthread.m4
new file mode 100644
index 0000000..d90de34
--- /dev/null
+++ b/ax_pthread.m4
@@ -0,0 +1,309 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <[email protected]>
+#   Copyright (c) 2011 Daniel Richard G. <[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 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 18
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with 
CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads 
-mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config 
--libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            ax_cv_PTHREAD_PRIO_INHERIT, [
+                AC_LINK_IFELSE([
+                    AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = 
PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have 
PTHREAD_PRIO_INHERIT.]))
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+        if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+        fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX 
threads libraries and header files.]),[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff --git a/configure.ac b/configure.ac
index c680bda..d75f121 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,6 +4,7 @@ AC_INIT([openocd], [0.10.0+dev],
 AC_CONFIG_SRCDIR([src/openocd.c])
 
 m4_include([config_subdir.m4])dnl
+m4_include([ax_pthread.m4])dnl
 
 # check for makeinfo before calling AM_INIT_AUTOMAKE
 AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo])
@@ -29,6 +30,8 @@ AM_PROG_CC_C_O
 AC_PROG_RANLIB
 PKG_PROG_PKG_CONFIG([0.23])
 
+AX_PTHREAD(,[AC_MSG_ERROR([Could not configure pthreads support])])
+
 dnl disable checks for C++, Fortran and GNU Java Compiler
 m4_defun([_LT_AC_LANG_CXX_CONFIG], [:])
 m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c
index c689848..26a44b4 100644
--- a/src/jtag/drivers/kitprog.c
+++ b/src/jtag/drivers/kitprog.c
@@ -421,7 +421,7 @@ static int kitprog_set_protocol(uint8_t protocol)
                (CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | 
CONTROL_COMMAND_PROGRAM,
                protocol, &status, 1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -440,7 +440,7 @@ static int kitprog_get_status(void)
        char status = PROGRAMMER_NOK_NACK;
 
        /* Try a maximum of three times */
-       for (int i = 0; (i < 3) && (transferred == 0); i++) {
+       for (int i = 0; (i < 3) && (transferred <= 0); i++) {
                transferred = 
jtag_libusb_control_transfer(kitprog_handle->usb_handle,
                        LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | 
LIBUSB_RECIPIENT_DEVICE,
                        CONTROL_TYPE_READ,
@@ -449,7 +449,7 @@ static int kitprog_get_status(void)
                jtag_sleep(1000);
        }
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -473,7 +473,7 @@ static int kitprog_set_unknown(void)
                (0x03 << 8) | 0x04,
                0, &status, 1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -498,7 +498,7 @@ static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t 
acquire_mode,
                (CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | 
CONTROL_COMMAND_PROGRAM,
                (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 
1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -522,7 +522,7 @@ static int kitprog_reset_target(void)
                (CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM,
                0, &status, 1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -546,7 +546,7 @@ static int kitprog_swd_sync(void)
                (CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | 
CONTROL_COMMAND_PROGRAM,
                0, &status, 1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
@@ -570,7 +570,7 @@ static int kitprog_swd_seq(uint8_t seq_type)
                (CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM,
                seq_type, &status, 1, 0);
 
-       if (transferred == 0) {
+       if (transferred <= 0) {
                LOG_DEBUG("Zero bytes transferred");
                return ERROR_FAIL;
        }
diff --git a/src/jtag/drivers/libusb0_common.c 
b/src/jtag/drivers/libusb0_common.c
index 1825543..1d79f1c 100644
--- a/src/jtag/drivers/libusb0_common.c
+++ b/src/jtag/drivers/libusb0_common.c
@@ -111,15 +111,8 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle 
*dev, uint8_t request
                uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
                uint16_t size, unsigned int timeout)
 {
-       int transferred = 0;
-
-       transferred = usb_control_msg(dev, requestType, request, wValue, wIndex,
+       return usb_control_msg(dev, requestType, request, wValue, wIndex,
                                bytes, size, timeout);
-
-       if (transferred < 0)
-               transferred = 0;
-
-       return transferred;
 }
 
 int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
diff --git a/src/jtag/drivers/libusb1_common.c 
b/src/jtag/drivers/libusb1_common.c
index 89f8092..f56dcde 100644
--- a/src/jtag/drivers/libusb1_common.c
+++ b/src/jtag/drivers/libusb1_common.c
@@ -121,38 +121,91 @@ void jtag_libusb_close(jtag_libusb_device_handle *dev)
        libusb_exit(jtag_libusb_context);
 }
 
+/* Convert libusb1 specific error codes to generic error codes, same as libusb0
+   returns.  This abstract the version of libusb used.
+   Took from libusb-compat-1.0 */
+static int libusb1_to_generic_result(int result)
+{
+       if (result >= 0)
+               return result;
+
+       switch (result) {
+               case LIBUSB_ERROR_IO:
+                       return -EIO;
+               case LIBUSB_ERROR_INVALID_PARAM:
+                       return -EINVAL;
+               case LIBUSB_ERROR_ACCESS:
+                       return -EACCES;
+               case LIBUSB_ERROR_NO_DEVICE:
+                       return -ENXIO;
+               case LIBUSB_ERROR_NOT_FOUND:
+                       return -ENOENT;
+               case LIBUSB_ERROR_BUSY:
+                       return -EBUSY;
+               case LIBUSB_ERROR_TIMEOUT:
+                       return -ETIMEDOUT;
+               case -ETIMEDOUT:
+                       /* libusb1 bug, sometime, -ETIMEDOUT is returned 
instead of
+                          LIBUSB_ERROR_TIMEOUT, so handle this case */
+                       return -ETIMEDOUT;
+               case LIBUSB_ERROR_OVERFLOW:
+                       return -EOVERFLOW;
+               case LIBUSB_ERROR_PIPE:
+                       return -EPIPE;
+               case LIBUSB_ERROR_INTERRUPTED:
+                       return -EINTR;
+               case LIBUSB_ERROR_NO_MEM:
+                       return -ENOMEM;
+               case LIBUSB_ERROR_NOT_SUPPORTED:
+                       return -ENOSYS;
+               default:
+                       return -ERANGE;
+       }
+}
+
 int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t 
requestType,
                uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
                uint16_t size, unsigned int timeout)
 {
-       int transferred = 0;
+       int retcode;
 
-       transferred = libusb_control_transfer(dev, requestType, request, 
wValue, wIndex,
+       retcode = libusb_control_transfer(dev, requestType, request, wValue, 
wIndex,
                                (unsigned char *)bytes, size, timeout);
 
-       if (transferred < 0)
-               transferred = 0;
-
-       return transferred;
+       return libusb1_to_generic_result(retcode);
 }
 
 int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
                int size, int timeout)
 {
+       int retcode;
        int transferred = 0;
 
-       libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
+       retcode = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
                             &transferred, timeout);
+       if (retcode < 0) {
+               /* Convert libusb1 specific error codes to generic error codes, 
same as
+                  libusb0 return.  This abstract the version of libusb used. */
+               return libusb1_to_generic_result(retcode);
+       }
+
        return transferred;
 }
 
 int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
                int size, int timeout)
 {
+       int retcode;
        int transferred = 0;
 
-       libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
+       retcode = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
                             &transferred, timeout);
+       if (retcode < 0) {
+               /* Convert libusb1 specific error codes to generic error codes, 
same as
+                  libusb0 return.  This abstract the version of libusb used. */
+               return libusb1_to_generic_result(retcode);
+       }
+
        return transferred;
 }
 
diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c
index 8f11b4b..a6332cf 100644
--- a/src/jtag/drivers/openjtag.c
+++ b/src/jtag/drivers/openjtag.c
@@ -229,7 +229,7 @@ static int openjtag_buf_write_standard(
                return ERROR_JTAG_DEVICE_ERROR;
        }
 
-       *bytes_written += retval;
+       *bytes_written = retval;
 
        return ERROR_OK;
 }
@@ -251,7 +251,7 @@ static int openjtag_buf_write_cy7c65215(
        ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST,
                                                                           
CY7C65215_JTAG_WRITE, size, 0,
                                                                           
NULL, 0, CY7C65215_USB_TIMEOUT);
-       if (ret < 0) {
+       if (ret != 0) {
                LOG_ERROR("vendor command failed, error %d", ret);
                return ERROR_JTAG_DEVICE_ERROR;
        }
@@ -319,7 +319,7 @@ static int openjtag_buf_read_cy7c65215(
        ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST,
                                                                           
CY7C65215_JTAG_READ, qty, 0,
                                                                           
NULL, 0, CY7C65215_USB_TIMEOUT);
-       if (ret < 0) {
+       if (ret != 0) {
                LOG_ERROR("vendor command failed, error %d", ret);
                return ERROR_JTAG_DEVICE_ERROR;
        }
@@ -469,7 +469,7 @@ static int openjtag_init_cy7c65215(void)
                                                                           
CY7C65215_JTAG_REQUEST,
                                                                           
CY7C65215_JTAG_ENABLE,
                                                                           0, 
0, NULL, 0, CY7C65215_USB_TIMEOUT);
-       if (ret < 0) {
+       if (ret != 0) {
                LOG_ERROR("could not enable JTAG module");
                goto err;
        }
@@ -522,7 +522,7 @@ static int openjtag_quit_cy7c65215(void)
                                                                           
CY7C65215_JTAG_REQUEST,
                                                                           
CY7C65215_JTAG_DISABLE,
                                                                           0, 
0, NULL, 0, CY7C65215_USB_TIMEOUT);
-       if (ret < 0)
+       if (ret != 0)
                LOG_WARNING("could not disable JTAG module");
 
        jtag_libusb_close(usbh);
diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c 
b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
index d991733..6686e31 100644
--- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
+++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
@@ -40,26 +40,54 @@
 #define SECTION_BUFFERSIZE             16384
 
 static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
-                             unsigned size, uint32_t *bytes_read)
+                             unsigned size, uint32_t *bytes_read, int timeout)
 {
-       *bytes_read = jtag_libusb_bulk_read(low->libusb_dev,
+       int retval;
+
+       retval = jtag_libusb_bulk_read(low->libusb_dev,
                                            USBBLASTER_EPIN | \
                                            LIBUSB_ENDPOINT_IN,
                                            (char *)buf,
                                            size,
-                                           100);
+                                           timeout);
+
+       if (retval < 0) {
+               *bytes_read = 0;
+
+               /* Check if timeout.  If so, return OK (with 0 bytes 
transferred) */
+               if (-ETIMEDOUT == retval)
+                       return ERROR_OK;
+
+               return retval;
+       }
+
+       *bytes_read = (uint32_t)retval;
        return ERROR_OK;
 }
 
 static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
-                              int size, uint32_t *bytes_written)
+                              int size, uint32_t *bytes_written, int timeout)
 {
-       *bytes_written = jtag_libusb_bulk_write(low->libusb_dev,
+       int retval;
+
+       retval = jtag_libusb_bulk_write(low->libusb_dev,
                                                USBBLASTER_EPOUT | \
                                                LIBUSB_ENDPOINT_OUT,
                                                (char *)buf,
                                                size,
-                                               100);
+                                               timeout);
+
+       if (retval < 0) {
+               *bytes_written = 0;
+
+               /* Check if timeout.  If so, return OK (with 0 bytes 
transferred) */
+               if (-ETIMEDOUT == retval)
+                       return ERROR_OK;
+
+               return retval;
+       }
+
+       *bytes_written = (uint32_t)retval;
        return ERROR_OK;
 }
 
@@ -96,7 +124,7 @@ static int ublast2_write_firmware_section(struct 
jtag_libusb_device_handle *libu
                else
                        chunk_size = bytes_remaining;
 
-               jtag_libusb_control_transfer(libusb_dev,
+               ret = jtag_libusb_control_transfer(libusb_dev,
                                             LIBUSB_REQUEST_TYPE_VENDOR | \
                                             LIBUSB_ENDPOINT_OUT,
                                             USBBLASTER_CTRL_LOAD_FIRM,
@@ -106,6 +134,12 @@ static int ublast2_write_firmware_section(struct 
jtag_libusb_device_handle *libu
                                             chunk_size,
                                             100);
 
+               /* Error? */
+               if (ret != chunk_size) {
+                       LOG_ERROR("Error sending USB firmware data");
+                       return ERROR_FAIL;
+               }
+
                bytes_remaining -= chunk_size;
                addr += chunk_size;
                data_ptr += chunk_size;
@@ -142,7 +176,7 @@ static int load_usb_blaster_firmware(struct 
jtag_libusb_device_handle *libusb_de
         */
 
        char value = CPU_RESET;
-       jtag_libusb_control_transfer(libusb_dev,
+       ret = jtag_libusb_control_transfer(libusb_dev,
                                     LIBUSB_REQUEST_TYPE_VENDOR | \
                                     LIBUSB_ENDPOINT_OUT,
                                     USBBLASTER_CTRL_LOAD_FIRM,
@@ -151,6 +185,11 @@ static int load_usb_blaster_firmware(struct 
jtag_libusb_device_handle *libusb_de
                                     &value,
                                     1,
                                     100);
+       /* Error? */
+       if (ret != 1) {
+               LOG_ERROR("Error while downloading the firmware");
+               return ERROR_FAIL;
+       }
 
        /* Download all sections in the image to ULINK */
        for (int i = 0; i < ublast2_firmware_image.num_sections; i++) {
@@ -163,7 +202,7 @@ static int load_usb_blaster_firmware(struct 
jtag_libusb_device_handle *libusb_de
        }
 
        value = !CPU_RESET;
-       jtag_libusb_control_transfer(libusb_dev,
+       ret = jtag_libusb_control_transfer(libusb_dev,
                                     LIBUSB_REQUEST_TYPE_VENDOR | \
                                     LIBUSB_ENDPOINT_OUT,
                                     USBBLASTER_CTRL_LOAD_FIRM,
@@ -172,6 +211,11 @@ static int load_usb_blaster_firmware(struct 
jtag_libusb_device_handle *libusb_de
                                     &value,
                                     1,
                                     100);
+       /* Error? */
+       if (ret != 1) {
+               LOG_ERROR("Error while downloading the firmware");
+               return ERROR_FAIL;
+       }
 
        image_close(&ublast2_firmware_image);
 
@@ -218,7 +262,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
        }
 
        char buffer[5];
-       jtag_libusb_control_transfer(low->libusb_dev,
+       ret = jtag_libusb_control_transfer(low->libusb_dev,
                                     LIBUSB_REQUEST_TYPE_VENDOR | \
                                     LIBUSB_ENDPOINT_IN,
                                     USBBLASTER_CTRL_READ_REV,
@@ -227,6 +271,11 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
                                     buffer,
                                     5,
                                     100);
+       /* Error? */
+       if (ret != 5) {
+               LOG_ERROR("Error getting firmware revision");
+               return ERROR_FAIL;
+       }
 
        LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer);
 
diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h 
b/src/jtag/drivers/usb_blaster/ublast_access.h
index 252f003..b9e2019 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access.h
+++ b/src/jtag/drivers/usb_blaster/ublast_access.h
@@ -43,9 +43,9 @@ struct ublast_lowlevel {
        char *firmware_path;
 
        int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size,
-                    uint32_t *bytes_written);
+                    uint32_t *bytes_written, int timeout);
        int (*read)(struct ublast_lowlevel *low, uint8_t *buf, unsigned size,
-                   uint32_t *bytes_read);
+                   uint32_t *bytes_read, int timeout);
        int (*open)(struct ublast_lowlevel *low);
        int (*close)(struct ublast_lowlevel *low);
        int (*speed)(struct ublast_lowlevel *low, int speed);
diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c 
b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
index cb442f2..29035fd 100644
--- a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
+++ b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c
@@ -29,6 +29,7 @@
 #endif
 #include <jtag/interface.h>
 #include <jtag/commands.h>
+#include <helper/time_support.h>
 
 #include "ublast_access.h"
 #include <ftdi.h>
@@ -39,41 +40,73 @@ static struct ftdi_context *ublast_getftdic(struct 
ublast_lowlevel *low)
 }
 
 static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf,
-                           unsigned size, uint32_t *bytes_read)
+                           unsigned size, uint32_t *bytes_read, int timeout)
 {
        int retval;
-       int timeout = 100;
        struct ftdi_context *ftdic = ublast_getftdic(low);
+       int64_t timeout_time = timeval_ms() + timeout;
+
+       if (timeout)
+               ftdic->usb_read_timeout = timeout;
 
        *bytes_read = 0;
-       while ((*bytes_read < size) && timeout--) {
-               retval = ftdi_read_data(ftdic, buf + *bytes_read,
-                               size - *bytes_read);
-               if (retval < 0) {
+
+       /* Work around libftdi bug, which return immediately withouth honoring 
the
+         timeout value */
+       while (*bytes_read < size) {
+               retval = ftdi_read_data(ftdic, buf + *bytes_read, size - 
*bytes_read);
+               /* Discard timeout errors here */
+#if (defined LIBUSB_ERROR_TIMEOUT)
+               /* Maybe compiled on a system with an old libftdi, with only
+                  libusb0 installed, and no definition of LIBUSB_ERROR_TIMEOUT 
*/
+               if ((retval == LIBUSB_ERROR_TIMEOUT) && (retval == -ETIMEDOUT)) 
{
+#else
+               if (retval == -ETIMEDOUT)
+#endif
+                       retval = 0; /* No data */
+
+               /* Check if error */
+               if (retval < 0) {
+                       /* Return error */
                        *bytes_read = 0;
                        LOG_ERROR("ftdi_read_data: %s",
                                        ftdi_get_error_string(ftdic));
                        return ERROR_JTAG_DEVICE_ERROR;
                }
-               *bytes_read += retval;
+
+               *bytes_read += (uint32_t)retval;
+
+               /* Exit if we have timed-out. */
+               if (timeout) {
+                       if (timeval_ms() >= timeout_time)
+                               return ERROR_OK; /* Return OK, with what we 
have so far. */
+               }
        }
        return ERROR_OK;
 }
 
 static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int 
size,
-                            uint32_t *bytes_written)
+                            uint32_t *bytes_written, int timeout)
 {
        int retval;
        struct ftdi_context *ftdic = ublast_getftdic(low);
 
+       ftdic->usb_write_timeout = timeout;
+
        retval = ftdi_write_data(ftdic, buf, size);
        if (retval < 0) {
                *bytes_written = 0;
+
+               /* Check for timeout.  */
+               if ((retval == LIBUSB_ERROR_TIMEOUT) ||
+                       (retval == -ETIMEDOUT))
+                       return -ETIMEDOUT; /* Return what we have so far */
+
                LOG_ERROR("ftdi_write_data: %s",
                          ftdi_get_error_string(ftdic));
                return ERROR_JTAG_DEVICE_ERROR;
        }
-       *bytes_written = retval;
+       *bytes_written = (uint32_t)retval;
        return ERROR_OK;
 }
 
diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c 
b/src/jtag/drivers/usb_blaster/usb_blaster.c
index a975bd1..9bc5a80 100644
--- a/src/jtag/drivers/usb_blaster/usb_blaster.c
+++ b/src/jtag/drivers/usb_blaster/usb_blaster.c
@@ -85,6 +85,7 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <time.h>
+#include <pthread.h>
 
 /* Size of USB endpoint max packet size, ie. 64 bytes */
 #define MAX_PACKET_SIZE 64
@@ -99,6 +100,16 @@
 /* USB-Blaster II specific command */
 #define CMD_COPY_TDO_BUFFER    0x5F
 
+#define TCK            (1 << 0)
+#define TMS            (1 << 1)
+#define NCE            (1 << 2)
+#define NCS            (1 << 3)
+#define TDI            (1 << 4)
+#define LED            (1 << 5)
+#define READ           (1 << 6)
+#define SHMODE         (1 << 7)
+#define READ_TDO       (1 << 0)
+
 enum gpio_steer {
        FIXED_0 = 0,
        FIXED_1,
@@ -115,6 +126,15 @@ struct ublast_info {
        bool srst_asserted;
        uint8_t buf[BUF_LEN];
        int bufidx;
+       /* Use async USB input buf for much lower latency */
+       pthread_t     in_thread;
+       volatile int  in_thread_terminate; /* Signal input thread to terminate.
+                                                                               
  Not using a mutex here, only used
+                                                                               
  as a simple one-time signal */
+       int           in_thread_status;
+       uint8_t      *in_buf;
+       uint32_t      in_buf_size;
+       uint32_t      in_bufidx;
 
        char *lowlevel_name;
        struct ublast_lowlevel *drv;
@@ -169,9 +189,9 @@ static char *hexdump(uint8_t *buf, unsigned int size)
        return str;
 }
 
-static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read)
+static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read, 
int timeout)
 {
-       int ret = info.drv->read(info.drv, buf, size, bytes_read);
+       int ret = info.drv->read(info.drv, buf, size, bytes_read, timeout);
        char *str = hexdump(buf, *bytes_read);
 
        DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str,
@@ -180,9 +200,9 @@ static int ublast_buf_read(uint8_t *buf, unsigned size, 
uint32_t *bytes_read)
        return ret;
 }
 
-static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written)
+static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written, 
int timeout)
 {
-       int ret = info.drv->write(info.drv, buf, size, bytes_written);
+       int ret = info.drv->write(info.drv, buf, size, bytes_written, timeout);
        char *str = hexdump(buf, *bytes_written);
 
        DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str,
@@ -198,16 +218,242 @@ static int nb_buf_remaining(void)
 
 static void ublast_flush_buffer(void)
 {
+       int ret = ERROR_OK;
        unsigned int retlen;
-       int nb = info.bufidx, ret = ERROR_OK;
+       int nb_left = info.bufidx;
+       int nb_sent = 0;
+
+       while (nb_left > 0) {
+               ret = ublast_buf_write(&info.buf[nb_sent], nb_left, &retlen, 
500);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("Error flushing data");
+                       /* We should propagate and handle the error properly... 
*/
+                       break;
+               }
 
-       while (ret == ERROR_OK && nb > 0) {
-               ret = ublast_buf_write(info.buf, nb, &retlen);
-               nb -= retlen;
+               nb_sent += retlen;
+               nb_left -= retlen;
        }
        info.bufidx = 0;
 }
 
+static void *ublast_in_buf_read_thread(void *arg)
+{
+       (void)arg; /* Unused, just prevent compiler from whining... */
+
+       int ret = ERROR_OK;
+       uint32_t num_left_to_read, num_read;
+       int last_pass = 0;
+
+       while (((num_left_to_read = info.in_buf_size - info.in_bufidx) > 0) &&
+                  (!last_pass)) {
+               /* One last pass? */
+               if (info.in_thread_terminate)
+                       last_pass = 1; /* Last pass, wait 500ms more */
+
+               /* Get any bytes that are available */
+               ret = ublast_buf_read(&info.in_buf[info.in_bufidx], 
num_left_to_read, &num_read, 500);
+               if (ret != ERROR_OK)
+                       break; /* Stop here, we'll report this status... */
+
+               info.in_bufidx += num_read;
+       }
+
+       /* If no error, check that we read all the required bytes before being 
asked to terminate */
+       if (ret == ERROR_OK) {
+               if (info.in_bufidx != info.in_buf_size)
+                       ret = ERROR_FAIL; /* Did not receive all the expected 
data before termination */
+       }
+
+       /* Done */
+       info.in_thread_status = ret;
+       pthread_exit(NULL);
+}
+
+static int ublast_in_buf_read_thread_start(void)
+{
+       pthread_attr_t attr;
+
+       info.in_thread_terminate = 0; /* Reset this */
+
+       /* Set thread attribute, as joinable. */
+       if (pthread_attr_init(&attr) < 0)
+               return ERROR_FAIL;
+       if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) < 0) {
+               pthread_attr_destroy(&attr);
+               return ERROR_FAIL;
+       }
+
+       /* Create thread */
+       if (pthread_create(&info.in_thread, &attr, ublast_in_buf_read_thread, 
NULL) < 0) {
+               pthread_attr_destroy(&attr);
+               return ERROR_FAIL;
+       }
+
+       /* Done with attribute */
+       (void)pthread_attr_destroy(&attr);
+
+       return ERROR_OK;
+}
+
+static int ublast_in_buf_read_thread_wait(void)
+{
+       /* Signal thread to terminate */
+       info.in_thread_terminate = 1;
+
+       /* Wait for thread to terminate and get status */
+       if (pthread_join(info.in_thread, NULL) < 0)
+               return ERROR_FAIL;
+
+       /* Clear thread ID. */
+       memset(&info.in_thread, 0, sizeof(info.in_thread));
+
+       return info.in_thread_status;
+}
+
+/**
+ * ublast_read_byteshifted_tdos - read TDO of byteshift writes from USB input 
buffer
+ * @inbuf: the buffer where to get the byte shifted TDO
+ * @outbuf: the buffer to store the bytes
+ * @nb_bytes: the number of bytes
+ *
+ * Store the byteshifted TDO data received from the scan, from the USB input 
buffer.
+ *
+ * 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.
+ */
+static void ublast_read_byteshifted_tdos(uint8_t *inbuf, uint8_t *outbuf, int 
nb_bytes)
+{
+       memcpy(outbuf, inbuf, nb_bytes);
+}
+
+/**
+ * ublast_read_bitbang_tdos - read TDO of bitbang writes from USB input buffer
+ * @inbuf: the buffer where to get the byte shifted TDO
+ * @outbuf: the buffer to store the bits
+ * @nb_bits: the number of bits
+ *
+ * Store the bitbanged TDO data received from the scan, from the USB input 
buffer,
+ * ie. one bit per received byte from USB interface, and store them in buffer,
+ * where :
+ *  - first bit is stored in byte0, bit0 (LSB)
+ *  - second bit is stored in byte0, bit 1
+ *  ...
+ *  - eight bit is sotred in byte0, bit 7
+ *  - ninth bit is sotred in byte1, bit 0
+ *  - etc ...
+ */
+static void ublast_read_bitbang_tdos(uint8_t *inbuf, uint8_t *outbuf, int 
nb_bits)
+{
+       int i;
+       int bit;
+       int byte;
+
+       for (i = 0; i < nb_bits; i++) {
+               byte = i / 8;
+               bit = i % 8;
+               /* Clear new bytes */
+               if (bit == 0)
+                       outbuf[byte] = 0;
+               /* Set bits for which TDO read high */
+               if (inbuf[i] & READ_TDO)
+                       outbuf[byte] |= (1 << bit);
+       }
+}
+
+static void ublast_in_buf_build(void)
+{
+       struct jtag_command *cmd;
+
+       /* Find total number of input USB bytes */
+       info.in_buf_size = 0;
+       for (cmd = jtag_command_queue; cmd != NULL; cmd = cmd->next) {
+               /* Scan in? */
+               if ((cmd->type == JTAG_SCAN) && (jtag_scan_type(cmd->cmd.scan) 
& SCAN_IN)) {
+                       int nb_bits = jtag_scan_size(cmd->cmd.scan);
+                       int nb8 = nb_bits / 8;
+                       int nb1 = nb_bits % 8;
+
+                       /*
+                        * As stated in ublast_queue_tdi():
+                        * 
--------------------------------------------------------------------
+                        * As the last TDI bit should always be output in 
bitbang mode in
+                        * order to activate the TMS=1 transition to EXIT_?R 
state.
+                        * Therefore a situation where nb_bits is a multiple of 
8 is
+                        * handled as follows:
+                        * - the number of TDI shifted out in "byteshift mode" 
is 8 less
+                        *   than nb_bits
+                        * - nb1 = 8
+                        * This ensures that nb1 is never 0, and allows the TMS 
transition.
+                        */
+                       if (nb8 > 0 && nb1 == 0) {
+                               nb8--;
+                               nb1 = 8;
+                       }
+                       info.in_buf_size += nb8 + nb1;
+               }
+       }
+       info.in_bufidx = 0;
+       if (info.in_buf_size > 0)
+               info.in_buf = calloc(1, info.in_buf_size);
+}
+
+static void ublast_in_buf_read(void)
+{
+       struct jtag_command *cmd;
+       int inbuf_pos;
+
+       if (info.in_buf_size == 0)
+               return; /* Nothing to do */
+
+       /* Find total number of input USB bytes */
+       inbuf_pos = 0;
+       for (cmd = jtag_command_queue; cmd != NULL; cmd = cmd->next) {
+               /* Scan in? */
+               if ((cmd->type == JTAG_SCAN) && (jtag_scan_type(cmd->cmd.scan) 
& SCAN_IN)) {
+                       int nb_bits = jtag_scan_size(cmd->cmd.scan);
+                       int nb8 = nb_bits / 8;
+                       int nb1 = nb_bits % 8;
+
+                       /*
+                        * Same calculations as in ublast_queue_tdi().  As 
stated:
+                        * 
----------------------------------------------------------------
+                        * As the last TDI bit should always be output in 
bitbang mode in
+                        * order to activate the TMS=1 transition to EXIT_?R 
state.
+                        * Therefore a situation where nb_bits is a multiple of 
8 is
+                        * handled as follows:
+                        * - the number of TDI shifted out in "byteshift mode" 
is 8 less
+                        *   than nb_bits
+                        * - nb1 = 8
+                        * This ensures that nb1 is never 0, and allows the TMS 
transition.
+                        * 
----------------------------------------------------------------
+                        */
+                       if (nb8 > 0 && nb1 == 0) {
+                               nb8--;
+                               nb1 = 8;
+                       }
+
+                       uint8_t *tdos = calloc(1, (nb_bits + 7) / 8);
+
+                       ublast_read_byteshifted_tdos(&info.in_buf[inbuf_pos], 
tdos, nb8);
+                       ublast_read_bitbang_tdos(&info.in_buf[inbuf_pos + nb8], 
&tdos[nb8], nb1);
+                       inbuf_pos += nb8 + nb1;
+
+                       /* Fill input fields */
+                       jtag_read_buffer(tdos, cmd->cmd.scan);
+
+                       free(tdos);
+               }
+       }
+
+       /* Clear input buffer */
+       info.in_bufidx = 0;
+       info.in_buf_size = 0;
+       free(info.in_buf);
+       info.in_buf = NULL;
+}
+
 /*
  * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 
data
  * bits (bidirectional) in a single USB packet. A header byte has to be sent as
@@ -241,16 +487,6 @@ static void ublast_flush_buffer(void)
  * It isn't possible to read a data without transmitting data.
  */
 
-#define TCK            (1 << 0)
-#define TMS            (1 << 1)
-#define NCE            (1 << 2)
-#define NCS            (1 << 3)
-#define TDI            (1 << 4)
-#define LED            (1 << 5)
-#define READ           (1 << 6)
-#define SHMODE         (1 << 7)
-#define READ_TDO       (1 << 0)
-
 /**
  * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster
  * @abyte: the byte to queue
@@ -521,74 +757,6 @@ 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
- * @nb_bits: the number of bits
- *
- * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. 
eight
- * bits per received byte from USB interface, and store them in buffer.
- *
- * 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
- */
-static int ublast_read_byteshifted_tdos(uint8_t *buf, 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;
-}
-
-/**
- * ublast_read_bitbang_tdos - read TDO of bitbang writes
- * @buf: the buffer to store the bits
- * @nb_bits: the number of bits
- *
- * 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 :
- *  - first bit is stored in byte0, bit0 (LSB)
- *  - second bit is stored in byte0, bit 1
- *  ...
- *  - eight bit is sotred in byte0, bit 7
- *  - ninth bit is sotred in byte1, bit 0
- *  - etc ...
- *
- * Returns ERROR_OK if OK, ERROR_xxx if a read error occured
- */
-static int ublast_read_bitbang_tdos(uint8_t *buf, 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);
-
-       /*
-        * Ensure all previous bitbang writes were issued to the dongle, so that
-        * it returns back the read values.
-        */
-       ublast_flush_buffer();
-
-       ret = ublast_buf_read(tmp, nb1, &retlen);
-       for (i = 0; ret == ERROR_OK && i < nb1; i++)
-               if (tmp[i] & READ_TDO)
-                       *buf |= (1 << i);
-               else
-                       *buf &= ~(1 << i);
-       return ret;
-}
-
-/**
  * ublast_queue_tdi - short description
  * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
  * @nb_bits: number of bits
@@ -612,7 +780,6 @@ static void 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);
        static uint8_t byte0[BUF_LEN];
 
        /*
@@ -654,7 +821,6 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, 
enum scan_type scan)
                if (read_tdos) {
                        if (info.flags & COPY_TDO_BUFFER)
                                ublast_queue_byte(CMD_COPY_TDO_BUFFER);
-                       ublast_read_byteshifted_tdos(&tdos[i], trans);
                }
        }
 
@@ -671,13 +837,8 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, 
enum scan_type scan)
        if (nb1 && read_tdos) {
                if (info.flags & COPY_TDO_BUFFER)
                        ublast_queue_byte(CMD_COPY_TDO_BUFFER);
-               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
         */
@@ -743,7 +904,6 @@ 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);
@@ -772,7 +932,8 @@ static void ublast_initial_wipeout(void)
         *  - empty the write FIFO (128 bytes)
         *  - empty the read FIFO (384 bytes)
         */
-       ublast_buf_write(info.buf, BUF_LEN, &retlen);
+       ublast_buf_write(info.buf, BUF_LEN, &retlen, 100);
+       ublast_buf_read(info.buf, BUF_LEN, &retlen, 100);
        /*
         * Put JTAG in RESET state (five 1 on TMS)
         */
@@ -791,6 +952,16 @@ static int ublast_execute_queue(void)
                ublast_initial_wipeout();
        }
 
+       /* Prepage input buffer */
+       ublast_in_buf_build();
+       if (info.in_buf_size > 0) {
+               ret = ublast_in_buf_read_thread_start();
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("Unable to start input buffer trhread");
+                       return ret;
+               }
+       }
+
        for (cmd = jtag_command_queue; ret == ERROR_OK && cmd != NULL;
             cmd = cmd->next) {
                switch (cmd->type) {
@@ -823,6 +994,18 @@ static int ublast_execute_queue(void)
        }
 
        ublast_flush_buffer();
+
+       if (info.in_buf_size > 0) {
+               ret = ublast_in_buf_read_thread_wait();
+               if ((ret != ERROR_OK) ||
+                       (info.in_bufidx != info.in_buf_size)) {
+                       LOG_ERROR("Error receiving data bytes from USB");
+                       return ret;
+               }
+               /* Write back the received data */
+               ublast_in_buf_read();
+       }
+
        return ret;
 }
 
@@ -898,7 +1081,7 @@ static int ublast_quit(void)
        uint8_t byte0 = 0;
        unsigned int retlen;
 
-       ublast_buf_write(&byte0, 1, &retlen);
+       ublast_buf_write(&byte0, 1, &retlen, 100);
        return info.drv->close(info.drv);
 }
 

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to