This is an automated email from Gerrit.

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

-- gerrit

commit e64b1333c38bed42137b04a29aa2a501df092006
Author: Tarek BOCHKATI <[email protected]>
Date:   Sun May 10 13:19:57 2020 +0100

    stlink: split driver [RFC]
    
    this is an absolute move of code without unneeded modification.
    the driver is now split into:
     - stlink_usb.c : contains USB related functions.
     - stlink_server.c : contains the implementation to support ST-Link server
    
    Note: in stlink_usb there is special commands for stlink v1, needed only in
    stlink_usb.c
    
    Change-Id: Id4428424a6c835419f27c78064a291605225569c
    Signed-off-by: Tarek BOCHKATI <[email protected]>

diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index 052a4ea..f7172de 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -131,6 +131,8 @@ DRIVERFILES += %D%/remote_bitbang.c
 endif
 if HLADAPTER
 DRIVERFILES += %D%/stlink/stlink.c
+DRIVERFILES += %D%/stlink/stlink_usb.c
+DRIVERFILES += %D%/stlink/stlink_server.c
 DRIVERFILES += %D%/ti_icdi_usb.c
 endif
 if OSBDM
@@ -180,5 +182,6 @@ DRIVERHEADERS = \
        %D%/versaloon/usbtoxxx/usbtoxxx_internal.h \
        %D%/versaloon/versaloon.h \
        %D%/versaloon/versaloon_include.h \
-       %D%/versaloon/versaloon_internal.h
+       %D%/versaloon/versaloon_internal.h \
+       %D%/stlink/stlink.h
 
diff --git a/src/jtag/drivers/stlink/stlink.c b/src/jtag/drivers/stlink/stlink.c
index d772a9d..934d7a0 100644
--- a/src/jtag/drivers/stlink/stlink.c
+++ b/src/jtag/drivers/stlink/stlink.c
@@ -28,374 +28,20 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "stlink.h"
+
+
 
 /* project specific includes */
-#include <helper/binarybuffer.h>
+
 #include <helper/bits.h>
 #include <jtag/interface.h>
-#include <jtag/hla/hla_layout.h>
-#include <jtag/hla/hla_transport.h>
-#include <jtag/hla/hla_interface.h>
 #include <jtag/swim.h>
 #include <target/target.h>
 #include <transport/transport.h>
 
 #include <target/cortex_m.h>
 
-#if WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/uio.h>
-#include <netinet/tcp.h>
-#endif
-
-#include "../libusb_helper.h"
-
-#ifdef HAVE_LIBUSB1
-#define USE_LIBUSB_ASYNCIO
-#endif
-
-#define STLINK_SERIAL_LEN 24
-
-#define ENDPOINT_IN  0x80
-#define ENDPOINT_OUT 0x00
-
-#define STLINK_WRITE_TIMEOUT 1000
-#define STLINK_READ_TIMEOUT 1000
-
-#define STLINK_RX_EP          (1|ENDPOINT_IN)
-#define STLINK_TX_EP          (2|ENDPOINT_OUT)
-#define STLINK_TRACE_EP       (3|ENDPOINT_IN)
-
-#define STLINK_V2_1_TX_EP     (1|ENDPOINT_OUT)
-#define STLINK_V2_1_TRACE_EP  (2|ENDPOINT_IN)
-
-#define STLINK_SG_SIZE        (31)
-#define STLINK_DATA_SIZE      (4096)
-#define STLINK_CMD_SIZE_V2    (16)
-#define STLINK_CMD_SIZE_V1    (10)
-
-#define STLINK_V1_PID         (0x3744)
-#define STLINK_V2_PID         (0x3748)
-#define STLINK_V2_1_PID       (0x374B)
-#define STLINK_V2_1_NO_MSD_PID  (0x3752)
-#define STLINK_V3_USBLOADER_PID (0x374D)
-#define STLINK_V3E_PID          (0x374E)
-#define STLINK_V3S_PID          (0x374F)
-#define STLINK_V3_2VCP_PID      (0x3753)
-
-/*
- * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and
- * this limits the bulk packet size and the 8bit read/writes to max 64 bytes.
- * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6.
- */
-#define STLINK_MAX_RW8         (64)
-#define STLINKV3_MAX_RW8       (512)
-
-/* "WAIT" responses will be retried (with exponential backoff) at
- * most this many times before failing to caller.
- */
-#define MAX_WAIT_RETRIES 8
-
-enum stlink_jtag_api_version {
-       STLINK_JTAG_API_V1 = 1,
-       STLINK_JTAG_API_V2,
-       STLINK_JTAG_API_V3,
-};
-
-enum stlink_mode {
-       STLINK_MODE_UNKNOWN = 0,
-       STLINK_MODE_DFU,
-       STLINK_MODE_MASS,
-       STLINK_MODE_DEBUG_JTAG,
-       STLINK_MODE_DEBUG_SWD,
-       STLINK_MODE_DEBUG_SWIM
-};
-
-/** */
-struct stlink_usb_version {
-       /** */
-       int stlink;
-       /** */
-       int jtag;
-       /** */
-       int swim;
-       /** jtag api version supported */
-       enum stlink_jtag_api_version jtag_api;
-       /** one bit for each feature supported. See macros STLINK_F_* */
-       uint32_t flags;
-};
-
-struct stlink_usb_priv_s {
-       /** */
-       struct libusb_device_handle *fd;
-       /** */
-       struct libusb_transfer *trans;
-};
-
-struct stlink_server_priv_s {
-       /** */
-       int fd;
-       /** */
-       bool connected;
-       /** */
-       uint32_t device_id;
-       /** */
-       uint32_t connect_id;
-};
-
-struct stlink_interface_s {
-       /** */
-       void *priv;
-       /** */
-       int (*open)(void *handle, struct hl_interface_param_s *param);
-       /** */
-       int (*close)(void *handle);
-       /** */
-       int (*xfer)(void *handle, const uint8_t *buf, int size);
-       /** */
-       int (*read)(void *handle, const uint8_t *buf, int size);
-};
-
-/** */
-struct stlink_usb_handle_s {
-       /** */
-       struct stlink_interface_s *itf;
-       /** */
-       uint8_t rx_ep;
-       /** */
-       uint8_t tx_ep;
-       /** */
-       uint8_t trace_ep;
-       /** */
-       uint8_t cmdbuf[STLINK_SG_SIZE];
-       /** */
-       uint8_t cmdidx;
-       /** */
-       uint8_t direction;
-       /** */
-       uint8_t databuf[STLINK_DATA_SIZE];
-       /** */
-       uint32_t max_mem_packet;
-       /** */
-       enum stlink_mode st_mode;
-       /** */
-       struct stlink_usb_version version;
-       /** */
-       uint16_t vid;
-       /** */
-       uint16_t pid;
-       /** */
-       struct {
-               /** whether SWO tracing is enabled or not */
-               bool enabled;
-               /** trace module source clock */
-               uint32_t source_hz;
-       } trace;
-       /** reconnect is needed next time we try to query the
-        * status */
-       bool reconnect_pending;
-};
-
-#define STLINK_SWIM_ERR_OK             0x00
-#define STLINK_SWIM_BUSY               0x01
-#define STLINK_DEBUG_ERR_OK            0x80
-#define STLINK_DEBUG_ERR_FAULT         0x81
-#define STLINK_SWD_AP_WAIT             0x10
-#define STLINK_SWD_AP_FAULT            0x11
-#define STLINK_SWD_AP_ERROR            0x12
-#define STLINK_SWD_AP_PARITY_ERROR     0x13
-#define STLINK_JTAG_GET_IDCODE_ERROR   0x09
-#define STLINK_JTAG_WRITE_ERROR        0x0c
-#define STLINK_JTAG_WRITE_VERIF_ERROR  0x0d
-#define STLINK_SWD_DP_WAIT             0x14
-#define STLINK_SWD_DP_FAULT            0x15
-#define STLINK_SWD_DP_ERROR            0x16
-#define STLINK_SWD_DP_PARITY_ERROR     0x17
-
-#define STLINK_SWD_AP_WDATA_ERROR      0x18
-#define STLINK_SWD_AP_STICKY_ERROR     0x19
-#define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a
-
-#define STLINK_BAD_AP_ERROR            0x1d
-
-#define STLINK_CORE_RUNNING            0x80
-#define STLINK_CORE_HALTED             0x81
-#define STLINK_CORE_STAT_UNKNOWN       -1
-
-#define STLINK_GET_VERSION             0xF1
-#define STLINK_DEBUG_COMMAND           0xF2
-#define STLINK_DFU_COMMAND             0xF3
-#define STLINK_SWIM_COMMAND            0xF4
-#define STLINK_GET_CURRENT_MODE        0xF5
-#define STLINK_GET_TARGET_VOLTAGE      0xF7
-
-#define STLINK_DEV_DFU_MODE            0x00
-#define STLINK_DEV_MASS_MODE           0x01
-#define STLINK_DEV_DEBUG_MODE          0x02
-#define STLINK_DEV_SWIM_MODE           0x03
-#define STLINK_DEV_BOOTLOADER_MODE     0x04
-#define STLINK_DEV_UNKNOWN_MODE        -1
-
-#define STLINK_DFU_EXIT                0x07
-
-/*
-       STLINK_SWIM_ENTER_SEQ
-       1.3ms low then 750Hz then 1.5kHz
-
-       STLINK_SWIM_GEN_RST
-       STM8 DM pulls reset pin low 50us
-
-       STLINK_SWIM_SPEED
-       uint8_t (0=low|1=high)
-
-       STLINK_SWIM_WRITEMEM
-       uint16_t length
-       uint32_t address
-
-       STLINK_SWIM_RESET
-       send syncronization seq (16us low, response 64 clocks low)
-*/
-#define STLINK_SWIM_ENTER                  0x00
-#define STLINK_SWIM_EXIT                   0x01
-#define STLINK_SWIM_READ_CAP               0x02
-#define STLINK_SWIM_SPEED                  0x03
-#define STLINK_SWIM_ENTER_SEQ              0x04
-#define STLINK_SWIM_GEN_RST                0x05
-#define STLINK_SWIM_RESET                  0x06
-#define STLINK_SWIM_ASSERT_RESET           0x07
-#define STLINK_SWIM_DEASSERT_RESET         0x08
-#define STLINK_SWIM_READSTATUS             0x09
-#define STLINK_SWIM_WRITEMEM               0x0a
-#define STLINK_SWIM_READMEM                0x0b
-#define STLINK_SWIM_READBUF                0x0c
-
-#define STLINK_DEBUG_GETSTATUS             0x01
-#define STLINK_DEBUG_FORCEDEBUG            0x02
-#define STLINK_DEBUG_APIV1_RESETSYS        0x03
-#define STLINK_DEBUG_APIV1_READALLREGS     0x04
-#define STLINK_DEBUG_APIV1_READREG         0x05
-#define STLINK_DEBUG_APIV1_WRITEREG        0x06
-#define STLINK_DEBUG_READMEM_32BIT         0x07
-#define STLINK_DEBUG_WRITEMEM_32BIT        0x08
-#define STLINK_DEBUG_RUNCORE               0x09
-#define STLINK_DEBUG_STEPCORE              0x0a
-#define STLINK_DEBUG_APIV1_SETFP           0x0b
-#define STLINK_DEBUG_READMEM_8BIT          0x0c
-#define STLINK_DEBUG_WRITEMEM_8BIT         0x0d
-#define STLINK_DEBUG_APIV1_CLEARFP         0x0e
-#define STLINK_DEBUG_APIV1_WRITEDEBUGREG   0x0f
-#define STLINK_DEBUG_APIV1_SETWATCHPOINT   0x10
-
-#define STLINK_DEBUG_ENTER_JTAG_RESET      0x00
-#define STLINK_DEBUG_ENTER_SWD_NO_RESET    0xa3
-#define STLINK_DEBUG_ENTER_JTAG_NO_RESET   0xa4
-
-#define STLINK_DEBUG_APIV1_ENTER           0x20
-#define STLINK_DEBUG_EXIT                  0x21
-#define STLINK_DEBUG_READCOREID            0x22
-
-#define STLINK_DEBUG_APIV2_ENTER           0x30
-#define STLINK_DEBUG_APIV2_READ_IDCODES    0x31
-#define STLINK_DEBUG_APIV2_RESETSYS        0x32
-#define STLINK_DEBUG_APIV2_READREG         0x33
-#define STLINK_DEBUG_APIV2_WRITEREG        0x34
-#define STLINK_DEBUG_APIV2_WRITEDEBUGREG   0x35
-#define STLINK_DEBUG_APIV2_READDEBUGREG    0x36
-
-#define STLINK_DEBUG_APIV2_READALLREGS     0x3A
-#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B
-#define STLINK_DEBUG_APIV2_DRIVE_NRST      0x3C
-
-#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 0x3E
-
-#define STLINK_DEBUG_APIV2_START_TRACE_RX  0x40
-#define STLINK_DEBUG_APIV2_STOP_TRACE_RX   0x41
-#define STLINK_DEBUG_APIV2_GET_TRACE_NB    0x42
-#define STLINK_DEBUG_APIV2_SWD_SET_FREQ    0x43
-#define STLINK_DEBUG_APIV2_JTAG_SET_FREQ   0x44
-#define STLINK_DEBUG_APIV2_READ_DAP_REG    0x45
-#define STLINK_DEBUG_APIV2_WRITE_DAP_REG   0x46
-#define STLINK_DEBUG_APIV2_READMEM_16BIT   0x47
-#define STLINK_DEBUG_APIV2_WRITEMEM_16BIT  0x48
-
-#define STLINK_DEBUG_APIV2_INIT_AP         0x4B
-#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG    0x4C
-
-#define STLINK_APIV3_SET_COM_FREQ           0x61
-#define STLINK_APIV3_GET_COM_FREQ           0x62
-
-#define STLINK_APIV3_GET_VERSION_EX         0xFB
-
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW   0x00
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH  0x01
-#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
-
-#define STLINK_DEBUG_PORT_ACCESS            0xffff
-
-#define STLINK_TRACE_SIZE               4096
-#define STLINK_TRACE_MAX_HZ             2000000
-
-#define STLINK_V3_MAX_FREQ_NB               10
-
-#define REQUEST_SENSE        0x03
-#define REQUEST_SENSE_LENGTH 18
-
-/* STLINK TCP commands */
-#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST   0x00
-#define STLINK_TCP_CMD_GET_NB_DEV            0x01
-#define STLINK_TCP_CMD_GET_DEV_INFO          0x02
-#define STLINK_TCP_CMD_OPEN_DEV              0x03
-#define STLINK_TCP_CMD_CLOSE_DEV             0x04
-#define STLINK_TCP_CMD_SEND_USB_CMD          0x05
-#define STLINK_TCP_CMD_GET_SERVER_VERSION    0x06
-#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07
-
-/* STLINK TCP constants */
-#define OPENOCD_STLINK_TCP_API_VERSION       1
-#define STLINK_TCP_REQUEST_WRITE             0
-#define STLINK_TCP_REQUEST_READ              1
-#define STLINK_TCP_REQUEST_READ_SWO          3
-#define STLINK_TCP_SS_SIZE                   4
-#define STLINK_TCP_USB_CMD_SIZE              32
-#define STLINK_TCP_SERIAL_SIZE               32
-#define STLINK_TCP_SEND_BUFFER_SIZE          2048
-#define STLINK_TCP_RECV_BUFFER_SIZE          10240
-
-/* STLINK TCP command status */
-#define STLINK_TCP_SS_OK                     0x00000001
-#define STLINK_TCP_SS_MEMORY_PROBLEM         0x00001000
-#define STLINK_TCP_SS_TIMEOUT                0x00001001
-#define STLINK_TCP_SS_BAD_PARAMETER          0x00001002
-#define STLINK_TCP_SS_OPEN_ERR               0x00001003
-#define STLINK_TCP_SS_TRUNCATED_DATA         0x00001052
-#define STLINK_TCP_SS_CMD_NOT_AVAILABLE      0x00001053
-#define STLINK_TCP_SS_TCP_ERROR              0x00002001
-#define STLINK_TCP_SS_TCP_CANT_CONNECT       0x00002002
-#define STLINK_TCP_SS_WIN32_ERROR            0x00010000
-
-/*
- * Map the relevant features, quirks and workaround for specific firmware
- * version of stlink
- */
-#define STLINK_F_HAS_TRACE              BIT(0)
-#define STLINK_F_HAS_SWD_SET_FREQ       BIT(1)
-#define STLINK_F_HAS_JTAG_SET_FREQ      BIT(2)
-#define STLINK_F_HAS_MEM_16BIT          BIT(3)
-#define STLINK_F_HAS_GETLASTRWSTATUS2   BIT(4)
-#define STLINK_F_HAS_DAP_REG            BIT(5)
-#define STLINK_F_QUIRK_JTAG_DP_READ     BIT(6)
-#define STLINK_F_HAS_AP_INIT            BIT(7)
-#define STLINK_F_HAS_DPBANKSEL          BIT(8)
-#define STLINK_F_HAS_RW8_512BYTES       BIT(9)
-
 /* aliases */
 #define STLINK_F_HAS_TARGET_VOLT        STLINK_F_HAS_TRACE
 
