Align loader to 32-bit boundary
[fw/stlink] / src / stlink-sg.c
index fd10c16ebad757ed3e82aac037b41b3303172d67..03df7d85468f09b0356222d84beb21031d013191 100644 (file)
@@ -1,77 +1,77 @@
 /*
- Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
-
- A linux stlink access demo. The purpose of this file is to mitigate the usual
- "reinventing the wheel" force by incompatible licenses and give you an idea,
- how to access the stlink device. That doesn't mean you should be a free-loader
- and not contribute your improvements to this code.
-
- Author: Martin Capitanio <m@capitanio.org>
- The stlink related constants kindly provided by Oliver Spencer (OpenOCD)
- for use in a GPL compatible license.
-
- Tested compatibility: linux, gcc >= 4.3.3
-
- The communication is based on standard USB mass storage device
- BOT (Bulk Only Transfer)
- - Endpoint 1: BULK_IN, 64 bytes max
- - Endpoint 2: BULK_OUT, 64 bytes max
-
- All CBW transfers are ordered with the LSB (byte 0) first (little endian).
- Any command must be answered before sending the next command.
- Each USB transfer must complete in less than 1s.
-
- SB Device Class Definition for Mass Storage Devices:
- www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
-
dt            - Data Transfer (IN/OUT)
CBW           - Command Block Wrapper
CSW           - Command Status Wrapper
RFU           - Reserved for Future Use
-
- Originally, this driver used scsi pass through commands, which required the
- usb-storage module to be loaded, providing the /dev/sgX links.  The USB mass
- storage implementation on the STLinkv1 is however terribly broken, and it can 
- take many minutes for the kernel to give up.
- However, in Nov 2011, the scsi pass through was replaced by raw libusb, so 
- instead of having to let usb-storage struggle with the device, and also greatly 
- limiting the portability of the driver, you can now tell usb-storage to simply
- ignore this device completely.
-   
- usb-storage.quirks
- http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt
- Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product
- ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding
- to a common usb-storage quirk flag as follows:
-
- a = SANE_SENSE (collect more than 18 bytes of sense data);
- b = BAD_SENSE (don't collect more than 18 bytes of sense data);
- c = FIX_CAPACITY (decrease the reported device capacity by one sector);
- h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd);
- i = IGNORE_DEVICE (don't bind to this device);
- l = NOT_LOCKABLE (don't try to lock and unlock ejectable media);
- m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time);
- o = CAPACITY_OK (accept the capacity reported by the device);
- r = IGNORE_RESIDUE (the device reports bogus residue values);
- s = SINGLE_LUN (the device has only one Logical Unit);
- w = NO_WP_DETECT (don't test whether the medium is write-protected).
-
- Example: quirks=0419:aaf5:rl,0421:0433:rc
- http://permalink.gmane.org/gmane.linux.usb.general/35053
- For the stlinkv1, you just want the following
-
- modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
-
- Equivalently, you can add a line saying
-
- options usb-storage quirks=483:3744:i
-
- to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..."
- part to an existing options line for usb-storage).
Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
+ *
A linux stlink access demo. The purpose of this file is to mitigate the usual
"reinventing the wheel" force by incompatible licenses and give you an idea,
how to access the stlink device. That doesn't mean you should be a free-loader
and not contribute your improvements to this code.
+ *
Author: Martin Capitanio <m@capitanio.org>
The stlink related constants kindly provided by Oliver Spencer (OpenOCD)
for use in a GPL compatible license.
+ *
Tested compatibility: linux, gcc >= 4.3.3
+ *
The communication is based on standard USB mass storage device
BOT (Bulk Only Transfer)
- Endpoint 1: BULK_IN, 64 bytes max
- Endpoint 2: BULK_OUT, 64 bytes max
+ *
All CBW transfers are ordered with the LSB (byte 0) first (little endian).
Any command must be answered before sending the next command.
Each USB transfer must complete in less than 1s.
+ *
SB Device Class Definition for Mass Storage Devices:
www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
+ *
* dt          - Data Transfer (IN/OUT)
* CBW                 - Command Block Wrapper
* CSW         - Command Status Wrapper
* RFU         - Reserved for Future Use
+ *
Originally, this driver used scsi pass through commands, which required the
usb-storage module to be loaded, providing the /dev/sgX links.  The USB mass
+ * storage implementation on the STLinkv1 is however terribly broken, and it can
take many minutes for the kernel to give up.
+ *
+ * However, in Nov 2011, the scsi pass through was replaced by raw libusb, so
+ * instead of having to let usb-storage struggle with the device, and also greatly
limiting the portability of the driver, you can now tell usb-storage to simply
ignore this device completely.
+ *
usb-storage.quirks
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt
Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product
ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding
to a common usb-storage quirk flag as follows:
+ *
a = SANE_SENSE (collect more than 18 bytes of sense data);
b = BAD_SENSE (don't collect more than 18 bytes of sense data);
c = FIX_CAPACITY (decrease the reported device capacity by one sector);
h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd);
i = IGNORE_DEVICE (don't bind to this device);
l = NOT_LOCKABLE (don't try to lock and unlock ejectable media);
m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time);
o = CAPACITY_OK (accept the capacity reported by the device);
r = IGNORE_RESIDUE (the device reports bogus residue values);
s = SINGLE_LUN (the device has only one Logical Unit);
w = NO_WP_DETECT (don't test whether the medium is write-protected).
+ *
Example: quirks=0419:aaf5:rl,0421:0433:rc
http://permalink.gmane.org/gmane.linux.usb.general/35053
+ *
For the stlinkv1, you just want the following
+ *
modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
+ *
Equivalently, you can add a line saying
+ *
options usb-storage quirks=483:3744:i
+ *
to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..."
*         part to an existing options line for usb-storage).
  */
 
 
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
-#include <stdarg.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
 
 #include "stlink-common.h"
 #include "stlink-sg.h"
 #include "uglylogging.h"
 
