From 3a99da700874289ab4b000840cd8e0e0cbe8646e Mon Sep 17 00:00:00 2001
From: Nikias Bassen <nikias@gmx.li>
Date: Sat, 29 Aug 2009 16:40:31 +0200
Subject: [PATCH] Linux: Correctly terminate bulk packets of size wMaxPacketSize

... and multiples. This patch will automatically set the URB_ZERO_PACKET
flag if the packet size is a multiple of the endpoint's wMaxPacketSize
so that the kernel actually submits bulk packet. This is only for
outgoing transfers.
---
 libusb/os/linux_usbfs.c |   18 ++++++++++++++++++
 libusb/os/linux_usbfs.h |    1 +
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 1280188..ad1dc89 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1265,6 +1265,8 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
 	int r;
 	int i;
 	size_t alloc_size;
+	uint8_t is_read; /* 0 = we're reading, 1 = we're writing */
+	uint8_t flag_zero_packet = 0; /* 0 = don't flag, 1 = flag */
 
 	if (tpriv->urbs)
 		return LIBUSB_ERROR_BUSY;
@@ -1294,6 +1296,17 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
 	tpriv->num_retired = 0;
 	tpriv->reap_action = NORMAL;
 
+	/* are we reading or writing? */
+	is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+	if (!is_read) {
+		libusb_device *tdev = libusb_get_device(transfer->dev_handle);
+ 		int max_packet_size = libusb_get_max_packet_size(tdev, transfer->endpoint);
+		if ((max_packet_size > 0) && (transfer->length > 0)
+			&& (transfer->length % max_packet_size == 0)) {
+			flag_zero_packet = 1;
+		}
+	}
+
 	for (i = 0; i < num_urbs; i++) {
 		struct usbfs_urb *urb = &urbs[i];
 		urb->usercontext = itransfer;
@@ -1307,6 +1320,11 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer,
 		else
 			urb->buffer_length = MAX_BULK_BUFFER_LENGTH;
 
+		if ((i == num_urbs - 1) && (flag_zero_packet)) {
+			printf("flagging URB_ZERO_PACKET\n");
+			urb->flags |= USBFS_URB_ZERO_PACKET;
+		}
+
 		r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
 		if (r < 0) {
 			int j;
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
index fdf5e9b..9ed0b4f 100644
--- a/libusb/os/linux_usbfs.h
+++ b/libusb/os/linux_usbfs.h
@@ -63,6 +63,7 @@ struct usbfs_getdriver {
 #define USBFS_URB_DISABLE_SPD	1
 #define USBFS_URB_ISO_ASAP	2
 #define USBFS_URB_QUEUE_BULK	0x10
+#define USBFS_URB_ZERO_PACKET	0x40
 
 enum usbfs_urb_type {
 	USBFS_URB_TYPE_ISO = 0,
-- 
1.6.0.4


