diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/core/devio.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 1483 |
1 files changed, 1483 insertions, 0 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c new file mode 100644 index 000000000000..a047bc392983 --- /dev/null +++ b/drivers/usb/core/devio.c | |||
@@ -0,0 +1,1483 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * devio.c -- User space communication with USB devices. | ||
5 | * | ||
6 | * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $ | ||
23 | * | ||
24 | * This file implements the usbfs/x/y files, where | ||
25 | * x is the bus number and y the device number. | ||
26 | * | ||
27 | * It allows user space programs/"drivers" to communicate directly | ||
28 | * with USB devices without intervening kernel driver. | ||
29 | * | ||
30 | * Revision history | ||
31 | * 22.12.1999 0.1 Initial release (split from proc_usb.c) | ||
32 | * 04.01.2000 0.2 Turned into its own filesystem | ||
33 | */ | ||
34 | |||
35 | /*****************************************************************************/ | ||
36 | |||
37 | #include <linux/fs.h> | ||
38 | #include <linux/mm.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/smp_lock.h> | ||
41 | #include <linux/signal.h> | ||
42 | #include <linux/poll.h> | ||
43 | #include <linux/module.h> | ||
44 | #include <linux/usb.h> | ||
45 | #include <linux/usbdevice_fs.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | #include <asm/byteorder.h> | ||
48 | #include <linux/moduleparam.h> | ||
49 | |||
50 | #include "hcd.h" /* for usbcore internals */ | ||
51 | #include "usb.h" | ||
52 | |||
53 | struct async { | ||
54 | struct list_head asynclist; | ||
55 | struct dev_state *ps; | ||
56 | struct task_struct *task; | ||
57 | unsigned int signr; | ||
58 | unsigned int ifnum; | ||
59 | void __user *userbuffer; | ||
60 | void __user *userurb; | ||
61 | struct urb *urb; | ||
62 | }; | ||
63 | |||
64 | static int usbfs_snoop = 0; | ||
65 | module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR); | ||
66 | MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic"); | ||
67 | |||
68 | #define snoop(dev, format, arg...) \ | ||
69 | do { \ | ||
70 | if (usbfs_snoop) \ | ||
71 | dev_info( dev , format , ## arg); \ | ||
72 | } while (0) | ||
73 | |||
74 | |||
75 | #define MAX_USBFS_BUFFER_SIZE 16384 | ||
76 | |||
77 | static inline int connected (struct usb_device *dev) | ||
78 | { | ||
79 | return dev->state != USB_STATE_NOTATTACHED; | ||
80 | } | ||
81 | |||
82 | static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) | ||
83 | { | ||
84 | loff_t ret; | ||
85 | |||
86 | lock_kernel(); | ||
87 | |||
88 | switch (orig) { | ||
89 | case 0: | ||
90 | file->f_pos = offset; | ||
91 | ret = file->f_pos; | ||
92 | break; | ||
93 | case 1: | ||
94 | file->f_pos += offset; | ||
95 | ret = file->f_pos; | ||
96 | break; | ||
97 | case 2: | ||
98 | default: | ||
99 | ret = -EINVAL; | ||
100 | } | ||
101 | |||
102 | unlock_kernel(); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | ||
107 | { | ||
108 | struct dev_state *ps = (struct dev_state *)file->private_data; | ||
109 | struct usb_device *dev = ps->dev; | ||
110 | ssize_t ret = 0; | ||
111 | unsigned len; | ||
112 | loff_t pos; | ||
113 | int i; | ||
114 | |||
115 | pos = *ppos; | ||
116 | usb_lock_device(dev); | ||
117 | if (!connected(dev)) { | ||
118 | ret = -ENODEV; | ||
119 | goto err; | ||
120 | } else if (pos < 0) { | ||
121 | ret = -EINVAL; | ||
122 | goto err; | ||
123 | } | ||
124 | |||
125 | if (pos < sizeof(struct usb_device_descriptor)) { | ||
126 | struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL); | ||
127 | if (!desc) { | ||
128 | ret = -ENOMEM; | ||
129 | goto err; | ||
130 | } | ||
131 | memcpy(desc, &dev->descriptor, sizeof(dev->descriptor)); | ||
132 | le16_to_cpus(&desc->bcdUSB); | ||
133 | le16_to_cpus(&desc->idVendor); | ||
134 | le16_to_cpus(&desc->idProduct); | ||
135 | le16_to_cpus(&desc->bcdDevice); | ||
136 | |||
137 | len = sizeof(struct usb_device_descriptor) - pos; | ||
138 | if (len > nbytes) | ||
139 | len = nbytes; | ||
140 | if (copy_to_user(buf, ((char *)desc) + pos, len)) { | ||
141 | kfree(desc); | ||
142 | ret = -EFAULT; | ||
143 | goto err; | ||
144 | } | ||
145 | kfree(desc); | ||
146 | |||
147 | *ppos += len; | ||
148 | buf += len; | ||
149 | nbytes -= len; | ||
150 | ret += len; | ||
151 | } | ||
152 | |||
153 | pos = sizeof(struct usb_device_descriptor); | ||
154 | for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) { | ||
155 | struct usb_config_descriptor *config = | ||
156 | (struct usb_config_descriptor *)dev->rawdescriptors[i]; | ||
157 | unsigned int length = le16_to_cpu(config->wTotalLength); | ||
158 | |||
159 | if (*ppos < pos + length) { | ||
160 | |||
161 | /* The descriptor may claim to be longer than it | ||
162 | * really is. Here is the actual allocated length. */ | ||
163 | unsigned alloclen = | ||
164 | le16_to_cpu(dev->config[i].desc.wTotalLength); | ||
165 | |||
166 | len = length - (*ppos - pos); | ||
167 | if (len > nbytes) | ||
168 | len = nbytes; | ||
169 | |||
170 | /* Simply don't write (skip over) unallocated parts */ | ||
171 | if (alloclen > (*ppos - pos)) { | ||
172 | alloclen -= (*ppos - pos); | ||
173 | if (copy_to_user(buf, | ||
174 | dev->rawdescriptors[i] + (*ppos - pos), | ||
175 | min(len, alloclen))) { | ||
176 | ret = -EFAULT; | ||
177 | goto err; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | *ppos += len; | ||
182 | buf += len; | ||
183 | nbytes -= len; | ||
184 | ret += len; | ||
185 | } | ||
186 | |||
187 | pos += length; | ||
188 | } | ||
189 | |||
190 | err: | ||
191 | usb_unlock_device(dev); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * async list handling | ||
197 | */ | ||
198 | |||
199 | static struct async *alloc_async(unsigned int numisoframes) | ||
200 | { | ||
201 | unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); | ||
202 | struct async *as = kmalloc(assize, GFP_KERNEL); | ||
203 | if (!as) | ||
204 | return NULL; | ||
205 | memset(as, 0, assize); | ||
206 | as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); | ||
207 | if (!as->urb) { | ||
208 | kfree(as); | ||
209 | return NULL; | ||
210 | } | ||
211 | return as; | ||
212 | } | ||
213 | |||
214 | static void free_async(struct async *as) | ||
215 | { | ||
216 | if (as->urb->transfer_buffer) | ||
217 | kfree(as->urb->transfer_buffer); | ||
218 | if (as->urb->setup_packet) | ||
219 | kfree(as->urb->setup_packet); | ||
220 | usb_free_urb(as->urb); | ||
221 | kfree(as); | ||
222 | } | ||
223 | |||
224 | static inline void async_newpending(struct async *as) | ||
225 | { | ||
226 | struct dev_state *ps = as->ps; | ||
227 | unsigned long flags; | ||
228 | |||
229 | spin_lock_irqsave(&ps->lock, flags); | ||
230 | list_add_tail(&as->asynclist, &ps->async_pending); | ||
231 | spin_unlock_irqrestore(&ps->lock, flags); | ||
232 | } | ||
233 | |||
234 | static inline void async_removepending(struct async *as) | ||
235 | { | ||
236 | struct dev_state *ps = as->ps; | ||
237 | unsigned long flags; | ||
238 | |||
239 | spin_lock_irqsave(&ps->lock, flags); | ||
240 | list_del_init(&as->asynclist); | ||
241 | spin_unlock_irqrestore(&ps->lock, flags); | ||
242 | } | ||
243 | |||
244 | static inline struct async *async_getcompleted(struct dev_state *ps) | ||
245 | { | ||
246 | unsigned long flags; | ||
247 | struct async *as = NULL; | ||
248 | |||
249 | spin_lock_irqsave(&ps->lock, flags); | ||
250 | if (!list_empty(&ps->async_completed)) { | ||
251 | as = list_entry(ps->async_completed.next, struct async, asynclist); | ||
252 | list_del_init(&as->asynclist); | ||
253 | } | ||
254 | spin_unlock_irqrestore(&ps->lock, flags); | ||
255 | return as; | ||
256 | } | ||
257 | |||
258 | static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb) | ||
259 | { | ||
260 | unsigned long flags; | ||
261 | struct async *as; | ||
262 | |||
263 | spin_lock_irqsave(&ps->lock, flags); | ||
264 | list_for_each_entry(as, &ps->async_pending, asynclist) | ||
265 | if (as->userurb == userurb) { | ||
266 | list_del_init(&as->asynclist); | ||
267 | spin_unlock_irqrestore(&ps->lock, flags); | ||
268 | return as; | ||
269 | } | ||
270 | spin_unlock_irqrestore(&ps->lock, flags); | ||
271 | return NULL; | ||
272 | } | ||
273 | |||
274 | static void async_completed(struct urb *urb, struct pt_regs *regs) | ||
275 | { | ||
276 | struct async *as = (struct async *)urb->context; | ||
277 | struct dev_state *ps = as->ps; | ||
278 | struct siginfo sinfo; | ||
279 | |||
280 | spin_lock(&ps->lock); | ||
281 | list_move_tail(&as->asynclist, &ps->async_completed); | ||
282 | spin_unlock(&ps->lock); | ||
283 | if (as->signr) { | ||
284 | sinfo.si_signo = as->signr; | ||
285 | sinfo.si_errno = as->urb->status; | ||
286 | sinfo.si_code = SI_ASYNCIO; | ||
287 | sinfo.si_addr = as->userurb; | ||
288 | send_sig_info(as->signr, &sinfo, as->task); | ||
289 | } | ||
290 | wake_up(&ps->wait); | ||
291 | } | ||
292 | |||
293 | static void destroy_async (struct dev_state *ps, struct list_head *list) | ||
294 | { | ||
295 | struct async *as; | ||
296 | unsigned long flags; | ||
297 | |||
298 | spin_lock_irqsave(&ps->lock, flags); | ||
299 | while (!list_empty(list)) { | ||
300 | as = list_entry(list->next, struct async, asynclist); | ||
301 | list_del_init(&as->asynclist); | ||
302 | |||
303 | /* drop the spinlock so the completion handler can run */ | ||
304 | spin_unlock_irqrestore(&ps->lock, flags); | ||
305 | usb_kill_urb(as->urb); | ||
306 | spin_lock_irqsave(&ps->lock, flags); | ||
307 | } | ||
308 | spin_unlock_irqrestore(&ps->lock, flags); | ||
309 | as = async_getcompleted(ps); | ||
310 | while (as) { | ||
311 | free_async(as); | ||
312 | as = async_getcompleted(ps); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum) | ||
317 | { | ||
318 | struct list_head *p, *q, hitlist; | ||
319 | unsigned long flags; | ||
320 | |||
321 | INIT_LIST_HEAD(&hitlist); | ||
322 | spin_lock_irqsave(&ps->lock, flags); | ||
323 | list_for_each_safe(p, q, &ps->async_pending) | ||
324 | if (ifnum == list_entry(p, struct async, asynclist)->ifnum) | ||
325 | list_move_tail(p, &hitlist); | ||
326 | spin_unlock_irqrestore(&ps->lock, flags); | ||
327 | destroy_async(ps, &hitlist); | ||
328 | } | ||
329 | |||
330 | static inline void destroy_all_async(struct dev_state *ps) | ||
331 | { | ||
332 | destroy_async(ps, &ps->async_pending); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * interface claims are made only at the request of user level code, | ||
337 | * which can also release them (explicitly or by closing files). | ||
338 | * they're also undone when devices disconnect. | ||
339 | */ | ||
340 | |||
341 | static int driver_probe (struct usb_interface *intf, | ||
342 | const struct usb_device_id *id) | ||
343 | { | ||
344 | return -ENODEV; | ||
345 | } | ||
346 | |||
347 | static void driver_disconnect(struct usb_interface *intf) | ||
348 | { | ||
349 | struct dev_state *ps = usb_get_intfdata (intf); | ||
350 | unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; | ||
351 | |||
352 | if (!ps) | ||
353 | return; | ||
354 | |||
355 | /* NOTE: this relies on usbcore having canceled and completed | ||
356 | * all pending I/O requests; 2.6 does that. | ||
357 | */ | ||
358 | |||
359 | if (likely(ifnum < 8*sizeof(ps->ifclaimed))) | ||
360 | clear_bit(ifnum, &ps->ifclaimed); | ||
361 | else | ||
362 | warn("interface number %u out of range", ifnum); | ||
363 | |||
364 | usb_set_intfdata (intf, NULL); | ||
365 | |||
366 | /* force async requests to complete */ | ||
367 | destroy_async_on_interface(ps, ifnum); | ||
368 | } | ||
369 | |||
370 | struct usb_driver usbfs_driver = { | ||
371 | .owner = THIS_MODULE, | ||
372 | .name = "usbfs", | ||
373 | .probe = driver_probe, | ||
374 | .disconnect = driver_disconnect, | ||
375 | }; | ||
376 | |||
377 | static int claimintf(struct dev_state *ps, unsigned int ifnum) | ||
378 | { | ||
379 | struct usb_device *dev = ps->dev; | ||
380 | struct usb_interface *intf; | ||
381 | int err; | ||
382 | |||
383 | if (ifnum >= 8*sizeof(ps->ifclaimed)) | ||
384 | return -EINVAL; | ||
385 | /* already claimed */ | ||
386 | if (test_bit(ifnum, &ps->ifclaimed)) | ||
387 | return 0; | ||
388 | |||
389 | /* lock against other changes to driver bindings */ | ||
390 | down_write(&usb_bus_type.subsys.rwsem); | ||
391 | intf = usb_ifnum_to_if(dev, ifnum); | ||
392 | if (!intf) | ||
393 | err = -ENOENT; | ||
394 | else | ||
395 | err = usb_driver_claim_interface(&usbfs_driver, intf, ps); | ||
396 | up_write(&usb_bus_type.subsys.rwsem); | ||
397 | if (err == 0) | ||
398 | set_bit(ifnum, &ps->ifclaimed); | ||
399 | return err; | ||
400 | } | ||
401 | |||
402 | static int releaseintf(struct dev_state *ps, unsigned int ifnum) | ||
403 | { | ||
404 | struct usb_device *dev; | ||
405 | struct usb_interface *intf; | ||
406 | int err; | ||
407 | |||
408 | err = -EINVAL; | ||
409 | if (ifnum >= 8*sizeof(ps->ifclaimed)) | ||
410 | return err; | ||
411 | dev = ps->dev; | ||
412 | /* lock against other changes to driver bindings */ | ||
413 | down_write(&usb_bus_type.subsys.rwsem); | ||
414 | intf = usb_ifnum_to_if(dev, ifnum); | ||
415 | if (!intf) | ||
416 | err = -ENOENT; | ||
417 | else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { | ||
418 | usb_driver_release_interface(&usbfs_driver, intf); | ||
419 | err = 0; | ||
420 | } | ||
421 | up_write(&usb_bus_type.subsys.rwsem); | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | static int checkintf(struct dev_state *ps, unsigned int ifnum) | ||
426 | { | ||
427 | if (ps->dev->state != USB_STATE_CONFIGURED) | ||
428 | return -EHOSTUNREACH; | ||
429 | if (ifnum >= 8*sizeof(ps->ifclaimed)) | ||
430 | return -EINVAL; | ||
431 | if (test_bit(ifnum, &ps->ifclaimed)) | ||
432 | return 0; | ||
433 | /* if not yet claimed, claim it for the driver */ | ||
434 | dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n", | ||
435 | current->pid, current->comm, ifnum); | ||
436 | return claimintf(ps, ifnum); | ||
437 | } | ||
438 | |||
439 | static int findintfep(struct usb_device *dev, unsigned int ep) | ||
440 | { | ||
441 | unsigned int i, j, e; | ||
442 | struct usb_interface *intf; | ||
443 | struct usb_host_interface *alts; | ||
444 | struct usb_endpoint_descriptor *endpt; | ||
445 | |||
446 | if (ep & ~(USB_DIR_IN|0xf)) | ||
447 | return -EINVAL; | ||
448 | if (!dev->actconfig) | ||
449 | return -ESRCH; | ||
450 | for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { | ||
451 | intf = dev->actconfig->interface[i]; | ||
452 | for (j = 0; j < intf->num_altsetting; j++) { | ||
453 | alts = &intf->altsetting[j]; | ||
454 | for (e = 0; e < alts->desc.bNumEndpoints; e++) { | ||
455 | endpt = &alts->endpoint[e].desc; | ||
456 | if (endpt->bEndpointAddress == ep) | ||
457 | return alts->desc.bInterfaceNumber; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | return -ENOENT; | ||
462 | } | ||
463 | |||
464 | static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index) | ||
465 | { | ||
466 | int ret = 0; | ||
467 | |||
468 | if (ps->dev->state != USB_STATE_CONFIGURED) | ||
469 | return -EHOSTUNREACH; | ||
470 | if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) | ||
471 | return 0; | ||
472 | |||
473 | index &= 0xff; | ||
474 | switch (requesttype & USB_RECIP_MASK) { | ||
475 | case USB_RECIP_ENDPOINT: | ||
476 | if ((ret = findintfep(ps->dev, index)) >= 0) | ||
477 | ret = checkintf(ps, ret); | ||
478 | break; | ||
479 | |||
480 | case USB_RECIP_INTERFACE: | ||
481 | ret = checkintf(ps, index); | ||
482 | break; | ||
483 | } | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * file operations | ||
489 | */ | ||
490 | static int usbdev_open(struct inode *inode, struct file *file) | ||
491 | { | ||
492 | struct usb_device *dev; | ||
493 | struct dev_state *ps; | ||
494 | int ret; | ||
495 | |||
496 | /* | ||
497 | * no locking necessary here, as chrdev_open has the kernel lock | ||
498 | * (still acquire the kernel lock for safety) | ||
499 | */ | ||
500 | ret = -ENOMEM; | ||
501 | if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) | ||
502 | goto out_nolock; | ||
503 | |||
504 | lock_kernel(); | ||
505 | ret = -ENOENT; | ||
506 | dev = usb_get_dev(inode->u.generic_ip); | ||
507 | if (!dev) { | ||
508 | kfree(ps); | ||
509 | goto out; | ||
510 | } | ||
511 | ret = 0; | ||
512 | ps->dev = dev; | ||
513 | ps->file = file; | ||
514 | spin_lock_init(&ps->lock); | ||
515 | INIT_LIST_HEAD(&ps->async_pending); | ||
516 | INIT_LIST_HEAD(&ps->async_completed); | ||
517 | init_waitqueue_head(&ps->wait); | ||
518 | ps->discsignr = 0; | ||
519 | ps->disctask = current; | ||
520 | ps->disccontext = NULL; | ||
521 | ps->ifclaimed = 0; | ||
522 | wmb(); | ||
523 | list_add_tail(&ps->list, &dev->filelist); | ||
524 | file->private_data = ps; | ||
525 | out: | ||
526 | unlock_kernel(); | ||
527 | out_nolock: | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | static int usbdev_release(struct inode *inode, struct file *file) | ||
532 | { | ||
533 | struct dev_state *ps = (struct dev_state *)file->private_data; | ||
534 | struct usb_device *dev = ps->dev; | ||
535 | unsigned int ifnum; | ||
536 | |||
537 | usb_lock_device(dev); | ||
538 | list_del_init(&ps->list); | ||
539 | for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); | ||
540 | ifnum++) { | ||
541 | if (test_bit(ifnum, &ps->ifclaimed)) | ||
542 | releaseintf(ps, ifnum); | ||
543 | } | ||
544 | destroy_all_async(ps); | ||
545 | usb_unlock_device(dev); | ||
546 | usb_put_dev(dev); | ||
547 | ps->dev = NULL; | ||
548 | kfree(ps); | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int proc_control(struct dev_state *ps, void __user *arg) | ||
553 | { | ||
554 | struct usb_device *dev = ps->dev; | ||
555 | struct usbdevfs_ctrltransfer ctrl; | ||
556 | unsigned int tmo; | ||
557 | unsigned char *tbuf; | ||
558 | int i, j, ret; | ||
559 | |||
560 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
561 | return -EFAULT; | ||
562 | if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) | ||
563 | return ret; | ||
564 | if (ctrl.wLength > PAGE_SIZE) | ||
565 | return -EINVAL; | ||
566 | if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) | ||
567 | return -ENOMEM; | ||
568 | tmo = ctrl.timeout; | ||
569 | if (ctrl.bRequestType & 0x80) { | ||
570 | if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { | ||
571 | free_page((unsigned long)tbuf); | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", | ||
575 | ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); | ||
576 | |||
577 | usb_unlock_device(dev); | ||
578 | i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, | ||
579 | ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); | ||
580 | usb_lock_device(dev); | ||
581 | if ((i > 0) && ctrl.wLength) { | ||
582 | if (usbfs_snoop) { | ||
583 | dev_info(&dev->dev, "control read: data "); | ||
584 | for (j = 0; j < ctrl.wLength; ++j) | ||
585 | printk ("%02x ", (unsigned char)(tbuf)[j]); | ||
586 | printk("\n"); | ||
587 | } | ||
588 | if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) { | ||
589 | free_page((unsigned long)tbuf); | ||
590 | return -EFAULT; | ||
591 | } | ||
592 | } | ||
593 | } else { | ||
594 | if (ctrl.wLength) { | ||
595 | if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { | ||
596 | free_page((unsigned long)tbuf); | ||
597 | return -EFAULT; | ||
598 | } | ||
599 | } | ||
600 | snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", | ||
601 | ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); | ||
602 | if (usbfs_snoop) { | ||
603 | dev_info(&dev->dev, "control write: data: "); | ||
604 | for (j = 0; j < ctrl.wLength; ++j) | ||
605 | printk ("%02x ", (unsigned char)(tbuf)[j]); | ||
606 | printk("\n"); | ||
607 | } | ||
608 | usb_unlock_device(dev); | ||
609 | i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, | ||
610 | ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); | ||
611 | usb_lock_device(dev); | ||
612 | } | ||
613 | free_page((unsigned long)tbuf); | ||
614 | if (i<0 && i != -EPIPE) { | ||
615 | dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " | ||
616 | "failed cmd %s rqt %u rq %u len %u ret %d\n", | ||
617 | current->comm, ctrl.bRequestType, ctrl.bRequest, | ||
618 | ctrl.wLength, i); | ||
619 | } | ||
620 | return i; | ||
621 | } | ||
622 | |||
623 | static int proc_bulk(struct dev_state *ps, void __user *arg) | ||
624 | { | ||
625 | struct usb_device *dev = ps->dev; | ||
626 | struct usbdevfs_bulktransfer bulk; | ||
627 | unsigned int tmo, len1, pipe; | ||
628 | int len2; | ||
629 | unsigned char *tbuf; | ||
630 | int i, ret; | ||
631 | |||
632 | if (copy_from_user(&bulk, arg, sizeof(bulk))) | ||
633 | return -EFAULT; | ||
634 | if ((ret = findintfep(ps->dev, bulk.ep)) < 0) | ||
635 | return ret; | ||
636 | if ((ret = checkintf(ps, ret))) | ||
637 | return ret; | ||
638 | if (bulk.ep & USB_DIR_IN) | ||
639 | pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); | ||
640 | else | ||
641 | pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); | ||
642 | if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) | ||
643 | return -EINVAL; | ||
644 | len1 = bulk.len; | ||
645 | if (len1 > MAX_USBFS_BUFFER_SIZE) | ||
646 | return -EINVAL; | ||
647 | if (!(tbuf = kmalloc(len1, GFP_KERNEL))) | ||
648 | return -ENOMEM; | ||
649 | tmo = bulk.timeout; | ||
650 | if (bulk.ep & 0x80) { | ||
651 | if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { | ||
652 | kfree(tbuf); | ||
653 | return -EINVAL; | ||
654 | } | ||
655 | usb_unlock_device(dev); | ||
656 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); | ||
657 | usb_lock_device(dev); | ||
658 | if (!i && len2) { | ||
659 | if (copy_to_user(bulk.data, tbuf, len2)) { | ||
660 | kfree(tbuf); | ||
661 | return -EFAULT; | ||
662 | } | ||
663 | } | ||
664 | } else { | ||
665 | if (len1) { | ||
666 | if (copy_from_user(tbuf, bulk.data, len1)) { | ||
667 | kfree(tbuf); | ||
668 | return -EFAULT; | ||
669 | } | ||
670 | } | ||
671 | usb_unlock_device(dev); | ||
672 | i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); | ||
673 | usb_lock_device(dev); | ||
674 | } | ||
675 | kfree(tbuf); | ||
676 | if (i < 0) | ||
677 | return i; | ||
678 | return len2; | ||
679 | } | ||
680 | |||
681 | static int proc_resetep(struct dev_state *ps, void __user *arg) | ||
682 | { | ||
683 | unsigned int ep; | ||
684 | int ret; | ||
685 | |||
686 | if (get_user(ep, (unsigned int __user *)arg)) | ||
687 | return -EFAULT; | ||
688 | if ((ret = findintfep(ps->dev, ep)) < 0) | ||
689 | return ret; | ||
690 | if ((ret = checkintf(ps, ret))) | ||
691 | return ret; | ||
692 | usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | static int proc_clearhalt(struct dev_state *ps, void __user *arg) | ||
697 | { | ||
698 | unsigned int ep; | ||
699 | int pipe; | ||
700 | int ret; | ||
701 | |||
702 | if (get_user(ep, (unsigned int __user *)arg)) | ||
703 | return -EFAULT; | ||
704 | if ((ret = findintfep(ps->dev, ep)) < 0) | ||
705 | return ret; | ||
706 | if ((ret = checkintf(ps, ret))) | ||
707 | return ret; | ||
708 | if (ep & USB_DIR_IN) | ||
709 | pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); | ||
710 | else | ||
711 | pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); | ||
712 | |||
713 | return usb_clear_halt(ps->dev, pipe); | ||
714 | } | ||
715 | |||
716 | |||
717 | static int proc_getdriver(struct dev_state *ps, void __user *arg) | ||
718 | { | ||
719 | struct usbdevfs_getdriver gd; | ||
720 | struct usb_interface *intf; | ||
721 | int ret; | ||
722 | |||
723 | if (copy_from_user(&gd, arg, sizeof(gd))) | ||
724 | return -EFAULT; | ||
725 | down_read(&usb_bus_type.subsys.rwsem); | ||
726 | intf = usb_ifnum_to_if(ps->dev, gd.interface); | ||
727 | if (!intf || !intf->dev.driver) | ||
728 | ret = -ENODATA; | ||
729 | else { | ||
730 | strncpy(gd.driver, intf->dev.driver->name, | ||
731 | sizeof(gd.driver)); | ||
732 | ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); | ||
733 | } | ||
734 | up_read(&usb_bus_type.subsys.rwsem); | ||
735 | return ret; | ||
736 | } | ||
737 | |||
738 | static int proc_connectinfo(struct dev_state *ps, void __user *arg) | ||
739 | { | ||
740 | struct usbdevfs_connectinfo ci; | ||
741 | |||
742 | ci.devnum = ps->dev->devnum; | ||
743 | ci.slow = ps->dev->speed == USB_SPEED_LOW; | ||
744 | if (copy_to_user(arg, &ci, sizeof(ci))) | ||
745 | return -EFAULT; | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int proc_resetdevice(struct dev_state *ps) | ||
750 | { | ||
751 | return usb_reset_device(ps->dev); | ||
752 | |||
753 | } | ||
754 | |||
755 | static int proc_setintf(struct dev_state *ps, void __user *arg) | ||
756 | { | ||
757 | struct usbdevfs_setinterface setintf; | ||
758 | int ret; | ||
759 | |||
760 | if (copy_from_user(&setintf, arg, sizeof(setintf))) | ||
761 | return -EFAULT; | ||
762 | if ((ret = checkintf(ps, setintf.interface))) | ||
763 | return ret; | ||
764 | return usb_set_interface(ps->dev, setintf.interface, | ||
765 | setintf.altsetting); | ||
766 | } | ||
767 | |||
768 | static int proc_setconfig(struct dev_state *ps, void __user *arg) | ||
769 | { | ||
770 | unsigned int u; | ||
771 | int status = 0; | ||
772 | struct usb_host_config *actconfig; | ||
773 | |||
774 | if (get_user(u, (unsigned int __user *)arg)) | ||
775 | return -EFAULT; | ||
776 | |||
777 | actconfig = ps->dev->actconfig; | ||
778 | |||
779 | /* Don't touch the device if any interfaces are claimed. | ||
780 | * It could interfere with other drivers' operations, and if | ||
781 | * an interface is claimed by usbfs it could easily deadlock. | ||
782 | */ | ||
783 | if (actconfig) { | ||
784 | int i; | ||
785 | |||
786 | for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { | ||
787 | if (usb_interface_claimed(actconfig->interface[i])) { | ||
788 | dev_warn (&ps->dev->dev, | ||
789 | "usbfs: interface %d claimed " | ||
790 | "while '%s' sets config #%d\n", | ||
791 | actconfig->interface[i] | ||
792 | ->cur_altsetting | ||
793 | ->desc.bInterfaceNumber, | ||
794 | current->comm, u); | ||
795 | #if 0 /* FIXME: enable in 2.6.10 or so */ | ||
796 | status = -EBUSY; | ||
797 | break; | ||
798 | #endif | ||
799 | } | ||
800 | } | ||
801 | } | ||
802 | |||
803 | /* SET_CONFIGURATION is often abused as a "cheap" driver reset, | ||
804 | * so avoid usb_set_configuration()'s kick to sysfs | ||
805 | */ | ||
806 | if (status == 0) { | ||
807 | if (actconfig && actconfig->desc.bConfigurationValue == u) | ||
808 | status = usb_reset_configuration(ps->dev); | ||
809 | else | ||
810 | status = usb_set_configuration(ps->dev, u); | ||
811 | } | ||
812 | |||
813 | return status; | ||
814 | } | ||
815 | |||
816 | |||
817 | static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | ||
818 | struct usbdevfs_iso_packet_desc __user *iso_frame_desc, | ||
819 | void __user *arg) | ||
820 | { | ||
821 | struct usbdevfs_iso_packet_desc *isopkt = NULL; | ||
822 | struct usb_host_endpoint *ep; | ||
823 | struct async *as; | ||
824 | struct usb_ctrlrequest *dr = NULL; | ||
825 | unsigned int u, totlen, isofrmlen; | ||
826 | int ret, interval = 0, ifnum = -1; | ||
827 | |||
828 | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| | ||
829 | URB_NO_FSBR|URB_ZERO_PACKET)) | ||
830 | return -EINVAL; | ||
831 | if (!uurb->buffer) | ||
832 | return -EINVAL; | ||
833 | if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX)) | ||
834 | return -EINVAL; | ||
835 | if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { | ||
836 | if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0) | ||
837 | return ifnum; | ||
838 | if ((ret = checkintf(ps, ifnum))) | ||
839 | return ret; | ||
840 | } | ||
841 | if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) | ||
842 | ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; | ||
843 | else | ||
844 | ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; | ||
845 | if (!ep) | ||
846 | return -ENOENT; | ||
847 | switch(uurb->type) { | ||
848 | case USBDEVFS_URB_TYPE_CONTROL: | ||
849 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
850 | != USB_ENDPOINT_XFER_CONTROL) | ||
851 | return -EINVAL; | ||
852 | /* min 8 byte setup packet, max arbitrary */ | ||
853 | if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE) | ||
854 | return -EINVAL; | ||
855 | if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) | ||
856 | return -ENOMEM; | ||
857 | if (copy_from_user(dr, uurb->buffer, 8)) { | ||
858 | kfree(dr); | ||
859 | return -EFAULT; | ||
860 | } | ||
861 | if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { | ||
862 | kfree(dr); | ||
863 | return -EINVAL; | ||
864 | } | ||
865 | if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) { | ||
866 | kfree(dr); | ||
867 | return ret; | ||
868 | } | ||
869 | uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); | ||
870 | uurb->number_of_packets = 0; | ||
871 | uurb->buffer_length = le16_to_cpup(&dr->wLength); | ||
872 | uurb->buffer += 8; | ||
873 | if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { | ||
874 | kfree(dr); | ||
875 | return -EFAULT; | ||
876 | } | ||
877 | break; | ||
878 | |||
879 | case USBDEVFS_URB_TYPE_BULK: | ||
880 | switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
881 | case USB_ENDPOINT_XFER_CONTROL: | ||
882 | case USB_ENDPOINT_XFER_ISOC: | ||
883 | return -EINVAL; | ||
884 | /* allow single-shot interrupt transfers, at bogus rates */ | ||
885 | } | ||
886 | uurb->number_of_packets = 0; | ||
887 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | ||
888 | return -EINVAL; | ||
889 | if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) | ||
890 | return -EFAULT; | ||
891 | break; | ||
892 | |||
893 | case USBDEVFS_URB_TYPE_ISO: | ||
894 | /* arbitrary limit */ | ||
895 | if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) | ||
896 | return -EINVAL; | ||
897 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
898 | != USB_ENDPOINT_XFER_ISOC) | ||
899 | return -EINVAL; | ||
900 | interval = 1 << min (15, ep->desc.bInterval - 1); | ||
901 | isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; | ||
902 | if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) | ||
903 | return -ENOMEM; | ||
904 | if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { | ||
905 | kfree(isopkt); | ||
906 | return -EFAULT; | ||
907 | } | ||
908 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { | ||
909 | if (isopkt[u].length > 1023) { | ||
910 | kfree(isopkt); | ||
911 | return -EINVAL; | ||
912 | } | ||
913 | totlen += isopkt[u].length; | ||
914 | } | ||
915 | if (totlen > 32768) { | ||
916 | kfree(isopkt); | ||
917 | return -EINVAL; | ||
918 | } | ||
919 | uurb->buffer_length = totlen; | ||
920 | break; | ||
921 | |||
922 | case USBDEVFS_URB_TYPE_INTERRUPT: | ||
923 | uurb->number_of_packets = 0; | ||
924 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
925 | != USB_ENDPOINT_XFER_INT) | ||
926 | return -EINVAL; | ||
927 | if (ps->dev->speed == USB_SPEED_HIGH) | ||
928 | interval = 1 << min (15, ep->desc.bInterval - 1); | ||
929 | else | ||
930 | interval = ep->desc.bInterval; | ||
931 | if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) | ||
932 | return -EINVAL; | ||
933 | if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) | ||
934 | return -EFAULT; | ||
935 | break; | ||
936 | |||
937 | default: | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | if (!(as = alloc_async(uurb->number_of_packets))) { | ||
941 | if (isopkt) | ||
942 | kfree(isopkt); | ||
943 | if (dr) | ||
944 | kfree(dr); | ||
945 | return -ENOMEM; | ||
946 | } | ||
947 | if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) { | ||
948 | if (isopkt) | ||
949 | kfree(isopkt); | ||
950 | if (dr) | ||
951 | kfree(dr); | ||
952 | free_async(as); | ||
953 | return -ENOMEM; | ||
954 | } | ||
955 | as->urb->dev = ps->dev; | ||
956 | as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); | ||
957 | as->urb->transfer_flags = uurb->flags; | ||
958 | as->urb->transfer_buffer_length = uurb->buffer_length; | ||
959 | as->urb->setup_packet = (unsigned char*)dr; | ||
960 | as->urb->start_frame = uurb->start_frame; | ||
961 | as->urb->number_of_packets = uurb->number_of_packets; | ||
962 | as->urb->interval = interval; | ||
963 | as->urb->context = as; | ||
964 | as->urb->complete = async_completed; | ||
965 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { | ||
966 | as->urb->iso_frame_desc[u].offset = totlen; | ||
967 | as->urb->iso_frame_desc[u].length = isopkt[u].length; | ||
968 | totlen += isopkt[u].length; | ||
969 | } | ||
970 | if (isopkt) | ||
971 | kfree(isopkt); | ||
972 | as->ps = ps; | ||
973 | as->userurb = arg; | ||
974 | if (uurb->endpoint & USB_DIR_IN) | ||
975 | as->userbuffer = uurb->buffer; | ||
976 | else | ||
977 | as->userbuffer = NULL; | ||
978 | as->signr = uurb->signr; | ||
979 | as->ifnum = ifnum; | ||
980 | as->task = current; | ||
981 | if (!(uurb->endpoint & USB_DIR_IN)) { | ||
982 | if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { | ||
983 | free_async(as); | ||
984 | return -EFAULT; | ||
985 | } | ||
986 | } | ||
987 | async_newpending(as); | ||
988 | if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { | ||
989 | dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); | ||
990 | async_removepending(as); | ||
991 | free_async(as); | ||
992 | return ret; | ||
993 | } | ||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | static int proc_submiturb(struct dev_state *ps, void __user *arg) | ||
998 | { | ||
999 | struct usbdevfs_urb uurb; | ||
1000 | |||
1001 | if (copy_from_user(&uurb, arg, sizeof(uurb))) | ||
1002 | return -EFAULT; | ||
1003 | |||
1004 | return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); | ||
1005 | } | ||
1006 | |||
1007 | static int proc_unlinkurb(struct dev_state *ps, void __user *arg) | ||
1008 | { | ||
1009 | struct async *as; | ||
1010 | |||
1011 | as = async_getpending(ps, arg); | ||
1012 | if (!as) | ||
1013 | return -EINVAL; | ||
1014 | usb_kill_urb(as->urb); | ||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | static int processcompl(struct async *as, void __user * __user *arg) | ||
1019 | { | ||
1020 | struct urb *urb = as->urb; | ||
1021 | struct usbdevfs_urb __user *userurb = as->userurb; | ||
1022 | void __user *addr = as->userurb; | ||
1023 | unsigned int i; | ||
1024 | |||
1025 | if (as->userbuffer) | ||
1026 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) | ||
1027 | return -EFAULT; | ||
1028 | if (put_user(urb->status, &userurb->status)) | ||
1029 | return -EFAULT; | ||
1030 | if (put_user(urb->actual_length, &userurb->actual_length)) | ||
1031 | return -EFAULT; | ||
1032 | if (put_user(urb->error_count, &userurb->error_count)) | ||
1033 | return -EFAULT; | ||
1034 | |||
1035 | if (!(usb_pipeisoc(urb->pipe))) | ||
1036 | return 0; | ||
1037 | for (i = 0; i < urb->number_of_packets; i++) { | ||
1038 | if (put_user(urb->iso_frame_desc[i].actual_length, | ||
1039 | &userurb->iso_frame_desc[i].actual_length)) | ||
1040 | return -EFAULT; | ||
1041 | if (put_user(urb->iso_frame_desc[i].status, | ||
1042 | &userurb->iso_frame_desc[i].status)) | ||
1043 | return -EFAULT; | ||
1044 | } | ||
1045 | |||
1046 | free_async(as); | ||
1047 | |||
1048 | if (put_user(addr, (void __user * __user *)arg)) | ||
1049 | return -EFAULT; | ||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | static struct async* reap_as(struct dev_state *ps) | ||
1054 | { | ||
1055 | DECLARE_WAITQUEUE(wait, current); | ||
1056 | struct async *as = NULL; | ||
1057 | struct usb_device *dev = ps->dev; | ||
1058 | |||
1059 | add_wait_queue(&ps->wait, &wait); | ||
1060 | for (;;) { | ||
1061 | __set_current_state(TASK_INTERRUPTIBLE); | ||
1062 | if ((as = async_getcompleted(ps))) | ||
1063 | break; | ||
1064 | if (signal_pending(current)) | ||
1065 | break; | ||
1066 | usb_unlock_device(dev); | ||
1067 | schedule(); | ||
1068 | usb_lock_device(dev); | ||
1069 | } | ||
1070 | remove_wait_queue(&ps->wait, &wait); | ||
1071 | set_current_state(TASK_RUNNING); | ||
1072 | return as; | ||
1073 | } | ||
1074 | |||
1075 | static int proc_reapurb(struct dev_state *ps, void __user *arg) | ||
1076 | { | ||
1077 | struct async *as = reap_as(ps); | ||
1078 | if (as) | ||
1079 | return processcompl(as, (void __user * __user *)arg); | ||
1080 | if (signal_pending(current)) | ||
1081 | return -EINTR; | ||
1082 | return -EIO; | ||
1083 | } | ||
1084 | |||
1085 | static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) | ||
1086 | { | ||
1087 | struct async *as; | ||
1088 | |||
1089 | if (!(as = async_getcompleted(ps))) | ||
1090 | return -EAGAIN; | ||
1091 | return processcompl(as, (void __user * __user *)arg); | ||
1092 | } | ||
1093 | |||
1094 | #ifdef CONFIG_COMPAT | ||
1095 | |||
1096 | static int get_urb32(struct usbdevfs_urb *kurb, | ||
1097 | struct usbdevfs_urb32 __user *uurb) | ||
1098 | { | ||
1099 | __u32 uptr; | ||
1100 | if (get_user(kurb->type, &uurb->type) || | ||
1101 | __get_user(kurb->endpoint, &uurb->endpoint) || | ||
1102 | __get_user(kurb->status, &uurb->status) || | ||
1103 | __get_user(kurb->flags, &uurb->flags) || | ||
1104 | __get_user(kurb->buffer_length, &uurb->buffer_length) || | ||
1105 | __get_user(kurb->actual_length, &uurb->actual_length) || | ||
1106 | __get_user(kurb->start_frame, &uurb->start_frame) || | ||
1107 | __get_user(kurb->number_of_packets, &uurb->number_of_packets) || | ||
1108 | __get_user(kurb->error_count, &uurb->error_count) || | ||
1109 | __get_user(kurb->signr, &uurb->signr)) | ||
1110 | return -EFAULT; | ||
1111 | |||
1112 | if (__get_user(uptr, &uurb->buffer)) | ||
1113 | return -EFAULT; | ||
1114 | kurb->buffer = compat_ptr(uptr); | ||
1115 | if (__get_user(uptr, &uurb->buffer)) | ||
1116 | return -EFAULT; | ||
1117 | kurb->usercontext = compat_ptr(uptr); | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) | ||
1123 | { | ||
1124 | struct usbdevfs_urb uurb; | ||
1125 | |||
1126 | if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) | ||
1127 | return -EFAULT; | ||
1128 | |||
1129 | return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb __user *)arg)->iso_frame_desc, arg); | ||
1130 | } | ||
1131 | |||
1132 | static int processcompl_compat(struct async *as, void __user * __user *arg) | ||
1133 | { | ||
1134 | struct urb *urb = as->urb; | ||
1135 | struct usbdevfs_urb32 __user *userurb = as->userurb; | ||
1136 | void __user *addr = as->userurb; | ||
1137 | unsigned int i; | ||
1138 | |||
1139 | if (as->userbuffer) | ||
1140 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) | ||
1141 | return -EFAULT; | ||
1142 | if (put_user(urb->status, &userurb->status)) | ||
1143 | return -EFAULT; | ||
1144 | if (put_user(urb->actual_length, &userurb->actual_length)) | ||
1145 | return -EFAULT; | ||
1146 | if (put_user(urb->error_count, &userurb->error_count)) | ||
1147 | return -EFAULT; | ||
1148 | |||
1149 | if (!(usb_pipeisoc(urb->pipe))) | ||
1150 | return 0; | ||
1151 | for (i = 0; i < urb->number_of_packets; i++) { | ||
1152 | if (put_user(urb->iso_frame_desc[i].actual_length, | ||
1153 | &userurb->iso_frame_desc[i].actual_length)) | ||
1154 | return -EFAULT; | ||
1155 | if (put_user(urb->iso_frame_desc[i].status, | ||
1156 | &userurb->iso_frame_desc[i].status)) | ||
1157 | return -EFAULT; | ||
1158 | } | ||
1159 | |||
1160 | free_async(as); | ||
1161 | if (put_user((u32)(u64)addr, (u32 __user *)arg)) | ||
1162 | return -EFAULT; | ||
1163 | return 0; | ||
1164 | } | ||
1165 | |||
1166 | static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) | ||
1167 | { | ||
1168 | struct async *as = reap_as(ps); | ||
1169 | if (as) | ||
1170 | return processcompl_compat(as, (void __user * __user *)arg); | ||
1171 | if (signal_pending(current)) | ||
1172 | return -EINTR; | ||
1173 | return -EIO; | ||
1174 | } | ||
1175 | |||
1176 | static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) | ||
1177 | { | ||
1178 | struct async *as; | ||
1179 | |||
1180 | printk("reapurbnblock\n"); | ||
1181 | if (!(as = async_getcompleted(ps))) | ||
1182 | return -EAGAIN; | ||
1183 | printk("reap got as %p\n", as); | ||
1184 | return processcompl_compat(as, (void __user * __user *)arg); | ||
1185 | } | ||
1186 | |||
1187 | #endif | ||
1188 | |||
1189 | static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) | ||
1190 | { | ||
1191 | struct usbdevfs_disconnectsignal ds; | ||
1192 | |||
1193 | if (copy_from_user(&ds, arg, sizeof(ds))) | ||
1194 | return -EFAULT; | ||
1195 | if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX)) | ||
1196 | return -EINVAL; | ||
1197 | ps->discsignr = ds.signr; | ||
1198 | ps->disccontext = ds.context; | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static int proc_claiminterface(struct dev_state *ps, void __user *arg) | ||
1203 | { | ||
1204 | unsigned int ifnum; | ||
1205 | |||
1206 | if (get_user(ifnum, (unsigned int __user *)arg)) | ||
1207 | return -EFAULT; | ||
1208 | return claimintf(ps, ifnum); | ||
1209 | } | ||
1210 | |||
1211 | static int proc_releaseinterface(struct dev_state *ps, void __user *arg) | ||
1212 | { | ||
1213 | unsigned int ifnum; | ||
1214 | int ret; | ||
1215 | |||
1216 | if (get_user(ifnum, (unsigned int __user *)arg)) | ||
1217 | return -EFAULT; | ||
1218 | if ((ret = releaseintf(ps, ifnum)) < 0) | ||
1219 | return ret; | ||
1220 | destroy_async_on_interface (ps, ifnum); | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | static int proc_ioctl (struct dev_state *ps, void __user *arg) | ||
1225 | { | ||
1226 | struct usbdevfs_ioctl ctrl; | ||
1227 | int size; | ||
1228 | void *buf = NULL; | ||
1229 | int retval = 0; | ||
1230 | struct usb_interface *intf = NULL; | ||
1231 | struct usb_driver *driver = NULL; | ||
1232 | int i; | ||
1233 | |||
1234 | /* get input parameters and alloc buffer */ | ||
1235 | if (copy_from_user(&ctrl, arg, sizeof (ctrl))) | ||
1236 | return -EFAULT; | ||
1237 | if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { | ||
1238 | if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) | ||
1239 | return -ENOMEM; | ||
1240 | if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { | ||
1241 | if (copy_from_user (buf, ctrl.data, size)) { | ||
1242 | kfree (buf); | ||
1243 | return -EFAULT; | ||
1244 | } | ||
1245 | } else { | ||
1246 | memset (buf, 0, size); | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | if (!connected(ps->dev)) { | ||
1251 | if (buf) | ||
1252 | kfree(buf); | ||
1253 | return -ENODEV; | ||
1254 | } | ||
1255 | |||
1256 | if (ps->dev->state != USB_STATE_CONFIGURED) | ||
1257 | retval = -EHOSTUNREACH; | ||
1258 | else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) | ||
1259 | retval = -EINVAL; | ||
1260 | else switch (ctrl.ioctl_code) { | ||
1261 | |||
1262 | /* disconnect kernel driver from interface */ | ||
1263 | case USBDEVFS_DISCONNECT: | ||
1264 | |||
1265 | /* don't allow the user to unbind the hub driver from | ||
1266 | * a hub with children to manage */ | ||
1267 | for (i = 0; i < ps->dev->maxchild; ++i) { | ||
1268 | if (ps->dev->children[i]) | ||
1269 | retval = -EBUSY; | ||
1270 | } | ||
1271 | if (retval) | ||
1272 | break; | ||
1273 | |||
1274 | down_write(&usb_bus_type.subsys.rwsem); | ||
1275 | if (intf->dev.driver) { | ||
1276 | driver = to_usb_driver(intf->dev.driver); | ||
1277 | dev_dbg (&intf->dev, "disconnect by usbfs\n"); | ||
1278 | usb_driver_release_interface(driver, intf); | ||
1279 | } else | ||
1280 | retval = -ENODATA; | ||
1281 | up_write(&usb_bus_type.subsys.rwsem); | ||
1282 | break; | ||
1283 | |||
1284 | /* let kernel drivers try to (re)bind to the interface */ | ||
1285 | case USBDEVFS_CONNECT: | ||
1286 | usb_unlock_device(ps->dev); | ||
1287 | usb_lock_all_devices(); | ||
1288 | bus_rescan_devices(intf->dev.bus); | ||
1289 | usb_unlock_all_devices(); | ||
1290 | usb_lock_device(ps->dev); | ||
1291 | break; | ||
1292 | |||
1293 | /* talk directly to the interface's driver */ | ||
1294 | default: | ||
1295 | down_read(&usb_bus_type.subsys.rwsem); | ||
1296 | if (intf->dev.driver) | ||
1297 | driver = to_usb_driver(intf->dev.driver); | ||
1298 | if (driver == NULL || driver->ioctl == NULL) { | ||
1299 | retval = -ENOTTY; | ||
1300 | } else { | ||
1301 | retval = driver->ioctl (intf, ctrl.ioctl_code, buf); | ||
1302 | if (retval == -ENOIOCTLCMD) | ||
1303 | retval = -ENOTTY; | ||
1304 | } | ||
1305 | up_read(&usb_bus_type.subsys.rwsem); | ||
1306 | } | ||
1307 | |||
1308 | /* cleanup and return */ | ||
1309 | if (retval >= 0 | ||
1310 | && (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 | ||
1311 | && size > 0 | ||
1312 | && copy_to_user (ctrl.data, buf, size) != 0) | ||
1313 | retval = -EFAULT; | ||
1314 | if (buf != NULL) | ||
1315 | kfree (buf); | ||
1316 | return retval; | ||
1317 | } | ||
1318 | |||
1319 | /* | ||
1320 | * NOTE: All requests here that have interface numbers as parameters | ||
1321 | * are assuming that somehow the configuration has been prevented from | ||
1322 | * changing. But there's no mechanism to ensure that... | ||
1323 | */ | ||
1324 | static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
1325 | { | ||
1326 | struct dev_state *ps = (struct dev_state *)file->private_data; | ||
1327 | struct usb_device *dev = ps->dev; | ||
1328 | void __user *p = (void __user *)arg; | ||
1329 | int ret = -ENOTTY; | ||
1330 | |||
1331 | if (!(file->f_mode & FMODE_WRITE)) | ||
1332 | return -EPERM; | ||
1333 | usb_lock_device(dev); | ||
1334 | if (!connected(dev)) { | ||
1335 | usb_unlock_device(dev); | ||
1336 | return -ENODEV; | ||
1337 | } | ||
1338 | |||
1339 | switch (cmd) { | ||
1340 | case USBDEVFS_CONTROL: | ||
1341 | snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); | ||
1342 | ret = proc_control(ps, p); | ||
1343 | if (ret >= 0) | ||
1344 | inode->i_mtime = CURRENT_TIME; | ||
1345 | break; | ||
1346 | |||
1347 | case USBDEVFS_BULK: | ||
1348 | snoop(&dev->dev, "%s: BULK\n", __FUNCTION__); | ||
1349 | ret = proc_bulk(ps, p); | ||
1350 | if (ret >= 0) | ||
1351 | inode->i_mtime = CURRENT_TIME; | ||
1352 | break; | ||
1353 | |||
1354 | case USBDEVFS_RESETEP: | ||
1355 | snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__); | ||
1356 | ret = proc_resetep(ps, p); | ||
1357 | if (ret >= 0) | ||
1358 | inode->i_mtime = CURRENT_TIME; | ||
1359 | break; | ||
1360 | |||
1361 | case USBDEVFS_RESET: | ||
1362 | snoop(&dev->dev, "%s: RESET\n", __FUNCTION__); | ||
1363 | ret = proc_resetdevice(ps); | ||
1364 | break; | ||
1365 | |||
1366 | case USBDEVFS_CLEAR_HALT: | ||
1367 | snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__); | ||
1368 | ret = proc_clearhalt(ps, p); | ||
1369 | if (ret >= 0) | ||
1370 | inode->i_mtime = CURRENT_TIME; | ||
1371 | break; | ||
1372 | |||
1373 | case USBDEVFS_GETDRIVER: | ||
1374 | snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__); | ||
1375 | ret = proc_getdriver(ps, p); | ||
1376 | break; | ||
1377 | |||
1378 | case USBDEVFS_CONNECTINFO: | ||
1379 | snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__); | ||
1380 | ret = proc_connectinfo(ps, p); | ||
1381 | break; | ||
1382 | |||
1383 | case USBDEVFS_SETINTERFACE: | ||
1384 | snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__); | ||
1385 | ret = proc_setintf(ps, p); | ||
1386 | break; | ||
1387 | |||
1388 | case USBDEVFS_SETCONFIGURATION: | ||
1389 | snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__); | ||
1390 | ret = proc_setconfig(ps, p); | ||
1391 | break; | ||
1392 | |||
1393 | case USBDEVFS_SUBMITURB: | ||
1394 | snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__); | ||
1395 | ret = proc_submiturb(ps, p); | ||
1396 | if (ret >= 0) | ||
1397 | inode->i_mtime = CURRENT_TIME; | ||
1398 | break; | ||
1399 | |||
1400 | #ifdef CONFIG_COMPAT | ||
1401 | |||
1402 | case USBDEVFS_SUBMITURB32: | ||
1403 | snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__); | ||
1404 | ret = proc_submiturb_compat(ps, p); | ||
1405 | if (ret >= 0) | ||
1406 | inode->i_mtime = CURRENT_TIME; | ||
1407 | break; | ||
1408 | |||
1409 | case USBDEVFS_REAPURB32: | ||
1410 | snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__); | ||
1411 | ret = proc_reapurb_compat(ps, p); | ||
1412 | break; | ||
1413 | |||
1414 | case USBDEVFS_REAPURBNDELAY32: | ||
1415 | snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__); | ||
1416 | ret = proc_reapurbnonblock_compat(ps, p); | ||
1417 | break; | ||
1418 | |||
1419 | #endif | ||
1420 | |||
1421 | case USBDEVFS_DISCARDURB: | ||
1422 | snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); | ||
1423 | ret = proc_unlinkurb(ps, p); | ||
1424 | break; | ||
1425 | |||
1426 | case USBDEVFS_REAPURB: | ||
1427 | snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__); | ||
1428 | ret = proc_reapurb(ps, p); | ||
1429 | break; | ||
1430 | |||
1431 | case USBDEVFS_REAPURBNDELAY: | ||
1432 | snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__); | ||
1433 | ret = proc_reapurbnonblock(ps, p); | ||
1434 | break; | ||
1435 | |||
1436 | case USBDEVFS_DISCSIGNAL: | ||
1437 | snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__); | ||
1438 | ret = proc_disconnectsignal(ps, p); | ||
1439 | break; | ||
1440 | |||
1441 | case USBDEVFS_CLAIMINTERFACE: | ||
1442 | snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__); | ||
1443 | ret = proc_claiminterface(ps, p); | ||
1444 | break; | ||
1445 | |||
1446 | case USBDEVFS_RELEASEINTERFACE: | ||
1447 | snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__); | ||
1448 | ret = proc_releaseinterface(ps, p); | ||
1449 | break; | ||
1450 | |||
1451 | case USBDEVFS_IOCTL: | ||
1452 | snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); | ||
1453 | ret = proc_ioctl(ps, p); | ||
1454 | break; | ||
1455 | } | ||
1456 | usb_unlock_device(dev); | ||
1457 | if (ret >= 0) | ||
1458 | inode->i_atime = CURRENT_TIME; | ||
1459 | return ret; | ||
1460 | } | ||
1461 | |||
1462 | /* No kernel lock - fine */ | ||
1463 | static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait) | ||
1464 | { | ||
1465 | struct dev_state *ps = (struct dev_state *)file->private_data; | ||
1466 | unsigned int mask = 0; | ||
1467 | |||
1468 | poll_wait(file, &ps->wait, wait); | ||
1469 | if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) | ||
1470 | mask |= POLLOUT | POLLWRNORM; | ||
1471 | if (!connected(ps->dev)) | ||
1472 | mask |= POLLERR | POLLHUP; | ||
1473 | return mask; | ||
1474 | } | ||
1475 | |||
1476 | struct file_operations usbfs_device_file_operations = { | ||
1477 | .llseek = usbdev_lseek, | ||
1478 | .read = usbdev_read, | ||
1479 | .poll = usbdev_poll, | ||
1480 | .ioctl = usbdev_ioctl, | ||
1481 | .open = usbdev_open, | ||
1482 | .release = usbdev_release, | ||
1483 | }; | ||