-#define LOG_TAG __FILE__
-#define DLOG(format, args...)         ugly_log(UDEBUG, LOG_TAG, format, ## args)
-#define ILOG(format, args...)         ugly_log(UINFO, LOG_TAG, format, ## args)
-#define WLOG(format, args...)         ugly_log(UWARN, LOG_TAG, format, ## args)
-#define fatal(format, args...)        ugly_log(UFATAL, LOG_TAG, format, ## args)
-
-// Suspends execution of the calling process for
-// (at least) ms milliseconds.
-
-static void delay(int ms) {
-    //fprintf(stderr, "*** wait %d ms\n", ms);
-    usleep(1000 * ms);
-}
-
 static void clear_cdb(struct stlink_libsg *sl) {
     for (size_t i = 0; i < sizeof (sl->cdb_cmd_blk); i++)
         sl->cdb_cmd_blk[i] = 0;
@@ -113,15 +94,16 @@ static void clear_cdb(struct stlink_libsg *sl) {
     sl->q_data_dir = Q_DATA_IN;
 }
 
-// close the device, free the allocated memory
-
+/**
+ * Close and free any _backend_ related information...
+ * @param sl
+ */
 void _stlink_sg_close(stlink_t *sl) {
     if (sl) {
-#if FINISHED_WITH_SG
         struct stlink_libsg *slsg = sl->backend_data;
-        scsi_pt_close_device(slsg->sg_fd);
+        libusb_close(slsg->usb_handle);
+        libusb_exit(slsg->libusb_ctx);
         free(slsg);
-#endif
     }
 }
 
@@ -134,33 +116,31 @@ static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t end
     int try = 0;
     do {
         ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw),
-                                   &transferred, SG_TIMEOUT_MSEC);
+                &transferred, SG_TIMEOUT_MSEC);
         if (ret == LIBUSB_ERROR_PIPE) {
             libusb_clear_halt(handle, endpoint);
         }
         try++;
     } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3));
     if (ret != LIBUSB_SUCCESS) {
-        fprintf(stderr, "%s: receiving failed: %d\n", __func__, ret);
+        WLOG("%s: receiving failed: %d\n", __func__, ret);
         return -1;
     }
     if (transferred != sizeof(csw)) {
-        fprintf(stderr, "%s: received unexpected amount: %d\n", __func__, transferred);
+        WLOG("%s: received unexpected amount: %d\n", __func__, transferred);
         return -1;
     }
 
     uint32_t rsig = read_uint32(csw, 0);
     uint32_t rtag = read_uint32(csw, 4);
-    uint32_t residue = read_uint32(csw, 8);
+    /* uint32_t residue = read_uint32(csw, 8); */
 #define USB_CSW_SIGNATURE 0x53425355  // 'U' 'S' 'B' 'S' (reversed)
     if (rsig != USB_CSW_SIGNATURE) {
         WLOG("status signature was invalid: %#x\n", rsig);
         return -1;
     }
-    DLOG("residue was= %#x\n", residue);
     *tag = rtag;
     uint8_t rstatus = csw[12];
-    DLOG("rstatus = %x\n", rstatus);
     return rstatus;
 }
 
@@ -185,11 +165,11 @@ static int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
  * @param lun
  * @param flags
  * @param expected_rx_size
- * @return 
+ * @return
  */
 int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out,
-                              uint8_t *cdb, uint8_t cdb_length,
-                              uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
+        uint8_t *cdb, uint8_t cdb_length,
+        uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
     DLOG("Sending usb m-s cmd: cdblen:%d, rxsize=%d\n", cdb_length, expected_rx_size);
     dump_CDB_command(cdb, cdb_length);
 
@@ -221,15 +201,13 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
     // Now the actual CDB request
     assert(cdb_length <= CDB_SL);
     memcpy(&(c_buf[i]), cdb, cdb_length);
-    
+
     int sending_length = STLINK_SG_SIZE;
-    DLOG("sending length set to: %d\n", sending_length);
-    
+
     // send....
     do {
-        DLOG("attempting tx...\n");
         ret = libusb_bulk_transfer(handle, endpoint_out, c_buf, sending_length,
-                                   &real_transferred, SG_TIMEOUT_MSEC);
+                &real_transferred, SG_TIMEOUT_MSEC);
         if (ret == LIBUSB_ERROR_PIPE) {
             libusb_clear_halt(handle, endpoint_out);
         }
@@ -239,7 +217,6 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
         WLOG("sending failed: %d\n", ret);
         return -1;
     }
-    DLOG("Actually sent: %d, returning tag: %d\n", real_transferred, tag);
     return this_tag;
 }
 
@@ -250,7 +227,7 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
  * @param endpoint_in
  * @param endpoint_out
  */
-static void
+    static void
 get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out)
 {
     DLOG("Fetching sense...\n");
@@ -261,7 +238,7 @@ get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_ou
     cdb[0] = REQUEST_SENSE;
     cdb[4] = REQUEST_SENSE_LENGTH;
     uint32_t tag = send_usb_mass_storage_command(handle, endpoint_out, cdb, sizeof(cdb), 0,
-                                                 LIBUSB_ENDPOINT_IN, REQUEST_SENSE_LENGTH);
+            LIBUSB_ENDPOINT_IN, REQUEST_SENSE_LENGTH);
     if (tag == 0) {
         WLOG("refusing to send request sense with tag 0\n");
         return;
@@ -272,7 +249,7 @@ get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_ou
     int try = 0;
     do {
         ret = libusb_bulk_transfer(handle, endpoint_in, sense, sizeof(sense),
-                                   &transferred, SG_TIMEOUT_MSEC);
+                &transferred, SG_TIMEOUT_MSEC);
         if (ret == LIBUSB_ERROR_PIPE) {
             libusb_clear_halt(handle, endpoint_in);
         }
@@ -298,112 +275,24 @@ get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_ou
     }
 }
 
