diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-10-02 08:45:08 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-10-02 08:45:08 -0400 |
commit | 59458f40e25915a355d8b1d701425fe9f4f9ea23 (patch) | |
tree | f1c9a2934df686e36d75f759ab7313b6f0e0e5f9 /drivers/usb/gadget | |
parent | 825f9075d74028d11d7f5932f04e1b5db3022b51 (diff) | |
parent | d834c16516d1ebec4766fc58c059bf01311e6045 (diff) | |
download | linux-3.10-59458f40e25915a355d8b1d701425fe9f4f9ea23.tar.gz linux-3.10-59458f40e25915a355d8b1d701425fe9f4f9ea23.tar.bz2 linux-3.10-59458f40e25915a355d8b1d701425fe9f4f9ea23.zip |
Merge branch 'master' into gfs2
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 6 | ||||
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 33 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 35 | ||||
-rw-r--r-- | drivers/usb/gadget/inode.c | 82 | ||||
-rw-r--r-- | drivers/usb/gadget/omap_udc.c | 2 |
5 files changed, 110 insertions, 48 deletions
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d00958a01cf..77beba485a8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1658,7 +1658,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) { + if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; } @@ -1720,7 +1720,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91_BASE_UDP, SZ_16K); + release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } @@ -1742,7 +1742,7 @@ static int __devexit at91udc_remove(struct platform_device *pdev) free_irq(udc->board.vbus_pin, udc); free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); - release_mem_region(AT91_BASE_UDP, SZ_16K); + release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); clk_put(udc->iclk); clk_put(udc->fclk); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index fdab97a27c0..4d2946e540c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -816,15 +816,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = driver->bind (&dum->gadget)) != 0) { - dum->driver = NULL; - dum->gadget.dev.driver = NULL; - return retval; - } + if ((retval = driver->bind (&dum->gadget)) != 0) + goto err_bind_gadget; driver->driver.bus = dum->gadget.dev.parent->bus; - driver_register (&driver->driver); - device_bind_driver (&dum->gadget.dev); + if ((retval = driver_register (&driver->driver)) != 0) + goto err_register; + if ((retval = device_bind_driver (&dum->gadget.dev)) != 0) + goto err_bind_driver; /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); @@ -834,6 +833,19 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; + +err_bind_driver: + driver_unregister (&driver->driver); +err_register: + driver->unbind (&dum->gadget); + spin_lock_irq (&dum->lock); + dum->pullup = 0; + set_link_state (dum); + spin_unlock_irq (&dum->lock); +err_bind_gadget: + dum->driver = NULL; + dum->gadget.dev.driver = NULL; + return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -916,7 +928,9 @@ static int dummy_udc_probe (struct platform_device *pdev) usb_get_hcd (dummy_to_hcd (dum)); platform_set_drvdata (pdev, dum); - device_create_file (&dum->gadget.dev, &dev_attr_function); + rc = device_create_file (&dum->gadget.dev, &dev_attr_function); + if (rc < 0) + device_unregister (&dum->gadget.dev); return rc; } @@ -1864,8 +1878,7 @@ static int dummy_start (struct usb_hcd *hcd) #endif /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ - device_create_file (dummy_dev(dum), &dev_attr_urbs); - return 0; + return device_create_file (dummy_dev(dum), &dev_attr_urbs); } static void dummy_stop (struct usb_hcd *hcd) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8d7f1e84cd7..c83d3b6c68f 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -567,6 +567,7 @@ struct lun { unsigned int ro : 1; unsigned int prevent_medium_removal : 1; unsigned int registered : 1; + unsigned int info_valid : 1; u32 sense_data; u32 sense_data_info; @@ -1656,6 +1657,7 @@ static int do_read(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; break; @@ -1691,6 +1693,7 @@ static int do_read(struct fsg_dev *fsg) if (nread < amount) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -1785,6 +1788,7 @@ static int do_write(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = usb_offset >> 9; + curlun->info_valid = 1; continue; } amount -= (amount & 511); @@ -1827,6 +1831,7 @@ static int do_write(struct fsg_dev *fsg) if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -1868,6 +1873,7 @@ static int do_write(struct fsg_dev *fsg) if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -2010,6 +2016,7 @@ static int do_verify(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -2036,6 +2043,7 @@ static int do_verify(struct fsg_dev *fsg) if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } file_offset += nread; @@ -2079,6 +2087,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) struct lun *curlun = fsg->curlun; u8 *buf = (u8 *) bh->buf; u32 sd, sdinfo; + int valid; /* * From the SCSI-2 spec., section 7.9 (Unit attention condition): @@ -2106,15 +2115,18 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) fsg->bad_lun_okay = 1; sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; sdinfo = 0; + valid = 0; } else { sd = curlun->sense_data; sdinfo = curlun->sense_data_info; + valid = curlun->info_valid << 7; curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } memset(buf, 0, 18); - buf[0] = 0x80 | 0x70; // Valid, current error + buf[0] = valid | 0x70; // Valid, current error buf[2] = SK(sd); put_be32(&buf[3], sdinfo); // Sense information buf[7] = 18 - 8; // Additional sense length @@ -2703,6 +2715,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, if (fsg->cmnd[0] != SC_REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } } else { fsg->curlun = curlun = NULL; @@ -3332,6 +3345,7 @@ static void handle_exception(struct fsg_dev *fsg) curlun->sense_data = curlun->unit_attention_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } fsg->state = FSG_STATE_IDLE; } @@ -3873,21 +3887,26 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; curlun->ro = mod_data.ro[i]; + curlun->dev.release = lun_release; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; dev_set_drvdata(&curlun->dev, fsg); snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); - if ((rc = device_register(&curlun->dev)) != 0) + if ((rc = device_register(&curlun->dev)) != 0) { INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - kref_get(&fsg->ref); + goto out; + } + if ((rc = device_create_file(&curlun->dev, + &dev_attr_ro)) != 0 || + (rc = device_create_file(&curlun->dev, + &dev_attr_file)) != 0) { + device_unregister(&curlun->dev); + goto out; } + curlun->registered = 1; + kref_get(&fsg->ref); if (mod_data.file[i] && *mod_data.file[i]) { if ((rc = open_backing_file(curlun, diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 4655522a08d..86924f9cdd7 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -342,7 +342,7 @@ fail: static ssize_t ep_io (struct ep_data *epdata, void *buf, unsigned len) { - DECLARE_COMPLETION (done); + DECLARE_COMPLETION_ONSTACK (done); int value; spin_lock_irq (&epdata->dev->lock); @@ -533,7 +533,8 @@ struct kiocb_priv { struct usb_request *req; struct ep_data *epdata; void *buf; - char __user *ubuf; /* NULL for writes */ + const struct iovec *iv; + unsigned long nr_segs; unsigned actual; }; @@ -561,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) static ssize_t ep_aio_read_retry(struct kiocb *iocb) { struct kiocb_priv *priv = iocb->private; - ssize_t status = priv->actual; - - /* we "retry" to get the right mm context for this: */ - status = copy_to_user(priv->ubuf, priv->buf, priv->actual); - if (unlikely(0 != status)) - status = -EFAULT; - else - status = priv->actual; - kfree(priv->buf); - kfree(priv); - return status; + ssize_t len, total; + int i; + + /* we "retry" to get the right mm context for this: */ + + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } + + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + aio_put_req(iocb); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -584,7 +600,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->ubuf == NULL + if (priv->iv == NULL || unlikely(req->actual == 0) || unlikely(kiocbIsCancelled(iocb))) { kfree(req->buf); @@ -619,7 +635,8 @@ ep_aio_rwtail( char *buf, size_t len, struct ep_data *epdata, - char __user *ubuf + const struct iovec *iv, + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -634,7 +651,8 @@ fail: return value; } iocb->private = priv; - priv->ubuf = ubuf; + priv->iv = iv; + priv->nr_segs = nr_segs; value = get_ready_ep(iocb->ki_filp->f_flags, epdata); if (unlikely(value < 0)) { @@ -674,41 +692,53 @@ fail: kfree(priv); put_ep(epdata); } else - value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED); + value = (iv ? -EIOCBRETRY : -EIOCBQUEUED); return value; } static ssize_t -ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) +ep_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); + + buf = kmalloc(iocb->ki_left, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; + iocb->ki_retry = ep_aio_read_retry; - return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); + return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs); } static ssize_t -ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) +ep_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; + size_t len = 0; + int i = 0; if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); + + buf = kmalloc(iocb->ki_left, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; - if (unlikely(copy_from_user(buf, ubuf, len) != 0)) { - kfree(buf); - return -EFAULT; + + for (i=0; i < nr_segs; i++) { + if (unlikely(copy_from_user(&buf[len], iov[i].iov_base, + iov[i].iov_len) != 0)) { + kfree(buf); + return -EFAULT; + } + len += iov[i].iov_len; } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL); + return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0); } /*----------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 0a64504c254..8c18df86983 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2869,7 +2869,7 @@ cleanup0: static int __exit omap_udc_remove(struct platform_device *pdev) { - DECLARE_COMPLETION(done); + DECLARE_COMPLETION_ONSTACK(done); if (!udc) return -ENODEV; |