jtag/hla, jtag/stlink: switch to command 'adapter serial'
[fw/openocd] / src / jtag / drivers / stlink_usb.c
index 134cb2f42180ff01878b3eac7ea698a73698d9da..4c0e025fc5f9522097caf039d469f10de9a930b6 100644 (file)
@@ -1,4 +1,7 @@
 /***************************************************************************
+ *   Copyright (C) 2020 by Tarek Bochkati                                  *
+ *   Tarek Bochkati <tarek.bouchkati@gmail.com>                            *
+ *                                                                         *
  *   SWIM contributions by Ake Rehnman                                     *
  *   Copyright (C) 2017  Ake Rehnman                                       *
  *   ake.rehnman(at)gmail.com                                              *
 #endif
 
 /* project specific includes */
+#include <helper/align.h>
 #include <helper/binarybuffer.h>
+#include <helper/bits.h>
+#include <helper/system.h>
+#include <helper/time_support.h>
+#include <jtag/adapter.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/arm_adi_v5.h>
 #include <target/target.h>
+#include <transport/transport.h>
 
 #include <target/cortex_m.h>
 
-#include "libusb_common.h"
+#include <helper/system.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_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_NULL_EP        0
 #define STLINK_RX_EP          (1|ENDPOINT_IN)
 #define STLINK_TX_EP          (2|ENDPOINT_OUT)
 #define STLINK_TRACE_EP       (3|ENDPOINT_IN)
@@ -60,7 +82,7 @@
 #define STLINK_V2_1_TRACE_EP  (2|ENDPOINT_IN)
 
 #define STLINK_SG_SIZE        (31)
-#define STLINK_DATA_SIZE      (4096)
+#define STLINK_DATA_SIZE      (6144)
 #define STLINK_CMD_SIZE_V2    (16)
 #define STLINK_CMD_SIZE_V1    (10)
 
 #define STLINK_V3E_PID          (0x374E)
 #define STLINK_V3S_PID          (0x374F)
 #define STLINK_V3_2VCP_PID      (0x3753)
+#define STLINK_V3E_NO_MSD_PID   (0x3754)
 
 /*
  * 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.
+ * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6.
+ *
+ * For 16 and 32bit read/writes stlink handles USB packet split and the limit
+ * is the internal buffer size of 6144 bytes.
+ * TODO: override ADIv5 layer's tar_autoincr_block that limits the transfer
+ * to 1024 or 4096 bytes
  */
-#define STLINK_MAX_RW8         (64)
-#define STLINKV3_MAX_RW8       (512)
+#define STLINK_MAX_RW8          (64)
+#define STLINKV3_MAX_RW8        (512)
+#define STLINK_MAX_RW16_32      STLINK_DATA_SIZE
+#define STLINK_SWIM_DATA_SIZE   STLINK_DATA_SIZE
 
 /* "WAIT" responses will be retried (with exponential backoff) at
  * most this many times before failing to caller.
  */
 #define MAX_WAIT_RETRIES 8
 
+/* HLA is currently limited at AP#0 and no control on CSW */
+#define STLINK_HLA_AP_NUM       0
+#define STLINK_HLA_CSW          0
+
 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 {
        /** */
@@ -106,12 +149,110 @@ struct stlink_usb_version {
        uint32_t flags;
 };
 
+struct stlink_usb_priv_s {
+       /** */
+       struct libusb_device_handle *fd;
+       /** */
+       struct libusb_transfer *trans;
+};
+
+struct stlink_tcp_priv_s {
+       /** */
+       int fd;
+       /** */
+       bool connected;
+       /** */
+       uint32_t device_id;
+       /** */
+       uint32_t connect_id;
+       /** */
+       uint8_t *send_buf;
+       /** */
+       uint8_t *recv_buf;
+};
+
+struct stlink_backend_s {
+       /** */
+       int (*open)(void *handle, struct hl_interface_param_s *param);
+       /** */
+       int (*close)(void *handle);
+       /** */
+       int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size);
+       /** */
+       int (*read_trace)(void *handle, const uint8_t *buf, int size);
+};
+
+/* TODO: make queue size dynamic */
+/* TODO: don't allocate queue for HLA */
+#define MAX_QUEUE_DEPTH (4096)
+
+enum queue_cmd {
+       CMD_DP_READ = 1,
+       CMD_DP_WRITE,
+
+       CMD_AP_READ,
+       CMD_AP_WRITE,
+
+       /*
+        * encode the bytes size in the enum's value. This makes easy to extract it
+        * with a simple logic AND, by using the macro CMD_MEM_AP_2_SIZE() below
+        */
+       CMD_MEM_AP_READ8   = 0x10 + 1,
+       CMD_MEM_AP_READ16  = 0x10 + 2,
+       CMD_MEM_AP_READ32  = 0x10 + 4,
+
+       CMD_MEM_AP_WRITE8  = 0x20 + 1,
+       CMD_MEM_AP_WRITE16 = 0x20 + 2,
+       CMD_MEM_AP_WRITE32 = 0x20 + 4,
+};
+
+#define CMD_MEM_AP_2_SIZE(cmd) ((cmd) & 7)
+
+struct dap_queue {
+       enum queue_cmd cmd;
+       union {
+               struct dp_r {
+                       unsigned int reg;
+                       struct adiv5_dap *dap;
+                       uint32_t *p_data;
+               } dp_r;
+               struct dp_w {
+                       unsigned int reg;
+                       struct adiv5_dap *dap;
+                       uint32_t data;
+               } dp_w;
+               struct ap_r {
+                       unsigned int reg;
+                       struct adiv5_ap *ap;
+                       uint32_t *p_data;
+               } ap_r;
+               struct ap_w {
+                       unsigned int reg;
+                       struct adiv5_ap *ap;
+                       uint32_t data;
+                       bool changes_csw_default;
+               } ap_w;
+               struct mem_ap {
+                       uint32_t addr;
+                       struct adiv5_ap *ap;
+                       union {
+                               uint32_t *p_data;
+                               uint32_t data;
+                       };
+                       uint32_t csw;
+               } mem_ap;
+       };
+};
+
 /** */
 struct stlink_usb_handle_s {
        /** */
-       struct jtag_libusb_device_handle *fd;
+       struct stlink_backend_s *backend;
        /** */
-       struct libusb_transfer *trans;
+       union {
+               struct stlink_usb_priv_s usb_backend_priv;
+               struct stlink_tcp_priv_s tcp_backend_priv;
+       };
        /** */
        uint8_t rx_ep;
        /** */
@@ -119,17 +260,17 @@ struct stlink_usb_handle_s {
        /** */
        uint8_t trace_ep;
        /** */
-       uint8_t cmdbuf[STLINK_SG_SIZE];
+       uint8_t *cmdbuf;
        /** */
        uint8_t cmdidx;
        /** */
        uint8_t direction;
        /** */
-       uint8_t databuf[STLINK_DATA_SIZE];
+       uint8_t *databuf;
        /** */
        uint32_t max_mem_packet;
        /** */
-       enum hl_transports transport;
+       enum stlink_mode st_mode;
        /** */
        struct stlink_usb_version version;
        /** */
@@ -146,8 +287,32 @@ struct stlink_usb_handle_s {
        /** reconnect is needed next time we try to query the
         * status */
        bool reconnect_pending;
+       /** queue of dap_direct operations */
+       struct dap_queue queue[MAX_QUEUE_DEPTH];
+       /** first element available in the queue */
+       unsigned int queue_index;
 };
 
+/** */
+static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
+{
+       struct stlink_usb_handle_s *h = handle;
+       return h->backend->open(handle, param);
+}
+
+/** */
+static inline int stlink_usb_close(void *handle)
+{
+       struct stlink_usb_handle_s *h = handle;
+       return h->backend->close(handle);
+}
+/** */
+static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       return h->backend->xfer_noerrcheck(handle, buf, size);
+}
+
 #define STLINK_SWIM_ERR_OK             0x00
 #define STLINK_SWIM_BUSY               0x01
 #define STLINK_DEBUG_ERR_OK            0x80
@@ -156,6 +321,7 @@ struct stlink_usb_handle_s {
 #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
@@ -204,7 +370,7 @@ struct stlink_usb_handle_s {
        uint32_t address
 
        STLINK_SWIM_RESET
-       send syncronization seq (16us low, response 64 clocks low)
+       send synchronization seq (16us low, response 64 clocks low)
 */
 #define STLINK_SWIM_ENTER                  0x00
 #define STLINK_SWIM_EXIT                   0x01
@@ -264,10 +430,20 @@ struct stlink_usb_handle_s {
 #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_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC         0x50
+#define STLINK_DEBUG_APIV2_RW_MISC_OUT     0x51
+#define STLINK_DEBUG_APIV2_RW_MISC_IN      0x52
+
+#define STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC          0x54
+
 #define STLINK_APIV3_SET_COM_FREQ           0x61
 #define STLINK_APIV3_GET_COM_FREQ           0x62
 
@@ -277,36 +453,75 @@ struct stlink_usb_handle_s {
 #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_TRACE_MAX_HZ          24000000
 
 #define STLINK_V3_MAX_FREQ_NB               10
 
-/** */
-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
-};
-
 #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          10240
+#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              (1UL << 0)
-#define STLINK_F_HAS_SWD_SET_FREQ       (1UL << 1)
-#define STLINK_F_HAS_JTAG_SET_FREQ      (1UL << 2)
-#define STLINK_F_HAS_MEM_16BIT          (1UL << 3)
-#define STLINK_F_HAS_GETLASTRWSTATUS2   (1UL << 4)
+#define STLINK_F_HAS_TRACE              BIT(0)  /* v2>=j13 || v3     */
+#define STLINK_F_HAS_GETLASTRWSTATUS2   BIT(1)  /* v2>=j15 || v3     */
+#define STLINK_F_HAS_SWD_SET_FREQ       BIT(2)  /* v2>=j22           */
+#define STLINK_F_HAS_JTAG_SET_FREQ      BIT(3)  /* v2>=j24           */
+#define STLINK_F_QUIRK_JTAG_DP_READ     BIT(4)  /* v2>=j24 && v2<j32 */
+#define STLINK_F_HAS_DAP_REG            BIT(5)  /* v2>=j24 || v3     */
+#define STLINK_F_HAS_MEM_16BIT          BIT(6)  /* v2>=j26 || v3     */
+#define STLINK_F_HAS_AP_INIT            BIT(7)  /* v2>=j28 || v3     */
+#define STLINK_F_FIX_CLOSE_AP           BIT(8)  /* v2>=j29 || v3     */
+#define STLINK_F_HAS_DPBANKSEL          BIT(9)  /* v2>=j32 || v3>=j2 */
+#define STLINK_F_HAS_RW8_512BYTES       BIT(10) /*            v3>=j6 */
 
 /* aliases */
 #define STLINK_F_HAS_TARGET_VOLT        STLINK_F_HAS_TRACE
+#define STLINK_F_HAS_FPU_REG            STLINK_F_HAS_GETLASTRWSTATUS2
+#define STLINK_F_HAS_MEM_WR_NO_INC      STLINK_F_HAS_MEM_16BIT
+#define STLINK_F_HAS_MEM_RD_NO_INC      STLINK_F_HAS_DPBANKSEL
+#define STLINK_F_HAS_RW_MISC            STLINK_F_HAS_DPBANKSEL
+#define STLINK_F_HAS_CSW                STLINK_F_HAS_DPBANKSEL
+
+#define STLINK_REGSEL_IS_FPU(x)         ((x) > 0x1F)
 
 struct speed_map {
        int speed;
@@ -331,7 +546,6 @@ static const struct speed_map stlink_khz_to_speed_map_swd[] = {
 
 /* JTAG clock speed */
 static const struct speed_map stlink_khz_to_speed_map_jtag[] = {
-       {18000, 2},
        {9000,  4},
        {4500,  8},
        {2250, 16},
@@ -343,22 +557,24 @@ static const struct speed_map stlink_khz_to_speed_map_jtag[] = {
 
 static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
 static int stlink_swim_status(void *handle);
+static 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);
+static int stlink_speed(void *handle, int khz, bool query);
+static int stlink_usb_open_ap(void *handle, unsigned short apsel);
 
 /** */
 static unsigned int stlink_usb_block(void *handle)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       if (h->version.stlink == 3)
+       if (h->version.flags & STLINK_F_HAS_RW8_512BYTES)
                return STLINKV3_MAX_RW8;
        else
                return STLINK_MAX_RW8;
 }
 
-
-
 #ifdef USE_LIBUSB_ASYNCIO
 
 static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
@@ -373,13 +589,8 @@ 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);
+               r = jtag_libusb_handle_events_completed(completed);
                if (r < 0) {
                        if (r == LIBUSB_ERROR_INTERRUPTED)
                                continue;
@@ -434,7 +645,7 @@ struct jtag_xfer {
 };
 
 static int jtag_libusb_bulk_transfer_n(
-               jtag_libusb_device_handle * dev_handle,
+               struct libusb_device_handle *dev_handle,
                struct jtag_xfer *transfers,
                size_t n_transfers,
                int timeout)
@@ -449,7 +660,7 @@ static int jtag_libusb_bulk_transfer_n(
                transfers[i].transfer_size = 0;
                transfers[i].transfer = libusb_alloc_transfer(0);
 
-               if (transfers[i].transfer == NULL) {
+               if (!transfers[i].transfer) {
                        for (size_t j = 0; j < i; ++j)
                                libusb_free_transfer(transfers[j].transfer);
 
@@ -515,14 +726,16 @@ static int jtag_libusb_bulk_transfer_n(
 static int stlink_usb_xfer_v1_get_status(void *handle)
 {
        struct stlink_usb_handle_s *h = handle;
+       int tr, ret;
 
-       assert(handle != NULL);
+       assert(handle);
 
        /* read status */
        memset(h->cmdbuf, 0, STLINK_SG_SIZE);
 
-       if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf,
-                       13, STLINK_READ_TIMEOUT) != 13)
+       ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13,
+                                   STLINK_READ_TIMEOUT, &tr);
+       if (ret || tr != 13)
                return ERROR_FAIL;
 
        uint32_t t1;
@@ -549,7 +762,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        size_t n_transfers = 0;
        struct jtag_xfer transfers[2];
@@ -577,7 +790,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
        }
 
        return jtag_libusb_bulk_transfer_n(
-                       h->fd,
+                       h->usb_backend_priv.fd,
                        transfers,
                        n_transfers,
                        STLINK_WRITE_TIMEOUT);
@@ -586,23 +799,26 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
 static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
 {
        struct stlink_usb_handle_s *h = handle;
+       int tr, ret;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, cmdsize,
-                       STLINK_WRITE_TIMEOUT) != cmdsize) {
+       ret = jtag_libusb_bulk_write(h->usb_backend_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) {
-               if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
-                               size, STLINK_WRITE_TIMEOUT) != size) {
+               ret = jtag_libusb_bulk_write(h->usb_backend_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) {
-               if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
-                               size, STLINK_READ_TIMEOUT) != size) {
+               ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf,
+                                           size, STLINK_READ_TIMEOUT, &tr);
+               if (ret || tr != size) {
                        LOG_DEBUG("bulk read failed");
                        return ERROR_FAIL;
                }
@@ -618,7 +834,7 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 16);
 
@@ -639,17 +855,34 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
        return ERROR_OK;
 }
 
+/** */
+static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+       int tr, ret;
+
+       ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (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(void *handle, const uint8_t *buf, int size)
+static int stlink_usb_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);
+       assert(handle);
 
        if (h->version.stlink == 1) {
                cmdsize = STLINK_SG_SIZE;
@@ -677,6 +910,135 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
        return ERROR_OK;
 }
 
+
+static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle);
+
+       /* send the TCP command */
+       int sent_size = send(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.send_buf, send_size, 0);
+       if (sent_size != send_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, send_size);
+               return ERROR_FAIL;
+       }
+
+       /* read the TCP response */
+       int retval = ERROR_OK;
+       int remaining_bytes = recv_size;
+       uint8_t *recv_buf = h->tcp_backend_priv.recv_buf;
+       const int64_t timeout = timeval_ms() + 1000; /* 1 second */
+
+       while (remaining_bytes > 0) {
+               if (timeval_ms() > timeout) {
+                       LOG_DEBUG("received size %d (expected %d)", recv_size - remaining_bytes, recv_size);
+                       retval = ERROR_TIMEOUT_REACHED;
+                       break;
+               }
+
+               keep_alive();
+               int received = recv(h->tcp_backend_priv.fd, (void *)recv_buf, remaining_bytes, 0);
+
+               if (received == -1) {
+                       LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno);
+                       retval = ERROR_FAIL;
+                       break;
+               }
+
+               recv_buf += received;
+               remaining_bytes -= received;
+       }
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("failed to receive USB CMD response");
+               return retval;
+       }
+
+       if (check_tcp_status) {
+               uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf);
+               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_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       int send_size = STLINK_TCP_USB_CMD_SIZE;
+       int recv_size = STLINK_TCP_SS_SIZE;
+
+       assert(handle);
+
+       /* prepare the TCP command */
+       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_SEND_USB_CMD;
+       memset(&h->tcp_backend_priv.send_buf[1], 0, 3); /* reserved for alignment and future use, must be zero */
+       h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id);
+       /* tcp_backend_priv.send_buf[8..23] already contains the constructed stlink command */
+       h->tcp_backend_priv.send_buf[24] = h->direction;
+       memset(&h->tcp_backend_priv.send_buf[25], 0, 3);  /* reserved for alignment and future use, must be zero */
+
+       h_u32_to_le(&h->tcp_backend_priv.send_buf[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 */
+               send_size += size;
+               if (send_size > STLINK_TCP_SEND_BUFFER_SIZE) {
+                       LOG_ERROR("STLINK_TCP command buffer overflow");
+                       return ERROR_FAIL;
+               }
+               memcpy(&h->tcp_backend_priv.send_buf[32], buf, size);
+       } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */
+               recv_size += size;
+               if (recv_size > STLINK_TCP_RECV_BUFFER_SIZE) {
+                       LOG_ERROR("STLINK_TCP data buffer overflow");
+                       return ERROR_FAIL;
+               }
+       }
+
+       int ret = stlink_tcp_send_cmd(h, send_size, recv_size, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       if (h->direction != h->tx_ep) {
+               /* the read data is located in tcp_backend_priv.recv_buf[4] */
+               /* most of the case it will be copying the data from tcp_backend_priv.recv_buf[4]
+                * to handle->cmd_buff which are the same, so let's avoid unnecessary copying */
+               if (buf != &h->tcp_backend_priv.recv_buf[4])
+                       memcpy((uint8_t *)buf, &h->tcp_backend_priv.recv_buf[4], size);
+       }
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       stlink_usb_init_buffer(h, h->trace_ep, 0);
+       return stlink_tcp_xfer_noerrcheck(handle, buf, size);
+}
+
 /**
     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.
@@ -685,9 +1047,9 @@ static int stlink_usb_error_check(void *handle)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       if (h->transport == HL_TRANSPORT_SWIM) {
+       if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
                switch (h->databuf[0]) {
                        case STLINK_SWIM_ERR_OK:
                                return ERROR_OK;
@@ -715,6 +1077,9 @@ static int stlink_usb_error_check(void *handle)
                case STLINK_SWD_DP_WAIT:
                        LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT);
                        return ERROR_WAIT;
+               case STLINK_JTAG_GET_IDCODE_ERROR:
+                       LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR");
+                       return ERROR_FAIL;
                case STLINK_JTAG_WRITE_ERROR:
                        LOG_DEBUG("Write error");
                        return ERROR_FAIL;
@@ -762,6 +1127,22 @@ static int stlink_usb_error_check(void *handle)
        }
 }
 
+/*
+ * Wrapper around stlink_usb_xfer_noerrcheck()
+ * to check the error code in the received packet
+ */
+static int stlink_usb_xfer_errcheck(void *handle, const uint8_t *buf, int size)
+{
+       int retval;
+
+       assert(size > 0);
+
+       retval = stlink_usb_xfer_noerrcheck(handle, buf, size);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return stlink_usb_error_check(handle);
+}
 
 /** Issue an STLINK command via USB transfer, with retries on any wait status responses.
 
@@ -777,13 +1158,13 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
        struct stlink_usb_handle_s *h = handle;
 
        while (1) {
-               if ((h->transport != HL_TRANSPORT_SWIM) || !retries) {
-                       res = stlink_usb_xfer(handle, buf, size);
+               if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) {
+                       res = stlink_usb_xfer_noerrcheck(handle, buf, size);
                        if (res != ERROR_OK)
                                return res;
                }
 
-               if (h->transport == HL_TRANSPORT_SWIM) {
+               if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
                        res = stlink_swim_status(handle);
                        if (res != ERROR_OK)
                                return res;
@@ -791,7 +1172,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
 
                res = stlink_usb_error_check(handle);
                if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
-                       useconds_t delay_us = (1<<retries++) * 1000;
+                       unsigned int delay_us = (1<<retries++) * 1000;
                        LOG_DEBUG("stlink_cmd_allow_retry ERROR_WAIT, retry %d, delaying %u microseconds", retries, delay_us);
                        usleep(delay_us);
                        continue;
@@ -805,17 +1186,11 @@ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        assert(h->version.flags & STLINK_F_HAS_TRACE);
 
-       if (jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf,
-                       size, STLINK_READ_TIMEOUT) != size) {
-               LOG_ERROR("bulk trace read failed");
-               return ERROR_FAIL;
-       }
-
-       return ERROR_OK;
+       return h->backend->read_trace(handle, buf, size);
 }
 
 /*
@@ -876,13 +1251,13 @@ static int stlink_usb_version(void *handle)
        char *p;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 6);
 
        h->cmdbuf[h->cmdidx++] = STLINK_GET_VERSION;
 
-       res = stlink_usb_xfer(handle, h->databuf, 6);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 6);
 
        if (res != ERROR_OK)
                return res;
@@ -923,7 +1298,7 @@ static int stlink_usb_version(void *handle)
 
                h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_VERSION_EX;
 
-               res = stlink_usb_xfer(handle, h->databuf, 12);
+               res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 12);
                if (res != ERROR_OK)
                        return res;
 
@@ -968,13 +1343,35 @@ static int stlink_usb_version(void *handle)
                        flags |= STLINK_F_HAS_SWD_SET_FREQ;
 
                /* API to set JTAG frequency from J24 */
