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 | |
| 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>
| -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 | ||||
| -rw-r--r-- | include/linux/usb.h | 10 |
9 files changed, 183 insertions, 115 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 */ |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 5e8e144afbae..f9e4445d5b53 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -299,8 +299,9 @@ struct usb_bus { | |||
| 299 | int bandwidth_int_reqs; /* number of Interrupt requests */ | 299 | int bandwidth_int_reqs; /* number of Interrupt requests */ |
| 300 | int bandwidth_isoc_reqs; /* number of Isoc. requests */ | 300 | int bandwidth_isoc_reqs; /* number of Isoc. requests */ |
| 301 | 301 | ||
| 302 | #ifdef CONFIG_USB_DEVICEFS | ||
| 302 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ | 303 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ |
| 303 | 304 | #endif | |
| 304 | struct class_device *class_dev; /* class device for this bus */ | 305 | struct class_device *class_dev; /* class device for this bus */ |
| 305 | 306 | ||
| 306 | #if defined(CONFIG_USB_MON) | 307 | #if defined(CONFIG_USB_MON) |
| @@ -373,9 +374,12 @@ struct usb_device { | |||
| 373 | char *serial; /* iSerialNumber string, if present */ | 374 | char *serial; /* iSerialNumber string, if present */ |
| 374 | 375 | ||
| 375 | struct list_head filelist; | 376 | struct list_head filelist; |
| 376 | struct device *usbfs_dev; | 377 | #ifdef CONFIG_USB_DEVICE_CLASS |
| 378 | struct device *usb_classdev; | ||
| 379 | #endif | ||
| 380 | #ifdef CONFIG_USB_DEVICEFS | ||
| 377 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ | 381 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ |
| 378 | 382 | #endif | |
| 379 | /* | 383 | /* |
| 380 | * Child devices - these can be either new devices | 384 | * Child devices - these can be either new devices |
| 381 | * (if this is a hub device), or different instances | 385 | * (if this is a hub device), or different instances |
