jtag_libusb_bulk_read|write: return error code instead of size

A USB bulk write/read operation may fail with different errors:
 LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates transferred)
 LIBUSB_ERROR_PIPE if the endpoint halted
 LIBUSB_ERROR_OVERFLOW if the device offered more data, see Packets and overflows
 LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
 another LIBUSB_ERROR code on other failures

Current OpenOCD code is using the transfer size based error detection.
Which may not always work. For example for LIBUSB_ERROR_OVERFLOW as libusb
documentation says:
"Problems may occur if the device attempts to send more data than can fit in
the buffer. libusb reports LIBUSB_TRANSFER_OVERFLOW for this condition but
other behaviour is largely undefined: actual_length may or may not be accurate,
the chunk of data that can fit in the buffer (before overflow) may or may not
have been transferred."

This patch is refactoring code to use actual error return value for
error detection instead of size.

Change-Id: Iec0798438ca7b5c76e2e2912af21d9aa76ee0217
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-on: http://openocd.zylin.com/4590
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
This commit is contained in:
Oleksij Rempel 2018-07-05 13:42:14 +02:00 committed by Oleksij Rempel
parent f98099507f
commit d612baacaa
12 changed files with 186 additions and 89 deletions

View File

@ -349,41 +349,53 @@ static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id,
/* calls the given usb_bulk_* function, allowing for the data to
* trickle in with some timeouts */
static int usb_bulk_with_retries(
int (*f)(jtag_libusb_device_handle *, int, char *, int, int),
int (*f)(jtag_libusb_device_handle *, int, char *, int, int, int *),
jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout)
char *bytes, int size, int timeout, int *transferred)
{
int tries = 3, count = 0;
while (tries && (count < size)) {
int result = f(dev, ep, bytes + count, size - count, timeout);
if (result > 0)
int result, ret;
ret = f(dev, ep, bytes + count, size - count, timeout, &result);
if (ERROR_OK == ret)
count += result;
else if ((-ETIMEDOUT != result) || !--tries)
return result;
else if ((ERROR_TIMEOUT_REACHED != ret) || !--tries)
return ret;
}
return count;
*transferred = count;
return ERROR_OK;
}
static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep,
char *buff, int size, int timeout)
char *buff, int size, int timeout, int *transferred)
{
/* usb_bulk_write() takes const char *buff */
return jtag_libusb_bulk_write(dev, ep, buff, size, timeout);
jtag_libusb_bulk_write(dev, ep, buff, size, timeout, transferred);
return 0;
}
static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout)
{
return usb_bulk_with_retries(&wrap_usb_bulk_write,
dev, ep, bytes, size, timeout);
int tr = 0;
usb_bulk_with_retries(&wrap_usb_bulk_write,
dev, ep, bytes, size, timeout, &tr);
return tr;
}
static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout)
{
return usb_bulk_with_retries(&jtag_libusb_bulk_read,
dev, ep, bytes, size, timeout);
int tr = 0;
usb_bulk_with_retries(&jtag_libusb_bulk_read,
dev, ep, bytes, size, timeout, &tr);
return tr;
}
/* Write data from out_buffer to USB. */

View File