-               if (h->version.jtag >= 24)
+               /* API to access DAP registers from J24 */
+               if (h->version.jtag >= 24) {
                        flags |= STLINK_F_HAS_JTAG_SET_FREQ;
+                       flags |= STLINK_F_HAS_DAP_REG;
+               }
+
+               /* Quirk for read DP in JTAG mode (V2 only) from J24, fixed in J32 */
+               if (h->version.jtag >= 24 && h->version.jtag < 32)
+                       flags |= STLINK_F_QUIRK_JTAG_DP_READ;
 
                /* API to read/write memory at 16 bit from J26 */
+               /* API to write memory without address increment from J26 */
                if (h->version.jtag >= 26)
                        flags |= STLINK_F_HAS_MEM_16BIT;
 
+               /* API required to init AP before any AP access from J28 */
+               if (h->version.jtag >= 28)
+                       flags |= STLINK_F_HAS_AP_INIT;
+
+               /* API required to return proper error code on close AP from J29 */
+               if (h->version.jtag >= 29)
+                       flags |= STLINK_F_FIX_CLOSE_AP;
+
+               /* Banked regs (DPv1 & DPv2) support from V2J32 */
+               /* API to read memory without address increment from V2J32 */
+               /* Memory R/W supports CSW from V2J32 */
+               if (h->version.jtag >= 32)
+                       flags |= STLINK_F_HAS_DPBANKSEL;
+
                break;
        case 3:
                /* all STLINK-V3 use api-v3 */
@@ -989,9 +1386,29 @@ static int stlink_usb_version(void *handle)
                /* preferred API to get last R/W status */
                flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
 
+               /* API to access DAP registers */
+               flags |= STLINK_F_HAS_DAP_REG;
+
                /* API to read/write memory at 16 bit */
+               /* API to write memory without address increment */
                flags |= STLINK_F_HAS_MEM_16BIT;
 
+               /* API required to init AP before any AP access */
+               flags |= STLINK_F_HAS_AP_INIT;
+
+               /* API required to return proper error code on close AP */
+               flags |= STLINK_F_FIX_CLOSE_AP;
+
+               /* Banked regs (DPv1 & DPv2) support from V3J2 */
+               /* API to read memory without address increment from V3J2 */
+               /* Memory R/W supports CSW from V3J2 */
+               if (h->version.jtag >= 2)
+                       flags |= STLINK_F_HAS_DPBANKSEL;
+
+               /* 8bit read/write max packet size 512 bytes from V3J6 */
+               if (h->version.jtag >= 6)
+                       flags |= STLINK_F_HAS_RW8_512BYTES;
+
                break;
        default:
                break;
@@ -1031,7 +1448,7 @@ static int stlink_usb_check_voltage(void *handle, float *target_voltage)
 
        h->cmdbuf[h->cmdidx++] = STLINK_GET_TARGET_VOLTAGE;
 
-       int result = stlink_usb_xfer(handle, h->databuf, 8);
+       int result = stlink_usb_xfer_noerrcheck(handle, h->databuf, 8);
 
        if (result != ERROR_OK)
                return result;
@@ -1054,7 +1471,7 @@ static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ))
                return ERROR_COMMAND_NOTFOUND;
@@ -1078,7 +1495,7 @@ static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ))
                return ERROR_COMMAND_NOTFOUND;
@@ -1104,13 +1521,13 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
 
        h->cmdbuf[h->cmdidx++] = STLINK_GET_CURRENT_MODE;
 
-       res = stlink_usb_xfer(handle, h->databuf, 2);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
@@ -1126,7 +1543,7 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
        int rx_size = 0;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        /* on api V2 we are able the read the latest command
         * status
@@ -1157,9 +1574,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
                case STLINK_MODE_DEBUG_SWIM:
                        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
                        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER;
-                       /* no answer for this function... */
-                       rx_size = 0;
-                       break;
+                       /* swim enter does not return any response or status */
+                       return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0);
                case STLINK_MODE_DFU:
                case STLINK_MODE_MASS:
                default:
@@ -1175,9 +1591,10 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0);
+       /* command with no reply, use a valid endpoint but zero size */
+       stlink_usb_init_buffer(handle, h->rx_ep, 0);
 
        switch (type) {
                case STLINK_MODE_DEBUG_JTAG:
@@ -1198,7 +1615,7 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
                        return ERROR_FAIL;
        }
 
-       res = stlink_usb_xfer(handle, 0, 0);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0);
 
        if (res != ERROR_OK)
                return res;
@@ -1215,22 +1632,19 @@ static enum stlink_mode stlink_get_mode(enum hl_transports t)
                return STLINK_MODE_DEBUG_SWD;
        case HL_TRANSPORT_JTAG:
                return STLINK_MODE_DEBUG_JTAG;
-       case HL_TRANSPORT_SWIM:
-               return STLINK_MODE_DEBUG_SWIM;
        default:
                return STLINK_MODE_UNKNOWN;
        }
 }
 
 /** */
-static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
+static int stlink_usb_exit_mode(void *handle)
 {
        int res;
        uint8_t mode;
        enum stlink_mode emode;
-       struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        res = stlink_usb_current_mode(handle, &mode);
 
@@ -1257,12 +1671,25 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
                        break;
        }
 
-       if (emode != STLINK_MODE_UNKNOWN) {
-               res = stlink_usb_mode_leave(handle, emode);
+       if (emode != STLINK_MODE_UNKNOWN)
+               return stlink_usb_mode_leave(handle, emode);
 
-               if (res != ERROR_OK)
-                       return res;
-       }
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed)
+{
+       int res;
+       uint8_t mode;
+       enum stlink_mode emode;
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle);
+
+       res = stlink_usb_exit_mode(handle);
+       if (res != ERROR_OK)
+               return res;
 
        res = stlink_usb_current_mode(handle, &mode);
 
@@ -1295,13 +1722,35 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
        LOG_DEBUG("MODE: 0x%02X", mode);
 
        /* set selected mode */
-       emode = stlink_get_mode(h->transport);
+       emode = h->st_mode;
 
        if (emode == STLINK_MODE_UNKNOWN) {
                LOG_ERROR("selected mode (transport) not supported");
                return ERROR_FAIL;
        }
 
