devio.c 33.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*****************************************************************************/

/*
 *      devio.c  --  User space communication with USB devices.
 *
 *      Copyright (C) 1999-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
 *
 *  This file implements the usbdevfs/x/y files, where
 *  x is the bus number and y the device number.
 *
 *  It allows user space programs/"drivers" to communicate directly
 *  with USB devices without intervening kernel driver.
 *
 *  Revision history
 *    22.12.1999   0.1   Initial release (split from proc_usb.c)
 *    04.01.2000   0.2   Turned into its own filesystem
 */

/*****************************************************************************/

#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
Linus Torvalds's avatar
Linus Torvalds committed
43
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
44 45 46
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <asm/uaccess.h>
47
#include <asm/byteorder.h>
Linus Torvalds's avatar
Linus Torvalds committed
48

David Brownell's avatar
David Brownell committed
49
#include "hcd.h"	/* for usbcore internals */
50
#include "usb.h"
Linus Torvalds's avatar
Linus Torvalds committed
51 52

struct async {
53 54
	struct list_head asynclist;
	struct dev_state *ps;
Linus Torvalds's avatar
Linus Torvalds committed
55 56
	struct task_struct *task;
	unsigned int signr;
57
	unsigned int intf;
58 59 60
	void __user *userbuffer;
	void __user *userurb;
	struct urb *urb;
Linus Torvalds's avatar
Linus Torvalds committed
61 62
};

63 64 65 66 67
static inline int connected (struct usb_device *dev)
{
	return dev->state != USB_STATE_NOTATTACHED;
}

Linus Torvalds's avatar
Linus Torvalds committed
68 69
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
70 71 72 73
	loff_t ret;

	lock_kernel();

Linus Torvalds's avatar
Linus Torvalds committed
74 75 76
	switch (orig) {
	case 0:
		file->f_pos = offset;
77 78
		ret = file->f_pos;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
79 80
	case 1:
		file->f_pos += offset;
81 82
		ret = file->f_pos;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
83 84
	case 2:
	default:
85
		ret = -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
86
	}
87 88 89

	unlock_kernel();
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
90 91
}

92
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
93 94
{
	struct dev_state *ps = (struct dev_state *)file->private_data;
95
	struct usb_device *dev = ps->dev;
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98 99 100 101
	ssize_t ret = 0;
	unsigned len;
	loff_t pos;
	int i;

	pos = *ppos;
102 103
	down(&dev->serialize);
	if (!connected(dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
104 105 106 107 108 109 110 111 112 113 114
		ret = -ENODEV;
		goto err;
	} else if (pos < 0) {
		ret = -EINVAL;
		goto err;
	}

	if (pos < sizeof(struct usb_device_descriptor)) {
		len = sizeof(struct usb_device_descriptor) - pos;
		if (len > nbytes)
			len = nbytes;
115
		if (copy_to_user(buf, ((char *)&dev->descriptor) + pos, len)) {
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119 120 121 122 123 124 125 126
			ret = -EFAULT;
			goto err;
		}

		*ppos += len;
		buf += len;
		nbytes -= len;
		ret += len;
	}

	pos = sizeof(struct usb_device_descriptor);
127
	for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
128
		struct usb_config_descriptor *config =
129
			(struct usb_config_descriptor *)dev->rawdescriptors[i];
Linus Torvalds's avatar
Linus Torvalds committed
130 131 132
		unsigned int length = le16_to_cpu(config->wTotalLength);

		if (*ppos < pos + length) {
133 134 135 136

			/* The descriptor may claim to be longer than it
			 * really is.  Here is the actual allocated length. */
			unsigned alloclen =
137
				dev->config[i].desc.wTotalLength;
138

Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142
			len = length - (*ppos - pos);
			if (len > nbytes)
				len = nbytes;

143 144 145 146
			/* Simply don't write (skip over) unallocated parts */
			if (alloclen > (*ppos - pos)) {
				alloclen -= (*ppos - pos);
				if (copy_to_user(buf,
147
				    dev->rawdescriptors[i] + (*ppos - pos),
148 149 150 151
				    min(len, alloclen))) {
					ret = -EFAULT;
					goto err;
				}
Linus Torvalds's avatar
Linus Torvalds committed
152 153 154 155 156 157 158 159 160 161 162 163
			}

			*ppos += len;
			buf += len;
			nbytes -= len;
			ret += len;
		}

		pos += length;
	}

err:
164
	up(&dev->serialize);
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	return ret;
}

extern inline unsigned int ld2(unsigned int x)
{
        unsigned int r = 0;
        
        if (x >= 0x10000) {
                x >>= 16;
                r += 16;
        }
        if (x >= 0x100) {
                x >>= 8;
                r += 8;
        }
        if (x >= 0x10) {
                x >>= 4;
                r += 4;
        }
        if (x >= 4) {
                x >>= 2;
                r += 2;
        }
        if (x >= 2)
                r++;
        return r;
}

/*
 * async list handling
 */

