summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2008-05-05 16:22:33 +0100
committerDaniel Drake <dsd@gentoo.org>2008-05-05 16:45:11 +0100
commita304eca71f22c6df7d70a901483b30f1b8e93378 (patch)
tree1ca25c3ec1db242980523f3ef47cc6dcf9f166c1
parent7da521954ba661d3f537440c31a84b66e974d56b (diff)
downloadlibusb-a304eca71f22c6df7d70a901483b30f1b8e93378.tar.gz
Detect endpoint halts and unsupported control requests
-rw-r--r--libusb/io.c4
-rw-r--r--libusb/libusb.h11
-rw-r--r--libusb/os/linux_usbfs.c25
-rw-r--r--libusb/sync.c10
4 files changed, 41 insertions, 9 deletions
diff --git a/libusb/io.c b/libusb/io.c
index 453ecce..ac153ce 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -332,6 +332,10 @@ if (r == 0 && actual_length == sizeof(data)) {
* and libusb_control_transfer_get_setup() functions within your transfer
* callback.
*
+ * Even though control endpoints do not halt, a completed control transfer
+ * may have a LIBUSB_TRANSFER_STALL status code. This indicates the control
+ * request was not supported.
+ *
* \section asyncintr Considerations for interrupt transfers
*
* All interrupt transfers are performed using the polling interval presented
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 5cce3fb..b568d36 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -524,9 +524,10 @@ enum libusb_error {
LIBUSB_ERROR_NOT_FOUND = -4,
LIBUSB_ERROR_BUSY = -5,
LIBUSB_ERROR_TIMEOUT = -6,
- LIBUSB_ERROR_NO_MEM = -7,
- LIBUSB_ERROR_NOT_SUPPORTED = -8,
- LIBUSB_ERROR_OTHER = -9,
+ LIBUSB_ERROR_PIPE = -7,
+ LIBUSB_ERROR_NO_MEM = -8,
+ LIBUSB_ERROR_NOT_SUPPORTED = -9,
+ LIBUSB_ERROR_OTHER = -10,
};
/** \ingroup asyncio
@@ -544,6 +545,10 @@ enum libusb_transfer_status {
/** Transfer was cancelled */
LIBUSB_TRANSFER_CANCELLED,
+
+ /** For bulk/interrupt endpoints: halt condition detected (endpoint
+ * stalled). For control endpoints: control request not supported. */
+ LIBUSB_TRANSFER_STALL,
};
/** \ingroup asyncio
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index ec7907f..22d6b6a 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1006,9 +1006,13 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer,
return 0;
}
- /* FIXME: research what other status codes may exist */
- if (urb->status != 0)
+ if (urb->status == -EPIPE) {
+ usbi_dbg("detected endpoint stall");
+ usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_STALL);
+ return 0;
+ } else if (urb->status != 0) {
usbi_warn("unrecognised urb status %d", urb->status);
+ }
/* if we're the last urb or we got less data than requested then we're
* done */
@@ -1090,7 +1094,6 @@ static int handle_iso_completion(struct usbi_transfer *itransfer,
return 0;
}
- /* FIXME: research what other status codes may exist */
if (urb->status != 0)
usbi_warn("unrecognised urb status %d", urb->status);
@@ -1109,6 +1112,8 @@ static int handle_control_completion(struct usbi_transfer *itransfer,
struct usbfs_urb *urb)
{
struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ int status;
+
usbi_dbg("handling completion status %d", urb->status);
if (urb->status == 0)
@@ -1122,13 +1127,21 @@ static int handle_control_completion(struct usbi_transfer *itransfer,
return 0;
}
- /* FIXME: research what other status codes may exist */
- if (urb->status != 0)
+ if (urb->status == -EPIPE) {
+ usbi_dbg("unsupported control request");
+ status = LIBUSB_TRANSFER_STALL;
+ goto out;
+ } else if (urb->status != 0) {
usbi_warn("unrecognised urb status %d", urb->status);
+ status = LIBUSB_TRANSFER_ERROR;
+ goto out;
+ }
itransfer->transferred = urb->actual_length;
+ status = LIBUSB_TRANSFER_COMPLETED;
+out:
free(tpriv->urbs);
- usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
+ usbi_handle_transfer_completion(itransfer, status);
return 0;
}
diff --git a/libusb/sync.c b/libusb/sync.c
index 77d01db..6f1f07b 100644
--- a/libusb/sync.c
+++ b/libusb/sync.c
@@ -60,6 +60,8 @@ static void ctrl_transfer_cb(struct libusb_transfer *transfer)
* value 0.
* \returns 0 on success
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out
+ * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the
+ * device
* \returns another LIBUSB_ERROR code on other failures
*/
API_EXPORTED int libusb_control_transfer(libusb_device_handle *dev_handle,
@@ -116,6 +118,9 @@ API_EXPORTED int libusb_control_transfer(libusb_device_handle *dev_handle,
case LIBUSB_TRANSFER_TIMED_OUT:
r = LIBUSB_ERROR_TIMEOUT;
break;
+ case LIBUSB_TRANSFER_STALL:
+ r = LIBUSB_ERROR_PIPE;
+ break;
default:
usbi_warn("unrecognised status code %d", transfer->status);
r = LIBUSB_ERROR_OTHER;
@@ -174,6 +179,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
case LIBUSB_TRANSFER_TIMED_OUT:
r = LIBUSB_ERROR_TIMEOUT;
break;
+ case LIBUSB_TRANSFER_STALL:
+ r = LIBUSB_ERROR_PIPE;
+ break;
default:
usbi_warn("unrecognised status code %d", transfer->status);
r = LIBUSB_ERROR_OTHER;
@@ -217,6 +225,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
* \returns 0 on success (and populates <tt>transferred</tt>)
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates
* <tt>transferred</tt>)
+ * \returns LIBUSB_ERROR_PIPE if the endpoint halted
* \returns another LIBUSB_ERROR code on other failures
*/
API_EXPORTED int libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
@@ -262,6 +271,7 @@ API_EXPORTED int libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
*
* \returns 0 on success (and populates <tt>transferred</tt>)
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out
+ * \returns LIBUSB_ERROR_PIPE if the endpoint halted
* \returns another LIBUSB_ERROR code on other error
*/
API_EXPORTED int libusb_interrupt_transfer(