+       /* set the speed before entering the mode, as the chip discovery phase should be done at this speed too */
+       if (emode == STLINK_MODE_DEBUG_JTAG) {
+               if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) {
+                       stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag));
+                       stlink_speed(h, initial_interface_speed, false);
+               }
+       } else if (emode == STLINK_MODE_DEBUG_SWD) {
+               if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) {
+                       stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd));
+                       stlink_speed(h, initial_interface_speed, false);
+               }
+       }
+
+       if (h->version.jtag_api == STLINK_JTAG_API_V3 &&
+                       (emode == STLINK_MODE_DEBUG_JTAG || emode == STLINK_MODE_DEBUG_SWD)) {
+               struct speed_map map[STLINK_V3_MAX_FREQ_NB];
+
+               stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map);
+               stlink_dump_speed_map(map, ARRAY_SIZE(map));
+               stlink_speed(h, initial_interface_speed, false);
+       }
+
        /* preliminary SRST assert:
         * We want SRST is asserted before activating debug signals (mode_enter).
         * As the required mode has not been set, the adapter may not know what pin to use.
@@ -1344,14 +1793,15 @@ static int stlink_swim_status(void *handle)
        stlink_usb_init_buffer(handle, h->rx_ep, 4);
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READSTATUS;
-       res = stlink_usb_xfer(handle, h->databuf, 4);
+       /* error is checked by the caller */
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4);
        if (res != ERROR_OK)
                return res;
        return ERROR_OK;
 }
 /*
        the purpose of this function is unknown...
-       capabilites? anyway for swim v6 it returns
+       capabilities? anyway for swim v6 it returns
        0001020600000000
 */
 __attribute__((unused))
@@ -1364,7 +1814,7 @@ static int stlink_swim_cap(void *handle, uint8_t *cap)
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READ_CAP;
        h->cmdbuf[h->cmdidx++] = 0x01;
-       res = stlink_usb_xfer(handle, h->databuf, 8);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 8);
        if (res != ERROR_OK)
                return res;
        memcpy(cap, h->databuf, 8);
@@ -1445,7 +1895,7 @@ static int stlink_swim_generate_rst(void *handle)
 }
 
 /*
-       send resyncronize sequence
+       send resynchronize sequence
        swim is pulled low for 16us
        reply is 64 clks low
 */
@@ -1471,7 +1921,7 @@ static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, con
        unsigned int datalen = 0;
        int cmdsize = STLINK_CMD_SIZE_V2;
 
-       if (len > STLINK_DATA_SIZE)
+       if (len > STLINK_SWIM_DATA_SIZE)
                return ERROR_FAIL;
 
        if (h->version.stlink == 1)
@@ -1504,7 +1954,7 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint
        struct stlink_usb_handle_s *h = handle;
        int res;
 
-       if (len > STLINK_DATA_SIZE)
+       if (len > STLINK_SWIM_DATA_SIZE)
                return ERROR_FAIL;
 
        stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1521,7 +1971,7 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint
        stlink_usb_init_buffer(handle, h->rx_ep, len);
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
        h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READBUF;
-       res = stlink_usb_xfer(handle, data, len);
+       res = stlink_usb_xfer_noerrcheck(handle, data, len);
        if (res != ERROR_OK)
                return res;
 
@@ -1531,28 +1981,36 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint
 /** */
 static int stlink_usb_idcode(void *handle, uint32_t *idcode)
 {
-       int res;
+       int res, offset;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        /* there is no swim read core id cmd */
-       if (h->transport == HL_TRANSPORT_SWIM) {
+       if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
                *idcode = 0;
                return ERROR_OK;
        }
 
-       stlink_usb_init_buffer(handle, h->rx_ep, 4);
+       stlink_usb_init_buffer(handle, h->rx_ep, 12);
 
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
-       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READCOREID;
+       if (h->version.jtag_api == STLINK_JTAG_API_V1) {
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READCOREID;
+
+               res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4);
+               offset = 0;
+       } else {
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_IDCODES;
 
-       res = stlink_usb_xfer(handle, h->databuf, 4);
+               res = stlink_usb_xfer_errcheck(handle, h->databuf, 12);
+               offset = 4;
+       }
 
        if (res != ERROR_OK)
                return res;
 
-       *idcode = le_to_h_u32(h->databuf);
+       *idcode = le_to_h_u32(h->databuf + offset);
 
        LOG_DEBUG("IDCODE: 0x%08" PRIX32, *idcode);
 
@@ -1564,7 +2022,7 @@ static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *v
        struct stlink_usb_handle_s *h = handle;
        int res;
 
-       assert(handle != NULL);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 8);
 
@@ -1585,7 +2043,7 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
 
@@ -1607,7 +2065,7 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->trace.enabled && (h->version.flags & STLINK_F_HAS_TRACE)) {
                int res;
@@ -1617,12 +2075,12 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GET_TRACE_NB;
 
-               res = stlink_usb_xfer(handle, h->databuf, 2);
+               res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
                if (res != ERROR_OK)
                        return res;
 
                size_t bytes_avail = le_to_h_u16(h->databuf);
-               *size = bytes_avail < *size ? bytes_avail : *size - 1;
+               *size = bytes_avail < *size ? bytes_avail : *size;
 
                if (*size > 0) {
                        res = stlink_usb_read_trace(handle, buf, *size);
@@ -1658,24 +2116,11 @@ static enum target_state stlink_usb_state(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
-
-       if (h->transport == HL_TRANSPORT_SWIM) {
-               res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
-               if (res != ERROR_OK)
-                       return TARGET_UNKNOWN;
-
-               res = stlink_swim_resync(handle);
-               if (res != ERROR_OK)
-                       return TARGET_UNKNOWN;
-
-               return ERROR_OK;
-       }
+       assert(handle);
 
        if (h->reconnect_pending) {
                LOG_INFO("Previous state query failed, trying to reconnect");
-               res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
-
+               res = stlink_usb_mode_enter(handle, h->st_mode);
                if (res != ERROR_OK)
                        return TARGET_UNKNOWN;
 
@@ -1694,7 +2139,7 @@ static enum target_state stlink_usb_state(void *handle)
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_GETSTATUS;
 
-       res = stlink_usb_xfer(handle, h->databuf, 2);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return TARGET_UNKNOWN;
@@ -1713,9 +2158,9 @@ static int stlink_usb_assert_srst(void *handle, int srst)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       if (h->transport == HL_TRANSPORT_SWIM)
+       if (h->st_mode == STLINK_MODE_DEBUG_SWIM)
                return stlink_swim_assert_reset(handle, srst);
 
        if (h->version.stlink == 1)
@@ -1736,7 +2181,7 @@ static void stlink_usb_trace_disable(void *handle)
        int res = ERROR_OK;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        assert(h->version.flags & STLINK_F_HAS_TRACE);
 
@@ -1745,7 +2190,7 @@ static void stlink_usb_trace_disable(void *handle)
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX;
-       res = stlink_usb_xfer(handle, h->databuf, 2);
+       res = stlink_usb_xfer_errcheck(handle, h->databuf, 2);
 
        if (res == ERROR_OK)
                h->trace.enabled = false;
@@ -1758,7 +2203,7 @@ static int stlink_usb_trace_enable(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->version.flags & STLINK_F_HAS_TRACE) {
                stlink_usb_init_buffer(handle, h->rx_ep, 10);
@@ -1770,7 +2215,7 @@ static int stlink_usb_trace_enable(void *handle)
                h_u32_to_le(h->cmdbuf+h->cmdidx, h->trace.source_hz);
                h->cmdidx += 4;
 
-               res = stlink_usb_xfer(handle, h->databuf, 2);
+               res = stlink_usb_xfer_errcheck(handle, h->databuf, 2);
 
                if (res == ERROR_OK)  {
                        h->trace.enabled = true;
@@ -1790,10 +2235,7 @@ static int stlink_usb_reset(void *handle)
        struct stlink_usb_handle_s *h = handle;
        int retval;
 
-       assert(handle != NULL);
-
-       if (h->transport == HL_TRANSPORT_SWIM)
-               return stlink_swim_generate_rst(handle);
+       assert(handle);
 
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
 
@@ -1822,7 +2264,7 @@ static int stlink_usb_run(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->version.jtag_api != STLINK_JTAG_API_V1) {
                res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
@@ -1844,7 +2286,7 @@ static int stlink_usb_halt(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->version.jtag_api != STLINK_JTAG_API_V1) {
                res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
@@ -1865,7 +2307,7 @@ static int stlink_usb_step(void *handle)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->version.jtag_api != STLINK_JTAG_API_V1) {
                /* TODO: this emulates the v1 api, it should really use a similar auto mask isr
@@ -1889,31 +2331,41 @@ static int stlink_usb_read_regs(void *handle)
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
-       stlink_usb_init_buffer(handle, h->rx_ep, 84);
+       stlink_usb_init_buffer(handle, h->rx_ep, 88);
 
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
-       if (h->version.jtag_api == STLINK_JTAG_API_V1)
+       if (h->version.jtag_api == STLINK_JTAG_API_V1) {
+
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READALLREGS;
-       else
+               res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 84);
+               /* regs data from offset 0 */
+       } else {
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READALLREGS;
+               res = stlink_usb_xfer_errcheck(handle, h->databuf, 88);
+               /* status at offset 0, regs data from offset 4 */
+       }
 
-       res = stlink_usb_xfer(handle, h->databuf, 84);
-
-       if (res != ERROR_OK)
-               return res;
-
-       return ERROR_OK;
+       return res;
 }
 
 /** */
-static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
+static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
+               res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f);
+               if (res != ERROR_OK)
+                       return res;
+
+               /* FIXME: poll DHCSR.S_REGRDY before read DCRDR */
+               return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val);
+       }
 
        stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
 
@@ -1922,10 +2374,10 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG;
        else
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
-       h->cmdbuf[h->cmdidx++] = num;
+       h->cmdbuf[h->cmdidx++] = regsel;
 
        if (h->version.jtag_api == STLINK_JTAG_API_V1) {
-               res = stlink_usb_xfer(handle, h->databuf, 4);
+               res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4);
                if (res != ERROR_OK)
                        return res;
                *val = le_to_h_u32(h->databuf);
@@ -1940,11 +2392,20 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
 }
 
 /** */
-static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
+static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) {
+               int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val);
+               if (res != ERROR_OK)
+                       return res;
+
+               return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WNR | (regsel & 0x7f));
+               /* FIXME: poll DHCSR.S_REGRDY after write DCRSR */
+       }
 
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
 
@@ -1953,7 +2414,7 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG;
        else
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG;
-       h->cmdbuf[h->cmdidx++] = num;
+       h->cmdbuf[h->cmdidx++] = regsel;
        h_u32_to_le(h->cmdbuf+h->cmdidx, val);
        h->cmdidx += 4;
 
@@ -1962,10 +2423,9 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
 
 static int stlink_usb_get_rw_status(void *handle)
 {
-       int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (h->version.jtag_api == STLINK_JTAG_API_V1)
                return ERROR_OK;
@@ -1975,29 +2435,25 @@ static int stlink_usb_get_rw_status(void *handle)
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        if (h->version.flags & STLINK_F_HAS_GETLASTRWSTATUS2) {
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS2;
-
-               res = stlink_usb_xfer(handle, h->databuf, 12);
+               return stlink_usb_xfer_errcheck(handle, h->databuf, 12);
        } else {
                h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS;
-
-               res = stlink_usb_xfer(handle, h->databuf, 2);
+               return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
        }
-
-       if (res != ERROR_OK)
-               return res;
-
-       return stlink_usb_error_check(h);
 }
 
 /** */
-static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
-                         uint8_t *buffer)
+static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, uint8_t *buffer)
 {
        int res;
        uint16_t read_len = len;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
 
        /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */
        if (len > stlink_usb_block(h)) {
@@ -2013,12 +2469,15 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
        /* we need to fix read length for single bytes */
        if (read_len == 1)
                read_len++;
 
-       res = stlink_usb_xfer(handle, h->databuf, read_len);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, read_len);
 
        if (res != ERROR_OK)
                return res;
@@ -2029,13 +2488,16 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
 }
 
 /** */
-static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
-                          const uint8_t *buffer)
+static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, const uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
 
        /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */
        if (len > stlink_usb_block(h)) {
@@ -2051,8 +2513,11 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
-       res = stlink_usb_xfer(handle, buffer, len);
+       res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
 
        if (res != ERROR_OK)
                return res;
@@ -2061,17 +2526,25 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
 }
 
 /** */
-static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len,
-                         uint8_t *buffer)
+static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT))
                return ERROR_COMMAND_NOTFOUND;
 
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
+
        /* data must be a multiple of 2 and half-word aligned */
        if (len % 2 || addr % 2) {
                LOG_DEBUG("Invalid data alignment");
@@ -2086,8 +2559,11 @@ static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
-       res = stlink_usb_xfer(handle, h->databuf, len);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len);
 
        if (res != ERROR_OK)
                return res;
@@ -2098,17 +2574,25 @@ static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len,
 }
 
 /** */
-static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len,
-                          const uint8_t *buffer)
+static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, const uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
 
        if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT))
                return ERROR_COMMAND_NOTFOUND;
 
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
+
        /* data must be a multiple of 2 and half-word aligned */
        if (len % 2 || addr % 2) {
                LOG_DEBUG("Invalid data alignment");
@@ -2123,8 +2607,11 @@ static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
-       res = stlink_usb_xfer(handle, buffer, len);
+       res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
 
        if (res != ERROR_OK)
                return res;
@@ -2133,13 +2620,21 @@ static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len,
 }
 
 /** */
-static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
-                         uint8_t *buffer)
+static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
 
        /* data must be a multiple of 4 and word aligned */
        if (len % 4 || addr % 4) {
@@ -2155,8 +2650,11 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
-       res = stlink_usb_xfer(handle, h->databuf, len);
+       res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len);
 
        if (res != ERROR_OK)
                return res;
@@ -2167,13 +2665,21 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
 }
 
 /** */
-static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
-                          const uint8_t *buffer)
+static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, const uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h = handle;
 