@@ -431,7 +77,6 @@ static const struct speed_map stlink_khz_to_speed_map_jtag[] 
= {
        {140, 256}
 };
 
-static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t 
size);
 static int stlink_swim_status(void *handle);
 void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size);
 static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map 
*map);
@@ -450,453 +95,6 @@ static unsigned int stlink_usb_block(void *handle)
                return STLINK_MAX_RW8;
 }
 
-
-
-#ifdef USE_LIBUSB_ASYNCIO
-
-static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
-{
-       int *completed = transfer->user_data;
-       *completed = 1;
-       /* caller interprets result and frees transfer */
-}
-
-
-static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
-{
-       int r, *completed = transfer->user_data;
-
-       /* Assuming a single libusb context exists.  There no existing 
interface into this
-        * module to pass a libusb context.
-        */
-       struct libusb_context *ctx = NULL;
-
-       while (!*completed) {
-               r = libusb_handle_events_completed(ctx, completed);
-               if (r < 0) {
-                       if (r == LIBUSB_ERROR_INTERRUPTED)
-                               continue;
-                       libusb_cancel_transfer(transfer);
-                       continue;
-               }
-       }
-}
-
-
-static int transfer_error_status(const struct libusb_transfer *transfer)
-{
-       int r = 0;
-
-       switch (transfer->status) {
-               case LIBUSB_TRANSFER_COMPLETED:
-                       r = 0;
-                       break;
-               case LIBUSB_TRANSFER_TIMED_OUT:
-                       r = LIBUSB_ERROR_TIMEOUT;
-                       break;
-               case LIBUSB_TRANSFER_STALL:
-                       r = LIBUSB_ERROR_PIPE;
-                       break;
-               case LIBUSB_TRANSFER_OVERFLOW:
-                       r = LIBUSB_ERROR_OVERFLOW;
-                       break;
-               case LIBUSB_TRANSFER_NO_DEVICE:
-                       r = LIBUSB_ERROR_NO_DEVICE;
-                       break;
-               case LIBUSB_TRANSFER_ERROR:
-               case LIBUSB_TRANSFER_CANCELLED:
-                       r = LIBUSB_ERROR_IO;
-                       break;
-               default:
-                       r = LIBUSB_ERROR_OTHER;
-                       break;
-       }
-
-       return r;
-}
-
-struct jtag_xfer {
-       int ep;
-       uint8_t *buf;
-       size_t size;
-       /* Internal */
-       int retval;
-       int completed;
-       size_t transfer_size;
-       struct libusb_transfer *transfer;
-};
-
-static int jtag_libusb_bulk_transfer_n(
-               struct libusb_device_handle *dev_handle,
-               struct jtag_xfer *transfers,
-               size_t n_transfers,
-               int timeout)
-{
-       int retval = 0;
-       int returnval = ERROR_OK;
-
-
-       for (size_t i = 0; i < n_transfers; ++i) {
-               transfers[i].retval = 0;
-               transfers[i].completed = 0;
-               transfers[i].transfer_size = 0;
-               transfers[i].transfer = libusb_alloc_transfer(0);
-
-               if (transfers[i].transfer == NULL) {
-                       for (size_t j = 0; j < i; ++j)
-                               libusb_free_transfer(transfers[j].transfer);
-
-                       LOG_DEBUG("ERROR, failed to alloc usb transfers");
-                       for (size_t k = 0; k < n_transfers; ++k)
-                               transfers[k].retval = LIBUSB_ERROR_NO_MEM;
-                       return ERROR_FAIL;
-               }
-       }
-
-       for (size_t i = 0; i < n_transfers; ++i) {
-               libusb_fill_bulk_transfer(
-                               transfers[i].transfer,
-                               dev_handle,
-                               transfers[i].ep, transfers[i].buf, 
transfers[i].size,
-                               sync_transfer_cb, &transfers[i].completed, 
timeout);
-               transfers[i].transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
-
-               retval = libusb_submit_transfer(transfers[i].transfer);
-               if (retval < 0) {
-                       LOG_DEBUG("ERROR, failed to submit transfer %zu, error 
%d", i, retval);
-
-                       /* Probably no point continuing to submit transfers 
once a submission fails.
-                        * As a result, tag all remaining transfers as errors.
-                        */
-                       for (size_t j = i; j < n_transfers; ++j)
-                               transfers[j].retval = retval;
-
-                       returnval = ERROR_FAIL;
-                       break;
-               }
-       }
-
-       /* Wait for every submitted USB transfer to complete.
-       */
-       for (size_t i = 0; i < n_transfers; ++i) {
-               if (transfers[i].retval == 0) {
-                       
sync_transfer_wait_for_completion(transfers[i].transfer);
-
-                       retval = transfer_error_status(transfers[i].transfer);
-                       if (retval) {
-                               returnval = ERROR_FAIL;
-                               transfers[i].retval = retval;
-                               LOG_DEBUG("ERROR, transfer %zu failed, error 
%d", i, retval);
-                       } else {
-                               /* Assuming actual_length is only valid if 
there is no transfer error.
-                                */
-                               transfers[i].transfer_size = 
transfers[i].transfer->actual_length;
-                       }
-               }
-
-               libusb_free_transfer(transfers[i].transfer);
-               transfers[i].transfer = NULL;
-       }
-
-       return returnval;
-}
-
-#endif
-
-
-/** */
-static int stlink_usb_xfer_v1_get_status(void *handle)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-       int tr, ret;
-
-       assert(handle != NULL);
-
-       /* read status */
-       memset(h->cmdbuf, 0, STLINK_SG_SIZE);
-
-       ret = jtag_libusb_bulk_read(itf_priv->fd, h->rx_ep, (char *)h->cmdbuf, 
13,
-                                   STLINK_READ_TIMEOUT, &tr);
-       if (ret || tr != 13)
-               return ERROR_FAIL;
-
-       uint32_t t1;
-
-       t1 = buf_get_u32(h->cmdbuf, 0, 32);
-
-       /* check for USBS */
-       if (t1 != 0x53425355)
-               return ERROR_FAIL;
-       /*
-        * CSW status:
-        * 0 success
-        * 1 command failure
-        * 2 phase error
-        */
-       if (h->cmdbuf[12] != 0)
-               return ERROR_FAIL;
-
-       return ERROR_OK;
-}
-
-#ifdef USE_LIBUSB_ASYNCIO
-static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, 
int size)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-
-       assert(handle != NULL);
-
-       size_t n_transfers = 0;
-       struct jtag_xfer transfers[2];
-
-       memset(transfers, 0, sizeof(transfers));
-
-       transfers[0].ep = h->tx_ep;
-       transfers[0].buf = h->cmdbuf;
-       transfers[0].size = cmdsize;
-
-       ++n_transfers;
-
-       if (h->direction == h->tx_ep && size) {
-               transfers[1].ep = h->tx_ep;
-               transfers[1].buf = (uint8_t *)buf;
-               transfers[1].size = size;
-
-               ++n_transfers;
-       } else if (h->direction == h->rx_ep && size) {
-               transfers[1].ep = h->rx_ep;
-               transfers[1].buf = (uint8_t *)buf;
-               transfers[1].size = size;
-
-               ++n_transfers;
-       }
-
-       return jtag_libusb_bulk_transfer_n(
-                       itf_priv->fd,
-                       transfers,
-                       n_transfers,
-                       STLINK_WRITE_TIMEOUT);
-}
-#else
-static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, 
int size)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-       int tr, ret;
-
-       assert(handle != NULL);
-
-       ret = jtag_libusb_bulk_write(itf_priv->fd, h->tx_ep, (char *)h->cmdbuf,
-                                    cmdsize, STLINK_WRITE_TIMEOUT, &tr);
-       if (ret || tr != cmdsize)
-               return ERROR_FAIL;
-
-       if (h->direction == h->tx_ep && size) {
-               ret = jtag_libusb_bulk_write(itf_priv->fd, h->tx_ep, (char 
*)buf,
-                                            size, STLINK_WRITE_TIMEOUT, &tr);
-               if (ret || tr != size) {
-                       LOG_DEBUG("bulk write failed");
-                       return ERROR_FAIL;
-               }
-       } else if (h->direction == h->rx_ep && size) {
-               ret = jtag_libusb_bulk_read(itf_priv->fd, h->rx_ep, (char *)buf,
-                                           size, STLINK_READ_TIMEOUT, &tr);
-               if (ret || tr != size) {
-                       LOG_DEBUG("bulk read failed");
-                       return ERROR_FAIL;
-               }
-       }
-
-       return ERROR_OK;
-}
-#endif
-
-/** */
-static int stlink_usb_xfer_v1_get_sense(void *handle)
-{
-       int res;
-       struct stlink_usb_handle_s *h = handle;
-
-       assert(handle != NULL);
-
-       stlink_usb_init_buffer(handle, h->rx_ep, 16);
-
-       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE;
-       h->cmdbuf[h->cmdidx++] = 0;
-       h->cmdbuf[h->cmdidx++] = 0;
-       h->cmdbuf[h->cmdidx++] = 0;
-       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE_LENGTH;
-
-       res = stlink_usb_xfer_rw(handle, REQUEST_SENSE_LENGTH, h->databuf, 16);
-
-       if (res != ERROR_OK)
-               return res;
-
-       if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK)
-               return ERROR_FAIL;
-
-       return ERROR_OK;
-}
-
-/** */
-static int stlink_usb_bulk_read(void *handle, const uint8_t *buf, int size)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-       int tr, ret;
-
-       ret = jtag_libusb_bulk_read(itf_priv->fd, h->direction, (char *)buf, 
size,
-                                   STLINK_READ_TIMEOUT, &tr);
-       if (ret || tr != size) {
-               LOG_ERROR("bulk trace read failed");
-               return ERROR_FAIL;
-       }
-
-       return ERROR_OK;
-}
-
-/*
-       transfers block in cmdbuf
-       <size> indicates number of bytes in the following
-       data phase.
-       Ignore the (eventual) error code in the received packet.
-*/
-static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int 
size)
-{
-       int err, cmdsize = STLINK_CMD_SIZE_V2;
-       struct stlink_usb_handle_s *h = handle;
-
-       assert(handle != NULL);
-
-       if (h->version.stlink == 1) {
-               cmdsize = STLINK_SG_SIZE;
-               /* put length in bCBWCBLength */
-               h->cmdbuf[14] = h->cmdidx-15;
-       }
-
-       err = stlink_usb_xfer_rw(handle, cmdsize, buf, size);
-
-       if (err != ERROR_OK)
-               return err;
-
-       if (h->version.stlink == 1) {
-               if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) {
-                       /* check csw status */
-                       if (h->cmdbuf[12] == 1) {
-                               LOG_DEBUG("get sense");
-                               if (stlink_usb_xfer_v1_get_sense(handle) != 
ERROR_OK)
-                                       return ERROR_FAIL;
-                       }
-                       return ERROR_FAIL;
-               }
-       }
-
-       return ERROR_OK;
-}
-
-static int stlink_server_send_cmd(void *handle, const uint8_t *cmd, int 
cmd_size,
-               uint8_t *data, int data_size, bool check_tcp_status)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_server_priv_s *itf_priv = h->itf->priv;
-
-       assert(handle != NULL);
-
-       /* send the TCP command */
-       int sent_size = send(itf_priv->fd, (char *) cmd, cmd_size, 0);
-       if (sent_size != cmd_size) {
-               LOG_ERROR("failed to send USB CMD");
-               if (sent_size == -1)
-                       LOG_DEBUG("socket send error: %s (errno %d)", 
strerror(errno), errno);
-               else
-                       LOG_DEBUG("sent size %d (expected %d)", sent_size, 
cmd_size);
-               return ERROR_FAIL;
-       }
-
-       keep_alive();
-
-       /* read the TCP response */
-       int received_size = recv(itf_priv->fd, (char *) data, data_size, 0);
-       if (received_size != data_size) {
-               LOG_ERROR("failed to receive USB CMD response");
-               if (received_size == -1)
-                       LOG_DEBUG("socket recv error: %s (errno %d)", 
strerror(errno), errno);
-               else
-                       LOG_DEBUG("received size %d (expected %d)", 
received_size, data_size);
-               return ERROR_FAIL;
-       }
-
-       if (check_tcp_status) {
-               uint32_t tcp_ss = le_to_h_u32(data);
-               if (tcp_ss != STLINK_TCP_SS_OK) {
-                       LOG_ERROR("TCP error status 0x%X", tcp_ss);
-                       return ERROR_FAIL;
-               }
-       }
-
-       return ERROR_OK;
-}
-
-/** */
-static int stlink_server_xfer(void *handle, const uint8_t *buf, int size)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_server_priv_s *itf_priv = h->itf->priv;
-
-       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
-       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
-       int cmd_size = STLINK_TCP_USB_CMD_SIZE;
-       int data_size = STLINK_TCP_SS_SIZE;
-
-       assert(handle != NULL);
-
-       /* prepare the TCP command */
-       cmdbuf[0] = STLINK_TCP_CMD_SEND_USB_CMD;
-       memset(&cmdbuf[1], 0, 3); /* reserved for alignment and future use, 
must be zero */
-       h_u32_to_le(&cmdbuf[4], itf_priv->connect_id);
-       memcpy(&cmdbuf[8], h->cmdbuf, 16);
-       cmdbuf[24] = h->direction;
-       memset(&cmdbuf[25], 0, 3);  /* reserved for alignment and future use, 
must be zero */
-
-       h_u32_to_le(&cmdbuf[28], size);
-
-       /*
-        * if the xfer is a write request (tx_ep)
-        *  > then buf content will be copied
-        * into &cmdbuf[32].
-        * else : the xfer is a read or trace read request (rx_ep or trace_ep)
-        *  > the buf content will be filled from &databuf[4].
-        *
-        * note : if h->direction is trace_ep, h->cmdbuf is zeros.
-        */
-
-       if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */
-               cmd_size += size;
-               if (cmd_size > STLINK_TCP_SEND_BUFFER_SIZE) {
-                       LOG_ERROR("STLINK_TCP command buffer overflow");
-                       return ERROR_FAIL;
-               }
-               memcpy(&cmdbuf[32], buf, size);
-       } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */
-               data_size += size;
-               if (data_size > STLINK_TCP_RECV_BUFFER_SIZE) {
-                       LOG_ERROR("STLINK_TCP data buffer overflow");
-                       return ERROR_FAIL;
-               }
-       }
-
-       int ret = stlink_server_send_cmd(h, cmdbuf, cmd_size, databuf, 
data_size, true);
-       if (ret != ERROR_OK)
-               return ret;
-
-       if (h->direction != h->tx_ep)
-               memcpy((uint8_t *) buf, &databuf[STLINK_TCP_SS_SIZE], size);
-
-       return ERROR_OK;
-}
-
 /**
     Converts an STLINK status code held in the first byte of a response
     to an openocd error, logs any error/wait status as debug output.
@@ -1086,7 +284,7 @@ static void stlink_usb_xfer_v1_create_cmd(void *handle, 
uint8_t direction, uint3
 }
 
 /** */