@ -132,11 +132,11 @@ static int ft232r_send_recv(void)
bytes_to_write = rxfifo_free;
if (bytes_to_write) {
int n = jtag_libusb_bulk_write(adapter, IN_EP,
(char *) ft232r_output + total_written,
bytes_to_write, 1000);
int n;
if (n == 0) {
if (jtag_libusb_bulk_write(adapter, IN_EP,
(char *) ft232r_output + total_written,
bytes_to_write, 1000, &n) != ERROR_OK) {
LOG_ERROR("usb bulk write failed");
return ERROR_JTAG_DEVICE_ERROR;
}
@ -147,12 +147,10 @@ static int ft232r_send_recv(void)
/* Read */
uint8_t reply[64];
int n;
int n = jtag_libusb_bulk_read(adapter, OUT_EP,
(char *) reply,
sizeof(reply), 1000);
if (n == 0) {
if (jtag_libusb_bulk_read(adapter, OUT_EP, (char *) reply,
sizeof(reply), 1000, &n) != ERROR_OK) {
LOG_ERROR("usb bulk read failed");
return ERROR_JTAG_DEVICE_ERROR;
}

View File

@ -731,14 +731,14 @@ static int kitprog_swd_run_queue(void)
}
}
ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle,
BULK_EP_OUT, (char *)buffer, write_count, 0);
if (ret > 0) {
queued_retval = ERROR_OK;
} else {
if (jtag_libusb_bulk_write(kitprog_handle->usb_handle,
BULK_EP_OUT, (char *)buffer,
write_count, 0, &ret)) {
LOG_ERROR("Bulk write failed");
queued_retval = ERROR_FAIL;
break;
} else {
queued_retval = ERROR_OK;
}
/* KitProg firmware does not send a zero length packet
@ -754,18 +754,17 @@ static int kitprog_swd_run_queue(void)
if (read_count % 64 == 0)
read_count_workaround = read_count;
ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle,
if (jtag_libusb_bulk_read(kitprog_handle->usb_handle,
BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer,
read_count_workaround, 1000);
if (ret > 0) {
read_count_workaround, 1000, &ret)) {
LOG_ERROR("Bulk read failed");
queued_retval = ERROR_FAIL;
break;
} else {
/* Handle garbage data by offsetting the initial read index */
if ((unsigned int)ret > read_count)
read_index = ret - read_count;
queued_retval = ERROR_OK;
} else {
LOG_ERROR("Bulk read failed");
queued_retval = ERROR_FAIL;
break;
}
for (int i = 0; i < pending_transfer_count; i++) {

View File

@ -23,6 +23,18 @@
#include "log.h"
#include "libusb0_common.h"
static int jtag_libusb_error(int err)
{
switch (err) {
case 0:
return ERROR_OK;
case -ETIMEDOUT:
return ERROR_TIMEOUT_REACHED;
default:
return ERROR_FAIL;
}
}
static bool jtag_libusb_match(struct jtag_libusb_device *dev,
const uint16_t vids[], const uint16_t pids[])
{
@ -130,15 +142,37 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t request
}
int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
int size, int timeout)
int size, int timeout, int *transferred)
{
return usb_bulk_write(dev, ep, bytes, size, timeout);
int ret;
*transferred = 0;
ret = usb_bulk_write(dev, ep, bytes, size, timeout);
if (ret < 0) {
LOG_ERROR("usb_bulk_write error: %i", ret);
return jtag_libusb_error(ret);
}
return ERROR_OK;
}
int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
int size, int timeout)
int size, int timeout, int *transferred)
{
return usb_bulk_read(dev, ep, bytes, size, timeout);
int ret;
*transferred = 0;
ret = usb_bulk_read(dev, ep, bytes, size, timeout);
if (ret < 0) {
LOG_ERROR("usb_bulk_read error: %i", ret);
return jtag_libusb_error(ret);
}
return ERROR_OK;
}
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,

View File

@ -60,9 +60,9 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
uint8_t requestType, uint8_t request, uint16_t wValue,
uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
char *bytes, int size, int timeout, int *transferred);
int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
char *bytes, int size, int timeout, int *transferred);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration);
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,

View File

@ -33,6 +33,31 @@
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
static libusb_device **devs; /**< The usb device list **/
static int jtag_libusb_error(int err)
{
switch (err) {
case LIBUSB_SUCCESS:
return ERROR_OK;
case LIBUSB_ERROR_TIMEOUT:
return ERROR_TIMEOUT_REACHED;
case LIBUSB_ERROR_IO:
case LIBUSB_ERROR_INVALID_PARAM:
case LIBUSB_ERROR_ACCESS:
case LIBUSB_ERROR_NO_DEVICE:
case LIBUSB_ERROR_NOT_FOUND:
case LIBUSB_ERROR_BUSY:
case LIBUSB_ERROR_OVERFLOW:
case LIBUSB_ERROR_PIPE:
case LIBUSB_ERROR_INTERRUPTED:
case LIBUSB_ERROR_NO_MEM:
case LIBUSB_ERROR_NOT_SUPPORTED:
case LIBUSB_ERROR_OTHER:
return ERROR_FAIL;
default:
return ERROR_FAIL;
}
}
static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[])
{
@ -179,23 +204,37 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t request
}
int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
int size, int timeout)
int size, int timeout, int *transferred)
{
int transferred = 0;
int ret;
libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
&transferred, timeout);
return transferred;
*transferred = 0;
ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
transferred, timeout);
if (ret != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_bulk_write error: %s", libusb_error_name(ret));
return jtag_libusb_error(ret);
}
return ERROR_OK;
}
int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
int size, int timeout)
int size, int timeout, int *transferred)
{
int transferred = 0;
int ret;
libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
&transferred, timeout);
return transferred;
*transferred = 0;
ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
transferred, timeout);
if (ret != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_bulk_read error: %s", libusb_error_name(ret));
return jtag_libusb_error(ret);
}
return ERROR_OK;
}
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,

View File