-       assert(handle != NULL);
+       assert(handle);
+
+       if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
 
        /* data must be a multiple of 4 and word aligned */
        if (len % 4 || addr % 4) {
@@ -2189,8 +2695,11 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
        h->cmdidx += 4;
        h_u16_to_le(h->cmdbuf+h->cmdidx, len);
        h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
 
-       res = stlink_usb_xfer(handle, buffer, len);
+       res = stlink_usb_xfer_noerrcheck(handle, buffer, len);
 
        if (res != ERROR_OK)
                return res;
@@ -2198,6 +2707,88 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
        return stlink_usb_get_rw_status(handle);
 }
 
+static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, uint8_t *buffer)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle != NULL);
+
+       if (!(h->version.flags & STLINK_F_HAS_MEM_RD_NO_INC))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
+
+       /* data must be a multiple of 4 and word aligned */
+       if (len % 4 || addr % 4) {
+               LOG_DEBUG("Invalid data alignment");
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       }
+
+       stlink_usb_init_buffer(handle, h->rx_ep, len);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC;
+       h_u32_to_le(h->cmdbuf + h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf + h->cmdidx, len);
+       h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
+
+       int retval = stlink_usb_xfer_noerrcheck(handle, h->databuf, len);
+       if (retval != ERROR_OK)
+               return retval;
+
+       memcpy(buffer, h->databuf, len);
+
+       return stlink_usb_get_rw_status(handle);
+}
+
+static int stlink_usb_write_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint16_t len, const uint8_t *buffer)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle != NULL);
+
+       if (!(h->version.flags & STLINK_F_HAS_MEM_WR_NO_INC))
+               return ERROR_COMMAND_NOTFOUND;
+
+       if (len > STLINK_MAX_RW16_32) {
+               LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32);
+               return ERROR_FAIL;
+       }
+
+       /* data must be a multiple of 4 and word aligned */
+       if (len % 4 || addr % 4) {
+               LOG_DEBUG("Invalid data alignment");
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       }
+
+       stlink_usb_init_buffer(handle, h->tx_ep, len);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC;
+       h_u32_to_le(h->cmdbuf + h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf + h->cmdidx, len);
+       h->cmdidx += 2;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+       h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8);
+       h->cmdidx += 3;
+
+       int retval = stlink_usb_xfer_noerrcheck(handle, buffer, len);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return stlink_usb_get_rw_status(handle);
+}
+
 static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t address)
 {
        uint32_t max_tar_block = (tar_autoincr_block - ((tar_autoincr_block - 1) & address));
@@ -2206,8 +2797,8 @@ static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t addr
        return max_tar_block;
 }
 
-static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
-               uint32_t count, uint8_t *buffer)
+static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer)
 {
        int retval = ERROR_OK;
        uint32_t bytes_remaining;
@@ -2222,18 +2813,12 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
                size = 1;
 
        while (count) {
-
-               bytes_remaining = (size != 1) ? \
+               bytes_remaining = (size != 1) ?
                                stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h);
 
                if (count < bytes_remaining)
                        bytes_remaining = count;
 
-               if (h->transport == HL_TRANSPORT_SWIM) {
-                       retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer);
-                       if (retval != ERROR_OK)
-                               return retval;
-               } else
                /*
                 * all stlink support 8/32bit memory read/writes and only from
                 * stlink V2J26 there is support for 16 bit memory read/write.
@@ -2241,7 +2826,6 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
                 * as 8bit access.
                 */
                if (size != 1) {
-
                        /* When in jtag mode the stlink uses the auto-increment functionality.
                         * However it expects us to pass the data correctly, this includes
                         * alignment and any page boundaries. We already do this as part of the
@@ -2252,11 +2836,10 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
 
                        /* we first need to check for any unaligned bytes */
                        if (addr & (size - 1)) {
-
                                uint32_t head_bytes = size - (addr & (size - 1));
-                               retval = stlink_usb_read_mem8(handle, addr, head_bytes, buffer);
+                               retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, head_bytes, buffer);
                                if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
-                                       usleep((1<<retries++) * 1000);
+                                       usleep((1 << retries++) * 1000);
                                        continue;
                                }
                                if (retval != ERROR_OK)
@@ -2268,16 +2851,17 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
                        }
 
                        if (bytes_remaining & (size - 1))
-                               retval = stlink_usb_read_mem(handle, addr, 1, bytes_remaining, buffer);
+                               retval = stlink_usb_read_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer);
                        else if (size == 2)
-                               retval = stlink_usb_read_mem16(handle, addr, bytes_remaining, buffer);
+                               retval = stlink_usb_read_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer);
                        else
-                               retval = stlink_usb_read_mem32(handle, addr, bytes_remaining, buffer);
-               } else
-                       retval = stlink_usb_read_mem8(handle, addr, bytes_remaining, buffer);
+                               retval = stlink_usb_read_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer);
+               } else {
+                       retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer);
+               }
 
                if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
-                       usleep((1<<retries++) * 1000);
+                       usleep((1 << retries++) * 1000);
                        continue;
                }
                if (retval != ERROR_OK)
@@ -2291,8 +2875,15 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
        return retval;
 }
 
-static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
-               uint32_t count, const uint8_t *buffer)
+static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
+               uint32_t count, uint8_t *buffer)
+{
+       return stlink_usb_read_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW,
+                                                                 addr, size, count, buffer);
+}
+
+static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
+               uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer)
 {
        int retval = ERROR_OK;
        uint32_t bytes_remaining;
@@ -2308,17 +2899,12 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
 
        while (count) {
 
-               bytes_remaining = (size != 1) ? \
+               bytes_remaining = (size != 1) ?
                                stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h);
 
                if (count < bytes_remaining)
                        bytes_remaining = count;
 
-               if (h->transport == HL_TRANSPORT_SWIM) {
-                       retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer);
-                       if (retval != ERROR_OK)
-                               return retval;
-               } else
                /*
                 * all stlink support 8/32bit memory read/writes and only from
                 * stlink V2J26 there is support for 16 bit memory read/write.
@@ -2339,7 +2925,7 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
                        if (addr & (size - 1)) {
 
                                uint32_t head_bytes = size - (addr & (size - 1));
-                               retval = stlink_usb_write_mem8(handle, addr, head_bytes, buffer);
+                               retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, head_bytes, buffer);
                                if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
                                        usleep((1<<retries++) * 1000);
                                        continue;
@@ -2353,14 +2939,14 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
                        }
 
                        if (bytes_remaining & (size - 1))
-                               retval = stlink_usb_write_mem(handle, addr, 1, bytes_remaining, buffer);
+                               retval = stlink_usb_write_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer);
                        else if (size == 2)
-                               retval = stlink_usb_write_mem16(handle, addr, bytes_remaining, buffer);
+                               retval = stlink_usb_write_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer);
                        else
-                               retval = stlink_usb_write_mem32(handle, addr, bytes_remaining, buffer);
+                               retval = stlink_usb_write_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer);
 
                } else
-                       retval = stlink_usb_write_mem8(handle, addr, bytes_remaining, buffer);
+                       retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer);
                if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
                        usleep((1<<retries++) * 1000);
                        continue;
@@ -2376,6 +2962,13 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
        return retval;
 }
 
+static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
+               uint32_t count, const uint8_t *buffer)
+{
+       return stlink_usb_write_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW,
+                                                                  addr, size, count, buffer);
+}
+
 /** */
 static int stlink_usb_override_target(const char *targetname)
 {
@@ -2384,17 +2977,20 @@ static int stlink_usb_override_target(const char *targetname)
 
 static int stlink_speed_swim(void *handle, int khz, bool query)
 {
+       int retval;
+
        /*
-                       we dont care what the khz rate is
                        we only have low and high speed...
                        before changing speed the SWIM_CSR HS bit
                        must be updated
         */
-       if (khz == 0)
-               stlink_swim_speed(handle, 0);
-       else
-               stlink_swim_speed(handle, 1);
-       return khz;
+       if (!query) {
+               retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1);
+               if (retval != ERROR_OK)
+                       LOG_ERROR("Unable to set adapter speed");
+       }
+
+       return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH;
 }
 
 static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query)
@@ -2432,7 +3028,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_
                match = false;
 
        if (!match && query) {
-               LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \
+               LOG_INFO("Unable to match requested speed %d kHz, using %d kHz",
                                khz, map[speed_index].speed);
        }
 
@@ -2485,7 +3081,7 @@ static int stlink_speed_jtag(void *handle, int khz, bool query)
        return stlink_khz_to_speed_map_jtag[speed_index].speed;
 }
 
-void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
+static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size)
 {
        unsigned int i;
 
@@ -2511,7 +3107,7 @@ static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map
        h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_COM_FREQ;
        h->cmdbuf[h->cmdidx++] = is_jtag ? 1 : 0;
 
-       int res = stlink_usb_xfer(handle, h->databuf, 52);
+       int res = stlink_usb_xfer_errcheck(handle, h->databuf, 52);
 
        int size = h->databuf[8];
 
@@ -2548,7 +3144,7 @@ static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequenc
 
        h_u32_to_le(&h->cmdbuf[4], frequency);
 
-       return stlink_usb_xfer(handle, h->databuf, 8);
+       return stlink_usb_xfer_errcheck(handle, h->databuf, 8);
 }
 
 static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query)
@@ -2578,17 +3174,16 @@ static int stlink_speed(void *handle, int khz, bool query)
        if (!handle)
                return khz;
 
