diff options
Diffstat (limited to 'drivers/usb/gadget/inode.c')
| -rw-r--r-- | drivers/usb/gadget/inode.c | 177 |
1 files changed, 89 insertions, 88 deletions
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3ed73f49cf1..2e4ce770490 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -8,15 +8,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -33,6 +24,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/poll.h> +#include <linux/mmu_context.h> +#include <linux/aio.h> #include <linux/device.h> #include <linux/moduleparam.h> @@ -85,7 +78,6 @@ MODULE_LICENSE ("GPL"); /*----------------------------------------------------------------------*/ #define GADGETFS_MAGIC 0xaee71ee7 -#define DMA_ADDR_INVALID (~(dma_addr_t)0) /* /dev/gadget/$CHIP represents ep0 and the whole device */ enum ep0_state { @@ -386,8 +378,10 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* halt any endpoint by doing a "wrong direction" i/o call */ if (usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) + if (usb_endpoint_xfer_isoc(&data->desc)) { + mutex_unlock(&data->lock); return -EINVAL; + } DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); if (likely (data->ep != NULL)) @@ -429,8 +423,10 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* halt any endpoint by doing a "wrong direction" i/o call */ if (!usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) + if (usb_endpoint_xfer_isoc(&data->desc)) { + mutex_unlock(&data->lock); return -EINVAL; + } DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); if (likely (data->ep != NULL)) @@ -443,11 +439,9 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ value = -ENOMEM; - kbuf = kmalloc (len, GFP_KERNEL); - if (!kbuf) - goto free1; - if (copy_from_user (kbuf, buf, len)) { - value = -EFAULT; + kbuf = memdup_user(buf, len); + if (!kbuf) { + value = PTR_ERR(kbuf); goto free1; } @@ -456,7 +450,6 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) data->name, len, (int) value); free1: mutex_unlock(&data->lock); - kfree (kbuf); return value; } @@ -519,13 +512,16 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value) struct kiocb_priv { struct usb_request *req; struct ep_data *epdata; + struct kiocb *iocb; + struct mm_struct *mm; + struct work_struct work; void *buf; const struct iovec *iv; unsigned long nr_segs; unsigned actual; }; -static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) +static int ep_aio_cancel(struct kiocb *iocb) { struct kiocb_priv *priv = iocb->private; struct ep_data *epdata; @@ -534,7 +530,6 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) local_irq_disable(); epdata = priv->epdata; // spin_lock(&epdata->dev->lock); - kiocbSetCancelled(iocb); if (likely(epdata && epdata->ep && priv->req)) value = usb_ep_dequeue (epdata->ep, priv->req); else @@ -542,19 +537,15 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) // spin_unlock(&epdata->dev->lock); local_irq_enable(); - aio_put_req(iocb); return value; } -static ssize_t ep_aio_read_retry(struct kiocb *iocb) +static ssize_t ep_copy_to_user(struct kiocb_priv *priv) { - struct kiocb_priv *priv = iocb->private; ssize_t len, total; void *to_copy; int i; - /* we "retry" to get the right mm context for this: */ - /* copy stuff into user buffers */ total = priv->actual; len = 0; @@ -574,9 +565,26 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) if (total == 0) break; } + + return len; +} + +static void ep_user_copy_worker(struct work_struct *work) +{ + struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work); + struct mm_struct *mm = priv->mm; + struct kiocb *iocb = priv->iocb; + size_t ret; + + use_mm(mm); + ret = ep_copy_to_user(priv); + unuse_mm(mm); + + /* completing the iocb can drop the ctx and mm, don't touch mm after */ + aio_complete(iocb, ret, ret); + kfree(priv->buf); kfree(priv); - return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -602,14 +610,14 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) aio_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { - /* retry() won't report both; so we hide some faults */ + /* ep_copy_to_user() won't report both; we hide some faults */ if (unlikely(0 != req->status)) DBG(epdata->dev, "%s fault %d len %d\n", ep->name, req->status, req->actual); priv->buf = req->buf; priv->actual = req->actual; - kick_iocb(iocb); + schedule_work(&priv->work); } spin_unlock(&epdata->dev->lock); @@ -639,8 +647,10 @@ fail: return value; } iocb->private = priv; + priv->iocb = iocb; priv->iv = iv; priv->nr_segs = nr_segs; + INIT_WORK(&priv->work, ep_user_copy_worker); value = get_ready_ep(iocb->ki_filp->f_flags, epdata); if (unlikely(value < 0)) { @@ -648,10 +658,11 @@ fail: goto fail; } - iocb->ki_cancel = ep_aio_cancel; + kiocb_set_cancel_fn(iocb, ep_aio_cancel); get_ep(epdata); priv->epdata = epdata; priv->actual = 0; + priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */ /* each kiocb is coupled to one usb_request, but we can't * allocate or submit those if the host disconnected. @@ -680,7 +691,7 @@ fail: kfree(priv); put_ep(epdata); } else - value = (iv ? -EIOCBRETRY : -EIOCBQUEUED); + value = -EIOCBQUEUED; return value; } @@ -694,12 +705,11 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov, if (unlikely(usb_endpoint_dir_in(&epdata->desc))) return -EINVAL; - buf = kmalloc(iocb->ki_left, GFP_KERNEL); + buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; - iocb->ki_retry = ep_aio_read_retry; - return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs); + return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs); } static ssize_t @@ -714,7 +724,7 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov, if (unlikely(!usb_endpoint_dir_in(&epdata->desc))) return -EINVAL; - buf = kmalloc(iocb->ki_left, GFP_KERNEL); + buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); if (unlikely(!buf)) return -ENOMEM; @@ -828,18 +838,18 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) switch (data->dev->gadget->speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: - value = usb_ep_enable (ep, &data->desc); + ep->desc = &data->desc; + value = usb_ep_enable(ep); if (value == 0) data->state = STATE_EP_ENABLED; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ - value = usb_ep_enable (ep, &data->hs_desc); + ep->desc = &data->hs_desc; + value = usb_ep_enable(ep); if (value == 0) data->state = STATE_EP_ENABLED; break; -#endif default: DBG(data->dev, "unconnected, %s init abandoned\n", data->name); @@ -893,7 +903,6 @@ ep_open (struct inode *inode, struct file *fd) /* used before endpoint configuration */ static const struct file_operations ep_config_operations = { - .owner = THIS_MODULE, .llseek = no_llseek, .open = ep_open, @@ -923,7 +932,6 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) if (req->buf != dev->rbuf) { kfree(req->buf); req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; } req->complete = epio_complete; dev->setup_out_ready = 0; @@ -1046,6 +1054,8 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) // FIXME don't call this with the spinlock held ... if (copy_to_user (buf, dev->req->buf, len)) retval = -EFAULT; + else + retval = len; clean_req (dev->gadget->ep0, dev->req); /* NOTE userspace can't yet choose to stall */ } @@ -1254,12 +1264,13 @@ dev_release (struct inode *inode, struct file *fd) kfree (dev->buf); dev->buf = NULL; - put_dev (dev); /* other endpoints were all decoupled from this device */ spin_lock_irq(&dev->lock); dev->state = STATE_DEV_DISABLED; spin_unlock_irq(&dev->lock); + + put_dev (dev); return 0; } @@ -1325,7 +1336,6 @@ static const struct file_operations ep0_io_operations = { * Unrecognized ep0 requests may be handled in user space. */ -#ifdef CONFIG_USB_GADGET_DUALSPEED static void make_qualifier (struct dev_data *dev) { struct usb_qualifier_descriptor qual; @@ -1341,14 +1351,13 @@ static void make_qualifier (struct dev_data *dev) qual.bDeviceProtocol = desc->bDeviceProtocol; /* assumes ep0 uses the same value for both speeds ... */ - qual.bMaxPacketSize0 = desc->bMaxPacketSize0; + qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket; qual.bNumConfigurations = 1; qual.bRESERVED = 0; memcpy (dev->rbuf, &qual, sizeof qual); } -#endif static int config_buf (struct dev_data *dev, u8 type, unsigned index) @@ -1398,7 +1407,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } dev->state = STATE_DEV_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); @@ -1414,7 +1422,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->setup_abort = 1; req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; req->context = NULL; value = -EOPNOTSUPP; switch (ctrl->bRequest) { @@ -1426,9 +1433,9 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_DEVICE: value = min (w_length, (u16) sizeof *dev->dev); + dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket; req->buf = dev->dev; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!dev->hs_config) break; @@ -1438,7 +1445,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; case USB_DT_OTHER_SPEED_CONFIG: // FALLTHROUGH -#endif case USB_DT_CONFIG: value = config_buf (dev, w_value >> 8, @@ -1493,6 +1499,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) */ if (value == 0) { INFO (dev, "configuration #%d\n", dev->current_config); + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); if (dev->usermode_setup) { dev->setup_can_stall = 0; goto delegate; @@ -1500,7 +1507,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } break; -#ifndef CONFIG_USB_GADGET_PXA25X +#ifndef CONFIG_USB_PXA25X /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) @@ -1572,20 +1579,17 @@ delegate: static void destroy_ep_files (struct dev_data *dev) { - struct list_head *entry, *tmp; - DBG (dev, "%s %d\n", __func__, dev->state); /* dev->state must prevent interference */ -restart: spin_lock_irq (&dev->lock); - list_for_each_safe (entry, tmp, &dev->epfiles) { + while (!list_empty(&dev->epfiles)) { struct ep_data *ep; struct inode *parent; struct dentry *dentry; /* break link to FS */ - ep = list_entry (entry, struct ep_data, epfiles); + ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); list_del_init (&ep->epfiles); dentry = ep->dentry; ep->dentry = NULL; @@ -1608,8 +1612,7 @@ restart: dput (dentry); mutex_unlock (&parent->i_mutex); - /* fds may still be open */ - goto restart; + spin_lock_irq (&dev->lock); } spin_unlock_irq (&dev->lock); } @@ -1690,8 +1693,8 @@ gadgetfs_unbind (struct usb_gadget *gadget) static struct dev_data *the_device; -static int -gadgetfs_bind (struct usb_gadget *gadget) +static int gadgetfs_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { struct dev_data *dev = the_device; @@ -1706,7 +1709,6 @@ gadgetfs_bind (struct usb_gadget *gadget) set_gadget_data (gadget, dev); dev->gadget = gadget; gadget->ep0->driver_data = dev; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); @@ -1734,8 +1736,9 @@ static void gadgetfs_disconnect (struct usb_gadget *gadget) { struct dev_data *dev = get_gadget_data (gadget); + unsigned long flags; - spin_lock (&dev->lock); + spin_lock_irqsave (&dev->lock, flags); if (dev->state == STATE_DEV_UNCONNECTED) goto exit; dev->state = STATE_DEV_UNCONNECTED; @@ -1744,7 +1747,7 @@ gadgetfs_disconnect (struct usb_gadget *gadget) next_event (dev, GADGETFS_DISCONNECT); ep0_readable (dev); exit: - spin_unlock (&dev->lock); + spin_unlock_irqrestore (&dev->lock, flags); } static void @@ -1768,12 +1771,8 @@ gadgetfs_suspend (struct usb_gadget *gadget) } static struct usb_gadget_driver gadgetfs_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, -#else - .speed = USB_SPEED_FULL, -#endif .function = (char *) driver_desc, + .bind = gadgetfs_bind, .unbind = gadgetfs_unbind, .setup = gadgetfs_setup, .disconnect = gadgetfs_disconnect, @@ -1788,14 +1787,16 @@ static struct usb_gadget_driver gadgetfs_driver = { static void gadgetfs_nop(struct usb_gadget *arg) { } -static int gadgetfs_probe (struct usb_gadget *gadget) +static int gadgetfs_probe(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { CHIP = gadget->name; return -EISNAM; } static struct usb_gadget_driver probe_driver = { - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, + .bind = gadgetfs_probe, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, @@ -1905,7 +1906,12 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* triggers gadgetfs_bind(); then we can enumerate. */ spin_unlock_irq (&dev->lock); - value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind); + if (dev->hs_config) + gadgetfs_driver.max_speed = USB_SPEED_HIGH; + else + gadgetfs_driver.max_speed = USB_SPEED_FULL; + + value = usb_gadget_probe_driver(&gadgetfs_driver); if (value != 0) { kfree (dev->buf); dev->buf = NULL; @@ -1951,7 +1957,6 @@ dev_open (struct inode *inode, struct file *fd) } static const struct file_operations dev_init_operations = { - .owner = THIS_MODULE, .llseek = no_llseek, .open = dev_open, @@ -1993,8 +1998,8 @@ gadgetfs_make_inode (struct super_block *sb, if (inode) { inode->i_ino = get_next_ino(); inode->i_mode = mode; - inode->i_uid = default_uid; - inode->i_gid = default_gid; + inode->i_uid = make_kuid(&init_user_ns, default_uid); + inode->i_gid = make_kgid(&init_user_ns, default_gid); inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_private = data; @@ -2038,14 +2043,14 @@ static int gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) { struct inode *inode; - struct dentry *d; struct dev_data *dev; if (the_device) return -ESRCH; /* fake probe to determine $CHIP */ - (void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe); + CHIP = NULL; + usb_gadget_probe_driver(&probe_driver); if (!CHIP) return -ENODEV; @@ -2061,24 +2066,25 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) NULL, &simple_dir_operations, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) - goto enomem0; + goto Enomem; inode->i_op = &simple_dir_inode_operations; - if (!(d = d_alloc_root (inode))) - goto enomem1; - sb->s_root = d; + if (!(sb->s_root = d_make_root (inode))) + goto Enomem; /* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do. */ dev = dev_new (); if (!dev) - goto enomem2; + goto Enomem; dev->sb = sb; if (!gadgetfs_create_file (sb, CHIP, dev, &dev_init_operations, - &dev->dentry)) - goto enomem3; + &dev->dentry)) { + put_dev(dev); + goto Enomem; + } /* other endpoint files are available after hardware setup, * from binding to a controller. @@ -2086,13 +2092,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) the_device = dev; return 0; -enomem3: - put_dev (dev); -enomem2: - dput (d); -enomem1: - iput (inode); -enomem0: +Enomem: return -ENOMEM; } @@ -2122,6 +2122,7 @@ static struct file_system_type gadgetfs_type = { .mount = gadgetfs_mount, .kill_sb = gadgetfs_kill_sb, }; +MODULE_ALIAS_FS("gadgetfs"); /*----------------------------------------------------------------------*/ |
