]> git.sur5r.net Git - openocd/blobdiff - src/jtag/drivers/stlink_usb.c
stlink: fix stlink api2 single step
[openocd] / src / jtag / drivers / stlink_usb.c
index bf146444b21bf74f831854f1d1c6db7b21128be7..708b24b41c8fc00056453dc42dc5e6209b1e1847 100644 (file)
 #include <jtag/stlink/stlink_interface.h>
 #include <target/target.h>
 
+#include <target/cortex_m.h>
+
 #include "libusb_common.h"
 
 #define ENDPOINT_IN    0x80
 #define ENDPOINT_OUT   0x00
 
-#define STLINK_RX_EP   (1|ENDPOINT_IN)
-#define STLINK_TX_EP   (2|ENDPOINT_OUT)
-#define STLINK_CMD_SIZE        (16)
-#define STLINK_TX_SIZE (4*128)
-#define STLINK_RX_SIZE (4*128)
+#define STLINK_NULL_EP         0
+#define STLINK_RX_EP           (1|ENDPOINT_IN)
+#define STLINK_TX_EP           (2|ENDPOINT_OUT)
+#define STLINK_SG_SIZE         (31)
+#define STLINK_DATA_SIZE       (4*128)
+#define STLINK_CMD_SIZE_V2     (16)
+#define STLINK_CMD_SIZE_V1     (10)
 
 enum stlink_jtag_api_version {
-       STLINK_JTAG_API_V1 = 0,
+       STLINK_JTAG_API_V1 = 1,
        STLINK_JTAG_API_V2,
 };
 
@@ -67,9 +71,13 @@ struct stlink_usb_handle_s {
        /** */
        struct libusb_transfer *trans;
        /** */
-       uint8_t txbuf[STLINK_TX_SIZE];
+       uint8_t cmdbuf[STLINK_SG_SIZE];
+       /** */
+       uint8_t cmdidx;
        /** */
-       uint8_t rxbuf[STLINK_RX_SIZE];
+       uint8_t direction;
+       /** */
+       uint8_t databuf[STLINK_DATA_SIZE];
        /** */
        enum stlink_transports transport;
        /** */
@@ -78,14 +86,12 @@ struct stlink_usb_handle_s {
        uint16_t vid;
        /** */
        uint16_t pid;
-       /** */
-       uint32_t sg_tag;
        /** this is the currently used jtag api */
        enum stlink_jtag_api_version jtag_api;
 };
 
-#define STLINK_OK                              0x80
-#define STLINK_FALSE                           0x81
+#define STLINK_DEBUG_ERR_OK                    0x80
+#define STLINK_DEBUG_ERR_FAULT                 0x81
 #define STLINK_CORE_RUNNING                    0x80
 #define STLINK_CORE_HALTED                     0x81
 #define STLINK_CORE_STAT_UNKNOWN               -1
@@ -134,12 +140,21 @@ struct stlink_usb_handle_s {
 #define STLINK_DEBUG_READCOREID                        0x22
 
 #define STLINK_DEBUG_APIV2_ENTER               0x30
-
+#define STLINK_DEBUG_APIV2_READ_IDCODES                0x31
 #define STLINK_DEBUG_APIV2_RESETSYS            0x32
 #define STLINK_DEBUG_APIV2_READREG             0x33
 #define STLINK_DEBUG_APIV2_WRITEREG            0x34
+#define STLINK_DEBUG_APIV2_WRITEDEBUGREG       0x35
+#define STLINK_DEBUG_APIV2_READDEBUGREG        0x36
 
 #define STLINK_DEBUG_APIV2_READALLREGS         0x3A
+#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS     0x3B
+#define STLINK_DEBUG_APIV2_DRIVE_NRST          0x3C
+
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW      0x00
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH     0x01
+#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE    0x02
+
 /** */
 enum stlink_mode {
        STLINK_MODE_UNKNOWN = 0,
@@ -150,57 +165,48 @@ enum stlink_mode {
        STLINK_MODE_DEBUG_SWIM
 };
 
-/** */
-static void stlink_usb_recv_v1_create_cmd(char *b, int s, uint32_t tag, uint32_t rxsize,
-                       uint8_t flag, uint8_t lun, uint8_t length)
-{
-       int i = 0;
-
-       memset(b, 0x00, s);
+#define REQUEST_SENSE          0x03
+#define REQUEST_SENSE_LENGTH   18
 
-       /* fill the send buffer */
-       strcpy(b, "USBC");
-       i += 4;
-
-       buf_set_u32(b+i, 0, 32, tag);
-       i += 4;
-       buf_set_u32(b+i, 0, 32, rxsize);
-       i += 4;
-       b[i++] = flag;
-       b[i++] = lun;
-       b[i++] = length;
-}
+static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
 
 /** */
-static int stlink_usb_recv_v1_mass_storage_cmd(void *handle, const uint8_t *txbuf, int txsize, uint8_t *rxbuf,
-                   int rxsize)
+static int stlink_usb_xfer_v1_get_status(void *handle)
 {
-       char sg_buffer[31];
        struct stlink_usb_handle_s *h;
 
        assert(handle != NULL);
 
        h = (struct stlink_usb_handle_s *)handle;
-       h->sg_tag = (h->sg_tag + 1) & 1;
 
-       stlink_usb_recv_v1_create_cmd(sg_buffer, 31, h->sg_tag, rxsize, STLINK_TX_EP, 0x00, txsize);
+       /* read status */
+       memset(h->cmdbuf, 0, STLINK_SG_SIZE);
+
+       if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)h->cmdbuf,
+                               13, 1000) != 13)
+               return ERROR_FAIL;
 
-       memcpy(sg_buffer+15, txbuf, 10);
+       uint32_t t1;
 
-       if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)sg_buffer, 31,
-                                  1000) != 31) {
-               printf("send failed\n");
+       t1 = buf_get_u32(h->cmdbuf, 0, 32);
+
+       /* check for USBS */
+       if (t1 != 0x53425355)
+               return ERROR_FAIL;
+       /*
+        * CSW status:
+        * 0 success
+        * 1 command failure
+        * 2 phase error
+        */
+       if (h->cmdbuf[12] != 0)
                return ERROR_FAIL;
-       }
 
        return ERROR_OK;
 }
 