-
-//TODO rewrite/cleanup, save the error in sl
-
-#if FINISHED_WITH_SG
-static void stlink_confirm_inq(stlink_t *stl, struct sg_pt_base *ptvp) {
-    struct stlink_libsg *sl = stl->backend_data;
-    const int e = sl->do_scsi_pt_err;
-    if (e < 0) {
-        fprintf(stderr, "scsi_pt error: pass through os error: %s\n",
-                safe_strerror(-e));
-        return;
-    } else if (e == SCSI_PT_DO_BAD_PARAMS) {
-        fprintf(stderr, "scsi_pt error: bad pass through setup\n");
-        return;
-    } else if (e == SCSI_PT_DO_TIMEOUT) {
-        fprintf(stderr, "  pass through timeout\n");
-        return;
-    }
-    const int duration = get_scsi_pt_duration_ms(ptvp);
-    if ((stl->verbose > 1) && (duration >= 0))
-        DLOG("      duration=%d ms\n", duration);
-
-    // XXX stlink fw sends broken residue, so ignore it and use the known q_len
-    // "usb-storage quirks=483:3744:r"
-    // forces residue to be ignored and calculated, but this causes aboard if
-    // data_len = 0 and by some other data_len values.
-
-    const int resid = get_scsi_pt_resid(ptvp);
-    const int dsize = stl->q_len - resid;
-
-    const int cat = get_scsi_pt_result_category(ptvp);
-    char buf[512];
-    unsigned int slen;
-
-    switch (cat) {
-        case SCSI_PT_RESULT_GOOD:
-            if (stl->verbose && (resid > 0))
-                DLOG("      notice: requested %d bytes but "
-                    "got %d bytes, ignore [broken] residue = %d\n",
-                    stl->q_len, dsize, resid);
-            break;
-        case SCSI_PT_RESULT_STATUS:
-            if (stl->verbose) {
-                sg_get_scsi_status_str(
-                        get_scsi_pt_status_response(ptvp), sizeof (buf),
-                        buf);
-                DLOG("  scsi status: %s\n", buf);
-            }
-            return;
-        case SCSI_PT_RESULT_SENSE:
-            slen = get_scsi_pt_sense_len(ptvp);
-            if (stl->verbose) {
-                sg_get_sense_str("", sl->sense_buf, slen, (stl->verbose
-                        > 1), sizeof (buf), buf);
-                DLOG("%s", buf);
-            }
-            if (stl->verbose && (resid > 0)) {
-                if ((stl->verbose) || (stl->q_len > 0))
-                    DLOG("    requested %d bytes but "
-                        "got %d bytes\n", stl->q_len, dsize);
-            }
-            return;
-        case SCSI_PT_RESULT_TRANSPORT_ERR:
-            if (stl->verbose) {
-                get_scsi_pt_transport_err_str(ptvp, sizeof (buf), buf);
-                // http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html
-                // These codes potentially come from the firmware on a host adapter
-                // or from one of several hosts that an adapter driver controls.
-                // The 'host_status' field has the following values:
-                //     [0x07] Internal error detected in the host adapter.
-                // This may not be fatal (and the command may have succeeded).
-                DLOG("  transport: %s", buf);
-            }
-            return;
-        case SCSI_PT_RESULT_OS_ERR:
-            if (stl->verbose) {
-                get_scsi_pt_os_err_str(ptvp, sizeof (buf), buf);
-                DLOG("  os: %s", buf);
-            }
-            return;
-        default:
-            fprintf(stderr, "  unknown pass through result "
-                    "category (%d)\n", cat);
-    }
-}
-#endif
-
 /**
  * Just send a buffer on an endpoint, no questions asked.
  * Handles repeats, and time outs.  Also handles reading status reports and sense
  * @param handle libusb device *
- * @param endpoint_out sends 
- * @param endpoint_in used to read status reports back in 
+ * @param endpoint_out sends
+ * @param endpoint_in used to read status reports back in
  * @param cbuf  what to send
  * @param length how much to send
  * @return number of bytes actually sent, or -1 for failures.
  */
 int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
-    unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) {
+        unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) {
     int ret;
     int real_transferred;
-    int try;
+    int try = 0;
     do {
-        DLOG("attempting tx...\n");
         ret = libusb_bulk_transfer(handle, endpoint_out, cbuf, length,
-                                   &real_transferred, SG_TIMEOUT_MSEC);
+                &real_transferred, SG_TIMEOUT_MSEC);
         if (ret == LIBUSB_ERROR_PIPE) {
             libusb_clear_halt(handle, endpoint_out);
         }
@@ -413,8 +302,7 @@ int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
         WLOG("sending failed: %d\n", ret);
         return -1;
     }
-    DLOG("Actually sent: %d\n", real_transferred);
-    
+
     // now, swallow up the status, so that things behave nicely...
     uint32_t received_tag;
     // -ve is for my errors, 0 is good, +ve is libusb sense status bytes
@@ -430,7 +318,7 @@ int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
         get_sense(handle, endpoint_in, endpoint_out);
         return -1;
     }
-    
+
     return real_transferred;
 }
 
@@ -440,10 +328,10 @@ int stlink_q(stlink_t *sl) {
     //uint8_t cdb_len = 6;  // FIXME varies!!!
     uint8_t cdb_len = 10;  // FIXME varies!!!
     uint8_t lun = 0;  // always zero...
-    uint32_t tag = send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, 
-        sg->cdb_cmd_blk, cdb_len, lun, LIBUSB_ENDPOINT_IN, sl->q_len);
-    
-    
+    uint32_t tag = send_usb_mass_storage_command(sg->usb_handle, sg->ep_req,
+            sg->cdb_cmd_blk, cdb_len, lun, LIBUSB_ENDPOINT_IN, sl->q_len);
+
+
     // now wait for our response...
     // length copied from stlink-usb...
     int rx_length = sl->q_len;