-       switch (h->transport) {
-       case HL_TRANSPORT_SWIM:
+       switch (h->st_mode) {
+       case STLINK_MODE_DEBUG_SWIM:
                return stlink_speed_swim(handle, khz, query);
-               break;
-       case HL_TRANSPORT_SWD:
+       case STLINK_MODE_DEBUG_SWD:
                if (h->version.jtag_api == STLINK_JTAG_API_V3)
                        return stlink_speed_v3(handle, false, khz, query);
                else
                        return stlink_speed_swd(handle, khz, query);
                break;
-       case HL_TRANSPORT_JTAG:
+       case STLINK_MODE_DEBUG_JTAG:
                if (h->version.jtag_api == STLINK_JTAG_API_V3)
                        return stlink_speed_v3(handle, true, khz, query);
                else
@@ -2602,76 +3197,163 @@ static int stlink_speed(void *handle, int khz, bool query)
 }
 
 /** */
-static int stlink_usb_close(void *handle)
+static int stlink_usb_usb_close(void *handle)
 {
-       int res;
-       uint8_t mode;
-       enum stlink_mode emode;
        struct stlink_usb_handle_s *h = handle;
 
-       if (h && h->fd)
-               res = stlink_usb_current_mode(handle, &mode);
-       else
-               res = ERROR_FAIL;
-       /* do not exit if return code != ERROR_OK,
-          it prevents us from closing jtag_libusb */
-
-       if (res == ERROR_OK) {
-               /* try to exit current mode */
-               switch (mode) {
-                       case STLINK_DEV_DFU_MODE:
-                               emode = STLINK_MODE_DFU;
-                               break;
-                       case STLINK_DEV_DEBUG_MODE:
-                               emode = STLINK_MODE_DEBUG_SWD;
-                               break;
-                       case STLINK_DEV_SWIM_MODE:
-                               emode = STLINK_MODE_DEBUG_SWIM;
-                               break;
-                       case STLINK_DEV_BOOTLOADER_MODE:
-                       case STLINK_DEV_MASS_MODE:
-                       default:
-                               emode = STLINK_MODE_UNKNOWN;
-                               break;
-               }
+       if (!h)
+               return ERROR_OK;
 
-               if (emode != STLINK_MODE_UNKNOWN)
-                       stlink_usb_mode_leave(handle, emode);
-                       /* do not check return code, it prevent
-                       us from closing jtag_libusb */
+       if (h->usb_backend_priv.fd) {
+               stlink_usb_exit_mode(h);
+               /* do not check return code, it prevent
+               us from closing jtag_libusb */
+               jtag_libusb_close(h->usb_backend_priv.fd);
        }
 
-       if (h && h->fd)
-               jtag_libusb_close(h->fd);
-
-       free(h);
+       free(h->cmdbuf);
+       free(h->databuf);
 
        return ERROR_OK;
 }
 
 /** */
-static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
+static int stlink_tcp_close(void *handle)
 {
-       int err, retry_count = 1;
-       struct stlink_usb_handle_s *h;
+       struct stlink_usb_handle_s *h = handle;
 
-       LOG_DEBUG("stlink_usb_open");
+       if (!h)
+               return ERROR_OK;
 
-       h = calloc(1, sizeof(struct stlink_usb_handle_s));
+       int ret = ERROR_OK;
+       if (h->tcp_backend_priv.connected) {
+               if (h->tcp_backend_priv.connect_id) {
+                       stlink_usb_exit_mode(h);
+
+                       /* close the stlink */
+                       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_CLOSE_DEV;
+                       memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */
+                       h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id);
+                       ret = stlink_tcp_send_cmd(h, 8, 4, true);
+                       if (ret != ERROR_OK)
+                               LOG_ERROR("cannot close the STLINK");
+               }
 
-       if (h == 0) {
-               LOG_DEBUG("malloc failed");
-               return ERROR_FAIL;
+               if (close_socket(h->tcp_backend_priv.fd) != 0)
+                       LOG_ERROR("error closing the socket, errno: %s", strerror(errno));
        }
 
-       h->transport = param->transport;
+       free(h->tcp_backend_priv.send_buf);
+       free(h->tcp_backend_priv.recv_buf);
 
-       for (unsigned i = 0; param->vid[i]; i++) {
-               LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
-                         param->transport, param->vid[i], param->pid[i],
-                         param->serial ? param->serial : "");
+       return ret;
+}
+
+/** */
+static int stlink_close(void *handle)
+{
+       if (handle) {
+               struct stlink_usb_handle_s *h = handle;
+
+               stlink_usb_close(handle);
+
+               free(h);
+       }
+
+       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(struct 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)
+               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_usb_open(void *handle, struct hl_interface_param_s *param)
+{
+       struct stlink_usb_handle_s *h = handle;
+       int err, retry_count = 1;
+
+       h->cmdbuf = malloc(STLINK_SG_SIZE);
+       h->databuf = malloc(STLINK_DATA_SIZE);
+
+       if (!h->cmdbuf || !h->databuf)
+               return ERROR_FAIL;
+
        /*
          On certain host USB configurations(e.g. MacBook Air)
          STLINKv2 dongle seems to have its FW in a funky state if,
@@ -2682,25 +3364,26 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
          in order to become operational.
         */
        do {
-               if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) {
+               if (jtag_libusb_open(param->vid, param->pid, adapter_get_required_serial(),
+                               &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
                        LOG_ERROR("open failed");
-                       goto error_open;
+                       return ERROR_FAIL;
                }
 
-               jtag_libusb_set_configuration(h->fd, 0);
+               jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0);
 
-               if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) {
+               if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) {
                        LOG_DEBUG("claim interface failed");
-                       goto error_open;
+                       return ERROR_FAIL;
                }
 
                /* RX EP is common for all versions */
                h->rx_ep = STLINK_RX_EP;
 
                uint16_t pid;
-               if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) {
+               if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) {
                        LOG_DEBUG("libusb_get_pid failed");
-                       goto error_open;
+                       return ERROR_FAIL;
                }
 
                /* wrap version for first read */
@@ -2713,6 +3396,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
                        case STLINK_V3E_PID:
                        case STLINK_V3S_PID:
                        case STLINK_V3_2VCP_PID:
+                       case STLINK_V3E_NO_MSD_PID:
                                h->version.stlink = 3;
                                h->tx_ep = STLINK_V2_1_TX_EP;
                                h->trace_ep = STLINK_V2_1_TRACE_EP;
@@ -2740,21 +3424,21 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
                } else if (h->version.stlink == 1 ||
                           retry_count == 0) {
                        LOG_ERROR("read version failed");
-                       goto error_open;
+                       return ERROR_FAIL;
                } else {
-                       err = jtag_libusb_release_interface(h->fd, 0);
+                       err = libusb_release_interface(h->usb_backend_priv.fd, 0);
                        if (err != ERROR_OK) {
                                LOG_ERROR("release interface failed");
-                               goto error_open;
+                               return ERROR_FAIL;
                        }
 
-                       err = jtag_libusb_reset_device(h->fd);
+                       err = libusb_reset_device(h->usb_backend_priv.fd);
                        if (err != ERROR_OK) {
                                LOG_ERROR("reset device failed");
-                               goto error_open;
+                               return ERROR_FAIL;
                        }
 
-                       jtag_libusb_close(h->fd);
+                       jtag_libusb_close(h->usb_backend_priv.fd);
                        /*
                          Give the device one second to settle down and
                          reenumerate.
@@ -2764,106 +3448,354 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
                }
        } while (1);
 
-       /* check if mode is supported */
-       err = ERROR_OK;
+       return ERROR_OK;
+}
 
-       switch (h->transport) {
-               case HL_TRANSPORT_SWD:
-                       if (h->version.jtag_api == STLINK_JTAG_API_V1)
-                               err = ERROR_FAIL;
-                       /* fall-through */
-               case HL_TRANSPORT_JTAG:
-                       if (h->version.jtag == 0)
-                               err = ERROR_FAIL;
-                       break;
-               case HL_TRANSPORT_SWIM:
-                       if (h->version.swim == 0)
-                               err = ERROR_FAIL;
-                       break;
-               default:
-                       err = ERROR_FAIL;
-                       break;
-       }
+/** */
+static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param)
+{
+       struct stlink_usb_handle_s *h = handle;
+       int ret;
 
-       if (err != ERROR_OK) {
-               LOG_ERROR("mode (transport) not supported by device");
-               goto error_open;
+       /* 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;
        }
 
-       /* initialize the debug hardware */
-       err = stlink_usb_init_mode(h, param->connect_under_reset);
+       h->tcp_backend_priv.send_buf = malloc(STLINK_TCP_SEND_BUFFER_SIZE);
+       h->tcp_backend_priv.recv_buf = malloc(STLINK_TCP_RECV_BUFFER_SIZE);
 
-       if (err != ERROR_OK) {
-               LOG_ERROR("init mode failed (unable to connect to the target)");
-               goto error_open;
+       if (!h->tcp_backend_priv.send_buf || !h->tcp_backend_priv.recv_buf)
+               return ERROR_FAIL;
+
+       h->cmdbuf = &h->tcp_backend_priv.send_buf[8];
+       h->databuf = &h->tcp_backend_priv.recv_buf[4];
+
+       /* configure directions */
+       h->rx_ep = STLINK_TCP_REQUEST_READ;
+       h->tx_ep = STLINK_TCP_REQUEST_WRITE;
+       h->trace_ep = STLINK_TCP_REQUEST_READ_SWO;
+
+       h->tcp_backend_priv.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       h->tcp_backend_priv.connected = false;
+       h->tcp_backend_priv.device_id = 0;
+       h->tcp_backend_priv.connect_id = 0;
+
+       if (h->tcp_backend_priv.fd == -1) {
+               LOG_ERROR("error creating the socket, errno: %s", strerror(errno));
+               return ERROR_FAIL;
        }
 
-       if (h->transport == HL_TRANSPORT_SWIM) {
-               err = stlink_swim_enter(h);
-               if (err != ERROR_OK) {
-                       LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)");
-                       goto error_open;
-               }
-               *fd = h;
-               h->max_mem_packet = STLINK_DATA_SIZE;
-               return ERROR_OK;
+       struct sockaddr_in serv;
+       memset(&serv, 0, sizeof(struct sockaddr_in));
+       serv.sin_family = AF_INET;
+       serv.sin_port = htons(param->stlink_tcp_port);
+       serv.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+       LOG_DEBUG("socket : %x", h->tcp_backend_priv.fd);
+
+       int optval = 1;
+       if (setsockopt(h->tcp_backend_priv.fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, sizeof(int)) == -1) {
+               LOG_ERROR("cannot set sock option 'TCP_NODELAY', errno: %s", strerror(errno));
+               return ERROR_FAIL;
        }
 
-       if (h->transport == HL_TRANSPORT_JTAG) {
-               if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) {
-                       stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag));
-                       stlink_speed(h, param->initial_interface_speed, false);
+       optval = STLINK_TCP_RECV_BUFFER_SIZE;
+       if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_RCVBUF, (const void *)&optval, sizeof(int)) == -1) {
+               LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       optval = STLINK_TCP_SEND_BUFFER_SIZE;
+       if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_SNDBUF, (const void *)&optval, sizeof(int)) == -1) {
+               LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       if (connect(h->tcp_backend_priv.fd, (const struct sockaddr *)&serv, sizeof(serv)) == -1) {
+               LOG_ERROR("cannot connect to stlink server, errno: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       h->tcp_backend_priv.connected = true;
+
+       LOG_INFO("connected to stlink-server");
+
+       /* print stlink-server version */
+       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION;
+       h->tcp_backend_priv.send_buf[1] = OPENOCD_STLINK_TCP_API_VERSION;
+       memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */
+       ret = stlink_tcp_send_cmd(h, 4, 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(&h->tcp_backend_priv.recv_buf[0]);
+       uint32_t ver_major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+       uint32_t ver_minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]);
+       uint32_t ver_build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]);
+       LOG_INFO("stlink-server API v%d, version %d.%d.%d",
+                       api_ver, ver_major, ver_minor, ver_build);
+
+       /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server
+        * to crash in windows: select a safe default value (1K) */
+       if (api_ver < 2)
+               h->max_mem_packet = (1 << 10);
+
+       /* refresh stlink list (re-enumerate) */
+       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST;
+       h->tcp_backend_priv.send_buf[1] = 0; /* don't clear the list, just refresh it */
+       ret = stlink_tcp_send_cmd(h, 2, 4, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* get the number of connected stlinks */
+       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_NB_DEV;
+       ret = stlink_tcp_send_cmd(h, 1, 4, false);
+       if (ret != ERROR_OK)
+               return ret;
+
+       uint32_t connected_stlinks = le_to_h_u32(h->tcp_backend_priv.recv_buf);
+
+       if (connected_stlinks == 0) {
+               LOG_ERROR("no ST-LINK detected");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("%d ST-LINK detected", connected_stlinks);
+
+       if (connected_stlinks > 255) {
+               LOG_WARNING("STLink server cannot handle more than 255 ST-LINK connected");
+               connected_stlinks = 255;
+       }
+
+       /* list all connected ST-Link and seek for the requested vid:pid and serial */
+       char serial[STLINK_TCP_SERIAL_SIZE + 1] = {0};
+       uint8_t stlink_used;
+       bool stlink_id_matched = false;
+       const char *adapter_serial = adapter_get_required_serial();
+       bool stlink_serial_matched = !adapter_serial;
+
+       for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) {
+               /* get the stlink info */
+               h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_DEV_INFO;
+               h->tcp_backend_priv.send_buf[1] = (uint8_t)stlink_id;
+               memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */
+               h_u32_to_le(&h->tcp_backend_priv.send_buf[4], 41); /* size of TDeviceInfo2 */
+               ret = stlink_tcp_send_cmd(h, 8, 45, true);
+               if (ret != ERROR_OK)
+                       return ret;
+
+               h->tcp_backend_priv.device_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+               memcpy(serial, &h->tcp_backend_priv.recv_buf[8], STLINK_TCP_SERIAL_SIZE);
+               h->vid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[40]);
+               h->pid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[42]);
+               stlink_used = h->tcp_backend_priv.recv_buf[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;
+                       }
                }
-       } else if (h->transport == HL_TRANSPORT_SWD) {
-               if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) {
-                       stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd));
-                       stlink_speed(h, param->initial_interface_speed, false);
+
+               if (!stlink_id_matched)
+                       continue;
+
+               /* check the serial if specified */
+               if (adapter_serial) {
+                       /* ST-Link server fixes the buggy serial returned by old ST-Link DFU
+                        * for further details refer to stlink_usb_get_alternate_serial
+                        * so if the user passes the buggy serial, we need to fix it before
+                        * comparing with the serial returned by ST-Link server */
+                       if (strlen(adapter_serial) == STLINK_SERIAL_LEN / 2) {
+                               char fixed_serial[STLINK_SERIAL_LEN + 1];
+
+                               for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
+                                       sprintf(fixed_serial + i, "%02X", adapter_serial[i / 2]);
+
+                               fixed_serial[STLINK_SERIAL_LEN] = '\0';
+
+                               stlink_serial_matched = strcmp(fixed_serial, serial) == 0;
+                       } else {
+                               stlink_serial_matched = strcmp(adapter_serial, serial) == 0;
+                       }
                }
+
+               if (!stlink_serial_matched)
+                       LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
+                                       serial, adapter_serial);
+               else /* exit the search loop if there is match */
+                       break;
        }
 
-       if (h->version.jtag_api == STLINK_JTAG_API_V3) {
-               struct speed_map map[STLINK_V3_MAX_FREQ_NB];
+       if (!stlink_id_matched) {
+               LOG_ERROR("ST-LINK open failed (vid/pid mismatch)");
+               return ERROR_FAIL;
+       }
 
-               stlink_get_com_freq(h, (h->transport == HL_TRANSPORT_JTAG), map);
-               stlink_dump_speed_map(map, ARRAY_SIZE(map));
-               stlink_speed(h, param->initial_interface_speed, false);
+       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 */
+       h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_OPEN_DEV;
+       memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */
+       h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.device_id);
+       ret = stlink_tcp_send_cmd(h, 8, 8, true);
+       if (ret != ERROR_OK)
+               return ret;
+
+       h->tcp_backend_priv.connect_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+
+       /* get stlink version */
+       return stlink_usb_version(h);
+}
+
+static struct stlink_backend_s stlink_usb_backend = {
+       .open = stlink_usb_usb_open,
+       .close = stlink_usb_usb_close,
+       .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck,
+       .read_trace = stlink_usb_usb_read_trace,
+};
+
+static struct stlink_backend_s stlink_tcp_backend = {
+       .open = stlink_tcp_open,
+       .close = stlink_tcp_close,
+       .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck,
+       .read_trace = stlink_tcp_read_trace,
+};
+
+static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+{
+       struct stlink_usb_handle_s *h;
+
+       LOG_DEBUG("stlink_open");
+
+       h = calloc(1, sizeof(struct stlink_usb_handle_s));
+
+       if (h == 0) {
+               LOG_DEBUG("malloc failed");
+               return ERROR_FAIL;
+       }
+
+       h->st_mode = mode;
+
+       for (unsigned i = 0; param->vid[i]; i++) {
+               LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
+                         h->st_mode, param->vid[i], param->pid[i],
+                         adapter_get_required_serial() ? adapter_get_required_serial() : "");
+       }
+
+       if (param->use_stlink_tcp)
+               h->backend = &stlink_tcp_backend;
+       else
+               h->backend = &stlink_usb_backend;
+
+       if (stlink_usb_open(h, param) != ERROR_OK)
+               goto error_open;
+
+       /* check if mode is supported */
+       int err = ERROR_OK;
+
+       switch (h->st_mode) {
+               case STLINK_MODE_DEBUG_SWD:
+                       if (h->version.jtag_api == STLINK_JTAG_API_V1)
+                               err = ERROR_FAIL;
+                       /* fall-through */
+               case STLINK_MODE_DEBUG_JTAG:
+                       if (h->version.jtag == 0)
+                               err = ERROR_FAIL;
+                       break;
+               case STLINK_MODE_DEBUG_SWIM:
+                       if (h->version.swim == 0)
+                               err = ERROR_FAIL;
+                       break;
+               default:
+                       err = ERROR_FAIL;
+                       break;
+       }
+
+       if (err != ERROR_OK) {
+               LOG_ERROR("mode (transport) not supported by device");
+               goto error_open;
        }
 
-       /* get cpuid, so we can determine the max page size
-        * start with a safe default */
-       h->max_mem_packet = (1 << 10);
+       /* initialize the debug hardware */
+       err = stlink_usb_init_mode(h, param->connect_under_reset, param->initial_interface_speed);
+
+       if (err != ERROR_OK) {
+               LOG_ERROR("init mode failed (unable to connect to the target)");
+               goto error_open;
+       }
 
