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