From 603bba67b96b35d4bc64afc9006b106c89ffba52 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 3 Oct 2013 11:50:45 +1000 Subject: [PATCH] Treat any unexpected timeouts waiting for async transfers as though there may be a usb halt condition and attempt to clear the halt before cancelling the tranfer. --- usbutils.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/usbutils.c b/usbutils.c index 14a2bf4a..dc983b0d 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2228,6 +2228,7 @@ static void LIBUSB_CALL bulk_callback(struct libusb_transfer *transfer) * use our own timer to cancel the request if we go beyond the timeout. */ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeout) { + struct libusb_transfer *transfer= ut->transfer; struct timespec ts_now, ts_end; struct timeval tv_now; int ret; @@ -2239,15 +2240,22 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeraddspec(&ts_end, &ts_now); ret = pthread_cond_timedwait(&ut->cond, &ut->mutex, &ts_end); if (ret) { - libusb_cancel_transfer(ut->transfer); + /* Assume that if we timed out on the conditional then the + * transfer has stalled for some reason and attempt to clear + * a halt as a solution. Then cancel the transaction, treating + * it the same as a timeout. */ + libusb_clear_halt(transfer->dev_handle, transfer->endpoint); + libusb_cancel_transfer(transfer); + + /* Now wait for the callback function to be invoked. */ pthread_cond_wait(&ut->cond, &ut->mutex); /* Fake the timed out message since it's effectively that */ ret = LIBUSB_TRANSFER_TIMED_OUT; } else - ret = ut->transfer->status; + ret = transfer->status; /* No need to sort out mutexes here since they won't be reused */ - *transferred = ut->transfer->actual_length; - libusb_free_transfer(ut->transfer); + *transferred = transfer->actual_length; + libusb_free_transfer(transfer); return ret; }