-static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t 
size)
+void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size)
 {
        struct stlink_usb_handle_s *h = handle;
 
@@ -1102,7 +300,7 @@ static void stlink_usb_init_buffer(void *handle, uint8_t 
direction, uint32_t siz
 }
 
 /** */
-static int stlink_usb_version(void *handle)
+int stlink_usb_version(void *handle)
 {
        int res;
        uint32_t flags;
@@ -1486,7 +684,7 @@ static enum stlink_mode stlink_get_mode(enum hl_transports 
t)
 }
 
 /** */
-static int stlink_usb_exit_mode(void *handle)
+int stlink_usb_exit_mode(void *handle)
 {
        int res;
        uint8_t mode;
@@ -2877,54 +2075,6 @@ static int stlink_speed(void *handle, int khz, bool 
query)
 }
 
 /** */
-static int stlink_usb_close(void *handle)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-
-       if (h && itf_priv->fd) {
-               stlink_usb_exit_mode(h);
-               /* do not check return code, it prevent
-               us from closing jtag_libusb */
-               jtag_libusb_close(itf_priv->fd);
-       }
-
-       return ERROR_OK;
-}
-
-/** */
-static int stlink_server_close(void *handle)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_server_priv_s *itf_priv = h->itf->priv;
-
-       int ret = ERROR_OK;
-       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
-       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
-
-       if (h && itf_priv->connected) {
-               if (itf_priv->connect_id) {
-                       stlink_usb_exit_mode(h);
-
-                       /* close the stlink */
-                       cmdbuf[0] = STLINK_TCP_CMD_CLOSE_DEV;
-                       memset(&cmdbuf[1], 0, 4); /* reserved */
-                       h_u32_to_le(&cmdbuf[4], itf_priv->connect_id);
-                       ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 4, 
true);
-                       if (ret != ERROR_OK)
-                               LOG_ERROR("cannot close the STLINK");
-               }
-
-               if (close_socket(itf_priv->fd) != 0) {
-                       LOG_ERROR("error closing the socket");
-                       LOG_DEBUG("close error: %s (errno %d)", 
strerror(errno), errno);
-               }
-       }
-
-       return ret;
-}
-
-/** */
 static int stlink_close(void *handle)
 {
        if (handle != NULL) {
@@ -2939,383 +2089,8 @@ static int stlink_close(void *handle)
        return ERROR_OK;
 }
 
-/* Compute ST-Link serial number from the device descriptor
- * this function will help to work-around a bug in old ST-Link/V2 DFU
- * the buggy DFU returns an incorrect serial in the USB descriptor
- * example for the following serial "57FF72067265575742132067"
- *  - the correct descriptor serial is:
- *    0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 
0x32, 0x00 ...
- *    this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the 
serial in unicode format
- *    the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... 
>>  57FF72 ...
- *    this format could be read correctly by 
'libusb_get_string_descriptor_ascii'
- *    so this case is managed by libusb_helper::string_descriptor_equal
- *  - the buggy DFU is not doing any unicode conversion and returns a raw 
serial data in the descriptor
- *    0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ...
- *            >>    57          FF          72       ...
- *    based on the length (0x1a = 26) we could easily decide if we have to 
fixup the serial
- *    and then we have just to convert the raw data into printable characters 
using sprintf
- */
-char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
-               struct libusb_device_descriptor *dev_desc)
-{
-       int usb_retval;
-       unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2];
-
-       if (dev_desc->iSerialNumber == 0)
-               return NULL;
-
-       /* get the LANGID from String Descriptor Zero */
-       usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial,
-                       sizeof(desc_serial));
-
-       if (usb_retval < LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
-                               libusb_error_name(usb_retval), usb_retval);
-               return NULL;
-       } else if (usb_retval < 4) {
-               /* the size should be least 4 bytes to contain a minimum of 1 
supported LANGID */
-               LOG_ERROR("could not get the LANGID");
-               return NULL;
-       }
-
-       uint32_t langid = desc_serial[2] | (desc_serial[3] << 8);
-
-       /* get the serial */
-       usb_retval = libusb_get_string_descriptor(device, 
dev_desc->iSerialNumber,
-                       langid, desc_serial, sizeof(desc_serial));
-
-       unsigned char len = desc_serial[0];
-
-       if (usb_retval < LIBUSB_SUCCESS) {
-               LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
-                               libusb_error_name(usb_retval), usb_retval);
-               return NULL;
-       } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) {
-               LOG_ERROR("invalid string in ST-LINK USB serial descriptor");
-               return NULL;
-       }
-
-       if (len == ((STLINK_SERIAL_LEN + 1) * 2)) {
-               /* good ST-Link adapter, this case is managed by
-                * libusb::libusb_get_string_descriptor_ascii */
-               return NULL;
-       } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) {
-               LOG_ERROR("unexpected serial length (%d) in descriptor", len);
-               return NULL;
-       }
-
-       /* else (len == 26) => buggy ST-Link */
-
-       char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char));
-       if (alternate_serial == NULL)
-               return NULL;
-
-       for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
-               sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]);
-
-       alternate_serial[STLINK_SERIAL_LEN] = '\0';
-
-       return alternate_serial;
-}
-
-/** */
-static int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
-       int err, retry_count = 1;
-
-       /*
-         On certain host USB configurations(e.g. MacBook Air)
-         STLINKv2 dongle seems to have its FW in a funky state if,
-         after plugging it in, you try to use openocd with it more
-         then once (by launching and closing openocd). In cases like
-         that initial attempt to read the FW info via
-         stlink_usb_version will fail and the device has to be reset
-         in order to become operational.
-        */
-       do {
-               if (jtag_libusb_open(param->vid, param->pid, param->serial,
-                               &itf_priv->fd, stlink_usb_get_alternate_serial) 
!= ERROR_OK) {
-                       LOG_ERROR("open failed");
-                       return ERROR_FAIL;
-               }
-
-               jtag_libusb_set_configuration(itf_priv->fd, 0);
-
-               if (libusb_claim_interface(itf_priv->fd, 0) != ERROR_OK) {
-                       LOG_DEBUG("claim interface failed");
-                       return ERROR_FAIL;
-               }
-
-               /* RX EP is common for all versions */
-               h->rx_ep = STLINK_RX_EP;
-
-               uint16_t pid;
-               if (jtag_libusb_get_pid(libusb_get_device(itf_priv->fd), &pid) 
!= ERROR_OK) {
-                       LOG_DEBUG("libusb_get_pid failed");
-                       return ERROR_FAIL;
-               }
-
-               /* wrap version for first read */
-               switch (pid) {
-                       case STLINK_V1_PID:
-                               h->version.stlink = 1;
-                               h->tx_ep = STLINK_TX_EP;
-                               break;
-                       case STLINK_V3_USBLOADER_PID:
-                       case STLINK_V3E_PID:
-                       case STLINK_V3S_PID:
-                       case STLINK_V3_2VCP_PID:
-                               h->version.stlink = 3;
-                               h->tx_ep = STLINK_V2_1_TX_EP;
-                               h->trace_ep = STLINK_V2_1_TRACE_EP;
-                               break;
-                       case STLINK_V2_1_PID:
-                       case STLINK_V2_1_NO_MSD_PID:
-                               h->version.stlink = 2;
-                               h->tx_ep = STLINK_V2_1_TX_EP;
-                               h->trace_ep = STLINK_V2_1_TRACE_EP;
-                               break;
-                       default:
-                       /* fall through - we assume V2 to be the default 
version*/
-                       case STLINK_V2_PID:
-                               h->version.stlink = 2;
-                               h->tx_ep = STLINK_TX_EP;
-                               h->trace_ep = STLINK_TRACE_EP;
-                               break;
-               }
-
-               /* get the device version */
-               err = stlink_usb_version(h);
-
-               if (err == ERROR_OK) {
-                       break;
-               } else if (h->version.stlink == 1 ||
-                          retry_count == 0) {
-                       LOG_ERROR("read version failed");
-                       return ERROR_FAIL;
-               } else {
-                       err = libusb_release_interface(itf_priv->fd, 0);
-                       if (err != ERROR_OK) {
-                               LOG_ERROR("release interface failed");
-                               return ERROR_FAIL;
-                       }
-
-                       err = libusb_reset_device(itf_priv->fd);
-                       if (err != ERROR_OK) {
-                               LOG_ERROR("reset device failed");
-                               return ERROR_FAIL;
-                       }
-
-                       jtag_libusb_close(itf_priv->fd);
-                       /*
-                         Give the device one second to settle down and
-                         reenumerate.
-                        */
-                       usleep(1 * 1000 * 1000);
-                       retry_count--;
-               }
-       } while (1);
-
-       return ERROR_OK;
-}
-
-static int stlink_server_open(void *handle, struct hl_interface_param_s *param)
-{
-       struct stlink_usb_handle_s *h = handle;
-       struct stlink_server_priv_s *itf_priv = h->itf->priv;
-       int ret;
-       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
-       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
-
-       /* SWIM is not supported using stlink-server */
-       if (h->st_mode ==  STLINK_MODE_DEBUG_SWIM) {
-               LOG_ERROR("stlink-server does not support SWIM mode");
-               return ERROR_FAIL;
-       }
-
-       /* configure directions */
-       h->rx_ep = STLINK_TCP_REQUEST_READ;
-       h->tx_ep = STLINK_TCP_REQUEST_WRITE;
-       h->trace_ep = STLINK_TCP_REQUEST_READ_SWO;
-
-       itf_priv->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       itf_priv->connected = false;
-       itf_priv->device_id = 0;
-       itf_priv->connect_id = 0;
-
-       struct sockaddr_in serv;
-       memset(&serv, 0, sizeof(struct sockaddr_in));
-       serv.sin_family = AF_INET;
-       serv.sin_port = htons(param->stlink_server_port);
-       serv.sin_addr.s_addr = inet_addr("127.0.0.1");
-
-       LOG_DEBUG("socket : %x", itf_priv->fd);
-
-       int res;
-
-       int flag = 1;
-       res = setsockopt(itf_priv->fd, IPPROTO_TCP, TCP_NODELAY, (char *) 
&flag, sizeof(flag));
-       if (res == -1) {
-               LOG_ERROR("cannot set sock option 'TCP_NODELEAY', errno: %s", 
strerror(errno));
-               return ERROR_FAIL;
-       }
-
-       int a = 49152;
-       res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_RCVBUF, (char *) &a, 
sizeof(a));
-       if (res == -1) {
-               LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", 
strerror(errno));
-               return ERROR_FAIL;
-       }
-
-       res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_SNDBUF, (char *) &a, 
sizeof(a));
-       if (res == -1) {
-               LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", 
strerror(errno));
-               return ERROR_FAIL;
-       }
-
-       if (connect(itf_priv->fd, (const struct sockaddr *) &serv, 
sizeof(serv)) == -1) {
-               LOG_ERROR("cannot connect to stlink server");
-               return ERROR_FAIL;
-       }
-
-       itf_priv->connected = true;
-
-       LOG_INFO("connected to stlink-server");
-
-       /* print stlink-server version */
-       cmdbuf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION;
-       cmdbuf[1] = OPENOCD_STLINK_TCP_API_VERSION;
-       memset(&cmdbuf[2], 0, 2); /* reserved */
-       ret = stlink_server_send_cmd(h, cmdbuf, 4, databuf, 16, false);
-       if (ret != ERROR_OK) {
-               LOG_ERROR("cannot get the stlink-server version");
-               return ERROR_FAIL;
-       }
-
-       uint32_t api_ver = le_to_h_u32(&databuf[0]);
-       uint32_t ver_major = le_to_h_u32(&databuf[4]);
-       uint32_t ver_minor = le_to_h_u32(&databuf[8]);
-       uint32_t ver_build = le_to_h_u32(&databuf[12]);
-       LOG_INFO("stlink-server API v%d, version %d.%d.%d",
-                       api_ver, ver_major, ver_minor, ver_build);
-
-       /* refresh stlink list (re-enumerate) */
-       cmdbuf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST;
-       cmdbuf[1] = 0; /* don't clear the list, just refresh it */
-       ret = stlink_server_send_cmd(h, cmdbuf, 2, databuf, 4, true);
-       if (ret != ERROR_OK)
-               return ret;
-
-       /* get the number of connected stlinks */
-       cmdbuf[0] = STLINK_TCP_CMD_GET_NB_DEV;
-       ret = stlink_server_send_cmd(h, cmdbuf, 1, databuf, 4, false);
-       if (ret != ERROR_OK)
-               return ret;
-
-       uint32_t connected_stlinks = le_to_h_u32(databuf);
-
-       if (connected_stlinks == 0) {
-               LOG_ERROR("no ST-LINK detected");
-               return ERROR_FAIL;
-       }
-
-       LOG_DEBUG("%d ST-LINK detected", connected_stlinks);
-
-       /* list all connected ST-Link and seek for the requested vid:pid and 
serial */
-       uint8_t serial[STLINK_TCP_SERIAL_SIZE+1] = {0};
-       uint8_t stlink_used;
-       bool stlink_id_matched = false;
-       bool stlink_serial_matched = (param->serial == NULL);
-
-       for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; 
stlink_id++) {
-               /* get the stlink info */
-               cmdbuf[0] = STLINK_TCP_CMD_GET_DEV_INFO;
-               cmdbuf[1] = (uint8_t) stlink_id;
-               memset(&cmdbuf[2], 0, 2); /* reserved */
-               h_u32_to_le(&cmdbuf[4], 41); /* size of TDeviceInfo2 */
-               ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 45, true);
-               if (ret != ERROR_OK)
-                       return ret;
-
-               itf_priv->device_id = le_to_h_u32(&databuf[4]);
-               memcpy(serial, &databuf[8], STLINK_TCP_SERIAL_SIZE);
-               h->vid = le_to_h_u16(&databuf[40]);
-               h->pid = le_to_h_u16(&databuf[42]);
-               stlink_used = databuf[44];
-
-               /* check the vid:pid */
-               for (int i = 0; param->vid[i]; i++) {
-                       if (param->vid[i] == h->vid && param->pid[i] == h->pid) 
{
-                               stlink_id_matched = true;
-                               break;
-                       }
-               }
-
-               if (!stlink_id_matched)
-                       continue;
-
-               /* check the serial if specified */
-               if (param->serial)
-                       stlink_serial_matched = strcmp(param->serial, (const 
char *) serial) == 0;
-
-               if (!stlink_serial_matched)
-                       LOG_DEBUG("Device serial number '%s' doesn't match 
requested serial '%s'",
-                                       (const char *) serial, param->serial);
-               else /* exit the search loop if there is match */
-                       break;
-       }
-
-       if (!stlink_id_matched) {
-               LOG_ERROR("ST-LINK open failed (vid/pid mismatch)");
-               return ERROR_FAIL;
-       }
-
-       if (!stlink_serial_matched) {
-               LOG_ERROR("ST-LINK open failed (serial mismatch)");
-               return ERROR_FAIL;
-       }
-
-       /* check if device is 'exclusively' used by another application */
-       if (stlink_used) {
-               LOG_ERROR("the selected device is already used");
-               return ERROR_FAIL;
-       }
-
-       LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, 
h->pid, serial);
-
-       /* now let's open the stlink */
-       cmdbuf[0] = STLINK_TCP_CMD_OPEN_DEV;
-       memset(&cmdbuf[1], 0, 4); /* reserved */
-       h_u32_to_le(&cmdbuf[4], itf_priv->device_id);
-       ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 8, true);
-       if (ret != ERROR_OK)
-               return ret;
-
-       itf_priv->connect_id = le_to_h_u32(&databuf[4]);
-
-       /* get stlink version */
-       ret = stlink_usb_version(h);
-       if (ret != ERROR_OK)
-               return ERROR_FAIL;
-
-       return ERROR_OK;
-}
-
-static struct stlink_interface_s stlink_usb_itf = {
-       .open = stlink_usb_open,
-       .close = stlink_usb_close,
-       .xfer = stlink_usb_xfer_noerrcheck,
-       .read = stlink_usb_bulk_read,
-};
-
-static struct stlink_interface_s stlink_server_itf = {
-       .open = stlink_server_open,
-       .close = stlink_server_close,
-       .xfer = stlink_server_xfer,
-       .read = stlink_server_xfer,
-};
+extern struct stlink_interface_s stlink_usb_itf;
+extern struct stlink_interface_s stlink_server_itf;
 
 static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode 
