xref: /linux-6.15/drivers/usb/core/devio.c (revision fa518772)
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 ([email protected])
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 
2413ea36dc8SJann Horn 	if (!(file->f_mode & FMODE_WRITE))
2423ea36dc8SJann Horn 		return -EPERM;
2433ea36dc8SJann Horn 
244f7d34b44SSteinar H. Gunderson 	ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
245f7d34b44SSteinar H. Gunderson 	if (ret)
246f7d34b44SSteinar H. Gunderson 		goto error;
247f7d34b44SSteinar H. Gunderson 
248f7d34b44SSteinar H. Gunderson 	usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
249f7d34b44SSteinar H. Gunderson 	if (!usbm) {
250f7d34b44SSteinar H. Gunderson 		ret = -ENOMEM;
251f7d34b44SSteinar H. Gunderson 		goto error_decrease_mem;
252f7d34b44SSteinar H. Gunderson 	}
253f7d34b44SSteinar H. Gunderson 
2540143d148SRuihan Li 	mem = hcd_buffer_alloc_pages(hcd,
2550143d148SRuihan Li 			size, GFP_USER | __GFP_NOWARN, &dma_handle);
256f7d34b44SSteinar H. Gunderson 	if (!mem) {
257f7d34b44SSteinar H. Gunderson 		ret = -ENOMEM;
258f7d34b44SSteinar H. Gunderson 		goto error_free_usbm;
259f7d34b44SSteinar H. Gunderson 	}
260f7d34b44SSteinar H. Gunderson 
261f7d34b44SSteinar H. Gunderson 	memset(mem, 0, size);
262f7d34b44SSteinar H. Gunderson 
263f7d34b44SSteinar H. Gunderson 	usbm->mem = mem;
264f7d34b44SSteinar H. Gunderson 	usbm->dma_handle = dma_handle;
265f7d34b44SSteinar H. Gunderson 	usbm->size = size;
266f7d34b44SSteinar H. Gunderson 	usbm->ps = ps;
267f7d34b44SSteinar H. Gunderson 	usbm->vm_start = vma->vm_start;
268f7d34b44SSteinar H. Gunderson 	usbm->vma_use_count = 1;
269f7d34b44SSteinar H. Gunderson 	INIT_LIST_HEAD(&usbm->memlist);
270f7d34b44SSteinar H. Gunderson 
271d0b86165SRuihan Li 	/*
272d0b86165SRuihan Li 	 * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates
273d0b86165SRuihan Li 	 * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check
274d0b86165SRuihan Li 	 * whether we are in such cases, and then use remap_pfn_range (or
275d0b86165SRuihan Li 	 * dma_mmap_coherent) to map normal (or DMA) pages into the user
276d0b86165SRuihan Li 	 * space, respectively.
277d0b86165SRuihan Li 	 */
278d0b86165SRuihan Li 	if (dma_handle == DMA_MAPPING_ERROR) {
279a0e710a7SGreg Kroah-Hartman 		if (remap_pfn_range(vma, vma->vm_start,
280a0e710a7SGreg Kroah-Hartman 				    virt_to_phys(usbm->mem) >> PAGE_SHIFT,
281a0e710a7SGreg Kroah-Hartman 				    size, vma->vm_page_prot) < 0) {
282f7d34b44SSteinar H. Gunderson 			dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
283f7d34b44SSteinar H. Gunderson 			return -EAGAIN;
284f7d34b44SSteinar H. Gunderson 		}
285a0e710a7SGreg Kroah-Hartman 	} else {
286a0e710a7SGreg Kroah-Hartman 		if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle,
287a0e710a7SGreg Kroah-Hartman 				      size)) {
288a0e710a7SGreg Kroah-Hartman 			dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
289a0e710a7SGreg Kroah-Hartman 			return -EAGAIN;
290a0e710a7SGreg Kroah-Hartman 		}
291a0e710a7SGreg Kroah-Hartman 	}
292f7d34b44SSteinar H. Gunderson 
2931c71222eSSuren Baghdasaryan 	vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
294f7d34b44SSteinar H. Gunderson 	vma->vm_ops = &usbdev_vm_ops;
295f7d34b44SSteinar H. Gunderson 	vma->vm_private_data = usbm;
296f7d34b44SSteinar H. Gunderson 
297f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&ps->lock, flags);
298f7d34b44SSteinar H. Gunderson 	list_add_tail(&usbm->memlist, &ps->memory_list);
299f7d34b44SSteinar H. Gunderson 	spin_unlock_irqrestore(&ps->lock, flags);
300f7d34b44SSteinar H. Gunderson 
301f7d34b44SSteinar H. Gunderson 	return 0;
302f7d34b44SSteinar H. Gunderson 
303f7d34b44SSteinar H. Gunderson error_free_usbm:
304f7d34b44SSteinar H. Gunderson 	kfree(usbm);
305f7d34b44SSteinar H. Gunderson error_decrease_mem:
306f7d34b44SSteinar H. Gunderson 	usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
307f7d34b44SSteinar H. Gunderson error:
308f7d34b44SSteinar H. Gunderson 	return ret;
309f7d34b44SSteinar H. Gunderson }
310f7d34b44SSteinar H. Gunderson 
usbdev_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)31104e482ffSGreg Kroah-Hartman static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
31204e482ffSGreg Kroah-Hartman 			   loff_t *ppos)
3131da177e4SLinus Torvalds {
3149b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
3151da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
3161da177e4SLinus Torvalds 	ssize_t ret = 0;
3171da177e4SLinus Torvalds 	unsigned len;
3181da177e4SLinus Torvalds 	loff_t pos;
3191da177e4SLinus Torvalds 	int i;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	pos = *ppos;
3221da177e4SLinus Torvalds 	usb_lock_device(dev);
323349710c3SAlan Stern 	if (!connected(ps)) {
3241da177e4SLinus Torvalds 		ret = -ENODEV;
3251da177e4SLinus Torvalds 		goto err;
3261da177e4SLinus Torvalds 	} else if (pos < 0) {
3271da177e4SLinus Torvalds 		ret = -EINVAL;
3281da177e4SLinus Torvalds 		goto err;
3291da177e4SLinus Torvalds 	}
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	if (pos < sizeof(struct usb_device_descriptor)) {
33204e482ffSGreg Kroah-Hartman 		/* 18 bytes - fits on the stack */
33304e482ffSGreg Kroah-Hartman 		struct usb_device_descriptor temp_desc;
3348781ba0aSOliver Neukum 
3358781ba0aSOliver Neukum 		memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
3369fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.bcdUSB);
3379fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.idVendor);
3389fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.idProduct);
3399fcd5c32SAndrew Morton 		le16_to_cpus(&temp_desc.bcdDevice);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 		len = sizeof(struct usb_device_descriptor) - pos;
3421da177e4SLinus Torvalds 		if (len > nbytes)
3431da177e4SLinus Torvalds 			len = nbytes;
3448781ba0aSOliver Neukum 		if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
3451da177e4SLinus Torvalds 			ret = -EFAULT;
3461da177e4SLinus Torvalds 			goto err;
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 		*ppos += len;
3501da177e4SLinus Torvalds 		buf += len;
3511da177e4SLinus Torvalds 		nbytes -= len;
3521da177e4SLinus Torvalds 		ret += len;
3531da177e4SLinus Torvalds 	}
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	pos = sizeof(struct usb_device_descriptor);
3561da177e4SLinus Torvalds 	for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
3571da177e4SLinus Torvalds 		struct usb_config_descriptor *config =
3581da177e4SLinus Torvalds 			(struct usb_config_descriptor *)dev->rawdescriptors[i];
3591da177e4SLinus Torvalds 		unsigned int length = le16_to_cpu(config->wTotalLength);
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 		if (*ppos < pos + length) {
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 			/* The descriptor may claim to be longer than it
3641da177e4SLinus Torvalds 			 * really is.  Here is the actual allocated length. */
3651da177e4SLinus Torvalds 			unsigned alloclen =
3661da177e4SLinus Torvalds 				le16_to_cpu(dev->config[i].desc.wTotalLength);
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds 			len = length - (*ppos - pos);
3691da177e4SLinus Torvalds 			if (len > nbytes)
3701da177e4SLinus Torvalds 				len = nbytes;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 			/* Simply don't write (skip over) unallocated parts */
3731da177e4SLinus Torvalds 			if (alloclen > (*ppos - pos)) {
3741da177e4SLinus Torvalds 				alloclen -= (*ppos - pos);
3751da177e4SLinus Torvalds 				if (copy_to_user(buf,
3761da177e4SLinus Torvalds 				    dev->rawdescriptors[i] + (*ppos - pos),
3771da177e4SLinus Torvalds 				    min(len, alloclen))) {
3781da177e4SLinus Torvalds 					ret = -EFAULT;
3791da177e4SLinus Torvalds 					goto err;
3801da177e4SLinus Torvalds 				}
3811da177e4SLinus Torvalds 			}
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 			*ppos += len;
3841da177e4SLinus Torvalds 			buf += len;
3851da177e4SLinus Torvalds 			nbytes -= len;
3861da177e4SLinus Torvalds 			ret += len;
3871da177e4SLinus Torvalds 		}
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 		pos += length;
3901da177e4SLinus Torvalds 	}
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds err:
3931da177e4SLinus Torvalds 	usb_unlock_device(dev);
3941da177e4SLinus Torvalds 	return ret;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds /*
3981da177e4SLinus Torvalds  * async list handling
3991da177e4SLinus Torvalds  */
4001da177e4SLinus Torvalds 
alloc_async(unsigned int numisoframes)4011da177e4SLinus Torvalds static struct async *alloc_async(unsigned int numisoframes)
4021da177e4SLinus Torvalds {
403dd95b814SPete Zaitcev 	struct async *as;
4040a1ef3b5SAlan Stern 
405dd95b814SPete Zaitcev 	as = kzalloc(sizeof(struct async), GFP_KERNEL);
4061da177e4SLinus Torvalds 	if (!as)
4071da177e4SLinus Torvalds 		return NULL;
4081da177e4SLinus Torvalds 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
4091da177e4SLinus Torvalds 	if (!as->urb) {
4101da177e4SLinus Torvalds 		kfree(as);
4111da177e4SLinus Torvalds 		return NULL;
4121da177e4SLinus Torvalds 	}
4131da177e4SLinus Torvalds 	return as;
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds 
free_async(struct async * as)4161da177e4SLinus Torvalds static void free_async(struct async *as)
4171da177e4SLinus Torvalds {
4183d97ff63SHans de Goede 	int i;
4193d97ff63SHans de Goede 
4202425c08bSEric W. Biederman 	put_pid(as->pid);
4211b41c832SSarah Sharp 	if (as->cred)
422d178bc3aSSerge Hallyn 		put_cred(as->cred);
4233d97ff63SHans de Goede 	for (i = 0; i < as->urb->num_sgs; i++) {
4243d97ff63SHans de Goede 		if (sg_page(&as->urb->sg[i]))
4253d97ff63SHans de Goede 			kfree(sg_virt(&as->urb->sg[i]));
4263d97ff63SHans de Goede 	}
427f7d34b44SSteinar H. Gunderson 
4283d97ff63SHans de Goede 	kfree(as->urb->sg);
429f7d34b44SSteinar H. Gunderson 	if (as->usbm == NULL)
4301da177e4SLinus Torvalds 		kfree(as->urb->transfer_buffer);
431f7d34b44SSteinar H. Gunderson 	else
432f7d34b44SSteinar H. Gunderson 		dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
433f7d34b44SSteinar H. Gunderson 
4341da177e4SLinus Torvalds 	kfree(as->urb->setup_packet);
4351da177e4SLinus Torvalds 	usb_free_urb(as->urb);
436add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(as->mem_usage);
4371da177e4SLinus Torvalds 	kfree(as);
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds 
async_newpending(struct async * as)440d34d9721SAlan Stern static void async_newpending(struct async *as)
4411da177e4SLinus Torvalds {
4429b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
4431da177e4SLinus Torvalds 	unsigned long flags;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4461da177e4SLinus Torvalds 	list_add_tail(&as->asynclist, &ps->async_pending);
4471da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
async_removepending(struct async * as)450d34d9721SAlan Stern static void async_removepending(struct async *as)
4511da177e4SLinus Torvalds {
4529b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
4531da177e4SLinus Torvalds 	unsigned long flags;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4561da177e4SLinus Torvalds 	list_del_init(&as->asynclist);
4571da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds 
async_getcompleted(struct usb_dev_state * ps)4609b6f0c4bSValentina Manea static struct async *async_getcompleted(struct usb_dev_state *ps)
4611da177e4SLinus Torvalds {
4621da177e4SLinus Torvalds 	unsigned long flags;
4631da177e4SLinus Torvalds 	struct async *as = NULL;
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
4661da177e4SLinus Torvalds 	if (!list_empty(&ps->async_completed)) {
46704e482ffSGreg Kroah-Hartman 		as = list_entry(ps->async_completed.next, struct async,
46804e482ffSGreg Kroah-Hartman 				asynclist);
4691da177e4SLinus Torvalds 		list_del_init(&as->asynclist);
4701da177e4SLinus Torvalds 	}
4711da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
4721da177e4SLinus Torvalds 	return as;
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds 
async_getpending(struct usb_dev_state * ps,void __user * userurb)4759b6f0c4bSValentina Manea static struct async *async_getpending(struct usb_dev_state *ps,
47604e482ffSGreg Kroah-Hartman 					     void __user *userurb)
4771da177e4SLinus Torvalds {
4781da177e4SLinus Torvalds 	struct async *as;
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	list_for_each_entry(as, &ps->async_pending, asynclist)
4811da177e4SLinus Torvalds 		if (as->userurb == userurb) {
4821da177e4SLinus Torvalds 			list_del_init(&as->asynclist);
4831da177e4SLinus Torvalds 			return as;
4841da177e4SLinus Torvalds 		}
4854e09dcf2SHuajun Li 
4861da177e4SLinus Torvalds 	return NULL;
4871da177e4SLinus Torvalds }
4881da177e4SLinus 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)4894c6e8971SAlan Stern static void snoop_urb(struct usb_device *udev,
4904c6e8971SAlan Stern 		void __user *userurb, int pipe, unsigned length,
4910880aef4SChris Frey 		int timeout_or_status, enum snoop_when when,
4920880aef4SChris Frey 		unsigned char *data, unsigned data_len)
493e639dd3fSGreg Kroah-Hartman {
4944c6e8971SAlan Stern 	static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
4954c6e8971SAlan Stern 	static const char *dirs[] = {"out", "in"};
4964c6e8971SAlan Stern 	int ep;
4974c6e8971SAlan Stern 	const char *t, *d;
498e639dd3fSGreg Kroah-Hartman 
499e639dd3fSGreg Kroah-Hartman 	if (!usbfs_snoop)
500e639dd3fSGreg Kroah-Hartman 		return;
501e639dd3fSGreg Kroah-Hartman 
5024c6e8971SAlan Stern 	ep = usb_pipeendpoint(pipe);
5034c6e8971SAlan Stern 	t = types[usb_pipetype(pipe)];
5044c6e8971SAlan Stern 	d = dirs[!!usb_pipein(pipe)];
5054c6e8971SAlan Stern 
5064c6e8971SAlan Stern 	if (userurb) {		/* Async */
5074c6e8971SAlan Stern 		if (when == SUBMIT)
508f3bc432aSAlan Stern 			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
5094c6e8971SAlan Stern 					"length %u\n",
5104c6e8971SAlan Stern 					userurb, ep, t, d, length);
5114c6e8971SAlan Stern 		else
512f3bc432aSAlan Stern 			dev_info(&udev->dev, "userurb %px, ep%d %s-%s, "
5134c6e8971SAlan Stern 					"actual_length %u status %d\n",
5144c6e8971SAlan Stern 					userurb, ep, t, d, length,
5154c6e8971SAlan Stern 					timeout_or_status);
5164c6e8971SAlan Stern 	} else {
5174c6e8971SAlan Stern 		if (when == SUBMIT)
5184c6e8971SAlan Stern 			dev_info(&udev->dev, "ep%d %s-%s, length %u, "
5194c6e8971SAlan Stern 					"timeout %d\n",
5204c6e8971SAlan Stern 					ep, t, d, length, timeout_or_status);
5214c6e8971SAlan Stern 		else
5224c6e8971SAlan Stern 			dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
5234c6e8971SAlan Stern 					"status %d\n",
5244c6e8971SAlan Stern 					ep, t, d, length, timeout_or_status);
5254c6e8971SAlan Stern 	}
5260880aef4SChris Frey 
5270290cc9fSAlan Stern 	data_len = min(data_len, usbfs_snoop_max);
5280880aef4SChris Frey 	if (data && data_len > 0) {
5290880aef4SChris Frey 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5300880aef4SChris Frey 			data, data_len, 1);
5310880aef4SChris Frey 	}
532e639dd3fSGreg Kroah-Hartman }
533e639dd3fSGreg Kroah-Hartman 
snoop_urb_data(struct urb * urb,unsigned len)5343d97ff63SHans de Goede static void snoop_urb_data(struct urb *urb, unsigned len)
5353d97ff63SHans de Goede {
5363d97ff63SHans de Goede 	int i, size;
5373d97ff63SHans de Goede 
5380290cc9fSAlan Stern 	len = min(len, usbfs_snoop_max);
5390290cc9fSAlan Stern 	if (!usbfs_snoop || len == 0)
5403d97ff63SHans de Goede 		return;
5413d97ff63SHans de Goede 
5423d97ff63SHans de Goede 	if (urb->num_sgs == 0) {
5433d97ff63SHans de Goede 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5443d97ff63SHans de Goede 			urb->transfer_buffer, len, 1);
5453d97ff63SHans de Goede 		return;
5463d97ff63SHans de Goede 	}
5473d97ff63SHans de Goede 
5483d97ff63SHans de Goede 	for (i = 0; i < urb->num_sgs && len; i++) {
5493d97ff63SHans de Goede 		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
5503d97ff63SHans de Goede 		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
5513d97ff63SHans de Goede 			sg_virt(&urb->sg[i]), size, 1);
5523d97ff63SHans de Goede 		len -= size;
5533d97ff63SHans de Goede 	}
5543d97ff63SHans de Goede }
5553d97ff63SHans de Goede 
copy_urb_data_to_user(u8 __user * userbuffer,struct urb * urb)5563d97ff63SHans de Goede static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
5573d97ff63SHans de Goede {
5583d97ff63SHans de Goede 	unsigned i, len, size;
5593d97ff63SHans de Goede 
5603d97ff63SHans de Goede 	if (urb->number_of_packets > 0)		/* Isochronous */
5613d97ff63SHans de Goede 		len = urb->transfer_buffer_length;
5623d97ff63SHans de Goede 	else					/* Non-Isoc */
5633d97ff63SHans de Goede 		len = urb->actual_length;
5643d97ff63SHans de Goede 
5653d97ff63SHans de Goede 	if (urb->num_sgs == 0) {
5663d97ff63SHans de Goede 		if (copy_to_user(userbuffer, urb->transfer_buffer, len))
5673d97ff63SHans de Goede 			return -EFAULT;
5683d97ff63SHans de Goede 		return 0;
5693d97ff63SHans de Goede 	}
5703d97ff63SHans de Goede 
5713d97ff63SHans de Goede 	for (i = 0; i < urb->num_sgs && len; i++) {
5723d97ff63SHans de Goede 		size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
5733d97ff63SHans de Goede 		if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
5743d97ff63SHans de Goede 			return -EFAULT;
5753d97ff63SHans de Goede 		userbuffer += size;
5763d97ff63SHans de Goede 		len -= size;
5773d97ff63SHans de Goede 	}
5783d97ff63SHans de Goede 
5793d97ff63SHans de Goede 	return 0;
5803d97ff63SHans de Goede }
5813d97ff63SHans de Goede 
58201c6460fSAlan Stern #define AS_CONTINUATION	1
58301c6460fSAlan Stern #define AS_UNLINK	2
58401c6460fSAlan Stern 
cancel_bulk_urbs(struct usb_dev_state * ps,unsigned bulk_addr)5859b6f0c4bSValentina Manea static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)
58601c6460fSAlan Stern __releases(ps->lock)
58701c6460fSAlan Stern __acquires(ps->lock)
58801c6460fSAlan Stern {
5894e09dcf2SHuajun Li 	struct urb *urb;
59001c6460fSAlan Stern 	struct async *as;
59101c6460fSAlan Stern 
59201c6460fSAlan Stern 	/* Mark all the pending URBs that match bulk_addr, up to but not
59301c6460fSAlan Stern 	 * including the first one without AS_CONTINUATION.  If such an
59401c6460fSAlan Stern 	 * URB is encountered then a new transfer has already started so
59501c6460fSAlan Stern 	 * the endpoint doesn't need to be disabled; otherwise it does.
59601c6460fSAlan Stern 	 */
59701c6460fSAlan Stern 	list_for_each_entry(as, &ps->async_pending, asynclist) {
59801c6460fSAlan Stern 		if (as->bulk_addr == bulk_addr) {
59901c6460fSAlan Stern 			if (as->bulk_status != AS_CONTINUATION)
60001c6460fSAlan Stern 				goto rescan;
60101c6460fSAlan Stern 			as->bulk_status = AS_UNLINK;
60201c6460fSAlan Stern 			as->bulk_addr = 0;
60301c6460fSAlan Stern 		}
60401c6460fSAlan Stern 	}
60501c6460fSAlan Stern 	ps->disabled_bulk_eps |= (1 << bulk_addr);
60601c6460fSAlan Stern 
60701c6460fSAlan Stern 	/* Now carefully unlink all the marked pending URBs */
60801c6460fSAlan Stern  rescan:
609fdd64df7SAlan Stern 	list_for_each_entry_reverse(as, &ps->async_pending, asynclist) {
61001c6460fSAlan Stern 		if (as->bulk_status == AS_UNLINK) {
61101c6460fSAlan Stern 			as->bulk_status = 0;		/* Only once */
6124e09dcf2SHuajun Li 			urb = as->urb;
6134e09dcf2SHuajun Li 			usb_get_urb(urb);
61401c6460fSAlan Stern 			spin_unlock(&ps->lock);		/* Allow completions */
6154e09dcf2SHuajun Li 			usb_unlink_urb(urb);
6164e09dcf2SHuajun Li 			usb_put_urb(urb);
61701c6460fSAlan Stern 			spin_lock(&ps->lock);
61801c6460fSAlan Stern 			goto rescan;
61901c6460fSAlan Stern 		}
62001c6460fSAlan Stern 	}
62101c6460fSAlan Stern }
62201c6460fSAlan Stern 
async_completed(struct urb * urb)6237d12e780SDavid Howells static void async_completed(struct urb *urb)
6241da177e4SLinus Torvalds {
625ec17cf1cSTobias Klauser 	struct async *as = urb->context;
6269b6f0c4bSValentina Manea 	struct usb_dev_state *ps = as->ps;
627516a1a07SOliver Neukum 	struct pid *pid = NULL;
628d178bc3aSSerge Hallyn 	const struct cred *cred = NULL;
6293f38daceSSebastian Andrzej Siewior 	unsigned long flags;
63070f1b0d3SEric W. Biederman 	sigval_t addr;
63170f1b0d3SEric W. Biederman 	int signr, errno;
6321da177e4SLinus Torvalds 
6333f38daceSSebastian Andrzej Siewior 	spin_lock_irqsave(&ps->lock, flags);
6341da177e4SLinus Torvalds 	list_move_tail(&as->asynclist, &ps->async_completed);
635e015268dSAlan Stern 	as->status = urb->status;
636516a1a07SOliver Neukum 	signr = as->signr;
637516a1a07SOliver Neukum 	if (signr) {
63870f1b0d3SEric W. Biederman 		errno = as->status;
63970f1b0d3SEric W. Biederman 		addr = as->userurb_sigval;
640aec01c58SSerge Hallyn 		pid = get_pid(as->pid);
641d178bc3aSSerge Hallyn 		cred = get_cred(as->cred);
6421da177e4SLinus Torvalds 	}
643e639dd3fSGreg Kroah-Hartman 	snoop(&urb->dev->dev, "urb complete\n");
6444c6e8971SAlan Stern 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
6453d97ff63SHans de Goede 			as->status, COMPLETE, NULL, 0);
64679595a73SKeyur Patel 	if (usb_urb_dir_in(urb))
6473d97ff63SHans de Goede 		snoop_urb_data(urb, urb->actual_length);
6483d97ff63SHans de Goede 
64901c6460fSAlan Stern 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
65001c6460fSAlan Stern 			as->status != -ENOENT)
65101c6460fSAlan Stern 		cancel_bulk_urbs(ps, as->bulk_addr);
652ed62ca2fSDouglas Anderson 
653ed62ca2fSDouglas Anderson 	wake_up(&ps->wait);
6543f38daceSSebastian Andrzej Siewior 	spin_unlock_irqrestore(&ps->lock, flags);
655516a1a07SOliver Neukum 
656aec01c58SSerge Hallyn 	if (signr) {
65770f1b0d3SEric W. Biederman 		kill_pid_usb_asyncio(signr, errno, addr, pid, cred);
658aec01c58SSerge Hallyn 		put_pid(pid);
659d178bc3aSSerge Hallyn 		put_cred(cred);
660aec01c58SSerge Hallyn 	}
6611da177e4SLinus Torvalds }
6621da177e4SLinus Torvalds 
destroy_async(struct usb_dev_state * ps,struct list_head * list)6639b6f0c4bSValentina Manea static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
6641da177e4SLinus Torvalds {
6654e09dcf2SHuajun Li 	struct urb *urb;
6661da177e4SLinus Torvalds 	struct async *as;
6671da177e4SLinus Torvalds 	unsigned long flags;
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
6701da177e4SLinus Torvalds 	while (!list_empty(list)) {
671fdd64df7SAlan Stern 		as = list_last_entry(list, struct async, asynclist);
6721da177e4SLinus Torvalds 		list_del_init(&as->asynclist);
6734e09dcf2SHuajun Li 		urb = as->urb;
6744e09dcf2SHuajun Li 		usb_get_urb(urb);
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 		/* drop the spinlock so the completion handler can run */
6771da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ps->lock, flags);
6784e09dcf2SHuajun Li 		usb_kill_urb(urb);
6794e09dcf2SHuajun Li 		usb_put_urb(urb);
6801da177e4SLinus Torvalds 		spin_lock_irqsave(&ps->lock, flags);
6811da177e4SLinus Torvalds 	}
6821da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds 
destroy_async_on_interface(struct usb_dev_state * ps,unsigned int ifnum)6859b6f0c4bSValentina Manea static void destroy_async_on_interface(struct usb_dev_state *ps,
68604e482ffSGreg Kroah-Hartman 				       unsigned int ifnum)
6871da177e4SLinus Torvalds {
6881da177e4SLinus Torvalds 	struct list_head *p, *q, hitlist;
6891da177e4SLinus Torvalds 	unsigned long flags;
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	INIT_LIST_HEAD(&hitlist);
6921da177e4SLinus Torvalds 	spin_lock_irqsave(&ps->lock, flags);
6931da177e4SLinus Torvalds 	list_for_each_safe(p, q, &ps->async_pending)
6941da177e4SLinus Torvalds 		if (ifnum == list_entry(p, struct async, asynclist)->ifnum)
6951da177e4SLinus Torvalds 			list_move_tail(p, &hitlist);
6961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ps->lock, flags);
6971da177e4SLinus Torvalds 	destroy_async(ps, &hitlist);
6981da177e4SLinus Torvalds }
6991da177e4SLinus Torvalds 
destroy_all_async(struct usb_dev_state * ps)7009b6f0c4bSValentina Manea static void destroy_all_async(struct usb_dev_state *ps)
7011da177e4SLinus Torvalds {
7021da177e4SLinus Torvalds 	destroy_async(ps, &ps->async_pending);
7031da177e4SLinus Torvalds }
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds /*
7061da177e4SLinus Torvalds  * interface claims are made only at the request of user level code,
7071da177e4SLinus Torvalds  * which can also release them (explicitly or by closing files).
7081da177e4SLinus Torvalds  * they're also undone when devices disconnect.
7091da177e4SLinus Torvalds  */
7101da177e4SLinus Torvalds 
driver_probe(struct usb_interface * intf,const struct usb_device_id * id)7111da177e4SLinus Torvalds static int driver_probe(struct usb_interface *intf,
7121da177e4SLinus Torvalds 			const struct usb_device_id *id)
7131da177e4SLinus Torvalds {
7141da177e4SLinus Torvalds 	return -ENODEV;
7151da177e4SLinus Torvalds }
7161da177e4SLinus Torvalds 
driver_disconnect(struct usb_interface * intf)7171da177e4SLinus Torvalds static void driver_disconnect(struct usb_interface *intf)
7181da177e4SLinus Torvalds {
7199b6f0c4bSValentina Manea 	struct usb_dev_state *ps = usb_get_intfdata(intf);
7201da177e4SLinus Torvalds 	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	if (!ps)
7231da177e4SLinus Torvalds 		return;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	/* NOTE:  this relies on usbcore having canceled and completed
7261da177e4SLinus Torvalds 	 * all pending I/O requests; 2.6 does that.
7271da177e4SLinus Torvalds 	 */
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds 	if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
7301da177e4SLinus Torvalds 		clear_bit(ifnum, &ps->ifclaimed);
7311da177e4SLinus Torvalds 	else
7323b6004f3SGreg Kroah-Hartman 		dev_warn(&intf->dev, "interface number %u out of range\n",
7333b6004f3SGreg Kroah-Hartman 			 ifnum);
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 	usb_set_intfdata(intf, NULL);
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 	/* force async requests to complete */
7381da177e4SLinus Torvalds 	destroy_async_on_interface(ps, ifnum);
7391da177e4SLinus Torvalds }
7401da177e4SLinus Torvalds 
7417794f486SAlan Stern /* We don't care about suspend/resume of claimed interfaces */
driver_suspend(struct usb_interface * intf,pm_message_t msg)7422e2eb83fSAlan Stern static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
7432e2eb83fSAlan Stern {
7442e2eb83fSAlan Stern 	return 0;
7452e2eb83fSAlan Stern }
7462e2eb83fSAlan Stern 
driver_resume(struct usb_interface * intf)7472e2eb83fSAlan Stern static int driver_resume(struct usb_interface *intf)
7482e2eb83fSAlan Stern {
7492e2eb83fSAlan Stern 	return 0;
7502e2eb83fSAlan Stern }
7512e2eb83fSAlan Stern 
7528e6bd945SArnd Bergmann #ifdef CONFIG_PM
7537794f486SAlan Stern /* The following routines apply to the entire device, not interfaces */
usbfs_notify_suspend(struct usb_device * udev)7547794f486SAlan Stern void usbfs_notify_suspend(struct usb_device *udev)
7557794f486SAlan Stern {
7567794f486SAlan Stern 	/* We don't need to handle this */
7577794f486SAlan Stern }
7587794f486SAlan Stern 
usbfs_notify_resume(struct usb_device * udev)7597794f486SAlan Stern void usbfs_notify_resume(struct usb_device *udev)
7607794f486SAlan Stern {
7617794f486SAlan Stern 	struct usb_dev_state *ps;
7627794f486SAlan Stern 
7637794f486SAlan Stern 	/* Protect against simultaneous remove or release */
7647794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
7657794f486SAlan Stern 	list_for_each_entry(ps, &udev->filelist, list) {
7667794f486SAlan Stern 		WRITE_ONCE(ps->not_yet_resumed, 0);
7677794f486SAlan Stern 		wake_up_all(&ps->wait_for_resume);
7687794f486SAlan Stern 	}
7697794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
7707794f486SAlan Stern }
7718e6bd945SArnd Bergmann #endif
7727794f486SAlan Stern 
7731da177e4SLinus Torvalds struct usb_driver usbfs_driver = {
7741da177e4SLinus Torvalds 	.name =		"usbfs",
7751da177e4SLinus Torvalds 	.probe =	driver_probe,
7761da177e4SLinus Torvalds 	.disconnect =	driver_disconnect,
7772e2eb83fSAlan Stern 	.suspend =	driver_suspend,
7782e2eb83fSAlan Stern 	.resume =	driver_resume,
7797794f486SAlan Stern 	.supports_autosuspend = 1,
7801da177e4SLinus Torvalds };
7811da177e4SLinus Torvalds 
claimintf(struct usb_dev_state * ps,unsigned int ifnum)7829b6f0c4bSValentina Manea static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
7831da177e4SLinus Torvalds {
7841da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
7851da177e4SLinus Torvalds 	struct usb_interface *intf;
7861da177e4SLinus Torvalds 	int err;
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
7891da177e4SLinus Torvalds 		return -EINVAL;
7901da177e4SLinus Torvalds 	/* already claimed */
7911da177e4SLinus Torvalds 	if (test_bit(ifnum, &ps->ifclaimed))
7921da177e4SLinus Torvalds 		return 0;
7931da177e4SLinus Torvalds 
794d883f52eSReilly Grant 	if (ps->privileges_dropped &&
795d883f52eSReilly Grant 			!test_bit(ifnum, &ps->interface_allowed_mask))
796d883f52eSReilly Grant 		return -EACCES;
797d883f52eSReilly Grant 
7981da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(dev, ifnum);
7991da177e4SLinus Torvalds 	if (!intf)
8001da177e4SLinus Torvalds 		err = -ENOENT;
801abb0b3d9SIngo Rohloff 	else {
802abb0b3d9SIngo Rohloff 		unsigned int old_suppress;
803abb0b3d9SIngo Rohloff 
804abb0b3d9SIngo Rohloff 		/* suppress uevents while claiming interface */
805abb0b3d9SIngo Rohloff 		old_suppress = dev_get_uevent_suppress(&intf->dev);
806abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, 1);
8071da177e4SLinus Torvalds 		err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
808abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, old_suppress);
809abb0b3d9SIngo Rohloff 	}
8101da177e4SLinus Torvalds 	if (err == 0)
8111da177e4SLinus Torvalds 		set_bit(ifnum, &ps->ifclaimed);
8121da177e4SLinus Torvalds 	return err;
8131da177e4SLinus Torvalds }
8141da177e4SLinus Torvalds 
releaseintf(struct usb_dev_state * ps,unsigned int ifnum)8159b6f0c4bSValentina Manea static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds 	struct usb_device *dev;
8181da177e4SLinus Torvalds 	struct usb_interface *intf;
8191da177e4SLinus Torvalds 	int err;
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	err = -EINVAL;
8221da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
8231da177e4SLinus Torvalds 		return err;
8241da177e4SLinus Torvalds 	dev = ps->dev;
8251da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(dev, ifnum);
8261da177e4SLinus Torvalds 	if (!intf)
8271da177e4SLinus Torvalds 		err = -ENOENT;
8281da177e4SLinus Torvalds 	else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
829abb0b3d9SIngo Rohloff 		unsigned int old_suppress;
830abb0b3d9SIngo Rohloff 
831abb0b3d9SIngo Rohloff 		/* suppress uevents while releasing interface */
832abb0b3d9SIngo Rohloff 		old_suppress = dev_get_uevent_suppress(&intf->dev);
833abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, 1);
8341da177e4SLinus Torvalds 		usb_driver_release_interface(&usbfs_driver, intf);
835abb0b3d9SIngo Rohloff 		dev_set_uevent_suppress(&intf->dev, old_suppress);
8361da177e4SLinus Torvalds 		err = 0;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 	return err;
8391da177e4SLinus Torvalds }
8401da177e4SLinus Torvalds 
checkintf(struct usb_dev_state * ps,unsigned int ifnum)8419b6f0c4bSValentina Manea static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)
8421da177e4SLinus Torvalds {
8431da177e4SLinus Torvalds 	if (ps->dev->state != USB_STATE_CONFIGURED)
8441da177e4SLinus Torvalds 		return -EHOSTUNREACH;
8451da177e4SLinus Torvalds 	if (ifnum >= 8*sizeof(ps->ifclaimed))
8461da177e4SLinus Torvalds 		return -EINVAL;
8471da177e4SLinus Torvalds 	if (test_bit(ifnum, &ps->ifclaimed))
8481da177e4SLinus Torvalds 		return 0;
8491da177e4SLinus Torvalds 	/* if not yet claimed, claim it for the driver */
85004e482ffSGreg Kroah-Hartman 	dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
85104e482ffSGreg Kroah-Hartman 		 "interface %u before use\n", task_pid_nr(current),
85204e482ffSGreg Kroah-Hartman 		 current->comm, ifnum);
8531da177e4SLinus Torvalds 	return claimintf(ps, ifnum);
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds 
findintfep(struct usb_device * dev,unsigned int ep)8561da177e4SLinus Torvalds static int findintfep(struct usb_device *dev, unsigned int ep)
8571da177e4SLinus Torvalds {
8581da177e4SLinus Torvalds 	unsigned int i, j, e;
8591da177e4SLinus Torvalds 	struct usb_interface *intf;
8601da177e4SLinus Torvalds 	struct usb_host_interface *alts;
8611da177e4SLinus Torvalds 	struct usb_endpoint_descriptor *endpt;
8621da177e4SLinus Torvalds 
8631da177e4SLinus Torvalds 	if (ep & ~(USB_DIR_IN|0xf))
8641da177e4SLinus Torvalds 		return -EINVAL;
8651da177e4SLinus Torvalds 	if (!dev->actconfig)
8661da177e4SLinus Torvalds 		return -ESRCH;
8671da177e4SLinus Torvalds 	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
8681da177e4SLinus Torvalds 		intf = dev->actconfig->interface[i];
8691da177e4SLinus Torvalds 		for (j = 0; j < intf->num_altsetting; j++) {
8701da177e4SLinus Torvalds 			alts = &intf->altsetting[j];
8711da177e4SLinus Torvalds 			for (e = 0; e < alts->desc.bNumEndpoints; e++) {
8721da177e4SLinus Torvalds 				endpt = &alts->endpoint[e].desc;
8731da177e4SLinus Torvalds 				if (endpt->bEndpointAddress == ep)
8741da177e4SLinus Torvalds 					return alts->desc.bInterfaceNumber;
8751da177e4SLinus Torvalds 			}
8761da177e4SLinus Torvalds 		}
8771da177e4SLinus Torvalds 	}
8781da177e4SLinus Torvalds 	return -ENOENT;
8791da177e4SLinus Torvalds }
8801da177e4SLinus Torvalds 
check_ctrlrecip(struct usb_dev_state * ps,unsigned int requesttype,unsigned int request,unsigned int index)8819b6f0c4bSValentina Manea static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,
882393cbb51SMatthias Dellweg 			   unsigned int request, unsigned int index)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds 	int ret = 0;
885393cbb51SMatthias Dellweg 	struct usb_host_interface *alt_setting;
8861da177e4SLinus Torvalds 
8876da9c990SDavid Vrabel 	if (ps->dev->state != USB_STATE_UNAUTHENTICATED
8886da9c990SDavid Vrabel 	 && ps->dev->state != USB_STATE_ADDRESS
88924f8b116SHorst Schirmeier 	 && ps->dev->state != USB_STATE_CONFIGURED)
8901da177e4SLinus Torvalds 		return -EHOSTUNREACH;
8911da177e4SLinus Torvalds 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
8921da177e4SLinus Torvalds 		return 0;
8931da177e4SLinus Torvalds 
894393cbb51SMatthias Dellweg 	/*
895393cbb51SMatthias Dellweg 	 * check for the special corner case 'get_device_id' in the printer
8965dc50c35SHans de Goede 	 * class specification, which we always want to allow as it is used
8975dc50c35SHans de Goede 	 * to query things like ink level, etc.
898393cbb51SMatthias Dellweg 	 */
899393cbb51SMatthias Dellweg 	if (requesttype == 0xa1 && request == 0) {
900393cbb51SMatthias Dellweg 		alt_setting = usb_find_alt_setting(ps->dev->actconfig,
901393cbb51SMatthias Dellweg 						   index >> 8, index & 0xff);
902393cbb51SMatthias Dellweg 		if (alt_setting
903393cbb51SMatthias Dellweg 		 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
9045dc50c35SHans de Goede 			return 0;
905393cbb51SMatthias Dellweg 	}
906393cbb51SMatthias Dellweg 
9071da177e4SLinus Torvalds 	index &= 0xff;
9081da177e4SLinus Torvalds 	switch (requesttype & USB_RECIP_MASK) {
9091da177e4SLinus Torvalds 	case USB_RECIP_ENDPOINT:
9101361bf4bSHans de Goede 		if ((index & ~USB_DIR_IN) == 0)
9111361bf4bSHans de Goede 			return 0;
91204e482ffSGreg Kroah-Hartman 		ret = findintfep(ps->dev, index);
913831abf76SKurt Garloff 		if (ret < 0) {
914831abf76SKurt Garloff 			/*
915831abf76SKurt Garloff 			 * Some not fully compliant Win apps seem to get
916831abf76SKurt Garloff 			 * index wrong and have the endpoint number here
917831abf76SKurt Garloff 			 * rather than the endpoint address (with the
918831abf76SKurt Garloff 			 * correct direction). Win does let this through,
919831abf76SKurt Garloff 			 * so we'll not reject it here but leave it to
920831abf76SKurt Garloff 			 * the device to not break KVM. But we warn.
921831abf76SKurt Garloff 			 */
922831abf76SKurt Garloff 			ret = findintfep(ps->dev, index ^ 0x80);
923831abf76SKurt Garloff 			if (ret >= 0)
924831abf76SKurt Garloff 				dev_info(&ps->dev->dev,
925831abf76SKurt Garloff 					"%s: process %i (%s) requesting ep %02x but needs %02x\n",
926831abf76SKurt Garloff 					__func__, task_pid_nr(current),
927831abf76SKurt Garloff 					current->comm, index, index ^ 0x80);
928831abf76SKurt Garloff 		}
92904e482ffSGreg Kroah-Hartman 		if (ret >= 0)
9301da177e4SLinus Torvalds 			ret = checkintf(ps, ret);
9311da177e4SLinus Torvalds 		break;
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	case USB_RECIP_INTERFACE:
9341da177e4SLinus Torvalds 		ret = checkintf(ps, index);
9351da177e4SLinus Torvalds 		break;
9361da177e4SLinus Torvalds 	}
9371da177e4SLinus Torvalds 	return ret;
9381da177e4SLinus Torvalds }
9391da177e4SLinus Torvalds 
ep_to_host_endpoint(struct usb_device * dev,unsigned char ep)9402fec32b0SHans de Goede static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
9412fec32b0SHans de Goede 						     unsigned char ep)
9422fec32b0SHans de Goede {
9432fec32b0SHans de Goede 	if (ep & USB_ENDPOINT_DIR_MASK)
9442fec32b0SHans de Goede 		return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK];
9452fec32b0SHans de Goede 	else
9462fec32b0SHans de Goede 		return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
9472fec32b0SHans de Goede }
9482fec32b0SHans 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)9493e75c6deSLinus Torvalds static int parse_usbdevfs_streams(struct usb_dev_state *ps,
950bcf7f6e3SHans de Goede 				  struct usbdevfs_streams __user *streams,
951bcf7f6e3SHans de Goede 				  unsigned int *num_streams_ret,
952bcf7f6e3SHans de Goede 				  unsigned int *num_eps_ret,
953bcf7f6e3SHans de Goede 				  struct usb_host_endpoint ***eps_ret,
954bcf7f6e3SHans de Goede 				  struct usb_interface **intf_ret)
955bcf7f6e3SHans de Goede {
956bcf7f6e3SHans de Goede 	unsigned int i, num_streams, num_eps;
957bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
958bcf7f6e3SHans de Goede 	struct usb_interface *intf = NULL;
959bcf7f6e3SHans de Goede 	unsigned char ep;
960bcf7f6e3SHans de Goede 	int ifnum, ret;
961bcf7f6e3SHans de Goede 
962bcf7f6e3SHans de Goede 	if (get_user(num_streams, &streams->num_streams) ||
963bcf7f6e3SHans de Goede 	    get_user(num_eps, &streams->num_eps))
964bcf7f6e3SHans de Goede 		return -EFAULT;
965bcf7f6e3SHans de Goede 
966bcf7f6e3SHans de Goede 	if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
967bcf7f6e3SHans de Goede 		return -EINVAL;
968bcf7f6e3SHans de Goede 
969bcf7f6e3SHans de Goede 	/* The XHCI controller allows max 2 ^ 16 streams */
970bcf7f6e3SHans de Goede 	if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
971bcf7f6e3SHans de Goede 		return -EINVAL;
972bcf7f6e3SHans de Goede 
9736da2ec56SKees Cook 	eps = kmalloc_array(num_eps, sizeof(*eps), GFP_KERNEL);
974bcf7f6e3SHans de Goede 	if (!eps)
975bcf7f6e3SHans de Goede 		return -ENOMEM;
976bcf7f6e3SHans de Goede 
977bcf7f6e3SHans de Goede 	for (i = 0; i < num_eps; i++) {
978bcf7f6e3SHans de Goede 		if (get_user(ep, &streams->eps[i])) {
979bcf7f6e3SHans de Goede 			ret = -EFAULT;
980bcf7f6e3SHans de Goede 			goto error;
981bcf7f6e3SHans de Goede 		}
982bcf7f6e3SHans de Goede 		eps[i] = ep_to_host_endpoint(ps->dev, ep);
983bcf7f6e3SHans de Goede 		if (!eps[i]) {
984bcf7f6e3SHans de Goede 			ret = -EINVAL;
985bcf7f6e3SHans de Goede 			goto error;
986bcf7f6e3SHans de Goede 		}
987bcf7f6e3SHans de Goede 
988bcf7f6e3SHans de Goede 		/* usb_alloc/free_streams operate on an usb_interface */
989bcf7f6e3SHans de Goede 		ifnum = findintfep(ps->dev, ep);
990bcf7f6e3SHans de Goede 		if (ifnum < 0) {
991bcf7f6e3SHans de Goede 			ret = ifnum;
992bcf7f6e3SHans de Goede 			goto error;
993bcf7f6e3SHans de Goede 		}
994bcf7f6e3SHans de Goede 
995bcf7f6e3SHans de Goede 		if (i == 0) {
996bcf7f6e3SHans de Goede 			ret = checkintf(ps, ifnum);
997bcf7f6e3SHans de Goede 			if (ret < 0)
998bcf7f6e3SHans de Goede 				goto error;
999bcf7f6e3SHans de Goede 			intf = usb_ifnum_to_if(ps->dev, ifnum);
1000bcf7f6e3SHans de Goede 		} else {
1001bcf7f6e3SHans de Goede 			/* Verify all eps belong to the same interface */
1002bcf7f6e3SHans de Goede 			if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
1003bcf7f6e3SHans de Goede 				ret = -EINVAL;
1004bcf7f6e3SHans de Goede 				goto error;
1005bcf7f6e3SHans de Goede 			}
1006bcf7f6e3SHans de Goede 		}
1007bcf7f6e3SHans de Goede 	}
1008bcf7f6e3SHans de Goede 
1009bcf7f6e3SHans de Goede 	if (num_streams_ret)
1010bcf7f6e3SHans de Goede 		*num_streams_ret = num_streams;
1011bcf7f6e3SHans de Goede 	*num_eps_ret = num_eps;
1012bcf7f6e3SHans de Goede 	*eps_ret = eps;
1013bcf7f6e3SHans de Goede 	*intf_ret = intf;
1014bcf7f6e3SHans de Goede 
1015bcf7f6e3SHans de Goede 	return 0;
1016bcf7f6e3SHans de Goede 
1017bcf7f6e3SHans de Goede error:
1018bcf7f6e3SHans de Goede 	kfree(eps);
1019bcf7f6e3SHans de Goede 	return ret;
1020bcf7f6e3SHans de Goede }
1021bcf7f6e3SHans de Goede 
usbdev_lookup_by_devt(dev_t devt)102261ad04a8SAlan Stern static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
10239f8b17e6SKay Sievers {
10249f8b17e6SKay Sievers 	struct device *dev;
10259f8b17e6SKay Sievers 
10264495dfddSSuzuki K Poulose 	dev = bus_find_device_by_devt(&usb_bus_type, devt);
10279f8b17e6SKay Sievers 	if (!dev)
10289f8b17e6SKay Sievers 		return NULL;
102969ab55d7SGeliang Tang 	return to_usb_device(dev);
10309f8b17e6SKay Sievers }
10314592bf5aSGreg Kroah-Hartman 
10321da177e4SLinus Torvalds /*
10331da177e4SLinus Torvalds  * file operations
10341da177e4SLinus Torvalds  */
usbdev_open(struct inode * inode,struct file * file)10351da177e4SLinus Torvalds static int usbdev_open(struct inode *inode, struct file *file)
10361da177e4SLinus Torvalds {
1037fbf82fd2SKay Sievers 	struct usb_device *dev = NULL;
10389b6f0c4bSValentina Manea 	struct usb_dev_state *ps;
10391da177e4SLinus Torvalds 	int ret;
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	ret = -ENOMEM;
1042d883f52eSReilly Grant 	ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
104304e482ffSGreg Kroah-Hartman 	if (!ps)
104462e299e6SAlan Stern 		goto out_free_ps;
10451da177e4SLinus Torvalds 
104601105a24SAlan Stern 	ret = -ENODEV;
104761ad04a8SAlan Stern 
10489f8b17e6SKay Sievers 	/* usbdev device-node */
1049fbf82fd2SKay Sievers 	if (imajor(inode) == USB_DEVICE_MAJOR)
105061ad04a8SAlan Stern 		dev = usbdev_lookup_by_devt(inode->i_rdev);
105162e299e6SAlan Stern 	if (!dev)
105262e299e6SAlan Stern 		goto out_free_ps;
105362e299e6SAlan Stern 
105462e299e6SAlan Stern 	usb_lock_device(dev);
105562e299e6SAlan Stern 	if (dev->state == USB_STATE_NOTATTACHED)
105662e299e6SAlan Stern 		goto out_unlock_device;
105762e299e6SAlan Stern 
105894fcda1fSAlan Stern 	ret = usb_autoresume_device(dev);
105901d883d4SAlan Stern 	if (ret)
106062e299e6SAlan Stern 		goto out_unlock_device;
106101d883d4SAlan Stern 
10621da177e4SLinus Torvalds 	ps->dev = dev;
10631da177e4SLinus Torvalds 	ps->file = file;
1064d883f52eSReilly Grant 	ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
10651da177e4SLinus Torvalds 	spin_lock_init(&ps->lock);
1066316547fdSDan Carpenter 	INIT_LIST_HEAD(&ps->list);
10671da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ps->async_pending);
10681da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ps->async_completed);
1069f7d34b44SSteinar H. Gunderson 	INIT_LIST_HEAD(&ps->memory_list);
10701da177e4SLinus Torvalds 	init_waitqueue_head(&ps->wait);
10717794f486SAlan Stern 	init_waitqueue_head(&ps->wait_for_resume);
10722425c08bSEric W. Biederman 	ps->disc_pid = get_pid(task_pid(current));
1073d178bc3aSSerge Hallyn 	ps->cred = get_current_cred();
1074527660a8SOliver Neukum 	smp_wmb();
10757794f486SAlan Stern 
10767794f486SAlan Stern 	/* Can't race with resume; the device is already active */
10771da177e4SLinus Torvalds 	list_add_tail(&ps->list, &dev->filelist);
10781da177e4SLinus Torvalds 	file->private_data = ps;
107962e299e6SAlan Stern 	usb_unlock_device(dev);
10802da41d5fSAlan Stern 	snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
10812da41d5fSAlan Stern 			current->comm);
108262e299e6SAlan Stern 	return ret;
108362e299e6SAlan Stern 
108462e299e6SAlan Stern  out_unlock_device:
108562e299e6SAlan Stern 	usb_unlock_device(dev);
1086d64aac36SAlan Stern 	usb_put_dev(dev);
108762e299e6SAlan Stern  out_free_ps:
108862e299e6SAlan Stern 	kfree(ps);
10891da177e4SLinus Torvalds 	return ret;
10901da177e4SLinus Torvalds }
10911da177e4SLinus Torvalds 
usbdev_release(struct inode * inode,struct file * file)10921da177e4SLinus Torvalds static int usbdev_release(struct inode *inode, struct file *file)
10931da177e4SLinus Torvalds {
10949b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
10951da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
10961da177e4SLinus Torvalds 	unsigned int ifnum;
10976ff10464SAlan Stern 	struct async *as;
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	usb_lock_device(dev);
11007cbe5dcaSAlan Stern 	usb_hub_release_all_ports(dev, ps);
11014a2a8a2cSAlan Stern 
11027794f486SAlan Stern 	/* Protect against simultaneous resume */
11037794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
11041da177e4SLinus Torvalds 	list_del_init(&ps->list);
11057794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
11064a2a8a2cSAlan Stern 
11071da177e4SLinus Torvalds 	for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
11081da177e4SLinus Torvalds 			ifnum++) {
11091da177e4SLinus Torvalds 		if (test_bit(ifnum, &ps->ifclaimed))
11101da177e4SLinus Torvalds 			releaseintf(ps, ifnum);
11111da177e4SLinus Torvalds 	}
11121da177e4SLinus Torvalds 	destroy_all_async(ps);
11137794f486SAlan Stern 	if (!ps->suspend_allowed)
111494fcda1fSAlan Stern 		usb_autosuspend_device(dev);
11151da177e4SLinus Torvalds 	usb_unlock_device(dev);
11161da177e4SLinus Torvalds 	usb_put_dev(dev);
11172425c08bSEric W. Biederman 	put_pid(ps->disc_pid);
1118d178bc3aSSerge Hallyn 	put_cred(ps->cred);
11196ff10464SAlan Stern 
11206ff10464SAlan Stern 	as = async_getcompleted(ps);
11216ff10464SAlan Stern 	while (as) {
11226ff10464SAlan Stern 		free_async(as);
11236ff10464SAlan Stern 		as = async_getcompleted(ps);
11246ff10464SAlan Stern 	}
1125f7d34b44SSteinar H. Gunderson 
11261da177e4SLinus Torvalds 	kfree(ps);
11271da177e4SLinus Torvalds 	return 0;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds 
usbfs_blocking_completion(struct urb * urb)1130ae8709b2SAlan Stern static void usbfs_blocking_completion(struct urb *urb)
1131ae8709b2SAlan Stern {
1132ae8709b2SAlan Stern 	complete((struct completion *) urb->context);
1133ae8709b2SAlan Stern }
1134ae8709b2SAlan Stern 
1135ae8709b2SAlan Stern /*
1136ae8709b2SAlan Stern  * Much like usb_start_wait_urb, but returns status separately from
1137ae8709b2SAlan Stern  * actual_length and uses a killable wait.
1138ae8709b2SAlan Stern  */
usbfs_start_wait_urb(struct urb * urb,int timeout,unsigned int * actlen)1139ae8709b2SAlan Stern static int usbfs_start_wait_urb(struct urb *urb, int timeout,
1140ae8709b2SAlan Stern 		unsigned int *actlen)
1141ae8709b2SAlan Stern {
1142ae8709b2SAlan Stern 	DECLARE_COMPLETION_ONSTACK(ctx);
1143ae8709b2SAlan Stern 	unsigned long expire;
1144ae8709b2SAlan Stern 	int rc;
1145ae8709b2SAlan Stern 
1146ae8709b2SAlan Stern 	urb->context = &ctx;
1147ae8709b2SAlan Stern 	urb->complete = usbfs_blocking_completion;
1148ae8709b2SAlan Stern 	*actlen = 0;
1149ae8709b2SAlan Stern 	rc = usb_submit_urb(urb, GFP_KERNEL);
1150ae8709b2SAlan Stern 	if (unlikely(rc))
1151ae8709b2SAlan Stern 		return rc;
1152ae8709b2SAlan Stern 
1153ae8709b2SAlan Stern 	expire = (timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT);
1154ae8709b2SAlan Stern 	rc = wait_for_completion_killable_timeout(&ctx, expire);
1155ae8709b2SAlan Stern 	if (rc <= 0) {
1156ae8709b2SAlan Stern 		usb_kill_urb(urb);
1157ae8709b2SAlan Stern 		*actlen = urb->actual_length;
1158ae8709b2SAlan Stern 		if (urb->status != -ENOENT)
1159ae8709b2SAlan Stern 			;	/* Completed before it was killed */
1160ae8709b2SAlan Stern 		else if (rc < 0)
1161ae8709b2SAlan Stern 			return -EINTR;
1162ae8709b2SAlan Stern 		else
1163ae8709b2SAlan Stern 			return -ETIMEDOUT;
1164ae8709b2SAlan Stern 	}
1165ae8709b2SAlan Stern 	*actlen = urb->actual_length;
1166ae8709b2SAlan Stern 	return urb->status;
1167ae8709b2SAlan Stern }
1168ae8709b2SAlan Stern 
do_proc_control(struct usb_dev_state * ps,struct usbdevfs_ctrltransfer * ctrl)1169c17536d0SChristoph Hellwig static int do_proc_control(struct usb_dev_state *ps,
1170c17536d0SChristoph Hellwig 		struct usbdevfs_ctrltransfer *ctrl)
11711da177e4SLinus Torvalds {
11721da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
11731da177e4SLinus Torvalds 	unsigned int tmo;
11741da177e4SLinus Torvalds 	unsigned char *tbuf;
1175ae8709b2SAlan Stern 	unsigned int wLength, actlen;
11764c6e8971SAlan Stern 	int i, pipe, ret;
1177ae8709b2SAlan Stern 	struct urb *urb = NULL;
1178ae8709b2SAlan Stern 	struct usb_ctrlrequest *dr = NULL;
11791da177e4SLinus Torvalds 
1180c17536d0SChristoph Hellwig 	ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest,
1181c17536d0SChristoph Hellwig 			      ctrl->wIndex);
118204e482ffSGreg Kroah-Hartman 	if (ret)
11831da177e4SLinus Torvalds 		return ret;
1184c17536d0SChristoph Hellwig 	wLength = ctrl->wLength;	/* To suppress 64k PAGE_SIZE warning */
1185ff66e3ceSAndrew Morton 	if (wLength > PAGE_SIZE)
11861da177e4SLinus Torvalds 		return -EINVAL;
1187add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
1188add1aaeaSAlan Stern 			sizeof(struct usb_ctrlrequest));
1189add1aaeaSAlan Stern 	if (ret)
1190add1aaeaSAlan Stern 		return ret;
1191ae8709b2SAlan Stern 
1192add1aaeaSAlan Stern 	ret = -ENOMEM;
1193ae8709b2SAlan Stern 	tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
1194ae8709b2SAlan Stern 	if (!tbuf)
1195add1aaeaSAlan Stern 		goto done;
1196ae8709b2SAlan Stern 	urb = usb_alloc_urb(0, GFP_NOIO);
1197ae8709b2SAlan Stern 	if (!urb)
1198ae8709b2SAlan Stern 		goto done;
1199ae8709b2SAlan Stern 	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
1200ae8709b2SAlan Stern 	if (!dr)
1201ae8709b2SAlan Stern 		goto done;
1202ae8709b2SAlan Stern 
1203ae8709b2SAlan Stern 	dr->bRequestType = ctrl->bRequestType;
1204ae8709b2SAlan Stern 	dr->bRequest = ctrl->bRequest;
1205ae8709b2SAlan Stern 	dr->wValue = cpu_to_le16(ctrl->wValue);
1206ae8709b2SAlan Stern 	dr->wIndex = cpu_to_le16(ctrl->wIndex);
1207ae8709b2SAlan Stern 	dr->wLength = cpu_to_le16(ctrl->wLength);
1208ae8709b2SAlan Stern 
1209c17536d0SChristoph Hellwig 	tmo = ctrl->timeout;
12100880aef4SChris Frey 	snoop(&dev->dev, "control urb: bRequestType=%02x "
12110880aef4SChris Frey 		"bRequest=%02x wValue=%04x "
12120880aef4SChris Frey 		"wIndex=%04x wLength=%04x\n",
1213c17536d0SChristoph Hellwig 		ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
1214c17536d0SChristoph Hellwig 		ctrl->wIndex, ctrl->wLength);
1215ae8709b2SAlan Stern 
1216ae8709b2SAlan Stern 	if ((ctrl->bRequestType & USB_DIR_IN) && wLength) {
12174c6e8971SAlan Stern 		pipe = usb_rcvctrlpipe(dev, 0);
1218ae8709b2SAlan Stern 		usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
1219ae8709b2SAlan Stern 				wLength, NULL, NULL);
1220ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, NULL, 0);
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds 		usb_unlock_device(dev);
1223ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &actlen);
12240543e4e8STasos Sahanidis 
12250543e4e8STasos Sahanidis 		/* Linger a bit, prior to the next control message. */
12260543e4e8STasos Sahanidis 		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
12270543e4e8STasos Sahanidis 			msleep(200);
12281da177e4SLinus Torvalds 		usb_lock_device(dev);
1229ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, tbuf, actlen);
1230ae8709b2SAlan Stern 		if (!i && actlen) {
1231ae8709b2SAlan Stern 			if (copy_to_user(ctrl->data, tbuf, actlen)) {
123252fb743dSAlan Stern 				ret = -EFAULT;
12330543e4e8STasos Sahanidis 				goto done;
12341da177e4SLinus Torvalds 			}
12351da177e4SLinus Torvalds 		}
12361da177e4SLinus Torvalds 	} else {
1237ae8709b2SAlan Stern 		if (wLength) {
1238ae8709b2SAlan Stern 			if (copy_from_user(tbuf, ctrl->data, wLength)) {
123952fb743dSAlan Stern 				ret = -EFAULT;
124052fb743dSAlan Stern 				goto done;
12411da177e4SLinus Torvalds 			}
12421da177e4SLinus Torvalds 		}
12434c6e8971SAlan Stern 		pipe = usb_sndctrlpipe(dev, 0);
1244ae8709b2SAlan Stern 		usb_fill_control_urb(urb, dev, pipe, (unsigned char *) dr, tbuf,
1245ae8709b2SAlan Stern 				wLength, NULL, NULL);
1246ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, wLength, tmo, SUBMIT, tbuf, wLength);
12474c6e8971SAlan Stern 
12481da177e4SLinus Torvalds 		usb_unlock_device(dev);
1249ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &actlen);
12500543e4e8STasos Sahanidis 
12510543e4e8STasos Sahanidis 		/* Linger a bit, prior to the next control message. */
12520543e4e8STasos Sahanidis 		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
12530543e4e8STasos Sahanidis 			msleep(200);
12541da177e4SLinus Torvalds 		usb_lock_device(dev);
1255ae8709b2SAlan Stern 		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, NULL, 0);
12561da177e4SLinus Torvalds 	}
12571da177e4SLinus Torvalds 	if (i < 0 && i != -EPIPE) {
12581da177e4SLinus Torvalds 		dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
12591da177e4SLinus Torvalds 			   "failed cmd %s rqt %u rq %u len %u ret %d\n",
1260c17536d0SChristoph Hellwig 			   current->comm, ctrl->bRequestType, ctrl->bRequest,
1261c17536d0SChristoph Hellwig 			   ctrl->wLength, i);
12621da177e4SLinus Torvalds 	}
1263ae8709b2SAlan Stern 	ret = (i < 0 ? i : actlen);
1264ae8709b2SAlan Stern 
126552fb743dSAlan Stern  done:
1266ae8709b2SAlan Stern 	kfree(dr);
1267ae8709b2SAlan Stern 	usb_free_urb(urb);
126852fb743dSAlan Stern 	free_page((unsigned long) tbuf);
1269add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
1270add1aaeaSAlan Stern 			sizeof(struct usb_ctrlrequest));
127152fb743dSAlan Stern 	return ret;
12721da177e4SLinus Torvalds }
12731da177e4SLinus Torvalds 
proc_control(struct usb_dev_state * ps,void __user * arg)1274c17536d0SChristoph Hellwig static int proc_control(struct usb_dev_state *ps, void __user *arg)
1275c17536d0SChristoph Hellwig {
1276c17536d0SChristoph Hellwig 	struct usbdevfs_ctrltransfer ctrl;
1277c17536d0SChristoph Hellwig 
1278c17536d0SChristoph Hellwig 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
1279c17536d0SChristoph Hellwig 		return -EFAULT;
1280c17536d0SChristoph Hellwig 	return do_proc_control(ps, &ctrl);
1281c17536d0SChristoph Hellwig }
1282c17536d0SChristoph Hellwig 
do_proc_bulk(struct usb_dev_state * ps,struct usbdevfs_bulktransfer * bulk)1283c17536d0SChristoph Hellwig static int do_proc_bulk(struct usb_dev_state *ps,
1284c17536d0SChristoph Hellwig 		struct usbdevfs_bulktransfer *bulk)
12851da177e4SLinus Torvalds {
12861da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
1287ae8709b2SAlan Stern 	unsigned int tmo, len1, len2, pipe;
12881da177e4SLinus Torvalds 	unsigned char *tbuf;
12894c6e8971SAlan Stern 	int i, ret;
1290ae8709b2SAlan Stern 	struct urb *urb = NULL;
1291ae8709b2SAlan Stern 	struct usb_host_endpoint *ep;
12921da177e4SLinus Torvalds 
1293c17536d0SChristoph Hellwig 	ret = findintfep(ps->dev, bulk->ep);
129404e482ffSGreg Kroah-Hartman 	if (ret < 0)
12951da177e4SLinus Torvalds 		return ret;
129604e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
129704e482ffSGreg Kroah-Hartman 	if (ret)
12981da177e4SLinus Torvalds 		return ret;
1299ae8709b2SAlan Stern 
1300ae8709b2SAlan Stern 	len1 = bulk->len;
1301*fa518772SRex Nie 	if (len1 >= (INT_MAX - sizeof(struct urb)))
1302ae8709b2SAlan Stern 		return -EINVAL;
1303ae8709b2SAlan Stern 
1304c17536d0SChristoph Hellwig 	if (bulk->ep & USB_DIR_IN)
1305c17536d0SChristoph Hellwig 		pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f);
13061da177e4SLinus Torvalds 	else
1307c17536d0SChristoph Hellwig 		pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f);
1308ae8709b2SAlan Stern 	ep = usb_pipe_endpoint(dev, pipe);
1309ae8709b2SAlan Stern 	if (!ep || !usb_endpoint_maxp(&ep->desc))
13101da177e4SLinus Torvalds 		return -EINVAL;
1311add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
1312add1aaeaSAlan Stern 	if (ret)
1313add1aaeaSAlan Stern 		return ret;
13144f2629eaSAlan Stern 
13154f2629eaSAlan Stern 	/*
13164f2629eaSAlan Stern 	 * len1 can be almost arbitrarily large.  Don't WARN if it's
13174f2629eaSAlan Stern 	 * too big, just fail the request.
13184f2629eaSAlan Stern 	 */
1319add1aaeaSAlan Stern 	ret = -ENOMEM;
1320ae8709b2SAlan Stern 	tbuf = kmalloc(len1, GFP_KERNEL | __GFP_NOWARN);
1321ae8709b2SAlan Stern 	if (!tbuf)
1322add1aaeaSAlan Stern 		goto done;
1323ae8709b2SAlan Stern 	urb = usb_alloc_urb(0, GFP_KERNEL);
1324ae8709b2SAlan Stern 	if (!urb)
1325ae8709b2SAlan Stern 		goto done;
1326ae8709b2SAlan Stern 
1327ae8709b2SAlan Stern 	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
1328ae8709b2SAlan Stern 			USB_ENDPOINT_XFER_INT) {
1329ae8709b2SAlan Stern 		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
1330ae8709b2SAlan Stern 		usb_fill_int_urb(urb, dev, pipe, tbuf, len1,
1331ae8709b2SAlan Stern 				NULL, NULL, ep->desc.bInterval);
1332ae8709b2SAlan Stern 	} else {
1333ae8709b2SAlan Stern 		usb_fill_bulk_urb(urb, dev, pipe, tbuf, len1, NULL, NULL);
1334add1aaeaSAlan Stern 	}
1335ae8709b2SAlan Stern 
1336c17536d0SChristoph Hellwig 	tmo = bulk->timeout;
1337c17536d0SChristoph Hellwig 	if (bulk->ep & 0x80) {
13380880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
13394c6e8971SAlan Stern 
13401da177e4SLinus Torvalds 		usb_unlock_device(dev);
1341ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &len2);
13421da177e4SLinus Torvalds 		usb_lock_device(dev);
13430880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
13444c6e8971SAlan Stern 
13451da177e4SLinus Torvalds 		if (!i && len2) {
1346c17536d0SChristoph Hellwig 			if (copy_to_user(bulk->data, tbuf, len2)) {
134752fb743dSAlan Stern 				ret = -EFAULT;
134852fb743dSAlan Stern 				goto done;
13491da177e4SLinus Torvalds 			}
13501da177e4SLinus Torvalds 		}
13511da177e4SLinus Torvalds 	} else {
13521da177e4SLinus Torvalds 		if (len1) {
1353c17536d0SChristoph Hellwig 			if (copy_from_user(tbuf, bulk->data, len1)) {
135452fb743dSAlan Stern 				ret = -EFAULT;
135552fb743dSAlan Stern 				goto done;
13561da177e4SLinus Torvalds 			}
13571da177e4SLinus Torvalds 		}
13580880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
13594c6e8971SAlan Stern 
13601da177e4SLinus Torvalds 		usb_unlock_device(dev);
1361ae8709b2SAlan Stern 		i = usbfs_start_wait_urb(urb, tmo, &len2);
13621da177e4SLinus Torvalds 		usb_lock_device(dev);
13630880aef4SChris Frey 		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
13641da177e4SLinus Torvalds 	}
136552fb743dSAlan Stern 	ret = (i < 0 ? i : len2);
136652fb743dSAlan Stern  done:
1367ae8709b2SAlan Stern 	usb_free_urb(urb);
13681da177e4SLinus Torvalds 	kfree(tbuf);
1369add1aaeaSAlan Stern 	usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
137052fb743dSAlan Stern 	return ret;
13711da177e4SLinus Torvalds }
13721da177e4SLinus Torvalds 
proc_bulk(struct usb_dev_state * ps,void __user * arg)1373c17536d0SChristoph Hellwig static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
1374c17536d0SChristoph Hellwig {
1375c17536d0SChristoph Hellwig 	struct usbdevfs_bulktransfer bulk;
1376c17536d0SChristoph Hellwig 
1377c17536d0SChristoph Hellwig 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
1378c17536d0SChristoph Hellwig 		return -EFAULT;
1379c17536d0SChristoph Hellwig 	return do_proc_bulk(ps, &bulk);
1380c17536d0SChristoph Hellwig }
1381c17536d0SChristoph Hellwig 
check_reset_of_active_ep(struct usb_device * udev,unsigned int epnum,char * ioctl_name)1382f080a51bSAlan Stern static void check_reset_of_active_ep(struct usb_device *udev,
1383f080a51bSAlan Stern 		unsigned int epnum, char *ioctl_name)
1384f080a51bSAlan Stern {
1385f080a51bSAlan Stern 	struct usb_host_endpoint **eps;
1386f080a51bSAlan Stern 	struct usb_host_endpoint *ep;
1387f080a51bSAlan Stern 
1388f080a51bSAlan Stern 	eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out;
1389f080a51bSAlan Stern 	ep = eps[epnum & 0x0f];
1390f080a51bSAlan Stern 	if (ep && !list_empty(&ep->urb_list))
1391f080a51bSAlan Stern 		dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n",
1392f080a51bSAlan Stern 				task_pid_nr(current), current->comm,
1393f080a51bSAlan Stern 				ioctl_name, epnum);
1394f080a51bSAlan Stern }
1395f080a51bSAlan Stern 
proc_resetep(struct usb_dev_state * ps,void __user * arg)13969b6f0c4bSValentina Manea static int proc_resetep(struct usb_dev_state *ps, void __user *arg)
13971da177e4SLinus Torvalds {
13981da177e4SLinus Torvalds 	unsigned int ep;
13991da177e4SLinus Torvalds 	int ret;
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds 	if (get_user(ep, (unsigned int __user *)arg))
14021da177e4SLinus Torvalds 		return -EFAULT;
140304e482ffSGreg Kroah-Hartman 	ret = findintfep(ps->dev, ep);
140404e482ffSGreg Kroah-Hartman 	if (ret < 0)
14051da177e4SLinus Torvalds 		return ret;
140604e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
140704e482ffSGreg Kroah-Hartman 	if (ret)
14081da177e4SLinus Torvalds 		return ret;
1409f080a51bSAlan Stern 	check_reset_of_active_ep(ps->dev, ep, "RESETEP");
14103444b26aSDavid Vrabel 	usb_reset_endpoint(ps->dev, ep);
14111da177e4SLinus Torvalds 	return 0;
14121da177e4SLinus Torvalds }
14131da177e4SLinus Torvalds 
proc_clearhalt(struct usb_dev_state * ps,void __user * arg)14149b6f0c4bSValentina Manea static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)
14151da177e4SLinus Torvalds {
14161da177e4SLinus Torvalds 	unsigned int ep;
14171da177e4SLinus Torvalds 	int pipe;
14181da177e4SLinus Torvalds 	int ret;
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	if (get_user(ep, (unsigned int __user *)arg))
14211da177e4SLinus Torvalds 		return -EFAULT;
142204e482ffSGreg Kroah-Hartman 	ret = findintfep(ps->dev, ep);
142304e482ffSGreg Kroah-Hartman 	if (ret < 0)
14241da177e4SLinus Torvalds 		return ret;
142504e482ffSGreg Kroah-Hartman 	ret = checkintf(ps, ret);
142604e482ffSGreg Kroah-Hartman 	if (ret)
14271da177e4SLinus Torvalds 		return ret;
1428f080a51bSAlan Stern 	check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");
14291da177e4SLinus Torvalds 	if (ep & USB_DIR_IN)
14301da177e4SLinus Torvalds 		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
14311da177e4SLinus Torvalds 	else
14321da177e4SLinus Torvalds 		pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 	return usb_clear_halt(ps->dev, pipe);
14351da177e4SLinus Torvalds }
14361da177e4SLinus Torvalds 
proc_getdriver(struct usb_dev_state * ps,void __user * arg)14379b6f0c4bSValentina Manea static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
14381da177e4SLinus Torvalds {
14391da177e4SLinus Torvalds 	struct usbdevfs_getdriver gd;
14401da177e4SLinus Torvalds 	struct usb_interface *intf;
14411da177e4SLinus Torvalds 	int ret;
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds 	if (copy_from_user(&gd, arg, sizeof(gd)))
14441da177e4SLinus Torvalds 		return -EFAULT;
14451da177e4SLinus Torvalds 	intf = usb_ifnum_to_if(ps->dev, gd.interface);
14461da177e4SLinus Torvalds 	if (!intf || !intf->dev.driver)
14471da177e4SLinus Torvalds 		ret = -ENODATA;
14481da177e4SLinus Torvalds 	else {
1449b7db5733SWolfram Sang 		strscpy(gd.driver, intf->dev.driver->name,
14501da177e4SLinus Torvalds 				sizeof(gd.driver));
14511da177e4SLinus Torvalds 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
14521da177e4SLinus Torvalds 	}
14531da177e4SLinus Torvalds 	return ret;
14541da177e4SLinus Torvalds }
14551da177e4SLinus Torvalds 
proc_connectinfo(struct usb_dev_state * ps,void __user * arg)14569b6f0c4bSValentina Manea static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
14571da177e4SLinus Torvalds {
1458681fef83SKangjie Lu 	struct usbdevfs_connectinfo ci;
1459681fef83SKangjie Lu 
1460681fef83SKangjie Lu 	memset(&ci, 0, sizeof(ci));
1461681fef83SKangjie Lu 	ci.devnum = ps->dev->devnum;
1462681fef83SKangjie Lu 	ci.slow = ps->dev->speed == USB_SPEED_LOW;
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds 	if (copy_to_user(arg, &ci, sizeof(ci)))
14651da177e4SLinus Torvalds 		return -EFAULT;
14661da177e4SLinus Torvalds 	return 0;
14671da177e4SLinus Torvalds }
14681da177e4SLinus Torvalds 
proc_conninfo_ex(struct usb_dev_state * ps,void __user * arg,size_t size)14696d101f24SDmitry Torokhov static int proc_conninfo_ex(struct usb_dev_state *ps,
14706d101f24SDmitry Torokhov 			    void __user *arg, size_t size)
14716d101f24SDmitry Torokhov {
14726d101f24SDmitry Torokhov 	struct usbdevfs_conninfo_ex ci;
14736d101f24SDmitry Torokhov 	struct usb_device *udev = ps->dev;
14746d101f24SDmitry Torokhov 
14756d101f24SDmitry Torokhov 	if (size < sizeof(ci.size))
14766d101f24SDmitry Torokhov 		return -EINVAL;
14776d101f24SDmitry Torokhov 
14786d101f24SDmitry Torokhov 	memset(&ci, 0, sizeof(ci));
14796d101f24SDmitry Torokhov 	ci.size = sizeof(ci);
14806d101f24SDmitry Torokhov 	ci.busnum = udev->bus->busnum;
14816d101f24SDmitry Torokhov 	ci.devnum = udev->devnum;
14826d101f24SDmitry Torokhov 	ci.speed = udev->speed;
14836d101f24SDmitry Torokhov 
14846d101f24SDmitry Torokhov 	while (udev && udev->portnum != 0) {
14856d101f24SDmitry Torokhov 		if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
14866d101f24SDmitry Torokhov 			ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
14876d101f24SDmitry Torokhov 					udev->portnum;
14886d101f24SDmitry Torokhov 		udev = udev->parent;
14896d101f24SDmitry Torokhov 	}
14906d101f24SDmitry Torokhov 
14916d101f24SDmitry Torokhov 	if (ci.num_ports < ARRAY_SIZE(ci.ports))
14926d101f24SDmitry Torokhov 		memmove(&ci.ports[0],
14936d101f24SDmitry Torokhov 			&ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
14946d101f24SDmitry Torokhov 			ci.num_ports);
14956d101f24SDmitry Torokhov 
14966d101f24SDmitry Torokhov 	if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
14976d101f24SDmitry Torokhov 		return -EFAULT;
14986d101f24SDmitry Torokhov 
14996d101f24SDmitry Torokhov 	return 0;
15006d101f24SDmitry Torokhov }
15016d101f24SDmitry Torokhov 
proc_resetdevice(struct usb_dev_state * ps)15029b6f0c4bSValentina Manea static int proc_resetdevice(struct usb_dev_state *ps)
15031da177e4SLinus Torvalds {
1504d883f52eSReilly Grant 	struct usb_host_config *actconfig = ps->dev->actconfig;
1505d883f52eSReilly Grant 	struct usb_interface *interface;
1506d883f52eSReilly Grant 	int i, number;
1507d883f52eSReilly Grant 
1508d883f52eSReilly Grant 	/* Don't allow a device reset if the process has dropped the
1509d883f52eSReilly Grant 	 * privilege to do such things and any of the interfaces are
1510d883f52eSReilly Grant 	 * currently claimed.
1511d883f52eSReilly Grant 	 */
1512d883f52eSReilly Grant 	if (ps->privileges_dropped && actconfig) {
1513d883f52eSReilly Grant 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
1514d883f52eSReilly Grant 			interface = actconfig->interface[i];
1515d883f52eSReilly Grant 			number = interface->cur_altsetting->desc.bInterfaceNumber;
1516d883f52eSReilly Grant 			if (usb_interface_claimed(interface) &&
1517d883f52eSReilly Grant 					!test_bit(number, &ps->ifclaimed)) {
1518d883f52eSReilly Grant 				dev_warn(&ps->dev->dev,
1519d883f52eSReilly Grant 					"usbfs: interface %d claimed by %s while '%s' resets device\n",
1520d883f52eSReilly Grant 					number,	interface->dev.driver->name, current->comm);
1521d883f52eSReilly Grant 				return -EACCES;
1522d883f52eSReilly Grant 			}
1523d883f52eSReilly Grant 		}
1524d883f52eSReilly Grant 	}
1525d883f52eSReilly Grant 
1526742120c6SMing Lei 	return usb_reset_device(ps->dev);
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
proc_setintf(struct usb_dev_state * ps,void __user * arg)15299b6f0c4bSValentina Manea static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
15301da177e4SLinus Torvalds {
15311da177e4SLinus Torvalds 	struct usbdevfs_setinterface setintf;
15321da177e4SLinus Torvalds 	int ret;
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	if (copy_from_user(&setintf, arg, sizeof(setintf)))
15351da177e4SLinus Torvalds 		return -EFAULT;
1536135551eaSKris Borer 	ret = checkintf(ps, setintf.interface);
1537135551eaSKris Borer 	if (ret)
15381da177e4SLinus Torvalds 		return ret;
15395ec9c177SHans de Goede 
15405ec9c177SHans de Goede 	destroy_async_on_interface(ps, setintf.interface);
15415ec9c177SHans de Goede 
15421da177e4SLinus Torvalds 	return usb_set_interface(ps->dev, setintf.interface,
15431da177e4SLinus Torvalds 			setintf.altsetting);
15441da177e4SLinus Torvalds }
15451da177e4SLinus Torvalds 
proc_setconfig(struct usb_dev_state * ps,void __user * arg)15469b6f0c4bSValentina Manea static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
15471da177e4SLinus Torvalds {
15483f141e2aSAlan Stern 	int u;
15491da177e4SLinus Torvalds 	int status = 0;
15501da177e4SLinus Torvalds 	struct usb_host_config *actconfig;
15511da177e4SLinus Torvalds 
15523f141e2aSAlan Stern 	if (get_user(u, (int __user *)arg))
15531da177e4SLinus Torvalds 		return -EFAULT;
15541da177e4SLinus Torvalds 
15551da177e4SLinus Torvalds 	actconfig = ps->dev->actconfig;
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 	/* Don't touch the device if any interfaces are claimed.
15581da177e4SLinus Torvalds 	 * It could interfere with other drivers' operations, and if
15591da177e4SLinus Torvalds 	 * an interface is claimed by usbfs it could easily deadlock.
15601da177e4SLinus Torvalds 	 */
15611da177e4SLinus Torvalds 	if (actconfig) {
15621da177e4SLinus Torvalds 		int i;
15631da177e4SLinus Torvalds 
15641da177e4SLinus Torvalds 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
15651da177e4SLinus Torvalds 			if (usb_interface_claimed(actconfig->interface[i])) {
15661da177e4SLinus Torvalds 				dev_warn(&ps->dev->dev,
156772ebddb5SDavid Brownell 					"usbfs: interface %d claimed by %s "
15681da177e4SLinus Torvalds 					"while '%s' sets config #%d\n",
15691da177e4SLinus Torvalds 					actconfig->interface[i]
15701da177e4SLinus Torvalds 						->cur_altsetting
15711da177e4SLinus Torvalds 						->desc.bInterfaceNumber,
157272ebddb5SDavid Brownell 					actconfig->interface[i]
157372ebddb5SDavid Brownell 						->dev.driver->name,
15741da177e4SLinus Torvalds 					current->comm, u);
15751da177e4SLinus Torvalds 				status = -EBUSY;
15761da177e4SLinus Torvalds 				break;
15771da177e4SLinus Torvalds 			}
15781da177e4SLinus Torvalds 		}
15791da177e4SLinus Torvalds 	}
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
15821da177e4SLinus Torvalds 	 * so avoid usb_set_configuration()'s kick to sysfs
15831da177e4SLinus Torvalds 	 */
15841da177e4SLinus Torvalds 	if (status == 0) {
15851da177e4SLinus Torvalds 		if (actconfig && actconfig->desc.bConfigurationValue == u)
15861da177e4SLinus Torvalds 			status = usb_reset_configuration(ps->dev);
15871da177e4SLinus Torvalds 		else
15881da177e4SLinus Torvalds 			status = usb_set_configuration(ps->dev, u);
15891da177e4SLinus Torvalds 	}
15901da177e4SLinus Torvalds 
15911da177e4SLinus Torvalds 	return status;
15921da177e4SLinus Torvalds }
15931da177e4SLinus Torvalds 
1594f7d34b44SSteinar H. Gunderson static struct usb_memory *
find_memory_area(struct usb_dev_state * ps,const struct usbdevfs_urb * uurb)1595f7d34b44SSteinar H. Gunderson find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
1596f7d34b44SSteinar H. Gunderson {
1597f7d34b44SSteinar H. Gunderson 	struct usb_memory *usbm = NULL, *iter;
1598f7d34b44SSteinar H. Gunderson 	unsigned long flags;
1599f7d34b44SSteinar H. Gunderson 	unsigned long uurb_start = (unsigned long)uurb->buffer;
1600f7d34b44SSteinar H. Gunderson 
1601f7d34b44SSteinar H. Gunderson 	spin_lock_irqsave(&ps->lock, flags);
1602f7d34b44SSteinar H. Gunderson 	list_for_each_entry(iter, &ps->memory_list, memlist) {
1603f7d34b44SSteinar H. Gunderson 		if (uurb_start >= iter->vm_start &&
1604f7d34b44SSteinar H. Gunderson 				uurb_start < iter->vm_start + iter->size) {
1605f7d34b44SSteinar H. Gunderson 			if (uurb->buffer_length > iter->vm_start + iter->size -
1606f7d34b44SSteinar H. Gunderson 					uurb_start) {
1607f7d34b44SSteinar H. Gunderson 				usbm = ERR_PTR(-EINVAL);
1608f7d34b44SSteinar H. Gunderson 			} else {
1609f7d34b44SSteinar H. Gunderson 				usbm = iter;
1610f7d34b44SSteinar H. Gunderson 				usbm->urb_use_count++;
1611f7d34b44SSteinar H. Gunderson 			}
1612f7d34b44SSteinar H. Gunderson 			break;
1613f7d34b44SSteinar H. Gunderson 		}
1614f7d34b44SSteinar H. Gunderson 	}
1615f7d34b44SSteinar H. Gunderson 	spin_unlock_irqrestore(&ps->lock, flags);
1616f7d34b44SSteinar H. Gunderson 	return usbm;
1617f7d34b44SSteinar H. Gunderson }
1618f7d34b44SSteinar 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)16199b6f0c4bSValentina Manea static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
16201da177e4SLinus Torvalds 			struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
162170f1b0d3SEric W. Biederman 			void __user *arg, sigval_t userurb_sigval)
16221da177e4SLinus Torvalds {
16231da177e4SLinus Torvalds 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
16241da177e4SLinus Torvalds 	struct usb_host_endpoint *ep;
162552fb743dSAlan Stern 	struct async *as = NULL;
16261da177e4SLinus Torvalds 	struct usb_ctrlrequest *dr = NULL;
16271da177e4SLinus Torvalds 	unsigned int u, totlen, isofrmlen;
16287a68d9fbSOliver Neukum 	int i, ret, num_sgs = 0, ifnum = -1;
1629b2d03eb5SHans de Goede 	int number_of_packets = 0;
1630948cd8c1SHans de Goede 	unsigned int stream_id = 0;
16313d97ff63SHans de Goede 	void *buf;
16327a68d9fbSOliver Neukum 	bool is_in;
16337a68d9fbSOliver Neukum 	bool allow_short = false;
16347a68d9fbSOliver Neukum 	bool allow_zero = false;
1635446f666dSOliver Neukum 	unsigned long mask =	USBDEVFS_URB_SHORT_NOT_OK |
163601c6460fSAlan Stern 				USBDEVFS_URB_BULK_CONTINUATION |
163714722ef4SAlan Stern 				USBDEVFS_URB_NO_FSBR |
163814722ef4SAlan Stern 				USBDEVFS_URB_ZERO_PACKET |
1639446f666dSOliver Neukum 				USBDEVFS_URB_NO_INTERRUPT;
1640446f666dSOliver Neukum 	/* USBDEVFS_URB_ISO_ASAP is a special case */
1641446f666dSOliver Neukum 	if (uurb->type == USBDEVFS_URB_TYPE_ISO)
1642446f666dSOliver Neukum 		mask |= USBDEVFS_URB_ISO_ASAP;
1643446f666dSOliver Neukum 
1644446f666dSOliver Neukum 	if (uurb->flags & ~mask)
16451da177e4SLinus Torvalds 			return -EINVAL;
1646446f666dSOliver Neukum 
164757999d11SDan Carpenter 	if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
164857999d11SDan Carpenter 		return -EINVAL;
16499180135bSAlan Stern 	if (uurb->buffer_length > 0 && !uurb->buffer)
16501da177e4SLinus Torvalds 		return -EINVAL;
165104e482ffSGreg Kroah-Hartman 	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
165204e482ffSGreg Kroah-Hartman 	    (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
165304e482ffSGreg Kroah-Hartman 		ifnum = findintfep(ps->dev, uurb->endpoint);
165404e482ffSGreg Kroah-Hartman 		if (ifnum < 0)
16551da177e4SLinus Torvalds 			return ifnum;
165604e482ffSGreg Kroah-Hartman 		ret = checkintf(ps, ifnum);
165704e482ffSGreg Kroah-Hartman 		if (ret)
16581da177e4SLinus Torvalds 			return ret;
16591da177e4SLinus Torvalds 	}
16602fec32b0SHans de Goede 	ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);
16611da177e4SLinus Torvalds 	if (!ep)
16621da177e4SLinus Torvalds 		return -ENOENT;
16632fec32b0SHans de Goede 	is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
1664add1aaeaSAlan Stern 
1665add1aaeaSAlan Stern 	u = 0;
16661da177e4SLinus Torvalds 	switch (uurb->type) {
16671da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_CONTROL:
166893cf9b90SAlan Stern 		if (!usb_endpoint_xfer_control(&ep->desc))
16691da177e4SLinus Torvalds 			return -EINVAL;
1670add1aaeaSAlan Stern 		/* min 8 byte setup packet */
1671add1aaeaSAlan Stern 		if (uurb->buffer_length < 8)
16721da177e4SLinus Torvalds 			return -EINVAL;
167304e482ffSGreg Kroah-Hartman 		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
167404e482ffSGreg Kroah-Hartman 		if (!dr)
16751da177e4SLinus Torvalds 			return -ENOMEM;
16761da177e4SLinus Torvalds 		if (copy_from_user(dr, uurb->buffer, 8)) {
167752fb743dSAlan Stern 			ret = -EFAULT;
167852fb743dSAlan Stern 			goto error;
16791da177e4SLinus Torvalds 		}
1680257adc0fSAlan Stern 		if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
168152fb743dSAlan Stern 			ret = -EINVAL;
168252fb743dSAlan Stern 			goto error;
16831da177e4SLinus Torvalds 		}
1684393cbb51SMatthias Dellweg 		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
1685257adc0fSAlan Stern 				      le16_to_cpu(dr->wIndex));
168652fb743dSAlan Stern 		if (ret)
168752fb743dSAlan Stern 			goto error;
1688257adc0fSAlan Stern 		uurb->buffer_length = le16_to_cpu(dr->wLength);
16891da177e4SLinus Torvalds 		uurb->buffer += 8;
169093cf9b90SAlan Stern 		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
169171464db9SSaurav Girepunje 			is_in = true;
169293cf9b90SAlan Stern 			uurb->endpoint |= USB_DIR_IN;
169393cf9b90SAlan Stern 		} else {
169471464db9SSaurav Girepunje 			is_in = false;
169593cf9b90SAlan Stern 			uurb->endpoint &= ~USB_DIR_IN;
169693cf9b90SAlan Stern 		}
1697665c365aSAlan Stern 		if (is_in)
1698665c365aSAlan Stern 			allow_short = true;
16990880aef4SChris Frey 		snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
17000880aef4SChris Frey 			"bRequest=%02x wValue=%04x "
17010880aef4SChris Frey 			"wIndex=%04x wLength=%04x\n",
17020880aef4SChris Frey 			dr->bRequestType, dr->bRequest,
1703257adc0fSAlan Stern 			__le16_to_cpu(dr->wValue),
1704257adc0fSAlan Stern 			__le16_to_cpu(dr->wIndex),
1705257adc0fSAlan Stern 			__le16_to_cpu(dr->wLength));
1706add1aaeaSAlan Stern 		u = sizeof(struct usb_ctrlrequest);
17071da177e4SLinus Torvalds 		break;
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_BULK:
17107a68d9fbSOliver Neukum 		if (!is_in)
17117a68d9fbSOliver Neukum 			allow_zero = true;
17127a68d9fbSOliver Neukum 		else
17137a68d9fbSOliver Neukum 			allow_short = true;
171493cf9b90SAlan Stern 		switch (usb_endpoint_type(&ep->desc)) {
17151da177e4SLinus Torvalds 		case USB_ENDPOINT_XFER_CONTROL:
17161da177e4SLinus Torvalds 		case USB_ENDPOINT_XFER_ISOC:
17171da177e4SLinus Torvalds 			return -EINVAL;
1718f661c6f8SAlan Stern 		case USB_ENDPOINT_XFER_INT:
1719f661c6f8SAlan Stern 			/* allow single-shot interrupt transfers */
1720f661c6f8SAlan Stern 			uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
1721f661c6f8SAlan Stern 			goto interrupt_urb;
17221da177e4SLinus Torvalds 		}
17233d97ff63SHans de Goede 		num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
17243d97ff63SHans de Goede 		if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
17253d97ff63SHans de Goede 			num_sgs = 0;
1726948cd8c1SHans de Goede 		if (ep->streams)
1727948cd8c1SHans de Goede 			stream_id = uurb->stream_id;
17281da177e4SLinus Torvalds 		break;
17291da177e4SLinus Torvalds 
1730f661c6f8SAlan Stern 	case USBDEVFS_URB_TYPE_INTERRUPT:
1731f661c6f8SAlan Stern 		if (!usb_endpoint_xfer_int(&ep->desc))
1732f661c6f8SAlan Stern 			return -EINVAL;
1733f661c6f8SAlan Stern  interrupt_urb:
17347a68d9fbSOliver Neukum 		if (!is_in)
17357a68d9fbSOliver Neukum 			allow_zero = true;
17367a68d9fbSOliver Neukum 		else
17377a68d9fbSOliver Neukum 			allow_short = true;
1738f661c6f8SAlan Stern 		break;
1739f661c6f8SAlan Stern 
17401da177e4SLinus Torvalds 	case USBDEVFS_URB_TYPE_ISO:
17411da177e4SLinus Torvalds 		/* arbitrary limit */
174204e482ffSGreg Kroah-Hartman 		if (uurb->number_of_packets < 1 ||
174304e482ffSGreg Kroah-Hartman 		    uurb->number_of_packets > 128)
17441da177e4SLinus Torvalds 			return -EINVAL;
174593cf9b90SAlan Stern 		if (!usb_endpoint_xfer_isoc(&ep->desc))
17461da177e4SLinus Torvalds 			return -EINVAL;
1747b2d03eb5SHans de Goede 		number_of_packets = uurb->number_of_packets;
174804e482ffSGreg Kroah-Hartman 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
1749b2d03eb5SHans de Goede 				   number_of_packets;
175073a02d32SRahul Pathak 		isopkt = memdup_user(iso_frame_desc, isofrmlen);
175173a02d32SRahul Pathak 		if (IS_ERR(isopkt)) {
175273a02d32SRahul Pathak 			ret = PTR_ERR(isopkt);
175373a02d32SRahul Pathak 			isopkt = NULL;
175452fb743dSAlan Stern 			goto error;
17551da177e4SLinus Torvalds 		}
1756b2d03eb5SHans de Goede 		for (totlen = u = 0; u < number_of_packets; u++) {
1757e2e2f0eaSFederico Manzan 			/*
17588a1dbc8dSChunfeng Yun 			 * arbitrary limit need for USB 3.1 Gen2
17598a1dbc8dSChunfeng Yun 			 * sizemax: 96 DPs at SSP, 96 * 1024 = 98304
1760e2e2f0eaSFederico Manzan 			 */
17618a1dbc8dSChunfeng Yun 			if (isopkt[u].length > 98304) {
176252fb743dSAlan Stern 				ret = -EINVAL;
176352fb743dSAlan Stern 				goto error;
17641da177e4SLinus Torvalds 			}
17651da177e4SLinus Torvalds 			totlen += isopkt[u].length;
17661da177e4SLinus Torvalds 		}
1767add1aaeaSAlan Stern 		u *= sizeof(struct usb_iso_packet_descriptor);
17681da177e4SLinus Torvalds 		uurb->buffer_length = totlen;
17691da177e4SLinus Torvalds 		break;
17701da177e4SLinus Torvalds 
17711da177e4SLinus Torvalds 	default:
17721da177e4SLinus Torvalds 		return -EINVAL;
17731da177e4SLinus Torvalds 	}
1774add1aaeaSAlan Stern 
17759180135bSAlan Stern 	if (uurb->buffer_length > 0 &&
177696d4f267SLinus Torvalds 			!access_ok(uurb->buffer, uurb->buffer_length)) {
177752fb743dSAlan Stern 		ret = -EFAULT;
177852fb743dSAlan Stern 		goto error;
17799180135bSAlan Stern 	}
1780b2d03eb5SHans de Goede 	as = alloc_async(number_of_packets);
178104e482ffSGreg Kroah-Hartman 	if (!as) {
178252fb743dSAlan Stern 		ret = -ENOMEM;
178352fb743dSAlan Stern 		goto error;
17841da177e4SLinus Torvalds 	}
17853d97ff63SHans de Goede 
1786f7d34b44SSteinar H. Gunderson 	as->usbm = find_memory_area(ps, uurb);
1787f7d34b44SSteinar H. Gunderson 	if (IS_ERR(as->usbm)) {
1788f7d34b44SSteinar H. Gunderson 		ret = PTR_ERR(as->usbm);
1789f7d34b44SSteinar H. Gunderson 		as->usbm = NULL;
1790f7d34b44SSteinar H. Gunderson 		goto error;
1791f7d34b44SSteinar H. Gunderson 	}
1792f7d34b44SSteinar H. Gunderson 
1793f7d34b44SSteinar H. Gunderson 	/* do not use SG buffers when memory mapped segments
1794f7d34b44SSteinar H. Gunderson 	 * are in use
1795f7d34b44SSteinar H. Gunderson 	 */
1796f7d34b44SSteinar H. Gunderson 	if (as->usbm)
1797f7d34b44SSteinar H. Gunderson 		num_sgs = 0;
1798f7d34b44SSteinar H. Gunderson 
1799b08a6259SGavin Li 	u += sizeof(struct async) + sizeof(struct urb) +
1800b08a6259SGavin Li 	     (as->usbm ? 0 : uurb->buffer_length) +
18013d97ff63SHans de Goede 	     num_sgs * sizeof(struct scatterlist);
1802add1aaeaSAlan Stern 	ret = usbfs_increase_memory_usage(u);
1803add1aaeaSAlan Stern 	if (ret)
1804add1aaeaSAlan Stern 		goto error;
1805add1aaeaSAlan Stern 	as->mem_usage = u;
1806add1aaeaSAlan Stern 
18073d97ff63SHans de Goede 	if (num_sgs) {
18086da2ec56SKees Cook 		as->urb->sg = kmalloc_array(num_sgs,
18096da2ec56SKees Cook 					    sizeof(struct scatterlist),
18104f2629eaSAlan Stern 					    GFP_KERNEL | __GFP_NOWARN);
18113d97ff63SHans de Goede 		if (!as->urb->sg) {
18123d97ff63SHans de Goede 			ret = -ENOMEM;
18133d97ff63SHans de Goede 			goto error;
18143d97ff63SHans de Goede 		}
18153d97ff63SHans de Goede 		as->urb->num_sgs = num_sgs;
18163d97ff63SHans de Goede 		sg_init_table(as->urb->sg, as->urb->num_sgs);
18173d97ff63SHans de Goede 
18183d97ff63SHans de Goede 		totlen = uurb->buffer_length;
18193d97ff63SHans de Goede 		for (i = 0; i < as->urb->num_sgs; i++) {
18203d97ff63SHans de Goede 			u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
18213d97ff63SHans de Goede 			buf = kmalloc(u, GFP_KERNEL);
18223d97ff63SHans de Goede 			if (!buf) {
18233d97ff63SHans de Goede 				ret = -ENOMEM;
18243d97ff63SHans de Goede 				goto error;
18253d97ff63SHans de Goede 			}
18263d97ff63SHans de Goede 			sg_set_buf(&as->urb->sg[i], buf, u);
18273d97ff63SHans de Goede 
18283d97ff63SHans de Goede 			if (!is_in) {
18293d97ff63SHans de Goede 				if (copy_from_user(buf, uurb->buffer, u)) {
18303d97ff63SHans de Goede 					ret = -EFAULT;
18313d97ff63SHans de Goede 					goto error;
18323d97ff63SHans de Goede 				}
183301463900SHenrik Rydberg 				uurb->buffer += u;
18343d97ff63SHans de Goede 			}
18353d97ff63SHans de Goede 			totlen -= u;
18363d97ff63SHans de Goede 		}
18373d97ff63SHans de Goede 	} else if (uurb->buffer_length > 0) {
1838f7d34b44SSteinar H. Gunderson 		if (as->usbm) {
1839f7d34b44SSteinar H. Gunderson 			unsigned long uurb_start = (unsigned long)uurb->buffer;
1840f7d34b44SSteinar H. Gunderson 
1841f7d34b44SSteinar H. Gunderson 			as->urb->transfer_buffer = as->usbm->mem +
1842f7d34b44SSteinar H. Gunderson 					(uurb_start - as->usbm->vm_start);
1843f7d34b44SSteinar H. Gunderson 		} else {
18449180135bSAlan Stern 			as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
18454f2629eaSAlan Stern 					GFP_KERNEL | __GFP_NOWARN);
184604e482ffSGreg Kroah-Hartman 			if (!as->urb->transfer_buffer) {
184752fb743dSAlan Stern 				ret = -ENOMEM;
184852fb743dSAlan Stern 				goto error;
18491da177e4SLinus Torvalds 			}
18503d97ff63SHans de Goede 			if (!is_in) {
18513d97ff63SHans de Goede 				if (copy_from_user(as->urb->transfer_buffer,
18523d97ff63SHans de Goede 						   uurb->buffer,
18533d97ff63SHans de Goede 						   uurb->buffer_length)) {
18543d97ff63SHans de Goede 					ret = -EFAULT;
18553d97ff63SHans de Goede 					goto error;
18563d97ff63SHans de Goede 				}
18573d97ff63SHans de Goede 			} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
18583d97ff63SHans de Goede 				/*
18593d97ff63SHans de Goede 				 * Isochronous input data may end up being
1860f7d34b44SSteinar H. Gunderson 				 * discontiguous if some of the packets are
1861f7d34b44SSteinar H. Gunderson 				 * short. Clear the buffer so that the gaps
1862f7d34b44SSteinar H. Gunderson 				 * don't leak kernel data to userspace.
18637152b592SAlan Stern 				 */
18647152b592SAlan Stern 				memset(as->urb->transfer_buffer, 0,
18657152b592SAlan Stern 						uurb->buffer_length);
18669180135bSAlan Stern 			}
18673d97ff63SHans de Goede 		}
1868f7d34b44SSteinar H. Gunderson 	}
18691da177e4SLinus Torvalds 	as->urb->dev = ps->dev;
187093cf9b90SAlan Stern 	as->urb->pipe = (uurb->type << 30) |
187193cf9b90SAlan Stern 			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
187293cf9b90SAlan Stern 			(uurb->endpoint & USB_DIR_IN);
187314722ef4SAlan Stern 
187414722ef4SAlan Stern 	/* This tedious sequence is necessary because the URB_* flags
187514722ef4SAlan Stern 	 * are internal to the kernel and subject to change, whereas
187614722ef4SAlan Stern 	 * the USBDEVFS_URB_* flags are a user API and must not be changed.
187714722ef4SAlan Stern 	 */
187814722ef4SAlan Stern 	u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
187914722ef4SAlan Stern 	if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
188014722ef4SAlan Stern 		u |= URB_ISO_ASAP;
18817a68d9fbSOliver Neukum 	if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
188214722ef4SAlan Stern 		u |= URB_SHORT_NOT_OK;
18837a68d9fbSOliver Neukum 	if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
188414722ef4SAlan Stern 		u |= URB_ZERO_PACKET;
188514722ef4SAlan Stern 	if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
188614722ef4SAlan Stern 		u |= URB_NO_INTERRUPT;
188714722ef4SAlan Stern 	as->urb->transfer_flags = u;
188814722ef4SAlan Stern 
188981e0403bSOliver Neukum 	if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
189081e0403bSOliver Neukum 		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n");
189181e0403bSOliver Neukum 	if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET)
189281e0403bSOliver Neukum 		dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n");
189381e0403bSOliver Neukum 
18941da177e4SLinus Torvalds 	as->urb->transfer_buffer_length = uurb->buffer_length;
18951da177e4SLinus Torvalds 	as->urb->setup_packet = (unsigned char *)dr;
189652fb743dSAlan Stern 	dr = NULL;
18971da177e4SLinus Torvalds 	as->urb->start_frame = uurb->start_frame;
1898b2d03eb5SHans de Goede 	as->urb->number_of_packets = number_of_packets;
1899948cd8c1SHans de Goede 	as->urb->stream_id = stream_id;
190053e5f36fSAlan Stern 
190153e5f36fSAlan Stern 	if (ep->desc.bInterval) {
190297b9eb91SAlan Stern 		if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
190353e5f36fSAlan Stern 				ps->dev->speed == USB_SPEED_HIGH ||
190453e5f36fSAlan Stern 				ps->dev->speed >= USB_SPEED_SUPER)
190553e5f36fSAlan Stern 			as->urb->interval = 1 <<
190653e5f36fSAlan Stern 					min(15, ep->desc.bInterval - 1);
190797b9eb91SAlan Stern 		else
190897b9eb91SAlan Stern 			as->urb->interval = ep->desc.bInterval;
190953e5f36fSAlan Stern 	}
191053e5f36fSAlan Stern 
19111da177e4SLinus Torvalds 	as->urb->context = as;
19121da177e4SLinus Torvalds 	as->urb->complete = async_completed;
1913b2d03eb5SHans de Goede 	for (totlen = u = 0; u < number_of_packets; u++) {
19141da177e4SLinus Torvalds 		as->urb->iso_frame_desc[u].offset = totlen;
19151da177e4SLinus Torvalds 		as->urb->iso_frame_desc[u].length = isopkt[u].length;
19161da177e4SLinus Torvalds 		totlen += isopkt[u].length;
19171da177e4SLinus Torvalds 	}
19181da177e4SLinus Torvalds 	kfree(isopkt);
191952fb743dSAlan Stern 	isopkt = NULL;
19201da177e4SLinus Torvalds 	as->ps = ps;
19211da177e4SLinus Torvalds 	as->userurb = arg;
192270f1b0d3SEric W. Biederman 	as->userurb_sigval = userurb_sigval;
1923f7d34b44SSteinar H. Gunderson 	if (as->usbm) {
1924f7d34b44SSteinar H. Gunderson 		unsigned long uurb_start = (unsigned long)uurb->buffer;
1925f7d34b44SSteinar H. Gunderson 
1926f7d34b44SSteinar H. Gunderson 		as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1927f7d34b44SSteinar H. Gunderson 		as->urb->transfer_dma = as->usbm->dma_handle +
1928f7d34b44SSteinar H. Gunderson 				(uurb_start - as->usbm->vm_start);
1929f7d34b44SSteinar H. Gunderson 	} else if (is_in && uurb->buffer_length > 0)
19301da177e4SLinus Torvalds 		as->userbuffer = uurb->buffer;
19311da177e4SLinus Torvalds 	as->signr = uurb->signr;
19321da177e4SLinus Torvalds 	as->ifnum = ifnum;
19332425c08bSEric W. Biederman 	as->pid = get_pid(task_pid(current));
1934d178bc3aSSerge Hallyn 	as->cred = get_current_cred();
19354c6e8971SAlan Stern 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
19360880aef4SChris Frey 			as->urb->transfer_buffer_length, 0, SUBMIT,
19373d97ff63SHans de Goede 			NULL, 0);
19383d97ff63SHans de Goede 	if (!is_in)
19393d97ff63SHans de Goede 		snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
19403d97ff63SHans de Goede 
19411da177e4SLinus Torvalds 	async_newpending(as);
194201c6460fSAlan Stern 
194301c6460fSAlan Stern 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
194401c6460fSAlan Stern 		spin_lock_irq(&ps->lock);
194501c6460fSAlan Stern 
194601c6460fSAlan Stern 		/* Not exactly the endpoint address; the direction bit is
194701c6460fSAlan Stern 		 * shifted to the 0x10 position so that the value will be
194801c6460fSAlan Stern 		 * between 0 and 31.
194901c6460fSAlan Stern 		 */
195001c6460fSAlan Stern 		as->bulk_addr = usb_endpoint_num(&ep->desc) |
195101c6460fSAlan Stern 			((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
195201c6460fSAlan Stern 				>> 3);
195301c6460fSAlan Stern 
195401c6460fSAlan Stern 		/* If this bulk URB is the start of a new transfer, re-enable
195501c6460fSAlan Stern 		 * the endpoint.  Otherwise mark it as a continuation URB.
195601c6460fSAlan Stern 		 */
195701c6460fSAlan Stern 		if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
195801c6460fSAlan Stern 			as->bulk_status = AS_CONTINUATION;
195901c6460fSAlan Stern 		else
196001c6460fSAlan Stern 			ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
196101c6460fSAlan Stern 
196201c6460fSAlan Stern 		/* Don't accept continuation URBs if the endpoint is
196301c6460fSAlan Stern 		 * disabled because of an earlier error.
196401c6460fSAlan Stern 		 */
196501c6460fSAlan Stern 		if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
196601c6460fSAlan Stern 			ret = -EREMOTEIO;
196701c6460fSAlan Stern 		else
196801c6460fSAlan Stern 			ret = usb_submit_urb(as->urb, GFP_ATOMIC);
196901c6460fSAlan Stern 		spin_unlock_irq(&ps->lock);
197001c6460fSAlan Stern 	} else {
197101c6460fSAlan Stern 		ret = usb_submit_urb(as->urb, GFP_KERNEL);
197201c6460fSAlan Stern 	}
197301c6460fSAlan Stern 
197401c6460fSAlan Stern 	if (ret) {
197504e482ffSGreg Kroah-Hartman 		dev_printk(KERN_DEBUG, &ps->dev->dev,
197604e482ffSGreg Kroah-Hartman 			   "usbfs: usb_submit_urb returned %d\n", ret);
19774c6e8971SAlan Stern 		snoop_urb(ps->dev, as->userurb, as->urb->pipe,
19780880aef4SChris Frey 				0, ret, COMPLETE, NULL, 0);
19791da177e4SLinus Torvalds 		async_removepending(as);
198052fb743dSAlan Stern 		goto error;
19811da177e4SLinus Torvalds 	}
19821da177e4SLinus Torvalds 	return 0;
198352fb743dSAlan Stern 
198452fb743dSAlan Stern  error:
198552fb743dSAlan Stern 	kfree(isopkt);
198652fb743dSAlan Stern 	kfree(dr);
198752fb743dSAlan Stern 	if (as)
198852fb743dSAlan Stern 		free_async(as);
198952fb743dSAlan Stern 	return ret;
19901da177e4SLinus Torvalds }
19911da177e4SLinus Torvalds 
proc_submiturb(struct usb_dev_state * ps,void __user * arg)19929b6f0c4bSValentina Manea static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
19931da177e4SLinus Torvalds {
19941da177e4SLinus Torvalds 	struct usbdevfs_urb uurb;
199570f1b0d3SEric W. Biederman 	sigval_t userurb_sigval;
19961da177e4SLinus Torvalds 
19971da177e4SLinus Torvalds 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
19981da177e4SLinus Torvalds 		return -EFAULT;
19991da177e4SLinus Torvalds 
200070f1b0d3SEric W. Biederman 	memset(&userurb_sigval, 0, sizeof(userurb_sigval));
200170f1b0d3SEric W. Biederman 	userurb_sigval.sival_ptr = arg;
200270f1b0d3SEric W. Biederman 
200304e482ffSGreg Kroah-Hartman 	return proc_do_submiturb(ps, &uurb,
200404e482ffSGreg Kroah-Hartman 			(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
200570f1b0d3SEric W. Biederman 			arg, userurb_sigval);
20061da177e4SLinus Torvalds }
20071da177e4SLinus Torvalds 
proc_unlinkurb(struct usb_dev_state * ps,void __user * arg)20089b6f0c4bSValentina Manea static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
20091da177e4SLinus Torvalds {
20104e09dcf2SHuajun Li 	struct urb *urb;
20111da177e4SLinus Torvalds 	struct async *as;
20124e09dcf2SHuajun Li 	unsigned long flags;
20131da177e4SLinus Torvalds 
20144e09dcf2SHuajun Li 	spin_lock_irqsave(&ps->lock, flags);
20151da177e4SLinus Torvalds 	as = async_getpending(ps, arg);
20164e09dcf2SHuajun Li 	if (!as) {
20174e09dcf2SHuajun Li 		spin_unlock_irqrestore(&ps->lock, flags);
20181da177e4SLinus Torvalds 		return -EINVAL;
20194e09dcf2SHuajun Li 	}
20204e09dcf2SHuajun Li 
20214e09dcf2SHuajun Li 	urb = as->urb;
20224e09dcf2SHuajun Li 	usb_get_urb(urb);
20234e09dcf2SHuajun Li 	spin_unlock_irqrestore(&ps->lock, flags);
20244e09dcf2SHuajun Li 
20254e09dcf2SHuajun Li 	usb_kill_urb(urb);
20264e09dcf2SHuajun Li 	usb_put_urb(urb);
20274e09dcf2SHuajun Li 
20281da177e4SLinus Torvalds 	return 0;
20291da177e4SLinus Torvalds }
20301da177e4SLinus Torvalds 
compute_isochronous_actual_length(struct urb * urb)20312ef47001SAlan Stern static void compute_isochronous_actual_length(struct urb *urb)
20322ef47001SAlan Stern {
20332ef47001SAlan Stern 	unsigned int i;
20342ef47001SAlan Stern 
20352ef47001SAlan Stern 	if (urb->number_of_packets > 0) {
20362ef47001SAlan Stern 		urb->actual_length = 0;
20372ef47001SAlan Stern 		for (i = 0; i < urb->number_of_packets; i++)
20382ef47001SAlan Stern 			urb->actual_length +=
20392ef47001SAlan Stern 					urb->iso_frame_desc[i].actual_length;
20402ef47001SAlan Stern 	}
20412ef47001SAlan Stern }
20422ef47001SAlan Stern 
processcompl(struct async * as,void __user * __user * arg)20431da177e4SLinus Torvalds static int processcompl(struct async *as, void __user * __user *arg)
20441da177e4SLinus Torvalds {
20451da177e4SLinus Torvalds 	struct urb *urb = as->urb;
20461da177e4SLinus Torvalds 	struct usbdevfs_urb __user *userurb = as->userurb;
20471da177e4SLinus Torvalds 	void __user *addr = as->userurb;
20481da177e4SLinus Torvalds 	unsigned int i;
20491da177e4SLinus Torvalds 
20502ef47001SAlan Stern 	compute_isochronous_actual_length(urb);
20517152b592SAlan Stern 	if (as->userbuffer && urb->actual_length) {
20523d97ff63SHans de Goede 		if (copy_urb_data_to_user(as->userbuffer, urb))
2053d794a021SOliver Neukum 			goto err_out;
20547152b592SAlan Stern 	}
2055e015268dSAlan Stern 	if (put_user(as->status, &userurb->status))
2056d794a021SOliver Neukum 		goto err_out;
20571da177e4SLinus Torvalds 	if (put_user(urb->actual_length, &userurb->actual_length))
2058d794a021SOliver Neukum 		goto err_out;
20591da177e4SLinus Torvalds 	if (put_user(urb->error_count, &userurb->error_count))
2060d794a021SOliver Neukum 		goto err_out;
20611da177e4SLinus Torvalds 
206293cf9b90SAlan Stern 	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
20631da177e4SLinus Torvalds 		for (i = 0; i < urb->number_of_packets; i++) {
20641da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].actual_length,
20651da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].actual_length))
2066d794a021SOliver Neukum 				goto err_out;
20671da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].status,
20681da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].status))
2069d794a021SOliver Neukum 				goto err_out;
20701da177e4SLinus Torvalds 		}
2071668a9541SChristopher Li 	}
20721da177e4SLinus Torvalds 
20731da177e4SLinus Torvalds 	if (put_user(addr, (void __user * __user *)arg))
20741da177e4SLinus Torvalds 		return -EFAULT;
20751da177e4SLinus Torvalds 	return 0;
2076d794a021SOliver Neukum 
2077d794a021SOliver Neukum err_out:
2078d794a021SOliver Neukum 	return -EFAULT;
20791da177e4SLinus Torvalds }
20801da177e4SLinus Torvalds 
reap_as(struct usb_dev_state * ps)20819b6f0c4bSValentina Manea static struct async *reap_as(struct usb_dev_state *ps)
20821da177e4SLinus Torvalds {
20831da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
20841da177e4SLinus Torvalds 	struct async *as = NULL;
20851da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
20861da177e4SLinus Torvalds 
20871da177e4SLinus Torvalds 	add_wait_queue(&ps->wait, &wait);
20881da177e4SLinus Torvalds 	for (;;) {
20891da177e4SLinus Torvalds 		__set_current_state(TASK_INTERRUPTIBLE);
209004e482ffSGreg Kroah-Hartman 		as = async_getcompleted(ps);
20913f2cee73SAlan Stern 		if (as || !connected(ps))
20921da177e4SLinus Torvalds 			break;
20931da177e4SLinus Torvalds 		if (signal_pending(current))
20941da177e4SLinus Torvalds 			break;
20951da177e4SLinus Torvalds 		usb_unlock_device(dev);
20961da177e4SLinus Torvalds 		schedule();
20971da177e4SLinus Torvalds 		usb_lock_device(dev);
20981da177e4SLinus Torvalds 	}
20991da177e4SLinus Torvalds 	remove_wait_queue(&ps->wait, &wait);
21001da177e4SLinus Torvalds 	set_current_state(TASK_RUNNING);
21011da177e4SLinus Torvalds 	return as;
21021da177e4SLinus Torvalds }
21031da177e4SLinus Torvalds 
proc_reapurb(struct usb_dev_state * ps,void __user * arg)21049b6f0c4bSValentina Manea static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
21051da177e4SLinus Torvalds {
21061da177e4SLinus Torvalds 	struct async *as = reap_as(ps);
2107a016a816SAlan Stern 
2108ddeee0b2SLinus Torvalds 	if (as) {
2109a016a816SAlan Stern 		int retval;
2110a016a816SAlan Stern 
2111f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2112a016a816SAlan Stern 		retval = processcompl(as, (void __user * __user *)arg);
2113ddeee0b2SLinus Torvalds 		free_async(as);
2114ddeee0b2SLinus Torvalds 		return retval;
2115ddeee0b2SLinus Torvalds 	}
21161da177e4SLinus Torvalds 	if (signal_pending(current))
21171da177e4SLinus Torvalds 		return -EINTR;
21183f2cee73SAlan Stern 	return -ENODEV;
21191da177e4SLinus Torvalds }
21201da177e4SLinus Torvalds 
proc_reapurbnonblock(struct usb_dev_state * ps,void __user * arg)21219b6f0c4bSValentina Manea static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
21221da177e4SLinus Torvalds {
2123ddeee0b2SLinus Torvalds 	int retval;
21241da177e4SLinus Torvalds 	struct async *as;
21251da177e4SLinus Torvalds 
2126ddeee0b2SLinus Torvalds 	as = async_getcompleted(ps);
2127ddeee0b2SLinus Torvalds 	if (as) {
2128f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2129ddeee0b2SLinus Torvalds 		retval = processcompl(as, (void __user * __user *)arg);
2130ddeee0b2SLinus Torvalds 		free_async(as);
21313f2cee73SAlan Stern 	} else {
21323f2cee73SAlan Stern 		retval = (connected(ps) ? -EAGAIN : -ENODEV);
2133ddeee0b2SLinus Torvalds 	}
2134ddeee0b2SLinus Torvalds 	return retval;
21351da177e4SLinus Torvalds }
21361da177e4SLinus Torvalds 
21371da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
proc_control_compat(struct usb_dev_state * ps,struct usbdevfs_ctrltransfer32 __user * p32)21389b6f0c4bSValentina Manea static int proc_control_compat(struct usb_dev_state *ps,
2139637e8a60SArnd Bergmann 				struct usbdevfs_ctrltransfer32 __user *p32)
2140637e8a60SArnd Bergmann {
2141c17536d0SChristoph Hellwig 	struct usbdevfs_ctrltransfer ctrl;
2142c17536d0SChristoph Hellwig 	u32 udata;
2143c17536d0SChristoph Hellwig 
2144c17536d0SChristoph Hellwig 	if (copy_from_user(&ctrl, p32, sizeof(*p32) - sizeof(compat_caddr_t)) ||
2145c17536d0SChristoph Hellwig 	    get_user(udata, &p32->data))
2146637e8a60SArnd Bergmann 		return -EFAULT;
2147c17536d0SChristoph Hellwig 	ctrl.data = compat_ptr(udata);
2148c17536d0SChristoph Hellwig 	return do_proc_control(ps, &ctrl);
2149637e8a60SArnd Bergmann }
2150637e8a60SArnd Bergmann 
proc_bulk_compat(struct usb_dev_state * ps,struct usbdevfs_bulktransfer32 __user * p32)21519b6f0c4bSValentina Manea static int proc_bulk_compat(struct usb_dev_state *ps,
2152637e8a60SArnd Bergmann 			struct usbdevfs_bulktransfer32 __user *p32)
2153637e8a60SArnd Bergmann {
2154c17536d0SChristoph Hellwig 	struct usbdevfs_bulktransfer bulk;
2155637e8a60SArnd Bergmann 	compat_caddr_t addr;
2156637e8a60SArnd Bergmann 
2157c17536d0SChristoph Hellwig 	if (get_user(bulk.ep, &p32->ep) ||
2158c17536d0SChristoph Hellwig 	    get_user(bulk.len, &p32->len) ||
2159c17536d0SChristoph Hellwig 	    get_user(bulk.timeout, &p32->timeout) ||
2160c17536d0SChristoph Hellwig 	    get_user(addr, &p32->data))
2161637e8a60SArnd Bergmann 		return -EFAULT;
2162c17536d0SChristoph Hellwig 	bulk.data = compat_ptr(addr);
2163c17536d0SChristoph Hellwig 	return do_proc_bulk(ps, &bulk);
2164637e8a60SArnd Bergmann }
2165c17536d0SChristoph Hellwig 
proc_disconnectsignal_compat(struct usb_dev_state * ps,void __user * arg)21669b6f0c4bSValentina Manea static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)
2167637e8a60SArnd Bergmann {
2168637e8a60SArnd Bergmann 	struct usbdevfs_disconnectsignal32 ds;
2169637e8a60SArnd Bergmann 
2170637e8a60SArnd Bergmann 	if (copy_from_user(&ds, arg, sizeof(ds)))
2171637e8a60SArnd Bergmann 		return -EFAULT;
2172637e8a60SArnd Bergmann 	ps->discsignr = ds.signr;
217370f1b0d3SEric W. Biederman 	ps->disccontext.sival_int = ds.context;
2174637e8a60SArnd Bergmann 	return 0;
2175637e8a60SArnd Bergmann }
21761da177e4SLinus Torvalds 
get_urb32(struct usbdevfs_urb * kurb,struct usbdevfs_urb32 __user * uurb)21771da177e4SLinus Torvalds static int get_urb32(struct usbdevfs_urb *kurb,
21781da177e4SLinus Torvalds 		     struct usbdevfs_urb32 __user *uurb)
21791da177e4SLinus Torvalds {
2180cc1a7c4bSAl Viro 	struct usbdevfs_urb32 urb32;
2181cc1a7c4bSAl Viro 	if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
21821da177e4SLinus Torvalds 		return -EFAULT;
2183cc1a7c4bSAl Viro 	kurb->type = urb32.type;
2184cc1a7c4bSAl Viro 	kurb->endpoint = urb32.endpoint;
2185cc1a7c4bSAl Viro 	kurb->status = urb32.status;
2186cc1a7c4bSAl Viro 	kurb->flags = urb32.flags;
2187cc1a7c4bSAl Viro 	kurb->buffer = compat_ptr(urb32.buffer);
2188cc1a7c4bSAl Viro 	kurb->buffer_length = urb32.buffer_length;
2189cc1a7c4bSAl Viro 	kurb->actual_length = urb32.actual_length;
2190cc1a7c4bSAl Viro 	kurb->start_frame = urb32.start_frame;
2191cc1a7c4bSAl Viro 	kurb->number_of_packets = urb32.number_of_packets;
2192cc1a7c4bSAl Viro 	kurb->error_count = urb32.error_count;
2193cc1a7c4bSAl Viro 	kurb->signr = urb32.signr;
2194cc1a7c4bSAl Viro 	kurb->usercontext = compat_ptr(urb32.usercontext);
21951da177e4SLinus Torvalds 	return 0;
21961da177e4SLinus Torvalds }
21971da177e4SLinus Torvalds 
proc_submiturb_compat(struct usb_dev_state * ps,void __user * arg)21989b6f0c4bSValentina Manea static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
21991da177e4SLinus Torvalds {
22001da177e4SLinus Torvalds 	struct usbdevfs_urb uurb;
220170f1b0d3SEric W. Biederman 	sigval_t userurb_sigval;
22021da177e4SLinus Torvalds 
2203c714de5dSAl Viro 	if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
22041da177e4SLinus Torvalds 		return -EFAULT;
22051da177e4SLinus Torvalds 
220670f1b0d3SEric W. Biederman 	memset(&userurb_sigval, 0, sizeof(userurb_sigval));
220770f1b0d3SEric W. Biederman 	userurb_sigval.sival_int = ptr_to_compat(arg);
220870f1b0d3SEric W. Biederman 
220904e482ffSGreg Kroah-Hartman 	return proc_do_submiturb(ps, &uurb,
221004e482ffSGreg Kroah-Hartman 			((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
221170f1b0d3SEric W. Biederman 			arg, userurb_sigval);
22121da177e4SLinus Torvalds }
22131da177e4SLinus Torvalds 
processcompl_compat(struct async * as,void __user * __user * arg)22141da177e4SLinus Torvalds static int processcompl_compat(struct async *as, void __user * __user *arg)
22151da177e4SLinus Torvalds {
22161da177e4SLinus Torvalds 	struct urb *urb = as->urb;
22171da177e4SLinus Torvalds 	struct usbdevfs_urb32 __user *userurb = as->userurb;
22181da177e4SLinus Torvalds 	void __user *addr = as->userurb;
22191da177e4SLinus Torvalds 	unsigned int i;
22201da177e4SLinus Torvalds 
22212ef47001SAlan Stern 	compute_isochronous_actual_length(urb);
22222102e06aSHans de Goede 	if (as->userbuffer && urb->actual_length) {
22233d97ff63SHans de Goede 		if (copy_urb_data_to_user(as->userbuffer, urb))
22241da177e4SLinus Torvalds 			return -EFAULT;
22252102e06aSHans de Goede 	}
2226e015268dSAlan Stern 	if (put_user(as->status, &userurb->status))
22271da177e4SLinus Torvalds 		return -EFAULT;
22281da177e4SLinus Torvalds 	if (put_user(urb->actual_length, &userurb->actual_length))
22291da177e4SLinus Torvalds 		return -EFAULT;
22301da177e4SLinus Torvalds 	if (put_user(urb->error_count, &userurb->error_count))
22311da177e4SLinus Torvalds 		return -EFAULT;
22321da177e4SLinus Torvalds 
223393cf9b90SAlan Stern 	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
22341da177e4SLinus Torvalds 		for (i = 0; i < urb->number_of_packets; i++) {
22351da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].actual_length,
22361da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].actual_length))
22371da177e4SLinus Torvalds 				return -EFAULT;
22381da177e4SLinus Torvalds 			if (put_user(urb->iso_frame_desc[i].status,
22391da177e4SLinus Torvalds 				     &userurb->iso_frame_desc[i].status))
22401da177e4SLinus Torvalds 				return -EFAULT;
22411da177e4SLinus Torvalds 		}
2242668a9541SChristopher Li 	}
22431da177e4SLinus Torvalds 
2244c714de5dSAl Viro 	if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
22451da177e4SLinus Torvalds 		return -EFAULT;
22461da177e4SLinus Torvalds 	return 0;
22471da177e4SLinus Torvalds }
22481da177e4SLinus Torvalds 
proc_reapurb_compat(struct usb_dev_state * ps,void __user * arg)22499b6f0c4bSValentina Manea static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
22501da177e4SLinus Torvalds {
22511da177e4SLinus Torvalds 	struct async *as = reap_as(ps);
2252a016a816SAlan Stern 
2253ddeee0b2SLinus Torvalds 	if (as) {
2254a016a816SAlan Stern 		int retval;
2255a016a816SAlan Stern 
2256f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2257a016a816SAlan Stern 		retval = processcompl_compat(as, (void __user * __user *)arg);
2258ddeee0b2SLinus Torvalds 		free_async(as);
2259ddeee0b2SLinus Torvalds 		return retval;
2260ddeee0b2SLinus Torvalds 	}
22611da177e4SLinus Torvalds 	if (signal_pending(current))
22621da177e4SLinus Torvalds 		return -EINTR;
22633f2cee73SAlan Stern 	return -ENODEV;
22641da177e4SLinus Torvalds }
22651da177e4SLinus Torvalds 
proc_reapurbnonblock_compat(struct usb_dev_state * ps,void __user * arg)22669b6f0c4bSValentina Manea static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
22671da177e4SLinus Torvalds {
2268ddeee0b2SLinus Torvalds 	int retval;
22691da177e4SLinus Torvalds 	struct async *as;
22701da177e4SLinus Torvalds 
2271ddeee0b2SLinus Torvalds 	as = async_getcompleted(ps);
2272ddeee0b2SLinus Torvalds 	if (as) {
2273f3bc432aSAlan Stern 		snoop(&ps->dev->dev, "reap %px\n", as->userurb);
2274ddeee0b2SLinus Torvalds 		retval = processcompl_compat(as, (void __user * __user *)arg);
2275ddeee0b2SLinus Torvalds 		free_async(as);
22763f2cee73SAlan Stern 	} else {
22773f2cee73SAlan Stern 		retval = (connected(ps) ? -EAGAIN : -ENODEV);
2278ddeee0b2SLinus Torvalds 	}
2279ddeee0b2SLinus Torvalds 	return retval;
22801da177e4SLinus Torvalds }
22811da177e4SLinus Torvalds 
2282637e8a60SArnd Bergmann 
22831da177e4SLinus Torvalds #endif
22841da177e4SLinus Torvalds 
proc_disconnectsignal(struct usb_dev_state * ps,void __user * arg)22859b6f0c4bSValentina Manea static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
22861da177e4SLinus Torvalds {
22871da177e4SLinus Torvalds 	struct usbdevfs_disconnectsignal ds;
22881da177e4SLinus Torvalds 
22891da177e4SLinus Torvalds 	if (copy_from_user(&ds, arg, sizeof(ds)))
22901da177e4SLinus Torvalds 		return -EFAULT;
22911da177e4SLinus Torvalds 	ps->discsignr = ds.signr;
229270f1b0d3SEric W. Biederman 	ps->disccontext.sival_ptr = ds.context;
22931da177e4SLinus Torvalds 	return 0;
22941da177e4SLinus Torvalds }
22951da177e4SLinus Torvalds 
proc_claiminterface(struct usb_dev_state * ps,void __user * arg)22969b6f0c4bSValentina Manea static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)
22971da177e4SLinus Torvalds {
22981da177e4SLinus Torvalds 	unsigned int ifnum;
22991da177e4SLinus Torvalds 
23001da177e4SLinus Torvalds 	if (get_user(ifnum, (unsigned int __user *)arg))
23011da177e4SLinus Torvalds 		return -EFAULT;
23021da177e4SLinus Torvalds 	return claimintf(ps, ifnum);
23031da177e4SLinus Torvalds }
23041da177e4SLinus Torvalds 
proc_releaseinterface(struct usb_dev_state * ps,void __user * arg)23059b6f0c4bSValentina Manea static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
23061da177e4SLinus Torvalds {
23071da177e4SLinus Torvalds 	unsigned int ifnum;
23081da177e4SLinus Torvalds 	int ret;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 	if (get_user(ifnum, (unsigned int __user *)arg))
23111da177e4SLinus Torvalds 		return -EFAULT;
2312135551eaSKris Borer 	ret = releaseintf(ps, ifnum);
2313135551eaSKris Borer 	if (ret < 0)
23141da177e4SLinus Torvalds 		return ret;
23151da177e4SLinus Torvalds 	destroy_async_on_interface(ps, ifnum);
23161da177e4SLinus Torvalds 	return 0;
23171da177e4SLinus Torvalds }
23181da177e4SLinus Torvalds 
proc_ioctl(struct usb_dev_state * ps,struct usbdevfs_ioctl * ctl)23199b6f0c4bSValentina Manea static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
23201da177e4SLinus Torvalds {
23211da177e4SLinus Torvalds 	int			size;
23221da177e4SLinus Torvalds 	void			*buf = NULL;
23231da177e4SLinus Torvalds 	int			retval = 0;
23241da177e4SLinus Torvalds 	struct usb_interface    *intf = NULL;
23251da177e4SLinus Torvalds 	struct usb_driver       *driver = NULL;
23261da177e4SLinus Torvalds 
2327d883f52eSReilly Grant 	if (ps->privileges_dropped)
2328d883f52eSReilly Grant 		return -EACCES;
2329d883f52eSReilly Grant 
2330086ebf92SWeitao Hou 	if (!connected(ps))
2331086ebf92SWeitao Hou 		return -ENODEV;
2332086ebf92SWeitao Hou 
2333c36fc889SPete Zaitcev 	/* alloc buffer */
2334135551eaSKris Borer 	size = _IOC_SIZE(ctl->ioctl_code);
2335135551eaSKris Borer 	if (size > 0) {
23364baf0df7STülin İzer 		buf = kmalloc(size, GFP_KERNEL);
23374baf0df7STülin İzer 		if (buf == NULL)
23381da177e4SLinus Torvalds 			return -ENOMEM;
2339c36fc889SPete Zaitcev 		if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
2340c36fc889SPete Zaitcev 			if (copy_from_user(buf, ctl->data, size)) {
23411da177e4SLinus Torvalds 				kfree(buf);
23421da177e4SLinus Torvalds 				return -EFAULT;
23431da177e4SLinus Torvalds 			}
23441da177e4SLinus Torvalds 		} else {
23451da177e4SLinus Torvalds 			memset(buf, 0, size);
23461da177e4SLinus Torvalds 		}
23471da177e4SLinus Torvalds 	}
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 	if (ps->dev->state != USB_STATE_CONFIGURED)
23501da177e4SLinus Torvalds 		retval = -EHOSTUNREACH;
2351c36fc889SPete Zaitcev 	else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
23521da177e4SLinus Torvalds 		retval = -EINVAL;
2353c36fc889SPete Zaitcev 	else switch (ctl->ioctl_code) {
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	/* disconnect kernel driver from interface */
23561da177e4SLinus Torvalds 	case USBDEVFS_DISCONNECT:
23571da177e4SLinus Torvalds 		if (intf->dev.driver) {
23581da177e4SLinus Torvalds 			driver = to_usb_driver(intf->dev.driver);
23591da177e4SLinus Torvalds 			dev_dbg(&intf->dev, "disconnect by usbfs\n");
23601da177e4SLinus Torvalds 			usb_driver_release_interface(driver, intf);
23611da177e4SLinus Torvalds 		} else
23621da177e4SLinus Torvalds 			retval = -ENODATA;
23631da177e4SLinus Torvalds 		break;
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds 	/* let kernel drivers try to (re)bind to the interface */
23661da177e4SLinus Torvalds 	case USBDEVFS_CONNECT:
2367885e9747SAlan Stern 		if (!intf->dev.driver)
2368885e9747SAlan Stern 			retval = device_attach(&intf->dev);
2369885e9747SAlan Stern 		else
2370885e9747SAlan Stern 			retval = -EBUSY;
23711da177e4SLinus Torvalds 		break;
23721da177e4SLinus Torvalds 
23731da177e4SLinus Torvalds 	/* talk directly to the interface's driver */
23741da177e4SLinus Torvalds 	default:
23751da177e4SLinus Torvalds 		if (intf->dev.driver)
23761da177e4SLinus Torvalds 			driver = to_usb_driver(intf->dev.driver);
2377c532b29aSAndi Kleen 		if (driver == NULL || driver->unlocked_ioctl == NULL) {
23781da177e4SLinus Torvalds 			retval = -ENOTTY;
23791da177e4SLinus Torvalds 		} else {
2380c532b29aSAndi Kleen 			retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
23811da177e4SLinus Torvalds 			if (retval == -ENOIOCTLCMD)
23821da177e4SLinus Torvalds 				retval = -ENOTTY;
23831da177e4SLinus Torvalds 		}
23841da177e4SLinus Torvalds 	}
23851da177e4SLinus Torvalds 
23861da177e4SLinus Torvalds 	/* cleanup and return */
23871da177e4SLinus Torvalds 	if (retval >= 0
2388c36fc889SPete Zaitcev 			&& (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
23891da177e4SLinus Torvalds 			&& size > 0
2390c36fc889SPete Zaitcev 			&& copy_to_user(ctl->data, buf, size) != 0)
23911da177e4SLinus Torvalds 		retval = -EFAULT;
23926fd19f4bSJesper Juhl 
23931da177e4SLinus Torvalds 	kfree(buf);
23941da177e4SLinus Torvalds 	return retval;
23951da177e4SLinus Torvalds }
23961da177e4SLinus Torvalds 
proc_ioctl_default(struct usb_dev_state * ps,void __user * arg)23979b6f0c4bSValentina Manea static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
2398c36fc889SPete Zaitcev {
2399c36fc889SPete Zaitcev 	struct usbdevfs_ioctl	ctrl;
2400c36fc889SPete Zaitcev 
2401c36fc889SPete Zaitcev 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
2402c36fc889SPete Zaitcev 		return -EFAULT;
2403c36fc889SPete Zaitcev 	return proc_ioctl(ps, &ctrl);
2404c36fc889SPete Zaitcev }
2405c36fc889SPete Zaitcev 
2406c36fc889SPete Zaitcev #ifdef CONFIG_COMPAT
proc_ioctl_compat(struct usb_dev_state * ps,compat_uptr_t arg)24079b6f0c4bSValentina Manea static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
2408c36fc889SPete Zaitcev {
2409cc1a7c4bSAl Viro 	struct usbdevfs_ioctl32 ioc32;
2410c36fc889SPete Zaitcev 	struct usbdevfs_ioctl ctrl;
2411c36fc889SPete Zaitcev 
2412cc1a7c4bSAl Viro 	if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
2413c36fc889SPete Zaitcev 		return -EFAULT;
2414cc1a7c4bSAl Viro 	ctrl.ifno = ioc32.ifno;
2415cc1a7c4bSAl Viro 	ctrl.ioctl_code = ioc32.ioctl_code;
2416cc1a7c4bSAl Viro 	ctrl.data = compat_ptr(ioc32.data);
2417c36fc889SPete Zaitcev 	return proc_ioctl(ps, &ctrl);
2418c36fc889SPete Zaitcev }
2419c36fc889SPete Zaitcev #endif
2420c36fc889SPete Zaitcev 
proc_claim_port(struct usb_dev_state * ps,void __user * arg)24219b6f0c4bSValentina Manea static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)
24227cbe5dcaSAlan Stern {
24237cbe5dcaSAlan Stern 	unsigned portnum;
24247cbe5dcaSAlan Stern 	int rc;
24257cbe5dcaSAlan Stern 
24267cbe5dcaSAlan Stern 	if (get_user(portnum, (unsigned __user *) arg))
24277cbe5dcaSAlan Stern 		return -EFAULT;
24287cbe5dcaSAlan Stern 	rc = usb_hub_claim_port(ps->dev, portnum, ps);
24297cbe5dcaSAlan Stern 	if (rc == 0)
24307cbe5dcaSAlan Stern 		snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
24317cbe5dcaSAlan Stern 			portnum, task_pid_nr(current), current->comm);
24327cbe5dcaSAlan Stern 	return rc;
24337cbe5dcaSAlan Stern }
24347cbe5dcaSAlan Stern 
proc_release_port(struct usb_dev_state * ps,void __user * arg)24359b6f0c4bSValentina Manea static int proc_release_port(struct usb_dev_state *ps, void __user *arg)
24367cbe5dcaSAlan Stern {
24377cbe5dcaSAlan Stern 	unsigned portnum;
24387cbe5dcaSAlan Stern 
24397cbe5dcaSAlan Stern 	if (get_user(portnum, (unsigned __user *) arg))
24407cbe5dcaSAlan Stern 		return -EFAULT;
24417cbe5dcaSAlan Stern 	return usb_hub_release_port(ps->dev, portnum, ps);
24427cbe5dcaSAlan Stern }
24437cbe5dcaSAlan Stern 
proc_get_capabilities(struct usb_dev_state * ps,void __user * arg)24449b6f0c4bSValentina Manea static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
244519181bc5SHans de Goede {
244619181bc5SHans de Goede 	__u32 caps;
244719181bc5SHans de Goede 
24483f2cee73SAlan Stern 	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
2449d883f52eSReilly Grant 			USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
24504ed33505SAlan Stern 			USBDEVFS_CAP_DROP_PRIVILEGES |
24514ed33505SAlan Stern 			USBDEVFS_CAP_CONNINFO_EX | MAYBE_CAP_SUSPEND;
245219181bc5SHans de Goede 	if (!ps->dev->bus->no_stop_on_short)
245319181bc5SHans de Goede 		caps |= USBDEVFS_CAP_BULK_CONTINUATION;
24543d97ff63SHans de Goede 	if (ps->dev->bus->sg_tablesize)
24553d97ff63SHans de Goede 		caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
245619181bc5SHans de Goede 
245719181bc5SHans de Goede 	if (put_user(caps, (__u32 __user *)arg))
245819181bc5SHans de Goede 		return -EFAULT;
245919181bc5SHans de Goede 
246019181bc5SHans de Goede 	return 0;
246119181bc5SHans de Goede }
246219181bc5SHans de Goede 
proc_disconnect_claim(struct usb_dev_state * ps,void __user * arg)24639b6f0c4bSValentina Manea static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
24640837e7e5SHans de Goede {
24650837e7e5SHans de Goede 	struct usbdevfs_disconnect_claim dc;
24660837e7e5SHans de Goede 	struct usb_interface *intf;
24670837e7e5SHans de Goede 
24680837e7e5SHans de Goede 	if (copy_from_user(&dc, arg, sizeof(dc)))
24690837e7e5SHans de Goede 		return -EFAULT;
24700837e7e5SHans de Goede 
24710837e7e5SHans de Goede 	intf = usb_ifnum_to_if(ps->dev, dc.interface);
24720837e7e5SHans de Goede 	if (!intf)
24730837e7e5SHans de Goede 		return -EINVAL;
24740837e7e5SHans de Goede 
24750837e7e5SHans de Goede 	if (intf->dev.driver) {
24760837e7e5SHans de Goede 		struct usb_driver *driver = to_usb_driver(intf->dev.driver);
24770837e7e5SHans de Goede 
2478d883f52eSReilly Grant 		if (ps->privileges_dropped)
2479d883f52eSReilly Grant 			return -EACCES;
2480d883f52eSReilly Grant 
24810837e7e5SHans de Goede 		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
24820837e7e5SHans de Goede 				strncmp(dc.driver, intf->dev.driver->name,
24830837e7e5SHans de Goede 					sizeof(dc.driver)) != 0)
24840837e7e5SHans de Goede 			return -EBUSY;
24850837e7e5SHans de Goede 
24860837e7e5SHans de Goede 		if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
24870837e7e5SHans de Goede 				strncmp(dc.driver, intf->dev.driver->name,
24880837e7e5SHans de Goede 					sizeof(dc.driver)) == 0)
24890837e7e5SHans de Goede 			return -EBUSY;
24900837e7e5SHans de Goede 
24910837e7e5SHans de Goede 		dev_dbg(&intf->dev, "disconnect by usbfs\n");
24920837e7e5SHans de Goede 		usb_driver_release_interface(driver, intf);
24930837e7e5SHans de Goede 	}
24940837e7e5SHans de Goede 
24950837e7e5SHans de Goede 	return claimintf(ps, dc.interface);
24960837e7e5SHans de Goede }
24970837e7e5SHans de Goede 
proc_alloc_streams(struct usb_dev_state * ps,void __user * arg)24983e75c6deSLinus Torvalds static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg)
2499bcf7f6e3SHans de Goede {
2500bcf7f6e3SHans de Goede 	unsigned num_streams, num_eps;
2501bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
2502bcf7f6e3SHans de Goede 	struct usb_interface *intf;
2503bcf7f6e3SHans de Goede 	int r;
2504bcf7f6e3SHans de Goede 
2505bcf7f6e3SHans de Goede 	r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
2506bcf7f6e3SHans de Goede 				   &eps, &intf);
2507bcf7f6e3SHans de Goede 	if (r)
2508bcf7f6e3SHans de Goede 		return r;
2509bcf7f6e3SHans de Goede 
2510bcf7f6e3SHans de Goede 	destroy_async_on_interface(ps,
2511bcf7f6e3SHans de Goede 				   intf->altsetting[0].desc.bInterfaceNumber);
2512bcf7f6e3SHans de Goede 
2513bcf7f6e3SHans de Goede 	r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
2514bcf7f6e3SHans de Goede 	kfree(eps);
2515bcf7f6e3SHans de Goede 	return r;
2516bcf7f6e3SHans de Goede }
2517bcf7f6e3SHans de Goede 
proc_free_streams(struct usb_dev_state * ps,void __user * arg)25183e75c6deSLinus Torvalds static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
2519bcf7f6e3SHans de Goede {
2520bcf7f6e3SHans de Goede 	unsigned num_eps;
2521bcf7f6e3SHans de Goede 	struct usb_host_endpoint **eps;
2522bcf7f6e3SHans de Goede 	struct usb_interface *intf;
2523bcf7f6e3SHans de Goede 	int r;
2524bcf7f6e3SHans de Goede 
2525bcf7f6e3SHans de Goede 	r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
2526bcf7f6e3SHans de Goede 	if (r)
2527bcf7f6e3SHans de Goede 		return r;
2528bcf7f6e3SHans de Goede 
2529bcf7f6e3SHans de Goede 	destroy_async_on_interface(ps,
2530bcf7f6e3SHans de Goede 				   intf->altsetting[0].desc.bInterfaceNumber);
2531bcf7f6e3SHans de Goede 
2532bcf7f6e3SHans de Goede 	r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
2533bcf7f6e3SHans de Goede 	kfree(eps);
2534bcf7f6e3SHans de Goede 	return r;
2535bcf7f6e3SHans de Goede }
2536bcf7f6e3SHans de Goede 
proc_drop_privileges(struct usb_dev_state * ps,void __user * arg)2537d883f52eSReilly Grant static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
2538d883f52eSReilly Grant {
2539d883f52eSReilly Grant 	u32 data;
2540d883f52eSReilly Grant 
2541d883f52eSReilly Grant 	if (copy_from_user(&data, arg, sizeof(data)))
2542d883f52eSReilly Grant 		return -EFAULT;
2543d883f52eSReilly Grant 
25440f5e1558SMasahiro Yamada 	/* This is a one way operation. Once privileges are
2545d883f52eSReilly Grant 	 * dropped, you cannot regain them. You may however reissue
2546d883f52eSReilly Grant 	 * this ioctl to shrink the allowed interfaces mask.
2547d883f52eSReilly Grant 	 */
2548d883f52eSReilly Grant 	ps->interface_allowed_mask &= data;
2549d883f52eSReilly Grant 	ps->privileges_dropped = true;
2550d883f52eSReilly Grant 
2551d883f52eSReilly Grant 	return 0;
2552d883f52eSReilly Grant }
2553d883f52eSReilly Grant 
proc_forbid_suspend(struct usb_dev_state * ps)25547794f486SAlan Stern static int proc_forbid_suspend(struct usb_dev_state *ps)
25557794f486SAlan Stern {
25567794f486SAlan Stern 	int ret = 0;
25577794f486SAlan Stern 
25587794f486SAlan Stern 	if (ps->suspend_allowed) {
25597794f486SAlan Stern 		ret = usb_autoresume_device(ps->dev);
25607794f486SAlan Stern 		if (ret == 0)
25617794f486SAlan Stern 			ps->suspend_allowed = false;
25627794f486SAlan Stern 		else if (ret != -ENODEV)
25637794f486SAlan Stern 			ret = -EIO;
25647794f486SAlan Stern 	}
25657794f486SAlan Stern 	return ret;
25667794f486SAlan Stern }
25677794f486SAlan Stern 
proc_allow_suspend(struct usb_dev_state * ps)25687794f486SAlan Stern static int proc_allow_suspend(struct usb_dev_state *ps)
25697794f486SAlan Stern {
25707794f486SAlan Stern 	if (!connected(ps))
25717794f486SAlan Stern 		return -ENODEV;
25727794f486SAlan Stern 
25737794f486SAlan Stern 	WRITE_ONCE(ps->not_yet_resumed, 1);
25747794f486SAlan Stern 	if (!ps->suspend_allowed) {
25757794f486SAlan Stern 		usb_autosuspend_device(ps->dev);
25767794f486SAlan Stern 		ps->suspend_allowed = true;
25777794f486SAlan Stern 	}
25787794f486SAlan Stern 	return 0;
25797794f486SAlan Stern }
25807794f486SAlan Stern 
proc_wait_for_resume(struct usb_dev_state * ps)25817794f486SAlan Stern static int proc_wait_for_resume(struct usb_dev_state *ps)
25827794f486SAlan Stern {
25837794f486SAlan Stern 	int ret;
25847794f486SAlan Stern 
25857794f486SAlan Stern 	usb_unlock_device(ps->dev);
25867794f486SAlan Stern 	ret = wait_event_interruptible(ps->wait_for_resume,
25877794f486SAlan Stern 			READ_ONCE(ps->not_yet_resumed) == 0);
25887794f486SAlan Stern 	usb_lock_device(ps->dev);
25897794f486SAlan Stern 
25907794f486SAlan Stern 	if (ret != 0)
25917794f486SAlan Stern 		return -EINTR;
25927794f486SAlan Stern 	return proc_forbid_suspend(ps);
25937794f486SAlan Stern }
25947794f486SAlan Stern 
25951da177e4SLinus Torvalds /*
25961da177e4SLinus Torvalds  * NOTE:  All requests here that have interface numbers as parameters
25971da177e4SLinus Torvalds  * are assuming that somehow the configuration has been prevented from
25981da177e4SLinus Torvalds  * changing.  But there's no mechanism to ensure that...
25991da177e4SLinus Torvalds  */
usbdev_do_ioctl(struct file * file,unsigned int cmd,void __user * p)2600637e8a60SArnd Bergmann static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2601637e8a60SArnd Bergmann 				void __user *p)
26021da177e4SLinus Torvalds {
26039b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
2604496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
26051da177e4SLinus Torvalds 	struct usb_device *dev = ps->dev;
26061da177e4SLinus Torvalds 	int ret = -ENOTTY;
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 	if (!(file->f_mode & FMODE_WRITE))
26091da177e4SLinus Torvalds 		return -EPERM;
261001412a21SOliver Neukum 
26111da177e4SLinus Torvalds 	usb_lock_device(dev);
26123f2cee73SAlan Stern 
26133f2cee73SAlan Stern 	/* Reap operations are allowed even after disconnection */
26143f2cee73SAlan Stern 	switch (cmd) {
26153f2cee73SAlan Stern 	case USBDEVFS_REAPURB:
26163f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURB\n", __func__);
26173f2cee73SAlan Stern 		ret = proc_reapurb(ps, p);
26183f2cee73SAlan Stern 		goto done;
26193f2cee73SAlan Stern 
26203f2cee73SAlan Stern 	case USBDEVFS_REAPURBNDELAY:
26213f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
26223f2cee73SAlan Stern 		ret = proc_reapurbnonblock(ps, p);
26233f2cee73SAlan Stern 		goto done;
26243f2cee73SAlan Stern 
26253f2cee73SAlan Stern #ifdef CONFIG_COMPAT
26263f2cee73SAlan Stern 	case USBDEVFS_REAPURB32:
26273f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURB32\n", __func__);
26283f2cee73SAlan Stern 		ret = proc_reapurb_compat(ps, p);
26293f2cee73SAlan Stern 		goto done;
26303f2cee73SAlan Stern 
26313f2cee73SAlan Stern 	case USBDEVFS_REAPURBNDELAY32:
26323f2cee73SAlan Stern 		snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
26333f2cee73SAlan Stern 		ret = proc_reapurbnonblock_compat(ps, p);
26343f2cee73SAlan Stern 		goto done;
26353f2cee73SAlan Stern #endif
26363f2cee73SAlan Stern 	}
26373f2cee73SAlan Stern 
2638349710c3SAlan Stern 	if (!connected(ps)) {
26391da177e4SLinus Torvalds 		usb_unlock_device(dev);
26401da177e4SLinus Torvalds 		return -ENODEV;
26411da177e4SLinus Torvalds 	}
26421da177e4SLinus Torvalds 
26431da177e4SLinus Torvalds 	switch (cmd) {
26441da177e4SLinus Torvalds 	case USBDEVFS_CONTROL:
2645441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CONTROL\n", __func__);
26461da177e4SLinus Torvalds 		ret = proc_control(ps, p);
26471da177e4SLinus Torvalds 		if (ret >= 0)
26482b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
26492b450e92SJeff Layton 					      inode_set_ctime_current(inode));
26501da177e4SLinus Torvalds 		break;
26511da177e4SLinus Torvalds 
26521da177e4SLinus Torvalds 	case USBDEVFS_BULK:
2653441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: BULK\n", __func__);
26541da177e4SLinus Torvalds 		ret = proc_bulk(ps, p);
26551da177e4SLinus Torvalds 		if (ret >= 0)
26562b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
26572b450e92SJeff Layton 					      inode_set_ctime_current(inode));
26581da177e4SLinus Torvalds 		break;
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds 	case USBDEVFS_RESETEP:
2661441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RESETEP\n", __func__);
26621da177e4SLinus Torvalds 		ret = proc_resetep(ps, p);
26631da177e4SLinus Torvalds 		if (ret >= 0)
26642b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
26652b450e92SJeff Layton 					      inode_set_ctime_current(inode));
26661da177e4SLinus Torvalds 		break;
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	case USBDEVFS_RESET:
2669441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RESET\n", __func__);
26701da177e4SLinus Torvalds 		ret = proc_resetdevice(ps);
26711da177e4SLinus Torvalds 		break;
26721da177e4SLinus Torvalds 
26731da177e4SLinus Torvalds 	case USBDEVFS_CLEAR_HALT:
2674441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
26751da177e4SLinus Torvalds 		ret = proc_clearhalt(ps, p);
26761da177e4SLinus Torvalds 		if (ret >= 0)
26772b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
26782b450e92SJeff Layton 					      inode_set_ctime_current(inode));
26791da177e4SLinus Torvalds 		break;
26801da177e4SLinus Torvalds 
26811da177e4SLinus Torvalds 	case USBDEVFS_GETDRIVER:
2682441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
26831da177e4SLinus Torvalds 		ret = proc_getdriver(ps, p);
26841da177e4SLinus Torvalds 		break;
26851da177e4SLinus Torvalds 
26861da177e4SLinus Torvalds 	case USBDEVFS_CONNECTINFO:
2687441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
26881da177e4SLinus Torvalds 		ret = proc_connectinfo(ps, p);
26891da177e4SLinus Torvalds 		break;
26901da177e4SLinus Torvalds 
26911da177e4SLinus Torvalds 	case USBDEVFS_SETINTERFACE:
2692441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
26931da177e4SLinus Torvalds 		ret = proc_setintf(ps, p);
26941da177e4SLinus Torvalds 		break;
26951da177e4SLinus Torvalds 
26961da177e4SLinus Torvalds 	case USBDEVFS_SETCONFIGURATION:
2697441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
26981da177e4SLinus Torvalds 		ret = proc_setconfig(ps, p);
26991da177e4SLinus Torvalds 		break;
27001da177e4SLinus Torvalds 
27011da177e4SLinus Torvalds 	case USBDEVFS_SUBMITURB:
2702441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
27031da177e4SLinus Torvalds 		ret = proc_submiturb(ps, p);
27041da177e4SLinus Torvalds 		if (ret >= 0)
27052b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
27062b450e92SJeff Layton 					      inode_set_ctime_current(inode));
27071da177e4SLinus Torvalds 		break;
27081da177e4SLinus Torvalds 
27091da177e4SLinus Torvalds #ifdef CONFIG_COMPAT
2710637e8a60SArnd Bergmann 	case USBDEVFS_CONTROL32:
2711637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: CONTROL32\n", __func__);
2712637e8a60SArnd Bergmann 		ret = proc_control_compat(ps, p);
2713637e8a60SArnd Bergmann 		if (ret >= 0)
27142b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
27152b450e92SJeff Layton 					      inode_set_ctime_current(inode));
2716637e8a60SArnd Bergmann 		break;
2717637e8a60SArnd Bergmann 
2718637e8a60SArnd Bergmann 	case USBDEVFS_BULK32:
2719637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: BULK32\n", __func__);
2720637e8a60SArnd Bergmann 		ret = proc_bulk_compat(ps, p);
2721637e8a60SArnd Bergmann 		if (ret >= 0)
27222b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
27232b450e92SJeff Layton 					      inode_set_ctime_current(inode));
2724637e8a60SArnd Bergmann 		break;
2725637e8a60SArnd Bergmann 
2726637e8a60SArnd Bergmann 	case USBDEVFS_DISCSIGNAL32:
2727637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
2728637e8a60SArnd Bergmann 		ret = proc_disconnectsignal_compat(ps, p);
2729637e8a60SArnd Bergmann 		break;
27301da177e4SLinus Torvalds 
27311da177e4SLinus Torvalds 	case USBDEVFS_SUBMITURB32:
2732441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
27331da177e4SLinus Torvalds 		ret = proc_submiturb_compat(ps, p);
27341da177e4SLinus Torvalds 		if (ret >= 0)
27352b450e92SJeff Layton 			inode_set_mtime_to_ts(inode,
27362b450e92SJeff Layton 					      inode_set_ctime_current(inode));
27371da177e4SLinus Torvalds 		break;
27381da177e4SLinus Torvalds 
2739c36fc889SPete Zaitcev 	case USBDEVFS_IOCTL32:
2740637e8a60SArnd Bergmann 		snoop(&dev->dev, "%s: IOCTL32\n", __func__);
2741c714de5dSAl Viro 		ret = proc_ioctl_compat(ps, ptr_to_compat(p));
2742c36fc889SPete Zaitcev 		break;
27431da177e4SLinus Torvalds #endif
27441da177e4SLinus Torvalds 
27451da177e4SLinus Torvalds 	case USBDEVFS_DISCARDURB:
2746f3bc432aSAlan Stern 		snoop(&dev->dev, "%s: DISCARDURB %px\n", __func__, p);
27471da177e4SLinus Torvalds 		ret = proc_unlinkurb(ps, p);
27481da177e4SLinus Torvalds 		break;
27491da177e4SLinus Torvalds 
27501da177e4SLinus Torvalds 	case USBDEVFS_DISCSIGNAL:
2751441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
27521da177e4SLinus Torvalds 		ret = proc_disconnectsignal(ps, p);
27531da177e4SLinus Torvalds 		break;
27541da177e4SLinus Torvalds 
27551da177e4SLinus Torvalds 	case USBDEVFS_CLAIMINTERFACE:
2756441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
27571da177e4SLinus Torvalds 		ret = proc_claiminterface(ps, p);
27581da177e4SLinus Torvalds 		break;
27591da177e4SLinus Torvalds 
27601da177e4SLinus Torvalds 	case USBDEVFS_RELEASEINTERFACE:
2761441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
27621da177e4SLinus Torvalds 		ret = proc_releaseinterface(ps, p);
27631da177e4SLinus Torvalds 		break;
27641da177e4SLinus Torvalds 
27651da177e4SLinus Torvalds 	case USBDEVFS_IOCTL:
2766441b62c1SHarvey Harrison 		snoop(&dev->dev, "%s: IOCTL\n", __func__);
2767c36fc889SPete Zaitcev 		ret = proc_ioctl_default(ps, p);
27681da177e4SLinus Torvalds 		break;
27697cbe5dcaSAlan Stern 
27707cbe5dcaSAlan Stern 	case USBDEVFS_CLAIM_PORT:
27717cbe5dcaSAlan Stern 		snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
27727cbe5dcaSAlan Stern 		ret = proc_claim_port(ps, p);
27737cbe5dcaSAlan Stern 		break;
27747cbe5dcaSAlan Stern 
27757cbe5dcaSAlan Stern 	case USBDEVFS_RELEASE_PORT:
27767cbe5dcaSAlan Stern 		snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
27777cbe5dcaSAlan Stern 		ret = proc_release_port(ps, p);
27787cbe5dcaSAlan Stern 		break;
277919181bc5SHans de Goede 	case USBDEVFS_GET_CAPABILITIES:
278019181bc5SHans de Goede 		ret = proc_get_capabilities(ps, p);
278119181bc5SHans de Goede 		break;
27820837e7e5SHans de Goede 	case USBDEVFS_DISCONNECT_CLAIM:
27830837e7e5SHans de Goede 		ret = proc_disconnect_claim(ps, p);
27840837e7e5SHans de Goede 		break;
2785bcf7f6e3SHans de Goede 	case USBDEVFS_ALLOC_STREAMS:
2786bcf7f6e3SHans de Goede 		ret = proc_alloc_streams(ps, p);
2787bcf7f6e3SHans de Goede 		break;
2788bcf7f6e3SHans de Goede 	case USBDEVFS_FREE_STREAMS:
2789bcf7f6e3SHans de Goede 		ret = proc_free_streams(ps, p);
2790bcf7f6e3SHans de Goede 		break;
2791d883f52eSReilly Grant 	case USBDEVFS_DROP_PRIVILEGES:
2792d883f52eSReilly Grant 		ret = proc_drop_privileges(ps, p);
2793d883f52eSReilly Grant 		break;
2794c01b244aSAlan Stern 	case USBDEVFS_GET_SPEED:
2795c01b244aSAlan Stern 		ret = ps->dev->speed;
2796c01b244aSAlan Stern 		break;
27977794f486SAlan Stern 	case USBDEVFS_FORBID_SUSPEND:
27987794f486SAlan Stern 		ret = proc_forbid_suspend(ps);
27997794f486SAlan Stern 		break;
28007794f486SAlan Stern 	case USBDEVFS_ALLOW_SUSPEND:
28017794f486SAlan Stern 		ret = proc_allow_suspend(ps);
28027794f486SAlan Stern 		break;
28037794f486SAlan Stern 	case USBDEVFS_WAIT_FOR_RESUME:
28047794f486SAlan Stern 		ret = proc_wait_for_resume(ps);
28057794f486SAlan Stern 		break;
28061da177e4SLinus Torvalds 	}
28073f2cee73SAlan Stern 
28086d101f24SDmitry Torokhov 	/* Handle variable-length commands */
28096d101f24SDmitry Torokhov 	switch (cmd & ~IOCSIZE_MASK) {
28106d101f24SDmitry Torokhov 	case USBDEVFS_CONNINFO_EX(0):
28116d101f24SDmitry Torokhov 		ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
28126d101f24SDmitry Torokhov 		break;
28136d101f24SDmitry Torokhov 	}
28146d101f24SDmitry Torokhov 
28153f2cee73SAlan Stern  done:
28161da177e4SLinus Torvalds 	usb_unlock_device(dev);
28171da177e4SLinus Torvalds 	if (ret >= 0)
28182b450e92SJeff Layton 		inode_set_atime_to_ts(inode, current_time(inode));
28191da177e4SLinus Torvalds 	return ret;
28201da177e4SLinus Torvalds }
28211da177e4SLinus Torvalds 
usbdev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)2822637e8a60SArnd Bergmann static long usbdev_ioctl(struct file *file, unsigned int cmd,
2823637e8a60SArnd Bergmann 			unsigned long arg)
2824637e8a60SArnd Bergmann {
2825637e8a60SArnd Bergmann 	int ret;
2826637e8a60SArnd Bergmann 
2827637e8a60SArnd Bergmann 	ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
2828637e8a60SArnd Bergmann 
2829637e8a60SArnd Bergmann 	return ret;
2830637e8a60SArnd Bergmann }
2831637e8a60SArnd Bergmann 
28321da177e4SLinus Torvalds /* No kernel lock - fine */
usbdev_poll(struct file * file,struct poll_table_struct * wait)2833afc9a42bSAl Viro static __poll_t usbdev_poll(struct file *file,
283404e482ffSGreg Kroah-Hartman 				struct poll_table_struct *wait)
28351da177e4SLinus Torvalds {
28369b6f0c4bSValentina Manea 	struct usb_dev_state *ps = file->private_data;
2837afc9a42bSAl Viro 	__poll_t mask = 0;
28381da177e4SLinus Torvalds 
28391da177e4SLinus Torvalds 	poll_wait(file, &ps->wait, wait);
28401da177e4SLinus Torvalds 	if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
2841a9a08845SLinus Torvalds 		mask |= EPOLLOUT | EPOLLWRNORM;
2842349710c3SAlan Stern 	if (!connected(ps))
2843a9a08845SLinus Torvalds 		mask |= EPOLLHUP;
28445cce4382SAlan Stern 	if (list_empty(&ps->list))
2845a9a08845SLinus Torvalds 		mask |= EPOLLERR;
28461da177e4SLinus Torvalds 	return mask;
28471da177e4SLinus Torvalds }
28481da177e4SLinus Torvalds 
28499f8b17e6SKay Sievers const struct file_operations usbdev_file_operations = {
28507e7654a9SGreg Kroah-Hartman 	.owner =	  THIS_MODULE,
2851b25472f9SAl Viro 	.llseek =	  no_seek_end_llseek,
28521da177e4SLinus Torvalds 	.read =		  usbdev_read,
28531da177e4SLinus Torvalds 	.poll =		  usbdev_poll,
2854637e8a60SArnd Bergmann 	.unlocked_ioctl = usbdev_ioctl,
2855407e9ef7SArnd Bergmann 	.compat_ioctl =   compat_ptr_ioctl,
2856f7d34b44SSteinar H. Gunderson 	.mmap =           usbdev_mmap,
28571da177e4SLinus Torvalds 	.open =		  usbdev_open,
28581da177e4SLinus Torvalds 	.release =	  usbdev_release,
28591da177e4SLinus Torvalds };
2860fbf82fd2SKay Sievers 
usbdev_remove(struct usb_device * udev)2861501950d8SAlan Stern static void usbdev_remove(struct usb_device *udev)
2862cd9f0375SAlan Stern {
28639b6f0c4bSValentina Manea 	struct usb_dev_state *ps;
2864cd9f0375SAlan Stern 
28657794f486SAlan Stern 	/* Protect against simultaneous resume */
28667794f486SAlan Stern 	mutex_lock(&usbfs_mutex);
2867cd9f0375SAlan Stern 	while (!list_empty(&udev->filelist)) {
28689b6f0c4bSValentina Manea 		ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
2869cd9f0375SAlan Stern 		destroy_all_async(ps);
2870cd9f0375SAlan Stern 		wake_up_all(&ps->wait);
28717794f486SAlan Stern 		WRITE_ONCE(ps->not_yet_resumed, 0);
28727794f486SAlan Stern 		wake_up_all(&ps->wait_for_resume);
2873cd9f0375SAlan Stern 		list_del_init(&ps->list);
287470f1b0d3SEric W. Biederman 		if (ps->discsignr)
287570f1b0d3SEric W. Biederman 			kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext,
28766b4f3d01SStephen Smalley 					     ps->disc_pid, ps->cred);
2877cd9f0375SAlan Stern 	}
28787794f486SAlan Stern 	mutex_unlock(&usbfs_mutex);
2879cd9f0375SAlan Stern }
2880cd9f0375SAlan Stern 
usbdev_notify(struct notifier_block * self,unsigned long action,void * dev)2881501950d8SAlan Stern static int usbdev_notify(struct notifier_block *self,
28829f8b17e6SKay Sievers 			       unsigned long action, void *dev)
2883a7b986b3SGreg Kroah-Hartman {
2884a7b986b3SGreg Kroah-Hartman 	switch (action) {
2885a7b986b3SGreg Kroah-Hartman 	case USB_DEVICE_ADD:
2886a7b986b3SGreg Kroah-Hartman 		break;
2887a7b986b3SGreg Kroah-Hartman 	case USB_DEVICE_REMOVE:
2888501950d8SAlan Stern 		usbdev_remove(dev);
2889a7b986b3SGreg Kroah-Hartman 		break;
2890a7b986b3SGreg Kroah-Hartman 	}
2891a7b986b3SGreg Kroah-Hartman 	return NOTIFY_OK;
2892a7b986b3SGreg Kroah-Hartman }
2893a7b986b3SGreg Kroah-Hartman 
2894a7b986b3SGreg Kroah-Hartman static struct notifier_block usbdev_nb = {
2895501950d8SAlan Stern 	.notifier_call =	usbdev_notify,
2896a7b986b3SGreg Kroah-Hartman };
2897a7b986b3SGreg Kroah-Hartman 
28987e7654a9SGreg Kroah-Hartman static struct cdev usb_device_cdev;
2899fbf82fd2SKay Sievers 
usb_devio_init(void)29009f8b17e6SKay Sievers int __init usb_devio_init(void)
2901fbf82fd2SKay Sievers {
2902fbf82fd2SKay Sievers 	int retval;
2903fbf82fd2SKay Sievers 
2904fad21bdfSAlan Stern 	retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
2905fad21bdfSAlan Stern 					"usb_device");
2906fbf82fd2SKay Sievers 	if (retval) {
290769a85942SGreg Kroah-Hartman 		printk(KERN_ERR "Unable to register minors for usb_device\n");
2908fbf82fd2SKay Sievers 		goto out;
2909fbf82fd2SKay Sievers 	}
29109f8b17e6SKay Sievers 	cdev_init(&usb_device_cdev, &usbdev_file_operations);
2911fad21bdfSAlan Stern 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
2912fbf82fd2SKay Sievers 	if (retval) {
291369a85942SGreg Kroah-Hartman 		printk(KERN_ERR "Unable to get usb_device major %d\n",
291469a85942SGreg Kroah-Hartman 		       USB_DEVICE_MAJOR);
2915a7b986b3SGreg Kroah-Hartman 		goto error_cdev;
2916fbf82fd2SKay Sievers 	}
2917501950d8SAlan Stern 	usb_register_notify(&usbdev_nb);
2918fbf82fd2SKay Sievers out:
2919fbf82fd2SKay Sievers 	return retval;
2920a7b986b3SGreg Kroah-Hartman 
2921a7b986b3SGreg Kroah-Hartman error_cdev:
2922a7b986b3SGreg Kroah-Hartman 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
2923a7b986b3SGreg Kroah-Hartman 	goto out;
2924fbf82fd2SKay Sievers }
2925fbf82fd2SKay Sievers 
usb_devio_cleanup(void)29269f8b17e6SKay Sievers void usb_devio_cleanup(void)
2927fbf82fd2SKay Sievers {
2928a7b986b3SGreg Kroah-Hartman 	usb_unregister_notify(&usbdev_nb);
2929fbf82fd2SKay Sievers 	cdev_del(&usb_device_cdev);
2930fad21bdfSAlan Stern 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
2931fbf82fd2SKay Sievers }
2932