stlink: separate stlink core from USB functions
the introduced stlink_backend_s struct provides an API to separate USB internals from stlink core. this separation aims to ease: - stlink-server integration [1] - stlink driver split into modules: - stlink_core - stlink_usb - stlink_tcp [1] [1] refer to http://openocd.zylin.com/#/c/5633/ Change-Id: Iff6790942612ce1769ec4c75990914534e5e9e24 Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> Reviewed-on: http://openocd.zylin.com/5632 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
cc9e3c2f7b
commit
75d512bb97
|
@ -1,4 +1,7 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2020 by Tarek Bochkati *
|
||||||
|
* Tarek Bochkati <tarek.bouchkati@gmail.com> *
|
||||||
|
* *
|
||||||
* SWIM contributions by Ake Rehnman *
|
* SWIM contributions by Ake Rehnman *
|
||||||
* Copyright (C) 2017 Ake Rehnman *
|
* Copyright (C) 2017 Ake Rehnman *
|
||||||
* ake.rehnman(at)gmail.com *
|
* ake.rehnman(at)gmail.com *
|
||||||
|
@ -119,12 +122,32 @@ struct stlink_usb_version {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** */
|
struct stlink_usb_priv_s {
|
||||||
struct stlink_usb_handle_s {
|
|
||||||
/** */
|
/** */
|
||||||
struct libusb_device_handle *fd;
|
struct libusb_device_handle *fd;
|
||||||
/** */
|
/** */
|
||||||
struct libusb_transfer *trans;
|
struct libusb_transfer *trans;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stlink_backend_s {
|
||||||
|
/** */
|
||||||
|
int (*open)(void *handle, struct hl_interface_param_s *param);
|
||||||
|
/** */
|
||||||
|
int (*close)(void *handle);
|
||||||
|
/** */
|
||||||
|
int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size);
|
||||||
|
/** */
|
||||||
|
int (*read_trace)(void *handle, const uint8_t *buf, int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** */
|
||||||
|
struct stlink_usb_handle_s {
|
||||||
|
/** */
|
||||||
|
struct stlink_backend_s *backend;
|
||||||
|
/** */
|
||||||
|
union {
|
||||||
|
struct stlink_usb_priv_s usb_backend_priv;
|
||||||
|
};
|
||||||
/** */
|
/** */
|
||||||
uint8_t rx_ep;
|
uint8_t rx_ep;
|
||||||
/** */
|
/** */
|
||||||
|
@ -161,6 +184,26 @@ struct stlink_usb_handle_s {
|
||||||
bool reconnect_pending;
|
bool reconnect_pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** */
|
||||||
|
static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
|
||||||
|
{
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
return h->backend->open(handle, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
static inline int stlink_usb_close(void *handle)
|
||||||
|
{
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
return h->backend->close(handle);
|
||||||
|
}
|
||||||
|
/** */
|
||||||
|
static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
return h->backend->xfer_noerrcheck(handle, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
#define STLINK_SWIM_ERR_OK 0x00
|
#define STLINK_SWIM_ERR_OK 0x00
|
||||||
#define STLINK_SWIM_BUSY 0x01
|
#define STLINK_SWIM_BUSY 0x01
|
||||||
#define STLINK_DEBUG_ERR_OK 0x80
|
#define STLINK_DEBUG_ERR_OK 0x80
|
||||||
|
@ -380,8 +423,6 @@ static unsigned int stlink_usb_block(void *handle)
|
||||||
return STLINK_MAX_RW8;
|
return STLINK_MAX_RW8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_LIBUSB_ASYNCIO
|
#ifdef USE_LIBUSB_ASYNCIO
|
||||||
|
|
||||||
static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
|
static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
|
||||||
|
@ -545,7 +586,7 @@ static int stlink_usb_xfer_v1_get_status(void *handle)
|
||||||
/* read status */
|
/* read status */
|
||||||
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
|
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
|
||||||
|
|
||||||
ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13,
|
ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13,
|
||||||
STLINK_READ_TIMEOUT, &tr);
|
STLINK_READ_TIMEOUT, &tr);
|
||||||
if (ret || tr != 13)
|
if (ret || tr != 13)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -602,7 +643,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
|
||||||
}
|
}
|
||||||
|
|
||||||
return jtag_libusb_bulk_transfer_n(
|
return jtag_libusb_bulk_transfer_n(
|
||||||
h->fd,
|
h->usb_backend_priv.fd,
|
||||||
transfers,
|
transfers,
|
||||||
n_transfers,
|
n_transfers,
|
||||||
STLINK_WRITE_TIMEOUT);
|
STLINK_WRITE_TIMEOUT);
|
||||||
|
@ -615,20 +656,20 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
|
||||||
|
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
|
|
||||||
ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf,
|
ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf,
|
||||||
cmdsize, STLINK_WRITE_TIMEOUT, &tr);
|
cmdsize, STLINK_WRITE_TIMEOUT, &tr);
|
||||||
if (ret || tr != cmdsize)
|
if (ret || tr != cmdsize)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (h->direction == h->tx_ep && size) {
|
if (h->direction == h->tx_ep && size) {
|
||||||
ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
|
ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf,
|
||||||
size, STLINK_WRITE_TIMEOUT, &tr);
|
size, STLINK_WRITE_TIMEOUT, &tr);
|
||||||
if (ret || tr != size) {
|
if (ret || tr != size) {
|
||||||
LOG_DEBUG("bulk write failed");
|
LOG_DEBUG("bulk write failed");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
} else if (h->direction == h->rx_ep && size) {
|
} else if (h->direction == h->rx_ep && size) {
|
||||||
ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
|
ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf,
|
||||||
size, STLINK_READ_TIMEOUT, &tr);
|
size, STLINK_READ_TIMEOUT, &tr);
|
||||||
if (ret || tr != size) {
|
if (ret || tr != size) {
|
||||||
LOG_DEBUG("bulk read failed");
|
LOG_DEBUG("bulk read failed");
|
||||||
|
@ -667,13 +708,29 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
int tr, ret;
|
||||||
|
|
||||||
|
ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size,
|
||||||
|
STLINK_READ_TIMEOUT, &tr);
|
||||||
|
if (ret || tr != size) {
|
||||||
|
LOG_ERROR("bulk trace read failed");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
transfers block in cmdbuf
|
transfers block in cmdbuf
|
||||||
<size> indicates number of bytes in the following
|
<size> indicates number of bytes in the following
|
||||||
data phase.
|
data phase.
|
||||||
Ignore the (eventual) error code in the received packet.
|
Ignore the (eventual) error code in the received packet.
|
||||||
*/
|
*/
|
||||||
static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
|
static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
int err, cmdsize = STLINK_CMD_SIZE_V2;
|
int err, cmdsize = STLINK_CMD_SIZE_V2;
|
||||||
struct stlink_usb_handle_s *h = handle;
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
@ -852,20 +909,12 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
|
||||||
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
|
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
struct stlink_usb_handle_s *h = handle;
|
struct stlink_usb_handle_s *h = handle;
|
||||||
int tr, ret;
|
|
||||||
|
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
|
|
||||||
assert(h->version.flags & STLINK_F_HAS_TRACE);
|
assert(h->version.flags & STLINK_F_HAS_TRACE);
|
||||||
|
|
||||||
ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size,
|
return h->backend->read_trace(handle, buf, size);
|
||||||
STLINK_READ_TIMEOUT, &tr);
|
|
||||||
if (ret || tr != size) {
|
|
||||||
LOG_ERROR("bulk trace read failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2715,18 +2764,30 @@ static int stlink_speed(void *handle, int khz, bool query)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
static int stlink_usb_close(void *handle)
|
static int stlink_usb_usb_close(void *handle)
|
||||||
{
|
{
|
||||||
struct stlink_usb_handle_s *h = handle;
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
|
||||||
if (h && h->fd) {
|
if (h && h->usb_backend_priv.fd) {
|
||||||
stlink_usb_exit_mode(h);
|
stlink_usb_exit_mode(h);
|
||||||
/* do not check return code, it prevent
|
/* do not check return code, it prevent
|
||||||
us from closing jtag_libusb */
|
us from closing jtag_libusb */
|
||||||
jtag_libusb_close(h->fd);
|
jtag_libusb_close(h->usb_backend_priv.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(h);
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
static int stlink_close(void *handle)
|
||||||
|
{
|
||||||
|
if (handle != NULL) {
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
|
|
||||||
|
stlink_usb_close(handle);
|
||||||
|
|
||||||
|
free(h);
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -2811,27 +2872,10 @@ static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
|
static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param)
|
||||||
{
|
{
|
||||||
|
struct stlink_usb_handle_s *h = handle;
|
||||||
int err, retry_count = 1;
|
int err, retry_count = 1;
|
||||||
struct stlink_usb_handle_s *h;
|
|
||||||
|
|
||||||
LOG_DEBUG("stlink_usb_open");
|
|
||||||
|
|
||||||
h = calloc(1, sizeof(struct stlink_usb_handle_s));
|
|
||||||
|
|
||||||
if (h == 0) {
|
|
||||||
LOG_DEBUG("malloc failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
h->st_mode = mode;
|
|
||||||
|
|
||||||
for (unsigned i = 0; param->vid[i]; i++) {
|
|
||||||
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
|
|
||||||
h->st_mode, param->vid[i], param->pid[i],
|
|
||||||
param->serial ? param->serial : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
On certain host USB configurations(e.g. MacBook Air)
|
On certain host USB configurations(e.g. MacBook Air)
|
||||||
|
@ -2844,25 +2888,25 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
if (jtag_libusb_open(param->vid, param->pid, param->serial,
|
if (jtag_libusb_open(param->vid, param->pid, param->serial,
|
||||||
&h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
|
&h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
|
||||||
LOG_ERROR("open failed");
|
LOG_ERROR("open failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jtag_libusb_set_configuration(h->fd, 0);
|
jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0);
|
||||||
|
|
||||||
if (libusb_claim_interface(h->fd, 0) != ERROR_OK) {
|
if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) {
|
||||||
LOG_DEBUG("claim interface failed");
|
LOG_DEBUG("claim interface failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX EP is common for all versions */
|
/* RX EP is common for all versions */
|
||||||
h->rx_ep = STLINK_RX_EP;
|
h->rx_ep = STLINK_RX_EP;
|
||||||
|
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) {
|
if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) {
|
||||||
LOG_DEBUG("libusb_get_pid failed");
|
LOG_DEBUG("libusb_get_pid failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wrap version for first read */
|
/* wrap version for first read */
|
||||||
|
@ -2902,21 +2946,21 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
|
||||||
} else if (h->version.stlink == 1 ||
|
} else if (h->version.stlink == 1 ||
|
||||||
retry_count == 0) {
|
retry_count == 0) {
|
||||||
LOG_ERROR("read version failed");
|
LOG_ERROR("read version failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
} else {
|
} else {
|
||||||
err = libusb_release_interface(h->fd, 0);
|
err = libusb_release_interface(h->usb_backend_priv.fd, 0);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("release interface failed");
|
LOG_ERROR("release interface failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = libusb_reset_device(h->fd);
|
err = libusb_reset_device(h->usb_backend_priv.fd);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("reset device failed");
|
LOG_ERROR("reset device failed");
|
||||||
goto error_open;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jtag_libusb_close(h->fd);
|
jtag_libusb_close(h->usb_backend_priv.fd);
|
||||||
/*
|
/*
|
||||||
Give the device one second to settle down and
|
Give the device one second to settle down and
|
||||||
reenumerate.
|
reenumerate.
|
||||||
|
@ -2926,8 +2970,44 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct stlink_backend_s stlink_usb_backend = {
|
||||||
|
.open = stlink_usb_usb_open,
|
||||||
|
.close = stlink_usb_usb_close,
|
||||||
|
.xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck,
|
||||||
|
.read_trace = stlink_usb_usb_read_trace,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
|
||||||
|
{
|
||||||
|
struct stlink_usb_handle_s *h;
|
||||||
|
|
||||||
|
LOG_DEBUG("stlink_open");
|
||||||
|
|
||||||
|
h = calloc(1, sizeof(struct stlink_usb_handle_s));
|
||||||
|
|
||||||
|
if (h == 0) {
|
||||||
|
LOG_DEBUG("malloc failed");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->st_mode = mode;
|
||||||
|
|
||||||
|
for (unsigned i = 0; param->vid[i]; i++) {
|
||||||
|
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
|
||||||
|
h->st_mode, param->vid[i], param->pid[i],
|
||||||
|
param->serial ? param->serial : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
h->backend = &stlink_usb_backend;
|
||||||
|
|
||||||
|
if (stlink_usb_open(h, param) != ERROR_OK)
|
||||||
|
goto error_open;
|
||||||
|
|
||||||
/* check if mode is supported */
|
/* check if mode is supported */
|
||||||
err = ERROR_OK;
|
int err = ERROR_OK;
|
||||||
|
|
||||||
switch (h->st_mode) {
|
switch (h->st_mode) {
|
||||||
case STLINK_MODE_DEBUG_SWD:
|
case STLINK_MODE_DEBUG_SWD:
|
||||||
|
@ -2994,14 +3074,13 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
error_open:
|
error_open:
|
||||||
stlink_usb_close(h);
|
stlink_close(h);
|
||||||
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
|
static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
|
||||||
{
|
{
|
||||||
return stlink_usb_open(param, stlink_get_mode(param->transport), fd);
|
return stlink_open(param, stlink_get_mode(param->transport), fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stlink_config_trace(void *handle, bool enabled,
|
static int stlink_config_trace(void *handle, bool enabled,
|
||||||
|
@ -3151,7 +3230,7 @@ struct hl_layout_api_s stlink_usb_layout_api = {
|
||||||
/** */
|
/** */
|
||||||
.open = stlink_usb_hl_open,
|
.open = stlink_usb_hl_open,
|
||||||
/** */
|
/** */
|
||||||
.close = stlink_usb_close,
|
.close = stlink_close,
|
||||||
/** */
|
/** */
|
||||||
.idcode = stlink_usb_idcode,
|
.idcode = stlink_usb_idcode,
|
||||||
/** */
|
/** */
|
||||||
|
@ -3728,7 +3807,7 @@ static int stlink_dap_init(void)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
|
retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -3748,7 +3827,7 @@ static int stlink_dap_quit(void)
|
||||||
free((void *)stlink_dap_param.serial);
|
free((void *)stlink_dap_param.serial);
|
||||||
stlink_dap_param.serial = NULL;
|
stlink_dap_param.serial = NULL;
|
||||||
|
|
||||||
return stlink_usb_close(stlink_dap_handle);
|
return stlink_close(stlink_dap_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
|
|
Loading…
Reference in New Issue