Overflow handling
authorDaniel Drake <dsd@gentoo.org>
Sat, 21 Jun 2008 04:04:53 +0000 (23:04 -0500)
committerDaniel Drake <dsd@gentoo.org>
Sat, 21 Jun 2008 04:05:09 +0000 (23:05 -0500)
TODO
libusb/io.c
libusb/libusb.h
libusb/os/linux_usbfs.c
libusb/sync.c

diff --git a/TODO b/TODO
index 907835b..5cb36db 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
 new sysfs descriptors format
-configuration API
 contexts
 event handling/threads issue
 
@@ -11,3 +10,4 @@ offer API to create/destroy handle_events thread
 isochronous sync I/O?
 exposing of parent-child device relationships
 "usb primer" introduction docs
+more examples
index f659d24..9760432 100644 (file)
@@ -186,6 +186,49 @@ if (r == 0 && actual_length == sizeof(data)) {
  * \ref asyncio "asynchronous I/O API" documentation pages.
  */
 
+
+/**
+ * \page packetoverflow Packets and overflows
+ *
+ * \section packets Packet abstraction
+ *
+ * The USB specifications describe how data is transmitted in packets, with
+ * constraints on packet size defined by endpoint descriptors. The host must
+ * not send data payloads larger than the endpoint's maximum packet size.
+ *
+ * libusb and the underlying OS abstract out the packet concept, allowing you
+ * to request transfers of any size. Internally, the request will be divided
+ * up into correctly-sized packets. You do not have to be concerned with
+ * packet sizes, but there is one exception when considering overflows.
+ *
+ * \section overflow Bulk/interrupt transfer overflows
+ *
+ * When requesting data on a bulk endpoint, libusb requires you to supply a
+ * buffer and the maximum number of bytes of data that libusb can put in that
+ * buffer. However, the size of the buffer is not communicated to the device -
+ * the device is just asked to send any amount of data.
+ *
+ * There is no problem if the device sends an amount of data that is less than
+ * or equal to the buffer size. libusb reports this condition to you through
+ * the \ref libusb_transfer::actual_length "libusb_transfer.actual_length"
+ * field.
+ *
+ * Problems may occur if the device attempts to send more data than can fit in
+ * the buffer. libusb reports LIBUSB_TRANSFER_OVERFLOW for this condition but
+ * other behaviour is largely undefined: actual_length may or may not be
+ * accurate, the chunk of data that can fit in the buffer (before overflow)
+ * may or may not have been transferred.
+ *
+ * Overflows are nasty, but can be avoided. Even though you were told to
+ * ignore packets above, think about the lower level details: each transfer is
+ * split into packets (typically small, with a maximum size of 512 bytes).
+ * Overflows can only happen if the final packet in an incoming data transfer
+ * is smaller than the actual packet that the device wants to transfer.
+ * Therefore, you will never see an overflow if your transfer buffer size is a
+ * multiple of the endpoint's packet size: the final packet will either
+ * fill up completely or will be only partially filled.
+ */
+
 /**
  * @defgroup asyncio Asynchronous device I/O
  *
@@ -293,6 +336,14 @@ 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.
  *
+ * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints
+ *
+ * If your device does not have predictable transfer sizes (or it misbehaves),
+ * your application may submit a request for data on an IN endpoint which is
+ * smaller than the data that the device wishes to send. In some circumstances
+ * this will cause an overflow, which is a nasty condition to deal with. See
+ * the \ref packetoverflow page for discussion.
+ *
  * \section asyncctrl Considerations for control transfers
  *
  * The <tt>libusb_transfer</tt> structure is generic and hence does not
index 295de38..40d1a87 100644 (file)
@@ -593,20 +593,23 @@ enum libusb_error {
        /** Operation timed out */
        LIBUSB_ERROR_TIMEOUT = -7,
 
+       /** Overflow */
+       LIBUSB_ERROR_OVERFLOW = -8,
+
        /** Pipe error */
-       LIBUSB_ERROR_PIPE = -8,
+       LIBUSB_ERROR_PIPE = -9,
 
        /** System call interrupted (perhaps due to signal) */
-       LIBUSB_ERROR_INTERRUPTED = -9,
+       LIBUSB_ERROR_INTERRUPTED = -10,
 
        /** Insufficient memory */
-       LIBUSB_ERROR_NO_MEM = -10,
+       LIBUSB_ERROR_NO_MEM = -11,
 
        /** Operation not supported or unimplemented on this platform */
-       LIBUSB_ERROR_NOT_SUPPORTED = -11,
+       LIBUSB_ERROR_NOT_SUPPORTED = -12,
 
        /** Other error */
-       LIBUSB_ERROR_OTHER = -12,
+       LIBUSB_ERROR_OTHER = -99,
 };
 
 /** \ingroup asyncio
@@ -631,6 +634,9 @@ enum libusb_transfer_status {
 
        /** Device was disconnected */
        LIBUSB_TRANSFER_NO_DEVICE,
+
+       /** Device sent more data than requested */
+       LIBUSB_TRANSFER_OVERFLOW,
 };
 
 /** \ingroup asyncio
index 95c3e25..fb50d34 100644 (file)
@@ -1546,7 +1546,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer,
        usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status,
                urb_idx + 1, num_urbs);
 
-       if (urb->status == 0)
+       if (urb->status == 0 ||
+                       (urb->status == -EOVERFLOW && urb->actual_length > 0))
                itransfer->transferred += urb->actual_length;
 
        if (tpriv->reap_action != NORMAL) {
@@ -1570,6 +1571,11 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer,
                                usbi_err("CANCEL: completed URB not awaiting reap?");
                        else
                                tpriv->awaiting_reap--;
+               } else if (urb->status == -EPIPE || urb->status == -EOVERFLOW) {
+                       if (tpriv->awaiting_reap == 0)
+                               usbi_err("CANCEL: completed URB not awaiting reap?");
+                       else
+                               tpriv->awaiting_reap--;
                } else {
                        usbi_warn("unhandled CANCEL urb status %d", urb->status);
                }
@@ -1594,6 +1600,11 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer,
                usbi_dbg("detected endpoint stall");
                status = LIBUSB_TRANSFER_STALL;
                goto out;
+       } else if (urb->status == -EOVERFLOW) {
+               /* overflow can only ever occur in the last urb */
+               usbi_dbg("overflow, actual_length=%d", urb->actual_length);
+               status = LIBUSB_TRANSFER_OVERFLOW;
+               goto out;
        } else if (urb->status != 0) {
                usbi_warn("unrecognised urb status %d", urb->status);
        }
index 3a71428..55450c4 100644 (file)
@@ -191,6 +191,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
        case LIBUSB_TRANSFER_STALL:
                r = LIBUSB_ERROR_PIPE;
                break;
+       case LIBUSB_TRANSFER_OVERFLOW:
+               r = LIBUSB_ERROR_OVERFLOW;
+               break;
        case LIBUSB_TRANSFER_NO_DEVICE:
                r = LIBUSB_ERROR_NO_DEVICE;
                break;
@@ -238,6 +241,8 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
  * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates
  * <tt>transferred</tt>)
  * \returns LIBUSB_ERROR_PIPE if the endpoint halted
+ * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see
+ * \ref packetoverflow
  * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
  * \returns another LIBUSB_ERROR code on other failures
  */
@@ -285,6 +290,8 @@ 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 LIBUSB_ERROR_OVERFLOW if the device offered more data, see
+ * \ref packetoverflow
  * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
  * \returns another LIBUSB_ERROR code on other error
  */