Skip to content

Commit

Permalink
jtag_libusb_bulk_read|write: return error code instead of size
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-on: http://openocd.zylin.com/4590
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <[email protected]>
  • Loading branch information
olerem committed Jan 22, 2020
1 parent f980995 commit d612baa
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 89 deletions.
38 changes: 25 additions & 13 deletions src/jtag/aice/aice_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
16 changes: 7 additions & 9 deletions src/jtag/drivers/ft232r.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
23 changes: 11 additions & 12 deletions src/jtag/drivers/kitprog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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++) {
Expand Down
42 changes: 38 additions & 4 deletions src/jtag/drivers/libusb0_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
{
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/jtag/drivers/libusb0_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
59 changes: 49 additions & 10 deletions src/jtag/drivers/libusb1_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
{
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/jtag/drivers/libusb1_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
/**
Expand Down
8 changes: 4 additions & 4 deletions src/jtag/drivers/opendous.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
14 changes: 6 additions & 8 deletions src/jtag/drivers/openjtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
17 changes: 9 additions & 8 deletions src/jtag/drivers/osbdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit d612baa

Please sign in to comment.