/***************************************************************************
+ * SWIM contributions by Ake Rehnman *
+ * Copyright (C) 2017 Ake Rehnman *
+ * ake.rehnman(at)gmail.com *
+ * *
* Copyright (C) 2011-2012 by Mathias Kuester *
* Mathias Kuester <kesmtp@freenet.de> *
* *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
bool reconnect_pending;
};
+#define STLINK_SWIM_ERR_OK 0x00
+#define STLINK_SWIM_BUSY 0x01
#define STLINK_DEBUG_ERR_OK 0x80
#define STLINK_DEBUG_ERR_FAULT 0x81
#define STLINK_SWD_AP_WAIT 0x10
+#define STLINK_SWD_AP_FAULT 0x11
+#define STLINK_SWD_AP_ERROR 0x12
+#define STLINK_SWD_AP_PARITY_ERROR 0x13
+#define STLINK_JTAG_WRITE_ERROR 0x0c
+#define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d
#define STLINK_SWD_DP_WAIT 0x14
+#define STLINK_SWD_DP_FAULT 0x15
+#define STLINK_SWD_DP_ERROR 0x16
+#define STLINK_SWD_DP_PARITY_ERROR 0x17
+
+#define STLINK_SWD_AP_WDATA_ERROR 0x18
+#define STLINK_SWD_AP_STICKY_ERROR 0x19
+#define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a
#define STLINK_CORE_RUNNING 0x80
#define STLINK_CORE_HALTED 0x81
#define STLINK_DFU_EXIT 0x07
-#define STLINK_SWIM_ENTER 0x00
-#define STLINK_SWIM_EXIT 0x01
+/*
+ STLINK_SWIM_ENTER_SEQ
+ 1.3ms low then 750Hz then 1.5kHz
+
+ STLINK_SWIM_GEN_RST
+ STM8 DM pulls reset pin low 50us
+
+ STLINK_SWIM_SPEED
+ uint8_t (0=low|1=high)
+
+ STLINK_SWIM_WRITEMEM
+ uint16_t length
+ uint32_t address
+
+ STLINK_SWIM_RESET
+ send syncronization seq (16us low, response 64 clocks low)
+*/
+#define STLINK_SWIM_ENTER 0x00
+#define STLINK_SWIM_EXIT 0x01
+#define STLINK_SWIM_READ_CAP 0x02
+#define STLINK_SWIM_SPEED 0x03
+#define STLINK_SWIM_ENTER_SEQ 0x04
+#define STLINK_SWIM_GEN_RST 0x05
+#define STLINK_SWIM_RESET 0x06
+#define STLINK_SWIM_ASSERT_RESET 0x07
+#define STLINK_SWIM_DEASSERT_RESET 0x08
+#define STLINK_SWIM_READSTATUS 0x09
+#define STLINK_SWIM_WRITEMEM 0x0a
+#define STLINK_SWIM_READMEM 0x0b
+#define STLINK_SWIM_READBUF 0x0c
#define STLINK_DEBUG_ENTER_JTAG 0x00
#define STLINK_DEBUG_GETSTATUS 0x01
#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01
#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02
-#define STLINK_TRACE_SIZE 1024
+#define STLINK_TRACE_SIZE 4096
#define STLINK_TRACE_MAX_HZ 2000000
#define STLINK_TRACE_MIN_VERSION 13
};
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
+static int stlink_swim_status(void *handle);
/** */
static int stlink_usb_xfer_v1_get_status(void *handle)
return ERROR_OK;
}
-/** */
+/*
+ transfers block in cmdbuf
+ <size> indicates number of bytes in the following
+ data phase.
+*/
static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
{
int err, cmdsize = STLINK_CMD_SIZE_V2;
assert(handle != NULL);
- if (h->version.stlink == 1)
+ if (h->version.stlink == 1) {
cmdsize = STLINK_SG_SIZE;
+ /* put length in bCBWCBLength */
+ h->cmdbuf[14] = h->cmdidx-15;
+ }
err = stlink_usb_xfer_rw(handle, cmdsize, buf, size);
return ERROR_OK;
}
-
/**
Converts an STLINK status code held in the first byte of a response
to an openocd error, logs any error/wait status as debug output.
assert(handle != NULL);
+ if (h->transport == HL_TRANSPORT_SWIM) {
+ switch (h->databuf[0]) {
+ case STLINK_SWIM_ERR_OK:
+ return ERROR_OK;
+ case STLINK_SWIM_BUSY:
+ return ERROR_WAIT;
+ default:
+ LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]);
+ return ERROR_FAIL;
+ }
+ }
+
/* TODO: no error checking yet on api V1 */
if (h->jtag_api == STLINK_JTAG_API_V1)
h->databuf[0] = STLINK_DEBUG_ERR_OK;
LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT);
return ERROR_WAIT;
case STLINK_SWD_DP_WAIT:
- LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_AP_WAIT);
+ LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT);
return ERROR_WAIT;
+ case STLINK_JTAG_WRITE_ERROR:
+ LOG_DEBUG("Write error");
+ return ERROR_FAIL;
+ case STLINK_JTAG_WRITE_VERIF_ERROR:
+ LOG_DEBUG("Verify error");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_FAULT:
+ /* git://git.ac6.fr/openocd commit 657e3e885b9ee10
+ * returns ERROR_OK with the comment:
+ * Change in error status when reading outside RAM.
+ * This fix allows CDT plugin to visualize memory.
+ */
+ LOG_DEBUG("STLINK_SWD_AP_FAULT");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_ERROR:
+ LOG_DEBUG("STLINK_SWD_AP_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_PARITY_ERROR:
+ LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_DP_FAULT:
+ LOG_DEBUG("STLINK_SWD_DP_FAULT");
+ return ERROR_FAIL;
+ case STLINK_SWD_DP_ERROR:
+ LOG_DEBUG("STLINK_SWD_DP_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_DP_PARITY_ERROR:
+ LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_WDATA_ERROR:
+ LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_STICKY_ERROR:
+ LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR");
+ return ERROR_FAIL;
+ case STLINK_SWD_AP_STICKYORUN_ERROR:
+ LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR");
+ return ERROR_FAIL;
default:
LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]);
return ERROR_FAIL;
/** Issue an STLINK command via USB transfer, with retries on any wait status responses.
Works for commands where the STLINK_DEBUG status is returned in the first
- byte of the response packet.
+ byte of the response packet. For SWIM a SWIM_READSTATUS is requested instead.
Returns an openocd result code.
*/
{
int retries = 0;
int res;
+ struct stlink_usb_handle_s *h = handle;
+
while (1) {
- res = stlink_usb_xfer(handle, buf, size);
- if (res != ERROR_OK)
- return res;
+ if ((h->transport != HL_TRANSPORT_SWIM) || !retries) {
+ res = stlink_usb_xfer(handle, buf, size);
+ if (res != ERROR_OK)
+ return res;
+ }
+
+ if (h->transport == HL_TRANSPORT_SWIM) {
+ res = stlink_swim_status(handle);
+ if (res != ERROR_OK)
+ return res;
+ }
+
res = stlink_usb_error_check(handle);
if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
return ERROR_OK;
}
-/** */
+/*
+ this function writes transfer length in
+ the right place in the cb
+*/
+static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ buf_set_u32(h->cmdbuf+8, 0, 32, size);
+}
+
static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size)
{
struct stlink_usb_handle_s *h = handle;
strcpy((char *)h->cmdbuf, "USBC");
h->cmdidx += 4;
/* csw tag not used */
+ buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, 0);
h->cmdidx += 4;
+ /* cbw data transfer length (in the following data phase in or out) */
buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size);
h->cmdidx += 4;
+ /* cbw flags */
h->cmdbuf[h->cmdidx++] = (direction == h->rx_ep ? ENDPOINT_IN : ENDPOINT_OUT);
h->cmdbuf[h->cmdidx++] = 0; /* lun */
- h->cmdbuf[h->cmdidx++] = STLINK_CMD_SIZE_V1;
+ /* cdb clength (is filled in at xfer) */
+ h->cmdbuf[h->cmdidx++] = 0;
}
/** */
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;
case STLINK_MODE_DFU:
case STLINK_MODE_MASS:
return ERROR_FAIL;
}
+ /* 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.
+ * Tested firmware STLINK v2 JTAG v29 API v2 SWIM v0 uses T_NRST pin by default
+ * Tested firmware STLINK v2 JTAG v27 API v2 SWIM v6 uses T_NRST pin by default
+ * after power on, SWIM_RST stays unchanged */
+ if (connect_under_reset && emode != STLINK_MODE_DEBUG_SWIM)
+ stlink_usb_assert_srst(handle, 0);
+ /* do not check the return status here, we will
+ proceed and enter the desired mode below
+ and try asserting srst again. */
+
+ res = stlink_usb_mode_enter(handle, emode);
+ if (res != ERROR_OK)
+ return res;
+
+ /* assert SRST again: a little bit late but now the adapter knows for sure what pin to use */
if (connect_under_reset) {
res = stlink_usb_assert_srst(handle, 0);
if (res != ERROR_OK)
return res;
}
- res = stlink_usb_mode_enter(handle, emode);
+ res = stlink_usb_current_mode(handle, &mode);
if (res != ERROR_OK)
return res;
- res = stlink_usb_current_mode(handle, &mode);
+ LOG_DEBUG("MODE: 0x%02X", mode);
+
+ return ERROR_OK;
+}
+/* request status from last swim request */
+static int stlink_swim_status(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ 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);
if (res != ERROR_OK)
return res;
+ return ERROR_OK;
+}
+/*
+ the purpose of this function is unknown...
+ capabilites? anyway for swim v6 it returns
+ 0001020600000000
+*/
+__attribute__((unused))
+static int stlink_swim_cap(void *handle, uint8_t *cap)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
- LOG_DEBUG("MODE: 0x%02X", mode);
+ stlink_usb_init_buffer(handle, h->rx_ep, 8);
+ 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);
+ if (res != ERROR_OK)
+ return res;
+ memcpy(cap, h->databuf, 8);
+ return ERROR_OK;
+}
+
+/* debug dongle assert/deassert sreset line */
+static int stlink_swim_assert_reset(void *handle, int reset)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ if (!reset)
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ASSERT_RESET;
+ else
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_DEASSERT_RESET;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+/*
+ send swim enter seq
+ 1.3ms low then 750Hz then 1.5kHz
+*/
+static int stlink_swim_enter(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER_SEQ;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+/* switch high/low speed swim */
+static int stlink_swim_speed(void *handle, int speed)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_SPEED;
+ if (speed)
+ h->cmdbuf[h->cmdidx++] = 1;
+ else
+ h->cmdbuf[h->cmdidx++] = 0;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+/*
+ initiate srst from swim.
+ nrst is pulled low for 50us.
+*/
+static int stlink_swim_generate_rst(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_GEN_RST;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+/*
+ send resyncronize sequence
+ swim is pulled low for 16us
+ reply is 64 clks low
+*/
+static int stlink_swim_resync(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_RESET;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, const uint8_t *data)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+ unsigned int i;
+ unsigned int datalen = 0;
+ int cmdsize = STLINK_CMD_SIZE_V2;
+
+ if (len > STLINK_DATA_SIZE)
+ return ERROR_FAIL;
+
+ if (h->version.stlink == 1)
+ cmdsize = STLINK_SG_SIZE;
+
+ stlink_usb_init_buffer(handle, h->tx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_WRITEMEM;
+ h_u16_to_be(h->cmdbuf+h->cmdidx, len);
+ h->cmdidx += 2;
+ h_u32_to_be(h->cmdbuf+h->cmdidx, addr);
+ h->cmdidx += 4;
+ for (i = 0; i < len; i++) {
+ if (h->cmdidx == cmdsize)
+ h->databuf[datalen++] = *(data++);
+ else
+ h->cmdbuf[h->cmdidx++] = *(data++);
+ }
+ if (h->version.stlink == 1)
+ stlink_usb_set_cbw_transfer_datalength(handle, datalen);
+
+ res = stlink_cmd_allow_retry(handle, h->databuf, datalen);
+ if (res != ERROR_OK)
+ return res;
+ return ERROR_OK;
+}
+
+static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint8_t *data)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int res;
+
+ if (len > STLINK_DATA_SIZE)
+ return ERROR_FAIL;
+
+ stlink_usb_init_buffer(handle, h->rx_ep, 0);
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND;
+ h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READMEM;
+ h_u16_to_be(h->cmdbuf+h->cmdidx, len);
+ h->cmdidx += 2;
+ h_u32_to_be(h->cmdbuf+h->cmdidx, addr);
+ h->cmdidx += 4;
+ res = stlink_cmd_allow_retry(handle, h->databuf, 0);
+ if (res != ERROR_OK)
+ return res;
+
+ 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);
+ if (res != ERROR_OK)
+ return res;
return ERROR_OK;
}
assert(handle != NULL);
+ /* there is no swim read core id cmd */
+ if (h->transport == HL_TRANSPORT_SWIM) {
+ *idcode = 0;
+ return ERROR_OK;
+ }
+
stlink_usb_init_buffer(handle, h->rx_ep, 4);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
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;
+ }
+
if (h->reconnect_pending) {
LOG_INFO("Previous state query failed, trying to reconnect");
res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
assert(handle != NULL);
- if (h->jtag_api == STLINK_JTAG_API_V1)
+ if (h->transport == HL_TRANSPORT_SWIM)
+ return stlink_swim_assert_reset(handle, srst);
+
+ if (h->version.stlink == 1)
return ERROR_COMMAND_NOTFOUND;
stlink_usb_init_buffer(handle, h->rx_ep, 2);
assert(handle != NULL);
+ if (h->transport == HL_TRANSPORT_SWIM)
+ return stlink_swim_generate_rst(handle);
+
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
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. */
+ * 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);
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
/* the stlink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */
if (size == 4) {
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
/* the stlink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */
if (size == 4) {
int speed_diff = INT_MAX;
struct stlink_usb_handle_s *h = handle;
+ if (h && (h->transport == HL_TRANSPORT_SWIM)) {
+ /*
+ 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;
+ }
+
/* only supported by stlink/v2 and for firmware >= 22 */
if (h && (h->version.stlink == 1 || h->version.jtag < 22))
return khz;
/** */
static int stlink_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 (emode != STLINK_MODE_UNKNOWN)
+ stlink_usb_mode_leave(handle, emode);
+ /* do not check return code, it prevent
+ us from closing jtag_libusb */
+ }
+
if (h && h->fd)
jtag_libusb_close(h->fd);
h->transport = param->transport;
- const uint16_t vids[] = { param->vid, 0 };
- const uint16_t pids[] = { param->pid, 0 };
- const char *serial = param->serial;
-
- LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
- param->transport, param->vid, param->pid,
- param->serial ? param->serial : "");
+ 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 : "");
+ }
/*
On certain host USB configurations(e.g. MacBook Air)
in order to become operational.
*/
do {
- if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) {
+ if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) {
LOG_ERROR("open failed");
goto error_open;
}
/* 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) {
+ LOG_DEBUG("libusb_get_pid failed");
+ goto error_open;
+ }
+
/* wrap version for first read */
- switch (param->pid) {
+ switch (pid) {
case STLINK_V1_PID:
h->version.stlink = 1;
h->tx_ep = STLINK_TX_EP;
}
} while (1);
- /* compare usb vid/pid */
- if ((param->vid != h->vid) || (param->pid != h->pid))
- LOG_INFO("vid/pid are not identical: 0x%04X/0x%04X 0x%04X/0x%04X",
- param->vid, param->pid,
- h->vid, h->pid);
-
/* check if mode is supported */
err = ERROR_OK;
goto error_open;
}
+ 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;
+ }
+
/* clock speed only supported by stlink/v2 and for firmware >= 22 */
if (h->version.stlink >= 2 && h->version.jtag >= 22) {
LOG_DEBUG("Supported clock speeds are:");