@ -53,9 +53,9 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
uint8_t requestType, uint8_t request, uint16_t wValue,
uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
char *bytes, int size, int timeout, int *transferred);
int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
char *bytes, int size, int timeout, int *transferred);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration);
/**

View File

@ -770,8 +770,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
} else {
result = jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \
(char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \
(char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("USB write end: %d bytes", result);
@ -797,8 +797,8 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag)
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
} else {
result = jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
(char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
(char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("USB read end: %d bytes", result);

View File

@ -256,10 +256,9 @@ static int openjtag_buf_write_cy7c65215(
return ERROR_JTAG_DEVICE_ERROR;
}
ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
CY7C65215_USB_TIMEOUT);
if (ret < 0) {
LOG_ERROR("bulk write failed, error %d", ret);
if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
CY7C65215_USB_TIMEOUT, &ret)) {
LOG_ERROR("bulk write failed, error");
return ERROR_JTAG_DEVICE_ERROR;
}
*bytes_written = ret;
@ -324,10 +323,9 @@ static int openjtag_buf_read_cy7c65215(
return ERROR_JTAG_DEVICE_ERROR;
}
ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
CY7C65215_USB_TIMEOUT);
if (ret < 0) {
LOG_ERROR("bulk read failed, error %d", ret);
if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
CY7C65215_USB_TIMEOUT, &ret)) {
LOG_ERROR("bulk read failed, error");
return ERROR_JTAG_DEVICE_ERROR;
}
*bytes_read = ret;

View File

@ -144,10 +144,12 @@ static struct osbdm osbdm_context;
static int osbdm_send_and_recv(struct osbdm *osbdm)
{
/* Send request */
int count = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
(char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT);
int count, ret;
if (count != osbdm->count) {
ret = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
(char *)osbdm->buffer, osbdm->count,
OSBDM_USB_TIMEOUT, &count);
if (ret || count != osbdm->count) {
LOG_ERROR("OSBDM communication error: can't write");
return ERROR_FAIL;
}
@ -156,13 +158,12 @@ static int osbdm_send_and_recv(struct osbdm *osbdm)
uint8_t cmd_saved = osbdm->buffer[0];
/* Reading answer */
osbdm->count = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
(char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT);
ret = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
(char *)osbdm->buffer, OSBDM_USB_BUFSIZE,
OSBDM_USB_TIMEOUT, &osbdm->count);
/* Now perform basic checks for data sent by BDM device
*/
if (osbdm->count < 0) {
if (ret) {
LOG_ERROR("OSBDM communication error: can't read");
return ERROR_FAIL;
}

View File

@ -531,14 +531,16 @@ static int jtag_libusb_bulk_transfer_n(
static int stlink_usb_xfer_v1_get_status(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int tr, ret;
assert(handle != NULL);
/* read status */
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf,
13, STLINK_READ_TIMEOUT) != 13)
ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13,
STLINK_READ_TIMEOUT, &tr);
if (ret || tr != 13)
return ERROR_FAIL;
uint32_t t1;
@ -602,23 +604,26 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
{
struct stlink_usb_handle_s *h = handle;
int tr, ret;
assert(handle != NULL);
if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, cmdsize,
STLINK_WRITE_TIMEOUT) != cmdsize) {
ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf,
cmdsize, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != cmdsize)
return ERROR_FAIL;
}
if (h->direction == h->tx_ep && size) {
if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
size, STLINK_WRITE_TIMEOUT) != size) {
ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
size, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk write failed");
return ERROR_FAIL;
}
} else if (h->direction == h->rx_ep && size) {
if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
size, STLINK_READ_TIMEOUT) != size) {
ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
size, STLINK_READ_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk read failed");
return ERROR_FAIL;
}
@ -840,13 +845,15 @@ 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)
{
struct stlink_usb_handle_s *h = handle;
int tr, ret;
assert(handle != NULL);
assert(h->version.flags & STLINK_F_HAS_TRACE);
if (jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf,
size, STLINK_READ_TIMEOUT) != size) {
ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size,
STLINK_READ_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_ERROR("bulk trace read failed");
return ERROR_FAIL;
}

View File

@ -42,25 +42,34 @@
static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
unsigned size, uint32_t *bytes_read)
{
*bytes_read = jtag_libusb_bulk_read(low->libusb_dev,
int ret, tmp = 0;
ret = jtag_libusb_bulk_read(low->libusb_dev,
USBBLASTER_EPIN | \
LIBUSB_ENDPOINT_IN,
(char *)buf,
size,
100);
return ERROR_OK;
100, &tmp);
*bytes_read = tmp;
return ret;
}
static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
int size, uint32_t *bytes_written)
{
*bytes_written = jtag_libusb_bulk_write(low->libusb_dev,
int ret, tmp = 0;
ret = jtag_libusb_bulk_write(low->libusb_dev,
USBBLASTER_EPOUT | \
LIBUSB_ENDPOINT_OUT,
(char *)buf,
size,
100);
return ERROR_OK;
100, &tmp);
*bytes_written = tmp;
return ret;
}
static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev,