* 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
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
/** 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
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 */
return 0;
}
- /* FIXME: research what other status codes may exist */
if (urb->status != 0)
usbi_warn("unrecognised urb status %d", urb->status);
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)
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;
}
* 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,
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;
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;
* \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,
*
* \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(