-#define REQUEST_SENSE          0x03
-#define REQUEST_SENSE_LENGTH   18
-
 /** */
-static int stlink_usb_recv_v1_get_status(void *handle, char *sg_buffer, int len)
+static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
 {
        struct stlink_usb_handle_s *h;
 
@@ -208,151 +214,161 @@ static int stlink_usb_recv_v1_get_status(void *handle, char *sg_buffer, int len)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       /* read status */
-       memset(sg_buffer, 0x00, len);
-
-       if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)sg_buffer,
-                               len, 1000) != len)
+       if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)h->cmdbuf, cmdsize,
+                                  1000) != cmdsize) {
                return ERROR_FAIL;
+       }
 
-       uint32_t t1, t2;
-
-       t1 = buf_get_u32(sg_buffer+0, 0, 32);
-       t2 = buf_get_u32(sg_buffer+4, 0, 32);
-
-       /* check for USBS */
-       if (t1 != 0x53425355)
-               return ERROR_FAIL;
+       if (h->direction == STLINK_TX_EP && size) {
+               if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)buf,
+                                         size, 1000) != size) {
+                       LOG_DEBUG("bulk write failed");
+                       return ERROR_FAIL;
+               }
+       } else if (h->direction == STLINK_RX_EP && size) {
+               if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)buf,
+                                         size, 1000) != size) {
+                       LOG_DEBUG("bulk read failed");
+                       return ERROR_FAIL;
+               }
+       }
 
        return ERROR_OK;
 }
 
 /** */
-static int stlink_usb_recv_v1_get_sense(void *handle)
+static int stlink_usb_xfer_v1_get_sense(void *handle)
 {
+       int res;
        struct stlink_usb_handle_s *h;
-       char cdb[16];
-       char sg_buffer[31];
 
        assert(handle != NULL);
 
        h = (struct stlink_usb_handle_s *)handle;
-       h->sg_tag = (h->sg_tag + 1) & 1;
-
-       cdb[0] = REQUEST_SENSE;
-       cdb[4] = REQUEST_SENSE_LENGTH;
 
-       stlink_usb_recv_v1_create_cmd(sg_buffer, 31, h->sg_tag, REQUEST_SENSE_LENGTH, STLINK_TX_EP,
-                       0x00, 16);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 16);
 
