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