From: Daniel Drake Date: Sat, 7 Nov 2009 10:43:59 +0000 (+0000) Subject: Update documentation about early completion caveats X-Git-Tag: upstream/1.0.21~959 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=11d591058e3f105b0e90c23bbf58b18de691e690;p=platform%2Fupstream%2Flibusb.git Update documentation about early completion caveats --- 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. */ /** diff --git a/libusb/io.c b/libusb/io.c index b58eafa..65c2cf4 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -323,6 +323,10 @@ if (r == 0 && actual_length == sizeof(data)) { * Freeing the transfer after it has been cancelled but before cancellation * has completed will result in undefined behaviour. * + * When a transfer is cancelled, some of the data may have been transferred. + * libusb will communicate this to you in the transfer callback. Do not assume + * that no data was transferred. + * * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints * * If your device does not have predictable transfer sizes (or it misbehaves),