-       memcpy(sg_buffer+15, cdb, 16);
+       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = 0;
+       h->cmdbuf[h->cmdidx++] = REQUEST_SENSE_LENGTH;
 
-       if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)sg_buffer, 16,
-                                  1000) != 16)
-               return ERROR_FAIL;
+       res = stlink_usb_xfer_rw(handle, REQUEST_SENSE_LENGTH, h->databuf, 16);
 
-       if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)cdb,
-                                 16, 1000) != 16)
-               return ERROR_FAIL;
+       if (res != ERROR_OK)
+               return res;
 
-       if (stlink_usb_recv_v1_get_status(handle, sg_buffer, 13) != ERROR_OK)
+       if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK)
                return ERROR_FAIL;
-       /* check for sense */
-       if (sg_buffer[12] != 0)
-               return ERROR_FAIL;
-
-       /* if (sense[0] != 0x70 && sense[0] != 0x71) */
 
        return ERROR_OK;
 }
 
 /** */
-static int stlink_usb_recv_v1(void *handle, const uint8_t *txbuf, int txsize, uint8_t *rxbuf,
-                   int rxsize)
+static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
 {
-       int err;
-       char sg_buffer[31];
+       int err, cmdsize = STLINK_CMD_SIZE_V2;
        struct stlink_usb_handle_s *h;
 
        assert(handle != NULL);
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       err = stlink_usb_recv_v1_mass_storage_cmd(handle, txbuf, txsize, rxbuf, rxsize);
+       if (h->version.stlink == 1)
+               cmdsize = STLINK_SG_SIZE;
+
+       err = stlink_usb_xfer_rw(handle, cmdsize, buf, size);
 
        if (err != ERROR_OK)
                return err;
 
-       if (rxsize && rxbuf) {
-               if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)rxbuf,
-                                         rxsize, 1000) != rxsize) {
-                       LOG_DEBUG("jtag_libusb_bulk_read");
+       if (h->version.stlink == 1) {
+               if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) {
+                       /* check csw status */
+                       if (h->cmdbuf[12] == 1) {
+                               LOG_DEBUG("get sense");
+                               if (stlink_usb_xfer_v1_get_sense(handle) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       }
                        return ERROR_FAIL;
                }
        }
 
-       if (stlink_usb_recv_v1_get_status(handle, sg_buffer, 13) != ERROR_OK)
-               return ERROR_FAIL;
-       /* check for sense */
-       if (sg_buffer[12] == 1) {
-               LOG_DEBUG("get sense");
-               err = stlink_usb_recv_v1_get_sense(handle);
-       }
-       return err;
+       return ERROR_OK;
 }
 
 /** */
-static int stlink_usb_recv_v2(void *handle, const uint8_t *txbuf, int txsize, uint8_t *rxbuf,
-                   int rxsize)
+static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size)
 {
        struct stlink_usb_handle_s *h;
 
-       assert(handle != NULL);
-
        h = (struct stlink_usb_handle_s *)handle;
 
-       if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)txbuf, txsize,
-                                  1000) != txsize) {
-               return ERROR_FAIL;
-       }
-       if (rxsize && rxbuf) {
-               if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)rxbuf,
-                                         rxsize, 1000) != rxsize) {
-                       return ERROR_FAIL;
-               }
-       }
-       return ERROR_OK;
+       /* fill the send buffer */
+       strcpy((char *)h->cmdbuf, "USBC");
+       h->cmdidx += 4;
+       /* csw tag not used */
+       h->cmdidx += 4;
+       buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size);
+       h->cmdidx += 4;
+       h->cmdbuf[h->cmdidx++] = (direction == STLINK_RX_EP ? ENDPOINT_IN : ENDPOINT_OUT);
+       h->cmdbuf[h->cmdidx++] = 0; /* lun */
+       h->cmdbuf[h->cmdidx++] = STLINK_CMD_SIZE_V1;
 }
 
 /** */
-static int stlink_usb_recv(void *handle, const uint8_t *txbuf, int txsize, uint8_t *rxbuf,
-                   int rxsize)
+static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size)
 {
        struct stlink_usb_handle_s *h;
 
-       assert(handle != NULL);
-
        h = (struct stlink_usb_handle_s *)handle;
 
-       if (h->version.stlink == 1) {
-               return stlink_usb_recv_v1(handle, txbuf, txsize, rxbuf, rxsize);
-       } else {
-               if (txsize < STLINK_CMD_SIZE)
-                       txsize = STLINK_CMD_SIZE;
-               return stlink_usb_recv_v2(handle, txbuf, txsize, rxbuf, rxsize);
-       }
+       h->direction = direction;
+
+       h->cmdidx = 0;
+
+       memset(h->cmdbuf, 0, STLINK_SG_SIZE);
+       memset(h->databuf, 0, STLINK_DATA_SIZE);
+
+       if (h->version.stlink == 1)
+               stlink_usb_xfer_v1_create_cmd(handle, direction, size);
 }
 
+static const char * const stlink_usb_error_msg[] = {
+       "unknown"
+};
+
 /** */
-static void stlink_usb_init_buffer(void *handle)
+static int stlink_usb_error_check(void *handle)
 {
+       int res;
+       const char *err_msg = 0;
        struct stlink_usb_handle_s *h;
 
        assert(handle != NULL);
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       memset(h->txbuf, 0, STLINK_CMD_SIZE);
+       /* TODO: no error checking yet on api V1 */
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               h->databuf[0] = STLINK_DEBUG_ERR_OK;
+
+       switch (h->databuf[0]) {
+               case STLINK_DEBUG_ERR_OK:
+                       res = ERROR_OK;
+                       break;
+               case STLINK_DEBUG_ERR_FAULT:
+               default:
+                       err_msg = stlink_usb_error_msg[0];
+                       res = ERROR_FAIL;
+                       break;
+       }
+
+       if (res != ERROR_OK)
+               LOG_DEBUG("status error: %d ('%s')", h->databuf[0], err_msg);
+
+       return res;
 }
 
 /** */
@@ -366,33 +382,32 @@ static int stlink_usb_version(void *handle)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 6);
 
-       h->txbuf[0] = STLINK_GET_VERSION;
+       h->cmdbuf[h->cmdidx++] = STLINK_GET_VERSION;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 6);
+       res = stlink_usb_xfer(handle, h->databuf, 6);
 
        if (res != ERROR_OK)
                return res;
 
-       v = (h->rxbuf[0] << 8) | h->rxbuf[1];
+       v = (h->databuf[0] << 8) | h->databuf[1];
 
        h->version.stlink = (v >> 12) & 0x0f;
        h->version.jtag = (v >> 6) & 0x3f;
        h->version.swim = v & 0x3f;
-       h->vid = buf_get_u32(h->rxbuf, 16, 16);
-       h->pid = buf_get_u32(h->rxbuf, 32, 16);
+       h->vid = buf_get_u32(h->databuf, 16, 16);
+       h->pid = buf_get_u32(h->databuf, 32, 16);
 
        /* set the supported jtag api version
-        * V1 doesn't support API V2 at all
-        * V2 support API V2 since JTAG V13
+        * API V2 is supported since JTAG V11
         */
-       if ((h->version.stlink == 2) && (h->version.jtag > 12))
+       if (h->version.jtag >= 11)
                h->version.jtag_api_max = STLINK_JTAG_API_V2;
        else
                h->version.jtag_api_max = STLINK_JTAG_API_V1;
 
-       LOG_DEBUG("STLINK v%d JTAG v%d API v%d SWIM v%d VID %04X PID %04X",
+       LOG_DEBUG("STLINK v%d JTAG v%d API v%d SWIM v%d VID 0x%04X PID 0x%04X",
                h->version.stlink,
                h->version.jtag,
                (h->version.jtag_api_max == STLINK_JTAG_API_V1) ? 1 : 2,
@@ -413,16 +428,16 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_GET_CURRENT_MODE;
+       h->cmdbuf[h->cmdidx++] = STLINK_GET_CURRENT_MODE;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       *mode = h->rxbuf[0];
+       *mode = h->databuf[0];
 
        return ERROR_OK;
 }
@@ -431,34 +446,42 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode)
 static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
 {
        int res;
+       int rx_size = 0;
        struct stlink_usb_handle_s *h;
 
        assert(handle != NULL);
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       /* on api V2 we are able the read the latest command
+        * status
+        * TODO: we need the test on api V1 too
+        */
+       if (h->jtag_api == STLINK_JTAG_API_V2)
+               rx_size = 2;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, rx_size);
 
        switch (type) {
                case STLINK_MODE_DEBUG_JTAG:
-                       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
                        if (h->jtag_api == STLINK_JTAG_API_V1)
-                               h->txbuf[1] = STLINK_DEBUG_APIV1_ENTER;
+                               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER;
                        else
-                               h->txbuf[1] = STLINK_DEBUG_APIV2_ENTER;
-                       h->txbuf[2] = STLINK_DEBUG_ENTER_JTAG;
+                               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG;
                        break;
                case STLINK_MODE_DEBUG_SWD:
-                       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
                        if (h->jtag_api == STLINK_JTAG_API_V1)
-                               h->txbuf[1] = STLINK_DEBUG_APIV1_ENTER;
+                               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER;
                        else
-                               h->txbuf[1] = STLINK_DEBUG_APIV2_ENTER;
-                       h->txbuf[2] = STLINK_DEBUG_ENTER_SWD;
+                               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD;
                        break;
                case STLINK_MODE_DEBUG_SWIM:
-                       h->txbuf[0] = STLINK_SWIM_COMMAND;
-                       h->txbuf[1] = STLINK_SWIM_ENTER;
+                       h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER;
                        break;
                case STLINK_MODE_DFU:
                case STLINK_MODE_MASS:
@@ -466,11 +489,14 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
                        return ERROR_FAIL;
        }
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
+       res = stlink_usb_xfer(handle, h->databuf, rx_size);
+
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       res = stlink_usb_error_check(h);
+
+       return res;
 }
 
 /** */
@@ -483,28 +509,29 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0);
 
        switch (type) {
                case STLINK_MODE_DEBUG_JTAG:
                case STLINK_MODE_DEBUG_SWD:
-                       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-                       h->txbuf[1] = STLINK_DEBUG_EXIT;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT;
                        break;
                case STLINK_MODE_DEBUG_SWIM:
-                       h->txbuf[0] = STLINK_SWIM_COMMAND;
-                       h->txbuf[1] = STLINK_SWIM_EXIT;
+                       h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT;
                        break;
                case STLINK_MODE_DFU:
-                       h->txbuf[0] = STLINK_DFU_COMMAND;
-                       h->txbuf[1] = STLINK_DFU_EXIT;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND;
+                       h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT;
                        break;
                case STLINK_MODE_MASS:
                default:
                        return ERROR_FAIL;
        }
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
+       res = stlink_usb_xfer(handle, 0, 0);
+
        if (res != ERROR_OK)
                return res;
 
@@ -528,7 +555,7 @@ static int stlink_usb_init_mode(void *handle)
        if (res != ERROR_OK)
                return res;
 
-       LOG_DEBUG("MODE: %02X", mode);
+       LOG_DEBUG("MODE: 0x%02X", mode);
 
        /* try to exit current mode */
        switch (mode) {
@@ -542,6 +569,7 @@ static int stlink_usb_init_mode(void *handle)
                        emode = STLINK_MODE_DEBUG_SWIM;
                        break;
                case STLINK_DEV_BOOTLOADER_MODE:
+               case STLINK_DEV_MASS_MODE:
                default:
                        emode = STLINK_MODE_UNKNOWN;
                        break;
@@ -559,7 +587,7 @@ static int stlink_usb_init_mode(void *handle)
        if (res != ERROR_OK)
                return res;
 
-       LOG_DEBUG("MODE: %02X", mode);
+       LOG_DEBUG("MODE: 0x%02X", mode);
 
        /* set selected mode */
        switch (h->transport) {
@@ -592,7 +620,7 @@ static int stlink_usb_init_mode(void *handle)
        if (res != ERROR_OK)
                return res;
 
-       LOG_DEBUG("MODE: %02X", mode);
+       LOG_DEBUG("MODE: 0x%02X", mode);
 
        return ERROR_OK;
 }
@@ -607,23 +635,95 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 4);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_READCOREID;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READCOREID;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 4);
+       res = stlink_usb_xfer(handle, h->databuf, 4);
 
        if (res != ERROR_OK)
                return res;
 
