diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2007-03-13 10:59:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-04-27 16:28:37 -0400 |
commit | 9f8b17e643fe6aa505629658445849397bda4e4f (patch) | |
tree | 30c45914f7be9f355db30964323673c7d37080e8 /drivers | |
parent | 87840289637e9ea95118ebd76e2e335fdcddd725 (diff) |
USB: make usbdevices export their device nodes instead of using a separate class
o The "real" usb-devices export now a device node which can
populate /dev/bus/usb.
o The usb_device class is optional now and can be disabled in the
kernel config. Major/minor of the "real" devices and class devices
are the same.
o The environment of the usb-device event contains DEVNUM and BUSNUM to
help udev and get rid of the ugly udev rule we need for the class
devices.
o The usb-devices and usb-interfaces share the same bus, so I used
the new "struct device_type" to let these devices identify
themselves. This also removes the current logic of using a magic
platform-pointer.
The name of the device_type is also added to the environment
which makes it easier to distinguish the different kinds of devices
on the same subsystem.
It looks like this:
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1
SUBSYSTEM=usb
SEQNUM=1533
MAJOR=189
MINOR=131
DEVTYPE=usb_device
PRODUCT=46d/c03e/2000
TYPE=0/0/0
BUSNUM=002
DEVNUM=004
This udev rule works as a replacement for usb_device class devices:
SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
Updated patch, which needs the device_type patches in Greg's tree.
I also got a bugzilla assigned for this. :)
https://bugzilla.novell.com/show_bug.cgi?id=250659
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/Kconfig | 25 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 94 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 58 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 10 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 65 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 20 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 14 |
8 files changed, 176 insertions, 112 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 2fc0f88a3d86..f493fb1eaa27 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig | |||
@@ -31,7 +31,30 @@ config USB_DEVICEFS | |||
31 | For the format of the various /proc/bus/usb/ files, please read | 31 | For the format of the various /proc/bus/usb/ files, please read |
32 | <file:Documentation/usb/proc_usb_info.txt>. | 32 | <file:Documentation/usb/proc_usb_info.txt>. |
33 | 33 | ||
34 | Most users want to say Y here. | 34 | Usbfs files can't handle Access Control Lists (ACL), which are the |
35 | default way to grant access to USB devices for untrusted users of a | ||
36 | desktop system. The usbfs functionality is replaced by real | ||
37 | device-nodes managed by udev. These nodes live in /dev/bus/usb and | ||
38 | are used by libusb. | ||
39 | |||
40 | config USB_DEVICE_CLASS | ||
41 | bool "USB device class-devices (DEPRECATED)" | ||
42 | depends on USB | ||
43 | default n | ||
44 | ---help--- | ||
45 | Userspace access to USB devices is granted by device-nodes exported | ||
46 | directly from the usbdev in sysfs. Old versions of the driver | ||
47 | core and udev needed additional class devices to export device nodes. | ||
48 | |||
49 | These additional devices are difficult to handle in userspace, if | ||
50 | information about USB interfaces must be available. One device contains | ||
51 | the device node, the other device contains the interface data. Both | ||
52 | devices are at the same level in sysfs (siblings) and one can't access | ||
53 | the other. The device node created directly by the usbdev is the parent | ||
54 | device of the interface and therefore easily accessible from the interface | ||
55 | event. | ||
56 | |||
57 | This option provides backward compatibility if needed. | ||
35 | 58 | ||
36 | config USB_DYNAMIC_MINORS | 59 | config USB_DYNAMIC_MINORS |
37 | bool "Dynamic USB minor allocation (EXPERIMENTAL)" | 60 | bool "Dynamic USB minor allocation (EXPERIMENTAL)" |
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fc3545ddb06e..e023f3d56248 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -57,7 +57,6 @@ | |||
57 | 57 | ||
58 | #define USB_MAXBUS 64 | 58 | #define USB_MAXBUS 64 |
59 | #define USB_DEVICE_MAX USB_MAXBUS * 128 | 59 | #define USB_DEVICE_MAX USB_MAXBUS * 128 |
60 | static struct class *usb_device_class; | ||
61 | 60 | ||
62 | /* Mutual exclusion for removal, open, and release */ | 61 | /* Mutual exclusion for removal, open, and release */ |
63 | DEFINE_MUTEX(usbfs_mutex); | 62 | DEFINE_MUTEX(usbfs_mutex); |
@@ -514,22 +513,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig | |||
514 | return ret; | 513 | return ret; |
515 | } | 514 | } |
516 | 515 | ||
517 | static struct usb_device *usbdev_lookup_minor(int minor) | 516 | static int __match_minor(struct device *dev, void *data) |
518 | { | 517 | { |
519 | struct device *device; | 518 | int minor = *((int *)data); |
520 | struct usb_device *udev = NULL; | ||
521 | 519 | ||
522 | down(&usb_device_class->sem); | 520 | if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) |
523 | list_for_each_entry(device, &usb_device_class->devices, node) { | 521 | return 1; |
524 | if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { | 522 | return 0; |
525 | udev = device->platform_data; | 523 | } |
526 | break; | ||
527 | } | ||
528 | } | ||
529 | up(&usb_device_class->sem); | ||
530 | 524 | ||
531 | return udev; | 525 | static struct usb_device *usbdev_lookup_by_minor(int minor) |
532 | }; | 526 | { |
527 | struct device *dev; | ||
528 | |||
529 | dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor); | ||
530 | if (!dev) | ||
531 | return NULL; | ||
532 | put_device(dev); | ||
533 | return container_of(dev, struct usb_device, dev); | ||
534 | } | ||
533 | 535 | ||
534 | /* | 536 | /* |
535 | * file operations | 537 | * file operations |
@@ -548,11 +550,14 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
548 | goto out; | 550 | goto out; |
549 | 551 | ||
550 | ret = -ENOENT; | 552 | ret = -ENOENT; |
551 | /* check if we are called from a real node or usbfs */ | 553 | /* usbdev device-node */ |
552 | if (imajor(inode) == USB_DEVICE_MAJOR) | 554 | if (imajor(inode) == USB_DEVICE_MAJOR) |
553 | dev = usbdev_lookup_minor(iminor(inode)); | 555 | dev = usbdev_lookup_by_minor(iminor(inode)); |
556 | #ifdef CONFIG_USB_DEVICEFS | ||
557 | /* procfs file */ | ||
554 | if (!dev) | 558 | if (!dev) |
555 | dev = inode->i_private; | 559 | dev = inode->i_private; |
560 | #endif | ||
556 | if (!dev) | 561 | if (!dev) |
557 | goto out; | 562 | goto out; |
558 | ret = usb_autoresume_device(dev); | 563 | ret = usb_autoresume_device(dev); |
@@ -1570,7 +1575,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai | |||
1570 | return mask; | 1575 | return mask; |
1571 | } | 1576 | } |
1572 | 1577 | ||
1573 | const struct file_operations usbfs_device_file_operations = { | 1578 | const struct file_operations usbdev_file_operations = { |
1574 | .llseek = usbdev_lseek, | 1579 | .llseek = usbdev_lseek, |
1575 | .read = usbdev_read, | 1580 | .read = usbdev_read, |
1576 | .poll = usbdev_poll, | 1581 | .poll = usbdev_poll, |
@@ -1579,50 +1584,53 @@ const struct file_operations usbfs_device_file_operations = { | |||
1579 | .release = usbdev_release, | 1584 | .release = usbdev_release, |
1580 | }; | 1585 | }; |
1581 | 1586 | ||
1582 | static int usbdev_add(struct usb_device *dev) | 1587 | #ifdef CONFIG_USB_DEVICE_CLASS |
1588 | static struct class *usb_classdev_class; | ||
1589 | |||
1590 | static int usb_classdev_add(struct usb_device *dev) | ||
1583 | { | 1591 | { |
1584 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); | 1592 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); |
1585 | 1593 | ||
1586 | dev->usbfs_dev = device_create(usb_device_class, &dev->dev, | 1594 | dev->usb_classdev = device_create(usb_classdev_class, &dev->dev, |
1587 | MKDEV(USB_DEVICE_MAJOR, minor), | 1595 | MKDEV(USB_DEVICE_MAJOR, minor), |
1588 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); | 1596 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); |
1589 | if (IS_ERR(dev->usbfs_dev)) | 1597 | if (IS_ERR(dev->usb_classdev)) |
1590 | return PTR_ERR(dev->usbfs_dev); | 1598 | return PTR_ERR(dev->usb_classdev); |
1591 | 1599 | ||
1592 | dev->usbfs_dev->platform_data = dev; | ||
1593 | return 0; | 1600 | return 0; |
1594 | } | 1601 | } |
1595 | 1602 | ||
1596 | static void usbdev_remove(struct usb_device *dev) | 1603 | static void usb_classdev_remove(struct usb_device *dev) |
1597 | { | 1604 | { |
1598 | device_unregister(dev->usbfs_dev); | 1605 | device_unregister(dev->usb_classdev); |
1599 | } | 1606 | } |
1600 | 1607 | ||
1601 | static int usbdev_notify(struct notifier_block *self, unsigned long action, | 1608 | static int usb_classdev_notify(struct notifier_block *self, |
1602 | void *dev) | 1609 | unsigned long action, void *dev) |
1603 | { | 1610 | { |
1604 | switch (action) { | 1611 | switch (action) { |
1605 | case USB_DEVICE_ADD: | 1612 | case USB_DEVICE_ADD: |
1606 | if (usbdev_add(dev)) | 1613 | if (usb_classdev_add(dev)) |
1607 | return NOTIFY_BAD; | 1614 | return NOTIFY_BAD; |
1608 | break; | 1615 | break; |
1609 | case USB_DEVICE_REMOVE: | 1616 | case USB_DEVICE_REMOVE: |
1610 | usbdev_remove(dev); | 1617 | usb_classdev_remove(dev); |
1611 | break; | 1618 | break; |
1612 | } | 1619 | } |
1613 | return NOTIFY_OK; | 1620 | return NOTIFY_OK; |
1614 | } | 1621 | } |
1615 | 1622 | ||
1616 | static struct notifier_block usbdev_nb = { | 1623 | static struct notifier_block usbdev_nb = { |
1617 | .notifier_call = usbdev_notify, | 1624 | .notifier_call = usb_classdev_notify, |
1618 | }; | 1625 | }; |
1626 | #endif | ||
1619 | 1627 | ||
1620 | static struct cdev usb_device_cdev = { | 1628 | static struct cdev usb_device_cdev = { |
1621 | .kobj = {.name = "usb_device", }, | 1629 | .kobj = {.name = "usb_device", }, |
1622 | .owner = THIS_MODULE, | 1630 | .owner = THIS_MODULE, |
1623 | }; | 1631 | }; |
1624 | 1632 | ||
1625 | int __init usbdev_init(void) | 1633 | int __init usb_devio_init(void) |
1626 | { | 1634 | { |
1627 | int retval; | 1635 | int retval; |
1628 | 1636 | ||
@@ -1632,38 +1640,38 @@ int __init usbdev_init(void) | |||
1632 | err("unable to register minors for usb_device"); | 1640 | err("unable to register minors for usb_device"); |
1633 | goto out; | 1641 | goto out; |
1634 | } | 1642 | } |
1635 | cdev_init(&usb_device_cdev, &usbfs_device_file_operations); | 1643 | cdev_init(&usb_device_cdev, &usbdev_file_operations); |
1636 | retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); | 1644 | retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); |
1637 | if (retval) { | 1645 | if (retval) { |
1638 | err("unable to get usb_device major %d", USB_DEVICE_MAJOR); | 1646 | err("unable to get usb_device major %d", USB_DEVICE_MAJOR); |
1639 | goto error_cdev; | 1647 | goto error_cdev; |
1640 | } | 1648 | } |
1641 | usb_device_class = class_create(THIS_MODULE, "usb_device"); | 1649 | #ifdef CONFIG_USB_DEVICE_CLASS |
1642 | if (IS_ERR(usb_device_class)) { | 1650 | usb_classdev_class = class_create(THIS_MODULE, "usb_device"); |
1651 | if (IS_ERR(usb_classdev_class)) { | ||
1643 | err("unable to register usb_device class"); | 1652 | err("unable to register usb_device class"); |
1644 | retval = PTR_ERR(usb_device_class); | 1653 | retval = PTR_ERR(usb_classdev_class); |
1645 | goto error_class; | 1654 | cdev_del(&usb_device_cdev); |
1655 | usb_classdev_class = NULL; | ||
1656 | goto out; | ||
1646 | } | 1657 | } |
1647 | 1658 | ||
1648 | usb_register_notify(&usbdev_nb); | 1659 | usb_register_notify(&usbdev_nb); |
1649 | 1660 | #endif | |
1650 | out: | 1661 | out: |
1651 | return retval; | 1662 | return retval; |
1652 | 1663 | ||
1653 | error_class: | ||
1654 | usb_device_class = NULL; | ||
1655 | cdev_del(&usb_device_cdev); | ||
1656 | |||
1657 | error_cdev: | 1664 | error_cdev: |
1658 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); | 1665 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); |
1659 | goto out; | 1666 | goto out; |
1660 | } | 1667 | } |
1661 | 1668 | ||
1662 | void usbdev_cleanup(void) | 1669 | void usb_devio_cleanup(void) |
1663 | { | 1670 | { |
1671 | #ifdef CONFIG_USB_DEVICE_CLASS | ||
1664 | usb_unregister_notify(&usbdev_nb); | 1672 | usb_unregister_notify(&usbdev_nb); |
1665 | class_destroy(usb_device_class); | 1673 | class_destroy(usb_classdev_class); |
1674 | #endif | ||
1666 | cdev_del(&usb_device_cdev); | 1675 | cdev_del(&usb_device_cdev); |
1667 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); | 1676 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); |
1668 | } | 1677 | } |
1669 | |||
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9b6a60fafddb..593386eb974d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -574,23 +574,10 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) | |||
574 | } | 574 | } |
575 | 575 | ||
576 | #ifdef CONFIG_HOTPLUG | 576 | #ifdef CONFIG_HOTPLUG |
577 | |||
578 | /* | ||
579 | * This sends an uevent to userspace, typically helping to load driver | ||
580 | * or other modules, configure the device, and more. Drivers can provide | ||
581 | * a MODULE_DEVICE_TABLE to help with module loading subtasks. | ||
582 | * | ||
583 | * We're called either from khubd (the typical case) or from root hub | ||
584 | * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle | ||
585 | * delays in event delivery. Use sysfs (and DEVPATH) to make sure the | ||
586 | * device (and this configuration!) are still present. | ||
587 | */ | ||
588 | static int usb_uevent(struct device *dev, char **envp, int num_envp, | 577 | static int usb_uevent(struct device *dev, char **envp, int num_envp, |
589 | char *buffer, int buffer_size) | 578 | char *buffer, int buffer_size) |
590 | { | 579 | { |
591 | struct usb_interface *intf; | ||
592 | struct usb_device *usb_dev; | 580 | struct usb_device *usb_dev; |
593 | struct usb_host_interface *alt; | ||
594 | int i = 0; | 581 | int i = 0; |
595 | int length = 0; | 582 | int length = 0; |
596 | 583 | ||
@@ -600,13 +587,11 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, | |||
600 | /* driver is often null here; dev_dbg() would oops */ | 587 | /* driver is often null here; dev_dbg() would oops */ |
601 | pr_debug ("usb %s: uevent\n", dev->bus_id); | 588 | pr_debug ("usb %s: uevent\n", dev->bus_id); |
602 | 589 | ||
603 | if (is_usb_device(dev)) { | 590 | if (is_usb_device(dev)) |
604 | usb_dev = to_usb_device(dev); | 591 | usb_dev = to_usb_device(dev); |
605 | alt = NULL; | 592 | else { |
606 | } else { | 593 | struct usb_interface *intf = to_usb_interface(dev); |
607 | intf = to_usb_interface(dev); | ||
608 | usb_dev = interface_to_usbdev(intf); | 594 | usb_dev = interface_to_usbdev(intf); |
609 | alt = intf->cur_altsetting; | ||
610 | } | 595 | } |
611 | 596 | ||
612 | if (usb_dev->devnum < 0) { | 597 | if (usb_dev->devnum < 0) { |
@@ -621,9 +606,7 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, | |||
621 | #ifdef CONFIG_USB_DEVICEFS | 606 | #ifdef CONFIG_USB_DEVICEFS |
622 | /* If this is available, userspace programs can directly read | 607 | /* If this is available, userspace programs can directly read |
623 | * all the device descriptors we don't tell them about. Or | 608 | * all the device descriptors we don't tell them about. Or |
624 | * even act as usermode drivers. | 609 | * act as usermode drivers. |
625 | * | ||
626 | * FIXME reduce hardwired intelligence here | ||
627 | */ | 610 | */ |
628 | if (add_uevent_var(envp, num_envp, &i, | 611 | if (add_uevent_var(envp, num_envp, &i, |
629 | buffer, buffer_size, &length, | 612 | buffer, buffer_size, &length, |
@@ -650,44 +633,29 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, | |||
650 | usb_dev->descriptor.bDeviceProtocol)) | 633 | usb_dev->descriptor.bDeviceProtocol)) |
651 | return -ENOMEM; | 634 | return -ENOMEM; |
652 | 635 | ||
653 | if (!is_usb_device(dev)) { | 636 | if (add_uevent_var(envp, num_envp, &i, |
654 | |||
655 | if (add_uevent_var(envp, num_envp, &i, | ||
656 | buffer, buffer_size, &length, | 637 | buffer, buffer_size, &length, |
657 | "INTERFACE=%d/%d/%d", | 638 | "BUSNUM=%03d", |
658 | alt->desc.bInterfaceClass, | 639 | usb_dev->bus->busnum)) |
659 | alt->desc.bInterfaceSubClass, | 640 | return -ENOMEM; |
660 | alt->desc.bInterfaceProtocol)) | ||
661 | return -ENOMEM; | ||
662 | 641 | ||
663 | if (add_uevent_var(envp, num_envp, &i, | 642 | if (add_uevent_var(envp, num_envp, &i, |
664 | buffer, buffer_size, &length, | 643 | buffer, buffer_size, &length, |
665 | "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", | 644 | "DEVNUM=%03d", |
666 | le16_to_cpu(usb_dev->descriptor.idVendor), | 645 | usb_dev->devnum)) |
667 | le16_to_cpu(usb_dev->descriptor.idProduct), | 646 | return -ENOMEM; |
668 | le16_to_cpu(usb_dev->descriptor.bcdDevice), | ||
669 | usb_dev->descriptor.bDeviceClass, | ||
670 | usb_dev->descriptor.bDeviceSubClass, | ||
671 | usb_dev->descriptor.bDeviceProtocol, | ||
672 | alt->desc.bInterfaceClass, | ||
673 | alt->desc.bInterfaceSubClass, | ||
674 | alt->desc.bInterfaceProtocol)) | ||
675 | return -ENOMEM; | ||
676 | } | ||
677 | 647 | ||
678 | envp[i] = NULL; | 648 | envp[i] = NULL; |
679 | |||
680 | return 0; | 649 | return 0; |
681 | } | 650 | } |
682 | 651 | ||
683 | #else | 652 | #else |
684 | 653 | ||
685 | static int usb_uevent(struct device *dev, char **envp, | 654 | static int usb_uevent(struct device *dev, char **envp, |
686 | int num_envp, char *buffer, int buffer_size) | 655 | int num_envp, char *buffer, int buffer_size) |
687 | { | 656 | { |
688 | return -ENODEV; | 657 | return -ENODEV; |
689 | } | 658 | } |
690 | |||
691 | #endif /* CONFIG_HOTPLUG */ | 659 | #endif /* CONFIG_HOTPLUG */ |
692 | 660 | ||
693 | /** | 661 | /** |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 19abe81babd5..2a0b15e42bc7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1367,11 +1367,15 @@ int usb_new_device(struct usb_device *udev) | |||
1367 | } | 1367 | } |
1368 | #endif | 1368 | #endif |
1369 | 1369 | ||
1370 | /* export the usbdev device-node for libusb */ | ||
1371 | udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, | ||
1372 | (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); | ||
1373 | |||
1370 | /* Register the device. The device driver is responsible | 1374 | /* Register the device. The device driver is responsible |
1371 | * for adding the device files to usbfs and sysfs and for | 1375 | * for adding the device files to sysfs and for configuring |
1372 | * configuring the device. | 1376 | * the device. |
1373 | */ | 1377 | */ |
1374 | err = device_add (&udev->dev); | 1378 | err = device_add(&udev->dev); |
1375 | if (err) { | 1379 | if (err) { |
1376 | dev_err(&udev->dev, "can't device_add, error %d\n", err); | 1380 | dev_err(&udev->dev, "can't device_add, error %d\n", err); |
1377 | goto fail; | 1381 | goto fail; |
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 11dad22da41c..cddfc62c4611 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
@@ -662,7 +662,7 @@ static void usbfs_add_device(struct usb_device *dev) | |||
662 | sprintf (name, "%03d", dev->devnum); | 662 | sprintf (name, "%03d", dev->devnum); |
663 | dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, | 663 | dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, |
664 | dev->bus->usbfs_dentry, dev, | 664 | dev->bus->usbfs_dentry, dev, |
665 | &usbfs_device_file_operations, | 665 | &usbdev_file_operations, |
666 | devuid, devgid); | 666 | devuid, devgid); |
667 | if (dev->usbfs_dentry == NULL) { | 667 | if (dev->usbfs_dentry == NULL) { |
668 | err ("error creating usbfs device entry"); | 668 | err ("error creating usbfs device entry"); |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c359ccb32998..da4ee07e0094 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1305,7 +1305,7 @@ int usb_reset_configuration(struct usb_device *dev) | |||
1305 | return 0; | 1305 | return 0; |
1306 | } | 1306 | } |
1307 | 1307 | ||
1308 | static void release_interface(struct device *dev) | 1308 | void usb_release_interface(struct device *dev) |
1309 | { | 1309 | { |
1310 | struct usb_interface *intf = to_usb_interface(dev); | 1310 | struct usb_interface *intf = to_usb_interface(dev); |
1311 | struct usb_interface_cache *intfc = | 1311 | struct usb_interface_cache *intfc = |
@@ -1315,6 +1315,67 @@ static void release_interface(struct device *dev) | |||
1315 | kfree(intf); | 1315 | kfree(intf); |
1316 | } | 1316 | } |
1317 | 1317 | ||
1318 | #ifdef CONFIG_HOTPLUG | ||
1319 | static int usb_if_uevent(struct device *dev, char **envp, int num_envp, | ||
1320 | char *buffer, int buffer_size) | ||
1321 | { | ||
1322 | struct usb_device *usb_dev; | ||
1323 | struct usb_interface *intf; | ||
1324 | struct usb_host_interface *alt; | ||
1325 | int i = 0; | ||
1326 | int length = 0; | ||
1327 | |||
1328 | if (!dev) | ||
1329 | return -ENODEV; | ||
1330 | |||
1331 | /* driver is often null here; dev_dbg() would oops */ | ||
1332 | pr_debug ("usb %s: uevent\n", dev->bus_id); | ||
1333 | |||
1334 | intf = to_usb_interface(dev); | ||
1335 | usb_dev = interface_to_usbdev(intf); | ||
1336 | alt = intf->cur_altsetting; | ||
1337 | |||
1338 | if (add_uevent_var(envp, num_envp, &i, | ||
1339 | buffer, buffer_size, &length, | ||
1340 | "INTERFACE=%d/%d/%d", | ||
1341 | alt->desc.bInterfaceClass, | ||
1342 | alt->desc.bInterfaceSubClass, | ||
1343 | alt->desc.bInterfaceProtocol)) | ||
1344 | return -ENOMEM; | ||
1345 | |||
1346 | if (add_uevent_var(envp, num_envp, &i, | ||
1347 | buffer, buffer_size, &length, | ||
1348 | "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", | ||
1349 | le16_to_cpu(usb_dev->descriptor.idVendor), | ||
1350 | le16_to_cpu(usb_dev->descriptor.idProduct), | ||
1351 | le16_to_cpu(usb_dev->descriptor.bcdDevice), | ||
1352 | usb_dev->descriptor.bDeviceClass, | ||
1353 | usb_dev->descriptor.bDeviceSubClass, | ||
1354 | usb_dev->descriptor.bDeviceProtocol, | ||
1355 | alt->desc.bInterfaceClass, | ||
1356 | alt->desc.bInterfaceSubClass, | ||
1357 | alt->desc.bInterfaceProtocol)) | ||
1358 | return -ENOMEM; | ||
1359 | |||
1360 | envp[i] = NULL; | ||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | #else | ||
1365 | |||
1366 | static int usb_if_uevent(struct device *dev, char **envp, | ||
1367 | int num_envp, char *buffer, int buffer_size) | ||
1368 | { | ||
1369 | return -ENODEV; | ||
1370 | } | ||
1371 | #endif /* CONFIG_HOTPLUG */ | ||
1372 | |||
1373 | struct device_type usb_if_device_type = { | ||
1374 | .name = "usb_interface", | ||
1375 | .release = usb_release_interface, | ||
1376 | .uevent = usb_if_uevent, | ||
1377 | }; | ||
1378 | |||
1318 | /* | 1379 | /* |
1319 | * usb_set_configuration - Makes a particular device setting be current | 1380 | * usb_set_configuration - Makes a particular device setting be current |
1320 | * @dev: the device whose configuration is being updated | 1381 | * @dev: the device whose configuration is being updated |
@@ -1478,8 +1539,8 @@ free_interfaces: | |||
1478 | intf->dev.parent = &dev->dev; | 1539 | intf->dev.parent = &dev->dev; |
1479 | intf->dev.driver = NULL; | 1540 | intf->dev.driver = NULL; |
1480 | intf->dev.bus = &usb_bus_type; | 1541 | intf->dev.bus = &usb_bus_type; |
1542 | intf->dev.type = &usb_if_device_type; | ||
1481 | intf->dev.dma_mask = dev->dev.dma_mask; | 1543 | intf->dev.dma_mask = dev->dev.dma_mask; |
1482 | intf->dev.release = release_interface; | ||
1483 | device_initialize (&intf->dev); | 1544 | device_initialize (&intf->dev); |
1484 | mark_quiesced(intf); | 1545 | mark_quiesced(intf); |
1485 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", | 1546 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", |
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 6f35dce8a95d..dfd1b5c87ca3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
@@ -197,6 +197,11 @@ static void usb_release_dev(struct device *dev) | |||
197 | kfree(udev); | 197 | kfree(udev); |
198 | } | 198 | } |
199 | 199 | ||
200 | struct device_type usb_device_type = { | ||
201 | .name = "usb_device", | ||
202 | .release = usb_release_dev, | ||
203 | }; | ||
204 | |||
200 | #ifdef CONFIG_PM | 205 | #ifdef CONFIG_PM |
201 | 206 | ||
202 | static int ksuspend_usb_init(void) | 207 | static int ksuspend_usb_init(void) |
@@ -247,13 +252,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) | |||
247 | 252 | ||
248 | device_initialize(&dev->dev); | 253 | device_initialize(&dev->dev); |
249 | dev->dev.bus = &usb_bus_type; | 254 | dev->dev.bus = &usb_bus_type; |
255 | dev->dev.type = &usb_device_type; | ||
250 | dev->dev.dma_mask = bus->controller->dma_mask; | 256 | dev->dev.dma_mask = bus->controller->dma_mask; |
251 | dev->dev.release = usb_release_dev; | ||
252 | dev->state = USB_STATE_ATTACHED; | 257 | dev->state = USB_STATE_ATTACHED; |
253 | 258 | ||
254 | /* This magic assignment distinguishes devices from interfaces */ | ||
255 | dev->dev.platform_data = &usb_generic_driver; | ||
256 | |||
257 | INIT_LIST_HEAD(&dev->ep0.urb_list); | 259 | INIT_LIST_HEAD(&dev->ep0.urb_list); |
258 | dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; | 260 | dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; |
259 | dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; | 261 | dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; |
@@ -882,9 +884,9 @@ static int __init usb_init(void) | |||
882 | retval = usb_register(&usbfs_driver); | 884 | retval = usb_register(&usbfs_driver); |
883 | if (retval) | 885 | if (retval) |
884 | goto driver_register_failed; | 886 | goto driver_register_failed; |
885 | retval = usbdev_init(); | 887 | retval = usb_devio_init(); |
886 | if (retval) | 888 | if (retval) |
887 | goto usbdevice_init_failed; | 889 | goto usb_devio_init_failed; |
888 | retval = usbfs_init(); | 890 | retval = usbfs_init(); |
889 | if (retval) | 891 | if (retval) |
890 | goto fs_init_failed; | 892 | goto fs_init_failed; |
@@ -899,8 +901,8 @@ static int __init usb_init(void) | |||
899 | hub_init_failed: | 901 | hub_init_failed: |
900 | usbfs_cleanup(); | 902 | usbfs_cleanup(); |
901 | fs_init_failed: | 903 | fs_init_failed: |
902 | usbdev_cleanup(); | 904 | usb_devio_cleanup(); |
903 | usbdevice_init_failed: | 905 | usb_devio_init_failed: |
904 | usb_deregister(&usbfs_driver); | 906 | usb_deregister(&usbfs_driver); |
905 | driver_register_failed: | 907 | driver_register_failed: |
906 | usb_major_cleanup(); | 908 | usb_major_cleanup(); |
@@ -927,7 +929,7 @@ static void __exit usb_exit(void) | |||
927 | usb_major_cleanup(); | 929 | usb_major_cleanup(); |
928 | usbfs_cleanup(); | 930 | usbfs_cleanup(); |
929 | usb_deregister(&usbfs_driver); | 931 | usb_deregister(&usbfs_driver); |
930 | usbdev_cleanup(); | 932 | usb_devio_cleanup(); |
931 | usb_hub_cleanup(); | 933 | usb_hub_cleanup(); |
932 | usb_host_cleanup(); | 934 | usb_host_cleanup(); |
933 | bus_unregister(&usb_bus_type); | 935 | bus_unregister(&usb_bus_type); |
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index c94379e55f2d..bf2eb0dae2ec 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
@@ -78,15 +78,13 @@ static inline int usb_autoresume_device(struct usb_device *udev) | |||
78 | 78 | ||
79 | extern struct workqueue_struct *ksuspend_usb_wq; | 79 | extern struct workqueue_struct *ksuspend_usb_wq; |
80 | extern struct bus_type usb_bus_type; | 80 | extern struct bus_type usb_bus_type; |
81 | extern struct device_type usb_device_type; | ||
82 | extern struct device_type usb_if_device_type; | ||
81 | extern struct usb_device_driver usb_generic_driver; | 83 | extern struct usb_device_driver usb_generic_driver; |
82 | 84 | ||
83 | /* Here's how we tell apart devices and interfaces. Luckily there's | ||
84 | * no such thing as a platform USB device, so we can steal the use | ||
85 | * of the platform_data field. */ | ||
86 | |||
87 | static inline int is_usb_device(const struct device *dev) | 85 | static inline int is_usb_device(const struct device *dev) |
88 | { | 86 | { |
89 | return dev->platform_data == &usb_generic_driver; | 87 | return dev->type == &usb_device_type; |
90 | } | 88 | } |
91 | 89 | ||
92 | /* Do the same for device drivers and interface drivers. */ | 90 | /* Do the same for device drivers and interface drivers. */ |
@@ -122,11 +120,11 @@ extern const char *usbcore_name; | |||
122 | extern struct mutex usbfs_mutex; | 120 | extern struct mutex usbfs_mutex; |
123 | extern struct usb_driver usbfs_driver; | 121 | extern struct usb_driver usbfs_driver; |
124 | extern const struct file_operations usbfs_devices_fops; | 122 | extern const struct file_operations usbfs_devices_fops; |
125 | extern const struct file_operations usbfs_device_file_operations; | 123 | extern const struct file_operations usbdev_file_operations; |
126 | extern void usbfs_conn_disc_event(void); | 124 | extern void usbfs_conn_disc_event(void); |
127 | 125 | ||
128 | extern int usbdev_init(void); | 126 | extern int usb_devio_init(void); |
129 | extern void usbdev_cleanup(void); | 127 | extern void usb_devio_cleanup(void); |
130 | 128 | ||
131 | struct dev_state { | 129 | struct dev_state { |
132 | struct list_head list; /* state list */ | 130 | struct list_head list; /* state list */ |