mode, void **fd)
 {
diff --git a/src/jtag/drivers/stlink/stlink.h b/src/jtag/drivers/stlink/stlink.h
new file mode 100644
index 0000000..a934e13
--- /dev/null
+++ b/src/jtag/drivers/stlink/stlink.h
@@ -0,0 +1,377 @@
+/***************************************************************************
+ *   Copyright (C) 2020 by Tarek Bochkati                                  *
+ *   Tarek Bochkati <[email protected]>                            *
+ *                                                                         *
+ *   SWIM contributions by Ake Rehnman                                     *
+ *   Copyright (C) 2017  Ake Rehnman                                       *
+ *   ake.rehnman(at)gmail.com                                              *
+ *                                                                         *
+ *   Copyright (C) 2011-2012 by Mathias Kuester                            *
+ *   Mathias Kuester <[email protected]>                                   *
+ *                                                                         *
+ *   Copyright (C) 2012 by Spencer Oliver                                  *
+ *   [email protected]                                                  *
+ *                                                                         *
+ *   This code is based on https://github.com/texane/stlink                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include <jtag/hla/hla_layout.h>
+#include <jtag/hla/hla_transport.h>
+#include <jtag/hla/hla_interface.h>
+
+#define STLINK_SERIAL_LEN 24
+
+#define ENDPOINT_IN  0x80
+#define ENDPOINT_OUT 0x00
+
+#define STLINK_WRITE_TIMEOUT 1000
+#define STLINK_READ_TIMEOUT 1000
+
+#define STLINK_RX_EP          (1|ENDPOINT_IN)
+#define STLINK_TX_EP          (2|ENDPOINT_OUT)
+#define STLINK_TRACE_EP       (3|ENDPOINT_IN)
+
+#define STLINK_V2_1_TX_EP     (1|ENDPOINT_OUT)
+#define STLINK_V2_1_TRACE_EP  (2|ENDPOINT_IN)
+
+#define STLINK_SG_SIZE        (31)
+#define STLINK_DATA_SIZE      (4096)
+#define STLINK_CMD_SIZE_V2    (16)
+#define STLINK_CMD_SIZE_V1    (10)
+
+#define STLINK_V1_PID         (0x3744)
+#define STLINK_V2_PID         (0x3748)
+#define STLINK_V2_1_PID       (0x374B)
+#define STLINK_V2_1_NO_MSD_PID  (0x3752)
+#define STLINK_V3_USBLOADER_PID (0x374D)
+#define STLINK_V3E_PID          (0x374E)
+#define STLINK_V3S_PID          (0x374F)
+#define STLINK_V3_2VCP_PID      (0x3753)
+
+/*
+ * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and
+ * this limits the bulk packet size and the 8bit read/writes to max 64 bytes.
+ * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6.
+ */
+#define STLINK_MAX_RW8         (64)
+#define STLINKV3_MAX_RW8       (512)
+
+/* "WAIT" responses will be retried (with exponential backoff) at
+ * most this many times before failing to caller.
+ */
+#define MAX_WAIT_RETRIES 8
+
+#define STLINK_SWIM_ERR_OK             0x00
+#define STLINK_SWIM_BUSY               0x01
+#define STLINK_DEBUG_ERR_OK            0x80
+#define STLINK_DEBUG_ERR_FAULT         0x81
+#define STLINK_SWD_AP_WAIT             0x10
+#define STLINK_SWD_AP_FAULT            0x11
+#define STLINK_SWD_AP_ERROR            0x12
+#define STLINK_SWD_AP_PARITY_ERROR     0x13
+#define STLINK_JTAG_GET_IDCODE_ERROR   0x09
+#define STLINK_JTAG_WRITE_ERROR        0x0c
+#define STLINK_JTAG_WRITE_VERIF_ERROR  0x0d
+#define STLINK_SWD_DP_WAIT             0x14
+#define STLINK_SWD_DP_FAULT            0x15
+#define STLINK_SWD_DP_ERROR            0x16
+#define STLINK_SWD_DP_PARITY_ERROR     0x17
+
+#define STLINK_SWD_AP_WDATA_ERROR      0x18
+#define STLINK_SWD_AP_STICKY_ERROR     0x19
+#define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a
+
+#define STLINK_BAD_AP_ERROR            0x1d
+
+#define STLINK_CORE_RUNNING            0x80
+#define STLINK_CORE_HALTED             0x81
+#define STLINK_CORE_STAT_UNKNOWN       -1
+
+#define STLINK_GET_VERSION             0xF1
+#define STLINK_DEBUG_COMMAND           0xF2
+#define STLINK_DFU_COMMAND             0xF3
+#define STLINK_SWIM_COMMAND            0xF4
+#define STLINK_GET_CURRENT_MODE        0xF5
+#define STLINK_GET_TARGET_VOLTAGE      0xF7
+
+#define STLINK_DEV_DFU_MODE            0x00
+#define STLINK_DEV_MASS_MODE           0x01
+#define STLINK_DEV_DEBUG_MODE          0x02
+#define STLINK_DEV_SWIM_MODE           0x03
+#define STLINK_DEV_BOOTLOADER_MODE     0x04
+#define STLINK_DEV_UNKNOWN_MODE        -1
+
+#define STLINK_DFU_EXIT                0x07
+
+/*
+       STLINK_SWIM_ENTER_SEQ
+       1.3ms low then 750Hz then 1.5kHz
+
+       STLINK_SWIM_GEN_RST
+       STM8 DM pulls reset pin low 50us
+
+       STLINK_SWIM_SPEED
+       uint8_t (0=low|1=high)
+
+       STLINK_SWIM_WRITEMEM
+       uint16_t length
+       uint32_t address
+
+       STLINK_SWIM_RESET
+       send syncronization seq (16us low, response 64 clocks low)
+*/
+#define STLINK_SWIM_ENTER                  0x00
+#define STLINK_SWIM_EXIT                   0x01
+#define STLINK_SWIM_READ_CAP               0x02
+#define STLINK_SWIM_SPEED                  0x03
+#define STLINK_SWIM_ENTER_SEQ              0x04
+#define STLINK_SWIM_GEN_RST                0x05
+#define STLINK_SWIM_RESET                  0x06
+#define STLINK_SWIM_ASSERT_RESET           0x07
+#define STLINK_SWIM_DEASSERT_RESET         0x08
+#define STLINK_SWIM_READSTATUS             0x09
+#define STLINK_SWIM_WRITEMEM               0x0a
+#define STLINK_SWIM_READMEM                0x0b
+#define STLINK_SWIM_READBUF                0x0c
+
+#define STLINK_DEBUG_GETSTATUS             0x01
+#define STLINK_DEBUG_FORCEDEBUG            0x02
+#define STLINK_DEBUG_APIV1_RESETSYS        0x03
+#define STLINK_DEBUG_APIV1_READALLREGS     0x04
+#define STLINK_DEBUG_APIV1_READREG         0x05
+#define STLINK_DEBUG_APIV1_WRITEREG        0x06
+#define STLINK_DEBUG_READMEM_32BIT         0x07
+#define STLINK_DEBUG_WRITEMEM_32BIT        0x08
+#define STLINK_DEBUG_RUNCORE               0x09
+#define STLINK_DEBUG_STEPCORE              0x0a
+#define STLINK_DEBUG_APIV1_SETFP           0x0b
+#define STLINK_DEBUG_READMEM_8BIT          0x0c
+#define STLINK_DEBUG_WRITEMEM_8BIT         0x0d
+#define STLINK_DEBUG_APIV1_CLEARFP         0x0e
+#define STLINK_DEBUG_APIV1_WRITEDEBUGREG   0x0f
+#define STLINK_DEBUG_APIV1_SETWATCHPOINT   0x10
+
+#define STLINK_DEBUG_ENTER_JTAG_RESET      0x00
+#define STLINK_DEBUG_ENTER_SWD_NO_RESET    0xa3
+#define STLINK_DEBUG_ENTER_JTAG_NO_RESET   0xa4
+
+#define STLINK_DEBUG_APIV1_ENTER           0x20
+#define STLINK_DEBUG_EXIT                  0x21
+#define STLINK_DEBUG_READCOREID            0x22
+
+#define STLINK_DEBUG_APIV2_ENTER           0x30
+#define STLINK_DEBUG_APIV2_READ_IDCODES    0x31
+#define STLINK_DEBUG_APIV2_RESETSYS        0x32
+#define STLINK_DEBUG_APIV2_READREG         0x33
+#define STLINK_DEBUG_APIV2_WRITEREG        0x34
+#define STLINK_DEBUG_APIV2_WRITEDEBUGREG   0x35
+#define STLINK_DEBUG_APIV2_READDEBUGREG    0x36
+
+#define STLINK_DEBUG_APIV2_READALLREGS     0x3A
+#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B
+#define STLINK_DEBUG_APIV2_DRIVE_NRST      0x3C
+
+#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 0x3E
+
+#define STLINK_DEBUG_APIV2_START_TRACE_RX  0x40
+#define STLINK_DEBUG_APIV2_STOP_TRACE_RX   0x41
+#define STLINK_DEBUG_APIV2_GET_TRACE_NB    0x42
+#define STLINK_DEBUG_APIV2_SWD_SET_FREQ    0x43
+#define STLINK_DEBUG_APIV2_JTAG_SET_FREQ   0x44
+#define STLINK_DEBUG_APIV2_READ_DAP_REG    0x45
+#define STLINK_DEBUG_APIV2_WRITE_DAP_REG   0x46
+#define STLINK_DEBUG_APIV2_READMEM_16BIT   0x47
+#define STLINK_DEBUG_APIV2_WRITEMEM_16BIT  0x48
+
+#define STLINK_DEBUG_APIV2_INIT_AP         0x4B
+#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG    0x4C
+
+#define STLINK_APIV3_SET_COM_FREQ           0x61
+#define STLINK_APIV3_GET_COM_FREQ           0x62
+
+#define STLINK_APIV3_GET_VERSION_EX         0xFB
+
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW   0x00
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH  0x01
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
+
+#define STLINK_DEBUG_PORT_ACCESS            0xffff
+
+#define STLINK_TRACE_SIZE               4096
+#define STLINK_TRACE_MAX_HZ             2000000
+
+#define STLINK_V3_MAX_FREQ_NB               10
+
+#define REQUEST_SENSE        0x03
+#define REQUEST_SENSE_LENGTH 18
+
+/* STLINK TCP commands */
+#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST   0x00
+#define STLINK_TCP_CMD_GET_NB_DEV            0x01
+#define STLINK_TCP_CMD_GET_DEV_INFO          0x02
+#define STLINK_TCP_CMD_OPEN_DEV              0x03
+#define STLINK_TCP_CMD_CLOSE_DEV             0x04
+#define STLINK_TCP_CMD_SEND_USB_CMD          0x05
+#define STLINK_TCP_CMD_GET_SERVER_VERSION    0x06
+#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07
+
+/* STLINK TCP constants */
+#define OPENOCD_STLINK_TCP_API_VERSION       1
+#define STLINK_TCP_REQUEST_WRITE             0
+#define STLINK_TCP_REQUEST_READ              1
+#define STLINK_TCP_REQUEST_READ_SWO          3
+#define STLINK_TCP_SS_SIZE                   4
+#define STLINK_TCP_USB_CMD_SIZE              32
+#define STLINK_TCP_SERIAL_SIZE               32
+#define STLINK_TCP_SEND_BUFFER_SIZE          2048
+#define STLINK_TCP_RECV_BUFFER_SIZE          10240
+
+/* STLINK TCP command status */
+#define STLINK_TCP_SS_OK                     0x00000001
+#define STLINK_TCP_SS_MEMORY_PROBLEM         0x00001000
+#define STLINK_TCP_SS_TIMEOUT                0x00001001
+#define STLINK_TCP_SS_BAD_PARAMETER          0x00001002
+#define STLINK_TCP_SS_OPEN_ERR               0x00001003
+#define STLINK_TCP_SS_TRUNCATED_DATA         0x00001052
+#define STLINK_TCP_SS_CMD_NOT_AVAILABLE      0x00001053
+#define STLINK_TCP_SS_TCP_ERROR              0x00002001
+#define STLINK_TCP_SS_TCP_CANT_CONNECT       0x00002002
+#define STLINK_TCP_SS_WIN32_ERROR            0x00010000
+
+/*
+ * Map the relevant features, quirks and workaround for specific firmware
+ * version of stlink
+ */
+#define STLINK_F_HAS_TRACE              BIT(0)
+#define STLINK_F_HAS_SWD_SET_FREQ       BIT(1)
+#define STLINK_F_HAS_JTAG_SET_FREQ      BIT(2)
+#define STLINK_F_HAS_MEM_16BIT          BIT(3)
+#define STLINK_F_HAS_GETLASTRWSTATUS2   BIT(4)
+#define STLINK_F_HAS_DAP_REG            BIT(5)
+#define STLINK_F_QUIRK_JTAG_DP_READ     BIT(6)
+#define STLINK_F_HAS_AP_INIT            BIT(7)
+#define STLINK_F_HAS_DPBANKSEL          BIT(8)
+#define STLINK_F_HAS_RW8_512BYTES       BIT(9)
+
+/** */
+enum stlink_mode {
+       STLINK_MODE_UNKNOWN = 0,
+       STLINK_MODE_DFU,
+       STLINK_MODE_MASS,
+       STLINK_MODE_DEBUG_JTAG,
+       STLINK_MODE_DEBUG_SWD,
+       STLINK_MODE_DEBUG_SWIM
+};
+
+/** */
+enum stlink_jtag_api_version {
+       STLINK_JTAG_API_V1 = 1,
+       STLINK_JTAG_API_V2,
+       STLINK_JTAG_API_V3,
+};
+
+/** */
+struct stlink_usb_version {
+       /** */
+       int stlink;
+       /** */
+       int jtag;
+       /** */
+       int swim;
+       /** jtag api version supported */
+       enum stlink_jtag_api_version jtag_api;
+       /** one bit for each feature supported. See macros STLINK_F_* */
+       uint32_t flags;
+};
+
+/** */
+struct stlink_usb_priv_s {
+       /** */
+       struct libusb_device_handle *fd;
+       /** */
+       struct libusb_transfer *trans;
+};
+
+/** */
+struct stlink_server_priv_s {
+       /** */
+       int fd;
+       /** */
+       bool connected;
+       /** */
+       uint32_t device_id;
+       /** */
+       uint32_t connect_id;
+};
+
+/** */
+struct stlink_interface_s {
+       /** */
+       void *priv;
+       /** */
+       int (*open)(void *handle, struct hl_interface_param_s *param);
+       /** */
+       int (*close)(void *handle);
+       /** */
+       int (*xfer)(void *handle, const uint8_t *buf, int size);
+       /** */
+       int (*read)(void *handle, const uint8_t *buf, int size);
+};
+
+/** */
+struct stlink_usb_handle_s {
+       /** */
+       struct stlink_interface_s *itf;
+       /** */
+       uint8_t rx_ep;
+       /** */
+       uint8_t tx_ep;
+       /** */
+       uint8_t trace_ep;
+       /** */
+       uint8_t cmdbuf[STLINK_SG_SIZE];
+       /** */
+       uint8_t cmdidx;
+       /** */
+       uint8_t direction;
+       /** */
+       uint8_t databuf[STLINK_DATA_SIZE];
+       /** */
+       uint32_t max_mem_packet;
+       /** */
+       enum stlink_mode st_mode;
+       /** */
+       struct stlink_usb_version version;
+       /** */
+       uint16_t vid;
+       /** */
+       uint16_t pid;
+       /** */
+       struct {
+               /** whether SWO tracing is enabled or not */
+               bool enabled;
+               /** trace module source clock */
+               uint32_t source_hz;
+       } trace;
+       /** reconnect is needed next time we try to query the
+        * status */
+       bool reconnect_pending;
+};
+
+/** shared functions */
+void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
+int stlink_usb_version(void *handle);
+int stlink_usb_exit_mode(void *handle);
diff --git a/src/jtag/drivers/stlink/stlink_server.c 
b/src/jtag/drivers/stlink/stlink_server.c
new file mode 100644
index 0000000..cd780fe
--- /dev/null
+++ b/src/jtag/drivers/stlink/stlink_server.c
@@ -0,0 +1,372 @@
+/***************************************************************************
+ *   Copyright (C) 2020 by Tarek Bochkati                                  *
+ *   Tarek Bochkati <[email protected]>                            *
+ *                                                                         *
+ *   SWIM contributions by Ake Rehnman                                     *
+ *   Copyright (C) 2017  Ake Rehnman                                       *
+ *   ake.rehnman(at)gmail.com                                              *
+ *                                                                         *
+ *   Copyright (C) 2011-2012 by Mathias Kuester                            *
+ *   Mathias Kuester <[email protected]>                                   *
+ *                                                                         *
+ *   Copyright (C) 2012 by Spencer Oliver                                  *
+ *   [email protected]                                                  *
+ *                                                                         *
+ *   This code is based on https://github.com/texane/stlink                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "stlink.h"
+#include <helper/log.h>
+
+#if WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <netinet/tcp.h>
+#endif
+
+/** */
+static int stlink_server_send_cmd(void *handle, const uint8_t *cmd, int 
cmd_size,
+               uint8_t *data, int data_size, bool check_tcp_status)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_server_priv_s *itf_priv = h->itf->priv;
+
+       assert(handle != NULL);
+
+       /* send the TCP command */
+       int sent_size = send(itf_priv->fd, (char *) cmd, cmd_size, 0);
+       if (sent_size != cmd_size) {
+               LOG_ERROR("failed to send USB CMD");
+               if (sent_size == -1)
+                       LOG_DEBUG("socket send error: %s (errno %d)", 
strerror(errno), errno);
+               else
+                       LOG_DEBUG("sent size %d (expected %d)", sent_size, 
cmd_size);
+               return ERROR_FAIL;
+       }
+
+       keep_alive();
+
+       /* read the TCP response */
+       int received_size = recv(itf_priv->fd, (char *) data, data_size, 0);
+       if (received_size != data_size) {
+               LOG_ERROR("failed to receive USB CMD response");
+               if (received_size == -1)
+                       LOG_DEBUG("socket recv error: %s (errno %d)", 
strerror(errno), errno);
+               else
+                       LOG_DEBUG("received size %d (expected %d)", 
received_size, data_size);
+               return ERROR_FAIL;
+       }
+
+       if (check_tcp_status) {
+               uint32_t tcp_ss = le_to_h_u32(data);
+               if (tcp_ss != STLINK_TCP_SS_OK) {
+                       LOG_ERROR("TCP error status 0x%X", tcp_ss);
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_server_xfer(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_server_priv_s *itf_priv = h->itf->priv;
+
+       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
+       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
+       int cmd_size = STLINK_TCP_USB_CMD_SIZE;
+       int data_size = STLINK_TCP_SS_SIZE;
+
+       assert(handle != NULL);
+
+       /* prepare the TCP command */
+       cmdbuf[0] = STLINK_TCP_CMD_SEND_USB_CMD;
+       memset(&cmdbuf[1], 0, 3); /* reserved for alignment and future use, 
must be zero */
+       h_u32_to_le(&cmdbuf[4], itf_priv->connect_id);
+       memcpy(&cmdbuf[8], h->cmdbuf, 16);
+       cmdbuf[24] = h->direction;
+       memset(&cmdbuf[25], 0, 3);  /* reserved for alignment and future use, 
must be zero */
+
+       h_u32_to_le(&cmdbuf[28], size);
+
+       /*
+        * if the xfer is a write request (tx_ep)
+        *  > then buf content will be copied
+        * into &cmdbuf[32].
+        * else : the xfer is a read or trace read request (rx_ep or trace_ep)
+        *  > the buf content will be filled from &databuf[4].
+        *
+        * note : if h->direction is trace_ep, h->cmdbuf is zeros.
+        */
+
+       if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */
+               cmd_size += size;
+               if (cmd_size > STLINK_TCP_SEND_BUFFER_SIZE) {
+                       LOG_ERROR("STLINK_TCP command buffer overflow");
+                       return ERROR_FAIL;
+               }
+               memcpy(&cmdbuf[32], buf, size);
+       } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */
+               data_size += size;
+               if (data_size > STLINK_TCP_RECV_BUFFER_SIZE) {
+                       LOG_ERROR("STLINK_TCP data buffer overflow");
+                       return ERROR_FAIL;
+               }
+       }
+
+       int ret = stlink_server_send_cmd(h, cmdbuf, cmd_size, databuf, 
data_size, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       if (h->direction != h->tx_ep)
+               memcpy((uint8_t *) buf, &databuf[STLINK_TCP_SS_SIZE], size);
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_server_close(void *handle)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_server_priv_s *itf_priv = h->itf->priv;
+
+       int ret = ERROR_OK;
+       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
+       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
+
+       if (h && itf_priv->connected) {
+               if (itf_priv->connect_id) {
+                       stlink_usb_exit_mode(h);
+
+                       /* close the stlink */
+                       cmdbuf[0] = STLINK_TCP_CMD_CLOSE_DEV;
+                       memset(&cmdbuf[1], 0, 4); /* reserved */
+                       h_u32_to_le(&cmdbuf[4], itf_priv->connect_id);
+                       ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 4, 
true);
+                       if (ret != ERROR_OK)
+                               LOG_ERROR("cannot close the STLINK");
+               }
+
+               if (close_socket(itf_priv->fd) != 0) {
+                       LOG_ERROR("error closing the socket");
+                       LOG_DEBUG("close error: %s (errno %d)", 
strerror(errno), errno);
+               }
+       }
+
+       return ret;
+}
+
+/** */
+static int stlink_server_open(void *handle, struct hl_interface_param_s *param)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_server_priv_s *itf_priv = h->itf->priv;
+       int ret;
+       uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE];
+       uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE];
+
+       /* SWIM is not supported using stlink-server */
+       if (h->st_mode ==  STLINK_MODE_DEBUG_SWIM) {
+               LOG_ERROR("stlink-server does not support SWIM mode");
+               return ERROR_FAIL;
+       }
+
+       /* configure directions */
+       h->rx_ep = STLINK_TCP_REQUEST_READ;
+       h->tx_ep = STLINK_TCP_REQUEST_WRITE;
+       h->trace_ep = STLINK_TCP_REQUEST_READ_SWO;
+
+       itf_priv->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       itf_priv->connected = false;
+       itf_priv->device_id = 0;
+       itf_priv->connect_id = 0;
+
+       struct sockaddr_in serv;
+       memset(&serv, 0, sizeof(struct sockaddr_in));
+       serv.sin_family = AF_INET;
+       serv.sin_port = htons(param->stlink_server_port);
+       serv.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+       LOG_DEBUG("socket : %x", itf_priv->fd);
+
+       int res;
+
+       int flag = 1;
+       res = setsockopt(itf_priv->fd, IPPROTO_TCP, TCP_NODELAY, (char *) 
&flag, sizeof(flag));
+       if (res == -1) {
+               LOG_ERROR("cannot set sock option 'TCP_NODELEAY', errno: %s", 
strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       int a = 49152;
+       res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_RCVBUF, (char *) &a, 
sizeof(a));
+       if (res == -1) {
+               LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", 
strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_SNDBUF, (char *) &a, 
sizeof(a));
+       if (res == -1) {
+               LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", 
strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       if (connect(itf_priv->fd, (const struct sockaddr *) &serv, 
sizeof(serv)) == -1) {
+               LOG_ERROR("cannot connect to stlink server");
+               return ERROR_FAIL;
+       }
+
+       itf_priv->connected = true;
+
+       LOG_INFO("connected to stlink-server");
+
+       /* print stlink-server version */
+       cmdbuf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION;
+       cmdbuf[1] = OPENOCD_STLINK_TCP_API_VERSION;
+       memset(&cmdbuf[2], 0, 2); /* reserved */
+       ret = stlink_server_send_cmd(h, cmdbuf, 4, databuf, 16, false);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("cannot get the stlink-server version");
+               return ERROR_FAIL;
+       }
+
+       uint32_t api_ver = le_to_h_u32(&databuf[0]);
+       uint32_t ver_major = le_to_h_u32(&databuf[4]);
+       uint32_t ver_minor = le_to_h_u32(&databuf[8]);
+       uint32_t ver_build = le_to_h_u32(&databuf[12]);
+       LOG_INFO("stlink-server API v%d, version %d.%d.%d",
+                       api_ver, ver_major, ver_minor, ver_build);
+
+       /* refresh stlink list (re-enumerate) */
+       cmdbuf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST;
+       cmdbuf[1] = 0; /* don't clear the list, just refresh it */
+       ret = stlink_server_send_cmd(h, cmdbuf, 2, databuf, 4, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* get the number of connected stlinks */
+       cmdbuf[0] = STLINK_TCP_CMD_GET_NB_DEV;
+       ret = stlink_server_send_cmd(h, cmdbuf, 1, databuf, 4, false);
+       if (ret != ERROR_OK)
+               return ret;
+
+       uint32_t connected_stlinks = le_to_h_u32(databuf);
+
+       if (connected_stlinks == 0) {
+               LOG_ERROR("no ST-LINK detected");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("%d ST-LINK detected", connected_stlinks);
+
+       /* list all connected ST-Link and seek for the requested vid:pid and 
serial */
+       uint8_t serial[STLINK_TCP_SERIAL_SIZE+1] = {0};
+       uint8_t stlink_used;
+       bool stlink_id_matched = false;
+       bool stlink_serial_matched = (param->serial == NULL);
+
+       for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; 
stlink_id++) {
+               /* get the stlink info */
+               cmdbuf[0] = STLINK_TCP_CMD_GET_DEV_INFO;
+               cmdbuf[1] = (uint8_t) stlink_id;
+               memset(&cmdbuf[2], 0, 2); /* reserved */
+               h_u32_to_le(&cmdbuf[4], 41); /* size of TDeviceInfo2 */
+               ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 45, true);
+               if (ret != ERROR_OK)
+                       return ret;
+
+               itf_priv->device_id = le_to_h_u32(&databuf[4]);
+               memcpy(serial, &databuf[8], STLINK_TCP_SERIAL_SIZE);
+               h->vid = le_to_h_u16(&databuf[40]);
+               h->pid = le_to_h_u16(&databuf[42]);
+               stlink_used = databuf[44];
+
+               /* check the vid:pid */
+               for (int i = 0; param->vid[i]; i++) {
+                       if (param->vid[i] == h->vid && param->pid[i] == h->pid) 
{
+                               stlink_id_matched = true;
+                               break;
+                       }
+               }
+
+               if (!stlink_id_matched)
+                       continue;
+
+               /* check the serial if specified */
+               if (param->serial)
+                       stlink_serial_matched = strcmp(param->serial, (const 
char *) serial) == 0;
+
+               if (!stlink_serial_matched)
+                       LOG_DEBUG("Device serial number '%s' doesn't match 
requested serial '%s'",
+                                       (const char *) serial, param->serial);
+               else /* exit the search loop if there is match */
+                       break;
+       }
+
+       if (!stlink_id_matched) {
+               LOG_ERROR("ST-LINK open failed (vid/pid mismatch)");
+               return ERROR_FAIL;
+       }
+
+       if (!stlink_serial_matched) {
+               LOG_ERROR("ST-LINK open failed (serial mismatch)");
+               return ERROR_FAIL;
+       }
+
+       /* check if device is 'exclusively' used by another application */
+       if (stlink_used) {
+               LOG_ERROR("the selected device is already used");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, 
h->pid, serial);
+
+       /* now let's open the stlink */
+       cmdbuf[0] = STLINK_TCP_CMD_OPEN_DEV;
+       memset(&cmdbuf[1], 0, 4); /* reserved */
+       h_u32_to_le(&cmdbuf[4], itf_priv->device_id);
+       ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 8, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       itf_priv->connect_id = le_to_h_u32(&databuf[4]);
+
+       /* get stlink version */
+       ret = stlink_usb_version(h);
+       if (ret != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+/** */
+struct stlink_interface_s stlink_server_itf = {
+       .open = stlink_server_open,
+       .close = stlink_server_close,
+       .xfer = stlink_server_xfer,
+       .read = stlink_server_xfer,
+};
diff --git a/src/jtag/drivers/stlink/stlink_usb.c 
b/src/jtag/drivers/stlink/stlink_usb.c
new file mode 100644
index 0000000..5caede7
--- /dev/null
+++ b/src/jtag/drivers/stlink/stlink_usb.c
@@ -0,0 +1,588 @@
+/***************************************************************************
+ *   Copyright (C) 2020 by Tarek Bochkati                                  *
+ *   Tarek Bochkati <[email protected]>                            *
+ *                                                                         *
+ *   SWIM contributions by Ake Rehnman                                     *
+ *   Copyright (C) 2017  Ake Rehnman                                       *
+ *   ake.rehnman(at)gmail.com                                              *
+ *                                                                         *
+ *   Copyright (C) 2011-2012 by Mathias Kuester                            *
+ *   Mathias Kuester <[email protected]>                                   *
+ *                                                                         *
+ *   Copyright (C) 2012 by Spencer Oliver                                  *
+ *   [email protected]                                                  *
+ *                                                                         *
+ *   This code is based on https://github.com/texane/stlink                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "stlink.h"
+#include <helper/binarybuffer.h>
+#include <helper/log.h>
+#include "../libusb_helper.h"
+
+#ifdef HAVE_LIBUSB1
+#define USE_LIBUSB_ASYNCIO
+#endif
+
+#ifdef USE_LIBUSB_ASYNCIO
+static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
+{
+       int *completed = transfer->user_data;
+       *completed = 1;
+       /* caller interprets result and frees transfer */
+}
+
+
+static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
+{
+       int r, *completed = transfer->user_data;
+
+       /* Assuming a single libusb context exists.  There no existing 
interface into this
+        * module to pass a libusb context.
+        */
+       struct libusb_context *ctx = NULL;
+
+       while (!*completed) {
+               r = libusb_handle_events_completed(ctx, completed);
+               if (r < 0) {
+                       if (r == LIBUSB_ERROR_INTERRUPTED)
+                               continue;
+                       libusb_cancel_transfer(transfer);
+                       continue;
+               }
+       }
+}
+
+static int transfer_error_status(const struct libusb_transfer *transfer)
+{
+       int r = 0;
+
+       switch (transfer->status) {
+               case LIBUSB_TRANSFER_COMPLETED:
+                       r = 0;
+                       break;
+               case LIBUSB_TRANSFER_TIMED_OUT:
+                       r = LIBUSB_ERROR_TIMEOUT;
+                       break;
+               case LIBUSB_TRANSFER_STALL:
+                       r = LIBUSB_ERROR_PIPE;
+                       break;
+               case LIBUSB_TRANSFER_OVERFLOW:
+                       r = LIBUSB_ERROR_OVERFLOW;
+                       break;
+               case LIBUSB_TRANSFER_NO_DEVICE:
+                       r = LIBUSB_ERROR_NO_DEVICE;
+                       break;
+               case LIBUSB_TRANSFER_ERROR:
+               case LIBUSB_TRANSFER_CANCELLED:
+                       r = LIBUSB_ERROR_IO;
+                       break;
+               default:
+                       r = LIBUSB_ERROR_OTHER;
+                       break;
+       }
+
+       return r;
+}
+
+struct jtag_xfer {
+       int ep;
+       uint8_t *buf;
+       size_t size;
+       /* Internal */
+       int retval;
+       int completed;
+       size_t transfer_size;
+       struct libusb_transfer *transfer;
+};
+
+static int jtag_libusb_bulk_transfer_n(
+               struct libusb_device_handle *dev_handle,
+               struct jtag_xfer *transfers,
+               size_t n_transfers,
+               int timeout)
+{
+       int retval = 0;
+       int returnval = ERROR_OK;
+
+
+       for (size_t i = 0; i < n_transfers; ++i) {
+               transfers[i].retval = 0;
+               transfers[i].completed = 0;
+               transfers[i].transfer_size = 0;
+               transfers[i].transfer = libusb_alloc_transfer(0);
+
+               if (transfers[i].transfer == NULL) {
+                       for (size_t j = 0; j < i; ++j)
+                               libusb_free_transfer(transfers[j].transfer);
+
+                       LOG_DEBUG("ERROR, failed to alloc usb transfers");
+                       for (size_t k = 0; k < n_transfers; ++k)
+                               transfers[k].retval = LIBUSB_ERROR_NO_MEM;
+                       return ERROR_FAIL;
+               }
+       }
+
+       for (size_t i = 0; i < n_transfers; ++i) {
+               libusb_fill_bulk_transfer(
+                               transfers[i].transfer,
+                               dev_handle,
+                               transfers[i].ep, transfers[i].buf, 
transfers[i].size,
+                               sync_transfer_cb, &transfers[i].completed, 
timeout);
+               transfers[i].transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
+
+               retval = libusb_submit_transfer(transfers[i].transfer);
+               if (retval < 0) {
+                       LOG_DEBUG("ERROR, failed to submit transfer %zu, error 
%d", i, retval);
+
+                       /* Probably no point continuing to submit transfers 
once a submission fails.
+                        * As a result, tag all remaining transfers as errors.
+                        */
+                       for (size_t j = i; j < n_transfers; ++j)
+                               transfers[j].retval = retval;
+
+                       returnval = ERROR_FAIL;
+                       break;
+               }
+       }
+
+       /* Wait for every submitted USB transfer to complete.
+       */
+       for (size_t i = 0; i < n_transfers; ++i) {
+               if (transfers[i].retval == 0) {
+                       
sync_transfer_wait_for_completion(transfers[i].transfer);
+
+                       retval = transfer_error_status(transfers[i].transfer);
+                       if (retval) {
+                               returnval = ERROR_FAIL;
+                               transfers[i].retval = retval;
+                               LOG_DEBUG("ERROR, transfer %zu failed, error 
%d", i, retval);
+                       } else {
+                               /* Assuming actual_length is only valid if 
there is no transfer error.
+                                */
+                               transfers[i].transfer_size = 
transfers[i].transfer->actual_length;
+                       }
+               }
+
+               libusb_free_transfer(transfers[i].transfer);
+               transfers[i].transfer = NULL;
+       }
+
+       return returnval;
+}
+#endif
+
+#ifdef USE_LIBUSB_ASYNCIO
+static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, 
int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+
+       assert(handle != NULL);
+
+       size_t n_transfers = 0;
+       struct jtag_xfer transfers[2];
+
+       memset(transfers, 0, sizeof(transfers));
+
+       transfers[0].ep = h->tx_ep;
+       transfers[0].buf = h->cmdbuf;
+       transfers[0].size = cmdsize;
+
+       ++n_transfers;
+
+       if (h->direction == h->tx_ep && size) {
+               transfers[1].ep = h->tx_ep;
+               transfers[1].buf = (uint8_t *)buf;
+               transfers[1].size = size;
+
+               ++n_transfers;
+       } else if (h->direction == h->rx_ep && size) {
+               transfers[1].ep = h->rx_ep;
+               transfers[1].buf = (uint8_t *)buf;
+               transfers[1].size = size;
+
+               ++n_transfers;
+       }
+
+       return jtag_libusb_bulk_transfer_n(
+                       itf_priv->fd,
+                       transfers,
+                       n_transfers,
+                       STLINK_WRITE_TIMEOUT);
+}
+#else
+static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, 
int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+       int tr, ret;
+
+       assert(handle != NULL);
+
+       ret = jtag_libusb_bulk_write(itf_priv->fd, h->tx_ep, (char *)h->cmdbuf,
+                                    cmdsize, STLINK_WRITE_TIMEOUT, &tr);
+       if (ret || tr != cmdsize)
+               return ERROR_FAIL;
+
+       if (h->direction == h->tx_ep && size) {
+               ret = jtag_libusb_bulk_write(itf_priv->fd, h->tx_ep, (char 
*)buf,
+                                            size, STLINK_WRITE_TIMEOUT, &tr);
+               if (ret || tr != size) {
+                       LOG_DEBUG("bulk write failed");
+                       return ERROR_FAIL;
+               }
+       } else if (h->direction == h->rx_ep && size) {
+               ret = jtag_libusb_bulk_read(itf_priv->fd, h->rx_ep, (char *)buf,
+                                           size, STLINK_READ_TIMEOUT, &tr);
+               if (ret || tr != size) {
+                       LOG_DEBUG("bulk read failed");
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+#endif
+
+/** */
+static int stlink_usb_bulk_read(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+       int tr, ret;
+
+       ret = jtag_libusb_bulk_read(itf_priv->fd, h->direction, (char *)buf, 
size,
+                                   STLINK_READ_TIMEOUT, &tr);
+       if (ret || tr != size) {
+               LOG_ERROR("bulk trace read failed");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_xfer_v1_get_status(void *handle)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+       int tr, ret;
+
+       assert(handle != NULL);
+
+       /* read status */
+       memset(h->cmdbuf, 0, STLINK_SG_SIZE);
+
+       ret = jtag_libusb_bulk_read(itf_priv->fd, h->rx_ep, (char *)h->cmdbuf, 
13,
+                                   STLINK_READ_TIMEOUT, &tr);
+       if (ret || tr != 13)
+               return ERROR_FAIL;
+
+       uint32_t t1;
+
+       t1 = buf_get_u32(h->cmdbuf, 0, 32);
+
+       /* check for USBS */
+       if (t1 != 0x53425355)
+               return ERROR_FAIL;
+       /*
+        * CSW status:
+        * 0 success
+        * 1 command failure
+        * 2 phase error
+        */
+       if (h->cmdbuf[12] != 0)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_xfer_v1_get_sense(void *handle)
+{
+       int res;
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle != NULL);
+
+       stlink_usb_init_buffer(handle, h->rx_ep, 16);
+
+       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE_LENGTH;
+
+       res = stlink_usb_xfer_rw(handle, REQUEST_SENSE_LENGTH, h->databuf, 16);
+
+       if (res != ERROR_OK)
+               return res;
+
+       if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+/*
+       transfers block in cmdbuf
+       <size> indicates number of bytes in the following
+       data phase.
+       Ignore the (eventual) error code in the received packet.
+*/
+static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int 
size)
+{
+       int err, cmdsize = STLINK_CMD_SIZE_V2;
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle != NULL);
+
+       if (h->version.stlink == 1) {
+               cmdsize = STLINK_SG_SIZE;
+               /* put length in bCBWCBLength */
+               h->cmdbuf[14] = h->cmdidx-15;
+       }
+
+       err = stlink_usb_xfer_rw(handle, cmdsize, buf, size);
+
+       if (err != ERROR_OK)
+               return err;
+
+       if (h->version.stlink == 1) {
+               if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) {
+                       /* check csw status */
+                       if (h->cmdbuf[12] == 1) {
+                               LOG_DEBUG("get sense");
+                               if (stlink_usb_xfer_v1_get_sense(handle) != 
ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_close(void *handle)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+
+       if (h && itf_priv->fd) {
+               stlink_usb_exit_mode(h);
+               /* do not check return code, it prevent
+               us from closing jtag_libusb */
+               jtag_libusb_close(itf_priv->fd);
+       }
+
+       return ERROR_OK;
+}
+
+/* Compute ST-Link serial number from the device descriptor
+ * this function will help to work-around a bug in old ST-Link/V2 DFU
+ * the buggy DFU returns an incorrect serial in the USB descriptor
+ * example for the following serial "57FF72067265575742132067"
+ *  - the correct descriptor serial is:
+ *    0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 
0x32, 0x00 ...
+ *    this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the 
serial in unicode format
+ *    the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... 
>>  57FF72 ...
+ *    this format could be read correctly by 
'libusb_get_string_descriptor_ascii'
+ *    so this case is managed by libusb_helper::string_descriptor_equal
+ *  - the buggy DFU is not doing any unicode conversion and returns a raw 
serial data in the descriptor
+ *    0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ...
+ *            >>    57          FF          72       ...
+ *    based on the length (0x1a = 26) we could easily decide if we have to 
fixup the serial
+ *    and then we have just to convert the raw data into printable characters 
using sprintf
+ */
+static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
+               struct libusb_device_descriptor *dev_desc)
+{
+       int usb_retval;
+       unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2];
+
+       if (dev_desc->iSerialNumber == 0)
+               return NULL;
+
+       /* get the LANGID from String Descriptor Zero */
+       usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial,
+                       sizeof(desc_serial));
+
+       if (usb_retval < LIBUSB_SUCCESS) {
+               LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+                               libusb_error_name(usb_retval), usb_retval);
+               return NULL;
+       } else if (usb_retval < 4) {
+               /* the size should be least 4 bytes to contain a minimum of 1 
supported LANGID */
+               LOG_ERROR("could not get the LANGID");
+               return NULL;
+       }
+
+       uint32_t langid = desc_serial[2] | (desc_serial[3] << 8);
+
+       /* get the serial */
+       usb_retval = libusb_get_string_descriptor(device, 
dev_desc->iSerialNumber,
+                       langid, desc_serial, sizeof(desc_serial));
+
+       unsigned char len = desc_serial[0];
+
+       if (usb_retval < LIBUSB_SUCCESS) {
+               LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+                               libusb_error_name(usb_retval), usb_retval);
+               return NULL;
+       } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) {
+               LOG_ERROR("invalid string in ST-LINK USB serial descriptor");
+               return NULL;
+       }
+
+       if (len == ((STLINK_SERIAL_LEN + 1) * 2)) {
+               /* good ST-Link adapter, this case is managed by
+                * libusb::libusb_get_string_descriptor_ascii */
+               return NULL;
+       } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) {
+               LOG_ERROR("unexpected serial length (%d) in descriptor", len);
+               return NULL;
+       }
+
+       /* else (len == 26) => buggy ST-Link */
+
+       char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char));
+       if (alternate_serial == NULL)
+               return NULL;
+
+       for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
+               sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]);
+
+       alternate_serial[STLINK_SERIAL_LEN] = '\0';
+
+       return alternate_serial;
+}
+
+/** */
+static int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
+{
+       struct stlink_usb_handle_s *h = handle;
+       struct stlink_usb_priv_s *itf_priv = h->itf->priv;
+       int err, retry_count = 1;
+
+       /*
+         On certain host USB configurations(e.g. MacBook Air)
+         STLINKv2 dongle seems to have its FW in a funky state if,
+         after plugging it in, you try to use openocd with it more
+         then once (by launching and closing openocd). In cases like
+         that initial attempt to read the FW info via
+         stlink_usb_version will fail and the device has to be reset
+         in order to become operational.
+        */
+       do {
+               if (jtag_libusb_open(param->vid, param->pid, param->serial,
+                               &itf_priv->fd, stlink_usb_get_alternate_serial) 
!= ERROR_OK) {
+                       LOG_ERROR("open failed");
+                       return ERROR_FAIL;
+               }
+
+               jtag_libusb_set_configuration(itf_priv->fd, 0);
+
+               if (libusb_claim_interface(itf_priv->fd, 0) != ERROR_OK) {
+                       LOG_DEBUG("claim interface failed");
+                       return ERROR_FAIL;
+               }
+
+               /* RX EP is common for all versions */
+               h->rx_ep = STLINK_RX_EP;
+
+               uint16_t pid;
+               if (jtag_libusb_get_pid(libusb_get_device(itf_priv->fd), &pid) 
!= ERROR_OK) {
+                       LOG_DEBUG("libusb_get_pid failed");
+                       return ERROR_FAIL;
+               }
+
+               /* wrap version for first read */
+               switch (pid) {
+                       case STLINK_V1_PID:
+                               h->version.stlink = 1;
+                               h->tx_ep = STLINK_TX_EP;
+                               break;
+                       case STLINK_V3_USBLOADER_PID:
+                       case STLINK_V3E_PID:
+                       case STLINK_V3S_PID:
+                       case STLINK_V3_2VCP_PID:
+                               h->version.stlink = 3;
+                               h->tx_ep = STLINK_V2_1_TX_EP;
+                               h->trace_ep = STLINK_V2_1_TRACE_EP;
+                               break;
+                       case STLINK_V2_1_PID:
+                       case STLINK_V2_1_NO_MSD_PID:
+                               h->version.stlink = 2;
+                               h->tx_ep = STLINK_V2_1_TX_EP;
+                               h->trace_ep = STLINK_V2_1_TRACE_EP;
+                               break;
+                       default:
+                       /* fall through - we assume V2 to be the default 
version*/
+                       case STLINK_V2_PID:
+                               h->version.stlink = 2;
+                               h->tx_ep = STLINK_TX_EP;
+                               h->trace_ep = STLINK_TRACE_EP;
+                               break;
+               }
+
+               /* get the device version */
+               err = stlink_usb_version(h);
+
+               if (err == ERROR_OK) {
+                       break;
+               } else if (h->version.stlink == 1 ||
+                          retry_count == 0) {
+                       LOG_ERROR("read version failed");
+                       return ERROR_FAIL;
+               } else {
+                       err = libusb_release_interface(itf_priv->fd, 0);
+                       if (err != ERROR_OK) {
+                               LOG_ERROR("release interface failed");
+                               return ERROR_FAIL;
+                       }
+
+                       err = libusb_reset_device(itf_priv->fd);
+                       if (err != ERROR_OK) {
+                               LOG_ERROR("reset device failed");
+                               return ERROR_FAIL;
+                       }
+
+                       jtag_libusb_close(itf_priv->fd);
+                       /*
+                         Give the device one second to settle down and
+                         reenumerate.
+                        */
+                       usleep(1 * 1000 * 1000);
+                       retry_count--;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+/** */
+struct stlink_interface_s stlink_usb_itf = {
+       .open = stlink_usb_open,
+       .close = stlink_usb_close,
+       .xfer = stlink_usb_xfer_noerrcheck,
+       .read = stlink_usb_bulk_read,
+};

-- 


_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to