-       uint8_t buffer[4];
-       err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
-       if (err == ERROR_OK) {
-               uint32_t cpuid = le_to_h_u32(buffer);
-               int i = (cpuid >> 4) & 0xf;
-               if (i == 4 || i == 3) {
-                       /* Cortex-M3/M4 has 4096 bytes autoincrement range */
-                       h->max_mem_packet = (1 << 12);
+       if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
+               err = stlink_swim_enter(h);
+               if (err != ERROR_OK) {
+                       LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)");
+                       goto error_open;
                }
+               *fd = h;
+               h->max_mem_packet = STLINK_SWIM_DATA_SIZE;
+               return ERROR_OK;
        }
 
-       LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet);
+       /* set max_mem_packet if it was not set by the low-level interface */
+       if (h->max_mem_packet == 0) {
+               /* get cpuid, so we can determine the max page size
+                * start with a safe default */
+               h->max_mem_packet = (1 << 10);
+
+               uint8_t buffer[4];
+               stlink_usb_open_ap(h, STLINK_HLA_AP_NUM);
+               err = stlink_usb_read_mem32(h, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, CPUID, 4, buffer);
+               if (err == ERROR_OK) {
+                       uint32_t cpuid = le_to_h_u32(buffer);
+                       int i = (cpuid >> 4) & 0xf;
+                       if (i == 4 || i == 3) {
+                               /* Cortex-M3/M4 has 4096 bytes autoincrement range */
+                               h->max_mem_packet = (1 << 12);
+                       }
+               }
+
+               LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet);
+       }
 
        *fd = h;
 
        return ERROR_OK;
 
 error_open:
-       stlink_usb_close(h);
-
+       stlink_close(h);
        return ERROR_FAIL;
 }
 
-int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
-                       uint32_t port_size, unsigned int *trace_freq)
+static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
+{
+       return stlink_open(param, stlink_get_mode(param->transport), fd);
+}
+
+static int stlink_config_trace(void *handle, bool enabled,
+               enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+               unsigned int *trace_freq, unsigned int traceclkin_freq,
+               uint16_t *prescaler)
 {
        struct stlink_usb_handle_s *h = handle;
 
-       if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
-                       pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
-               LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
+       if (!(h->version.flags & STLINK_F_HAS_TRACE)) {
+               LOG_ERROR("The attached ST-LINK version doesn't support trace");
                return ERROR_FAIL;
        }
 
@@ -2872,27 +3804,193 @@ int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_p
                return ERROR_OK;
        }
 
-       if (*trace_freq > STLINK_TRACE_MAX_HZ) {
+       assert(trace_freq);
+       assert(prescaler);
+
+       if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
+               LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
+               return ERROR_FAIL;
+       }
+
+       unsigned int max_trace_freq = (h->version.stlink == 3) ?
+                       STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ;
+
+       /* Only concern ourselves with the frequency if the STlink is processing it. */
+       if (*trace_freq > max_trace_freq) {
                LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
-                         STLINK_TRACE_MAX_HZ);
+                         max_trace_freq);
+               return ERROR_FAIL;
+       }
+
+       if (!*trace_freq)
+               *trace_freq = max_trace_freq;
+
+       unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq;
+       if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) {
+               LOG_ERROR("SWO frequency is not suitable. Please choose a different "
+                       "frequency.");
+               return ERROR_FAIL;
+       }
+
+       /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */
+       unsigned int max_deviation = (traceclkin_freq * 3) / 100;
+       if (presc * *trace_freq < traceclkin_freq - max_deviation ||
+                       presc * *trace_freq > traceclkin_freq + max_deviation) {
+               LOG_ERROR("SWO frequency is not suitable. Please choose a different "
+                       "frequency.");
                return ERROR_FAIL;
        }
 
+       *prescaler = presc;
+
        stlink_usb_trace_disable(h);
 
-       if (!*trace_freq)
-               *trace_freq = STLINK_TRACE_MAX_HZ;
        h->trace.source_hz = *trace_freq;
 
        return stlink_usb_trace_enable(h);
 }
 
