ChangeSet 1.1325.4.11, 2003/09/23 17:18:18-07:00, david-b@pacbell.net [PATCH] USB: usb gadgetfs updates Some small updates: - Sometimes read requests can be satisfied directly from the OUT fifo. This fixes a bug where the return code from usb_ep_queue() overwrite the transfer status, which in that case was set _before_ that call returned. (Synchronous behavior; not the usual async completion.) - In the same vein, usb_ep_dequeue() doesn't need to be synchronous -- though so far most controller drivers have implemented it that way. So drop the spinlock before the wait_event() sleep. - Some debug messages are more useful AFTER the event than before. - The only descriptor fetches user mode drivers will need to handle are for string descriptors. Stall all other requests, like ones for other-speed configs on single-speed devices. drivers/usb/gadget/inode.c | 34 +++++++++++++++++++++------------- 1 files changed, 21 insertions(+), 13 deletions(-) diff -Nru a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c --- a/drivers/usb/gadget/inode.c Thu Sep 25 14:31:44 2003 +++ b/drivers/usb/gadget/inode.c Thu Sep 25 14:31:44 2003 @@ -354,6 +354,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) { DECLARE_COMPLETION (done); + int value; spin_lock_irq (&epdata->dev->lock); if (likely (epdata->ep != NULL)) { @@ -363,14 +364,12 @@ req->complete = epio_complete; req->buf = buf; req->length = len; - epdata->status = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); + value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); } else - epdata->status = -ENODEV; + value = -ENODEV; spin_unlock_irq (&epdata->dev->lock); - if (epdata->status == 0) { - int value; - + if (likely (value == 0)) { value = wait_event_interruptible (done.wait, done.done); if (value != 0) { spin_lock_irq (&epdata->dev->lock); @@ -378,17 +377,21 @@ DBG (epdata->dev, "%s i/o interrupted\n", epdata->name); usb_ep_dequeue (epdata->ep, epdata->req); + spin_unlock_irq (&epdata->dev->lock); + wait_event (done.wait, done.done); - if (epdata->status == 0) - epdata->status = value; + if (epdata->status == -ECONNRESET) + epdata->status = -EINTR; } else { + spin_unlock_irq (&epdata->dev->lock); + DBG (epdata->dev, "endpoint gone\n"); epdata->status = -ENODEV; } - spin_unlock_irq (&epdata->dev->lock); } + return epdata->status; } - return epdata->status; + return value; } @@ -424,10 +427,12 @@ if (unlikely (!kbuf)) goto free1; - VDEBUG (data->dev, "%s read %d OUT\n", data->name, len); value = ep_io (data, kbuf, len); + VDEBUG (data->dev, "%s read %d OUT, status %d\n", + data->name, len, value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; + free1: up (&data->lock); kfree (kbuf); @@ -470,8 +475,9 @@ goto free1; } - VDEBUG (data->dev, "%s write %d IN\n", data->name, len); value = ep_io (data, kbuf, len); + VDEBUG (data->dev, "%s write %d IN, status %d\n", + data->name, len, value); free1: up (&data->lock); kfree (kbuf); @@ -1200,9 +1206,11 @@ if (value >= 0) value = min (ctrl->wLength, (u16) value); break; - - default: + case USB_DT_STRING: goto unrecognized; + + default: // all others are errors + break; } break;