diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index f86bf1454e21..d12bc5e84a1a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/module.h> | 43 | #include <linux/module.h> |
44 | #include <linux/usb.h> | 44 | #include <linux/usb.h> |
45 | #include <linux/usbdevice_fs.h> | 45 | #include <linux/usbdevice_fs.h> |
46 | #include <linux/cdev.h> | ||
46 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
47 | #include <asm/byteorder.h> | 48 | #include <asm/byteorder.h> |
48 | #include <linux/moduleparam.h> | 49 | #include <linux/moduleparam.h> |
@@ -50,6 +51,10 @@ | |||
50 | #include "hcd.h" /* for usbcore internals */ | 51 | #include "hcd.h" /* for usbcore internals */ |
51 | #include "usb.h" | 52 | #include "usb.h" |
52 | 53 | ||
54 | #define USB_MAXBUS 64 | ||
55 | #define USB_DEVICE_MAX USB_MAXBUS * 128 | ||
56 | static struct class *usb_device_class; | ||
57 | |||
53 | struct async { | 58 | struct async { |
54 | struct list_head asynclist; | 59 | struct list_head asynclist; |
55 | struct dev_state *ps; | 60 | struct dev_state *ps; |
@@ -487,7 +492,7 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig | |||
487 | */ | 492 | */ |
488 | static int usbdev_open(struct inode *inode, struct file *file) | 493 | static int usbdev_open(struct inode *inode, struct file *file) |
489 | { | 494 | { |
490 | struct usb_device *dev; | 495 | struct usb_device *dev = NULL; |
491 | struct dev_state *ps; | 496 | struct dev_state *ps; |
492 | int ret; | 497 | int ret; |
493 | 498 | ||
@@ -501,11 +506,16 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
501 | 506 | ||
502 | lock_kernel(); | 507 | lock_kernel(); |
503 | ret = -ENOENT; | 508 | ret = -ENOENT; |
504 | dev = usb_get_dev(inode->u.generic_ip); | 509 | /* check if we are called from a real node or usbfs */ |
510 | if (imajor(inode) == USB_DEVICE_MAJOR) | ||
511 | dev = usbdev_lookup_minor(iminor(inode)); | ||
512 | if (!dev) | ||
513 | dev = inode->u.generic_ip; | ||
505 | if (!dev) { | 514 | if (!dev) { |
506 | kfree(ps); | 515 | kfree(ps); |
507 | goto out; | 516 | goto out; |
508 | } | 517 | } |
518 | usb_get_dev(dev); | ||
509 | ret = 0; | 519 | ret = 0; |
510 | ps->dev = dev; | 520 | ps->dev = dev; |
511 | ps->file = file; | 521 | ps->file = file; |
@@ -1477,3 +1487,80 @@ struct file_operations usbfs_device_file_operations = { | |||
1477 | .open = usbdev_open, | 1487 | .open = usbdev_open, |
1478 | .release = usbdev_release, | 1488 | .release = usbdev_release, |
1479 | }; | 1489 | }; |
1490 | |||
1491 | struct usb_device *usbdev_lookup_minor(int minor) | ||
1492 | { | ||
1493 | struct class_device *class_dev; | ||
1494 | struct usb_device *dev = NULL; | ||
1495 | |||
1496 | down(&usb_device_class->sem); | ||
1497 | list_for_each_entry(class_dev, &usb_device_class->children, node) { | ||
1498 | if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { | ||
1499 | dev = class_dev->class_data; | ||
1500 | break; | ||
1501 | } | ||
1502 | } | ||
1503 | up(&usb_device_class->sem); | ||
1504 | |||
1505 | return dev; | ||
1506 | }; | ||
1507 | |||
1508 | void usbdev_add(struct usb_device *dev) | ||
1509 | { | ||
1510 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); | ||
1511 | |||
1512 | dev->class_dev = class_device_create(usb_device_class, | ||
1513 | MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, | ||
1514 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); | ||
1515 | |||
1516 | dev->class_dev->class_data = dev; | ||
1517 | } | ||
1518 | |||
1519 | void usbdev_remove(struct usb_device *dev) | ||
1520 | { | ||
1521 | class_device_unregister(dev->class_dev); | ||
1522 | } | ||
1523 | |||
1524 | static struct cdev usb_device_cdev = { | ||
1525 | .kobj = {.name = "usb_device", }, | ||
1526 | .owner = THIS_MODULE, | ||
1527 | }; | ||
1528 | |||
1529 | int __init usbdev_init(void) | ||
1530 | { | ||
1531 | int retval; | ||
1532 | |||
1533 | retval = register_chrdev_region(MKDEV(USB_DEVICE_MAJOR, 0), | ||
1534 | USB_DEVICE_MAX, "usb_device"); | ||
1535 | if (retval) { | ||
1536 | err("unable to register minors for usb_device"); | ||
1537 | goto out; | ||
1538 | } | ||
1539 | cdev_init(&usb_device_cdev, &usbfs_device_file_operations); | ||
1540 | retval = cdev_add(&usb_device_cdev, | ||
1541 | MKDEV(USB_DEVICE_MAJOR, 0), USB_DEVICE_MAX); | ||
1542 | if (retval) { | ||
1543 | err("unable to get usb_device major %d", USB_DEVICE_MAJOR); | ||
1544 | unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX); | ||
1545 | goto out; | ||
1546 | } | ||
1547 | usb_device_class = class_create(THIS_MODULE, "usb_device"); | ||
1548 | if (IS_ERR(usb_device_class)) { | ||
1549 | err("unable to register usb_device class"); | ||
1550 | retval = PTR_ERR(usb_device_class); | ||
1551 | usb_device_class = NULL; | ||
1552 | cdev_del(&usb_device_cdev); | ||
1553 | unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX); | ||
1554 | } | ||
1555 | |||
1556 | out: | ||
1557 | return retval; | ||
1558 | } | ||
1559 | |||
1560 | void usbdev_cleanup(void) | ||
1561 | { | ||
1562 | class_destroy(usb_device_class); | ||
1563 | cdev_del(&usb_device_cdev); | ||
1564 | unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX); | ||
1565 | } | ||
1566 | |||