-       *idcode = le_to_h_u32(h->rxbuf);
+       *idcode = le_to_h_u32(h->databuf);
 
-       LOG_DEBUG("IDCODE: %08X", *idcode);
+       LOG_DEBUG("IDCODE: 0x%08X", *idcode);
 
        return ERROR_OK;
 }
 
+static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val)
+{
+       struct stlink_usb_handle_s *h;
+       int res;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 8);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READDEBUGREG;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+
+       res = stlink_usb_xfer(handle, h->databuf, 8);
+
+       if (res != ERROR_OK)
+               return res;
+
+       *val = le_to_h_u32(h->databuf + 4);
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEDEBUGREG;
+       else
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, val);
+       h->cmdidx += 4;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static enum target_state stlink_usb_v2_get_status(void *handle)
+{
+       int result;
+       uint32_t status;
+
+       result = stlink_usb_v2_read_debug_reg(handle, DCB_DHCSR, &status);
+       if  (result != ERROR_OK)
+               return TARGET_UNKNOWN;
+
+       if (status & S_HALT)
+               return TARGET_HALTED;
+       else if (status & S_RESET_ST)
+               return TARGET_RESET;
+
+       return TARGET_RUNNING;
+}
+
 /** */
 static enum target_state stlink_usb_state(void *handle)
 {
@@ -635,21 +735,21 @@ static enum target_state stlink_usb_state(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return TARGET_UNKNOWN;
+               return stlink_usb_v2_get_status(handle);
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_GETSTATUS;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_GETSTATUS;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return TARGET_UNKNOWN;
 
-       if (h->rxbuf[0] == STLINK_CORE_RUNNING)
+       if (h->databuf[0] == STLINK_CORE_RUNNING)
                return TARGET_RUNNING;
-       if (h->rxbuf[0] == STLINK_CORE_HALTED)
+       if (h->databuf[0] == STLINK_CORE_HALTED)
                return TARGET_HALTED;
 
        return TARGET_UNKNOWN;
@@ -665,23 +765,49 @@ static int stlink_usb_reset(void *handle)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
 
        if (h->jtag_api == STLINK_JTAG_API_V1)
-               h->txbuf[1] = STLINK_DEBUG_APIV1_RESETSYS;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS;
        else
-               h->txbuf[1] = STLINK_DEBUG_APIV2_RESETSYS;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       LOG_DEBUG("RESET: %08X", h->rxbuf[0]);
+       LOG_DEBUG("RESET: 0x%08X", h->databuf[0]);
 
-       return ERROR_OK;
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static int stlink_usb_assert_srst(void *handle, int srst)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_DRIVE_NRST;
+       h->cmdbuf[h->cmdidx++] = srst;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
 /** */
@@ -695,19 +821,19 @@ static int stlink_usb_run(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_RUNCORE;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_RUNCORE;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
 /** */
@@ -721,19 +847,19 @@ static int stlink_usb_halt(void *handle)
        h = (struct stlink_usb_handle_s *)handle;
 
        if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_FORCEDEBUG;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_FORCEDEBUG;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
 /** */
@@ -746,20 +872,25 @@ static int stlink_usb_step(void *handle)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       if (h->jtag_api == STLINK_JTAG_API_V2)
-               return ERROR_FAIL;
+       if (h->jtag_api == STLINK_JTAG_API_V2) {
+               /* TODO: this emulates the v1 api, it should really use a similar auto mask isr
+                * that the cortex-m3 currently does. */
+               stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_MASKINTS|C_DEBUGEN);
+               stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_STEP|C_MASKINTS|C_DEBUGEN);
+               return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
+       }
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_STEPCORE;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_STEPCORE;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
 }
 
 /** */
