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");  /*----------------------------------------------------------------------*/  | 