@@ -452,9 +340,8 @@ int stlink_q(stlink_t *sl) {
     int ret;
     if (rx_length > 0) {
         do {
-            DLOG("attempting rx\n");
-            ret = libusb_bulk_transfer(sg->usb_handle, sg->ep_rep, sl->q_buf, rx_length, 
-                &real_transferred, SG_TIMEOUT_MSEC);
+            ret = libusb_bulk_transfer(sg->usb_handle, sg->ep_rep, sl->q_buf, rx_length,
+                    &real_transferred, SG_TIMEOUT_MSEC);
             if (ret == LIBUSB_ERROR_PIPE) {
                 libusb_clear_halt(sg->usb_handle, sg->ep_req);
             }
@@ -493,40 +380,6 @@ int stlink_q(stlink_t *sl) {
         return -1;
     }
     return 0;
-
-        
-    DLOG("Actually received: %d\n", real_transferred);
-
-#if FINISHED_WITH_SG
-    // Get control command descriptor of scsi structure,
-    // (one object per command!!)
-    struct sg_pt_base *ptvp = construct_scsi_pt_obj();
-    if (NULL == ptvp) {
-        fprintf(stderr, "construct_scsi_pt_obj: out of memory\n");
-        return;
-    }
-
-    set_scsi_pt_cdb(ptvp, sg->cdb_cmd_blk, sizeof (sg->cdb_cmd_blk));
-
-    // set buffer for sense (error information) data
-    set_scsi_pt_sense(ptvp, sg->sense_buf, sizeof (sg->sense_buf));
-
-    // Set a buffer to be used for data transferred from device
-    if (sg->q_data_dir == Q_DATA_IN) {
-        //clear_buf(sl);
-        set_scsi_pt_data_in(ptvp, sl->q_buf, sl->q_len);
-    } else {
-        set_scsi_pt_data_out(ptvp, sl->q_buf, sl->q_len);
-    }
-    // Executes SCSI command (or at least forwards it to lower layers).
-    sg->do_scsi_pt_err = do_scsi_pt(ptvp, sg->sg_fd, SG_TIMEOUT_SEC,
-            sl->verbose);
-
-    // check for scsi errors
-    stlink_confirm_inq(sl, ptvp);
-    // TODO recycle: clear_scsi_pt_obj(struct sg_pt_base * objp);
-    destruct_scsi_pt_obj(ptvp);
-#endif
 }
 
 // TODO thinking, cleanup
@@ -538,28 +391,25 @@ void stlink_stat(stlink_t *stl, char *txt) {
     stlink_print_data(stl);
 
     switch (stl->q_buf[0]) {
-        case STLINK_OK:
-            DLOG("  %s: ok\n", txt);
-            return;
-        case STLINK_FALSE:
-            DLOG("  %s: false\n", txt);
-            return;
-        default:
-            DLOG("  %s: unknown\n", txt);
+    case STLINK_OK:
+        DLOG("  %s: ok\n", txt);
+        return;
+    case STLINK_FALSE:
+        DLOG("  %s: false\n", txt);
+        return;
+    default:
+        DLOG("  %s: unknown\n", txt);
     }
 }
 
 
-void _stlink_sg_version(stlink_t *stl) {
+int _stlink_sg_version(stlink_t *stl) {
     struct stlink_libsg *sl = stl->backend_data;
-    DLOG("\n*** stlink_version ***\n");
     clear_cdb(sl);
     sl->cdb_cmd_blk[0] = STLINK_GET_VERSION;
     stl->q_len = 6;
     sl->q_addr = 0;
-    stlink_q(stl);
-    // HACK use my own private version right now...
-    
+    return stlink_q(stl);
 }
 
 // Get stlink mode:
@@ -572,150 +422,180 @@ int _stlink_sg_current_mode(stlink_t *stl) {
     sl->cdb_cmd_blk[0] = STLINK_GET_CURRENT_MODE;
     stl->q_len = 2;
     sl->q_addr = 0;
-    stlink_q(stl);
+    if (stlink_q(stl))
+        return -1;
+
     return stl->q_buf[0];
 }
 
 // Exit the mass mode and enter the swd debug mode.
 
-void _stlink_sg_enter_swd_mode(stlink_t *sl) {
+int _stlink_sg_enter_swd_mode(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_ENTER;
     sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_SWD;
     sl->q_len = 0; // >0 -> aboard
-    stlink_q(sl);
+    return stlink_q(sl);
 }
 
 // Exit the mass mode and enter the jtag debug mode.
 // (jtag is disabled in the discovery's stlink firmware)
 
-void _stlink_sg_enter_jtag_mode(stlink_t *sl) {
+int _stlink_sg_enter_jtag_mode(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
     DLOG("\n*** stlink_enter_jtag_mode ***\n");
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_ENTER;
     sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG;
     sl->q_len = 0;
-    stlink_q(sl);
+    return stlink_q(sl);
 }
 
 // XXX kernel driver performs reset, the device temporally disappears
-
-void _stlink_sg_exit_dfu_mode(stlink_t *sl) {
+// Suspect this is no longer the case when we have ignore on? RECHECK
+int _stlink_sg_exit_dfu_mode(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
     DLOG("\n*** stlink_exit_dfu_mode ***\n");
     clear_cdb(sg);
     sg->cdb_cmd_blk[0] = STLINK_DFU_COMMAND;
     sg->cdb_cmd_blk[1] = STLINK_DFU_EXIT;
     sl->q_len = 0; // ??
-    stlink_q(sl);
+    return stlink_q(sl);
     /*
-     [135121.844564] sd 19:0:0:0: [sdb] Unhandled error code
-     [135121.844569] sd 19:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
-     [135121.844574] sd 19:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 10 00 00 00 08 00
-     [135121.844584] end_request: I/O error, dev sdb, sector 4096
-     [135121.844590] Buffer I/O error on device sdb, logical block 512
-     [135130.122567] usb 6-1: reset full speed USB device using uhci_hcd and address 7
-     [135130.274551] usb 6-1: device firmware changed
-     [135130.274618] usb 6-1: USB disconnect, address 7
-     [135130.275186] VFS: busy inodes on changed media or resized disk sdb
-     [135130.275424] VFS: busy inodes on changed media or resized disk sdb
-     [135130.286758] VFS: busy inodes on changed media or resized disk sdb
-     [135130.292796] VFS: busy inodes on changed media or resized disk sdb
-     [135130.301481] VFS: busy inodes on changed media or resized disk sdb
-     [135130.304316] VFS: busy inodes on changed media or resized disk sdb
-     [135130.431113] usb 6-1: new full speed USB device using uhci_hcd and address 8
-     [135130.629444] usb-storage 6-1:1.0: Quirks match for vid 0483 pid 3744: 102a1
-     [135130.629492] scsi20 : usb-storage 6-1:1.0
-     [135131.625600] scsi 20:0:0:0: Direct-Access     STM32                          PQ: 0 ANSI: 0
-     [135131.627010] sd 20:0:0:0: Attached scsi generic sg2 type 0
-     [135131.633603] sd 20:0:0:0: [sdb] 64000 512-byte logical blocks: (32.7 MB/31.2 MiB)
-     [135131.633613] sd 20:0:0:0: [sdb] Assuming Write Enabled
-     [135131.633620] sd 20:0:0:0: [sdb] Assuming drive cache: write through
-     [135131.640584] sd 20:0:0:0: [sdb] Assuming Write Enabled
-     [135131.640592] sd 20:0:0:0: [sdb] Assuming drive cache: write through
-     [135131.640609]  sdb:
-     [135131.652634] sd 20:0:0:0: [sdb] Assuming Write Enabled
-     [135131.652639] sd 20:0:0:0: [sdb] Assuming drive cache: write through
-     [135131.652645] sd 20:0:0:0: [sdb] Attached SCSI removable disk
-     [135131.671536] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
-     [135131.671548] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current]
-     [135131.671553] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range
-     [135131.671560] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00
-     [135131.671570] end_request: I/O error, dev sdb, sector 63872
-     [135131.671575] Buffer I/O error on device sdb, logical block 7984
-     [135131.678527] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
-     [135131.678532] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current]
-     [135131.678537] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range
-     [135131.678542] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00
-     [135131.678551] end_request: I/O error, dev sdb, sector 63872
-     ...
-     [135131.853565] end_request: I/O error, dev sdb, sector 4096
-     */
+       [135121.844564] sd 19:0:0:0: [sdb] Unhandled error code
+       [135121.844569] sd 19:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
+       [135121.844574] sd 19:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 10 00 00 00 08 00
+       [135121.844584] end_request: I/O error, dev sdb, sector 4096
+       [135121.844590] Buffer I/O error on device sdb, logical block 512
+       [135130.122567] usb 6-1: reset full speed USB device using uhci_hcd and address 7
+       [135130.274551] usb 6-1: device firmware changed
+       [135130.274618] usb 6-1: USB disconnect, address 7
+       [135130.275186] VFS: busy inodes on changed media or resized disk sdb
+       [135130.275424] VFS: busy inodes on changed media or resized disk sdb
+       [135130.286758] VFS: busy inodes on changed media or resized disk sdb
+       [135130.292796] VFS: busy inodes on changed media or resized disk sdb
+       [135130.301481] VFS: busy inodes on changed media or resized disk sdb
+       [135130.304316] VFS: busy inodes on changed media or resized disk sdb
+       [135130.431113] usb 6-1: new full speed USB device using uhci_hcd and address 8
+       [135130.629444] usb-storage 6-1:1.0: Quirks match for vid 0483 pid 3744: 102a1
+       [135130.629492] scsi20 : usb-storage 6-1:1.0
+       [135131.625600] scsi 20:0:0:0: Direct-Access     STM32                          PQ: 0 ANSI: 0
+       [135131.627010] sd 20:0:0:0: Attached scsi generic sg2 type 0
+       [135131.633603] sd 20:0:0:0: [sdb] 64000 512-byte logical blocks: (32.7 MB/31.2 MiB)
+       [135131.633613] sd 20:0:0:0: [sdb] Assuming Write Enabled
+       [135131.633620] sd 20:0:0:0: [sdb] Assuming drive cache: write through
+       [135131.640584] sd 20:0:0:0: [sdb] Assuming Write Enabled
+       [135131.640592] sd 20:0:0:0: [sdb] Assuming drive cache: write through
+       [135131.640609]  sdb:
+       [135131.652634] sd 20:0:0:0: [sdb] Assuming Write Enabled
+       [135131.652639] sd 20:0:0:0: [sdb] Assuming drive cache: write through
+       [135131.652645] sd 20:0:0:0: [sdb] Attached SCSI removable disk
+       [135131.671536] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
+       [135131.671548] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current]
+       [135131.671553] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range
+       [135131.671560] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00
+       [135131.671570] end_request: I/O error, dev sdb, sector 63872
+       [135131.671575] Buffer I/O error on device sdb, logical block 7984
+       [135131.678527] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
+       [135131.678532] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current]
+       [135131.678537] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range
+       [135131.678542] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00
+       [135131.678551] end_request: I/O error, dev sdb, sector 63872
+       ...
+       [135131.853565] end_request: I/O error, dev sdb, sector 4096
+       */
 }
 
-void _stlink_sg_core_id(stlink_t *sl) {
+int _stlink_sg_core_id(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
+    int ret;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_READCOREID;
     sl->q_len = 4;
     sg->q_addr = 0;
-    stlink_q(sl);
+    ret = stlink_q(sl);
+    if (ret)
+        return ret;
+
     sl->core_id = read_uint32(sl->q_buf, 0);
+    return 0;
 }
 
 // Arm-core reset -> halted state.
 
-void _stlink_sg_reset(stlink_t *sl) {
+int _stlink_sg_reset(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_RESETSYS;
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_stat(sl, "core reset");
+    return 0;
+}
+
+// Arm-core reset -> halted state.
+
+int _stlink_sg_jtag_reset(stlink_t *sl, int value) {
+    struct stlink_libsg *sg = sl->backend_data;
+    clear_cdb(sg);
+    sg->cdb_cmd_blk[1] = STLINK_JTAG_DRIVE_NRST;
+    sg->cdb_cmd_blk[2] = (value)?0:1;
+    sl->q_len = 3;
+    sg->q_addr = 2;
+    if (stlink_q(sl))
+        return -1;
+
+    stlink_stat(sl, "core reset");
+
+    return 0;
 }
 
 // Arm-core status: halted or running.
 
-void _stlink_sg_status(stlink_t *sl) {
+int _stlink_sg_status(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
-    DLOG("\n*** stlink_status ***\n");
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_GETSTATUS;
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    return stlink_q(sl);
 }
 
 // Force the core into the debug mode -> halted state.
 
-void _stlink_sg_force_debug(stlink_t *sl) {
+int _stlink_sg_force_debug(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
-    DLOG("\n*** stlink_force_debug ***\n");
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_FORCEDEBUG;
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_stat(sl, "force debug");
+    return 0;
 }
 
 // Read all arm-core registers.
 
-void _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) {
+int _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) {
     struct stlink_libsg *sg = sl->backend_data;
 
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_READALLREGS;
     sl->q_len = 84;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_print_data(sl);
 
     // TODO - most of this should be re-extracted up....
-    
+
     // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71   | 72-75      | 76-79 | 80-83
     // r0  | r1  | ... | r15   | xpsr  | main_sp | process_sp | rw    | rw2
     for (int i = 0; i < 16; i++) {
@@ -729,27 +609,31 @@ void _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) {
     regp->rw = read_uint32(sl->q_buf, 76);
     regp->rw2 = read_uint32(sl->q_buf, 80);
     if (sl->verbose < 2)
-        return;
+        return 0;
 
     DLOG("xpsr       = 0x%08x\n", regp->xpsr);
     DLOG("main_sp    = 0x%08x\n", regp->main_sp);
     DLOG("process_sp = 0x%08x\n", regp->process_sp);
     DLOG("rw         = 0x%08x\n", regp->rw);
     DLOG("rw2        = 0x%08x\n", regp->rw2);
+
+    return 0;
 }
 
 // Read an arm-core register, the index must be in the range 0..20.
 //  0  |  1  | ... |  15   |  16   |   17    |   18       |  19   |  20
 // r0  | r1  | ... | r15   | xpsr  | main_sp | process_sp | rw    | rw2
 
-void _stlink_sg_read_reg(stlink_t *sl, int r_idx, reg *regp) {
+int _stlink_sg_read_reg(stlink_t *sl, int r_idx, reg *regp) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_READREG;
     sg->cdb_cmd_blk[2] = r_idx;
     sl->q_len = 4;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     //  0  |  1  | ... |  15   |  16   |   17    |   18       |  19   |  20
     // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71   | 72-75      | 76-79 | 80-83
     // r0  | r1  | ... | r15   | xpsr  | main_sp | process_sp | rw    | rw2
@@ -759,31 +643,33 @@ void _stlink_sg_read_reg(stlink_t *sl, int r_idx, reg *regp) {
     DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r);
 
     switch (r_idx) {
-        case 16:
-            regp->xpsr = r;
-            break;
-        case 17:
-            regp->main_sp = r;
-            break;
-        case 18:
-            regp->process_sp = r;
-            break;
-        case 19:
-            regp->rw = r; //XXX ?(primask, basemask etc.)
-            break;
-        case 20:
-            regp->rw2 = r; //XXX ?(primask, basemask etc.)
-            break;
-        default:
-            regp->r[r_idx] = r;
+    case 16:
+        regp->xpsr = r;
+        break;
+    case 17:
+        regp->main_sp = r;
+        break;
+    case 18:
+        regp->process_sp = r;
+        break;
+    case 19:
+        regp->rw = r; //XXX ?(primask, basemask etc.)
+        break;
+    case 20:
+        regp->rw2 = r; //XXX ?(primask, basemask etc.)
+        break;
+    default:
+        regp->r[r_idx] = r;
     }
+
+    return 0;
 }
 
 // Write an arm-core register. Index:
 //  0  |  1  | ... |  15   |  16   |   17    |   18       |  19   |  20
 // r0  | r1  | ... | r15   | xpsr  | main_sp | process_sp | rw    | rw2
 
-void _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+int _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEREG;
@@ -793,8 +679,11 @@ void _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
     write_uint32(sg->cdb_cmd_blk + 3, reg);
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_stat(sl, "write reg");
+    return 0;
 }
 
 // Write a register of the debug module of the core.
@@ -818,27 +707,33 @@ void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr) {
 
 // Force the core exit the debug mode.
 
-void _stlink_sg_run(stlink_t *sl) {
+int _stlink_sg_run(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
-    DLOG("\n*** stlink_run ***\n");
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_RUNCORE;
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_stat(sl, "run core");
+
+    return 0;
 }
 
 // Step the arm-core.
 
-void _stlink_sg_step(stlink_t *sl) {
+int _stlink_sg_step(stlink_t *sl) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_STEPCORE;
     sl->q_len = 2;
     sg->q_addr = 0;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_stat(sl, "step core");
+    return 0;
 }
 
 // TODO test
@@ -878,7 +773,7 @@ void stlink_clr_hw_bp(stlink_t *sl, int fp_nr) {
 
 // Read a "len" bytes to the sl->q_buf from the memory, max 6kB (6144 bytes)
 
-void _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     struct stlink_libsg *sg = sl->backend_data;
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_READMEM_32BIT;
@@ -894,14 +789,19 @@ void _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     //     (broken residue issue)
     sl->q_len = len;
     sg->q_addr = addr;
-    stlink_q(sl);
+    if (stlink_q(sl))
+        return -1;
+
     stlink_print_data(sl);
+    return 0;
 }
 
 // Write a "len" bytes from the sl->q_buf to the memory, max 64 Bytes.
 
-void _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+int _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
     struct stlink_libsg *sg = sl->backend_data;
+    int ret;
+
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_8BIT;
     // 2-5: addr
@@ -910,16 +810,27 @@ void _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
     write_uint16(sg->cdb_cmd_blk + 6, len);
 
     // this sends the command...
-    send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
+    ret = send_usb_mass_storage_command(sg->usb_handle,
+            sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
+    if (ret == -1)
+        return ret;
+
     // This sends the data...
-    send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len);
+    ret = send_usb_data_only(sg->usb_handle,
+            sg->ep_req, sg->ep_rep, sl->q_buf, len);
+    if (ret == -1)
+        return ret;
+
     stlink_print_data(sl);
+    return 0;
 }
 
 // Write a "len" bytes from the sl->q_buf to the memory, max Q_BUF_LEN bytes.
 
-void _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     struct stlink_libsg *sg = sl->backend_data;
+    int ret;
+
     clear_cdb(sg);
     sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_32BIT;
     // 2-5: addr
@@ -928,57 +839,63 @@ void _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     write_uint16(sg->cdb_cmd_blk + 6, len);
 
     // this sends the command...
-    send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
+    ret = send_usb_mass_storage_command(sg->usb_handle,
+            sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
+    if (ret == -1)
+        return ret;
+
     // This sends the data...
-    send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len);
+    ret = send_usb_data_only(sg->usb_handle,
+            sg->ep_req, sg->ep_rep, sl->q_buf, len);
+    if (ret == -1)
+        return ret;
 
     stlink_print_data(sl);
+    return 0;
 }
 
-#if 0 /* not working */
-
-static int write_flash_mem16
-(struct stlink* sl, uint32_t addr, uint16_t val) {
-    /* half word writes */
-    if (addr % 2) return -1;
+// Write one DWORD data to memory
 
-    /* unlock if locked */
-    unlock_flash_if(sl);
-
-    /* set flash programming chosen bit */
-    set_flash_cr_pg(sl);
-
-    write_uint16(sl->q_buf, val);
-    stlink_write_mem16(sl, addr, 2);
-
-    /* wait for non business */
-    wait_flash_busy(sl);
+int _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+    struct stlink_libsg *sg = sl->backend_data;
+    clear_cdb(sg);
+    sg->cdb_cmd_blk[1] = STLINK_JTAG_WRITEDEBUG_32BIT;
+    // 2-5: addr
+    write_uint32(sg->cdb_cmd_blk + 2, addr);
+    write_uint32(sg->cdb_cmd_blk + 6, data);
+    sl->q_len = 2;
+    return stlink_q(sl);
+}
 
-    lock_flash(sl);
+// Read one DWORD data from memory
 
-    /* check the programmed value back */
-    stlink_read_mem16(sl, addr, 2);
-    if (*(const uint16_t*) sl->q_buf != val) {
-        /* values differ at i * sizeof(uint16_t) */
+int _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+    struct stlink_libsg *sg = sl->backend_data;
+    clear_cdb(sg);
+    sg->cdb_cmd_blk[1] = STLINK_JTAG_READDEBUG_32BIT;
+    // 2-5: addr
+    write_uint32(sg->cdb_cmd_blk + 2, addr);
+    sl->q_len = 8;
+    if (stlink_q(sl))
         return -1;
-    }
 
-    /* success */
+    *data = read_uint32(sl->q_buf, 4);
     return 0;
 }
-#endif /* not working */
 
 // Exit the jtag or swd mode and enter the mass mode.
 
-void _stlink_sg_exit_debug_mode(stlink_t *stl) {
-
+int _stlink_sg_exit_debug_mode(stlink_t *stl)
+{
     if (stl) {
         struct stlink_libsg* sl = stl->backend_data;
         clear_cdb(sl);
         sl->cdb_cmd_blk[1] = STLINK_DEBUG_EXIT;
         stl->q_len = 0; // >0 -> aboard
-        stlink_q(stl);
+        return stlink_q(stl);
     }
+
+    return 0;
 }
 
 
@@ -996,22 +913,29 @@ stlink_backend_t _stlink_sg_backend = {
     _stlink_sg_exit_dfu_mode,
     _stlink_sg_core_id,
     _stlink_sg_reset,
+    _stlink_sg_jtag_reset,
     _stlink_sg_run,
     _stlink_sg_status,
     _stlink_sg_version,
+    _stlink_sg_read_debug32,
     _stlink_sg_read_mem32,
+    _stlink_sg_write_debug32,
     _stlink_sg_write_mem32,
     _stlink_sg_write_mem8,
     _stlink_sg_read_all_regs,
     _stlink_sg_read_reg,
+    NULL,                   /* read_all_unsupported_regs */
+    NULL,                   /* read_unsupported_regs */
+    NULL,                   /* write_unsupported_regs */
     _stlink_sg_write_reg,
     _stlink_sg_step,
     _stlink_sg_current_mode,
-    _stlink_sg_force_debug
+    _stlink_sg_force_debug,
+    NULL
 };
 
 static stlink_t* stlink_open(const int verbose) {
-    
+
     stlink_t *sl = malloc(sizeof (stlink_t));
     memset(sl, 0, sizeof(stlink_t));
     struct stlink_libsg *slsg = malloc(sizeof (struct stlink_libsg));
@@ -1019,34 +943,36 @@ static stlink_t* stlink_open(const int verbose) {
         WLOG("Couldn't malloc stlink and stlink_sg structures out of memory!\n");
         return NULL;
     }
-    
+
     if (libusb_init(&(slsg->libusb_ctx))) {
         WLOG("failed to init libusb context, wrong version of libraries?\n");
         free(sl);
         free(slsg);
         return NULL;
     }
-    
+
     libusb_set_debug(slsg->libusb_ctx, 3);
-    
+
     slsg->usb_handle = libusb_open_device_with_vid_pid(slsg->libusb_ctx, USB_ST_VID, USB_STLINK_PID);
     if (slsg->usb_handle == NULL) {
         WLOG("Failed to find an stlink v1 by VID:PID\n");
         libusb_close(slsg->usb_handle);
+        libusb_exit(slsg->libusb_ctx);
         free(sl);
         free(slsg);
         return NULL;
     }
-    
-    // TODO 
+
+    // TODO
     // Could read the interface config descriptor, and assert lots of the assumptions
-    
+
     // assumption: numInterfaces is always 1...
     if (libusb_kernel_driver_active(slsg->usb_handle, 0) == 1) {
         int r = libusb_detach_kernel_driver(slsg->usb_handle, 0);
         if (r < 0) {
             WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r));
             libusb_close(slsg->usb_handle);
+            libusb_exit(slsg->libusb_ctx);
             free(sl);
             free(slsg);
             return NULL;
@@ -1059,12 +985,13 @@ static stlink_t* stlink_open(const int verbose) {
         /* this may fail for a previous configured device */
         WLOG("libusb_get_configuration()\n");
         libusb_close(slsg->usb_handle);
+        libusb_exit(slsg->libusb_ctx);
         free(sl);
         free(slsg);
         return NULL;
 
     }
-    
+
     // assumption: bConfigurationValue is always 1
     if (config != 1) {
         WLOG("Your stlink got into a real weird configuration, trying to fix it!\n");
@@ -1073,6 +1000,7 @@ static stlink_t* stlink_open(const int verbose) {
             /* this may fail for a previous configured device */
             WLOG("libusb_set_configuration() failed\n");
             libusb_close(slsg->usb_handle);
+            libusb_exit(slsg->libusb_ctx);
             free(sl);
             free(slsg);
             return NULL;
@@ -1082,6 +1010,7 @@ static stlink_t* stlink_open(const int verbose) {
     if (libusb_claim_interface(slsg->usb_handle, 0)) {
         WLOG("libusb_claim_interface() failed\n");
         libusb_close(slsg->usb_handle);
+        libusb_exit(slsg->libusb_ctx);
         free(sl);
         free(slsg);
         return NULL;
@@ -1090,9 +1019,9 @@ static stlink_t* stlink_open(const int verbose) {
     // assumption: endpoint config is fixed mang. really.
     slsg->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
     slsg->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
-    
+
     DLOG("Successfully opened stlinkv1 by libusb :)\n");
-    
+
     sl->verbose = verbose;
     sl->backend_data = slsg;
     sl->backend = &_stlink_sg_backend;
@@ -1104,49 +1033,57 @@ static stlink_t* stlink_open(const int verbose) {
 }
 
 
-
-stlink_t* stlink_v1_open(const int verbose) {
+stlink_t* stlink_v1_open_inner(const int verbose) {
     ugly_init(verbose);
     stlink_t *sl = stlink_open(verbose);
     if (sl == NULL) {
-        fputs("Error: could not open stlink device\n", stderr);
+        ELOG("Could not open stlink device\n");
         return NULL;
     }
 
     stlink_version(sl);
-    stlink_load_device_params(sl);
     if ((sl->version.st_vid != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
-        ugly_log(UERROR, LOG_TAG, 
-            "WTF? successfully opened, but unable to read version details. BROKEN!\n");
+        ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
         return NULL;
     }
 
     DLOG("Reading current mode...\n");
     switch (stlink_current_mode(sl)) {
-        case STLINK_DEV_MASS_MODE:
-            return sl;
-        case STLINK_DEV_DEBUG_MODE:
-            // TODO go to mass?
-            return sl;
+    case STLINK_DEV_MASS_MODE:
+        return sl;
+    case STLINK_DEV_DEBUG_MODE:
+        // TODO go to mass?
+        return sl;
+    default:
+        ILOG("Current mode unusable, trying to get back to a useful state...\n");
+        break;
     }
 
     DLOG("Attempting to exit DFU mode\n");
     _stlink_sg_exit_dfu_mode(sl);
-    
-    // exit the dfu mode -> the device is gone
-    DLOG("\n*** reopen the stlink device ***\n");
-    delay(1000);
-    stlink_close(sl);
-    delay(5000);
-
-    DLOG("Attempting to reopen the stlink...\n");
-    sl = stlink_open(verbose);
-    if (sl == NULL) {
-        fputs("Error: could not open stlink device\n", stderr);
+
+    // re-query device info (and retest)
+    stlink_version(sl);
+    if ((sl->version.st_vid != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
+        ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
         return NULL;
     }
-    // re-query device info
-    stlink_version(sl);
-    stlink_load_device_params(sl);    
+
+    return sl;
+}
+
+stlink_t* stlink_v1_open(const int verbose, int reset) {
+    stlink_t *sl = stlink_v1_open_inner(verbose);
+    if (sl == NULL)
+        return NULL;
+
+    // by now, it _must_ be fully open and in a useful mode....
+    stlink_enter_swd_mode(sl);
+    /* Now we are ready to read the parameters  */
+    if (reset) {
+        stlink_reset(sl);
+    }
+    stlink_load_device_params(sl);
+    ILOG("Successfully opened a stlink v1 debugger\n");
     return sl;
 }