xref: /openbmc/linux/drivers/usb/core/devio.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*****************************************************************************/
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds /*
51da177e4SLinus Torvalds  *      devio.c  --  User space communication with USB devices.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *      Copyright (C) 1999-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  This file implements the usbfs/x/y files, where
101da177e4SLinus Torvalds  *  x is the bus number and y the device number.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  It allows user space programs/"drivers" to communicate directly
131da177e4SLinus Torvalds  *  with USB devices without intervening kernel driver.
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *  Revision history
161da177e4SLinus Torvalds  *    22.12.1999   0.1   Initial release (split from proc_usb.c)
171da177e4SLinus Torvalds  *    04.01.2000   0.2   Turned into its own filesystem
1846113830SHarald Welte  *    30.09.2005   0.3   Fix user-triggerable oops in async URB delivery
1946113830SHarald Welte  *    			 (CAN-2005-3055)
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds /*****************************************************************************/
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #include <linux/fs.h>
251da177e4SLinus Torvalds #include <linux/mm.h>
263f07c014SIngo Molnar #include <linux/sched/signal.h>
271da177e4SLinus Torvalds #include <linux/slab.h>
281da177e4SLinus Torvalds #include <linux/signal.h>
291da177e4SLinus Torvalds #include <linux/poll.h>
301da177e4SLinus Torvalds #include <linux/module.h>
31b11b2e1bSChen Gang #include <linux/string.h>
321da177e4SLinus Torvalds #include <linux/usb.h>
331da177e4SLinus Torvalds #include <linux/usbdevice_fs.h>
3427729aadSEric Lescouet #include <linux/usb/hcd.h>	/* for usbcore internals */
35ae8709b2SAlan Stern #include <linux/usb/quirks.h>
36fbf82fd2SKay Sievers #include <linux/cdev.h>
37a7b986b3SGreg Kroah-Hartman #include <linux/notifier.h>
387a01955fSDavid Quigley #include <linux/security.h>
39d178bc3aSSerge Hallyn #include <linux/user_namespace.h>
403d97ff63SHans de Goede #include <linux/scatterlist.h>
41e6889b31STülin İzer #include <linux/uaccess.h>
42f7d34b44SSteinar H. Gunderson #include <linux/dma-mapping.h>
431da177e4SLinus Torvalds #include <asm/byteorder.h>
441da177e4SLinus Torvalds #include <linux/moduleparam.h>
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds #include "usb.h"
471da177e4SLinus Torvalds 
484ed33505SAlan Stern #ifdef CONFIG_PM
494ed33505SAlan Stern #define MAYBE_CAP_SUSPEND	USBDEVFS_CAP_SUSPEND
504ed33505SAlan Stern #else
514ed33505SAlan Stern #define MAYBE_CAP_SUSPEND	0
524ed33505SAlan Stern #endif
534ed33505SAlan Stern 
54fbf82fd2SKay Sievers #define USB_MAXBUS			64
55fa86ad0bSTülin İzer #define USB_DEVICE_MAX			(USB_MAXBUS * 128)
563d97ff63SHans de Goede #define USB_SG_SIZE			16384 /* split-size for large txs */
57fbf82fd2SKay Sievers 
587794f486SAlan Stern /* Mutual exclusion for ps->list in resume vs. release and remove */
597794f486SAlan Stern static DEFINE_MUTEX(usbfs_mutex);
607794f486SAlan Stern 
619b6f0c4bSValentina Manea struct usb_dev_state {
62cd9f0375SAlan Stern 	struct list_head list;      /* state list */
63cd9f0375SAlan Stern 	struct usb_device *dev;
64cd9f0375SAlan Stern 	struct file *file;
65cd9f0375SAlan Stern 	spinlock_t lock;            /* protects the async urb lists */
66cd9f0375SAlan Stern 	struct list_head async_pending;
67cd9f0375SAlan Stern 	struct list_head async_completed;
68f7d34b44SSteinar H. Gunderson 	struct list_head memory_list;
69cd9f0375SAlan Stern 	wait_queue_head_t wait;     /* wake up if a request completed */
707794f486SAlan Stern 	wait_queue_head_t wait_for_resume;   /* wake up upon runtime resume */
71cd9f0375SAlan Stern 	unsigned int discsignr;
72cd9f0375SAlan Stern 	struct pid *disc_pid;
73d178bc3aSSerge Hallyn 	const struct cred *cred;
7470f1b0d3SEric W. Biederman 	sigval_t disccontext;
75cd9f0375SAlan Stern 	unsigned long ifclaimed;
7601c6460fSAlan Stern 	u32 disabled_bulk_eps;
77d883f52eSReilly Grant 	unsigned long interface_allowed_mask;
787794f486SAlan Stern 	int not_yet_resumed;
797794f486SAlan Stern 	bool suspend_allowed;
807794f486SAlan Stern 	bool privileges_dropped;
81cd9f0375SAlan Stern };
82cd9f0375SAlan Stern 
83f7d34b44SSteinar H. Gunderson struct usb_memory {
84f7d34b44SSteinar H. Gunderson 	struct list_head memlist;
85f7d34b44SSteinar H. Gunderson 	int vma_use_count;
86f7d34b44SSteinar H. Gunderson 	int urb_use_count;
87f7d34b44SSteinar H. Gunderson 	u32 size;
88f7d34b44SSteinar H. Gunderson 	void *mem;
89f7d34b44SSteinar H. Gunderson 	dma_addr_t dma_handle;
90f7d34b44SSteinar H. Gunderson 	unsigned long vm_start;
91f7d34b44SSteinar H. Gunderson 	struct usb_dev_state *ps;
92f7d34b44SSteinar H. Gunderson };
93f7d34b44SSteinar H. Gunderson 
941da177e4SLinus Torvalds struct async {
951da177e4SLinus Torvalds 	struct list_head asynclist;
969b6f0c4bSValentina Manea 	struct usb_dev_state *ps;
972425c08bSEric W. Biederman 	struct pid *pid;
98d178bc3aSSerge Hallyn 	const struct cred *cred;
991da177e4SLinus Torvalds 	unsigned int signr;
1001da177e4SLinus Torvalds 	unsigned int ifnum;
1011da177e4SLinus Torvalds 	void __user *userbuffer;
1021da177e4SLinus Torvalds 	void __user *userurb;
10370f1b0d3SEric W. Biederman 	sigval_t userurb_sigval;
1041da177e4SLinus Torvalds 	struct urb *urb;
105f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm;
106add1aaeaSAlan Stern 	unsigned int mem_usage;
107e015268dSAlan Stern 	int status;
10801c6460fSAlan Stern 	u8 bulk_addr;
10901c6460fSAlan Stern 	u8 bulk_status;
1101da177e4SLinus Torvalds };
1111da177e4SLinus Torvalds 
11290ab5ee9SRusty Russell static bool usbfs_snoop;
1131da177e4SLinus Torvalds module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
1141da177e4SLinus Torvalds MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
1151da177e4SLinus Torvalds 
1160290cc9fSAlan Stern static unsigned usbfs_snoop_max = 65536;
1170290cc9fSAlan Stern module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
1180290cc9fSAlan Stern MODULE_PARM_DESC(usbfs_snoop_max,
1190290cc9fSAlan Stern 		"maximum number of bytes to print while snooping");
1200290cc9fSAlan Stern 
1211da177e4SLinus Torvalds #define snoop(dev, format, arg...)				\
1221da177e4SLinus Torvalds 	do {							\
1231da177e4SLinus Torvalds 		if (usbfs_snoop)				\
1241da177e4SLinus Torvalds 			dev_info(dev, format, ## arg);		\
1251da177e4SLinus Torvalds 	} while (0)
1261da177e4SLinus Torvalds 
1274c6e8971SAlan Stern enum snoop_when {
1284c6e8971SAlan Stern 	SUBMIT, COMPLETE
1294c6e8971SAlan Stern };
1304c6e8971SAlan Stern 
131fad21bdfSAlan Stern #define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
132fad21bdfSAlan Stern 
133add1aaeaSAlan Stern /* Limit on the total amount of memory we can allocate for transfers */
1341129d270SMateusz Berezecki static u32 usbfs_memory_mb = 16;
1353f5eb8d5SAlan Stern module_param(usbfs_memory_mb, uint, 0644);
1363f5eb8d5SAlan Stern MODULE_PARM_DESC(usbfs_memory_mb,
1373f5eb8d5SAlan Stern 		"maximum MB allowed for usbfs buffers (0 = no limit)");
1383f5eb8d5SAlan Stern 
13957999d11SDan Carpenter /* Hard limit, necessary to avoid arithmetic overflow */
14057999d11SDan Carpenter #define USBFS_XFER_MAX         (UINT_MAX / 2 - 1000000)
14157999d11SDan Carpenter 
1426a3cd5beSIngo Rohloff static DEFINE_SPINLOCK(usbfs_memory_usage_lock);
1436a3cd5beSIngo Rohloff static u64 usbfs_memory_usage;	/* Total memory currently allocated */
144add1aaeaSAlan Stern 
145add1aaeaSAlan Stern /* Check whether it's okay to allocate more memory for a transfer */
usbfs_increase_memory_usage(u64 amount)1461129d270SMateusz Berezecki static int usbfs_increase_memory_usage(u64 amount)
147add1aaeaSAlan Stern {
1486a3cd5beSIngo Rohloff 	u64 lim, total_mem;
1496a3cd5beSIngo Rohloff 	unsigned long flags;
1506a3cd5beSIngo Rohloff 	int ret;
1513f5eb8d5SAlan Stern 
1526aa7de05SMark Rutland 	lim = READ_ONCE(usbfs_memory_mb);
1533f5eb8d5SAlan Stern 	lim <<= 20;
1543f5eb8d5SAlan Stern 
1556a3cd5beSIngo Rohloff 	ret = 0;
1566a3cd5beSIngo Rohloff 	spin_lock_irqsave(&usbfs_memory_usage_lock, flags);
1576a3cd5beSIngo Rohloff 	total_mem = usbfs_memory_usage + amount;
1586a3cd5beSIngo Rohloff 	if (lim > 0 && total_mem > lim)
1596a3cd5beSIngo Rohloff 		ret = -ENOMEM;
1606a3cd5beSIngo Rohloff 	else
1616a3cd5beSIngo Rohloff 		usbfs_memory_usage = total_mem;
1626a3cd5beSIngo Rohloff 	spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags);
1631129d270SMateusz Berezecki 
1646a3cd5beSIngo Rohloff 	return ret;
1651129d270SMateusz Berezecki }
1661129d270SMateusz Berezecki 
167add1aaeaSAlan Stern /* Memory for a transfer is being deallocated */
usbfs_decrease_memory_usage(u64 amount)1681129d270SMateusz Berezecki static void usbfs_decrease_memory_usage(u64 amount)
169add1aaeaSAlan Stern {
1706a3cd5beSIngo Rohloff 	unsigned long flags;
1716a3cd5beSIngo Rohloff 
1726a3cd5beSIngo Rohloff 	spin_lock_irqsave(&usbfs_memory_usage_lock, flags);
1736a3cd5beSIngo Rohloff 	if (amount > usbfs_memory_usage)
1746a3cd5beSIngo Rohloff 		usbfs_memory_usage = 0;
1756a3cd5beSIngo Rohloff 	else
1766a3cd5beSIngo Rohloff 		usbfs_memory_usage -= amount;
1776a3cd5beSIngo Rohloff 	spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags);
178add1aaeaSAlan Stern }
1794c6e8971SAlan Stern 
connected(struct usb_dev_state * ps)1809b6f0c4bSValentina Manea static int connected(struct usb_dev_state *ps)
1811da177e4SLinus Torvalds {
182349710c3SAlan Stern 	return (!list_empty(&ps->list) &&
183349710c3SAlan Stern 			ps->dev->state != USB_STATE_NOTATTACHED);
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds 
dec_usb_memory_use_count(struct usb_memory * usbm,int * count)186f7d34b44SSteinar H. Gunderson static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
187f7d34b44SSteinar H. Gunderson {
188f7d34b44SSteinar H. Gunderson 	struct usb_dev_state *ps = usbm->ps;
1890143d148SRuihan Li 	struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus);
190f7d34b44SSteinar H. Gunderson 	unsigned long flags;
191f7d34b44SSteinar H. Gunderson 
192f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&ps->lock, flags);
193f7d34b44SSteinar H. Gunderson 	--*count;
194f7d34b44SSteinar H. Gunderson 	if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) {
195f7d34b44SSteinar H. Gunderson 		list_del(&usbm->memlist);
196f7d34b44SSteinar H. Gunderson 		spin_unlock_irqrestore(&ps->lock, flags);
197f7d34b44SSteinar H. Gunderson 
1980143d148SRuihan Li 		hcd_buffer_free_pages(hcd, usbm->size,
1990143d148SRuihan Li 				usbm->mem, usbm->dma_handle);
200f7d34b44SSteinar H. Gunderson 		usbfs_decrease_memory_usage(
201f7d34b44SSteinar H. Gunderson 			usbm->size + sizeof(struct usb_memory));
202f7d34b44SSteinar H. Gunderson 		kfree(usbm);
203f7d34b44SSteinar H. Gunderson 	} else {
204f7d34b44SSteinar H. Gunderson 		spin_unlock_irqrestore(&ps->lock, flags);
205f7d34b44SSteinar H. Gunderson 	}
206f7d34b44SSteinar H. Gunderson }
207f7d34b44SSteinar H. Gunderson 
usbdev_vm_open(struct vm_area_struct * vma)208f7d34b44SSteinar H. Gunderson static void usbdev_vm_open(struct vm_area_struct *vma)
209f7d34b44SSteinar H. Gunderson {
210f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm = vma->vm_private_data;
211f7d34b44SSteinar H. Gunderson 	unsigned long flags;
212f7d34b44SSteinar H. Gunderson 
213f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&usbm->ps->lock, flags);
214f7d34b44SSteinar H. Gunderson 	++usbm->vma_use_count;
215f7d34b44SSteinar H. Gunderson 	spin_unlock_irqrestore(&usbm->ps->lock, flags);
216f7d34b44SSteinar H. Gunderson }
217f7d34b44SSteinar H. Gunderson 
usbdev_vm_close(struct vm_area_struct * vma)218f7d34b44SSteinar H. Gunderson static void usbdev_vm_close(struct vm_area_struct *vma)
219f7d34b44SSteinar H. Gunderson {
220f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm = vma->vm_private_data;
221f7d34b44SSteinar H. Gunderson 
222f7d34b44SSteinar H. Gunderson 	dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
223f7d34b44SSteinar H. Gunderson }
224f7d34b44SSteinar H. Gunderson 
225b64d47aeSArvind Yadav static const struct vm_operations_struct usbdev_vm_ops = {
226f7d34b44SSteinar H. Gunderson 	.open = usbdev_vm_open,
227f7d34b44SSteinar H. Gunderson 	.close = usbdev_vm_close
228f7d34b44SSteinar H. Gunderson };
229f7d34b44SSteinar H. Gunderson 
usbdev_mmap(struct file * file,struct vm_area_struct * vma)230f7d34b44SSteinar H. Gunderson static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
231f7d34b44SSteinar H. Gunderson {
232f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm = NULL;
233f7d34b44SSteinar H. Gunderson 	struct usb_dev_state *ps = file->private_data;
2342bef9aedSJeremy Linton 	struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus);
235f7d34b44SSteinar H. Gunderson 	size_t size = vma->vm_end - vma->vm_start;
236f7d34b44SSteinar H. Gunderson 	void *mem;
237f7d34b44SSteinar H. Gunderson 	unsigned long flags;
238d0b86165SRuihan Li 	dma_addr_t dma_handle = DMA_MAPPING_ERROR;
239f7d34b44SSteinar H. Gunderson 	int ret;
240f7d34b44SSteinar H. Gunderson 
241f7d34b44SSteinar H. Gunderson 	ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
242f7d34b44SSteinar H. Gunderson 	if (ret)
243f7d34b44SSteinar H. Gunderson 		goto error;
244f7d34b44SSteinar H. Gunderson 
245f7d34b44SSteinar H. Gunderson 	usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
246f7d34b44SSteinar H. Gunderson 	if (!usbm) {
247f7d34b44SSteinar H. Gunderson 		ret = -ENOMEM;
248f7d34b44SSteinar H. Gunderson 		goto error_decrease_mem;
249f7d34b44SSteinar H. Gunderson 	}
250f7d34b44SSteinar H. Gunderson 
2510143d148SRuihan Li 	mem = hcd_buffer_alloc_pages(hcd,
2520143d148SRuihan Li 			size, GFP_USER | __GFP_NOWARN, &dma_handle);
253f7d34b44SSteinar H. Gunderson 	if (!mem) {
254f7d34b44SSteinar H. Gunderson 		ret = -ENOMEM;
255f7d34b44SSteinar H. Gunderson 		goto error_free_usbm;
256f7d34b44SSteinar H. Gunderson 	}
257f7d34b44SSteinar H. Gunderson 
258f7d34b44SSteinar H. Gunderson 	memset(mem, 0, size);
259f7d34b44SSteinar H. Gunderson 
260f7d34b44SSteinar H. Gunderson 	usbm->mem = mem;
261f7d34b44SSteinar H. Gunderson 	usbm->dma_handle = dma_handle;
262f7d34b44SSteinar H. Gunderson 	usbm->size = size;
263f7d34b44SSteinar H. Gunderson 	usbm->ps = ps;
264f7d34b44SSteinar H. Gunderson 	usbm->vm_start = vma->vm_start;
265f7d34b44SSteinar H. Gunderson 	usbm->vma_use_count = 1;
266f7d34b44SSteinar H. Gunderson 	INIT_LIST_HEAD(&usbm->memlist);
267f7d34b44SSteinar H. Gunderson 
268d0b86165SRuihan Li 	/*
269d0b86165SRuihan Li 	 * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates
270d0b86165SRuihan Li 	 * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check
271d0b86165SRuihan Li 	 * whether we are in such cases, and then use remap_pfn_range (or
272d0b86165SRuihan Li 	 * dma_mmap_coherent) to map normal (or DMA) pages into the user
273d0b86165SRuihan Li 	 * space, respectively.
274d0b86165SRuihan Li 	 */
275d0b86165SRuihan Li 	if (dma_handle == DMA_MAPPING_ERROR) {
276a0e710a7SGreg Kroah-Hartman 		if (remap_pfn_range(vma, vma->vm_start,
277a0e710a7SGreg Kroah-Hartman 				    virt_to_phys(usbm->mem) >> PAGE_SHIFT,
278a0e710a7SGreg Kroah-Hartman 				    size, vma->vm_page_prot) < 0) {
279f7d34b44SSteinar H. Gunderson 			dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
280f7d34b44SSteinar H. Gunderson 			return -EAGAIN;
281f7d34b44SSteinar H. Gunderson 		}
282a0e710a7SGreg Kroah-Hartman 	} else {
283a0e710a7SGreg Kroah-Hartman 		if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle,
284a0e710a7SGreg Kroah-Hartman 				      size)) {
285a0e710a7SGreg Kroah-Hartman 			dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
286a0e710a7SGreg Kroah-Hartman 			return -EAGAIN;
287a0e710a7SGreg Kroah-Hartman 		}
288a0e710a7SGreg Kroah-Hartman 	}
289f7d34b44SSteinar H. Gunderson 
2901c71222eSSuren Baghdasaryan 	vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
291f7d34b44SSteinar H. Gunderson 	vma->vm_ops = &usbdev_vm_ops;
292f7d34b44SSteinar H. Gunderson 	vma->vm_private_data = usbm;
293f7d34b44SSteinar H. Gunderson 
294f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&ps->lock, flags);
295f7d34b44SSteinar H. Gunderson 	list_add_tail(&usbm->memlist, &ps->memory_list);
296f7d34b44SSteinar H. Gunderson 	spin_unlock_irqrestore(&ps->lock, flags);
297f7d34b44SSteinar H. Gunderson 
298f7d34b44SSteinar H. Gunderson 	return 0;
299f7d34b44SSteinar H. Gunderson 
300f7d34b44SSteinar H. Gunderson error_free_usbm:
301f7d34b44SSteinar H. Gunderson 	kfree(usbm);
302f7d34b44SSteinar H. Gunderson error_decrease_mem:
303f7d34b44SSteinar H. Gunderson 	usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
304f7d34b44SSteinar H. Gunderson error:
305f7d34b44SSteinar H. Gunderson 	return ret;
306f7d34b44SSteinar H. Gunderson }
307f7d34b44SSteinar H. Gunderson 
usbdev_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)30804e482ffSGreg Kroah-Hartman static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
30904e482ffSGreg Kroah-Hartman 			   loff_t *ppos)
3101da177e4SLinus Torvalds {
3119b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
3121da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
3131da177e4SLinus Torvalds 	ssize_t ret = 0;
3141da177e4SLinus Torvalds 	unsigned len;
3151da177e4SLinus Torvalds 	loff_t pos;
3161da177e4SLinus Torvalds 	int i;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	pos = *ppos;
3191da177e4SLinus Torvalds 	usb_lock_device(dev);
320349710c3SAlan Stern 	if (!connected(ps)) {
3211da177e4SLinus Torvalds 		ret = -ENODEV;
3221da177e4SLinus Torvalds 		goto err;
3231da177e4SLinus Torvalds 	} else if (pos < 0) {
3241da177e4SLinus Torvalds 		ret = -EINVAL;
3251da177e4SLinus Torvalds 		goto err;
3261da177e4SLinus Torvalds 	}
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	if (pos < sizeof(struct usb_device_descriptor)) {
32904e482ffSGreg Kroah-Hartman 		/* 18 bytes - fits on the stack */
33004e482ffSGreg Kroah-Hartman 		struct usb_device_descriptor temp_desc;
3318781ba0aSOliver Neukum 
3328781ba0aSOliver Neukum 		memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
3339fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.bcdUSB);
3349fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.idVendor);
3359fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.idProduct);
3369fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.bcdDevice);
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 		len = sizeof(struct usb_device_descriptor) - pos;
3391da177e4SLinus Torvalds 		if (len > nbytes)
3401da177e4SLinus Torvalds 			len = nbytes;
3418781ba0aSOliver Neukum 		if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
3421da177e4SLinus Torvalds 			ret = -EFAULT;
3431da177e4SLinus Torvalds 			goto err;
3441da177e4SLinus Torvalds 		}
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 		*ppos += len;
3471da177e4SLinus Torvalds 		buf += len;
3481da177e4SLinus Torvalds 		nbytes -= len;
3491da177e4SLinus Torvalds 		ret += len;
3501da177e4SLinus Torvalds 	}
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	pos = sizeof(struct usb_device_descriptor);
3531da177e4SLinus Torvalds 	for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
3541da177e4SLinus Torvalds 		struct usb_config_descriptor *config =
3551da177e4SLinus Torvalds 			(struct usb_config_descriptor *)dev->rawdescriptors[i];
3561da177e4SLinus Torvalds 		unsigned int length = le16_to_cpu(config->wTotalLength);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 		if (*ppos < pos + length) {
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 			/* The descriptor may claim to be longer than it
3611da177e4SLinus Torvalds 			 * really is.  Here is the actual allocated length. */
3621da177e4SLinus Torvalds 			unsigned alloclen =
3631da177e4SLinus Torvalds 				le16_to_cpu(dev->config[i].desc.wTotalLength);
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 			len = length - (*ppos - pos);
3661da177e4SLinus Torvalds 			if (len > nbytes)
3671da177e4SLinus Torvalds 				len = nbytes;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 			/* Simply don't write (skip over) unallocated parts */
3701da177e4SLinus Torvalds 			if (alloclen > (*ppos - pos)) {
3711da177e4SLinus Torvalds 				alloclen -= (*ppos - pos);
3721da177e4SLinus Torvalds 				if (copy_to_user(buf,
3731da177e4SLinus Torvalds 				    dev->rawdescriptors[i] + (*ppos - pos),
3741da177e4SLinus Torvalds 				    min(len, alloclen))) {
3751da177e4SLinus Torvalds 					ret = -EFAULT;
3761da177e4SLinus Torvalds 					goto err;
3771da177e4SLinus Torvalds 				}
3781da177e4SLinus Torvalds 			}
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 			*ppos += len;
3811da177e4SLinus Torvalds 			buf += len;
3821da177e4SLinus Torvalds 			nbytes -= len;
3831da177e4SLinus Torvalds 			ret += len;
3841da177e4SLinus Torvalds 		}
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 		pos += length;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds err:
3901da177e4SLinus Torvalds 	usb_unlock_device(dev);
3911da177e4SLinus Torvalds 	return ret;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds /*
3951da177e4SLinus Torvalds  * async list handling
3961da177e4SLinus Torvalds  */
3971da177e4SLinus Torvalds 
alloc_async(unsigned int numisoframes)3981da177e4SLinus Torvalds static struct async *alloc_async(unsigned int numisoframes)
3991da177e4SLinus Torvalds {
400dd95b814SPete Zaitcev 	struct async *as;
4010a1ef3b5SAlan Stern 
402dd95b814SPete Zaitcev 	as = kzalloc(sizeof(struct async), GFP_KERNEL);
4031da177e4SLinus Torvalds 	if (!as)
4041da177e4SLinus Torvalds 		return NULL;
4051da177e4SLinus Torvalds 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
4061da177e4SLinus Torvalds 	if (!as->urb) {
4071da177e4SLinus Torvalds 		kfree(as);
4081da177e4SLinus Torvalds 		return NULL;
4091da177e4SLinus Torvalds 	}
4101da177e4SLinus Torvalds 	return as;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
free_async(struct async * as)4131da177e4SLinus Torvalds static void free_async(struct async *as)
4141da177e4SLinus Torvalds {
4153d97ff63SHans de Goede 	int i;
4163d97ff63SHans de Goede 
4172425c08bSEric W. Biederman 	put_pid(as->pid);
4181b41c832SSarah Sharp 	if (as->cred)
419d178bc3aSSerge Hallyn 		put_cred(as->cred);
4203d97ff63SHans de Goede 	for (i = 0; i < as->urb->num_sgs; i++) {
4213d97ff63SHans de Goede 		if (sg_page(&as->urb->sg[i]))
4223d97ff63SHans de Goede 			kfree(sg_virt(&as->urb->sg[i]));
4233d97ff63SHans de Goede 	}
424f7d34b44SSteinar H. Gunderson 
4253d97ff63SHans de Goede 	kfree(as->urb->sg);
426f7d34b44SSteinar H. Gunderson 	if (as->usbm == NULL)
4271da177e4SLinus Torvalds 		kfree(as->urb->transfer_buffer);
428f7d34b44SSteinar H. Gunderson 	else
429f7d34b44SSteinar H. Gunderson 		dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
430f7d34b44SSteinar H. Gunderson 
4311da177e4SLinus Torvalds 	kfree(as->urb->setup_packet);
4321da177e4SLinus Torvalds 	usb_free_urb(as->urb);
433add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(as->mem_usage);
4341da177e4SLinus Torvalds 	kfree(as);
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds 
async_newpending(struct async * as)437d34d9721SAlan Stern static void async_newpending(struct async *as)
4381da177e4SLinus Torvalds {
4399b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
4401da177e4SLinus Torvalds 	unsigned long flags;
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4431da177e4SLinus Torvalds 	list_add_tail(&as->asynclist, &ps->async_pending);
4441da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4451da177e4SLinus Torvalds }
4461da177e4SLinus Torvalds 
async_removepending(struct async * as)447d34d9721SAlan Stern static void async_removepending(struct async *as)
4481da177e4SLinus Torvalds {
4499b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
4501da177e4SLinus Torvalds 	unsigned long flags;
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4531da177e4SLinus Torvalds 	list_del_init(&as->asynclist);
4541da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
async_getcompleted(struct usb_dev_state * ps)4579b6f0c4bSValentina Manea static struct async *async_getcompleted(struct usb_dev_state *ps)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	unsigned long flags;
4601da177e4SLinus Torvalds 	struct async *as = NULL;
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4631da177e4SLinus Torvalds 	if (!list_empty(&ps->async_completed)) {
46404e482ffSGreg Kroah-Hartman 		as = list_entry(ps->async_completed.next, struct async,
46504e482ffSGreg Kroah-Hartman 				asynclist);
4661da177e4SLinus Torvalds 		list_del_init(&as->asynclist);
4671da177e4SLinus Torvalds 	}
4681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4691da177e4SLinus Torvalds 	return as;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds 
async_getpending(struct usb_dev_state * ps,void __user * userurb)4729b6f0c4bSValentina Manea static struct async *async_getpending(struct usb_dev_state *ps,
47304e482ffSGreg Kroah-Hartman 					     void __user *userurb)
4741da177e4SLinus Torvalds {
4751da177e4SLinus Torvalds 	struct async *as;
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	list_for_each_entry(as, &ps->async_pending, asynclist)
4781da177e4SLinus Torvalds 		if (as->userurb == userurb) {
4791da177e4SLinus Torvalds 			list_del_init(&as->asynclist);
4801da177e4SLinus Torvalds 			return as;
4811da177e4SLinus Torvalds 		}
4824e09dcf2SHuajun Li 
4831da177e4SLinus Torvalds 	return NULL;
4841da177e4SLinus Torvalds }
4851da177e4SLinus Torvalds 
snoop_urb(struct usb_device * udev,void __user * userurb,int pipe,unsigned length,int timeout_or_status,enum snoop_when when,unsigned char * data,unsigned data_len)4864c6e8971SAlan Stern static void snoop_urb(struct usb_device *udev,
4874c6e8971SAlan Stern 		void __user *userurb, int pipe, unsigned length,
4880880aef4SChris Frey 		int timeout_or_status, enum snoop_when when,
4890880aef4SChris Frey 		unsigned char *data, unsigned data_len)
490e639dd3fSGreg Kroah-Hartman {
4914c6e8971SAlan Stern 	static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
4924c6e8971SAlan Stern 	static const char *dirs[] = {"out", "in"};
4934c6e8971SAlan Stern 	int ep;
4944c6e8971SAlan Stern 	const char *t, *d;
495e639dd3fSGreg Kroah-Hartman 
496e639dd3fSGreg Kroah-Hartman 	if (!usbfs_snoop)
497e639dd3fSGreg Kroah-Hartman 		return;
498e639dd3fSGreg Kroah-Hartman 
4994c6e8971SAlan Stern 	ep = usb_pipeendpoint(pipe);
5004c6e8971SAlan Stern 	t = types[usb_pipetype(pipe)];
5014c6e8971SAlan Stern 	d = dirs[!!usb_pipein(pipe)];
5024c6e8971SAlan Stern 
5034c6e8971SAlan Stern 	if (userurb) {		/* Async */
5044c6e8971SAlan Stern 		if (when == SUBMIT)
505f3bc432aSAlan Stern 			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
5064c6e8971SAlan Stern 					"length %u\n",
5074c6e8971SAlan Stern 					userurb, ep, t, d, length);
5084c6e8971SAlan Stern 		else
509f3bc432aSAlan Stern 			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
5104c6e8971SAlan Stern 					"actual_length %u status %d\n",
5114c6e8971SAlan Stern 					userurb, ep, t, d, length,
5124c6e8971SAlan Stern 					timeout_or_status);
5134c6e8971SAlan Stern 	} else {
5144c6e8971SAlan Stern 		if (when == SUBMIT)
5154c6e8971SAlan Stern 			dev_info(&udev->dev, "ep%d %s-%s, length %u, "
5164c6e8971SAlan Stern 					"timeout %d\n",
5174c6e8971SAlan Stern 					ep, t, d, length, timeout_or_status);
5184c6e8971SAlan Stern 		else
5194c6e8971SAlan Stern 			dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
5204c6e8971SAlan Stern 					"status %d\n",
5214c6e8971SAlan Stern 					ep, t, d, length, timeout_or_status);
5224c6e8971SAlan Stern 	}
5230880aef4SChris Frey 
5240290cc9fSAlan Stern 	data_len = min(data_len, usbfs_snoop_max);
5250880aef4SChris Frey 	if (data && data_len > 0) {
5260880aef4SChris Frey 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5270880aef4SChris Frey 			data, data_len, 1);
5280880aef4SChris Frey 	}
529e639dd3fSGreg Kroah-Hartman }
530e639dd3fSGreg Kroah-Hartman 
snoop_urb_data(struct urb * urb,unsigned len)5313d97ff63SHans de Goede static void snoop_urb_data(struct urb *urb, unsigned len)
5323d97ff63SHans de Goede {
5333d97ff63SHans de Goede 	int i, size;
5343d97ff63SHans de Goede 
5350290cc9fSAlan Stern 	len = min(len, usbfs_snoop_max);
5360290cc9fSAlan Stern 	if (!usbfs_snoop || len == 0)
5373d97ff63SHans de Goede 		return;
5383d97ff63SHans de Goede 
5393d97ff63SHans de Goede 	if (urb->num_sgs == 0) {
5403d97ff63SHans de Goede 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5413d97ff63SHans de Goede 			urb->transfer_buffer, len, 1);
5423d97ff63SHans de Goede 		return;
5433d97ff63SHans de Goede 	}
5443d97ff63SHans de Goede 
5453d97ff63SHans de Goede 	for (i = 0; i < urb->num_sgs && len; i++) {
5463d97ff63SHans de Goede 		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
5473d97ff63SHans de Goede 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5483d97ff63SHans de Goede 			sg_virt(&urb->sg[i]), size, 1);
5493d97ff63SHans de Goede 		len -= size;
5503d97ff63SHans de Goede 	}
5513d97ff63SHans de Goede }
5523d97ff63SHans de Goede 
copy_urb_data_to_user(u8 __user * userbuffer,struct urb * urb)5533d97ff63SHans de Goede static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
5543d97ff63SHans de Goede {
5553d97ff63SHans de Goede 	unsigned i, len, size;
5563d97ff63SHans de Goede 
5573d97ff63SHans de Goede 	if (urb->number_of_packets > 0)		/* Isochronous */
5583d97ff63SHans de Goede 		len = urb->transfer_buffer_length;
5593d97ff63SHans de Goede 	else					/* Non-Isoc */
5603d97ff63SHans de Goede 		len = urb->actual_length;
5613d97ff63SHans de Goede 
5623d97ff63SHans de Goede 	if (urb->num_sgs == 0) {
5633d97ff63SHans de Goede 		if (copy_to_user(userbuffer, urb->transfer_buffer, len))
5643d97ff63SHans de Goede 			return -EFAULT;
5653d97ff63SHans de Goede 		return 0;
5663d97ff63SHans de Goede 	}
5673d97ff63SHans de Goede 
5683d97ff63SHans de Goede 	for (i = 0; i < urb->num_sgs && len; i++) {
5693d97ff63SHans de Goede 		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
5703d97ff63SHans de Goede 		if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
5713d97ff63SHans de Goede 			return -EFAULT;
5723d97ff63SHans de Goede 		userbuffer += size;
5733d97ff63SHans de Goede 		len -= size;
5743d97ff63SHans de Goede 	}
5753d97ff63SHans de Goede 
5763d97ff63SHans de Goede 	return 0;
5773d97ff63SHans de Goede }
5783d97ff63SHans de Goede 
57901c6460fSAlan Stern #define AS_CONTINUATION	1
58001c6460fSAlan Stern #define AS_UNLINK	2
58101c6460fSAlan Stern 
cancel_bulk_urbs(struct usb_dev_state * ps,unsigned bulk_addr)5829b6f0c4bSValentina Manea static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)
58301c6460fSAlan Stern __releases(ps->lock)
58401c6460fSAlan Stern __acquires(ps->lock)
58501c6460fSAlan Stern {
5864e09dcf2SHuajun Li 	struct urb *urb;
58701c6460fSAlan Stern 	struct async *as;
58801c6460fSAlan Stern 
58901c6460fSAlan Stern 	/* Mark all the pending URBs that match bulk_addr, up to but not
59001c6460fSAlan Stern 	 * including the first one without AS_CONTINUATION.  If such an
59101c6460fSAlan Stern 	 * URB is encountered then a new transfer has already started so
59201c6460fSAlan Stern 	 * the endpoint doesn't need to be disabled; otherwise it does.
59301c6460fSAlan Stern 	 */
59401c6460fSAlan Stern 	list_for_each_entry(as, &ps->async_pending, asynclist) {
59501c6460fSAlan Stern 		if (as->bulk_addr == bulk_addr) {
59601c6460fSAlan Stern 			if (as->bulk_status != AS_CONTINUATION)
59701c6460fSAlan Stern 				goto rescan;
59801c6460fSAlan Stern 			as->bulk_status = AS_UNLINK;
59901c6460fSAlan Stern 			as->bulk_addr = 0;
60001c6460fSAlan Stern 		}
60101c6460fSAlan Stern 	}
60201c6460fSAlan Stern 	ps->disabled_bulk_eps |= (1 << bulk_addr);
60301c6460fSAlan Stern 
60401c6460fSAlan Stern 	/* Now carefully unlink all the marked pending URBs */
60501c6460fSAlan Stern  rescan:
606fdd64df7SAlan Stern 	list_for_each_entry_reverse(as, &ps->async_pending, asynclist) {
60701c6460fSAlan Stern 		if (as->bulk_status == AS_UNLINK) {
60801c6460fSAlan Stern 			as->bulk_status = 0;		/* Only once */
6094e09dcf2SHuajun Li 			urb = as->urb;
6104e09dcf2SHuajun Li 			usb_get_urb(urb);
61101c6460fSAlan Stern 			spin_unlock(&ps->lock);		/* Allow completions */
6124e09dcf2SHuajun Li 			usb_unlink_urb(urb);
6134e09dcf2SHuajun Li 			usb_put_urb(urb);
61401c6460fSAlan Stern 			spin_lock(&ps->lock);
61501c6460fSAlan Stern 			goto rescan;
61601c6460fSAlan Stern 		}
61701c6460fSAlan Stern 	}
61801c6460fSAlan Stern }
61901c6460fSAlan Stern 
async_completed(struct urb * urb)6207d12e780SDavid Howells static void async_completed(struct urb *urb)
6211da177e4SLinus Torvalds {
622ec17cf1cSTobias Klauser 	struct async *as = urb->context;
6239b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
624516a1a07SOliver Neukum 	struct pid *pid = NULL;
625d178bc3aSSerge Hallyn 	const struct cred *cred = NULL;
6263f38daceSSebastian Andrzej Siewior 	unsigned long flags;
62770f1b0d3SEric W. Biederman 	sigval_t addr;
62870f1b0d3SEric W. Biederman 	int signr, errno;
6291da177e4SLinus Torvalds 
6303f38daceSSebastian Andrzej Siewior 	spin_lock_irqsave(&ps->lock, flags);
6311da177e4SLinus Torvalds 	list_move_tail(&as->asynclist, &ps->async_completed);
632e015268dSAlan Stern 	as->status = urb->status;
633516a1a07SOliver Neukum 	signr = as->signr;
634516a1a07SOliver Neukum 	if (signr) {
63570f1b0d3SEric W. Biederman 		errno = as->status;
63670f1b0d3SEric W. Biederman 		addr = as->userurb_sigval;
637aec01c58SSerge Hallyn 		pid = get_pid(as->pid);
638d178bc3aSSerge Hallyn 		cred = get_cred(as->cred);
6391da177e4SLinus Torvalds 	}
640e639dd3fSGreg Kroah-Hartman 	snoop(&urb->dev->dev, "urb complete\n");
6414c6e8971SAlan Stern 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
6423d97ff63SHans de Goede 			as->status, COMPLETE, NULL, 0);
64379595a73SKeyur Patel 	if (usb_urb_dir_in(urb))
6443d97ff63SHans de Goede 		snoop_urb_data(urb, urb->actual_length);
6453d97ff63SHans de Goede 
64601c6460fSAlan Stern 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
64701c6460fSAlan Stern 			as->status != -ENOENT)
64801c6460fSAlan Stern 		cancel_bulk_urbs(ps, as->bulk_addr);
649ed62ca2fSDouglas Anderson 
650ed62ca2fSDouglas Anderson 	wake_up(&ps->wait);
6513f38daceSSebastian Andrzej Siewior 	spin_unlock_irqrestore(&ps->lock, flags);
652516a1a07SOliver Neukum 
653aec01c58SSerge Hallyn 	if (signr) {
65470f1b0d3SEric W. Biederman 		kill_pid_usb_asyncio(signr, errno, addr, pid, cred);
655aec01c58SSerge Hallyn 		put_pid(pid);
656d178bc3aSSerge Hallyn 		put_cred(cred);
657aec01c58SSerge Hallyn 	}
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
destroy_async(struct usb_dev_state * ps,struct list_head * list)6609b6f0c4bSValentina Manea static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
6611da177e4SLinus Torvalds {
6624e09dcf2SHuajun Li 	struct urb *urb;
6631da177e4SLinus Torvalds 	struct async *as;
6641da177e4SLinus Torvalds 	unsigned long flags;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
6671da177e4SLinus Torvalds 	while (!list_empty(list)) {
668fdd64df7SAlan Stern 		as = list_last_entry(list, struct async, asynclist);
6691da177e4SLinus Torvalds 		list_del_init(&as->asynclist);
6704e09dcf2SHuajun Li 		urb = as->urb;
6714e09dcf2SHuajun Li 		usb_get_urb(urb);
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 		/* drop the spinlock so the completion handler can run */
6741da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ps->lock, flags);
6754e09dcf2SHuajun Li 		usb_kill_urb(urb);
6764e09dcf2SHuajun Li 		usb_put_urb(urb);
6771da177e4SLinus Torvalds 		spin_lock_irqsave(&ps->lock, flags);
6781da177e4SLinus Torvalds 	}
6791da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds 
destroy_async_on_interface(struct usb_dev_state * ps,unsigned int ifnum)6829b6f0c4bSValentina Manea static void destroy_async_on_interface(struct usb_dev_state *ps,
68304e482ffSGreg Kroah-Hartman 				       unsigned int ifnum)
6841da177e4SLinus Torvalds {
6851da177e4SLinus Torvalds 	struct list_head *p, *q, hitlist;
6861da177e4SLinus Torvalds 	unsigned long flags;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	INIT_LIST_HEAD(&hitlist);
6891da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
6901da177e4SLinus Torvalds 	list_for_each_safe(p, q, &ps->async_pending)
6911da177e4SLinus Torvalds 		if (ifnum == list_entry(p, struct async, asynclist)->ifnum)
6921da177e4SLinus Torvalds 			list_move_tail(p, &hitlist);
6931da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
6941da177e4SLinus Torvalds 	destroy_async(ps, &hitlist);
6951da177e4SLinus Torvalds }
6961da177e4SLinus Torvalds 
destroy_all_async(struct usb_dev_state * ps)6979b6f0c4bSValentina Manea static void destroy_all_async(struct usb_dev_state *ps)
6981da177e4SLinus Torvalds {
6991da177e4SLinus Torvalds 	destroy_async(ps, &ps->async_pending);
7001da177e4SLinus Torvalds }
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds /*
7031da177e4SLinus Torvalds  * interface claims are made only at the request of user level code,
7041da177e4SLinus Torvalds  * which can also release them (explicitly or by closing files).
7051da177e4SLinus Torvalds  * they're also undone when devices disconnect.
7061da177e4SLinus Torvalds  */
7071da177e4SLinus Torvalds 
driver_probe(struct usb_interface * intf,const struct usb_device_id * id)7081da177e4SLinus Torvalds static int driver_probe(struct usb_interface *intf,
7091da177e4SLinus Torvalds 			const struct usb_device_id *id)
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds 	return -ENODEV;
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds 
driver_disconnect(struct usb_interface * intf)7141da177e4SLinus Torvalds static void driver_disconnect(struct usb_interface *intf)
7151da177e4SLinus Torvalds {
7169b6f0c4bSValentina Manea 	struct usb_dev_state *ps = usb_get_intfdata(intf);
7171da177e4SLinus Torvalds 	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	if (!ps)
7201da177e4SLinus Torvalds 		return;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	/* NOTE:  this relies on usbcore having canceled and completed
7231da177e4SLinus Torvalds 	 * all pending I/O requests; 2.6 does that.
7241da177e4SLinus Torvalds 	 */
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 	if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
7271da177e4SLinus Torvalds 		clear_bit(ifnum, &ps->ifclaimed);
7281da177e4SLinus Torvalds 	else
7293b6004f3SGreg Kroah-Hartman 		dev_warn(&intf->dev, "interface number %u out of range\n",
7303b6004f3SGreg Kroah-Hartman 			 ifnum);
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	usb_set_intfdata(intf, NULL);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	/* force async requests to complete */
7351da177e4SLinus Torvalds 	destroy_async_on_interface(ps, ifnum);
7361da177e4SLinus Torvalds }
7371da177e4SLinus Torvalds 
7387794f486SAlan Stern /* We don't care about suspend/resume of claimed interfaces */
driver_suspend(struct usb_interface * intf,pm_message_t msg)7392e2eb83fSAlan Stern static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
7402e2eb83fSAlan Stern {
7412e2eb83fSAlan Stern 	return 0;
7422e2eb83fSAlan Stern }
7432e2eb83fSAlan Stern 
driver_resume(struct usb_interface * intf)7442e2eb83fSAlan Stern static int driver_resume(struct usb_interface *intf)
7452e2eb83fSAlan Stern {
7462e2eb83fSAlan Stern 	return 0;
7472e2eb83fSAlan Stern }
7482e2eb83fSAlan Stern 
7498e6bd945SArnd Bergmann #ifdef CONFIG_PM
7507794f486SAlan Stern /* The following routines apply to the entire device, not interfaces */
usbfs_notify_suspend(struct usb_device * udev)7517794f486SAlan Stern void usbfs_notify_suspend(struct usb_device *udev)
7527794f486SAlan Stern {
7537794f486SAlan Stern 	/* We don't need to handle this */
7547794f486SAlan Stern }
7557794f486SAlan Stern 
usbfs_notify_resume(struct usb_device * udev)7567794f486SAlan Stern void usbfs_notify_resume(struct usb_device *udev)
7577794f486SAlan Stern {
7587794f486SAlan Stern 	struct usb_dev_state *ps;
7597794f486SAlan Stern 
7607794f486SAlan Stern 	/* Protect against simultaneous remove or release */
7617794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
7627794f486SAlan Stern 	list_for_each_entry(ps, &udev->filelist, list) {
7637794f486SAlan Stern 		WRITE_ONCE(ps->not_yet_resumed, 0);
7647794f486SAlan Stern 		wake_up_all(&ps->wait_for_resume);
7657794f486SAlan Stern 	}
7667794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
7677794f486SAlan Stern }
7688e6bd945SArnd Bergmann #endif
7697794f486SAlan Stern 
7701da177e4SLinus Torvalds struct usb_driver usbfs_driver = {
7711da177e4SLinus Torvalds 	.name =		"usbfs",
7721da177e4SLinus Torvalds 	.probe =	driver_probe,
7731da177e4SLinus Torvalds 	.disconnect =	driver_disconnect,
7742e2eb83fSAlan Stern 	.suspend =	driver_suspend,
7752e2eb83fSAlan Stern 	.resume =	driver_resume,
7767794f486SAlan Stern 	.supports_autosuspend = 1,
7771da177e4SLinus Torvalds };
7781da177e4SLinus Torvalds 
claimintf(struct usb_dev_state * ps,unsigned int ifnum)7799b6f0c4bSValentina Manea static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
7801da177e4SLinus Torvalds {
7811da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
7821da177e4SLinus Torvalds 	struct usb_interface *intf;
7831da177e4SLinus Torvalds 	int err;
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
7861da177e4SLinus Torvalds 		return -EINVAL;
7871da177e4SLinus Torvalds 	/* already claimed */
7881da177e4SLinus Torvalds 	if (test_bit(ifnum, &ps->ifclaimed))
7891da177e4SLinus Torvalds 		return 0;
7901da177e4SLinus Torvalds 
791d883f52eSReilly Grant 	if (ps->privileges_dropped &&
792d883f52eSReilly Grant 			!test_bit(ifnum, &ps->interface_allowed_mask))
793d883f52eSReilly Grant 		return -EACCES;
794d883f52eSReilly Grant 
7951da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(dev, ifnum);
7961da177e4SLinus Torvalds 	if (!intf)
7971da177e4SLinus Torvalds 		err = -ENOENT;
798abb0b3d9SIngo Rohloff 	else {
799abb0b3d9SIngo Rohloff 		unsigned int old_suppress;
800abb0b3d9SIngo Rohloff 
801abb0b3d9SIngo Rohloff 		/* suppress uevents while claiming interface */
802abb0b3d9SIngo Rohloff 		old_suppress = dev_get_uevent_suppress(&intf->dev);
803abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, 1);
8041da177e4SLinus Torvalds 		err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
805abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, old_suppress);
806abb0b3d9SIngo Rohloff 	}
8071da177e4SLinus Torvalds 	if (err == 0)
8081da177e4SLinus Torvalds 		set_bit(ifnum, &ps->ifclaimed);
8091da177e4SLinus Torvalds 	return err;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
releaseintf(struct usb_dev_state * ps,unsigned int ifnum)8129b6f0c4bSValentina Manea static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
8131da177e4SLinus Torvalds {
8141da177e4SLinus Torvalds 	struct usb_device *dev;
8151da177e4SLinus Torvalds 	struct usb_interface *intf;
8161da177e4SLinus Torvalds 	int err;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	err = -EINVAL;
8191da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
8201da177e4SLinus Torvalds 		return err;
8211da177e4SLinus Torvalds 	dev = ps->dev;
8221da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(dev, ifnum);
8231da177e4SLinus Torvalds 	if (!intf)
8241da177e4SLinus Torvalds 		err = -ENOENT;
8251da177e4SLinus Torvalds 	else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
826abb0b3d9SIngo Rohloff 		unsigned int old_suppress;
827abb0b3d9SIngo Rohloff 
828abb0b3d9SIngo Rohloff 		/* suppress uevents while releasing interface */
829abb0b3d9SIngo Rohloff 		old_suppress = dev_get_uevent_suppress(&intf->dev);
830abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, 1);
8311da177e4SLinus Torvalds 		usb_driver_release_interface(&usbfs_driver, intf);
832abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, old_suppress);
8331da177e4SLinus Torvalds 		err = 0;
8341da177e4SLinus Torvalds 	}
8351da177e4SLinus Torvalds 	return err;
8361da177e4SLinus Torvalds }
8371da177e4SLinus Torvalds 
checkintf(struct usb_dev_state * ps,unsigned int ifnum)8389b6f0c4bSValentina Manea static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)
8391da177e4SLinus Torvalds {
8401da177e4SLinus Torvalds 	if (ps->dev->state != USB_STATE_CONFIGURED)
8411da177e4SLinus Torvalds 		return -EHOSTUNREACH;
8421da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
8431da177e4SLinus Torvalds 		return -EINVAL;
8441da177e4SLinus Torvalds 	if (test_bit(ifnum, &ps->ifclaimed))
8451da177e4SLinus Torvalds 		return 0;
8461da177e4SLinus Torvalds 	/* if not yet claimed, claim it for the driver */
84704e482ffSGreg Kroah-Hartman 	dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
84804e482ffSGreg Kroah-Hartman 		 "interface %u before use\n", task_pid_nr(current),
84904e482ffSGreg Kroah-Hartman 		 current->comm, ifnum);
8501da177e4SLinus Torvalds 	return claimintf(ps, ifnum);
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
findintfep(struct usb_device * dev,unsigned int ep)8531da177e4SLinus Torvalds static int findintfep(struct usb_device *dev, unsigned int ep)
8541da177e4SLinus Torvalds {
8551da177e4SLinus Torvalds 	unsigned int i, j, e;
8561da177e4SLinus Torvalds 	struct usb_interface *intf;
8571da177e4SLinus Torvalds 	struct usb_host_interface *alts;
8581da177e4SLinus Torvalds 	struct usb_endpoint_descriptor *endpt;
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 	if (ep & ~(USB_DIR_IN|0xf))
8611da177e4SLinus Torvalds 		return -EINVAL;
8621da177e4SLinus Torvalds 	if (!dev->actconfig)
8631da177e4SLinus Torvalds 		return -ESRCH;
8641da177e4SLinus Torvalds 	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
8651da177e4SLinus Torvalds 		intf = dev->actconfig->interface[i];
8661da177e4SLinus Torvalds 		for (j = 0; j < intf->num_altsetting; j++) {
8671da177e4SLinus Torvalds 			alts = &intf->altsetting[j];
8681da177e4SLinus Torvalds 			for (e = 0; e < alts->desc.bNumEndpoints; e++) {
8691da177e4SLinus Torvalds 				endpt = &alts->endpoint[e].desc;
8701da177e4SLinus Torvalds 				if (endpt->bEndpointAddress == ep)
8711da177e4SLinus Torvalds 					return alts->desc.bInterfaceNumber;
8721da177e4SLinus Torvalds 			}
8731da177e4SLinus Torvalds 		}
8741da177e4SLinus Torvalds 	}
8751da177e4SLinus Torvalds 	return -ENOENT;
8761da177e4SLinus Torvalds }
8771da177e4SLinus Torvalds 
check_ctrlrecip(struct usb_dev_state * ps,unsigned int requesttype,unsigned int request,unsigned int index)8789b6f0c4bSValentina Manea static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,
879393cbb51SMatthias Dellweg 			   unsigned int request, unsigned int index)
8801da177e4SLinus Torvalds {
8811da177e4SLinus Torvalds 	int ret = 0;
882393cbb51SMatthias Dellweg 	struct usb_host_interface *alt_setting;
8831da177e4SLinus Torvalds 
8846da9c990SDavid Vrabel 	if (ps->dev->state != USB_STATE_UNAUTHENTICATED
8856da9c990SDavid Vrabel 	 && ps->dev->state != USB_STATE_ADDRESS
88624f8b116SHorst Schirmeier 	 && ps->dev->state != USB_STATE_CONFIGURED)
8871da177e4SLinus Torvalds 		return -EHOSTUNREACH;
8881da177e4SLinus Torvalds 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
8891da177e4SLinus Torvalds 		return 0;
8901da177e4SLinus Torvalds 
891393cbb51SMatthias Dellweg 	/*
892393cbb51SMatthias Dellweg 	 * check for the special corner case 'get_device_id' in the printer
8935dc50c35SHans de Goede 	 * class specification, which we always want to allow as it is used
8945dc50c35SHans de Goede 	 * to query things like ink level, etc.
895393cbb51SMatthias Dellweg 	 */
896393cbb51SMatthias Dellweg 	if (requesttype == 0xa1 && request == 0) {
897393cbb51SMatthias Dellweg 		alt_setting = usb_find_alt_setting(ps->dev->actconfig,
898393cbb51SMatthias Dellweg 						   index >> 8, index & 0xff);
899393cbb51SMatthias Dellweg 		if (alt_setting
900393cbb51SMatthias Dellweg 		 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
9015dc50c35SHans de Goede 			return 0;
902393cbb51SMatthias Dellweg 	}
903393cbb51SMatthias Dellweg 
9041da177e4SLinus Torvalds 	index &= 0xff;
9051da177e4SLinus Torvalds 	switch (requesttype & USB_RECIP_MASK) {
9061da177e4SLinus Torvalds 	case USB_RECIP_ENDPOINT:
9071361bf4bSHans de Goede 		if ((index & ~USB_DIR_IN) == 0)
9081361bf4bSHans de Goede 			return 0;
90904e482ffSGreg Kroah-Hartman 		ret = findintfep(ps->dev, index);
910831abf76SKurt Garloff 		if (ret < 0) {
911831abf76SKurt Garloff 			/*
912831abf76SKurt Garloff 			 * Some not fully compliant Win apps seem to get
913831abf76SKurt Garloff 			 * index wrong and have the endpoint number here
914831abf76SKurt Garloff 			 * rather than the endpoint address (with the
915831abf76SKurt Garloff 			 * correct direction). Win does let this through,
916831abf76SKurt Garloff 			 * so we'll not reject it here but leave it to
917831abf76SKurt Garloff 			 * the device to not break KVM. But we warn.
918831abf76SKurt Garloff 			 */
919831abf76SKurt Garloff 			ret = findintfep(ps->dev, index ^ 0x80);
920831abf76SKurt Garloff 			if (ret >= 0)
921831abf76SKurt Garloff 				dev_info(&ps->dev->dev,
922831abf76SKurt Garloff 					"%s: process %i (%s) requesting ep %02x but needs %02x\n",
923831abf76SKurt Garloff 					__func__, task_pid_nr(current),
924831abf76SKurt Garloff 					current->comm, index, index ^ 0x80);
925831abf76SKurt Garloff 		}
92604e482ffSGreg Kroah-Hartman 		if (ret >= 0)
9271da177e4SLinus Torvalds 			ret = checkintf(ps, ret);
9281da177e4SLinus Torvalds 		break;
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	case USB_RECIP_INTERFACE:
9311da177e4SLinus Torvalds 		ret = checkintf(ps, index);
9321da177e4SLinus Torvalds 		break;
9331da177e4SLinus Torvalds 	}
9341da177e4SLinus Torvalds 	return ret;
9351da177e4SLinus Torvalds }
9361da177e4SLinus Torvalds 
ep_to_host_endpoint(struct usb_device * dev,unsigned char ep)9372fec32b0SHans de Goede static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
9382fec32b0SHans de Goede 						     unsigned char ep)
9392fec32b0SHans de Goede {
9402fec32b0SHans de Goede 	if (ep & USB_ENDPOINT_DIR_MASK)
9412fec32b0SHans de Goede 		return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK];
9422fec32b0SHans de Goede 	else
9432fec32b0SHans de Goede 		return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
9442fec32b0SHans de Goede }
9452fec32b0SHans de Goede 
parse_usbdevfs_streams(struct usb_dev_state * ps,struct usbdevfs_streams __user * streams,unsigned int * num_streams_ret,unsigned int * num_eps_ret,struct usb_host_endpoint *** eps_ret,struct usb_interface ** intf_ret)9463e75c6deSLinus Torvalds static int parse_usbdevfs_streams(struct usb_dev_state *ps,
947bcf7f6e3SHans de Goede 				  struct usbdevfs_streams __user *streams,
948bcf7f6e3SHans de Goede 				  unsigned int *num_streams_ret,
949bcf7f6e3SHans de Goede 				  unsigned int *num_eps_ret,
950bcf7f6e3SHans de Goede 				  struct usb_host_endpoint ***eps_ret,
951bcf7f6e3SHans de Goede 				  struct usb_interface **intf_ret)
952bcf7f6e3SHans de Goede {
953bcf7f6e3SHans de Goede 	unsigned int i, num_streams, num_eps;
954bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
955bcf7f6e3SHans de Goede 	struct usb_interface *intf = NULL;
956bcf7f6e3SHans de Goede 	unsigned char ep;
957bcf7f6e3SHans de Goede 	int ifnum, ret;
958bcf7f6e3SHans de Goede 
959bcf7f6e3SHans de Goede 	if (get_user(num_streams, &streams->num_streams) ||
960bcf7f6e3SHans de Goede 	    get_user(num_eps, &streams->num_eps))
961bcf7f6e3SHans de Goede 		return -EFAULT;
962bcf7f6e3SHans de Goede 
963bcf7f6e3SHans de Goede 	if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
964bcf7f6e3SHans de Goede 		return -EINVAL;
965bcf7f6e3SHans de Goede 
966bcf7f6e3SHans de Goede 	/* The XHCI controller allows max 2 ^ 16 streams */
967bcf7f6e3SHans de Goede 	if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
968bcf7f6e3SHans de Goede 		return -EINVAL;
969bcf7f6e3SHans de Goede 
9706da2ec56SKees Cook 	eps = kmalloc_array(num_eps, sizeof(*eps), GFP_KERNEL);
971bcf7f6e3SHans de Goede 	if (!eps)
972bcf7f6e3SHans de Goede 		return -ENOMEM;
973bcf7f6e3SHans de Goede 
974bcf7f6e3SHans de Goede 	for (i = 0; i < num_eps; i++) {
975bcf7f6e3SHans de Goede 		if (get_user(ep, &streams->eps[i])) {
976bcf7f6e3SHans de Goede 			ret = -EFAULT;
977bcf7f6e3SHans de Goede 			goto error;
978bcf7f6e3SHans de Goede 		}
979bcf7f6e3SHans de Goede 		eps[i] = ep_to_host_endpoint(ps->dev, ep);
980bcf7f6e3SHans de Goede 		if (!eps[i]) {
981bcf7f6e3SHans de Goede 			ret = -EINVAL;
982bcf7f6e3SHans de Goede 			goto error;
983bcf7f6e3SHans de Goede 		}
984bcf7f6e3SHans de Goede 
985bcf7f6e3SHans de Goede 		/* usb_alloc/free_streams operate on an usb_interface */
986bcf7f6e3SHans de Goede 		ifnum = findintfep(ps->dev, ep);
987bcf7f6e3SHans de Goede 		if (ifnum < 0) {
988bcf7f6e3SHans de Goede 			ret = ifnum;
989bcf7f6e3SHans de Goede 			goto error;
990bcf7f6e3SHans de Goede 		}
991bcf7f6e3SHans de Goede 
992bcf7f6e3SHans de Goede 		if (i == 0) {
993bcf7f6e3SHans de Goede 			ret = checkintf(ps, ifnum);
994bcf7f6e3SHans de Goede 			if (ret < 0)
995bcf7f6e3SHans de Goede 				goto error;
996bcf7f6e3SHans de Goede 			intf = usb_ifnum_to_if(ps->dev, ifnum);
997bcf7f6e3SHans de Goede 		} else {
998bcf7f6e3SHans de Goede 			/* Verify all eps belong to the same interface */
999bcf7f6e3SHans de Goede 			if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
1000bcf7f6e3SHans de Goede 				ret = -EINVAL;
1001bcf7f6e3SHans de Goede 				goto error;
1002bcf7f6e3SHans de Goede 			}
1003bcf7f6e3SHans de Goede 		}
1004bcf7f6e3SHans de Goede 	}
1005bcf7f6e3SHans de Goede 
1006bcf7f6e3SHans de Goede 	if (num_streams_ret)
1007bcf7f6e3SHans de Goede 		*num_streams_ret = num_streams;
1008bcf7f6e3SHans de Goede 	*num_eps_ret = num_eps;
1009bcf7f6e3SHans de Goede 	*eps_ret = eps;
1010bcf7f6e3SHans de Goede 	*intf_ret = intf;
1011bcf7f6e3SHans de Goede 
1012bcf7f6e3SHans de Goede 	return 0;
1013bcf7f6e3SHans de Goede 
1014bcf7f6e3SHans de Goede error:
1015bcf7f6e3SHans de Goede 	kfree(eps);
1016bcf7f6e3SHans de Goede 	return ret;
1017bcf7f6e3SHans de Goede }
1018bcf7f6e3SHans de Goede 
usbdev_lookup_by_devt(dev_t devt)101961ad04a8SAlan Stern static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
10209f8b17e6SKay Sievers {
10219f8b17e6SKay Sievers 	struct device *dev;
10229f8b17e6SKay Sievers 
10234495dfddSSuzuki K Poulose 	dev = bus_find_device_by_devt(&usb_bus_type, devt);
10249f8b17e6SKay Sievers 	if (!dev)
10259f8b17e6SKay Sievers 		return NULL;
102669ab55d7SGeliang Tang 	return to_usb_device(dev);
10279f8b17e6SKay Sievers }
10284592bf5aSGreg Kroah-Hartman 
10291da177e4SLinus Torvalds /*
10301da177e4SLinus Torvalds  * file operations
10311da177e4SLinus Torvalds  */
usbdev_open(struct inode * inode,struct file * file)10321da177e4SLinus Torvalds static int usbdev_open(struct inode *inode, struct file *file)
10331da177e4SLinus Torvalds {
1034fbf82fd2SKay Sievers 	struct usb_device *dev = NULL;
10359b6f0c4bSValentina Manea 	struct usb_dev_state *ps;
10361da177e4SLinus Torvalds 	int ret;
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 	ret = -ENOMEM;
1039d883f52eSReilly Grant 	ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
104004e482ffSGreg Kroah-Hartman 	if (!ps)
104162e299e6SAlan Stern 		goto out_free_ps;
10421da177e4SLinus Torvalds 
104301105a24SAlan Stern 	ret = -ENODEV;
104461ad04a8SAlan Stern 
10459f8b17e6SKay Sievers 	/* usbdev device-node */
1046fbf82fd2SKay Sievers 	if (imajor(inode) == USB_DEVICE_MAJOR)
104761ad04a8SAlan Stern 		dev = usbdev_lookup_by_devt(inode->i_rdev);
104862e299e6SAlan Stern 	if (!dev)
104962e299e6SAlan Stern 		goto out_free_ps;
105062e299e6SAlan Stern 
105162e299e6SAlan Stern 	usb_lock_device(dev);
105262e299e6SAlan Stern 	if (dev->state == USB_STATE_NOTATTACHED)
105362e299e6SAlan Stern 		goto out_unlock_device;
105462e299e6SAlan Stern 
105594fcda1fSAlan Stern 	ret = usb_autoresume_device(dev);
105601d883d4SAlan Stern 	if (ret)
105762e299e6SAlan Stern 		goto out_unlock_device;
105801d883d4SAlan Stern 
10591da177e4SLinus Torvalds 	ps->dev = dev;
10601da177e4SLinus Torvalds 	ps->file = file;
1061d883f52eSReilly Grant 	ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
10621da177e4SLinus Torvalds 	spin_lock_init(&ps->lock);
1063316547fdSDan Carpenter 	INIT_LIST_HEAD(&ps->list);
10641da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ps->async_pending);
10651da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ps->async_completed);
1066f7d34b44SSteinar H. Gunderson 	INIT_LIST_HEAD(&ps->memory_list);
10671da177e4SLinus Torvalds 	init_waitqueue_head(&ps->wait);
10687794f486SAlan Stern 	init_waitqueue_head(&ps->wait_for_resume);
10692425c08bSEric W. Biederman 	ps->disc_pid = get_pid(task_pid(current));
1070d178bc3aSSerge Hallyn 	ps->cred = get_current_cred();
1071527660a8SOliver Neukum 	smp_wmb();
10727794f486SAlan Stern 
10737794f486SAlan Stern 	/* Can't race with resume; the device is already active */
10741da177e4SLinus Torvalds 	list_add_tail(&ps->list, &dev->filelist);
10751da177e4SLinus Torvalds 	file->private_data = ps;
107662e299e6SAlan Stern 	usb_unlock_device(dev);
10772da41d5fSAlan Stern 	snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
10782da41d5fSAlan Stern 			current->comm);
107962e299e6SAlan Stern 	return ret;
108062e299e6SAlan Stern 
108162e299e6SAlan Stern  out_unlock_device:
108262e299e6SAlan Stern 	usb_unlock_device(dev);
1083d64aac36SAlan Stern 	usb_put_dev(dev);
108462e299e6SAlan Stern  out_free_ps:
108562e299e6SAlan Stern 	kfree(ps);
10861da177e4SLinus Torvalds 	return ret;
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds 
usbdev_release(struct inode * inode,struct file * file)10891da177e4SLinus Torvalds static int usbdev_release(struct inode *inode, struct file *file)
10901da177e4SLinus Torvalds {
10919b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
10921da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
10931da177e4SLinus Torvalds 	unsigned int ifnum;
10946ff10464SAlan Stern 	struct async *as;
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	usb_lock_device(dev);
10977cbe5dcaSAlan Stern 	usb_hub_release_all_ports(dev, ps);
10984a2a8a2cSAlan Stern 
10997794f486SAlan Stern 	/* Protect against simultaneous resume */
11007794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
11011da177e4SLinus Torvalds 	list_del_init(&ps->list);
11027794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
11034a2a8a2cSAlan Stern 
11041da177e4SLinus Torvalds 	for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
11051da177e4SLinus Torvalds 			ifnum++) {
11061da177e4SLinus Torvalds 		if (test_bit(ifnum, &ps->ifclaimed))
11071da177e4SLinus Torvalds 			releaseintf(ps, ifnum);
11081da177e4SLinus Torvalds 	}
11091da177e4SLinus Torvalds 	destroy_all_async(ps);
11107794f486SAlan Stern 	if (!ps->suspend_allowed)
111194fcda1fSAlan Stern 		usb_autosuspend_device(dev);
11121da177e4SLinus Torvalds 	usb_unlock_device(dev);
11131da177e4SLinus Torvalds 	usb_put_dev(dev);
11142425c08bSEric W. Biederman 	put_pid(ps->disc_pid);
1115d178bc3aSSerge Hallyn 	put_cred(ps->cred);
11166ff10464SAlan Stern 
11176ff10464SAlan Stern 	as = async_getcompleted(ps);
11186ff10464SAlan Stern 	while (as) {
11196ff10464SAlan Stern 		free_async(as);
11206ff10464SAlan Stern 		as = async_getcompleted(ps);
11216ff10464SAlan Stern 	}
1122f7d34b44SSteinar H. Gunderson 
11231da177e4SLinus Torvalds 	kfree(ps);
11241da177e4SLinus Torvalds 	return 0;
11251da177e4SLinus Torvalds }
11261da177e4SLinus Torvalds 
usbfs_blocking_completion(struct urb * urb)1127ae8709b2SAlan Stern static void usbfs_blocking_completion(struct urb *urb)
1128ae8709b2SAlan Stern {
1129ae8709b2SAlan Stern 	complete((struct completion *) urb->context);
1130ae8709b2SAlan Stern }
1131ae8709b2SAlan Stern 
1132ae8709b2SAlan Stern /*
1133ae8709b2SAlan Stern  * Much like usb_start_wait_urb, but returns status separately from
1134ae8709b2SAlan Stern  * actual_length and uses a killable wait.
1135ae8709b2SAlan Stern  */
usbfs_start_wait_urb(struct urb * urb,int timeout,unsigned int * actlen)1136ae8709b2SAlan Stern static int usbfs_start_wait_urb(struct urb *urb, int timeout,
1137ae8709b2SAlan Stern 		unsigned int *actlen)
1138ae8709b2SAlan Stern {
1139ae8709b2SAlan Stern 	DECLARE_COMPLETION_ONSTACK(ctx);
1140ae8709b2SAlan Stern 	unsigned long expire;
1141ae8709b2SAlan Stern 	int rc;
1142ae8709b2SAlan Stern 
1143ae8709b2SAlan Stern 	urb->context = &ctx;
1144ae8709b2SAlan Stern 	urb->complete = usbfs_blocking_completion;
1145ae8709b2SAlan Stern 	*actlen = 0;
1146ae8709b2SAlan Stern 	rc = usb_submit_urb(urb, GFP_KERNEL);
1147ae8709b2SAlan Stern 	if (unlikely(rc))
1148ae8709b2SAlan Stern 		return rc;
1149ae8709b2SAlan Stern 
1150ae8709b2SAlan Stern 	expire = (timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT);
1151ae8709b2SAlan Stern 	rc = wait_for_completion_killable_timeout(&ctx, expire);
1152ae8709b2SAlan Stern 	if (rc <= 0) {
1153ae8709b2SAlan Stern 		usb_kill_urb(urb);
1154ae8709b2SAlan Stern 		*actlen = urb->actual_length;
1155ae8709b2SAlan Stern 		if (urb->status != -ENOENT)
1156ae8709b2SAlan Stern 			;	/* Completed before it was killed */
1157ae8709b2SAlan Stern 		else if (rc < 0)
1158ae8709b2SAlan Stern 			return -EINTR;
1159ae8709b2SAlan Stern 		else
1160ae8709b2SAlan Stern 			return -ETIMEDOUT;
1161ae8709b2SAlan Stern 	}
1162ae8709b2SAlan Stern 	*actlen = urb->actual_length;
1163ae8709b2SAlan Stern 	return urb->status;
1164ae8709b2SAlan Stern }
1165ae8709b2SAlan Stern 
do_proc_control(struct usb_dev_state * ps,struct usbdevfs_ctrltransfer * ctrl)1166c17536d0SChristoph Hellwig static int do_proc_control(struct usb_dev_state *ps,
1167c17536d0SChristoph Hellwig 		struct usbdevfs_ctrltransfer *ctrl)
11681da177e4SLinus Torvalds {
11691da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
11701da177e4SLinus Torvalds 	unsigned int tmo;
11711da177e4SLinus Torvalds 	unsigned char *tbuf;
1172ae8709b2SAlan Stern 	unsigned int wLength, actlen;
11734c6e8971SAlan Stern 	int i, pipe, ret;
1174ae8709b2SAlan Stern 	struct urb *urb = NULL;
1175ae8709b2SAlan Stern 	struct usb_ctrlrequest *dr = NULL;
11761da177e4SLinus Torvalds 
1177c17536d0SChristoph Hellwig 	ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest,
1178c17536d0SChristoph Hellwig 			      ctrl->wIndex);
117904e482ffSGreg Kroah-Hartman 	if (ret)
11801da177e4SLinus Torvalds 		return ret;
1181c17536d0SChristoph Hellwig 	wLength = ctrl->wLength;	/* To suppress 64k PAGE_SIZE warning */
1182ff66e3ceSAndrew Morton 	if (wLength > PAGE_SIZE)
11831da177e4SLinus Torvalds 		return -EINVAL;
1184add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
1185add1aaeaSAlan Stern 			sizeof(struct usb_ctrlrequest));
1186add1aaeaSAlan Stern 	if (ret)
1187add1aaeaSAlan Stern 		return ret;
1188ae8709b2SAlan Stern 
1189add1aaeaSAlan Stern 	ret = -ENOMEM;
1190ae8709b2SAlan Stern 	tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
1191ae8709b2SAlan Stern 	if (!tbuf)
1192add1aaeaSAlan Stern 		goto done;
1193ae8709b2SAlan Stern 	urb = usb_alloc_urb(0, GFP_NOIO);
1194ae8709b2SAlan Stern 	if (!urb)
1195ae8709b2SAlan Stern 		goto done;
1196ae8709b2SAlan Stern 	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
1197ae8709b2SAlan Stern 	if (!dr)
1198ae8709b2SAlan Stern 		goto done;
1199ae8709b2SAlan Stern 
1200ae8709b2SAlan Stern 	dr->bRequestType = ctrl->bRequestType;
1201ae8709b2SAlan Stern 	dr->bRequest = ctrl->bRequest;
1202ae8709b2SAlan Stern 	dr->wValue = cpu_to_le16(ctrl->wValue);
1203ae8709b2SAlan Stern 	dr->wIndex = cpu_to_le16(ctrl->wIndex);
1204ae8709b2SAlan Stern 	dr->wLength = cpu_to_le16(ctrl->wLength);
1205ae8709b2SAlan Stern 
1206c17536d0SChristoph Hellwig 	tmo = ctrl->timeout;
12070880aef4SChris Frey 	snoop(&dev->dev, "control urb: bRequestType=%02x "
12080880aef4SChris Frey 		"bRequest=%02x wValue=%04x "
12090880aef4SChris Frey 		"wIndex=%04x wLength=%04x\n",
1210c17536d0SChristoph Hellwig 		ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
1211c17536d0SChristoph Hellwig 		ctrl->wIndex, ctrl->wLength);
1212ae8709b2SAlan Stern 
1213ae8709b2SAlan Stern 	if ((ctrl->bRequestType & USB_DIR_IN) && wLength) {
12144c6e8971SAlan Stern 		pipe = usb_rcvctrlpipe(dev, 0);
1215ae8709b2SAlan Stern 		usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
1216ae8709b2SAlan Stern 				wLength, NULL, NULL);
1217ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, NULL, 0);
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 		usb_unlock_device(dev);
1220ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &actlen);
12210543e4e8STasos Sahanidis 
12220543e4e8STasos Sahanidis 		/* Linger a bit, prior to the next control message. */
12230543e4e8STasos Sahanidis 		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
12240543e4e8STasos Sahanidis 			msleep(200);
12251da177e4SLinus Torvalds 		usb_lock_device(dev);
1226ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, tbuf, actlen);
1227ae8709b2SAlan Stern 		if (!i && actlen) {
1228ae8709b2SAlan Stern 			if (copy_to_user(ctrl->data, tbuf, actlen)) {
122952fb743dSAlan Stern 				ret = -EFAULT;
12300543e4e8STasos Sahanidis 				goto done;
12311da177e4SLinus Torvalds 			}
12321da177e4SLinus Torvalds 		}
12331da177e4SLinus Torvalds 	} else {
1234ae8709b2SAlan Stern 		if (wLength) {
1235ae8709b2SAlan Stern 			if (copy_from_user(tbuf, ctrl->data, wLength)) {
123652fb743dSAlan Stern 				ret = -EFAULT;
123752fb743dSAlan Stern 				goto done;
12381da177e4SLinus Torvalds 			}
12391da177e4SLinus Torvalds 		}
12404c6e8971SAlan Stern 		pipe = usb_sndctrlpipe(dev, 0);
1241ae8709b2SAlan Stern 		usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
1242ae8709b2SAlan Stern 				wLength, NULL, NULL);
1243ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, tbuf, wLength);
12444c6e8971SAlan Stern 
12451da177e4SLinus Torvalds 		usb_unlock_device(dev);
1246ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &actlen);
12470543e4e8STasos Sahanidis 
12480543e4e8STasos Sahanidis 		/* Linger a bit, prior to the next control message. */
12490543e4e8STasos Sahanidis 		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
12500543e4e8STasos Sahanidis 			msleep(200);
12511da177e4SLinus Torvalds 		usb_lock_device(dev);
1252ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, NULL, 0);
12531da177e4SLinus Torvalds 	}
12541da177e4SLinus Torvalds 	if (i < 0 && i != -EPIPE) {
12551da177e4SLinus Torvalds 		dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
12561da177e4SLinus Torvalds 			   "failed cmd %s rqt %u rq %u len %u ret %d\n",
1257c17536d0SChristoph Hellwig 			   current->comm, ctrl->bRequestType, ctrl->bRequest,
1258c17536d0SChristoph Hellwig 			   ctrl->wLength, i);
12591da177e4SLinus Torvalds 	}
1260ae8709b2SAlan Stern 	ret = (i < 0 ? i : actlen);
1261ae8709b2SAlan Stern 
126252fb743dSAlan Stern  done:
1263ae8709b2SAlan Stern 	kfree(dr);
1264ae8709b2SAlan Stern 	usb_free_urb(urb);
126552fb743dSAlan Stern 	free_page((unsigned long) tbuf);
1266add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
1267add1aaeaSAlan Stern 			sizeof(struct usb_ctrlrequest));
126852fb743dSAlan Stern 	return ret;
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds 
proc_control(struct usb_dev_state * ps,void __user * arg)1271c17536d0SChristoph Hellwig static int proc_control(struct usb_dev_state *ps, void __user *arg)
1272c17536d0SChristoph Hellwig {
1273c17536d0SChristoph Hellwig 	struct usbdevfs_ctrltransfer ctrl;
1274c17536d0SChristoph Hellwig 
1275c17536d0SChristoph Hellwig 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
1276c17536d0SChristoph Hellwig 		return -EFAULT;
1277c17536d0SChristoph Hellwig 	return do_proc_control(ps, &ctrl);
1278c17536d0SChristoph Hellwig }
1279c17536d0SChristoph Hellwig 
do_proc_bulk(struct usb_dev_state * ps,struct usbdevfs_bulktransfer * bulk)1280c17536d0SChristoph Hellwig static int do_proc_bulk(struct usb_dev_state *ps,
1281c17536d0SChristoph Hellwig 		struct usbdevfs_bulktransfer *bulk)
12821da177e4SLinus Torvalds {
12831da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
1284ae8709b2SAlan Stern 	unsigned int tmo, len1, len2, pipe;
12851da177e4SLinus Torvalds 	unsigned char *tbuf;
12864c6e8971SAlan Stern 	int i, ret;
1287ae8709b2SAlan Stern 	struct urb *urb = NULL;
1288ae8709b2SAlan Stern 	struct usb_host_endpoint *ep;
12891da177e4SLinus Torvalds 
1290c17536d0SChristoph Hellwig 	ret = findintfep(ps->dev, bulk->ep);
129104e482ffSGreg Kroah-Hartman 	if (ret < 0)
12921da177e4SLinus Torvalds 		return ret;
129304e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
129404e482ffSGreg Kroah-Hartman 	if (ret)
12951da177e4SLinus Torvalds 		return ret;
1296ae8709b2SAlan Stern 
1297ae8709b2SAlan Stern 	len1 = bulk->len;
1298ae8709b2SAlan Stern 	if (len1 < 0 || len1 >= (INT_MAX - sizeof(struct urb)))
1299ae8709b2SAlan Stern 		return -EINVAL;
1300ae8709b2SAlan Stern 
1301c17536d0SChristoph Hellwig 	if (bulk->ep & USB_DIR_IN)
1302c17536d0SChristoph Hellwig 		pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f);
13031da177e4SLinus Torvalds 	else
1304c17536d0SChristoph Hellwig 		pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f);
1305ae8709b2SAlan Stern 	ep = usb_pipe_endpoint(dev, pipe);
1306ae8709b2SAlan Stern 	if (!ep || !usb_endpoint_maxp(&ep->desc))
13071da177e4SLinus Torvalds 		return -EINVAL;
1308add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
1309add1aaeaSAlan Stern 	if (ret)
1310add1aaeaSAlan Stern 		return ret;
13114f2629eaSAlan Stern 
13124f2629eaSAlan Stern 	/*
13134f2629eaSAlan Stern 	 * len1 can be almost arbitrarily large.  Don't WARN if it's
13144f2629eaSAlan Stern 	 * too big, just fail the request.
13154f2629eaSAlan Stern 	 */
1316add1aaeaSAlan Stern 	ret = -ENOMEM;
1317ae8709b2SAlan Stern 	tbuf = kmalloc(len1, GFP_KERNEL | __GFP_NOWARN);
1318ae8709b2SAlan Stern 	if (!tbuf)
1319add1aaeaSAlan Stern 		goto done;
1320ae8709b2SAlan Stern 	urb = usb_alloc_urb(0, GFP_KERNEL);
1321ae8709b2SAlan Stern 	if (!urb)
1322ae8709b2SAlan Stern 		goto done;
1323ae8709b2SAlan Stern 
1324ae8709b2SAlan Stern 	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
1325ae8709b2SAlan Stern 			USB_ENDPOINT_XFER_INT) {
1326ae8709b2SAlan Stern 		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
1327ae8709b2SAlan Stern 		usb_fill_int_urb(urb, dev, pipe, tbuf, len1,
1328ae8709b2SAlan Stern 				NULL, NULL, ep->desc.bInterval);
1329ae8709b2SAlan Stern 	} else {
1330ae8709b2SAlan Stern 		usb_fill_bulk_urb(urb, dev, pipe, tbuf, len1, NULL, NULL);
1331add1aaeaSAlan Stern 	}
1332ae8709b2SAlan Stern 
1333c17536d0SChristoph Hellwig 	tmo = bulk->timeout;
1334c17536d0SChristoph Hellwig 	if (bulk->ep & 0x80) {
13350880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
13364c6e8971SAlan Stern 
13371da177e4SLinus Torvalds 		usb_unlock_device(dev);
1338ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &len2);
13391da177e4SLinus Torvalds 		usb_lock_device(dev);
13400880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
13414c6e8971SAlan Stern 
13421da177e4SLinus Torvalds 		if (!i && len2) {
1343c17536d0SChristoph Hellwig 			if (copy_to_user(bulk->data, tbuf, len2)) {
134452fb743dSAlan Stern 				ret = -EFAULT;
134552fb743dSAlan Stern 				goto done;
13461da177e4SLinus Torvalds 			}
13471da177e4SLinus Torvalds 		}
13481da177e4SLinus Torvalds 	} else {
13491da177e4SLinus Torvalds 		if (len1) {
1350c17536d0SChristoph Hellwig 			if (copy_from_user(tbuf, bulk->data, len1)) {
135152fb743dSAlan Stern 				ret = -EFAULT;
135252fb743dSAlan Stern 				goto done;
13531da177e4SLinus Torvalds 			}
13541da177e4SLinus Torvalds 		}
13550880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
13564c6e8971SAlan Stern 
13571da177e4SLinus Torvalds 		usb_unlock_device(dev);
1358ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &len2);
13591da177e4SLinus Torvalds 		usb_lock_device(dev);
13600880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
13611da177e4SLinus Torvalds 	}
136252fb743dSAlan Stern 	ret = (i < 0 ? i : len2);
136352fb743dSAlan Stern  done:
1364ae8709b2SAlan Stern 	usb_free_urb(urb);
13651da177e4SLinus Torvalds 	kfree(tbuf);
1366add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
136752fb743dSAlan Stern 	return ret;
13681da177e4SLinus Torvalds }
13691da177e4SLinus Torvalds 
proc_bulk(struct usb_dev_state * ps,void __user * arg)1370c17536d0SChristoph Hellwig static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
1371c17536d0SChristoph Hellwig {
1372c17536d0SChristoph Hellwig 	struct usbdevfs_bulktransfer bulk;
1373c17536d0SChristoph Hellwig 
1374c17536d0SChristoph Hellwig 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
1375c17536d0SChristoph Hellwig 		return -EFAULT;
1376c17536d0SChristoph Hellwig 	return do_proc_bulk(ps, &bulk);
1377c17536d0SChristoph Hellwig }
1378c17536d0SChristoph Hellwig 
check_reset_of_active_ep(struct usb_device * udev,unsigned int epnum,char * ioctl_name)1379f080a51bSAlan Stern static void check_reset_of_active_ep(struct usb_device *udev,
1380f080a51bSAlan Stern 		unsigned int epnum, char *ioctl_name)
1381f080a51bSAlan Stern {
1382f080a51bSAlan Stern 	struct usb_host_endpoint **eps;
1383f080a51bSAlan Stern 	struct usb_host_endpoint *ep;
1384f080a51bSAlan Stern 
1385f080a51bSAlan Stern 	eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out;
1386f080a51bSAlan Stern 	ep = eps[epnum & 0x0f];
1387f080a51bSAlan Stern 	if (ep && !list_empty(&ep->urb_list))
1388f080a51bSAlan Stern 		dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n",
1389f080a51bSAlan Stern 				task_pid_nr(current), current->comm,
1390f080a51bSAlan Stern 				ioctl_name, epnum);
1391f080a51bSAlan Stern }
1392f080a51bSAlan Stern 
proc_resetep(struct usb_dev_state * ps,void __user * arg)13939b6f0c4bSValentina Manea static int proc_resetep(struct usb_dev_state *ps, void __user *arg)
13941da177e4SLinus Torvalds {
13951da177e4SLinus Torvalds 	unsigned int ep;
13961da177e4SLinus Torvalds 	int ret;
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds 	if (get_user(ep, (unsigned int __user *)arg))
13991da177e4SLinus Torvalds 		return -EFAULT;
140004e482ffSGreg Kroah-Hartman 	ret = findintfep(ps->dev, ep);
140104e482ffSGreg Kroah-Hartman 	if (ret < 0)
14021da177e4SLinus Torvalds 		return ret;
140304e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
140404e482ffSGreg Kroah-Hartman 	if (ret)
14051da177e4SLinus Torvalds 		return ret;
1406f080a51bSAlan Stern 	check_reset_of_active_ep(ps->dev, ep, "RESETEP");
14073444b26aSDavid Vrabel 	usb_reset_endpoint(ps->dev, ep);
14081da177e4SLinus Torvalds 	return 0;
14091da177e4SLinus Torvalds }
14101da177e4SLinus Torvalds 
proc_clearhalt(struct usb_dev_state * ps,void __user * arg)14119b6f0c4bSValentina Manea static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)
14121da177e4SLinus Torvalds {
14131da177e4SLinus Torvalds 	unsigned int ep;
14141da177e4SLinus Torvalds 	int pipe;
14151da177e4SLinus Torvalds 	int ret;
14161da177e4SLinus Torvalds 
14171da177e4SLinus Torvalds 	if (get_user(ep, (unsigned int __user *)arg))
14181da177e4SLinus Torvalds 		return -EFAULT;
141904e482ffSGreg Kroah-Hartman 	ret = findintfep(ps->dev, ep);
142004e482ffSGreg Kroah-Hartman 	if (ret < 0)
14211da177e4SLinus Torvalds 		return ret;
142204e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
142304e482ffSGreg Kroah-Hartman 	if (ret)
14241da177e4SLinus Torvalds 		return ret;
1425f080a51bSAlan Stern 	check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");
14261da177e4SLinus Torvalds 	if (ep & USB_DIR_IN)
14271da177e4SLinus Torvalds 		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
14281da177e4SLinus Torvalds 	else
14291da177e4SLinus Torvalds 		pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
14301da177e4SLinus Torvalds 
14311da177e4SLinus Torvalds 	return usb_clear_halt(ps->dev, pipe);
14321da177e4SLinus Torvalds }
14331da177e4SLinus Torvalds 
proc_getdriver(struct usb_dev_state * ps,void __user * arg)14349b6f0c4bSValentina Manea static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
14351da177e4SLinus Torvalds {
14361da177e4SLinus Torvalds 	struct usbdevfs_getdriver gd;
14371da177e4SLinus Torvalds 	struct usb_interface *intf;
14381da177e4SLinus Torvalds 	int ret;
14391da177e4SLinus Torvalds 
14401da177e4SLinus Torvalds 	if (copy_from_user(&gd, arg, sizeof(gd)))
14411da177e4SLinus Torvalds 		return -EFAULT;
14421da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(ps->dev, gd.interface);
14431da177e4SLinus Torvalds 	if (!intf || !intf->dev.driver)
14441da177e4SLinus Torvalds 		ret = -ENODATA;
14451da177e4SLinus Torvalds 	else {
1446b7db5733SWolfram Sang 		strscpy(gd.driver, intf->dev.driver->name,
14471da177e4SLinus Torvalds 				sizeof(gd.driver));
14481da177e4SLinus Torvalds 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
14491da177e4SLinus Torvalds 	}
14501da177e4SLinus Torvalds 	return ret;
14511da177e4SLinus Torvalds }
14521da177e4SLinus Torvalds 
proc_connectinfo(struct usb_dev_state * ps,void __user * arg)14539b6f0c4bSValentina Manea static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
14541da177e4SLinus Torvalds {
1455681fef83SKangjie Lu 	struct usbdevfs_connectinfo ci;
1456681fef83SKangjie Lu 
1457681fef83SKangjie Lu 	memset(&ci, 0, sizeof(ci));
1458681fef83SKangjie Lu 	ci.devnum = ps->dev->devnum;
1459681fef83SKangjie Lu 	ci.slow = ps->dev->speed == USB_SPEED_LOW;
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds 	if (copy_to_user(arg, &ci, sizeof(ci)))
14621da177e4SLinus Torvalds 		return -EFAULT;
14631da177e4SLinus Torvalds 	return 0;
14641da177e4SLinus Torvalds }
14651da177e4SLinus Torvalds 
proc_conninfo_ex(struct usb_dev_state * ps,void __user * arg,size_t size)14666d101f24SDmitry Torokhov static int proc_conninfo_ex(struct usb_dev_state *ps,
14676d101f24SDmitry Torokhov 			    void __user *arg, size_t size)
14686d101f24SDmitry Torokhov {
14696d101f24SDmitry Torokhov 	struct usbdevfs_conninfo_ex ci;
14706d101f24SDmitry Torokhov 	struct usb_device *udev = ps->dev;
14716d101f24SDmitry Torokhov 
14726d101f24SDmitry Torokhov 	if (size < sizeof(ci.size))
14736d101f24SDmitry Torokhov 		return -EINVAL;
14746d101f24SDmitry Torokhov 
14756d101f24SDmitry Torokhov 	memset(&ci, 0, sizeof(ci));
14766d101f24SDmitry Torokhov 	ci.size = sizeof(ci);
14776d101f24SDmitry Torokhov 	ci.busnum = udev->bus->busnum;
14786d101f24SDmitry Torokhov 	ci.devnum = udev->devnum;
14796d101f24SDmitry Torokhov 	ci.speed = udev->speed;
14806d101f24SDmitry Torokhov 
14816d101f24SDmitry Torokhov 	while (udev && udev->portnum != 0) {
14826d101f24SDmitry Torokhov 		if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
14836d101f24SDmitry Torokhov 			ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
14846d101f24SDmitry Torokhov 					udev->portnum;
14856d101f24SDmitry Torokhov 		udev = udev->parent;
14866d101f24SDmitry Torokhov 	}
14876d101f24SDmitry Torokhov 
14886d101f24SDmitry Torokhov 	if (ci.num_ports < ARRAY_SIZE(ci.ports))
14896d101f24SDmitry Torokhov 		memmove(&ci.ports[0],
14906d101f24SDmitry Torokhov 			&ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
14916d101f24SDmitry Torokhov 			ci.num_ports);
14926d101f24SDmitry Torokhov 
14936d101f24SDmitry Torokhov 	if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
14946d101f24SDmitry Torokhov 		return -EFAULT;
14956d101f24SDmitry Torokhov 
14966d101f24SDmitry Torokhov 	return 0;
14976d101f24SDmitry Torokhov }
14986d101f24SDmitry Torokhov 
proc_resetdevice(struct usb_dev_state * ps)14999b6f0c4bSValentina Manea static int proc_resetdevice(struct usb_dev_state *ps)
15001da177e4SLinus Torvalds {
1501d883f52eSReilly Grant 	struct usb_host_config *actconfig = ps->dev->actconfig;
1502d883f52eSReilly Grant 	struct usb_interface *interface;
1503d883f52eSReilly Grant 	int i, number;
1504d883f52eSReilly Grant 
1505d883f52eSReilly Grant 	/* Don't allow a device reset if the process has dropped the
1506d883f52eSReilly Grant 	 * privilege to do such things and any of the interfaces are
1507d883f52eSReilly Grant 	 * currently claimed.
1508d883f52eSReilly Grant 	 */
1509d883f52eSReilly Grant 	if (ps->privileges_dropped && actconfig) {
1510d883f52eSReilly Grant 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
1511d883f52eSReilly Grant 			interface = actconfig->interface[i];
1512d883f52eSReilly Grant 			number = interface->cur_altsetting->desc.bInterfaceNumber;
1513d883f52eSReilly Grant 			if (usb_interface_claimed(interface) &&
1514d883f52eSReilly Grant 					!test_bit(number, &ps->ifclaimed)) {
1515d883f52eSReilly Grant 				dev_warn(&ps->dev->dev,
1516d883f52eSReilly Grant 					"usbfs: interface %d claimed by %s while '%s' resets device\n",
1517d883f52eSReilly Grant 					number,	interface->dev.driver->name, current->comm);
1518d883f52eSReilly Grant 				return -EACCES;
1519d883f52eSReilly Grant 			}
1520d883f52eSReilly Grant 		}
1521d883f52eSReilly Grant 	}
1522d883f52eSReilly Grant 
1523742120c6SMing Lei 	return usb_reset_device(ps->dev);
15241da177e4SLinus Torvalds }
15251da177e4SLinus Torvalds 
proc_setintf(struct usb_dev_state * ps,void __user * arg)15269b6f0c4bSValentina Manea static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
15271da177e4SLinus Torvalds {
15281da177e4SLinus Torvalds 	struct usbdevfs_setinterface setintf;
15291da177e4SLinus Torvalds 	int ret;
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	if (copy_from_user(&setintf, arg, sizeof(setintf)))
15321da177e4SLinus Torvalds 		return -EFAULT;
1533135551eaSKris Borer 	ret = checkintf(ps, setintf.interface);
1534135551eaSKris Borer 	if (ret)
15351da177e4SLinus Torvalds 		return ret;
15365ec9c177SHans de Goede 
15375ec9c177SHans de Goede 	destroy_async_on_interface(ps, setintf.interface);
15385ec9c177SHans de Goede 
15391da177e4SLinus Torvalds 	return usb_set_interface(ps->dev, setintf.interface,
15401da177e4SLinus Torvalds 			setintf.altsetting);
15411da177e4SLinus Torvalds }
15421da177e4SLinus Torvalds 
proc_setconfig(struct usb_dev_state * ps,void __user * arg)15439b6f0c4bSValentina Manea static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
15441da177e4SLinus Torvalds {
15453f141e2aSAlan Stern 	int u;
15461da177e4SLinus Torvalds 	int status = 0;
15471da177e4SLinus Torvalds 	struct usb_host_config *actconfig;
15481da177e4SLinus Torvalds 
15493f141e2aSAlan Stern 	if (get_user(u, (int __user *)arg))
15501da177e4SLinus Torvalds 		return -EFAULT;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	actconfig = ps->dev->actconfig;
15531da177e4SLinus Torvalds 
15541da177e4SLinus Torvalds 	/* Don't touch the device if any interfaces are claimed.
15551da177e4SLinus Torvalds 	 * It could interfere with other drivers' operations, and if
15561da177e4SLinus Torvalds 	 * an interface is claimed by usbfs it could easily deadlock.
15571da177e4SLinus Torvalds 	 */
15581da177e4SLinus Torvalds 	if (actconfig) {
15591da177e4SLinus Torvalds 		int i;
15601da177e4SLinus Torvalds 
15611da177e4SLinus Torvalds 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
15621da177e4SLinus Torvalds 			if (usb_interface_claimed(actconfig->interface[i])) {
15631da177e4SLinus Torvalds 				dev_warn(&ps->dev->dev,
156472ebddb5SDavid Brownell 					"usbfs: interface %d claimed by %s "
15651da177e4SLinus Torvalds 					"while '%s' sets config #%d\n",
15661da177e4SLinus Torvalds 					actconfig->interface[i]
15671da177e4SLinus Torvalds 						->cur_altsetting
15681da177e4SLinus Torvalds 						->desc.bInterfaceNumber,
156972ebddb5SDavid Brownell 					actconfig->interface[i]
157072ebddb5SDavid Brownell 						->dev.driver->name,
15711da177e4SLinus Torvalds 					current->comm, u);
15721da177e4SLinus Torvalds 				status = -EBUSY;
15731da177e4SLinus Torvalds 				break;
15741da177e4SLinus Torvalds 			}
15751da177e4SLinus Torvalds 		}
15761da177e4SLinus Torvalds 	}
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds 	/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
15791da177e4SLinus Torvalds 	 * so avoid usb_set_configuration()'s kick to sysfs
15801da177e4SLinus Torvalds 	 */
15811da177e4SLinus Torvalds 	if (status == 0) {
15821da177e4SLinus Torvalds 		if (actconfig && actconfig->desc.bConfigurationValue == u)
15831da177e4SLinus Torvalds 			status = usb_reset_configuration(ps->dev);
15841da177e4SLinus Torvalds 		else
15851da177e4SLinus Torvalds 			status = usb_set_configuration(ps->dev, u);
15861da177e4SLinus Torvalds 	}
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds 	return status;
15891da177e4SLinus Torvalds }
15901da177e4SLinus Torvalds 
1591f7d34b44SSteinar H. Gunderson static struct usb_memory *
find_memory_area(struct usb_dev_state * ps,const struct usbdevfs_urb * uurb)1592f7d34b44SSteinar H. Gunderson find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
1593f7d34b44SSteinar H. Gunderson {
1594f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm = NULL, *iter;
1595f7d34b44SSteinar H. Gunderson 	unsigned long flags;
1596f7d34b44SSteinar H. Gunderson 	unsigned long uurb_start = (unsigned long)uurb->buffer;
1597f7d34b44SSteinar H. Gunderson 
1598f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&ps->lock, flags);
1599f7d34b44SSteinar H. Gunderson 	list_for_each_entry(iter, &ps->memory_list, memlist) {
1600f7d34b44SSteinar H. Gunderson 		if (uurb_start >= iter->vm_start &&
1601f7d34b44SSteinar H. Gunderson 				uurb_start < iter->vm_start + iter->size) {
1602f7d34b44SSteinar H. Gunderson 			if (uurb->buffer_length > iter->vm_start + iter->size -
1603f7d34b44SSteinar H. Gunderson 					uurb_start) {
1604f7d34b44SSteinar H. Gunderson 				usbm = ERR_PTR(-EINVAL);
1605f7d34b44SSteinar H. Gunderson 			} else {
1606f7d34b44SSteinar H. Gunderson 				usbm = iter;
1607f7d34b44SSteinar H. Gunderson 				usbm->urb_use_count++;
1608f7d34b44SSteinar H. Gunderson 			}
1609f7d34b44SSteinar H. Gunderson 			break;
1610f7d34b44SSteinar H. Gunderson 		}
1611f7d34b44SSteinar H. Gunderson 	}
1612f7d34b44SSteinar H. Gunderson 	spin_unlock_irqrestore(&ps->lock, flags);
1613f7d34b44SSteinar H. Gunderson 	return usbm;
1614f7d34b44SSteinar H. Gunderson }
1615f7d34b44SSteinar H. Gunderson 
proc_do_submiturb(struct usb_dev_state * ps,struct usbdevfs_urb * uurb,struct usbdevfs_iso_packet_desc __user * iso_frame_desc,void __user * arg,sigval_t userurb_sigval)16169b6f0c4bSValentina Manea static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
16171da177e4SLinus Torvalds 			struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
161870f1b0d3SEric W. Biederman 			void __user *arg, sigval_t userurb_sigval)
16191da177e4SLinus Torvalds {
16201da177e4SLinus Torvalds 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
16211da177e4SLinus Torvalds 	struct usb_host_endpoint *ep;
162252fb743dSAlan Stern 	struct async *as = NULL;
16231da177e4SLinus Torvalds 	struct usb_ctrlrequest *dr = NULL;
16241da177e4SLinus Torvalds 	unsigned int u, totlen, isofrmlen;
16257a68d9fbSOliver Neukum 	int i, ret, num_sgs = 0, ifnum = -1;
1626b2d03eb5SHans de Goede 	int number_of_packets = 0;
1627948cd8c1SHans de Goede 	unsigned int stream_id = 0;
16283d97ff63SHans de Goede 	void *buf;
16297a68d9fbSOliver Neukum 	bool is_in;
16307a68d9fbSOliver Neukum 	bool allow_short = false;
16317a68d9fbSOliver Neukum 	bool allow_zero = false;
1632446f666dSOliver Neukum 	unsigned long mask =	USBDEVFS_URB_SHORT_NOT_OK |
163301c6460fSAlan Stern 				USBDEVFS_URB_BULK_CONTINUATION |
163414722ef4SAlan Stern 				USBDEVFS_URB_NO_FSBR |
163514722ef4SAlan Stern 				USBDEVFS_URB_ZERO_PACKET |
1636446f666dSOliver Neukum 				USBDEVFS_URB_NO_INTERRUPT;
1637446f666dSOliver Neukum 	/* USBDEVFS_URB_ISO_ASAP is a special case */
1638446f666dSOliver Neukum 	if (uurb->type == USBDEVFS_URB_TYPE_ISO)
1639446f666dSOliver Neukum 		mask |= USBDEVFS_URB_ISO_ASAP;
1640446f666dSOliver Neukum 
1641446f666dSOliver Neukum 	if (uurb->flags & ~mask)
16421da177e4SLinus Torvalds 			return -EINVAL;
1643446f666dSOliver Neukum 
164457999d11SDan Carpenter 	if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
164557999d11SDan Carpenter 		return -EINVAL;
16469180135bSAlan Stern 	if (uurb->buffer_length > 0 && !uurb->buffer)
16471da177e4SLinus Torvalds 		return -EINVAL;
164804e482ffSGreg Kroah-Hartman 	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
164904e482ffSGreg Kroah-Hartman 	    (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
165004e482ffSGreg Kroah-Hartman 		ifnum = findintfep(ps->dev, uurb->endpoint);
165104e482ffSGreg Kroah-Hartman 		if (ifnum < 0)
16521da177e4SLinus Torvalds 			return ifnum;
165304e482ffSGreg Kroah-Hartman 		ret = checkintf(ps, ifnum);
165404e482ffSGreg Kroah-Hartman 		if (ret)
16551da177e4SLinus Torvalds 			return ret;
16561da177e4SLinus Torvalds 	}
16572fec32b0SHans de Goede 	ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);
16581da177e4SLinus Torvalds 	if (!ep)
16591da177e4SLinus Torvalds 		return -ENOENT;
16602fec32b0SHans de Goede 	is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
1661add1aaeaSAlan Stern 
1662add1aaeaSAlan Stern 	u = 0;
16631da177e4SLinus Torvalds 	switch (uurb->type) {
16641da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_CONTROL:
166593cf9b90SAlan Stern 		if (!usb_endpoint_xfer_control(&ep->desc))
16661da177e4SLinus Torvalds 			return -EINVAL;
1667add1aaeaSAlan Stern 		/* min 8 byte setup packet */
1668add1aaeaSAlan Stern 		if (uurb->buffer_length < 8)
16691da177e4SLinus Torvalds 			return -EINVAL;
167004e482ffSGreg Kroah-Hartman 		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
167104e482ffSGreg Kroah-Hartman 		if (!dr)
16721da177e4SLinus Torvalds 			return -ENOMEM;
16731da177e4SLinus Torvalds 		if (copy_from_user(dr, uurb->buffer, 8)) {
167452fb743dSAlan Stern 			ret = -EFAULT;
167552fb743dSAlan Stern 			goto error;
16761da177e4SLinus Torvalds 		}
1677257adc0fSAlan Stern 		if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
167852fb743dSAlan Stern 			ret = -EINVAL;
167952fb743dSAlan Stern 			goto error;
16801da177e4SLinus Torvalds 		}
1681393cbb51SMatthias Dellweg 		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
1682257adc0fSAlan Stern 				      le16_to_cpu(dr->wIndex));
168352fb743dSAlan Stern 		if (ret)
168452fb743dSAlan Stern 			goto error;
1685257adc0fSAlan Stern 		uurb->buffer_length = le16_to_cpu(dr->wLength);
16861da177e4SLinus Torvalds 		uurb->buffer += 8;
168793cf9b90SAlan Stern 		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
168871464db9SSaurav Girepunje 			is_in = true;
168993cf9b90SAlan Stern 			uurb->endpoint |= USB_DIR_IN;
169093cf9b90SAlan Stern 		} else {
169171464db9SSaurav Girepunje 			is_in = false;
169293cf9b90SAlan Stern 			uurb->endpoint &= ~USB_DIR_IN;
169393cf9b90SAlan Stern 		}
1694665c365aSAlan Stern 		if (is_in)
1695665c365aSAlan Stern 			allow_short = true;
16960880aef4SChris Frey 		snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
16970880aef4SChris Frey 			"bRequest=%02x wValue=%04x "
16980880aef4SChris Frey 			"wIndex=%04x wLength=%04x\n",
16990880aef4SChris Frey 			dr->bRequestType, dr->bRequest,
1700257adc0fSAlan Stern 			__le16_to_cpu(dr->wValue),
1701257adc0fSAlan Stern 			__le16_to_cpu(dr->wIndex),
1702257adc0fSAlan Stern 			__le16_to_cpu(dr->wLength));
1703add1aaeaSAlan Stern 		u = sizeof(struct usb_ctrlrequest);
17041da177e4SLinus Torvalds 		break;
17051da177e4SLinus Torvalds 
17061da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_BULK:
17077a68d9fbSOliver Neukum 		if (!is_in)
17087a68d9fbSOliver Neukum 			allow_zero = true;
17097a68d9fbSOliver Neukum 		else
17107a68d9fbSOliver Neukum 			allow_short = true;
171193cf9b90SAlan Stern 		switch (usb_endpoint_type(&ep->desc)) {
17121da177e4SLinus Torvalds 		case USB_ENDPOINT_XFER_CONTROL:
17131da177e4SLinus Torvalds 		case USB_ENDPOINT_XFER_ISOC:
17141da177e4SLinus Torvalds 			return -EINVAL;
1715f661c6f8SAlan Stern 		case USB_ENDPOINT_XFER_INT:
1716f661c6f8SAlan Stern 			/* allow single-shot interrupt transfers */
1717f661c6f8SAlan Stern 			uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
1718f661c6f8SAlan Stern 			goto interrupt_urb;
17191da177e4SLinus Torvalds 		}
17203d97ff63SHans de Goede 		num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
17213d97ff63SHans de Goede 		if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
17223d97ff63SHans de Goede 			num_sgs = 0;
1723948cd8c1SHans de Goede 		if (ep->streams)
1724948cd8c1SHans de Goede 			stream_id = uurb->stream_id;
17251da177e4SLinus Torvalds 		break;
17261da177e4SLinus Torvalds 
1727f661c6f8SAlan Stern 	case USBDEVFS_URB_TYPE_INTERRUPT:
1728f661c6f8SAlan Stern 		if (!usb_endpoint_xfer_int(&ep->desc))
1729f661c6f8SAlan Stern 			return -EINVAL;
1730f661c6f8SAlan Stern  interrupt_urb:
17317a68d9fbSOliver Neukum 		if (!is_in)
17327a68d9fbSOliver Neukum 			allow_zero = true;
17337a68d9fbSOliver Neukum 		else
17347a68d9fbSOliver Neukum 			allow_short = true;
1735f661c6f8SAlan Stern 		break;
1736f661c6f8SAlan Stern 
17371da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_ISO:
17381da177e4SLinus Torvalds 		/* arbitrary limit */
173904e482ffSGreg Kroah-Hartman 		if (uurb->number_of_packets < 1 ||
174004e482ffSGreg Kroah-Hartman 		    uurb->number_of_packets > 128)
17411da177e4SLinus Torvalds 			return -EINVAL;
174293cf9b90SAlan Stern 		if (!usb_endpoint_xfer_isoc(&ep->desc))
17431da177e4SLinus Torvalds 			return -EINVAL;
1744b2d03eb5SHans de Goede 		number_of_packets = uurb->number_of_packets;
174504e482ffSGreg Kroah-Hartman 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
1746b2d03eb5SHans de Goede 				   number_of_packets;
174773a02d32SRahul Pathak 		isopkt = memdup_user(iso_frame_desc, isofrmlen);
174873a02d32SRahul Pathak 		if (IS_ERR(isopkt)) {
174973a02d32SRahul Pathak 			ret = PTR_ERR(isopkt);
175073a02d32SRahul Pathak 			isopkt = NULL;
175152fb743dSAlan Stern 			goto error;
17521da177e4SLinus Torvalds 		}
1753b2d03eb5SHans de Goede 		for (totlen = u = 0; u < number_of_packets; u++) {
1754e2e2f0eaSFederico Manzan 			/*
17558a1dbc8dSChunfeng Yun 			 * arbitrary limit need for USB 3.1 Gen2
17568a1dbc8dSChunfeng Yun 			 * sizemax: 96 DPs at SSP, 96 * 1024 = 98304
1757e2e2f0eaSFederico Manzan 			 */
17588a1dbc8dSChunfeng Yun 			if (isopkt[u].length > 98304) {
175952fb743dSAlan Stern 				ret = -EINVAL;
176052fb743dSAlan Stern 				goto error;
17611da177e4SLinus Torvalds 			}
17621da177e4SLinus Torvalds 			totlen += isopkt[u].length;
17631da177e4SLinus Torvalds 		}
1764add1aaeaSAlan Stern 		u *= sizeof(struct usb_iso_packet_descriptor);
17651da177e4SLinus Torvalds 		uurb->buffer_length = totlen;
17661da177e4SLinus Torvalds 		break;
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds 	default:
17691da177e4SLinus Torvalds 		return -EINVAL;
17701da177e4SLinus Torvalds 	}
1771add1aaeaSAlan Stern 
17729180135bSAlan Stern 	if (uurb->buffer_length > 0 &&
177396d4f267SLinus Torvalds 			!access_ok(uurb->buffer, uurb->buffer_length)) {
177452fb743dSAlan Stern 		ret = -EFAULT;
177552fb743dSAlan Stern 		goto error;
17769180135bSAlan Stern 	}
1777b2d03eb5SHans de Goede 	as = alloc_async(number_of_packets);
177804e482ffSGreg Kroah-Hartman 	if (!as) {
177952fb743dSAlan Stern 		ret = -ENOMEM;
178052fb743dSAlan Stern 		goto error;
17811da177e4SLinus Torvalds 	}
17823d97ff63SHans de Goede 
1783f7d34b44SSteinar H. Gunderson 	as->usbm = find_memory_area(ps, uurb);
1784f7d34b44SSteinar H. Gunderson 	if (IS_ERR(as->usbm)) {
1785f7d34b44SSteinar H. Gunderson 		ret = PTR_ERR(as->usbm);
1786f7d34b44SSteinar H. Gunderson 		as->usbm = NULL;
1787f7d34b44SSteinar H. Gunderson 		goto error;
1788f7d34b44SSteinar H. Gunderson 	}
1789f7d34b44SSteinar H. Gunderson 
1790f7d34b44SSteinar H. Gunderson 	/* do not use SG buffers when memory mapped segments
1791f7d34b44SSteinar H. Gunderson 	 * are in use
1792f7d34b44SSteinar H. Gunderson 	 */
1793f7d34b44SSteinar H. Gunderson 	if (as->usbm)
1794f7d34b44SSteinar H. Gunderson 		num_sgs = 0;
1795f7d34b44SSteinar H. Gunderson 
1796b08a6259SGavin Li 	u += sizeof(struct async) + sizeof(struct urb) +
1797b08a6259SGavin Li 	     (as->usbm ? 0 : uurb->buffer_length) +
17983d97ff63SHans de Goede 	     num_sgs * sizeof(struct scatterlist);
1799add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(u);
1800add1aaeaSAlan Stern 	if (ret)
1801add1aaeaSAlan Stern 		goto error;
1802add1aaeaSAlan Stern 	as->mem_usage = u;
1803add1aaeaSAlan Stern 
18043d97ff63SHans de Goede 	if (num_sgs) {
18056da2ec56SKees Cook 		as->urb->sg = kmalloc_array(num_sgs,
18066da2ec56SKees Cook 					    sizeof(struct scatterlist),
18074f2629eaSAlan Stern 					    GFP_KERNEL | __GFP_NOWARN);
18083d97ff63SHans de Goede 		if (!as->urb->sg) {
18093d97ff63SHans de Goede 			ret = -ENOMEM;
18103d97ff63SHans de Goede 			goto error;
18113d97ff63SHans de Goede 		}
18123d97ff63SHans de Goede 		as->urb->num_sgs = num_sgs;
18133d97ff63SHans de Goede 		sg_init_table(as->urb->sg, as->urb->num_sgs);
18143d97ff63SHans de Goede 
18153d97ff63SHans de Goede 		totlen = uurb->buffer_length;
18163d97ff63SHans de Goede 		for (i = 0; i < as->urb->num_sgs; i++) {
18173d97ff63SHans de Goede 			u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
18183d97ff63SHans de Goede 			buf = kmalloc(u, GFP_KERNEL);
18193d97ff63SHans de Goede 			if (!buf) {
18203d97ff63SHans de Goede 				ret = -ENOMEM;
18213d97ff63SHans de Goede 				goto error;
18223d97ff63SHans de Goede 			}
18233d97ff63SHans de Goede 			sg_set_buf(&as->urb->sg[i], buf, u);
18243d97ff63SHans de Goede 
18253d97ff63SHans de Goede 			if (!is_in) {
18263d97ff63SHans de Goede 				if (copy_from_user(buf, uurb->buffer, u)) {
18273d97ff63SHans de Goede 					ret = -EFAULT;
18283d97ff63SHans de Goede 					goto error;
18293d97ff63SHans de Goede 				}
183001463900SHenrik Rydberg 				uurb->buffer += u;
18313d97ff63SHans de Goede 			}
18323d97ff63SHans de Goede 			totlen -= u;
18333d97ff63SHans de Goede 		}
18343d97ff63SHans de Goede 	} else if (uurb->buffer_length > 0) {
1835f7d34b44SSteinar H. Gunderson 		if (as->usbm) {
1836f7d34b44SSteinar H. Gunderson 			unsigned long uurb_start = (unsigned long)uurb->buffer;
1837f7d34b44SSteinar H. Gunderson 
1838f7d34b44SSteinar H. Gunderson 			as->urb->transfer_buffer = as->usbm->mem +
1839f7d34b44SSteinar H. Gunderson 					(uurb_start - as->usbm->vm_start);
1840f7d34b44SSteinar H. Gunderson 		} else {
18419180135bSAlan Stern 			as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
18424f2629eaSAlan Stern 					GFP_KERNEL | __GFP_NOWARN);
184304e482ffSGreg Kroah-Hartman 			if (!as->urb->transfer_buffer) {
184452fb743dSAlan Stern 				ret = -ENOMEM;
184552fb743dSAlan Stern 				goto error;
18461da177e4SLinus Torvalds 			}
18473d97ff63SHans de Goede 			if (!is_in) {
18483d97ff63SHans de Goede 				if (copy_from_user(as->urb->transfer_buffer,
18493d97ff63SHans de Goede 						   uurb->buffer,
18503d97ff63SHans de Goede 						   uurb->buffer_length)) {
18513d97ff63SHans de Goede 					ret = -EFAULT;
18523d97ff63SHans de Goede 					goto error;
18533d97ff63SHans de Goede 				}
18543d97ff63SHans de Goede 			} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
18553d97ff63SHans de Goede 				/*
18563d97ff63SHans de Goede 				 * Isochronous input data may end up being
1857f7d34b44SSteinar H. Gunderson 				 * discontiguous if some of the packets are
1858f7d34b44SSteinar H. Gunderson 				 * short. Clear the buffer so that the gaps
1859f7d34b44SSteinar H. Gunderson 				 * don't leak kernel data to userspace.
18607152b592SAlan Stern 				 */
18617152b592SAlan Stern 				memset(as->urb->transfer_buffer, 0,
18627152b592SAlan Stern 						uurb->buffer_length);
18639180135bSAlan Stern 			}
18643d97ff63SHans de Goede 		}
1865f7d34b44SSteinar H. Gunderson 	}
18661da177e4SLinus Torvalds 	as->urb->dev = ps->dev;
186793cf9b90SAlan Stern 	as->urb->pipe = (uurb->type << 30) |
186893cf9b90SAlan Stern 			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
186993cf9b90SAlan Stern 			(uurb->endpoint & USB_DIR_IN);
187014722ef4SAlan Stern 
187114722ef4SAlan Stern 	/* This tedious sequence is necessary because the URB_* flags
187214722ef4SAlan Stern 	 * are internal to the kernel and subject to change, whereas
187314722ef4SAlan Stern 	 * the USBDEVFS_URB_* flags are a user API and must not be changed.
187414722ef4SAlan Stern 	 */
187514722ef4SAlan Stern 	u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
187614722ef4SAlan Stern 	if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
187714722ef4SAlan Stern 		u |= URB_ISO_ASAP;
18787a68d9fbSOliver Neukum 	if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
187914722ef4SAlan Stern 		u |= URB_SHORT_NOT_OK;
18807a68d9fbSOliver Neukum 	if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
188114722ef4SAlan Stern 		u |= URB_ZERO_PACKET;
188214722ef4SAlan Stern 	if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
188314722ef4SAlan Stern 		u |= URB_NO_INTERRUPT;
188414722ef4SAlan Stern 	as->urb->transfer_flags = u;
188514722ef4SAlan Stern 
188681e0403bSOliver Neukum 	if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
188781e0403bSOliver Neukum 		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n");
188881e0403bSOliver Neukum 	if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
188981e0403bSOliver Neukum 		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n");
189081e0403bSOliver Neukum 
18911da177e4SLinus Torvalds 	as->urb->transfer_buffer_length = uurb->buffer_length;
18921da177e4SLinus Torvalds 	as->urb->setup_packet = (unsigned char *)dr;
189352fb743dSAlan Stern 	dr = NULL;
18941da177e4SLinus Torvalds 	as->urb->start_frame = uurb->start_frame;
1895b2d03eb5SHans de Goede 	as->urb->number_of_packets = number_of_packets;
1896948cd8c1SHans de Goede 	as->urb->stream_id = stream_id;
189753e5f36fSAlan Stern 
189853e5f36fSAlan Stern 	if (ep->desc.bInterval) {
189997b9eb91SAlan Stern 		if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
190053e5f36fSAlan Stern 				ps->dev->speed == USB_SPEED_HIGH ||
190153e5f36fSAlan Stern 				ps->dev->speed >= USB_SPEED_SUPER)
190253e5f36fSAlan Stern 			as->urb->interval = 1 <<
190353e5f36fSAlan Stern 					min(15, ep->desc.bInterval - 1);
190497b9eb91SAlan Stern 		else
190597b9eb91SAlan Stern 			as->urb->interval = ep->desc.bInterval;
190653e5f36fSAlan Stern 	}
190753e5f36fSAlan Stern 
19081da177e4SLinus Torvalds 	as->urb->context = as;
19091da177e4SLinus Torvalds 	as->urb->complete = async_completed;
1910b2d03eb5SHans de Goede 	for (totlen = u = 0; u < number_of_packets; u++) {
19111da177e4SLinus Torvalds 		as->urb->iso_frame_desc[u].offset = totlen;
19121da177e4SLinus Torvalds 		as->urb->iso_frame_desc[u].length = isopkt[u].length;
19131da177e4SLinus Torvalds 		totlen += isopkt[u].length;
19141da177e4SLinus Torvalds 	}
19151da177e4SLinus Torvalds 	kfree(isopkt);
191652fb743dSAlan Stern 	isopkt = NULL;
19171da177e4SLinus Torvalds 	as->ps = ps;
19181da177e4SLinus Torvalds 	as->userurb = arg;
191970f1b0d3SEric W. Biederman 	as->userurb_sigval = userurb_sigval;
1920f7d34b44SSteinar H. Gunderson 	if (as->usbm) {
1921f7d34b44SSteinar H. Gunderson 		unsigned long uurb_start = (unsigned long)uurb->buffer;
1922f7d34b44SSteinar H. Gunderson 
1923f7d34b44SSteinar H. Gunderson 		as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1924f7d34b44SSteinar H. Gunderson 		as->urb->transfer_dma = as->usbm->dma_handle +
1925f7d34b44SSteinar H. Gunderson 				(uurb_start - as->usbm->vm_start);
1926f7d34b44SSteinar H. Gunderson 	} else if (is_in && uurb->buffer_length > 0)
19271da177e4SLinus Torvalds 		as->userbuffer = uurb->buffer;
19281da177e4SLinus Torvalds 	as->signr = uurb->signr;
19291da177e4SLinus Torvalds 	as->ifnum = ifnum;
19302425c08bSEric W. Biederman 	as->pid = get_pid(task_pid(current));
1931d178bc3aSSerge Hallyn 	as->cred = get_current_cred();
19324c6e8971SAlan Stern 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
19330880aef4SChris Frey 			as->urb->transfer_buffer_length, 0, SUBMIT,
19343d97ff63SHans de Goede 			NULL, 0);
19353d97ff63SHans de Goede 	if (!is_in)
19363d97ff63SHans de Goede 		snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
19373d97ff63SHans de Goede 
19381da177e4SLinus Torvalds 	async_newpending(as);
193901c6460fSAlan Stern 
194001c6460fSAlan Stern 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
194101c6460fSAlan Stern 		spin_lock_irq(&ps->lock);
194201c6460fSAlan Stern 
194301c6460fSAlan Stern 		/* Not exactly the endpoint address; the direction bit is
194401c6460fSAlan Stern 		 * shifted to the 0x10 position so that the value will be
194501c6460fSAlan Stern 		 * between 0 and 31.
194601c6460fSAlan Stern 		 */
194701c6460fSAlan Stern 		as->bulk_addr = usb_endpoint_num(&ep->desc) |
194801c6460fSAlan Stern 			((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
194901c6460fSAlan Stern 				>> 3);
195001c6460fSAlan Stern 
195101c6460fSAlan Stern 		/* If this bulk URB is the start of a new transfer, re-enable
195201c6460fSAlan Stern 		 * the endpoint.  Otherwise mark it as a continuation URB.
195301c6460fSAlan Stern 		 */
195401c6460fSAlan Stern 		if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
195501c6460fSAlan Stern 			as->bulk_status = AS_CONTINUATION;
195601c6460fSAlan Stern 		else
195701c6460fSAlan Stern 			ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
195801c6460fSAlan Stern 
195901c6460fSAlan Stern 		/* Don't accept continuation URBs if the endpoint is
196001c6460fSAlan Stern 		 * disabled because of an earlier error.
196101c6460fSAlan Stern 		 */
196201c6460fSAlan Stern 		if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
196301c6460fSAlan Stern 			ret = -EREMOTEIO;
196401c6460fSAlan Stern 		else
196501c6460fSAlan Stern 			ret = usb_submit_urb(as->urb, GFP_ATOMIC);
196601c6460fSAlan Stern 		spin_unlock_irq(&ps->lock);
196701c6460fSAlan Stern 	} else {
196801c6460fSAlan Stern 		ret = usb_submit_urb(as->urb, GFP_KERNEL);
196901c6460fSAlan Stern 	}
197001c6460fSAlan Stern 
197101c6460fSAlan Stern 	if (ret) {
197204e482ffSGreg Kroah-Hartman 		dev_printk(KERN_DEBUG, &ps->dev->dev,
197304e482ffSGreg Kroah-Hartman 			   "usbfs: usb_submit_urb returned %d\n", ret);
19744c6e8971SAlan Stern 		snoop_urb(ps->dev, as->userurb, as->urb->pipe,
19750880aef4SChris Frey 				0, ret, COMPLETE, NULL, 0);
19761da177e4SLinus Torvalds 		async_removepending(as);
197752fb743dSAlan Stern 		goto error;
19781da177e4SLinus Torvalds 	}
19791da177e4SLinus Torvalds 	return 0;
198052fb743dSAlan Stern 
198152fb743dSAlan Stern  error:
198252fb743dSAlan Stern 	kfree(isopkt);
198352fb743dSAlan Stern 	kfree(dr);
198452fb743dSAlan Stern 	if (as)
198552fb743dSAlan Stern 		free_async(as);
198652fb743dSAlan Stern 	return ret;
19871da177e4SLinus Torvalds }
19881da177e4SLinus Torvalds 
proc_submiturb(struct usb_dev_state * ps,void __user * arg)19899b6f0c4bSValentina Manea static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
19901da177e4SLinus Torvalds {
19911da177e4SLinus Torvalds 	struct usbdevfs_urb uurb;
199270f1b0d3SEric W. Biederman 	sigval_t userurb_sigval;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
19951da177e4SLinus Torvalds 		return -EFAULT;
19961da177e4SLinus Torvalds 
199770f1b0d3SEric W. Biederman 	memset(&userurb_sigval, 0, sizeof(userurb_sigval));
199870f1b0d3SEric W. Biederman 	userurb_sigval.sival_ptr = arg;
199970f1b0d3SEric W. Biederman 
200004e482ffSGreg Kroah-Hartman 	return proc_do_submiturb(ps, &uurb,
200104e482ffSGreg Kroah-Hartman 			(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
200270f1b0d3SEric W. Biederman 			arg, userurb_sigval);
20031da177e4SLinus Torvalds }
20041da177e4SLinus Torvalds 
proc_unlinkurb(struct usb_dev_state * ps,void __user * arg)20059b6f0c4bSValentina Manea static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
20061da177e4SLinus Torvalds {
20074e09dcf2SHuajun Li 	struct urb *urb;
20081da177e4SLinus Torvalds 	struct async *as;
20094e09dcf2SHuajun Li 	unsigned long flags;
20101da177e4SLinus Torvalds 
20114e09dcf2SHuajun Li 	spin_lock_irqsave(&ps->lock, flags);
20121da177e4SLinus Torvalds 	as = async_getpending(ps, arg);
20134e09dcf2SHuajun Li 	if (!as) {
20144e09dcf2SHuajun Li 		spin_unlock_irqrestore(&ps->lock, flags);
20151da177e4SLinus Torvalds 		return -EINVAL;
20164e09dcf2SHuajun Li 	}
20174e09dcf2SHuajun Li 
20184e09dcf2SHuajun Li 	urb = as->urb;
20194e09dcf2SHuajun Li 	usb_get_urb(urb);
20204e09dcf2SHuajun Li 	spin_unlock_irqrestore(&ps->lock, flags);
20214e09dcf2SHuajun Li 
20224e09dcf2SHuajun Li 	usb_kill_urb(urb);
20234e09dcf2SHuajun Li 	usb_put_urb(urb);
20244e09dcf2SHuajun Li 
20251da177e4SLinus Torvalds 	return 0;
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds 
compute_isochronous_actual_length(struct urb * urb)20282ef47001SAlan Stern static void compute_isochronous_actual_length(struct urb *urb)
20292ef47001SAlan Stern {
20302ef47001SAlan Stern 	unsigned int i;
20312ef47001SAlan Stern 
20322ef47001SAlan Stern 	if (urb->number_of_packets > 0) {
20332ef47001SAlan Stern 		urb->actual_length = 0;
20342ef47001SAlan Stern 		for (i = 0; i < urb->number_of_packets; i++)
20352ef47001SAlan Stern 			urb->actual_length +=
20362ef47001SAlan Stern 					urb->iso_frame_desc[i].actual_length;
20372ef47001SAlan Stern 	}
20382ef47001SAlan Stern }
20392ef47001SAlan Stern 
processcompl(struct async * as,void __user * __user * arg)20401da177e4SLinus Torvalds static int processcompl(struct async *as, void __user * __user *arg)
20411da177e4SLinus Torvalds {
20421da177e4SLinus Torvalds 	struct urb *urb = as->urb;
20431da177e4SLinus Torvalds 	struct usbdevfs_urb __user *userurb = as->userurb;
20441da177e4SLinus Torvalds 	void __user *addr = as->userurb;
20451da177e4SLinus Torvalds 	unsigned int i;
20461da177e4SLinus Torvalds 
20472ef47001SAlan Stern 	compute_isochronous_actual_length(urb);
20487152b592SAlan Stern 	if (as->userbuffer && urb->actual_length) {
20493d97ff63SHans de Goede 		if (copy_urb_data_to_user(as->userbuffer, urb))
2050d794a021SOliver Neukum 			goto err_out;
20517152b592SAlan Stern 	}
2052e015268dSAlan Stern 	if (put_user(as->status, &userurb->status))
2053d794a021SOliver Neukum 		goto err_out;
20541da177e4SLinus Torvalds 	if (put_user(urb->actual_length, &userurb->actual_length))
2055d794a021SOliver Neukum 		goto err_out;
20561da177e4SLinus Torvalds 	if (put_user(urb->error_count, &userurb->error_count))
2057d794a021SOliver Neukum 		goto err_out;
20581da177e4SLinus Torvalds 
205993cf9b90SAlan Stern 	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
20601da177e4SLinus Torvalds 		for (i = 0; i < urb->number_of_packets; i++) {
20611da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].actual_length,
20621da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].actual_length))
2063d794a021SOliver Neukum 				goto err_out;
20641da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].status,
20651da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].status))
2066d794a021SOliver Neukum 				goto err_out;
20671da177e4SLinus Torvalds 		}
2068668a9541SChristopher Li 	}
20691da177e4SLinus Torvalds 
20701da177e4SLinus Torvalds 	if (put_user(addr, (void __user * __user *)arg))
20711da177e4SLinus Torvalds 		return -EFAULT;
20721da177e4SLinus Torvalds 	return 0;
2073d794a021SOliver Neukum 
2074d794a021SOliver Neukum err_out:
2075d794a021SOliver Neukum 	return -EFAULT;
20761da177e4SLinus Torvalds }
20771da177e4SLinus Torvalds 
reap_as(struct usb_dev_state * ps)20789b6f0c4bSValentina Manea static struct async *reap_as(struct usb_dev_state *ps)
20791da177e4SLinus Torvalds {
20801da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
20811da177e4SLinus Torvalds 	struct async *as = NULL;
20821da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
20831da177e4SLinus Torvalds 
20841da177e4SLinus Torvalds 	add_wait_queue(&ps->wait, &wait);
20851da177e4SLinus Torvalds 	for (;;) {
20861da177e4SLinus Torvalds 		__set_current_state(TASK_INTERRUPTIBLE);
208704e482ffSGreg Kroah-Hartman 		as = async_getcompleted(ps);
20883f2cee73SAlan Stern 		if (as || !connected(ps))
20891da177e4SLinus Torvalds 			break;
20901da177e4SLinus Torvalds 		if (signal_pending(current))
20911da177e4SLinus Torvalds 			break;
20921da177e4SLinus Torvalds 		usb_unlock_device(dev);
20931da177e4SLinus Torvalds 		schedule();
20941da177e4SLinus Torvalds 		usb_lock_device(dev);
20951da177e4SLinus Torvalds 	}
20961da177e4SLinus Torvalds 	remove_wait_queue(&ps->wait, &wait);
20971da177e4SLinus Torvalds 	set_current_state(TASK_RUNNING);
20981da177e4SLinus Torvalds 	return as;
20991da177e4SLinus Torvalds }
21001da177e4SLinus Torvalds 
proc_reapurb(struct usb_dev_state * ps,void __user * arg)21019b6f0c4bSValentina Manea static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
21021da177e4SLinus Torvalds {
21031da177e4SLinus Torvalds 	struct async *as = reap_as(ps);
2104a016a816SAlan Stern 
2105ddeee0b2SLinus Torvalds 	if (as) {
2106a016a816SAlan Stern 		int retval;
2107a016a816SAlan Stern 
2108f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2109a016a816SAlan Stern 		retval = processcompl(as, (void __user * __user *)arg);
2110ddeee0b2SLinus Torvalds 		free_async(as);
2111ddeee0b2SLinus Torvalds 		return retval;
2112ddeee0b2SLinus Torvalds 	}
21131da177e4SLinus Torvalds 	if (signal_pending(current))
21141da177e4SLinus Torvalds 		return -EINTR;
21153f2cee73SAlan Stern 	return -ENODEV;
21161da177e4SLinus Torvalds }
21171da177e4SLinus Torvalds 
proc_reapurbnonblock(struct usb_dev_state * ps,void __user * arg)21189b6f0c4bSValentina Manea static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
21191da177e4SLinus Torvalds {
2120ddeee0b2SLinus Torvalds 	int retval;
21211da177e4SLinus Torvalds 	struct async *as;
21221da177e4SLinus Torvalds 
2123ddeee0b2SLinus Torvalds 	as = async_getcompleted(ps);
2124ddeee0b2SLinus Torvalds 	if (as) {
2125f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2126ddeee0b2SLinus Torvalds 		retval = processcompl(as, (void __user * __user *)arg);
2127ddeee0b2SLinus Torvalds 		free_async(as);
21283f2cee73SAlan Stern 	} else {
21293f2cee73SAlan Stern 		retval = (connected(ps) ? -EAGAIN : -ENODEV);
2130ddeee0b2SLinus Torvalds 	}
2131ddeee0b2SLinus Torvalds 	return retval;
21321da177e4SLinus Torvalds }
21331da177e4SLinus Torvalds 
21341da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
proc_control_compat(struct usb_dev_state * ps,struct usbdevfs_ctrltransfer32 __user * p32)21359b6f0c4bSValentina Manea static int proc_control_compat(struct usb_dev_state *ps,
2136637e8a60SArnd Bergmann 				struct usbdevfs_ctrltransfer32 __user *p32)
2137637e8a60SArnd Bergmann {
2138c17536d0SChristoph Hellwig 	struct usbdevfs_ctrltransfer ctrl;
2139c17536d0SChristoph Hellwig 	u32 udata;
2140c17536d0SChristoph Hellwig 
2141c17536d0SChristoph Hellwig 	if (copy_from_user(&ctrl, p32, sizeof(*p32) - sizeof(compat_caddr_t)) ||
2142c17536d0SChristoph Hellwig 	    get_user(udata, &p32->data))
2143637e8a60SArnd Bergmann 		return -EFAULT;
2144c17536d0SChristoph Hellwig 	ctrl.data = compat_ptr(udata);
2145c17536d0SChristoph Hellwig 	return do_proc_control(ps, &ctrl);
2146637e8a60SArnd Bergmann }
2147637e8a60SArnd Bergmann 
proc_bulk_compat(struct usb_dev_state * ps,struct usbdevfs_bulktransfer32 __user * p32)21489b6f0c4bSValentina Manea static int proc_bulk_compat(struct usb_dev_state *ps,
2149637e8a60SArnd Bergmann 			struct usbdevfs_bulktransfer32 __user *p32)
2150637e8a60SArnd Bergmann {
2151c17536d0SChristoph Hellwig 	struct usbdevfs_bulktransfer bulk;
2152637e8a60SArnd Bergmann 	compat_caddr_t addr;
2153637e8a60SArnd Bergmann 
2154c17536d0SChristoph Hellwig 	if (get_user(bulk.ep, &p32->ep) ||
2155c17536d0SChristoph Hellwig 	    get_user(bulk.len, &p32->len) ||
2156c17536d0SChristoph Hellwig 	    get_user(bulk.timeout, &p32->timeout) ||
2157c17536d0SChristoph Hellwig 	    get_user(addr, &p32->data))
2158637e8a60SArnd Bergmann 		return -EFAULT;
2159c17536d0SChristoph Hellwig 	bulk.data = compat_ptr(addr);
2160c17536d0SChristoph Hellwig 	return do_proc_bulk(ps, &bulk);
2161637e8a60SArnd Bergmann }
2162c17536d0SChristoph Hellwig 
proc_disconnectsignal_compat(struct usb_dev_state * ps,void __user * arg)21639b6f0c4bSValentina Manea static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)
2164637e8a60SArnd Bergmann {
2165637e8a60SArnd Bergmann 	struct usbdevfs_disconnectsignal32 ds;
2166637e8a60SArnd Bergmann 
2167637e8a60SArnd Bergmann 	if (copy_from_user(&ds, arg, sizeof(ds)))
2168637e8a60SArnd Bergmann 		return -EFAULT;
2169637e8a60SArnd Bergmann 	ps->discsignr = ds.signr;
217070f1b0d3SEric W. Biederman 	ps->disccontext.sival_int = ds.context;
2171637e8a60SArnd Bergmann 	return 0;
2172637e8a60SArnd Bergmann }
21731da177e4SLinus Torvalds 
get_urb32(struct usbdevfs_urb * kurb,struct usbdevfs_urb32 __user * uurb)21741da177e4SLinus Torvalds static int get_urb32(struct usbdevfs_urb *kurb,
21751da177e4SLinus Torvalds 		     struct usbdevfs_urb32 __user *uurb)
21761da177e4SLinus Torvalds {
2177cc1a7c4bSAl Viro 	struct usbdevfs_urb32 urb32;
2178cc1a7c4bSAl Viro 	if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
21791da177e4SLinus Torvalds 		return -EFAULT;
2180cc1a7c4bSAl Viro 	kurb->type = urb32.type;
2181cc1a7c4bSAl Viro 	kurb->endpoint = urb32.endpoint;
2182cc1a7c4bSAl Viro 	kurb->status = urb32.status;
2183cc1a7c4bSAl Viro 	kurb->flags = urb32.flags;
2184cc1a7c4bSAl Viro 	kurb->buffer = compat_ptr(urb32.buffer);
2185cc1a7c4bSAl Viro 	kurb->buffer_length = urb32.buffer_length;
2186cc1a7c4bSAl Viro 	kurb->actual_length = urb32.actual_length;
2187cc1a7c4bSAl Viro 	kurb->start_frame = urb32.start_frame;
2188cc1a7c4bSAl Viro 	kurb->number_of_packets = urb32.number_of_packets;
2189cc1a7c4bSAl Viro 	kurb->error_count = urb32.error_count;
2190cc1a7c4bSAl Viro 	kurb->signr = urb32.signr;
2191cc1a7c4bSAl Viro 	kurb->usercontext = compat_ptr(urb32.usercontext);
21921da177e4SLinus Torvalds 	return 0;
21931da177e4SLinus Torvalds }
21941da177e4SLinus Torvalds 
proc_submiturb_compat(struct usb_dev_state * ps,void __user * arg)21959b6f0c4bSValentina Manea static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
21961da177e4SLinus Torvalds {
21971da177e4SLinus Torvalds 	struct usbdevfs_urb uurb;
219870f1b0d3SEric W. Biederman 	sigval_t userurb_sigval;
21991da177e4SLinus Torvalds 
2200c714de5dSAl Viro 	if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
22011da177e4SLinus Torvalds 		return -EFAULT;
22021da177e4SLinus Torvalds 
220370f1b0d3SEric W. Biederman 	memset(&userurb_sigval, 0, sizeof(userurb_sigval));
220470f1b0d3SEric W. Biederman 	userurb_sigval.sival_int = ptr_to_compat(arg);
220570f1b0d3SEric W. Biederman 
220604e482ffSGreg Kroah-Hartman 	return proc_do_submiturb(ps, &uurb,
220704e482ffSGreg Kroah-Hartman 			((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
220870f1b0d3SEric W. Biederman 			arg, userurb_sigval);
22091da177e4SLinus Torvalds }
22101da177e4SLinus Torvalds 
processcompl_compat(struct async * as,void __user * __user * arg)22111da177e4SLinus Torvalds static int processcompl_compat(struct async *as, void __user * __user *arg)
22121da177e4SLinus Torvalds {
22131da177e4SLinus Torvalds 	struct urb *urb = as->urb;
22141da177e4SLinus Torvalds 	struct usbdevfs_urb32 __user *userurb = as->userurb;
22151da177e4SLinus Torvalds 	void __user *addr = as->userurb;
22161da177e4SLinus Torvalds 	unsigned int i;
22171da177e4SLinus Torvalds 
22182ef47001SAlan Stern 	compute_isochronous_actual_length(urb);
22192102e06aSHans de Goede 	if (as->userbuffer && urb->actual_length) {
22203d97ff63SHans de Goede 		if (copy_urb_data_to_user(as->userbuffer, urb))
22211da177e4SLinus Torvalds 			return -EFAULT;
22222102e06aSHans de Goede 	}
2223e015268dSAlan Stern 	if (put_user(as->status, &userurb->status))
22241da177e4SLinus Torvalds 		return -EFAULT;
22251da177e4SLinus Torvalds 	if (put_user(urb->actual_length, &userurb->actual_length))
22261da177e4SLinus Torvalds 		return -EFAULT;
22271da177e4SLinus Torvalds 	if (put_user(urb->error_count, &userurb->error_count))
22281da177e4SLinus Torvalds 		return -EFAULT;
22291da177e4SLinus Torvalds 
223093cf9b90SAlan Stern 	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
22311da177e4SLinus Torvalds 		for (i = 0; i < urb->number_of_packets; i++) {
22321da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].actual_length,
22331da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].actual_length))
22341da177e4SLinus Torvalds 				return -EFAULT;
22351da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].status,
22361da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].status))
22371da177e4SLinus Torvalds 				return -EFAULT;
22381da177e4SLinus Torvalds 		}
2239668a9541SChristopher Li 	}
22401da177e4SLinus Torvalds 
2241c714de5dSAl Viro 	if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
22421da177e4SLinus Torvalds 		return -EFAULT;
22431da177e4SLinus Torvalds 	return 0;
22441da177e4SLinus Torvalds }
22451da177e4SLinus Torvalds 
proc_reapurb_compat(struct usb_dev_state * ps,void __user * arg)22469b6f0c4bSValentina Manea static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
22471da177e4SLinus Torvalds {
22481da177e4SLinus Torvalds 	struct async *as = reap_as(ps);
2249a016a816SAlan Stern 
2250ddeee0b2SLinus Torvalds 	if (as) {
2251a016a816SAlan Stern 		int retval;
2252a016a816SAlan Stern 
2253f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2254a016a816SAlan Stern 		retval = processcompl_compat(as, (void __user * __user *)arg);
2255ddeee0b2SLinus Torvalds 		free_async(as);
2256ddeee0b2SLinus Torvalds 		return retval;
2257ddeee0b2SLinus Torvalds 	}
22581da177e4SLinus Torvalds 	if (signal_pending(current))
22591da177e4SLinus Torvalds 		return -EINTR;
22603f2cee73SAlan Stern 	return -ENODEV;
22611da177e4SLinus Torvalds }
22621da177e4SLinus Torvalds 
proc_reapurbnonblock_compat(struct usb_dev_state * ps,void __user * arg)22639b6f0c4bSValentina Manea static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
22641da177e4SLinus Torvalds {
2265ddeee0b2SLinus Torvalds 	int retval;
22661da177e4SLinus Torvalds 	struct async *as;
22671da177e4SLinus Torvalds 
2268ddeee0b2SLinus Torvalds 	as = async_getcompleted(ps);
2269ddeee0b2SLinus Torvalds 	if (as) {
2270f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2271ddeee0b2SLinus Torvalds 		retval = processcompl_compat(as, (void __user * __user *)arg);
2272ddeee0b2SLinus Torvalds 		free_async(as);
22733f2cee73SAlan Stern 	} else {
22743f2cee73SAlan Stern 		retval = (connected(ps) ? -EAGAIN : -ENODEV);
2275ddeee0b2SLinus Torvalds 	}
2276ddeee0b2SLinus Torvalds 	return retval;
22771da177e4SLinus Torvalds }
22781da177e4SLinus Torvalds 
2279637e8a60SArnd Bergmann 
22801da177e4SLinus Torvalds #endif
22811da177e4SLinus Torvalds 
proc_disconnectsignal(struct usb_dev_state * ps,void __user * arg)22829b6f0c4bSValentina Manea static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
22831da177e4SLinus Torvalds {
22841da177e4SLinus Torvalds 	struct usbdevfs_disconnectsignal ds;
22851da177e4SLinus Torvalds 
22861da177e4SLinus Torvalds 	if (copy_from_user(&ds, arg, sizeof(ds)))
22871da177e4SLinus Torvalds 		return -EFAULT;
22881da177e4SLinus Torvalds 	ps->discsignr = ds.signr;
228970f1b0d3SEric W. Biederman 	ps->disccontext.sival_ptr = ds.context;
22901da177e4SLinus Torvalds 	return 0;
22911da177e4SLinus Torvalds }
22921da177e4SLinus Torvalds 
proc_claiminterface(struct usb_dev_state * ps,void __user * arg)22939b6f0c4bSValentina Manea static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)
22941da177e4SLinus Torvalds {
22951da177e4SLinus Torvalds 	unsigned int ifnum;
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 	if (get_user(ifnum, (unsigned int __user *)arg))
22981da177e4SLinus Torvalds 		return -EFAULT;
22991da177e4SLinus Torvalds 	return claimintf(ps, ifnum);
23001da177e4SLinus Torvalds }
23011da177e4SLinus Torvalds 
proc_releaseinterface(struct usb_dev_state * ps,void __user * arg)23029b6f0c4bSValentina Manea static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
23031da177e4SLinus Torvalds {
23041da177e4SLinus Torvalds 	unsigned int ifnum;
23051da177e4SLinus Torvalds 	int ret;
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	if (get_user(ifnum, (unsigned int __user *)arg))
23081da177e4SLinus Torvalds 		return -EFAULT;
2309135551eaSKris Borer 	ret = releaseintf(ps, ifnum);
2310135551eaSKris Borer 	if (ret < 0)
23111da177e4SLinus Torvalds 		return ret;
23121da177e4SLinus Torvalds 	destroy_async_on_interface(ps, ifnum);
23131da177e4SLinus Torvalds 	return 0;
23141da177e4SLinus Torvalds }
23151da177e4SLinus Torvalds 
proc_ioctl(struct usb_dev_state * ps,struct usbdevfs_ioctl * ctl)23169b6f0c4bSValentina Manea static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
23171da177e4SLinus Torvalds {
23181da177e4SLinus Torvalds 	int			size;
23191da177e4SLinus Torvalds 	void			*buf = NULL;
23201da177e4SLinus Torvalds 	int			retval = 0;
23211da177e4SLinus Torvalds 	struct usb_interface    *intf = NULL;
23221da177e4SLinus Torvalds 	struct usb_driver       *driver = NULL;
23231da177e4SLinus Torvalds 
2324d883f52eSReilly Grant 	if (ps->privileges_dropped)
2325d883f52eSReilly Grant 		return -EACCES;
2326d883f52eSReilly Grant 
2327086ebf92SWeitao Hou 	if (!connected(ps))
2328086ebf92SWeitao Hou 		return -ENODEV;
2329086ebf92SWeitao Hou 
2330c36fc889SPete Zaitcev 	/* alloc buffer */
2331135551eaSKris Borer 	size = _IOC_SIZE(ctl->ioctl_code);
2332135551eaSKris Borer 	if (size > 0) {
23334baf0df7STülin İzer 		buf = kmalloc(size, GFP_KERNEL);
23344baf0df7STülin İzer 		if (buf == NULL)
23351da177e4SLinus Torvalds 			return -ENOMEM;
2336c36fc889SPete Zaitcev 		if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
2337c36fc889SPete Zaitcev 			if (copy_from_user(buf, ctl->data, size)) {
23381da177e4SLinus Torvalds 				kfree(buf);
23391da177e4SLinus Torvalds 				return -EFAULT;
23401da177e4SLinus Torvalds 			}
23411da177e4SLinus Torvalds 		} else {
23421da177e4SLinus Torvalds 			memset(buf, 0, size);
23431da177e4SLinus Torvalds 		}
23441da177e4SLinus Torvalds 	}
23451da177e4SLinus Torvalds 
23461da177e4SLinus Torvalds 	if (ps->dev->state != USB_STATE_CONFIGURED)
23471da177e4SLinus Torvalds 		retval = -EHOSTUNREACH;
2348c36fc889SPete Zaitcev 	else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
23491da177e4SLinus Torvalds 		retval = -EINVAL;
2350c36fc889SPete Zaitcev 	else switch (ctl->ioctl_code) {
23511da177e4SLinus Torvalds 
23521da177e4SLinus Torvalds 	/* disconnect kernel driver from interface */
23531da177e4SLinus Torvalds 	case USBDEVFS_DISCONNECT:
23541da177e4SLinus Torvalds 		if (intf->dev.driver) {
23551da177e4SLinus Torvalds 			driver = to_usb_driver(intf->dev.driver);
23561da177e4SLinus Torvalds 			dev_dbg(&intf->dev, "disconnect by usbfs\n");
23571da177e4SLinus Torvalds 			usb_driver_release_interface(driver, intf);
23581da177e4SLinus Torvalds 		} else
23591da177e4SLinus Torvalds 			retval = -ENODATA;
23601da177e4SLinus Torvalds 		break;
23611da177e4SLinus Torvalds 
23621da177e4SLinus Torvalds 	/* let kernel drivers try to (re)bind to the interface */
23631da177e4SLinus Torvalds 	case USBDEVFS_CONNECT:
2364885e9747SAlan Stern 		if (!intf->dev.driver)
2365885e9747SAlan Stern 			retval = device_attach(&intf->dev);
2366885e9747SAlan Stern 		else
2367885e9747SAlan Stern 			retval = -EBUSY;
23681da177e4SLinus Torvalds 		break;
23691da177e4SLinus Torvalds 
23701da177e4SLinus Torvalds 	/* talk directly to the interface's driver */
23711da177e4SLinus Torvalds 	default:
23721da177e4SLinus Torvalds 		if (intf->dev.driver)
23731da177e4SLinus Torvalds 			driver = to_usb_driver(intf->dev.driver);
2374c532b29aSAndi Kleen 		if (driver == NULL || driver->unlocked_ioctl == NULL) {
23751da177e4SLinus Torvalds 			retval = -ENOTTY;
23761da177e4SLinus Torvalds 		} else {
2377c532b29aSAndi Kleen 			retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
23781da177e4SLinus Torvalds 			if (retval == -ENOIOCTLCMD)
23791da177e4SLinus Torvalds 				retval = -ENOTTY;
23801da177e4SLinus Torvalds 		}
23811da177e4SLinus Torvalds 	}
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 	/* cleanup and return */
23841da177e4SLinus Torvalds 	if (retval >= 0
2385c36fc889SPete Zaitcev 			&& (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
23861da177e4SLinus Torvalds 			&& size > 0
2387c36fc889SPete Zaitcev 			&& copy_to_user(ctl->data, buf, size) != 0)
23881da177e4SLinus Torvalds 		retval = -EFAULT;
23896fd19f4bSJesper Juhl 
23901da177e4SLinus Torvalds 	kfree(buf);
23911da177e4SLinus Torvalds 	return retval;
23921da177e4SLinus Torvalds }
23931da177e4SLinus Torvalds 
proc_ioctl_default(struct usb_dev_state * ps,void __user * arg)23949b6f0c4bSValentina Manea static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
2395c36fc889SPete Zaitcev {
2396c36fc889SPete Zaitcev 	struct usbdevfs_ioctl	ctrl;
2397c36fc889SPete Zaitcev 
2398c36fc889SPete Zaitcev 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
2399c36fc889SPete Zaitcev 		return -EFAULT;
2400c36fc889SPete Zaitcev 	return proc_ioctl(ps, &ctrl);
2401c36fc889SPete Zaitcev }
2402c36fc889SPete Zaitcev 
2403c36fc889SPete Zaitcev #ifdef CONFIG_COMPAT
proc_ioctl_compat(struct usb_dev_state * ps,compat_uptr_t arg)24049b6f0c4bSValentina Manea static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
2405c36fc889SPete Zaitcev {
2406cc1a7c4bSAl Viro 	struct usbdevfs_ioctl32 ioc32;
2407c36fc889SPete Zaitcev 	struct usbdevfs_ioctl ctrl;
2408c36fc889SPete Zaitcev 
2409cc1a7c4bSAl Viro 	if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
2410c36fc889SPete Zaitcev 		return -EFAULT;
2411cc1a7c4bSAl Viro 	ctrl.ifno = ioc32.ifno;
2412cc1a7c4bSAl Viro 	ctrl.ioctl_code = ioc32.ioctl_code;
2413cc1a7c4bSAl Viro 	ctrl.data = compat_ptr(ioc32.data);
2414c36fc889SPete Zaitcev 	return proc_ioctl(ps, &ctrl);
2415c36fc889SPete Zaitcev }
2416c36fc889SPete Zaitcev #endif
2417c36fc889SPete Zaitcev 
proc_claim_port(struct usb_dev_state * ps,void __user * arg)24189b6f0c4bSValentina Manea static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)
24197cbe5dcaSAlan Stern {
24207cbe5dcaSAlan Stern 	unsigned portnum;
24217cbe5dcaSAlan Stern 	int rc;
24227cbe5dcaSAlan Stern 
24237cbe5dcaSAlan Stern 	if (get_user(portnum, (unsigned __user *) arg))
24247cbe5dcaSAlan Stern 		return -EFAULT;
24257cbe5dcaSAlan Stern 	rc = usb_hub_claim_port(ps->dev, portnum, ps);
24267cbe5dcaSAlan Stern 	if (rc == 0)
24277cbe5dcaSAlan Stern 		snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
24287cbe5dcaSAlan Stern 			portnum, task_pid_nr(current), current->comm);
24297cbe5dcaSAlan Stern 	return rc;
24307cbe5dcaSAlan Stern }
24317cbe5dcaSAlan Stern 
proc_release_port(struct usb_dev_state * ps,void __user * arg)24329b6f0c4bSValentina Manea static int proc_release_port(struct usb_dev_state *ps, void __user *arg)
24337cbe5dcaSAlan Stern {
24347cbe5dcaSAlan Stern 	unsigned portnum;
24357cbe5dcaSAlan Stern 
24367cbe5dcaSAlan Stern 	if (get_user(portnum, (unsigned __user *) arg))
24377cbe5dcaSAlan Stern 		return -EFAULT;
24387cbe5dcaSAlan Stern 	return usb_hub_release_port(ps->dev, portnum, ps);
24397cbe5dcaSAlan Stern }
24407cbe5dcaSAlan Stern 
proc_get_capabilities(struct usb_dev_state * ps,void __user * arg)24419b6f0c4bSValentina Manea static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
244219181bc5SHans de Goede {
244319181bc5SHans de Goede 	__u32 caps;
244419181bc5SHans de Goede 
24453f2cee73SAlan Stern 	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
2446d883f52eSReilly Grant 			USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
24474ed33505SAlan Stern 			USBDEVFS_CAP_DROP_PRIVILEGES |
24484ed33505SAlan Stern 			USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND;
244919181bc5SHans de Goede 	if (!ps->dev->bus->no_stop_on_short)
245019181bc5SHans de Goede 		caps |= USBDEVFS_CAP_BULK_CONTINUATION;
24513d97ff63SHans de Goede 	if (ps->dev->bus->sg_tablesize)
24523d97ff63SHans de Goede 		caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
245319181bc5SHans de Goede 
245419181bc5SHans de Goede 	if (put_user(caps, (__u32 __user *)arg))
245519181bc5SHans de Goede 		return -EFAULT;
245619181bc5SHans de Goede 
245719181bc5SHans de Goede 	return 0;
245819181bc5SHans de Goede }
245919181bc5SHans de Goede 
proc_disconnect_claim(struct usb_dev_state * ps,void __user * arg)24609b6f0c4bSValentina Manea static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
24610837e7e5SHans de Goede {
24620837e7e5SHans de Goede 	struct usbdevfs_disconnect_claim dc;
24630837e7e5SHans de Goede 	struct usb_interface *intf;
24640837e7e5SHans de Goede 
24650837e7e5SHans de Goede 	if (copy_from_user(&dc, arg, sizeof(dc)))
24660837e7e5SHans de Goede 		return -EFAULT;
24670837e7e5SHans de Goede 
24680837e7e5SHans de Goede 	intf = usb_ifnum_to_if(ps->dev, dc.interface);
24690837e7e5SHans de Goede 	if (!intf)
24700837e7e5SHans de Goede 		return -EINVAL;
24710837e7e5SHans de Goede 
24720837e7e5SHans de Goede 	if (intf->dev.driver) {
24730837e7e5SHans de Goede 		struct usb_driver *driver = to_usb_driver(intf->dev.driver);
24740837e7e5SHans de Goede 
2475d883f52eSReilly Grant 		if (ps->privileges_dropped)
2476d883f52eSReilly Grant 			return -EACCES;
2477d883f52eSReilly Grant 
24780837e7e5SHans de Goede 		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
24790837e7e5SHans de Goede 				strncmp(dc.driver, intf->dev.driver->name,
24800837e7e5SHans de Goede 					sizeof(dc.driver)) != 0)
24810837e7e5SHans de Goede 			return -EBUSY;
24820837e7e5SHans de Goede 
24830837e7e5SHans de Goede 		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
24840837e7e5SHans de Goede 				strncmp(dc.driver, intf->dev.driver->name,
24850837e7e5SHans de Goede 					sizeof(dc.driver)) == 0)
24860837e7e5SHans de Goede 			return -EBUSY;
24870837e7e5SHans de Goede 
24880837e7e5SHans de Goede 		dev_dbg(&intf->dev, "disconnect by usbfs\n");
24890837e7e5SHans de Goede 		usb_driver_release_interface(driver, intf);
24900837e7e5SHans de Goede 	}
24910837e7e5SHans de Goede 
24920837e7e5SHans de Goede 	return claimintf(ps, dc.interface);
24930837e7e5SHans de Goede }
24940837e7e5SHans de Goede 
proc_alloc_streams(struct usb_dev_state * ps,void __user * arg)24953e75c6deSLinus Torvalds static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg)
2496bcf7f6e3SHans de Goede {
2497bcf7f6e3SHans de Goede 	unsigned num_streams, num_eps;
2498bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
2499bcf7f6e3SHans de Goede 	struct usb_interface *intf;
2500bcf7f6e3SHans de Goede 	int r;
2501bcf7f6e3SHans de Goede 
2502bcf7f6e3SHans de Goede 	r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
2503bcf7f6e3SHans de Goede 				   &eps, &intf);
2504bcf7f6e3SHans de Goede 	if (r)
2505bcf7f6e3SHans de Goede 		return r;
2506bcf7f6e3SHans de Goede 
2507bcf7f6e3SHans de Goede 	destroy_async_on_interface(ps,
2508bcf7f6e3SHans de Goede 				   intf->altsetting[0].desc.bInterfaceNumber);
2509bcf7f6e3SHans de Goede 
2510bcf7f6e3SHans de Goede 	r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
2511bcf7f6e3SHans de Goede 	kfree(eps);
2512bcf7f6e3SHans de Goede 	return r;
2513bcf7f6e3SHans de Goede }
2514bcf7f6e3SHans de Goede 
proc_free_streams(struct usb_dev_state * ps,void __user * arg)25153e75c6deSLinus Torvalds static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
2516bcf7f6e3SHans de Goede {
2517bcf7f6e3SHans de Goede 	unsigned num_eps;
2518bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
2519bcf7f6e3SHans de Goede 	struct usb_interface *intf;
2520bcf7f6e3SHans de Goede 	int r;
2521bcf7f6e3SHans de Goede 
2522bcf7f6e3SHans de Goede 	r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
2523bcf7f6e3SHans de Goede 	if (r)
2524bcf7f6e3SHans de Goede 		return r;
2525bcf7f6e3SHans de Goede 
2526bcf7f6e3SHans de Goede 	destroy_async_on_interface(ps,
2527bcf7f6e3SHans de Goede 				   intf->altsetting[0].desc.bInterfaceNumber);
2528bcf7f6e3SHans de Goede 
2529bcf7f6e3SHans de Goede 	r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
2530bcf7f6e3SHans de Goede 	kfree(eps);
2531bcf7f6e3SHans de Goede 	return r;
2532bcf7f6e3SHans de Goede }
2533bcf7f6e3SHans de Goede 
proc_drop_privileges(struct usb_dev_state * ps,void __user * arg)2534d883f52eSReilly Grant static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
2535d883f52eSReilly Grant {
2536d883f52eSReilly Grant 	u32 data;
2537d883f52eSReilly Grant 
2538d883f52eSReilly Grant 	if (copy_from_user(&data, arg, sizeof(data)))
2539d883f52eSReilly Grant 		return -EFAULT;
2540d883f52eSReilly Grant 
25410f5e1558SMasahiro Yamada 	/* This is a one way operation. Once privileges are
2542d883f52eSReilly Grant 	 * dropped, you cannot regain them. You may however reissue
2543d883f52eSReilly Grant 	 * this ioctl to shrink the allowed interfaces mask.
2544d883f52eSReilly Grant 	 */
2545d883f52eSReilly Grant 	ps->interface_allowed_mask &= data;
2546d883f52eSReilly Grant 	ps->privileges_dropped = true;
2547d883f52eSReilly Grant 
2548d883f52eSReilly Grant 	return 0;
2549d883f52eSReilly Grant }
2550d883f52eSReilly Grant 
proc_forbid_suspend(struct usb_dev_state * ps)25517794f486SAlan Stern static int proc_forbid_suspend(struct usb_dev_state *ps)
25527794f486SAlan Stern {
25537794f486SAlan Stern 	int ret = 0;
25547794f486SAlan Stern 
25557794f486SAlan Stern 	if (ps->suspend_allowed) {
25567794f486SAlan Stern 		ret = usb_autoresume_device(ps->dev);
25577794f486SAlan Stern 		if (ret == 0)
25587794f486SAlan Stern 			ps->suspend_allowed = false;
25597794f486SAlan Stern 		else if (ret != -ENODEV)
25607794f486SAlan Stern 			ret = -EIO;
25617794f486SAlan Stern 	}
25627794f486SAlan Stern 	return ret;
25637794f486SAlan Stern }
25647794f486SAlan Stern 
proc_allow_suspend(struct usb_dev_state * ps)25657794f486SAlan Stern static int proc_allow_suspend(struct usb_dev_state *ps)
25667794f486SAlan Stern {
25677794f486SAlan Stern 	if (!connected(ps))
25687794f486SAlan Stern 		return -ENODEV;
25697794f486SAlan Stern 
25707794f486SAlan Stern 	WRITE_ONCE(ps->not_yet_resumed, 1);
25717794f486SAlan Stern 	if (!ps->suspend_allowed) {
25727794f486SAlan Stern 		usb_autosuspend_device(ps->dev);
25737794f486SAlan Stern 		ps->suspend_allowed = true;
25747794f486SAlan Stern 	}
25757794f486SAlan Stern 	return 0;
25767794f486SAlan Stern }
25777794f486SAlan Stern 
proc_wait_for_resume(struct usb_dev_state * ps)25787794f486SAlan Stern static int proc_wait_for_resume(struct usb_dev_state *ps)
25797794f486SAlan Stern {
25807794f486SAlan Stern 	int ret;
25817794f486SAlan Stern 
25827794f486SAlan Stern 	usb_unlock_device(ps->dev);
25837794f486SAlan Stern 	ret = wait_event_interruptible(ps->wait_for_resume,
25847794f486SAlan Stern 			READ_ONCE(ps->not_yet_resumed) == 0);
25857794f486SAlan Stern 	usb_lock_device(ps->dev);
25867794f486SAlan Stern 
25877794f486SAlan Stern 	if (ret != 0)
25887794f486SAlan Stern 		return -EINTR;
25897794f486SAlan Stern 	return proc_forbid_suspend(ps);
25907794f486SAlan Stern }
25917794f486SAlan Stern 
25921da177e4SLinus Torvalds /*
25931da177e4SLinus Torvalds  * NOTE:  All requests here that have interface numbers as parameters
25941da177e4SLinus Torvalds  * are assuming that somehow the configuration has been prevented from
25951da177e4SLinus Torvalds  * changing.  But there's no mechanism to ensure that...
25961da177e4SLinus Torvalds  */
usbdev_do_ioctl(struct file * file,unsigned int cmd,void __user * p)2597637e8a60SArnd Bergmann static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2598637e8a60SArnd Bergmann 				void __user *p)
25991da177e4SLinus Torvalds {
26009b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
2601496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
26021da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
26031da177e4SLinus Torvalds 	int ret = -ENOTTY;
26041da177e4SLinus Torvalds 
26051da177e4SLinus Torvalds 	if (!(file->f_mode & FMODE_WRITE))
26061da177e4SLinus Torvalds 		return -EPERM;
260701412a21SOliver Neukum 
26081da177e4SLinus Torvalds 	usb_lock_device(dev);
26093f2cee73SAlan Stern 
26103f2cee73SAlan Stern 	/* Reap operations are allowed even after disconnection */
26113f2cee73SAlan Stern 	switch (cmd) {
26123f2cee73SAlan Stern 	case USBDEVFS_REAPURB:
26133f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURB\n", __func__);
26143f2cee73SAlan Stern 		ret = proc_reapurb(ps, p);
26153f2cee73SAlan Stern 		goto done;
26163f2cee73SAlan Stern 
26173f2cee73SAlan Stern 	case USBDEVFS_REAPURBNDELAY:
26183f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
26193f2cee73SAlan Stern 		ret = proc_reapurbnonblock(ps, p);
26203f2cee73SAlan Stern 		goto done;
26213f2cee73SAlan Stern 
26223f2cee73SAlan Stern #ifdef CONFIG_COMPAT
26233f2cee73SAlan Stern 	case USBDEVFS_REAPURB32:
26243f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURB32\n", __func__);
26253f2cee73SAlan Stern 		ret = proc_reapurb_compat(ps, p);
26263f2cee73SAlan Stern 		goto done;
26273f2cee73SAlan Stern 
26283f2cee73SAlan Stern 	case USBDEVFS_REAPURBNDELAY32:
26293f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
26303f2cee73SAlan Stern 		ret = proc_reapurbnonblock_compat(ps, p);
26313f2cee73SAlan Stern 		goto done;
26323f2cee73SAlan Stern #endif
26333f2cee73SAlan Stern 	}
26343f2cee73SAlan Stern 
2635349710c3SAlan Stern 	if (!connected(ps)) {
26361da177e4SLinus Torvalds 		usb_unlock_device(dev);
26371da177e4SLinus Torvalds 		return -ENODEV;
26381da177e4SLinus Torvalds 	}
26391da177e4SLinus Torvalds 
26401da177e4SLinus Torvalds 	switch (cmd) {
26411da177e4SLinus Torvalds 	case USBDEVFS_CONTROL:
2642441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CONTROL\n", __func__);
26431da177e4SLinus Torvalds 		ret = proc_control(ps, p);
26441da177e4SLinus Torvalds 		if (ret >= 0)
2645*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
26461da177e4SLinus Torvalds 		break;
26471da177e4SLinus Torvalds 
26481da177e4SLinus Torvalds 	case USBDEVFS_BULK:
2649441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: BULK\n", __func__);
26501da177e4SLinus Torvalds 		ret = proc_bulk(ps, p);
26511da177e4SLinus Torvalds 		if (ret >= 0)
2652*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
26531da177e4SLinus Torvalds 		break;
26541da177e4SLinus Torvalds 
26551da177e4SLinus Torvalds 	case USBDEVFS_RESETEP:
2656441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RESETEP\n", __func__);
26571da177e4SLinus Torvalds 		ret = proc_resetep(ps, p);
26581da177e4SLinus Torvalds 		if (ret >= 0)
2659*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
26601da177e4SLinus Torvalds 		break;
26611da177e4SLinus Torvalds 
26621da177e4SLinus Torvalds 	case USBDEVFS_RESET:
2663441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RESET\n", __func__);
26641da177e4SLinus Torvalds 		ret = proc_resetdevice(ps);
26651da177e4SLinus Torvalds 		break;
26661da177e4SLinus Torvalds 
26671da177e4SLinus Torvalds 	case USBDEVFS_CLEAR_HALT:
2668441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
26691da177e4SLinus Torvalds 		ret = proc_clearhalt(ps, p);
26701da177e4SLinus Torvalds 		if (ret >= 0)
2671*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
26721da177e4SLinus Torvalds 		break;
26731da177e4SLinus Torvalds 
26741da177e4SLinus Torvalds 	case USBDEVFS_GETDRIVER:
2675441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
26761da177e4SLinus Torvalds 		ret = proc_getdriver(ps, p);
26771da177e4SLinus Torvalds 		break;
26781da177e4SLinus Torvalds 
26791da177e4SLinus Torvalds 	case USBDEVFS_CONNECTINFO:
2680441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
26811da177e4SLinus Torvalds 		ret = proc_connectinfo(ps, p);
26821da177e4SLinus Torvalds 		break;
26831da177e4SLinus Torvalds 
26841da177e4SLinus Torvalds 	case USBDEVFS_SETINTERFACE:
2685441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
26861da177e4SLinus Torvalds 		ret = proc_setintf(ps, p);
26871da177e4SLinus Torvalds 		break;
26881da177e4SLinus Torvalds 
26891da177e4SLinus Torvalds 	case USBDEVFS_SETCONFIGURATION:
2690441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
26911da177e4SLinus Torvalds 		ret = proc_setconfig(ps, p);
26921da177e4SLinus Torvalds 		break;
26931da177e4SLinus Torvalds 
26941da177e4SLinus Torvalds 	case USBDEVFS_SUBMITURB:
2695441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
26961da177e4SLinus Torvalds 		ret = proc_submiturb(ps, p);
26971da177e4SLinus Torvalds 		if (ret >= 0)
2698*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
26991da177e4SLinus Torvalds 		break;
27001da177e4SLinus Torvalds 
27011da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
2702637e8a60SArnd Bergmann 	case USBDEVFS_CONTROL32:
2703637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: CONTROL32\n", __func__);
2704637e8a60SArnd Bergmann 		ret = proc_control_compat(ps, p);
2705637e8a60SArnd Bergmann 		if (ret >= 0)
2706*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
2707637e8a60SArnd Bergmann 		break;
2708637e8a60SArnd Bergmann 
2709637e8a60SArnd Bergmann 	case USBDEVFS_BULK32:
2710637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: BULK32\n", __func__);
2711637e8a60SArnd Bergmann 		ret = proc_bulk_compat(ps, p);
2712637e8a60SArnd Bergmann 		if (ret >= 0)
2713*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
2714637e8a60SArnd Bergmann 		break;
2715637e8a60SArnd Bergmann 
2716637e8a60SArnd Bergmann 	case USBDEVFS_DISCSIGNAL32:
2717637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
2718637e8a60SArnd Bergmann 		ret = proc_disconnectsignal_compat(ps, p);
2719637e8a60SArnd Bergmann 		break;
27201da177e4SLinus Torvalds 
27211da177e4SLinus Torvalds 	case USBDEVFS_SUBMITURB32:
2722441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
27231da177e4SLinus Torvalds 		ret = proc_submiturb_compat(ps, p);
27241da177e4SLinus Torvalds 		if (ret >= 0)
2725*c7603adcSJeff Layton 			inode->i_mtime = inode_set_ctime_current(inode);
27261da177e4SLinus Torvalds 		break;
27271da177e4SLinus Torvalds 
2728c36fc889SPete Zaitcev 	case USBDEVFS_IOCTL32:
2729637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: IOCTL32\n", __func__);
2730c714de5dSAl Viro 		ret = proc_ioctl_compat(ps, ptr_to_compat(p));
2731c36fc889SPete Zaitcev 		break;
27321da177e4SLinus Torvalds #endif
27331da177e4SLinus Torvalds 
27341da177e4SLinus Torvalds 	case USBDEVFS_DISCARDURB:
2735f3bc432aSAlan Stern 		snoop(&dev->dev, "%s: DISCARDURB %px\n", __func__, p);
27361da177e4SLinus Torvalds 		ret = proc_unlinkurb(ps, p);
27371da177e4SLinus Torvalds 		break;
27381da177e4SLinus Torvalds 
27391da177e4SLinus Torvalds 	case USBDEVFS_DISCSIGNAL:
2740441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
27411da177e4SLinus Torvalds 		ret = proc_disconnectsignal(ps, p);
27421da177e4SLinus Torvalds 		break;
27431da177e4SLinus Torvalds 
27441da177e4SLinus Torvalds 	case USBDEVFS_CLAIMINTERFACE:
2745441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
27461da177e4SLinus Torvalds 		ret = proc_claiminterface(ps, p);
27471da177e4SLinus Torvalds 		break;
27481da177e4SLinus Torvalds 
27491da177e4SLinus Torvalds 	case USBDEVFS_RELEASEINTERFACE:
2750441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
27511da177e4SLinus Torvalds 		ret = proc_releaseinterface(ps, p);
27521da177e4SLinus Torvalds 		break;
27531da177e4SLinus Torvalds 
27541da177e4SLinus Torvalds 	case USBDEVFS_IOCTL:
2755441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: IOCTL\n", __func__);
2756c36fc889SPete Zaitcev 		ret = proc_ioctl_default(ps, p);
27571da177e4SLinus Torvalds 		break;
27587cbe5dcaSAlan Stern 
27597cbe5dcaSAlan Stern 	case USBDEVFS_CLAIM_PORT:
27607cbe5dcaSAlan Stern 		snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
27617cbe5dcaSAlan Stern 		ret = proc_claim_port(ps, p);
27627cbe5dcaSAlan Stern 		break;
27637cbe5dcaSAlan Stern 
27647cbe5dcaSAlan Stern 	case USBDEVFS_RELEASE_PORT:
27657cbe5dcaSAlan Stern 		snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
27667cbe5dcaSAlan Stern 		ret = proc_release_port(ps, p);
27677cbe5dcaSAlan Stern 		break;
276819181bc5SHans de Goede 	case USBDEVFS_GET_CAPABILITIES:
276919181bc5SHans de Goede 		ret = proc_get_capabilities(ps, p);
277019181bc5SHans de Goede 		break;
27710837e7e5SHans de Goede 	case USBDEVFS_DISCONNECT_CLAIM:
27720837e7e5SHans de Goede 		ret = proc_disconnect_claim(ps, p);
27730837e7e5SHans de Goede 		break;
2774bcf7f6e3SHans de Goede 	case USBDEVFS_ALLOC_STREAMS:
2775bcf7f6e3SHans de Goede 		ret = proc_alloc_streams(ps, p);
2776bcf7f6e3SHans de Goede 		break;
2777bcf7f6e3SHans de Goede 	case USBDEVFS_FREE_STREAMS:
2778bcf7f6e3SHans de Goede 		ret = proc_free_streams(ps, p);
2779bcf7f6e3SHans de Goede 		break;
2780d883f52eSReilly Grant 	case USBDEVFS_DROP_PRIVILEGES:
2781d883f52eSReilly Grant 		ret = proc_drop_privileges(ps, p);
2782d883f52eSReilly Grant 		break;
2783c01b244aSAlan Stern 	case USBDEVFS_GET_SPEED:
2784c01b244aSAlan Stern 		ret = ps->dev->speed;
2785c01b244aSAlan Stern 		break;
27867794f486SAlan Stern 	case USBDEVFS_FORBID_SUSPEND:
27877794f486SAlan Stern 		ret = proc_forbid_suspend(ps);
27887794f486SAlan Stern 		break;
27897794f486SAlan Stern 	case USBDEVFS_ALLOW_SUSPEND:
27907794f486SAlan Stern 		ret = proc_allow_suspend(ps);
27917794f486SAlan Stern 		break;
27927794f486SAlan Stern 	case USBDEVFS_WAIT_FOR_RESUME:
27937794f486SAlan Stern 		ret = proc_wait_for_resume(ps);
27947794f486SAlan Stern 		break;
27951da177e4SLinus Torvalds 	}
27963f2cee73SAlan Stern 
27976d101f24SDmitry Torokhov 	/* Handle variable-length commands */
27986d101f24SDmitry Torokhov 	switch (cmd & ~IOCSIZE_MASK) {
27996d101f24SDmitry Torokhov 	case USBDEVFS_CONNINFO_EX(0):
28006d101f24SDmitry Torokhov 		ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
28016d101f24SDmitry Torokhov 		break;
28026d101f24SDmitry Torokhov 	}
28036d101f24SDmitry Torokhov 
28043f2cee73SAlan Stern  done:
28051da177e4SLinus Torvalds 	usb_unlock_device(dev);
28061da177e4SLinus Torvalds 	if (ret >= 0)
2807078cd827SDeepa Dinamani 		inode->i_atime = current_time(inode);
28081da177e4SLinus Torvalds 	return ret;
28091da177e4SLinus Torvalds }
28101da177e4SLinus Torvalds 
usbdev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)2811637e8a60SArnd Bergmann static long usbdev_ioctl(struct file *file, unsigned int cmd,
2812637e8a60SArnd Bergmann 			unsigned long arg)
2813637e8a60SArnd Bergmann {
2814637e8a60SArnd Bergmann 	int ret;
2815637e8a60SArnd Bergmann 
2816637e8a60SArnd Bergmann 	ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
2817637e8a60SArnd Bergmann 
2818637e8a60SArnd Bergmann 	return ret;
2819637e8a60SArnd Bergmann }
2820637e8a60SArnd Bergmann 
28211da177e4SLinus Torvalds /* No kernel lock - fine */
usbdev_poll(struct file * file,struct poll_table_struct * wait)2822afc9a42bSAl Viro static __poll_t usbdev_poll(struct file *file,
282304e482ffSGreg Kroah-Hartman 				struct poll_table_struct *wait)
28241da177e4SLinus Torvalds {
28259b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
2826afc9a42bSAl Viro 	__poll_t mask = 0;
28271da177e4SLinus Torvalds 
28281da177e4SLinus Torvalds 	poll_wait(file, &ps->wait, wait);
28291da177e4SLinus Torvalds 	if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
2830a9a08845SLinus Torvalds 		mask |= EPOLLOUT | EPOLLWRNORM;
2831349710c3SAlan Stern 	if (!connected(ps))
2832a9a08845SLinus Torvalds 		mask |= EPOLLHUP;
28335cce4382SAlan Stern 	if (list_empty(&ps->list))
2834a9a08845SLinus Torvalds 		mask |= EPOLLERR;
28351da177e4SLinus Torvalds 	return mask;
28361da177e4SLinus Torvalds }
28371da177e4SLinus Torvalds 
28389f8b17e6SKay Sievers const struct file_operations usbdev_file_operations = {
28397e7654a9SGreg Kroah-Hartman 	.owner =	  THIS_MODULE,
2840b25472f9SAl Viro 	.llseek =	  no_seek_end_llseek,
28411da177e4SLinus Torvalds 	.read =		  usbdev_read,
28421da177e4SLinus Torvalds 	.poll =		  usbdev_poll,
2843637e8a60SArnd Bergmann 	.unlocked_ioctl = usbdev_ioctl,
2844407e9ef7SArnd Bergmann 	.compat_ioctl =   compat_ptr_ioctl,
2845f7d34b44SSteinar H. Gunderson 	.mmap =           usbdev_mmap,
28461da177e4SLinus Torvalds 	.open =		  usbdev_open,
28471da177e4SLinus Torvalds 	.release =	  usbdev_release,
28481da177e4SLinus Torvalds };
2849fbf82fd2SKay Sievers 
usbdev_remove(struct usb_device * udev)2850501950d8SAlan Stern static void usbdev_remove(struct usb_device *udev)
2851cd9f0375SAlan Stern {
28529b6f0c4bSValentina Manea 	struct usb_dev_state *ps;
2853cd9f0375SAlan Stern 
28547794f486SAlan Stern 	/* Protect against simultaneous resume */
28557794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
2856cd9f0375SAlan Stern 	while (!list_empty(&udev->filelist)) {
28579b6f0c4bSValentina Manea 		ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
2858cd9f0375SAlan Stern 		destroy_all_async(ps);
2859cd9f0375SAlan Stern 		wake_up_all(&ps->wait);
28607794f486SAlan Stern 		WRITE_ONCE(ps->not_yet_resumed, 0);
28617794f486SAlan Stern 		wake_up_all(&ps->wait_for_resume);
2862cd9f0375SAlan Stern 		list_del_init(&ps->list);
286370f1b0d3SEric W. Biederman 		if (ps->discsignr)
286470f1b0d3SEric W. Biederman 			kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext,
28656b4f3d01SStephen Smalley 					     ps->disc_pid, ps->cred);
2866cd9f0375SAlan Stern 	}
28677794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
2868cd9f0375SAlan Stern }
2869cd9f0375SAlan Stern 
usbdev_notify(struct notifier_block * self,unsigned long action,void * dev)2870501950d8SAlan Stern static int usbdev_notify(struct notifier_block *self,
28719f8b17e6SKay Sievers 			       unsigned long action, void *dev)
2872a7b986b3SGreg Kroah-Hartman {
2873a7b986b3SGreg Kroah-Hartman 	switch (action) {
2874a7b986b3SGreg Kroah-Hartman 	case USB_DEVICE_ADD:
2875a7b986b3SGreg Kroah-Hartman 		break;
2876a7b986b3SGreg Kroah-Hartman 	case USB_DEVICE_REMOVE:
2877501950d8SAlan Stern 		usbdev_remove(dev);
2878a7b986b3SGreg Kroah-Hartman 		break;
2879a7b986b3SGreg Kroah-Hartman 	}
2880a7b986b3SGreg Kroah-Hartman 	return NOTIFY_OK;
2881a7b986b3SGreg Kroah-Hartman }
2882a7b986b3SGreg Kroah-Hartman 
2883a7b986b3SGreg Kroah-Hartman static struct notifier_block usbdev_nb = {
2884501950d8SAlan Stern 	.notifier_call =	usbdev_notify,
2885a7b986b3SGreg Kroah-Hartman };
2886a7b986b3SGreg Kroah-Hartman 
28877e7654a9SGreg Kroah-Hartman static struct cdev usb_device_cdev;
2888fbf82fd2SKay Sievers 
usb_devio_init(void)28899f8b17e6SKay Sievers int __init usb_devio_init(void)
2890fbf82fd2SKay Sievers {
2891fbf82fd2SKay Sievers 	int retval;
2892fbf82fd2SKay Sievers 
2893fad21bdfSAlan Stern 	retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
2894fad21bdfSAlan Stern 					"usb_device");
2895fbf82fd2SKay Sievers 	if (retval) {
289669a85942SGreg Kroah-Hartman 		printk(KERN_ERR "Unable to register minors for usb_device\n");
2897fbf82fd2SKay Sievers 		goto out;
2898fbf82fd2SKay Sievers 	}
28999f8b17e6SKay Sievers 	cdev_init(&usb_device_cdev, &usbdev_file_operations);
2900fad21bdfSAlan Stern 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
2901fbf82fd2SKay Sievers 	if (retval) {
290269a85942SGreg Kroah-Hartman 		printk(KERN_ERR "Unable to get usb_device major %d\n",
290369a85942SGreg Kroah-Hartman 		       USB_DEVICE_MAJOR);
2904a7b986b3SGreg Kroah-Hartman 		goto error_cdev;
2905fbf82fd2SKay Sievers 	}
2906501950d8SAlan Stern 	usb_register_notify(&usbdev_nb);
2907fbf82fd2SKay Sievers out:
2908fbf82fd2SKay Sievers 	return retval;
2909a7b986b3SGreg Kroah-Hartman 
2910a7b986b3SGreg Kroah-Hartman error_cdev:
2911a7b986b3SGreg Kroah-Hartman 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
2912a7b986b3SGreg Kroah-Hartman 	goto out;
2913fbf82fd2SKay Sievers }
2914fbf82fd2SKay Sievers 
usb_devio_cleanup(void)29159f8b17e6SKay Sievers void usb_devio_cleanup(void)
2916fbf82fd2SKay Sievers {
2917a7b986b3SGreg Kroah-Hartman 	usb_unregister_notify(&usbdev_nb);
2918fbf82fd2SKay Sievers 	cdev_del(&usb_device_cdev);
2919fad21bdfSAlan Stern 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
2920fbf82fd2SKay Sievers }
2921