static struct async *alloc_async(unsigned int numisoframes)
{
Linus Torvalds's avatar
Linus Torvalds committed
199
        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203
        struct async *as = kmalloc(assize, GFP_KERNEL);
        if (!as)
                return NULL;
        memset(as, 0, assize);
204
	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
205 206 207 208
	if (!as->urb) {
		kfree(as);
		return NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
209 210 211 212 213
        return as;
}

static void free_async(struct async *as)
{
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216 217 218
        if (as->urb->transfer_buffer)
                kfree(as->urb->transfer_buffer);
        if (as->urb->setup_packet)
                kfree(as->urb->setup_packet);
	usb_free_urb(as->urb);
Linus Torvalds's avatar
Linus Torvalds committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        kfree(as);
}

extern __inline__ void async_newpending(struct async *as)
{
        struct dev_state *ps = as->ps;
        unsigned long flags;
        
        spin_lock_irqsave(&ps->lock, flags);
        list_add_tail(&as->asynclist, &ps->async_pending);
        spin_unlock_irqrestore(&ps->lock, flags);
}

extern __inline__ void async_removepending(struct async *as)
{
        struct dev_state *ps = as->ps;
        unsigned long flags;
        
        spin_lock_irqsave(&ps->lock, flags);
238
        list_del_init(&as->asynclist);
Linus Torvalds's avatar
Linus Torvalds committed
239 240 241 242 243 244 245 246 247 248 249
        spin_unlock_irqrestore(&ps->lock, flags);
}

extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
{
        unsigned long flags;
        struct async *as = NULL;

        spin_lock_irqsave(&ps->lock, flags);
        if (!list_empty(&ps->async_completed)) {
                as = list_entry(ps->async_completed.next, struct async, asynclist);
250
                list_del_init(&as->asynclist);
Linus Torvalds's avatar
Linus Torvalds committed
251 252 253 254 255
        }
        spin_unlock_irqrestore(&ps->lock, flags);
        return as;
}

256
extern __inline__ struct async *async_getpending(struct dev_state *ps, void __user *userurb)
Linus Torvalds's avatar
Linus Torvalds committed
257 258 259 260 261
{
        unsigned long flags;
        struct async *as;

        spin_lock_irqsave(&ps->lock, flags);
262 263 264 265 266 267
	list_for_each_entry(as, &ps->async_pending, asynclist)
		if (as->userurb == userurb) {
			list_del_init(&as->asynclist);
			spin_unlock_irqrestore(&ps->lock, flags);
			return as;
		}
Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271
        spin_unlock_irqrestore(&ps->lock, flags);
        return NULL;
}

David S. Miller's avatar
David S. Miller committed
272
static void async_completed(struct urb *urb, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
273 274 275 276 277 278
{
        struct async *as = (struct async *)urb->context;
        struct dev_state *ps = as->ps;
	struct siginfo sinfo;

        spin_lock(&ps->lock);
279
        list_move_tail(&as->asynclist, &ps->async_completed);
Linus Torvalds's avatar
Linus Torvalds committed
280 281 282
        spin_unlock(&ps->lock);
	if (as->signr) {
		sinfo.si_signo = as->signr;
Linus Torvalds's avatar
Linus Torvalds committed
283
		sinfo.si_errno = as->urb->status;
Linus Torvalds's avatar
Linus Torvalds committed
284
		sinfo.si_code = SI_ASYNCIO;
285
		sinfo.si_addr = (void *)as->userurb;
Linus Torvalds's avatar
Linus Torvalds committed
286 287
		send_sig_info(as->signr, &sinfo, as->task);
	}
288
        wake_up(&ps->wait);
Linus Torvalds's avatar
Linus Torvalds committed
289 290
}

291
static void destroy_async (struct dev_state *ps, struct list_head *list)
Linus Torvalds's avatar
Linus Torvalds committed
292
{
293 294
	struct async *as;
	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
295

296 297 298 299 300
	spin_lock_irqsave(&ps->lock, flags);
	while (!list_empty(list)) {
		as = list_entry(list->next, struct async, asynclist);
		list_del_init(&as->asynclist);
		spin_unlock_irqrestore(&ps->lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
301
                /* usb_unlink_urb calls the completion handler with status == -ENOENT */
302 303 304 305 306 307 308 309 310 311
		usb_unlink_urb(as->urb);
		spin_lock_irqsave(&ps->lock, flags);
	}
	spin_unlock_irqrestore(&ps->lock, flags);
	while ((as = async_getcompleted(ps)))
		free_async(as);
}

static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
{
312
	struct list_head *p, *q, hitlist;
313 314 315 316
	unsigned long flags;

	INIT_LIST_HEAD(&hitlist);
	spin_lock_irqsave(&ps->lock, flags);
317 318 319
	list_for_each_safe(p, q, &ps->async_pending)
		if (intf == list_entry(p, struct async, asynclist)->intf)
			list_move_tail(p, &hitlist);
320 321 322 323 324 325 326
	spin_unlock_irqrestore(&ps->lock, flags);
	destroy_async(ps, &hitlist);
}

extern __inline__ void destroy_all_async(struct dev_state *ps)
{
	        destroy_async(ps, &ps->async_pending);
Linus Torvalds's avatar
Linus Torvalds committed
327 328 329
}

/*
330 331 332
 * interface claims are made only at the request of user level code,
 * which can also release them (explicitly or by closing files).
 * they're also undone when devices disconnect.
Linus Torvalds's avatar
Linus Torvalds committed
333 334
 */

335 336
static int driver_probe (struct usb_interface *intf,
			 const struct usb_device_id *id)
Linus Torvalds's avatar
Linus Torvalds committed
337
{
338
	return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
339 340
}

341
static void driver_disconnect(struct usb_interface *intf)
Linus Torvalds's avatar
Linus Torvalds committed
342
{
343
	struct dev_state *ps = usb_get_intfdata (intf);
344
	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
Linus Torvalds's avatar
Linus Torvalds committed
345

346 347 348
	if (!ps)
		return;

349 350 351
	/* NOTE:  this relies on usbcore having canceled and completed
	 * all pending I/O requests; 2.6 does that.
	 */
352

353 354
	if (ifnum < 8*sizeof(ps->ifclaimed))
		clear_bit(ifnum, &ps->ifclaimed);
355
	usb_set_intfdata (intf, NULL);
356 357

	/* force async requests to complete */
358
	destroy_async_on_interface(ps, ifnum);
Linus Torvalds's avatar
Linus Torvalds committed
359 360 361
}

struct usb_driver usbdevfs_driver = {
362
	.owner =	THIS_MODULE,
363 364 365
	.name =		"usbfs",
	.probe =	driver_probe,
	.disconnect =	driver_disconnect,
Linus Torvalds's avatar
Linus Torvalds committed
366 367 368 369 370 371 372 373
};

static int claimintf(struct dev_state *ps, unsigned int intf)
{
	struct usb_device *dev = ps->dev;
	struct usb_interface *iface;
	int err;

374
	if (intf >= 8*sizeof(ps->ifclaimed)
375
			|| intf >= dev->actconfig->desc.bNumInterfaces)
Linus Torvalds's avatar
Linus Torvalds committed
376 377 378 379
		return -EINVAL;
	/* already claimed */
	if (test_bit(intf, &ps->ifclaimed))
		return 0;
380
	iface = dev->actconfig->interface[intf];
Linus Torvalds's avatar
Linus Torvalds committed
381
	err = -EBUSY;
382 383 384

	/* lock against other changes to driver bindings */
	down_write(&usb_bus_type.subsys.rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
385 386 387 388 389
	if (!usb_interface_claimed(iface)) {
		usb_driver_claim_interface(&usbdevfs_driver, iface, ps);
		set_bit(intf, &ps->ifclaimed);
		err = 0;
	}
390
	up_write(&usb_bus_type.subsys.rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
391 392 393 394 395 396 397 398 399 400 401 402 403
	return err;
}

static int releaseintf(struct dev_state *ps, unsigned int intf)
{
	struct usb_device *dev;
	struct usb_interface *iface;
	int err;

	if (intf >= 8*sizeof(ps->ifclaimed))
		return -EINVAL;
	err = -EINVAL;
	dev = ps->dev;
404 405
	/* lock against other changes to driver bindings */
	down_write(&usb_bus_type.subsys.rwsem);
406
	if (test_and_clear_bit(intf, &ps->ifclaimed)) {
407
		iface = dev->actconfig->interface[intf];
Linus Torvalds's avatar
Linus Torvalds committed
408 409 410
		usb_driver_release_interface(&usbdevfs_driver, iface);
		err = 0;
	}
411
	up_write(&usb_bus_type.subsys.rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
412 413 414 415 416 417 418 419 420 421
	return err;
}

static int checkintf(struct dev_state *ps, unsigned int intf)
{
	if (intf >= 8*sizeof(ps->ifclaimed))
		return -EINVAL;
	if (test_bit(intf, &ps->ifclaimed))
		return 0;
	/* if not yet claimed, claim it for the driver */
422
	printk(KERN_WARNING "usbfs: process %d (%s) did not claim interface %u before use\n",
Linus Torvalds's avatar
Linus Torvalds committed
423 424 425 426 427 428 429 430
	       current->pid, current->comm, intf);
	return claimintf(ps, intf);
}

static int findintfep(struct usb_device *dev, unsigned int ep)
{
	unsigned int i, j, e;
        struct usb_interface *iface;
431
	struct usb_host_interface *alts;
Linus Torvalds's avatar
Linus Torvalds committed
432 433 434 435
	struct usb_endpoint_descriptor *endpt;

	if (ep & ~(USB_DIR_IN|0xf))
		return -EINVAL;
436 437
	if (!dev->actconfig)
		return -ESRCH;
438
	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
439
		iface = dev->actconfig->interface[i];
Linus Torvalds's avatar
Linus Torvalds committed
440 441
		for (j = 0; j < iface->num_altsetting; j++) {
                        alts = &iface->altsetting[j];
442 443
			for (e = 0; e < alts->desc.bNumEndpoints; e++) {
				endpt = &alts->endpoint[e].desc;
Linus Torvalds's avatar
Linus Torvalds committed
444 445 446 447 448 449 450 451 452 453
				if (endpt->bEndpointAddress == ep)
					return i;
			}
		}
	}
	return -ENOENT; 
}

static int findintfif(struct usb_device *dev, unsigned int ifn)
{
454
	unsigned int i;
Linus Torvalds's avatar
Linus Torvalds committed
455 456 457

	if (ifn & ~0xff)
		return -EINVAL;
458 459
	if (!dev->actconfig)
		return -ESRCH;
460
	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
461 462 463
		if (dev->actconfig->interface[i]->
				altsetting[0].desc.bInterfaceNumber == ifn)
			return i;
Linus Torvalds's avatar
Linus Torvalds committed
464 465 466 467
	}
	return -ENOENT; 
}

Linus Torvalds's avatar
Linus Torvalds committed
468
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
Linus Torvalds's avatar
Linus Torvalds committed
469 470 471
{
	int ret;

Linus Torvalds's avatar
Linus Torvalds committed
472 473 474 475
	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
		return 0;

	switch (requesttype & USB_RECIP_MASK) {
Linus Torvalds's avatar
Linus Torvalds committed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
	case USB_RECIP_ENDPOINT:
		if ((ret = findintfep(ps->dev, index & 0xff)) < 0)
			return ret;
		if ((ret = checkintf(ps, ret)))
			return ret;
		break;

	case USB_RECIP_INTERFACE:
		if ((ret = findintfif(ps->dev, index & 0xff)) < 0)
			return ret;
		if ((ret = checkintf(ps, ret)))
			return ret;
		break;
	}
	return 0;
}

/*
 * file operations
 */
static int usbdev_open(struct inode *inode, struct file *file)
{
	struct usb_device *dev;
	struct dev_state *ps;
	int ret;

	/* 
	 * no locking necessary here, as both sys_open (actually filp_open)
	 * and the hub thread have the kernel lock
	 * (still acquire the kernel lock for safety)
	 */
507 508 509 510
	ret = -ENOMEM;
	if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
		goto out_nolock;

Linus Torvalds's avatar
Linus Torvalds committed
511 512
	lock_kernel();
	ret = -ENOENT;
513
	dev = usb_get_dev(inode->u.generic_ip);
514 515
	if (!dev) {
		kfree(ps);
Linus Torvalds's avatar
Linus Torvalds committed
516
		goto out;
517
	}
Linus Torvalds's avatar
Linus Torvalds committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
	ret = 0;
	ps->dev = dev;
	ps->file = file;
	spin_lock_init(&ps->lock);
	INIT_LIST_HEAD(&ps->async_pending);
	INIT_LIST_HEAD(&ps->async_completed);
	init_waitqueue_head(&ps->wait);
	ps->discsignr = 0;
	ps->disctask = current;
	ps->disccontext = NULL;
	ps->ifclaimed = 0;
	wmb();
	list_add_tail(&ps->list, &dev->filelist);
	file->private_data = ps;
 out:
	unlock_kernel();
534
 out_nolock:
Linus Torvalds's avatar
Linus Torvalds committed
535 536 537 538 539 540
        return ret;
}

static int usbdev_release(struct inode *inode, struct file *file)
{
	struct dev_state *ps = (struct dev_state *)file->private_data;
541
	struct usb_device *dev = ps->dev;
Linus Torvalds's avatar
Linus Torvalds committed
542 543
	unsigned int i;

544
	down(&dev->serialize);
545 546
	list_del_init(&ps->list);

547
	if (connected(dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
548 549 550
		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
			if (test_bit(i, &ps->ifclaimed))
				releaseintf(ps, i);
551
		destroy_all_async(ps);
Linus Torvalds's avatar
Linus Torvalds committed
552
	}
553 554
	up(&dev->serialize);
	usb_put_dev(dev);
555
	ps->dev = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
556 557 558 559
	kfree(ps);
        return 0;
}

560
static int proc_control(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
561 562 563 564 565 566 567
{
	struct usb_device *dev = ps->dev;
	struct usbdevfs_ctrltransfer ctrl;
	unsigned int tmo;
	unsigned char *tbuf;
	int i, ret;

568
	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
Linus Torvalds's avatar
Linus Torvalds committed
569
		return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
570
	if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
Linus Torvalds's avatar
Linus Torvalds committed
571
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
572
	if (ctrl.wLength > PAGE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
573 574 575 576
		return -EINVAL;
	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
		return -ENOMEM;
	tmo = (ctrl.timeout * HZ + 999) / 1000;
Linus Torvalds's avatar
Linus Torvalds committed
577 578
	if (ctrl.bRequestType & 0x80) {
		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
Linus Torvalds's avatar
Linus Torvalds committed
579 580 581
			free_page((unsigned long)tbuf);
			return -EINVAL;
		}
Linus Torvalds's avatar
Linus Torvalds committed
582 583 584 585
		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
				       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
		if ((i > 0) && ctrl.wLength) {
			if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {
Linus Torvalds's avatar
Linus Torvalds committed
586 587 588 589 590
				free_page((unsigned long)tbuf);
				return -EFAULT;
			}
		}
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
591 592
		if (ctrl.wLength) {
			if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
Linus Torvalds's avatar
Linus Torvalds committed
593 594 595 596
				free_page((unsigned long)tbuf);
				return -EFAULT;
			}
		}
Linus Torvalds's avatar
Linus Torvalds committed
597 598
		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
				       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
Linus Torvalds's avatar
Linus Torvalds committed
599 600 601
	}
	free_page((unsigned long)tbuf);
	if (i<0) {
602 603 604
		printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed "
			"cmd %s dev %d rqt %u rq %u len %u ret %d\n", 
			current->comm,
Linus Torvalds's avatar
Linus Torvalds committed
605
		       dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
Linus Torvalds's avatar
Linus Torvalds committed
606 607 608 609
	}
	return i;
}

610
static int proc_bulk(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
611 612 613 614 615 616 617 618
{
	struct usb_device *dev = ps->dev;
	struct usbdevfs_bulktransfer bulk;
	unsigned int tmo, len1, pipe;
	int len2;
	unsigned char *tbuf;
	int i, ret;

619
	if (copy_from_user(&bulk, arg, sizeof(bulk)))
Linus Torvalds's avatar
Linus Torvalds committed
620 621 622 623 624 625 626 627 628 629 630 631
		return -EFAULT;
	if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
		return ret;
	if ((ret = checkintf(ps, ret)))
		return ret;
	if (bulk.ep & USB_DIR_IN)
		pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
	else
		pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
		return -EINVAL;
	len1 = bulk.len;
632
	if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
Linus Torvalds's avatar
Linus Torvalds committed
633 634 635 636
		return -ENOMEM;
	tmo = (bulk.timeout * HZ + 999) / 1000;
	if (bulk.ep & 0x80) {
		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
637
			kfree(tbuf);
Linus Torvalds's avatar
Linus Torvalds committed
638 639 640 641 642
			return -EINVAL;
		}
		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
		if (!i && len2) {
			if (copy_to_user(bulk.data, tbuf, len2)) {
643
				kfree(tbuf);
Linus Torvalds's avatar
Linus Torvalds committed
644 645 646 647 648 649
				return -EFAULT;
			}
		}
	} else {
		if (len1) {
			if (copy_from_user(tbuf, bulk.data, len1)) {
650
				kfree(tbuf);
Linus Torvalds's avatar
Linus Torvalds committed
651 652 653 654 655
				return -EFAULT;
			}
		}
		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
	}
656
	kfree(tbuf);
Linus Torvalds's avatar
Linus Torvalds committed
657
	if (i < 0) {
658
		printk(KERN_WARNING "usbfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
Linus Torvalds's avatar
Linus Torvalds committed
659 660 661 662 663 664
		       dev->devnum, bulk.ep, bulk.len, i);
		return i;
	}
	return len2;
}

665
static int proc_resetep(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
666 667 668 669
{
	unsigned int ep;
	int ret;

670
	if (get_user(ep, (unsigned int __user *)arg))
Linus Torvalds's avatar
Linus Torvalds committed
671 672 673 674 675 676 677 678 679
		return -EFAULT;
	if ((ret = findintfep(ps->dev, ep)) < 0)
		return ret;
	if ((ret = checkintf(ps, ret)))
		return ret;
	usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
	return 0;
}

680
static int proc_clearhalt(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
681 682 683 684 685
{
	unsigned int ep;
	int pipe;
	int ret;

686
	if (get_user(ep, (unsigned int __user *)arg))
Linus Torvalds's avatar
Linus Torvalds committed
687 688 689 690 691 692 693 694 695 696 697 698 699 700
		return -EFAULT;
	if ((ret = findintfep(ps->dev, ep)) < 0)
		return ret;
	if ((ret = checkintf(ps, ret)))
		return ret;
	if (ep & USB_DIR_IN)
                pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
        else
                pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);

	return usb_clear_halt(ps->dev, pipe);
}
		

701
static int proc_getdriver(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
702 703 704 705 706 707 708 709 710
{
	struct usbdevfs_getdriver gd;
	struct usb_interface *interface;
	int ret;

	if (copy_from_user(&gd, arg, sizeof(gd)))
		return -EFAULT;
	if ((ret = findintfif(ps->dev, gd.interface)) < 0)
		return ret;
711
	down_read(&usb_bus_type.subsys.rwsem);
712
	interface = ps->dev->actconfig->interface[ret];
713 714
	if (!interface || !interface->dev.driver) {
		up_read(&usb_bus_type.subsys.rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
715
		return -ENODATA;
716
	}
717
	strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver));
718 719
	up_read(&usb_bus_type.subsys.rwsem);
	return copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0;
Linus Torvalds's avatar
Linus Torvalds committed
720 721
}

722
static int proc_connectinfo(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
723 724 725 726
{
	struct usbdevfs_connectinfo ci;

	ci.devnum = ps->dev->devnum;
Linus Torvalds's avatar
Linus Torvalds committed
727
	ci.slow = ps->dev->speed == USB_SPEED_LOW;
Linus Torvalds's avatar
Linus Torvalds committed
728 729 730 731 732 733 734
	if (copy_to_user(arg, &ci, sizeof(ci)))
		return -EFAULT;
	return 0;
}

static int proc_resetdevice(struct dev_state *ps)
{
735
	return usb_reset_device(ps->dev);
Linus Torvalds's avatar
Linus Torvalds committed
736 737 738

}

739
static int proc_setintf(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
740 741 742 743 744 745 746 747 748
{
	struct usbdevfs_setinterface setintf;
	struct usb_interface *interface;
	int ret;

	if (copy_from_user(&setintf, arg, sizeof(setintf)))
		return -EFAULT;
	if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
		return ret;
749
	interface = ps->dev->actconfig->interface[ret];
750
	if (interface->dev.driver) {
Linus Torvalds's avatar
Linus Torvalds committed
751 752 753 754 755 756 757 758
		if ((ret = checkintf(ps, ret)))
			return ret;
	}
	if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
		return -EINVAL;
	return 0;
}

759
static int proc_setconfig(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
760 761
{
	unsigned int u;
762 763
	int status = 0;
 	struct usb_host_config *actconfig;
Linus Torvalds's avatar
Linus Torvalds committed
764

765
	if (get_user(u, (unsigned int __user *)arg))
Linus Torvalds's avatar
Linus Torvalds committed
766
		return -EFAULT;
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804

 	actconfig = ps->dev->actconfig;
 
 	/* Don't touch the device if any interfaces are claimed.
 	 * It could interfere with other drivers' operations, and if
	 * an interface is claimed by usbfs it could easily deadlock.
	 */
 	if (actconfig) {
 		int i;
 
 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
 			if (usb_interface_claimed(actconfig->interface[i])) {
				dev_warn (&ps->dev->dev,
					"usbfs: interface %d claimed "
					"while '%s' sets config #%d\n",
					actconfig->interface[i]
						->cur_altsetting
						->desc.bInterfaceNumber,
					current->comm, u);
#if 0	/* FIXME:  enable in 2.6.10 or so */
 				status = -EBUSY;
				break;
#endif
			}
 		}
 	}

	/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
	 * so avoid usb_set_configuration()'s kick to sysfs
	 */
	if (status == 0) {
		if (actconfig && actconfig->desc.bConfigurationValue == u)
			status = usb_reset_configuration(ps->dev);
		else
			status = usb_set_configuration(ps->dev, u);
	}

	return status;
Linus Torvalds's avatar
Linus Torvalds committed
805 806
}

807
static int proc_submiturb(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
808 809 810 811 812
{
	struct usbdevfs_urb uurb;
	struct usbdevfs_iso_packet_desc *isopkt = NULL;
	struct usb_endpoint_descriptor *ep_desc;
	struct async *as;
Linus Torvalds's avatar
Linus Torvalds committed
813
	struct usb_ctrlrequest *dr = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
814
	unsigned int u, totlen, isofrmlen;
815
	int ret, interval = 0, intf = -1;
Linus Torvalds's avatar
Linus Torvalds committed
816 817 818

	if (copy_from_user(&uurb, arg, sizeof(uurb)))
		return -EFAULT;
819
	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
820
			   URB_NO_FSBR|URB_ZERO_PACKET))
Linus Torvalds's avatar
Linus Torvalds committed
821 822 823 824 825 826
		return -EINVAL;
	if (!uurb.buffer)
		return -EINVAL;
	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
		return -EINVAL;
	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
827 828 829
		if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0)
			return intf;
		if ((ret = checkintf(ps, intf)))
Linus Torvalds's avatar
Linus Torvalds committed
830 831 832 833 834 835 836 837 838 839 840 841 842
			return ret;
	}
	switch(uurb.type) {
	case USBDEVFS_URB_TYPE_CONTROL:
		if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) {
			if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
				return -ENOENT;
			if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL)
				return -EINVAL;
		}
		/* min 8 byte setup packet, max arbitrary */
		if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
			return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
843
		if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
Linus Torvalds's avatar
Linus Torvalds committed
844
			return -ENOMEM;
845
		if (copy_from_user(dr, uurb.buffer, 8)) {
Linus Torvalds's avatar
Linus Torvalds committed
846 847 848
			kfree(dr);
			return -EFAULT;
		}
Linus Torvalds's avatar
Linus Torvalds committed
849
		if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
Linus Torvalds's avatar
Linus Torvalds committed
850 851 852
			kfree(dr);
			return -EINVAL;
		}
Linus Torvalds's avatar
Linus Torvalds committed
853
		if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
Linus Torvalds's avatar
Linus Torvalds committed
854 855 856
			kfree(dr);
			return ret;
		}
Linus Torvalds's avatar
Linus Torvalds committed
857
		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
Linus Torvalds's avatar
Linus Torvalds committed
858
		uurb.number_of_packets = 0;
Linus Torvalds's avatar
Linus Torvalds committed
859
		uurb.buffer_length = le16_to_cpup(&dr->wLength);
Linus Torvalds's avatar
Linus Torvalds committed
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
		uurb.buffer += 8;
		if (!access_ok((uurb.endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
			kfree(dr);
			return -EFAULT;
		}
		break;

	case USBDEVFS_URB_TYPE_BULK:
		uurb.number_of_packets = 0;
		if (uurb.buffer_length > 16384)
			return -EINVAL;
		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
			return -EFAULT;
		break;

	case USBDEVFS_URB_TYPE_ISO:
		/* arbitrary limit */
		if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
			return -EINVAL;
879 880
		if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
			return -ENOENT;
881
		interval = 1 << min (15, ep_desc->bInterval - 1);
Linus Torvalds's avatar
Linus Torvalds committed
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
			return -ENOMEM;
		if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) {
			kfree(isopkt);
			return -EFAULT;
		}
		for (totlen = u = 0; u < uurb.number_of_packets; u++) {
			if (isopkt[u].length > 1023) {
				kfree(isopkt);
				return -EINVAL;
			}
			totlen += isopkt[u].length;
		}
		if (totlen > 32768) {
			kfree(isopkt);
Linus Torvalds's avatar
Linus Torvalds committed
898
			return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
899 900 901 902
		}
		uurb.buffer_length = totlen;
		break;

Linus Torvalds's avatar
Linus Torvalds committed
903 904
	case USBDEVFS_URB_TYPE_INTERRUPT:
		uurb.number_of_packets = 0;
905 906
		if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
			return -ENOENT;
907
		if (ps->dev->speed == USB_SPEED_HIGH)
908
			interval = 1 << min (15, ep_desc->bInterval - 1);
909 910
		else
			interval = ep_desc->bInterval;
Linus Torvalds's avatar
Linus Torvalds committed
911 912 913
		if (uurb.buffer_length > 16384)
			return -EINVAL;
		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
914
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
915 916
		break;

Linus Torvalds's avatar
Linus Torvalds committed
917 918 919 920 921 922 923 924 925 926
	default:
		return -EINVAL;
	}
	if (!(as = alloc_async(uurb.number_of_packets))) {
		if (isopkt)
			kfree(isopkt);
		if (dr)
			kfree(dr);
		return -ENOMEM;
	}
Linus Torvalds's avatar
Linus Torvalds committed
927
	if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
Linus Torvalds's avatar
Linus Torvalds committed
928 929 930 931 932 933 934
		if (isopkt)
			kfree(isopkt);
		if (dr)
			kfree(dr);
		free_async(as);
		return -ENOMEM;
	}
Linus Torvalds's avatar
Linus Torvalds committed
935 936 937 938 939 940 941
        as->urb->dev = ps->dev;
        as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
        as->urb->transfer_flags = uurb.flags;
	as->urb->transfer_buffer_length = uurb.buffer_length;
	as->urb->setup_packet = (unsigned char*)dr;
	as->urb->start_frame = uurb.start_frame;
	as->urb->number_of_packets = uurb.number_of_packets;
942
	as->urb->interval = interval;
Linus Torvalds's avatar
Linus Torvalds committed
943 944
        as->urb->context = as;
        as->urb->complete = async_completed;
Linus Torvalds's avatar
Linus Torvalds committed
945
	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
Linus Torvalds's avatar
Linus Torvalds committed
946 947
		as->urb->iso_frame_desc[u].offset = totlen;
		as->urb->iso_frame_desc[u].length = isopkt[u].length;
Linus Torvalds's avatar
Linus Torvalds committed
948 949 950 951 952 953 954 955 956 957 958
		totlen += isopkt[u].length;
	}
	if (isopkt)
		kfree(isopkt);
	as->ps = ps;
        as->userurb = arg;
	if (uurb.endpoint & USB_DIR_IN)
		as->userbuffer = uurb.buffer;
	else
		as->userbuffer = NULL;
	as->signr = uurb.signr;
959
	as->intf = intf;
Linus Torvalds's avatar
Linus Torvalds committed
960 961
	as->task = current;
	if (!(uurb.endpoint & USB_DIR_IN)) {
Linus Torvalds's avatar
Linus Torvalds committed
962
		if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
Linus Torvalds's avatar
Linus Torvalds committed
963 964 965 966 967
			free_async(as);
			return -EFAULT;
		}
	}
        async_newpending(as);