@@ -772,15 +903,15 @@ static int stlink_usb_read_regs(void *handle)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 84);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        if (h->jtag_api == STLINK_JTAG_API_V1)
-               h->txbuf[1] = STLINK_DEBUG_APIV1_READALLREGS;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READALLREGS;
        else
-               h->txbuf[1] = STLINK_DEBUG_APIV2_READALLREGS;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READALLREGS;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 84);
+       res = stlink_usb_xfer(handle, h->databuf, 84);
 
        if (res != ERROR_OK)
                return res;
@@ -798,21 +929,26 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        if (h->jtag_api == STLINK_JTAG_API_V1)
-               h->txbuf[1] = STLINK_DEBUG_APIV1_READREG;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG;
        else
-               h->txbuf[1] = STLINK_DEBUG_APIV2_READREG;
-       h->txbuf[2] = num;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
+       h->cmdbuf[h->cmdidx++] = num;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 4);
+       res = stlink_usb_xfer(handle, h->databuf, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
 
        if (res != ERROR_OK)
                return res;
 
-       *val = le_to_h_u32(h->rxbuf);
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               *val = le_to_h_u32(h->databuf);
+       else {
+               *val = le_to_h_u32(h->databuf + 4);
+               return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+       }
 
        return ERROR_OK;
 }
@@ -827,22 +963,48 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
        if (h->jtag_api == STLINK_JTAG_API_V1)
-               h->txbuf[1] = STLINK_DEBUG_APIV1_WRITEREG;
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG;
        else
-               h->txbuf[1] = STLINK_DEBUG_APIV2_WRITEREG;
-       h->txbuf[2] = num;
-       h_u32_to_le(h->txbuf + 3, val);
+               h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG;
+       h->cmdbuf[h->cmdidx++] = num;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, val);
+       h->cmdidx += 4;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, 2);
+       res = stlink_usb_xfer(handle, h->databuf, 2);
 
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
+}
+
+static int stlink_usb_get_rw_status(void *handle)
+{
+       int res;
+       struct stlink_usb_handle_s *h;
+
+       assert(handle != NULL);
+
+       h = (struct stlink_usb_handle_s *)handle;
+
+       if (h->jtag_api == STLINK_JTAG_API_V1)
+               return ERROR_OK;
+
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS;
+
+       res = stlink_usb_xfer(handle, h->databuf, 2);
+
+       if (res != ERROR_OK)
+               return res;
+
+       return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : res;
 }
 
 /** */
@@ -857,25 +1019,27 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, read_len);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_READMEM_8BIT;
-       h_u32_to_le(h->txbuf + 2, addr);
-       h_u16_to_le(h->txbuf + 2 + 4, len);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_8BIT;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf+h->cmdidx, len);
+       h->cmdidx += 2;
 
        /* we need to fix read length for single bytes */
        if (read_len == 1)
                read_len++;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, read_len);
+       res = stlink_usb_xfer(handle, h->databuf, read_len);
 
        if (res != ERROR_OK)
                return res;
 
-       memcpy(buffer, h->rxbuf, len);
+       memcpy(buffer, h->databuf, len);
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -889,29 +1053,26 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
+       stlink_usb_init_buffer(handle, STLINK_TX_EP, len);
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_WRITEMEM_8BIT;
-       h_u32_to_le(h->txbuf + 2, addr);
-       h_u16_to_le(h->txbuf + 2 + 4, len);
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_8BIT;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf+h->cmdidx, len);
+       h->cmdidx += 2;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
+       res = stlink_usb_xfer(handle, buffer, len);
 
        if (res != ERROR_OK)
                return res;
 
-       res = stlink_usb_recv(handle, (uint8_t *) buffer, len, 0, 0);
-
-       if (res != ERROR_OK)
-               return res;
-
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
 static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
-                         uint32_t *buffer)
+                         uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h;
@@ -920,28 +1081,30 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
-
        len *= 4;
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_READMEM_32BIT;
-       h_u32_to_le(h->txbuf + 2, addr);
-       h_u16_to_le(h->txbuf + 2 + 4, len);
+       stlink_usb_init_buffer(handle, STLINK_RX_EP, len);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf+h->cmdidx, len);
+       h->cmdidx += 2;
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, h->rxbuf, len);
+       res = stlink_usb_xfer(handle, h->databuf, len);
 
        if (res != ERROR_OK)
                return res;
 
