ChangeSet 1.1760.26.11, 2004/06/24 10:43:02-07:00, david-b@pacbell.net

[PATCH] USB: usb gadget drivers should be stricter about ZLPs

Some USB device controllers make it easy to handle all the various ways
hosts interpret the USB spec about when control-IN transfers need to send
a ZLP ... they can just send one if the host asks, or start the status
stage whenever the host thinks it's time.  Other controllers make it hard
to be forgiving in those cases.

This patch updates all the gadget drivers to explicitly set the req->zero
flag to reflect whether the USB spec says a ZLP "must" be sent by the
device.  "Forgiving" drivers won't notice the change, but the others need
to see this information passed down from the gadget driver.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>


 drivers/usb/gadget/ether.c        |    2 ++
 drivers/usb/gadget/file_storage.c |    2 ++
 drivers/usb/gadget/inode.c        |    2 ++
 drivers/usb/gadget/serial.c       |    2 ++
 drivers/usb/gadget/zero.c         |    2 ++
 5 files changed, 10 insertions(+)


diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
--- a/drivers/usb/gadget/ether.c	2004-06-29 16:26:00 -07:00
+++ b/drivers/usb/gadget/ether.c	2004-06-29 16:26:00 -07:00
@@ -1597,6 +1597,8 @@
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
+		req->zero = value < ctrl->wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DEBUG (dev, "ep_queue --> %d\n", value);
diff -Nru a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
--- a/drivers/usb/gadget/file_storage.c	2004-06-29 16:26:00 -07:00
+++ b/drivers/usb/gadget/file_storage.c	2004-06-29 16:26:00 -07:00
@@ -1465,6 +1465,8 @@
 	/* Respond with data/status or defer until later? */
 	if (rc >= 0 && rc != DELAYED_STATUS) {
 		fsg->ep0req->length = rc;
+		fsg->ep0req->zero = rc < ctrl->wLength
+				&& (rc % gadget->ep0->maxpacket) == 0;
 		fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
 				"ep0-in" : "ep0-out");
 		rc = ep0_queue(fsg);
diff -Nru a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
--- a/drivers/usb/gadget/inode.c	2004-06-29 16:26:00 -07:00
+++ b/drivers/usb/gadget/inode.c	2004-06-29 16:26:00 -07:00
@@ -1320,6 +1320,8 @@
 	/* proceed with data transfer and status phases? */
 	if (value >= 0 && dev->state != STATE_SETUP) {
 		req->length = value;
+		req->zero = value < ctrl->wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
--- a/drivers/usb/gadget/serial.c	2004-06-29 16:26:00 -07:00
+++ b/drivers/usb/gadget/serial.c	2004-06-29 16:26:00 -07:00
@@ -1573,6 +1573,8 @@
 	/* respond with data transfer before status phase? */
 	if (ret >= 0) {
 		req->length = ret;
+		req->zero = ret < ctrl->wLength
+				&& (ret % gadget->ep0->maxpacket) == 0;
 		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
 		if (ret < 0) {
 			printk(KERN_ERR
diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- a/drivers/usb/gadget/zero.c	2004-06-29 16:26:00 -07:00
+++ b/drivers/usb/gadget/zero.c	2004-06-29 16:26:00 -07:00
@@ -1037,6 +1037,8 @@
 	/* respond with data transfer before status phase? */
 	if (value >= 0) {
 		req->length = value;
+		req->zero = value < ctrl->wLength
+				&& (value % gadget->ep0->maxpacket) == 0;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
