* 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.
+ *
+ * \section zlp Zero length packets
+ *
+ * - libusb is able to send a packet of zero length to an endpoint simply by
+ * submitting a transfer of zero length. On Linux, this did not work with
+ * libusb versions prior to 1.0.3 and kernel versions prior to 2.6.31.
+ * - The \ref libusb_transfer_flags::LIBUSB_TRANSFER_ADD_ZERO_PACKET
+ * "LIBUSB_TRANSFER_ADD_ZERO_PACKET" flag is currently only supported on Linux.
*/
/**
* \returns 0 on success
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
* \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted.
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported
+ * by the operating system.
* \returns another LIBUSB_ERROR code on other failure
*/
int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
* from your transfer callback, as this will result in a double-free
* when this flag is acted upon. */
LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2,
+
+ /** Terminate transfers that are a multiple of the endpoint's
+ * wMaxPacketSize with an extra zero length packet. This is useful
+ * when a device protocol mandates that each logical request is
+ * terminated by an incomplete packet (i.e. the logical requests are
+ * not separated by other means).
+ *
+ * This flag only affects host-to-device transfers to bulk and interrupt
+ * endpoints. In other situations, it is ignored.
+ *
+ * This flag only affects transfers with a length that is a multiple of
+ * the endpoint's wMaxPacketSize. On transfers of other lengths, this
+ * flag has no effect. Therefore, if you are working with a device that
+ * needs a ZLP whenever the end of the logical request falls on a packet
+ * boundary, then it is sensible to set this flag on <em>every</em>
+ * transfer (you do not have to worry about only setting it on transfers
+ * that end on the boundary).
+ *
+ * This flag is currently only supported on Linux.
+ * On other systems, libusb_submit_transfer() will return
+ * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
+ *
+ * Available since libusb-1.0.9.
+ */
+ LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
};
/** \ingroup asyncio
/* are we reading or writing? */
is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+ if (!is_read && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+
if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
*/
static int supports_flag_bulk_continuation = -1;
+/* Linux 2.6.31 fixes support for the zero length packet URB flag. This
+ * allows us to mark URBs that should be followed by a zero length data
+ * packet, which can be required by device- or class-specific protocols.
+ */
+static int supports_flag_zero_packet = -1;
+
/* clock ID for monotonic clock, as not all clock sources are available on all
* systems. appropriate choice made at initialization time. */
static clockid_t monotonic_clkid = -1;
if (supports_flag_bulk_continuation)
usbi_dbg("bulk continuation flag supported");
+ if (-1 == supports_flag_zero_packet) {
+ /* zero length packet URB flag fixed since Linux 2.6.31 */
+ supports_flag_zero_packet = kernel_version_ge(2,6,31);
+ if (-1 == supports_flag_zero_packet) {
+ usbi_err(ctx, "error checking for zero length packet support");
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
+ if (supports_flag_zero_packet)
+ usbi_dbg("zero length packet flag supported");
+
r = stat(SYSFS_DEVICE_PATH, &statbuf);
if (r == 0 && S_ISDIR(statbuf.st_mode)) {
DIR *devices = opendir(SYSFS_DEVICE_PATH);
if (tpriv->urbs)
return LIBUSB_ERROR_BUSY;
+ if (is_out && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET &&
+ !supports_flag_zero_packet)
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+
/* usbfs places a 16kb limit on bulk URBs. we divide up larger requests
* into smaller units to meet such restriction, then fire off all the
* units at once. it would be simpler if we just fired one unit at a time,
if (i > 0 && supports_flag_bulk_continuation)
urb->flags |= USBFS_URB_BULK_CONTINUATION;
+ /* we have already checked that the flag is supported */
+ if (is_out && i == num_urbs - 1 &&
+ transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+ urb->flags |= USBFS_URB_ZERO_PACKET;
+
r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
if (r < 0) {
if (errno == ENODEV) {
#define USBFS_URB_ISO_ASAP 0x02
#define USBFS_URB_BULK_CONTINUATION 0x04
#define USBFS_URB_QUEUE_BULK 0x10
+#define USBFS_URB_ZERO_PACKET 0x40
enum usbfs_urb_type {
USBFS_URB_TYPE_ISO = 0,
err = LIBUSB_ERROR_NOT_SUPPORTED;
break;
}
- /* PASSTHROUGH */
+ err = _sync_gen_transfer(itransfer);
+ break;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ if (0 == transfer->endpoint & LIBUSB_ENDPOINT_IN &&
+ transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
+ err = LIBUSB_ERROR_NOT_SUPPORTED;
+ break;
+ }
err = _sync_gen_transfer(itransfer);
break;
}
return submit_control_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ if (0 == transfer->endpoint & LIBUSB_ENDPOINT_IN &&
+ transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+ return LIBUSB_ERROR_NOT_SUPPORTED;
return submit_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return submit_iso_transfer(itransfer);