summaryrefslogtreecommitdiff
path: root/libusb/core.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2009-11-07 10:43:59 +0000
committerDaniel Drake <dsd@gentoo.org>2009-11-07 10:46:12 +0000
commit11d591058e3f105b0e90c23bbf58b18de691e690 (patch)
treef495ea0db1458d2117c477584ef8103a8396e84c /libusb/core.c
parentf796c9528a71aa55326b6f0c9c7c5ec073d2bf92 (diff)
downloadlibusbx-11d591058e3f105b0e90c23bbf58b18de691e690.tar.gz
Update documentation about early completion caveats
Diffstat (limited to 'libusb/core.c')
-rw-r--r--libusb/core.c91
1 files changed, 40 insertions, 51 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 92eb6bf..7e4fd24 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -239,61 +239,50 @@ if (cfg != desired)
* The above method works because once an interface is claimed, no application
* or driver is able to select another configuration.
*
- * \section cancel Cancellation, early completion and timeouts
+ * \section earlycomp Early transfer completion
*
* NOTE: This section is currently Linux-centric. I am not sure if any of these
* considerations apply to Darwin or other platforms.
*
- * Cancellation of transfers can produce some slightly undesirable results.
- * It is important to understand that a transfer timing out can also result in
- * cancellation, as can a transfer that completes early (with a short packet).
- *
- * The timeout case is easy to comprehend; if a transfer times out, libusb
- * will cancel it at the point of timeout and inform you of this. Hence timeout
- * equals cancellation.
- *
- * The early completion case needs a little more explanation: When you submit
- * a large transfer, libusb may need to divide it into several smaller
- * sub-transfers which are then submitted to the host controller in parallel
- * for performance reasons. If one sub-transfer completes early, libusb then
- * needs to cancel all the subsequent sub-transfers before returning the result
- * to you.
- *
- * All forms of cancellation including the usual libusb_cancel_transfer() can
- * add some complications as it is possible that data transfer may be happening
- * while libusb is performing cancellation. This can lead to the following
- * kinds of situations:
- * - A transfer may timeout or be cancelled by the user. While libusb is
- * cancelling the transfer (which may consist of several sub-transfers
- * which libusb has to cancel one-by-one), data may start to be transferred.
- * libusb will report successful cancellation as usual, and will reflect the
- * situation with the \ref libusb_transfer::actual_length "actual_length"
- * field of the transfer, and for device-to-host transfers, the appropriate
- * amount of data will be present in \ref libusb_transfer::buffer "buffer").
- * - Similarly, a few USB-level packets within the transfer may already have
- * been transferred when the timeout/cancellation occurred, and more
- * packets may complete during the time needed to cancel the transfer.
- * - A non-ultimate sub-transfer within a transfer may complete with a short
- * packet, prompting libusb to immediately cancel all subsequent
- * sub-transfers and report early completion. However, during the time
- * needed to cancel the subsequent transfers, more data may be transferred.
- * This is a difficult situation because the libusb API does not currently
- * have a way of indicating the point at which the transfer ended relative
- * to the surplus data that was transferred.
- *
- * In all cases where the transfer is a device-to-host transfer and surplus
- * data is recieved as above, libusb places it in the transfer buffer as if
- * it had arrived contiguously and updates
- * \ref libusb_transfer::actual_length "actual_length" accordingly.
- *
- * We hope to eliminate some of these difficulties in the near future, but
- * kernel changes may be required.
- *
- * Ultimately, if you cancel a transfer before it has completed then you are
- * obligated to handle the above caveats and to resynchronize with the device
- * at the application level. Also, remember that timeouts are simply time-based
- * cancellations which libusb makes convenient for you, hence the same
- * considerations apply.
+ * When a transfer completes early (i.e. when less data is received/sent in
+ * any one packet than the transfer buffer allows for) then libusb is designed
+ * to terminate the transfer immediately, not transferring or receiving any
+ * more data unless other transfers have been queued by the user.
+ *
+ * On legacy platforms, libusb is unable to do this in all situations. After
+ * the incomplete packet occurs, "surplus" data may be transferred. Prior to
+ * libusb v1.0.2, this information was lost (and for device-to-host transfers,
+ * the corresponding data was discarded). As of libusb v1.0.3, this information
+ * is kept (the data length of the transfer is updated) and, for device-to-host
+ * transfesr, any surplus data was added to the buffer. Still, this is not
+ * a nice solution because it loses the information about the end of the short
+ * packet, and the user probably wanted that surplus data to arrive in the next
+ * logical transfer.
+ *
+ * A previous workaround was to only ever submit transfers of size 16kb or
+ * less.
+ *
+ * As of libusb v1.0.4 and Linux v2.6.32, this is fixed. A technical
+ * explanation of this issue follows.
+ *
+ * When you ask libusb to submit a bulk transfer larger than 16kb in size,
+ * libusb breaks it up into a number of smaller subtransfers. This is because
+ * the usbfs kernel interface only accepts transfers of up to 16kb in size.
+ * The subtransfers are submitted all at once so that the kernel can queue
+ * them at the hardware level, therefore maximizing bus throughput.
+ *
+ * On legacy platforms, this caused problems when transfers completed early
+ * Upon this event, the kernel would terminate all further packets in that
+ * subtransfer (but not any following ones). libusb would note this event and
+ * immediately cancel any following subtransfers that had been queued,
+ * but often libusb was not fast enough, and the following subtransfers had
+ * started before libusb got around to cancelling them.
+ *
+ * Thanks to an API extension to usbfs, this is fixed with recent kernel and
+ * libusb releases. The solution was to allow libusb to communicate to the
+ * kernel where boundaries occur between logical libusb-level transfers. When
+ * a short transfer (or other error) occurs, the kernel will cancel all the
+ * subtransfers until the boundary without allowing those transfers to start.
*/
/**