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 Signed-off-by: Greg Kroah-Hartman 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);