-       memcpy(buffer, h->rxbuf, len);
+       memcpy(buffer, h->databuf, len);
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
 static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
-                          const uint32_t *buffer)
+                          const uint8_t *buffer)
 {
        int res;
        struct stlink_usb_handle_s *h;
@@ -950,26 +1113,23 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
 
        h = (struct stlink_usb_handle_s *)handle;
 
-       stlink_usb_init_buffer(handle);
-
        len *= 4;
 
-       h->txbuf[0] = STLINK_DEBUG_COMMAND;
-       h->txbuf[1] = STLINK_DEBUG_WRITEMEM_32BIT;
-       h_u32_to_le(h->txbuf + 2, addr);
-       h_u16_to_le(h->txbuf + 2 + 4, len);
+       stlink_usb_init_buffer(handle, STLINK_TX_EP, len);
 
-       res = stlink_usb_recv(handle, h->txbuf, STLINK_CMD_SIZE, 0, 0);
-
-       if (res != ERROR_OK)
-               return res;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT;
+       h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
+       h->cmdidx += 4;
+       h_u16_to_le(h->cmdbuf+h->cmdidx, len);
+       h->cmdidx += 2;
 
-       res = stlink_usb_recv(handle, (uint8_t *) buffer, len, 0, 0);
+       res = stlink_usb_xfer(handle, buffer, len);
 
        if (res != ERROR_OK)
                return res;
 
-       return ERROR_OK;
+       return stlink_usb_get_rw_status(handle);
 }
 
 /** */
@@ -977,6 +1137,7 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
 {
        int err;
        struct stlink_usb_handle_s *h;
+       enum stlink_jtag_api_version api;
 
        LOG_DEBUG("stlink_usb_open");
 
@@ -992,7 +1153,7 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
        const uint16_t vids[] = { param->vid, 0 };
        const uint16_t pids[] = { param->pid, 0 };
 
-       LOG_DEBUG("transport: %d vid: %04x pid: %04x", param->transport,
+       LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
                param->vid, param->pid);
 
        if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) {
@@ -1029,7 +1190,7 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
 
        /* compare usb vid/pid */
        if ((param->vid != h->vid) || (param->pid != h->pid))
-               LOG_INFO("vid/pid are not identical: %04X/%04X %04X/%04X",
+               LOG_INFO("vid/pid are not identical: 0x%04X/0x%04X 0x%04X/0x%04X",
                        param->vid, param->pid,
                        h->vid, h->pid);
 
@@ -1058,8 +1219,17 @@ static int stlink_usb_open(struct stlink_interface_param_s *param, void **fd)
                return err;
        }
 
-       /* set the used jtag api */
-       h->jtag_api = STLINK_JTAG_API_V1;
+       api = h->version.jtag_api_max;
+
+       /* check that user has not requested certain api version
+        * and if they have check it is supported */
+       if ((param->api != 0) && (param->api <= h->version.jtag_api_max)) {
+               api = param->api;
+               LOG_INFO("using stlink api v%d", api);
+       }
+
+       /* set the used jtag api, this will default to the newest supported version */
+       h->jtag_api = api;
 
        /* initialize the debug hardware */
        err = stlink_usb_init_mode(h);
@@ -1095,6 +1265,8 @@ struct stlink_layout_api_s stlink_usb_layout_api = {
        /** */
        .reset = stlink_usb_reset,
        /** */
+       .assert_srst = stlink_usb_assert_srst,
+       /** */
        .run = stlink_usb_run,
        /** */
        .halt = stlink_usb_halt,
@@ -1114,4 +1286,6 @@ struct stlink_layout_api_s stlink_usb_layout_api = {
        .read_mem32 = stlink_usb_read_mem32,
        /** */
        .write_mem32 = stlink_usb_write_mem32,
+       /** */
+       .write_debug_reg = stlink_usb_write_debug_reg
 };