diff options
author | Matthew Garrett <mjg@redhat.com> | 2012-05-11 12:08:27 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-12 04:06:13 +0400 |
commit | da0af6e78ef311d97754aa03e10eade82cc99e16 (patch) | |
tree | 52d904e831d619452299844c7f55b61be2d62a53 | |
parent | 38ac0f1b90dc9486cc039f1a4d8b0202813e5b67 (diff) | |
download | linux-da0af6e78ef311d97754aa03e10eade82cc99e16.tar.xz |
usb: Bind devices to ACPI devices when possible
Built-in USB devices will typically have a representation in the system
ACPI tables. Add support for binding the two together so the USB code can
make use of the associated methods.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/core/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/core/usb-acpi.c | 60 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 7 |
4 files changed, 74 insertions, 0 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index c4ea846d3c02..26059b93dbf4 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -9,5 +9,6 @@ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o usbcore-$(CONFIG_PCI) += hcd-pci.o +usbcore-$(CONFIG_ACPI) += usb-acpi.o obj-$(CONFIG_USB) += usbcore.o diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c new file mode 100644 index 000000000000..cab5cb7c256c --- /dev/null +++ b/drivers/usb/core/usb-acpi.c @@ -0,0 +1,60 @@ +/* + * USB-ACPI glue code + * + * Copyright 2012 Red Hat <mjg@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + */ +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/pci.h> +#include <acpi/acpi_bus.h> + +#include "usb.h" + +static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) +{ + struct usb_device *udev; + struct device *parent; + acpi_handle *parent_handle; + + if (!is_usb_device(dev)) + return -ENODEV; + + udev = to_usb_device(dev); + parent = dev->parent; + parent_handle = DEVICE_ACPI_HANDLE(parent); + + if (!parent_handle) + return -ENODEV; + + *handle = acpi_get_child(parent_handle, udev->portnum); + + if (!*handle) + return -ENODEV; + + return 0; +} + +static struct acpi_bus_type usb_acpi_bus = { + .bus = &usb_bus_type, + .find_bridge = NULL, + .find_device = usb_acpi_find_device, +}; + +int usb_acpi_register(void) +{ + return register_acpi_bus_type(&usb_acpi_bus); +} + +void usb_acpi_unregister(void) +{ + unregister_acpi_bus_type(&usb_acpi_bus); +} diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0ce862bfdd77..7998a67503c1 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1015,6 +1015,9 @@ static int __init usb_init(void) if (retval) goto out; + retval = usb_acpi_register(); + if (retval) + goto acpi_register_failed; retval = bus_register(&usb_bus_type); if (retval) goto bus_register_failed; @@ -1049,6 +1052,8 @@ major_init_failed: bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: + usb_acpi_unregister(); +acpi_register_failed: usb_debugfs_cleanup(); out: return retval; @@ -1070,6 +1075,7 @@ static void __exit usb_exit(void) usb_hub_cleanup(); bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); + usb_acpi_unregister(); usb_debugfs_cleanup(); } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 71648dcbe438..5c5c538ea73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); +#ifdef CONFIG_ACPI +extern int usb_acpi_register(void); +extern void usb_acpi_unregister(void); +#else +static inline int usb_acpi_register(void) { return 0; }; +static inline void usb_acpi_unregister(void) { }; +#endif |