+/** */
+static int stlink_usb_init_access_port(void *handle, unsigned char ap_num)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle);
+
+       if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+               return ERROR_COMMAND_NOTFOUND;
+
+       LOG_DEBUG_IO("init ap_num = %d", ap_num);
+       stlink_usb_init_buffer(handle, h->rx_ep, 16);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+
+       return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
+/** */
+static int stlink_usb_close_access_port(void *handle, unsigned char ap_num)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle);
+
+       if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+               return ERROR_COMMAND_NOTFOUND;
+
+       LOG_DEBUG_IO("close ap_num = %d", ap_num);
+       stlink_usb_init_buffer(handle, h->rx_ep, 16);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG;
+       h->cmdbuf[h->cmdidx++] = ap_num;
+
+       /* ignore incorrectly returned error on bogus FW */
+       if (h->version.flags & STLINK_F_FIX_CLOSE_AP)
+               return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+       else
+               return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2);
+
+}
+
+static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer)
+{
+       struct stlink_usb_handle_s *h = handle;
+       unsigned int buflen = ALIGN_UP(items, 4) + 4 * items;
+
+       LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
+
+       assert(handle != NULL);
+
+       if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, h->tx_ep, buflen);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_OUT;
+       h_u32_to_le(&h->cmdbuf[2], items);
+
+       return stlink_usb_xfer_noerrcheck(handle, buffer, buflen);
+}
+
+static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer)
+{
+       struct stlink_usb_handle_s *h = handle;
+       unsigned int buflen = 2 * 4 * items;
+
+       LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
+
+       assert(handle != NULL);
+
+       if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, h->rx_ep, buflen);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_IN;
+
+       int res = stlink_usb_xfer_noerrcheck(handle, h->databuf, buflen);
+       if (res != ERROR_OK)
+               return res;
+
+       memcpy(buffer, h->databuf, buflen);
+
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_read_dap_register(void *handle, unsigned short dap_port,
+                       unsigned short addr, uint32_t *val)
+{
+       struct stlink_usb_handle_s *h = handle;
+       int retval;
+
+       assert(handle);
+
+       if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, h->rx_ep, 16);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG;
+       h_u16_to_le(&h->cmdbuf[2], dap_port);
+       h_u16_to_le(&h->cmdbuf[4], addr);
+
+       retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8);
+       *val = le_to_h_u32(h->databuf + 4);
+       LOG_DEBUG_IO("dap_port_read = %d, addr =  0x%x, value = 0x%" PRIx32, dap_port, addr, *val);
+       return retval;
+}
+
+/** */
+static int stlink_write_dap_register(void *handle, unsigned short dap_port,
+                       unsigned short addr, uint32_t val)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle);
+
+       if (!(h->version.flags & STLINK_F_HAS_DAP_REG))
+               return ERROR_COMMAND_NOTFOUND;
+
+       LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, val);
+       stlink_usb_init_buffer(handle, h->rx_ep, 16);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG;
+       h_u16_to_le(&h->cmdbuf[2], dap_port);
+       h_u16_to_le(&h->cmdbuf[4], addr);
+       h_u32_to_le(&h->cmdbuf[6], val);
+       return stlink_usb_xfer_errcheck(handle, h->databuf, 2);
+}
+
 /** */
 struct hl_layout_api_s stlink_usb_layout_api = {
        /** */
-       .open = stlink_usb_open,
+       .open = stlink_usb_hl_open,
        /** */
-       .close = stlink_usb_close,
+       .close = stlink_close,
        /** */
        .idcode = stlink_usb_idcode,
        /** */
@@ -2928,3 +4026,1150 @@ struct hl_layout_api_s stlink_usb_layout_api = {
        /** */
        .poll_trace = stlink_usb_trace_read,
 };
+
+/*****************************************************************************
+ * DAP direct interface
+ */
+
+static struct stlink_usb_handle_s *stlink_dap_handle;
+static struct hl_interface_param_s stlink_dap_param;
+static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1);
+static uint32_t last_csw_default[DP_APSEL_MAX + 1];
+static int stlink_dap_error = ERROR_OK;
+
+/** */
+static int stlink_dap_record_error(int error)
+{
+       if (stlink_dap_error == ERROR_OK)
+               stlink_dap_error = error;
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_get_and_clear_error(void)
+{
+       int retval = stlink_dap_error;
+       stlink_dap_error = ERROR_OK;
+       return retval;
+}
+
+static int stlink_dap_get_error(void)
+{
+       return stlink_dap_error;
+}
+
+static int stlink_usb_open_ap(void *handle, unsigned short apsel)
+{
+       struct stlink_usb_handle_s *h = handle;
+       int retval;
+
+       /* nothing to do on old versions */
+       if (!(h->version.flags & STLINK_F_HAS_AP_INIT))
+               return ERROR_OK;
+
+       if (apsel > DP_APSEL_MAX)
+               return ERROR_FAIL;
+
+       if (test_bit(apsel, opened_ap))
+               return ERROR_OK;
+
+       retval = stlink_usb_init_access_port(h, apsel);
+       if (retval != ERROR_OK)
+               return retval;
+
+       LOG_DEBUG("AP %d enabled", apsel);
+       set_bit(apsel, opened_ap);
+       last_csw_default[apsel] = 0;
+       return ERROR_OK;
+}
+
+static int stlink_dap_open_ap(unsigned short apsel)
+{
+       return stlink_usb_open_ap(stlink_dap_handle, apsel);
+}
+
+/** */
+static int stlink_dap_closeall_ap(void)
+{
+       int retval, apsel;
+
+       /* nothing to do on old versions */
+       if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT))
+               return ERROR_OK;
+
+       for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) {
+               if (!test_bit(apsel, opened_ap))
+                       continue;
+               retval = stlink_usb_close_access_port(stlink_dap_handle, apsel);
+               if (retval != ERROR_OK)
+                       return retval;
+               clear_bit(apsel, opened_ap);
+       }
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_reinit_interface(void)
+{
+       int retval;
+
+       /*
+        * On JTAG only, it should be enough to call stlink_usb_reset(). But on
+        * some firmware version it does not work as expected, and there is no
+        * equivalent for SWD.
+        * At least for now, to reset the interface quit from JTAG/SWD mode then
+        * select the mode again.
+        */
+
+       if (!stlink_dap_handle->reconnect_pending) {
+               stlink_dap_handle->reconnect_pending = true;
+               stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode);
+       }
+
+       retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode);
+       if (retval != ERROR_OK)
+               return retval;
+
+       stlink_dap_handle->reconnect_pending = false;
+       /* on new FW, calling mode-leave closes all the opened AP; reopen them! */
+       if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)
+               for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++)
+                       if (test_bit(apsel, opened_ap)) {
+                               clear_bit(apsel, opened_ap);
+                               stlink_dap_open_ap(apsel);
+                       }
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_op_connect(struct adiv5_dap *dap)
+{
+       uint32_t idcode;
+       int retval;
+
+       LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : "");
+
+       /* Check if we should reset srst already when connecting, but not if reconnecting. */
+       if (!dap->do_reconnect) {
+               enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+               if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+                       if (jtag_reset_config & RESET_SRST_NO_GATING)
+                               adapter_assert_reset();
+                       else
+                               LOG_WARNING("\'srst_nogate\' reset_config option is required");
+               }
+       }
+
+       dap->do_reconnect = false;
+       dap_invalidate_cache(dap);
+       for (unsigned int i = 0; i <= DP_APSEL_MAX; i++)
+               last_csw_default[i] = 0;
+
+       retval = dap_dp_init(dap);
+       if (retval != ERROR_OK) {
+               dap->do_reconnect = true;
+               return retval;
+       }
+
+       retval = stlink_usb_idcode(stlink_dap_handle, &idcode);
+       if (retval == ERROR_OK)
+               LOG_INFO("%s %#8.8" PRIx32,
+                       (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR",
+                       idcode);
+       else
+               dap->do_reconnect = true;
+
+       return retval;
+}
+
+/** */
+static int stlink_dap_check_reconnect(struct adiv5_dap *dap)
+{
+       int retval;
+
+       if (!dap->do_reconnect)
+               return ERROR_OK;
+
+       retval = stlink_dap_reinit_interface();
+       if (retval != ERROR_OK)
+               return retval;
+
+       return stlink_dap_op_connect(dap);
+}
+
+/** */
+static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
+{
+       /* Ignore the request */
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data)
+{
+       uint32_t dummy;
+       int retval;
+
+       if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+               if (reg & 0x000000F0) {
+                       LOG_ERROR("Banked DP registers not supported in current STLink FW");
+                       return ERROR_COMMAND_NOTFOUND;
+               }
+
+       data = data ? data : &dummy;
+       if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ
+               && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) {
+               /* Quirk required in JTAG. Read RDBUFF to get the data */
+               retval = stlink_read_dap_register(stlink_dap_handle,
+                                       STLINK_DEBUG_PORT_ACCESS, reg, &dummy);
+               if (retval == ERROR_OK)
+                       retval = stlink_read_dap_register(stlink_dap_handle,
+                                               STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data);
+       } else {
+               retval = stlink_read_dap_register(stlink_dap_handle,
+                                       STLINK_DEBUG_PORT_ACCESS, reg, data);
+       }
+
+       return retval;
+}
+
+/** */
+static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data)
+{
+       int retval;
+
+       if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL))
+               if (reg & 0x000000F0) {
+                       LOG_ERROR("Banked DP registers not supported in current STLink FW");
+                       return ERROR_COMMAND_NOTFOUND;
+               }
+
+       if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) {
+               /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */
+               LOG_DEBUG("Ignoring DPBANKSEL while write SELECT");
+               data &= ~DP_SELECT_DPBANK;
+       }
+
+       /* ST-Link does not like that we set CORUNDETECT */
+       if (reg == DP_CTRL_STAT)
+               data &= ~CORUNDETECT;
+
+       retval = stlink_write_dap_register(stlink_dap_handle,
+                               STLINK_DEBUG_PORT_ACCESS, reg, data);
+       return retval;
+}
+
+/** */
+static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data)
+{
+       struct adiv5_dap *dap = ap->dap;
+       uint32_t dummy;
+       int retval;
+
+       if (reg != AP_REG_IDR) {
+               retval = stlink_dap_open_ap(ap->ap_num);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       data = data ? data : &dummy;
+       retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg,
+                                data);
+       dap->stlink_flush_ap_write = false;
+       return retval;
+}
+
+/** */
+static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data)
+{
+       struct adiv5_dap *dap = ap->dap;
+       int retval;
+
+       retval = stlink_dap_open_ap(ap->ap_num);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg,
+                               data);
+       dap->stlink_flush_ap_write = true;
+       return retval;
+}
+
+/** */
+static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
+{
+       LOG_WARNING("stlink_dap_op_queue_ap_abort()");
+       return ERROR_OK;
+}
+
+#define RW_MISC_CMD_ADDRESS     1
+#define RW_MISC_CMD_WRITE       2
+#define RW_MISC_CMD_READ        3
+#define RW_MISC_CMD_APNUM       5
+
+static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, unsigned int len, unsigned int items)
+{
+       uint8_t buf[2 * 4 * items];
+
+       LOG_DEBUG("Queue: %u commands in %u items", len, items);
+
+       int ap_num = DP_APSEL_INVALID;
+       unsigned int cmd_index = 0;
+       unsigned int val_index = ALIGN_UP(items, 4);
+       for (unsigned int i = 0; i < len; i++) {
+               if (ap_num != q[i].mem_ap.ap->ap_num) {
+                       ap_num = q[i].mem_ap.ap->ap_num;
+                       buf[cmd_index++] = RW_MISC_CMD_APNUM;
+                       h_u32_to_le(&buf[val_index], ap_num);
+                       val_index += 4;
+               }
+
+               switch (q[i].cmd) {
+               case CMD_MEM_AP_READ32:
+                       buf[cmd_index++] = RW_MISC_CMD_READ;
+                       h_u32_to_le(&buf[val_index], q[i].mem_ap.addr);
+                       val_index += 4;
+                       break;
+               case CMD_MEM_AP_WRITE32:
+                       buf[cmd_index++] = RW_MISC_CMD_ADDRESS;
+                       h_u32_to_le(&buf[val_index], q[i].mem_ap.addr);
+                       val_index += 4;
+                       buf[cmd_index++] = RW_MISC_CMD_WRITE;
+                       h_u32_to_le(&buf[val_index], q[i].mem_ap.data);
+                       val_index += 4;
+                       break;
+               default:
+                       /* Not supposed to happen */
+                       return ERROR_FAIL;
+               }
+       }
+       /* pad after last command */
+       while (!IS_ALIGNED(cmd_index, 4))
+               buf[cmd_index++] = 0;
+
+       int retval = stlink_usb_rw_misc_out(handle, items, buf);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stlink_usb_rw_misc_in(handle, items, buf);
+       if (retval != ERROR_OK)
+               return retval;
+
+       ap_num = DP_APSEL_INVALID;
+       val_index = 0;
+       unsigned int err_index = 4 * items;
+       for (unsigned int i = 0; i < len; i++) {
+               uint32_t errcode = le_to_h_u32(&buf[err_index]);
+               if (errcode != STLINK_DEBUG_ERR_OK) {
+                       LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+                       return ERROR_FAIL;
+               }
+               if (ap_num != q[i].mem_ap.ap->ap_num) {
+                       ap_num = q[i].mem_ap.ap->ap_num;
+                       err_index += 4;
+                       val_index += 4;
+                       errcode = le_to_h_u32(&buf[err_index]);
+                       if (errcode != STLINK_DEBUG_ERR_OK) {
+                               LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+                               return ERROR_FAIL;
+                       }
+               }
+
+               if (q[i].cmd == CMD_MEM_AP_READ32) {
+                       *q[i].mem_ap.p_data = le_to_h_u32(&buf[val_index]);
+               } else { /* q[i]->cmd == CMD_MEM_AP_WRITE32 */
+                       err_index += 4;
+                       val_index += 4;
+                       errcode = le_to_h_u32(&buf[err_index]);
+                       if (errcode != STLINK_DEBUG_ERR_OK) {
+                               LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode);
+                               return ERROR_FAIL;
+                       }
+               }
+               err_index += 4;
+               val_index += 4;
+       }
+
+       return ERROR_OK;
+}
+
+static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, unsigned int count)
+{
+       uint32_t bufsize = count * CMD_MEM_AP_2_SIZE(q[0].cmd);
+       uint8_t buf[bufsize];
+       uint8_t ap_num = q[0].mem_ap.ap->ap_num;
+       uint32_t addr = q[0].mem_ap.addr;
+       uint32_t csw = q[0].mem_ap.csw;
+
+       int retval = stlink_dap_open_ap(ap_num);
+       if (retval != ERROR_OK)
+               return retval;
+
+       switch (q[0].cmd) {
+       case CMD_MEM_AP_WRITE8:
+               for (unsigned int i = 0; i < count; i++)
+                       buf[i] = q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 3);
+               return stlink_usb_write_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+       case CMD_MEM_AP_WRITE16:
+               for (unsigned int i = 0; i < count; i++)
+                       h_u16_to_le(&buf[2 * i], q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 2));
+               return stlink_usb_write_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+       case CMD_MEM_AP_WRITE32:
+               for (unsigned int i = 0; i < count; i++)
+                       h_u32_to_le(&buf[4 * i], q[i].mem_ap.data);
+               if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+                       return stlink_usb_write_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+               else
+                       return stlink_usb_write_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+
+       case CMD_MEM_AP_READ8:
+               retval = stlink_usb_read_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+               if (retval == ERROR_OK)
+                       for (unsigned int i = 0; i < count; i++)
+                               *q[i].mem_ap.p_data = buf[i] << 8 * (q[i].mem_ap.addr & 3);
+               return retval;
+
+       case CMD_MEM_AP_READ16:
+               retval = stlink_usb_read_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+               if (retval == ERROR_OK)
+                       for (unsigned int i = 0; i < count; i++)
+                               *q[i].mem_ap.p_data = le_to_h_u16(&buf[2 * i]) << 8 * (q[i].mem_ap.addr & 2);
+               return retval;
+
+       case CMD_MEM_AP_READ32:
+               if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+                       retval = stlink_usb_read_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+               else
+                       retval = stlink_usb_read_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf);
+               if (retval == ERROR_OK)
+                       for (unsigned int i = 0; i < count; i++)
+                               *q[i].mem_ap.p_data = le_to_h_u32(&buf[4 * i]);
+               return retval;
+
+       default:
+               return ERROR_FAIL;
+       };
+}
+
+/* TODO: recover these values with cmd STLINK_DEBUG_APIV2_RW_MISC_GET_MAX (0x53) */
+#define STLINK_V2_RW_MISC_SIZE (64)
+#define STLINK_V3_RW_MISC_SIZE (1227)
+
+static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len,
+               unsigned int *pkt_items)
+{
+       struct stlink_usb_handle_s *h = handle;
+       unsigned int i, items = 0;
+       int ap_num = DP_APSEL_INVALID;
+       unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE;
+
+       if (!(h->version.flags & STLINK_F_HAS_RW_MISC))
+               return 0;
+       /*
+        * RW_MISC sequence doesn't lock the st-link, so are not safe in shared mode.
+        * Don't use it with TCP backend to prevent any issue in case of sharing.
+        * This further degrades the performance, on top of TCP server overhead.
+        */
+       if (h->backend == &stlink_tcp_backend)
+               return 0;
+
+       for (i = 0; i < len; i++) {
+               if (q[i].cmd != CMD_MEM_AP_READ32 && q[i].cmd != CMD_MEM_AP_WRITE32)
+                       break;
+               unsigned int count = 1;
+               if (ap_num != q[i].mem_ap.ap->ap_num) {
+                       count++;
+                       ap_num = q[i].mem_ap.ap->ap_num;
+               }
+               if (q[i].cmd == CMD_MEM_AP_WRITE32)
+                       count++;
+               if (items + count > misc_max_items)
+                       break;
+               items += count;
+       }
+
+       *pkt_items = items;
+
+       return i;
+}
+
+static int stlink_usb_count_buf_rw_queue(const struct dap_queue *q, unsigned int len)
+{
+       uint32_t incr = CMD_MEM_AP_2_SIZE(q[0].cmd);
+       unsigned int len_max;
+
+       if (incr == 1)
+               len_max = stlink_usb_block(stlink_dap_handle);
+       else
+               len_max = STLINK_MAX_RW16_32 / incr;
+
+       /* check for no address increment, 32 bits only */
+       if (len > 1 && incr == 4 && q[0].mem_ap.addr == q[1].mem_ap.addr)
+               incr = 0;
+
+       if (len > len_max)
+               len = len_max;
+
+       for (unsigned int i = 1; i < len; i++)
+               if (q[i].cmd != q[0].cmd ||
+                       q[i].mem_ap.ap != q[0].mem_ap.ap ||
+                       q[i].mem_ap.csw != q[0].mem_ap.csw ||
+                       q[i].mem_ap.addr != q[i - 1].mem_ap.addr + incr)
+                       return i;
+
+       return len;
+}
+
+static int stlink_usb_mem_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *skip)
+{
+       unsigned int count, misc_items = 0;
+       int retval;
+
+       unsigned int count_misc = stlink_usb_count_misc_rw_queue(handle, q, len, &misc_items);
+       unsigned int count_buf = stlink_usb_count_buf_rw_queue(q, len);
+
+       if (count_misc > count_buf) {
+               count = count_misc;
+               retval = stlink_usb_misc_rw_segment(handle, q, count, misc_items);
+       } else {
+               count = count_buf;
+               retval = stlink_usb_buf_rw_segment(handle, q, count_buf);
+       }
+       if (retval != ERROR_OK)
+               return retval;
+
+       *skip = count;
+       return ERROR_OK;
+}
+
+static void stlink_dap_run_internal(struct adiv5_dap *dap)
+{
+       int retval = stlink_dap_check_reconnect(dap);
+       if (retval != ERROR_OK) {
+               stlink_dap_handle->queue_index = 0;
+               stlink_dap_record_error(retval);
+               return;
+       }
+
+       unsigned int i = stlink_dap_handle->queue_index;
+       struct dap_queue *q = &stlink_dap_handle->queue[0];
+
+       while (i && stlink_dap_get_error() == ERROR_OK) {
+               unsigned int skip = 1;
+
+               switch (q->cmd) {
+               case CMD_DP_READ:
+                       retval = stlink_dap_dp_read(q->dp_r.dap, q->dp_r.reg, q->dp_r.p_data);
+                       break;
+               case CMD_DP_WRITE:
+                       retval = stlink_dap_dp_write(q->dp_w.dap, q->dp_w.reg, q->dp_w.data);
+                       break;
+               case CMD_AP_READ:
+                       retval = stlink_dap_ap_read(q->ap_r.ap, q->ap_r.reg, q->ap_r.p_data);
+                       break;
+               case CMD_AP_WRITE:
+                       /* ignore increment packed, not supported */
+                       if (q->ap_w.reg == MEM_AP_REG_CSW)
+                               q->ap_w.data &= ~CSW_ADDRINC_PACKED;
+                       retval = stlink_dap_ap_write(q->ap_w.ap, q->ap_w.reg, q->ap_w.data);
+                       break;
+
+               case CMD_MEM_AP_READ8:
+               case CMD_MEM_AP_READ16:
+               case CMD_MEM_AP_READ32:
+               case CMD_MEM_AP_WRITE8:
+               case CMD_MEM_AP_WRITE16:
+               case CMD_MEM_AP_WRITE32:
+                       retval = stlink_usb_mem_rw_queue(stlink_dap_handle, q, i, &skip);
+                       break;
+
+               default:
+                       LOG_ERROR("ST-Link: Unknown queue command %d", q->cmd);
+                       retval = ERROR_FAIL;
+                       break;
+               }
+               stlink_dap_record_error(retval);
+               q += skip;
+               i -= skip;
+       }
+
+       stlink_dap_handle->queue_index = 0;
+}
+
+/** */
+static int stlink_dap_run_finalize(struct adiv5_dap *dap)
+{
+       uint32_t ctrlstat, pwrmask;
+       int retval, saved_retval;
+
+       /* Here no LOG_DEBUG. This is called continuously! */
+
+       /*
+        * ST-Link returns immediately after a DAP write, without waiting for it
+        * to complete.
+        * Run a dummy read to DP_RDBUFF, as suggested in
+        * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html
+        */
+       if (dap->stlink_flush_ap_write) {
+               dap->stlink_flush_ap_write = false;
+               retval = stlink_dap_dp_read(dap, DP_RDBUFF, NULL);
+               if (retval != ERROR_OK) {
+                       dap->do_reconnect = true;
+                       return retval;
+               }
+       }
+
+       saved_retval = stlink_dap_get_and_clear_error();
+
+       retval = stlink_dap_dp_read(dap, DP_CTRL_STAT, &ctrlstat);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect");
+               dap->do_reconnect = true;
+               return retval;
+       }
+
+       if (ctrlstat & SSTICKYERR) {
+               if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG)
+                       retval = stlink_dap_dp_write(dap, DP_CTRL_STAT,
+                                       ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR));
+               else
+                       retval = stlink_dap_dp_write(dap, DP_ABORT, STKERRCLR);
+               if (retval != ERROR_OK) {
+                       dap->do_reconnect = true;
+                       return retval;
+               }
+       }
+
+       /* check for power lost */
+       pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ);
+       if ((ctrlstat & pwrmask) != pwrmask)
+               dap->do_reconnect = true;
+
+       return saved_retval;
+}
+
+static int stlink_dap_op_queue_run(struct adiv5_dap *dap)
+{
+       stlink_dap_run_internal(dap);
+       return stlink_dap_run_finalize(dap);
+}
+
+/** */
+static void stlink_dap_op_quit(struct adiv5_dap *dap)
+{
+       int retval;
+
+       retval = stlink_dap_closeall_ap();
+       if (retval != ERROR_OK)
+               LOG_ERROR("Error closing APs");
+}
+
+static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned int reg,
+       uint32_t *data)
+{
+       if (stlink_dap_get_error() != ERROR_OK)
+               return ERROR_OK;
+
+       unsigned int i = stlink_dap_handle->queue_index++;
+       struct dap_queue *q = &stlink_dap_handle->queue[i];
+       q->cmd = CMD_DP_READ;
+       q->dp_r.reg = reg;
+       q->dp_r.dap = dap;
+       q->dp_r.p_data = data;
+
+       if (i == MAX_QUEUE_DEPTH - 1)
+               stlink_dap_run_internal(dap);
+
+       return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned int reg,
+       uint32_t data)
+{
+       if (stlink_dap_get_error() != ERROR_OK)
+               return ERROR_OK;
+
+       unsigned int i = stlink_dap_handle->queue_index++;
+       struct dap_queue *q = &stlink_dap_handle->queue[i];
+       q->cmd = CMD_DP_WRITE;
+       q->dp_w.reg = reg;
+       q->dp_w.dap = dap;
+       q->dp_w.data = data;
+
+       if (i == MAX_QUEUE_DEPTH - 1)
+               stlink_dap_run_internal(dap);
+
+       return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg,
+       uint32_t *data)
+{
+       if (stlink_dap_get_error() != ERROR_OK)
+               return ERROR_OK;
+
+       unsigned int i = stlink_dap_handle->queue_index++;
+       struct dap_queue *q = &stlink_dap_handle->queue[i];
+
+       /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_RD_NO_INC
+        * and STLINK_F_HAS_RW_MISC */
+       if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) &&
+                       (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 ||
+                        reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) {
+               /* de-queue previous write-TAR */
+               struct dap_queue *prev_q = q - 1;
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) {
+                       stlink_dap_handle->queue_index = i;
+                       i--;
+                       q = prev_q;
+                       prev_q--;
+               }
+               /* de-queue previous write-CSW if it didn't changed ap->csw_default */
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW &&
+                               !prev_q->ap_w.changes_csw_default) {
+                       stlink_dap_handle->queue_index = i;
+                       q = prev_q;
+               }
+
+               switch (ap->csw_value & CSW_SIZE_MASK) {
+               case CSW_8BIT:
+                       q->cmd = CMD_MEM_AP_READ8;
+                       break;
+               case CSW_16BIT:
+                       q->cmd = CMD_MEM_AP_READ16;
+                       break;
+               case CSW_32BIT:
+                       q->cmd = CMD_MEM_AP_READ32;
+                       break;
+               default:
+                       LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK);
+                       stlink_dap_record_error(ERROR_FAIL);
+                       return ERROR_FAIL;
+               }
+
+               q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+               q->mem_ap.ap = ap;
+               q->mem_ap.p_data = data;
+               q->mem_ap.csw = ap->csw_default;
+
+               /* force TAR and CSW update */
+               ap->tar_valid = false;
+               ap->csw_value = 0;
+       } else {
+               q->cmd = CMD_AP_READ;
+               q->ap_r.reg = reg;
+               q->ap_r.ap = ap;
+               q->ap_r.p_data = data;
+       }
+
+       if (i == MAX_QUEUE_DEPTH - 1)
+               stlink_dap_run_internal(ap->dap);
+
+       return ERROR_OK;
+}
+
+static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg,
+       uint32_t data)
+{
+       if (stlink_dap_get_error() != ERROR_OK)
+               return ERROR_OK;
+
+       unsigned int i = stlink_dap_handle->queue_index++;
+       struct dap_queue *q = &stlink_dap_handle->queue[i];
+
+       /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_WR_NO_INC
+        * and STLINK_F_HAS_RW_MISC */
+       if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) &&
+                       (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 ||
+                        reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) {
+               /* de-queue previous write-TAR */
+               struct dap_queue *prev_q = q - 1;
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) {
+                       stlink_dap_handle->queue_index = i;
+                       i--;
+                       q = prev_q;
+                       prev_q--;
+               }
+               /* de-queue previous write-CSW if it didn't changed ap->csw_default */
+               if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW &&
+                               !prev_q->ap_w.changes_csw_default) {
+                       stlink_dap_handle->queue_index = i;
+                       q = prev_q;
+               }
+
+               switch (ap->csw_value & CSW_SIZE_MASK) {
+               case CSW_8BIT:
+                       q->cmd = CMD_MEM_AP_WRITE8;
+                       break;
+               case CSW_16BIT:
+                       q->cmd = CMD_MEM_AP_WRITE16;
+                       break;
+               case CSW_32BIT:
+                       q->cmd = CMD_MEM_AP_WRITE32;
+                       break;
+               default:
+                       LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK);
+                       stlink_dap_record_error(ERROR_FAIL);
+                       return ERROR_FAIL;
+               }
+
+               q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c));
+               q->mem_ap.ap = ap;
+               q->mem_ap.data = data;
+               q->mem_ap.csw = ap->csw_default;
+
+               /* force TAR and CSW update */
+               ap->tar_valid = false;
+               ap->csw_value = 0;
+       } else {
+               q->cmd = CMD_AP_WRITE;
+               q->ap_w.reg = reg;
+               q->ap_w.ap = ap;
+               q->ap_w.data = data;
+               if (reg == MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap->ap_num]) {
+                       q->ap_w.changes_csw_default = true;
+                       last_csw_default[ap->ap_num] = ap->csw_default;
+               } else {
+                       q->ap_w.changes_csw_default = false;
+               }
+       }
+
+       if (i == MAX_QUEUE_DEPTH - 1)
+               stlink_dap_run_internal(ap->dap);
+
+       return ERROR_OK;
+}
+
+static int stlink_swim_op_srst(void)
+{
+       return stlink_swim_generate_rst(stlink_dap_handle);
+}
+
+static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size,
+                                                                  uint32_t count, uint8_t *buffer)
+{
+       int retval;
+       uint32_t bytes_remaining;
+
+       LOG_DEBUG_IO("read at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+       count *= size;
+
+       while (count) {
+               bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count;
+               retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += bytes_remaining;
+               addr += bytes_remaining;
+               count -= bytes_remaining;
+       }
+
+       return ERROR_OK;
+}
+
+static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size,
+                                                                       uint32_t count, const uint8_t *buffer)
+{
+       int retval;
+       uint32_t bytes_remaining;
+
+       LOG_DEBUG_IO("write at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count);
+       count *= size;
+
+       while (count) {
+               bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count;
+               retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += bytes_remaining;
+               addr += bytes_remaining;
+               count -= bytes_remaining;
+       }
+
+       return ERROR_OK;
+}
+
+static int stlink_swim_op_reconnect(void)
+{
+       int retval;
+
+       retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return stlink_swim_resync(stlink_dap_handle);
+}
+
+static int stlink_dap_config_trace(bool enabled,
+               enum tpiu_pin_protocol pin_protocol, uint32_t port_size,
+               unsigned int *trace_freq, unsigned int traceclkin_freq,
+               uint16_t *prescaler)
+{
+       return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol,
+                                                          port_size, trace_freq, traceclkin_freq,
+                                                          prescaler);
+}
+
+static int stlink_dap_trace_read(uint8_t *buf, size_t *size)
+{
+       return stlink_usb_trace_read(stlink_dap_handle, buf, size);
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_vid_pid)
+{
+       unsigned int i, max_usb_ids = HLA_MAX_USB_IDS;
+
+       if (CMD_ARGC > max_usb_ids * 2) {
+               LOG_WARNING("ignoring extra IDs in vid_pid "
+                       "(maximum is %d pairs)", max_usb_ids);
+               CMD_ARGC = max_usb_ids * 2;
+       }
+       if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
+               LOG_WARNING("incomplete vid_pid configuration directive");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       for (i = 0; i < CMD_ARGC; i += 2) {
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]);
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]);
+       }
+
+       /* null termination */
+       stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0;
+
+       return ERROR_OK;
+}
+
+/** */
+COMMAND_HANDLER(stlink_dap_backend_command)
+{
+       /* default values */
+       bool use_stlink_tcp = false;
+       uint16_t stlink_tcp_port = 7184;
+
+       if (CMD_ARGC == 0 || CMD_ARGC > 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       else if (strcmp(CMD_ARGV[0], "usb") == 0) {
+               if (CMD_ARGC > 1)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               /* else use_stlink_tcp = false (already the case ) */
+       } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
+               use_stlink_tcp = true;
+               if (CMD_ARGC == 2)
+                       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port);
+       } else
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       stlink_dap_param.use_stlink_tcp = use_stlink_tcp;
+       stlink_dap_param.stlink_tcp_port = stlink_tcp_port;
+
+       return ERROR_OK;
+}
+
+#define BYTES_PER_LINE 16
+COMMAND_HANDLER(stlink_dap_cmd_command)
+{
+       unsigned int rx_n, tx_n;
+       struct stlink_usb_handle_s *h = stlink_dap_handle;
+
+       if (CMD_ARGC < 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], rx_n);
+       tx_n = CMD_ARGC - 1;
+       if (tx_n > STLINK_SG_SIZE || rx_n > STLINK_DATA_SIZE) {
+               LOG_ERROR("max %x byte sent and %d received", STLINK_SG_SIZE, STLINK_DATA_SIZE);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       stlink_usb_init_buffer(h, h->rx_ep, rx_n);
+
+       for (unsigned int i = 0; i < tx_n; i++) {
+               uint8_t byte;
+               COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 1], byte);
+               h->cmdbuf[h->cmdidx++] = byte;
+       }
+
+       int retval = stlink_usb_xfer_noerrcheck(h, h->databuf, rx_n);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error %d", retval);
+               return retval;
+       }
+
+       for (unsigned int i = 0; i < rx_n; i++)
+               command_print_sameline(CMD, "0x%02x%c", h->databuf[i],
+                       ((i == (rx_n - 1)) || ((i % BYTES_PER_LINE) == (BYTES_PER_LINE - 1))) ? '\n' : ' ');
+
+       return ERROR_OK;
+}
+
+/** */
+static const struct command_registration stlink_dap_subcommand_handlers[] = {
+       {
+               .name = "vid_pid",
+               .handler = stlink_dap_vid_pid,
+               .mode = COMMAND_CONFIG,
+               .help = "USB VID and PID of the adapter",
+               .usage = "(vid pid)+",
+       },
+       {
+               .name = "backend",
+               .handler = &stlink_dap_backend_command,
+               .mode = COMMAND_CONFIG,
+               .help = "select which ST-Link backend to use",
+               .usage = "usb | tcp [port]",
+       },
+       {
+               .name = "cmd",
+               .handler = stlink_dap_cmd_command,
+               .mode = COMMAND_EXEC,
+               .help = "send arbitrary command",
+               .usage = "rx_n (tx_byte)+",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static const struct command_registration stlink_dap_command_handlers[] = {
+       {
+               .name = "st-link",
+               .mode = COMMAND_ANY,
+               .help = "perform st-link management",
+               .chain = stlink_dap_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+/** */
+static int stlink_dap_init(void)
+{
+       enum reset_types jtag_reset_config = jtag_get_reset_config();
+       enum stlink_mode mode;
+       int retval;
+
+       LOG_DEBUG("stlink_dap_init()");
+
+       if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+               if (jtag_reset_config & RESET_SRST_NO_GATING)
+                       stlink_dap_param.connect_under_reset = true;
+               else
+                       LOG_WARNING("\'srst_nogate\' reset_config option is required");
+       }
+
+       if (transport_is_dapdirect_swd())
+               mode = STLINK_MODE_DEBUG_SWD;
+       else if (transport_is_dapdirect_jtag())
+               mode = STLINK_MODE_DEBUG_JTAG;
+       else if (transport_is_swim())
+               mode = STLINK_MODE_DEBUG_SWIM;
+       else {
+               LOG_ERROR("Unsupported transport");
+               return ERROR_FAIL;
+       }
+
+       retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((mode != STLINK_MODE_DEBUG_SWIM) &&
+               !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) {
+               LOG_ERROR("ST-Link version does not support DAP direct transport");
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_quit(void)
+{
+       LOG_DEBUG("stlink_dap_quit()");
+
+       return stlink_close(stlink_dap_handle);
+}
+
+/** */
+static int stlink_dap_reset(int req_trst, int req_srst)
+{
+       LOG_DEBUG("stlink_dap_reset(%d)", req_srst);
+       return stlink_usb_assert_srst(stlink_dap_handle,
+               req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW
+                                : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH);
+}
+
+/** */
+static int stlink_dap_speed(int speed)
+{
+       if (speed == 0) {
+               LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
+               return ERROR_JTAG_NOT_IMPLEMENTED;
+       }
+
+       stlink_dap_param.initial_interface_speed = speed;
+       stlink_speed(stlink_dap_handle, speed, false);
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_khz(int khz, int *jtag_speed)
+{
+       if (khz == 0) {
+               LOG_ERROR("RCLK not supported");
+               return ERROR_FAIL;
+       }
+
+       *jtag_speed = stlink_speed(stlink_dap_handle, khz, true);
+       return ERROR_OK;
+}
+
+/** */
+static int stlink_dap_speed_div(int speed, int *khz)
+{
+       *khz = speed;
+       return ERROR_OK;
+}
+
+static const struct dap_ops stlink_dap_ops = {
+       .connect = stlink_dap_op_connect,
+       .send_sequence = stlink_dap_op_send_sequence,
+       .queue_dp_read = stlink_dap_op_queue_dp_read,
+       .queue_dp_write = stlink_dap_op_queue_dp_write,
+       .queue_ap_read = stlink_dap_op_queue_ap_read,
+       .queue_ap_write = stlink_dap_op_queue_ap_write,
+       .queue_ap_abort = stlink_dap_op_queue_ap_abort,
+       .run = stlink_dap_op_queue_run,
+       .sync = NULL, /* optional */
+       .quit = stlink_dap_op_quit, /* optional */
+};
+
+static const struct swim_driver stlink_swim_ops = {
+       .srst = stlink_swim_op_srst,
+       .read_mem = stlink_swim_op_read_mem,
+       .write_mem = stlink_swim_op_write_mem,
+       .reconnect = stlink_swim_op_reconnect,
+};
+
+static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL };
+
+struct adapter_driver stlink_dap_adapter_driver = {
+       .name = "st-link",
+       .transports = stlink_dap_transport,
+       .commands = stlink_dap_command_handlers,
+
+       .init = stlink_dap_init,
+       .quit = stlink_dap_quit,
+       .reset = stlink_dap_reset,
+       .speed = stlink_dap_speed,
+       .khz = stlink_dap_khz,
+       .speed_div = stlink_dap_speed_div,
+       .config_trace = stlink_dap_config_trace,
+       .poll_trace = stlink_dap_trace_read,
+
+       .dap_jtag_ops = &stlink_dap_ops,
+       .dap_swd_ops = &stlink_dap_ops,
+       .swim_ops = &stlink_swim_ops,
+};