968 969
        if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
		printk(KERN_DEBUG "usbfs: usb_submit_urb returned %d\n", ret);
Linus Torvalds's avatar
Linus Torvalds committed
970 971 972 973 974 975 976
                async_removepending(as);
                free_async(as);
                return ret;
        }
        return 0;
}

977
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
978 979 980 981 982 983
{
	struct async *as;

	as = async_getpending(ps, arg);
	if (!as)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
984
	usb_unlink_urb(as->urb);
Linus Torvalds's avatar
Linus Torvalds committed
985 986 987 988 989
	return 0;
}

static int processcompl(struct async *as)
{
Linus Torvalds's avatar
Linus Torvalds committed
990
	struct urb *urb = as->urb;
Linus Torvalds's avatar
Linus Torvalds committed
991 992 993
	unsigned int i;

	if (as->userbuffer)
Linus Torvalds's avatar
Linus Torvalds committed
994
		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
Linus Torvalds's avatar
Linus Torvalds committed
995
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
996
	if (put_user(urb->status,
Linus Torvalds's avatar
Linus Torvalds committed
997 998
		     &((struct usbdevfs_urb *)as->userurb)->status))
		return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
999
	if (put_user(urb->actual_length,
Linus Torvalds's avatar
Linus Torvalds committed
1000 1001
		     &((struct usbdevfs_urb *)as->userurb)->actual_length))
		return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
1002
	if (put_user(urb->error_count,
Linus Torvalds's avatar
Linus Torvalds committed
1003 1004 1005
		     &((struct usbdevfs_urb *)as->userurb)->error_count))
		return -EFAULT;

Linus Torvalds's avatar
Linus Torvalds committed
1006
	if (!(usb_pipeisoc(urb->pipe)))
Linus Torvalds's avatar
Linus Torvalds committed
1007
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1008
	for (i = 0; i < urb->number_of_packets; i++) {
1009
		if (put_user(urb->iso_frame_desc[i].actual_length,
Linus Torvalds's avatar
Linus Torvalds committed
1010 1011
			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
			return -EFAULT;
1012
		if (put_user(urb->iso_frame_desc[i].status,
Linus Torvalds's avatar
Linus Torvalds committed
1013 1014 1015 1016 1017 1018
			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
			return -EFAULT;
	}
	return 0;
}

1019
static int proc_reapurb(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1020 1021 1022
{
        DECLARE_WAITQUEUE(wait, current);
	struct async *as = NULL;
1023
	void __user *addr;
1024
	struct usb_device *dev = ps->dev;
Linus Torvalds's avatar
Linus Torvalds committed
1025 1026 1027
	int ret;

	add_wait_queue(&ps->wait, &wait);
1028
	while (connected(dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
1029 1030 1031 1032 1033
		__set_current_state(TASK_INTERRUPTIBLE);
		if ((as = async_getcompleted(ps)))
			break;
		if (signal_pending(current))
			break;
1034
		up(&dev->serialize);
Linus Torvalds's avatar
Linus Torvalds committed
1035
		schedule();
1036
		down(&dev->serialize);
Linus Torvalds's avatar
Linus Torvalds committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
	}
	remove_wait_queue(&ps->wait, &wait);
	set_current_state(TASK_RUNNING);
	if (as) {
		ret = processcompl(as);
		addr = as->userurb;
		free_async(as);
		if (ret)
			return ret;
		if (put_user(addr, (void **)arg))
			return -EFAULT;
		return 0;
	}
	if (signal_pending(current))
		return -EINTR;
	return -EIO;
}

1055
static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1056 1057
{
	struct async *as;
1058
	void __user *addr;
Linus Torvalds's avatar
Linus Torvalds committed
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
	int ret;

	if (!(as = async_getcompleted(ps)))
		return -EAGAIN;
	ret = processcompl(as);
	addr = as->userurb;
	free_async(as);
	if (ret)
		return ret;
	if (put_user(addr, (void **)arg))
		return -EFAULT;
	return 0;
}

1073
static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
{
	struct usbdevfs_disconnectsignal ds;

	if (copy_from_user(&ds, arg, sizeof(ds)))
		return -EFAULT;
	if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
		return -EINVAL;
	ps->discsignr = ds.signr;
	ps->disccontext = ds.context;
	return 0;
}

1086
static int proc_claiminterface(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1087 1088 1089 1090
{
	unsigned int intf;
	int ret;

1091
	if (get_user(intf, (unsigned int __user *)arg))
Linus Torvalds's avatar
Linus Torvalds committed
1092 1093 1094 1095 1096 1097
		return -EFAULT;
	if ((ret = findintfif(ps->dev, intf)) < 0)
		return ret;
	return claimintf(ps, ret);
}

1098
static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1099 1100 1101 1102
{
	unsigned int intf;
	int ret;

1103
	if (get_user(intf, (unsigned int __user *)arg))
Linus Torvalds's avatar
Linus Torvalds committed
1104 1105 1106
		return -EFAULT;
	if ((ret = findintfif(ps->dev, intf)) < 0)
		return ret;
1107 1108 1109 1110
	if ((ret = releaseintf(ps, intf)) < 0)
		return ret;
	destroy_async_on_interface (ps, intf);
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1111 1112
}

1113
static int proc_ioctl (struct dev_state *ps, void __user *arg)
Linus Torvalds's avatar
Linus Torvalds committed
1114 1115 1116 1117 1118
{
	struct usbdevfs_ioctl	ctrl;
	int			size;
	void			*buf = 0;
	int			retval = 0;
David Brownell's avatar
David Brownell committed
1119 1120
	struct usb_interface    *ifp = 0;
	struct usb_driver       *driver = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1121 1122

	/* get input parameters and alloc buffer */
1123
	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
Linus Torvalds's avatar
Linus Torvalds committed
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
		return -EFAULT;
	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
		if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
			return -ENOMEM;
		if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) {
			if (copy_from_user (buf, ctrl.data, size)) {
				kfree (buf);
				return -EFAULT;
			}
		} else {
			memset (buf, 0, size);
		}
	}

1138
	if (!connected(ps->dev)) {
1139 1140 1141 1142 1143 1144 1145 1146
		if (buf)
			kfree(buf);
		return -ENODEV;
	}

	if (ps->dev->state != USB_STATE_CONFIGURED)
		retval = -ENODEV;
	else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
Dan Streetman's avatar
Dan Streetman committed
1147
               retval = -EINVAL;
1148 1149 1150 1151 1152 1153 1154 1155 1156
	else switch (ctrl.ioctl_code) {

	/* disconnect kernel driver from interface */
	case USBDEVFS_DISCONNECT:
		down_write(&usb_bus_type.subsys.rwsem);
		if (ifp->dev.driver) {
			driver = to_usb_driver(ifp->dev.driver);
			dev_dbg (&ifp->dev, "disconnect by usbfs\n");
			usb_driver_release_interface(driver, ifp);
1157
		} else
1158
			retval = -ENODATA;
1159
		up_write(&usb_bus_type.subsys.rwsem);
1160
		break;
Dan Streetman's avatar
Dan Streetman committed
1161

David Brownell's avatar
David Brownell committed
1162 1163
	/* let kernel drivers try to (re)bind to the interface */
	case USBDEVFS_CONNECT:
1164
		bus_rescan_devices(ifp->dev.bus);
David Brownell's avatar
David Brownell committed
1165
		break;
Dan Streetman's avatar
Dan Streetman committed
1166

1167 1168
	/* talk directly to the interface's driver */
	default:
1169 1170 1171
		down_read(&usb_bus_type.subsys.rwsem);
		if (ifp->dev.driver)
			driver = to_usb_driver(ifp->dev.driver);
1172
		if (driver == 0 || driver->ioctl == 0) {
1173
			retval = -ENOTTY;
1174
		} else {
1175
			retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
1176 1177
			if (retval == -ENOIOCTLCMD)
				retval = -ENOTTY;
Linus Torvalds's avatar
Linus Torvalds committed
1178
		}
1179
		up_read(&usb_bus_type.subsys.rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
	}

	/* cleanup and return */
	if (retval >= 0
			&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
			&& size > 0
			&& copy_to_user (ctrl.data, buf, size) != 0)
		retval = -EFAULT;
	if (buf != 0)
		kfree (buf);
	return retval;
}

David Brownell's avatar
David Brownell committed
1193 1194 1195 1196 1197
/*
 * NOTE:  All requests here that have interface numbers as parameters
 * are assuming that somehow the configuration has been prevented from
 * changing.  But there's no mechanism to ensure that...
 */
Linus Torvalds's avatar
Linus Torvalds committed
1198 1199 1200
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct dev_state *ps = (struct dev_state *)file->private_data;
1201
	struct usb_device *dev = ps->dev;
1202
	int ret = -ENOTTY;
Linus Torvalds's avatar
Linus Torvalds committed
1203 1204 1205

	if (!(file->f_mode & FMODE_WRITE))
		return -EPERM;
1206 1207 1208
	down(&dev->serialize);
	if (!connected(dev)) {
		up(&dev->serialize);
Linus Torvalds's avatar
Linus Torvalds committed
1209 1210 1211 1212
		return -ENODEV;
	}
	switch (cmd) {
	case USBDEVFS_CONTROL:
1213
		ret = proc_control(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1214 1215 1216 1217 1218
		if (ret >= 0)
			inode->i_mtime = CURRENT_TIME;
		break;

	case USBDEVFS_BULK:
1219
		ret = proc_bulk(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1220 1221 1222 1223 1224
		if (ret >= 0)
			inode->i_mtime = CURRENT_TIME;
		break;

	case USBDEVFS_RESETEP:
1225
		ret = proc_resetep(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1226 1227 1228 1229 1230 1231 1232
		if (ret >= 0)
			inode->i_mtime = CURRENT_TIME;
		break;

	case USBDEVFS_RESET:
		ret = proc_resetdevice(ps);
		break;
1233

Linus Torvalds's avatar
Linus Torvalds committed
1234
	case USBDEVFS_CLEAR_HALT:
1235
		ret = proc_clearhalt(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1236 1237 1238 1239 1240
		if (ret >= 0)
			inode->i_mtime = CURRENT_TIME;
		break;

	case USBDEVFS_GETDRIVER:
1241
		ret = proc_getdriver(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1242 1243 1244
		break;

	case USBDEVFS_CONNECTINFO:
1245
		ret = proc_connectinfo(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1246 1247 1248
		break;

	case USBDEVFS_SETINTERFACE:
1249
		ret = proc_setintf(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1250 1251 1252
		break;

	case USBDEVFS_SETCONFIGURATION:
1253
		ret = proc_setconfig(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1254 1255 1256
		break;

	case USBDEVFS_SUBMITURB:
1257
		ret = proc_submiturb(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1258 1259 1260 1261 1262
		if (ret >= 0)
			inode->i_mtime = CURRENT_TIME;
		break;

	case USBDEVFS_DISCARDURB:
1263
		ret = proc_unlinkurb(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1264 1265 1266
		break;

	case USBDEVFS_REAPURB:
1267
		ret = proc_reapurb(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1268 1269 1270
		break;

	case USBDEVFS_REAPURBNDELAY:
1271
		ret = proc_reapurbnonblock(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1272 1273 1274
		break;

	case USBDEVFS_DISCSIGNAL:
1275
		ret = proc_disconnectsignal(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1276 1277 1278
		break;

	case USBDEVFS_CLAIMINTERFACE:
1279
		ret = proc_claiminterface(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1280 1281 1282
		break;

	case USBDEVFS_RELEASEINTERFACE:
1283
		ret = proc_releaseinterface(ps, (void __user *)arg);
Linus Torvalds's avatar
Linus Torvalds committed
1284 1285 1286
		break;

	case USBDEVFS_IOCTL:
1287
		ret = proc_ioctl(ps, (void __user *) arg);
Linus Torvalds's avatar
Linus Torvalds committed
1288 1289
		break;
	}
1290
	up(&dev->serialize);
Linus Torvalds's avatar
Linus Torvalds committed
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
	if (ret >= 0)
		inode->i_atime = CURRENT_TIME;
	return ret;
}

/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
	struct dev_state *ps = (struct dev_state *)file->private_data;
        unsigned int mask = 0;

	poll_wait(file, &ps->wait, wait);
	if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
		mask |= POLLOUT | POLLWRNORM;
1305
	if (!connected(ps->dev))
Linus Torvalds's avatar
Linus Torvalds committed
1306 1307 1308 1309 1310
		mask |= POLLERR | POLLHUP;
	return mask;
}

struct file_operations usbdevfs_device_file_operations = {
1311 1312 1313 1314 1315 1316
	.llseek =	usbdev_lseek,
	.read =		usbdev_read,
	.poll =		usbdev_poll,
	.ioctl =	usbdev_ioctl,
	.open =		usbdev_open,
	.release =	usbdev_release,
Linus Torvalds's avatar
Linus Torvalds committed
1317
};