ACPI / glue: Add .match() callback to struct acpi_bus_type
USB uses the .find_bridge() callback from struct acpi_bus_type incorrectly, because as a result of the way it is used by USB every device in the system that doesn't have a bus type or parent is passed to usb_acpi_find_device() for inspection. What USB actually needs, though, is to call usb_acpi_find_device() for USB ports that don't have a bus type defined, but have usb_port_device_type as their device type, as well as for USB devices. To fix that replace the struct bus_type pointer in struct acpi_bus_type used for matching devices to specific subsystems with a .match() callback to be used for this purpose and update the users of struct acpi_bus_type, including USB, accordingly. Define the .match() callback routine for USB, usb_acpi_bus_match(), in such a way that it will cover both USB devices and USB ports and remove the now redundant .find_bridge() callback pointer from usb_acpi_bus. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Yinghai Lu <yinghai@kernel.org> Acked-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
9b27516fcd
commit
53540098b2
7 changed files with 43 additions and 32 deletions
|
@ -36,12 +36,11 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
|
||||||
{
|
{
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (type && type->bus && type->find_device) {
|
if (type && type->match && type->find_device) {
|
||||||
down_write(&bus_type_sem);
|
down_write(&bus_type_sem);
|
||||||
list_add_tail(&type->list, &bus_type_list);
|
list_add_tail(&type->list, &bus_type_list);
|
||||||
up_write(&bus_type_sem);
|
up_write(&bus_type_sem);
|
||||||
printk(KERN_INFO PREFIX "bus type %s registered\n",
|
printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
|
||||||
type->bus->name);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -56,24 +55,21 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
|
||||||
down_write(&bus_type_sem);
|
down_write(&bus_type_sem);
|
||||||
list_del_init(&type->list);
|
list_del_init(&type->list);
|
||||||
up_write(&bus_type_sem);
|
up_write(&bus_type_sem);
|
||||||
printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n",
|
printk(KERN_INFO PREFIX "bus type %s unregistered\n",
|
||||||
type->bus->name);
|
type->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
|
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
|
||||||
|
|
||||||
static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
|
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
||||||
{
|
{
|
||||||
struct acpi_bus_type *tmp, *ret = NULL;
|
struct acpi_bus_type *tmp, *ret = NULL;
|
||||||
|
|
||||||
if (!type)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
down_read(&bus_type_sem);
|
down_read(&bus_type_sem);
|
||||||
list_for_each_entry(tmp, &bus_type_list, list) {
|
list_for_each_entry(tmp, &bus_type_list, list) {
|
||||||
if (tmp->bus == type) {
|
if (tmp->match(dev)) {
|
||||||
ret = tmp;
|
ret = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -261,26 +257,17 @@ static int acpi_unbind_one(struct device *dev)
|
||||||
|
|
||||||
static int acpi_platform_notify(struct device *dev)
|
static int acpi_platform_notify(struct device *dev)
|
||||||
{
|
{
|
||||||
struct acpi_bus_type *type;
|
struct acpi_bus_type *type = acpi_get_bus_type(dev);
|
||||||
acpi_handle handle;
|
acpi_handle handle;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = acpi_bind_one(dev, NULL);
|
ret = acpi_bind_one(dev, NULL);
|
||||||
if (ret && (!dev->bus || !dev->parent)) {
|
|
||||||
/* bridge devices genernally haven't bus or parent */
|
|
||||||
ret = acpi_find_bridge_device(dev, &handle);
|
|
||||||
if (!ret) {
|
|
||||||
ret = acpi_bind_one(dev, handle);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type = acpi_get_bus_type(dev->bus);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (!type || !type->find_device) {
|
if (!type) {
|
||||||
DBG("No ACPI bus support for %s\n", dev_name(dev));
|
ret = acpi_find_bridge_device(dev, &handle);
|
||||||
ret = -EINVAL;
|
if (!ret)
|
||||||
|
ret = acpi_bind_one(dev, handle);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +303,7 @@ static int acpi_platform_notify_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct acpi_bus_type *type;
|
struct acpi_bus_type *type;
|
||||||
|
|
||||||
type = acpi_get_bus_type(dev->bus);
|
type = acpi_get_bus_type(dev);
|
||||||
if (type && type->cleanup)
|
if (type && type->cleanup)
|
||||||
type->cleanup(dev);
|
type->cleanup(dev);
|
||||||
|
|
||||||
|
|
|
@ -1150,6 +1150,7 @@ static int ata_acpi_find_dummy(struct device *dev, acpi_handle *handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct acpi_bus_type ata_acpi_bus = {
|
static struct acpi_bus_type ata_acpi_bus = {
|
||||||
|
.name = "ATA",
|
||||||
.find_bridge = ata_acpi_find_dummy,
|
.find_bridge = ata_acpi_find_dummy,
|
||||||
.find_device = ata_acpi_find_device,
|
.find_device = ata_acpi_find_device,
|
||||||
};
|
};
|
||||||
|
|
|
@ -331,8 +331,14 @@ static void pci_acpi_cleanup(struct device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool pci_acpi_bus_match(struct device *dev)
|
||||||
|
{
|
||||||
|
return dev->bus == &pci_bus_type;
|
||||||
|
}
|
||||||
|
|
||||||
static struct acpi_bus_type acpi_pci_bus = {
|
static struct acpi_bus_type acpi_pci_bus = {
|
||||||
.bus = &pci_bus_type,
|
.name = "PCI",
|
||||||
|
.match = pci_acpi_bus_match,
|
||||||
.find_device = acpi_pci_find_device,
|
.find_device = acpi_pci_find_device,
|
||||||
.setup = pci_acpi_setup,
|
.setup = pci_acpi_setup,
|
||||||
.cleanup = pci_acpi_cleanup,
|
.cleanup = pci_acpi_cleanup,
|
||||||
|
|
|
@ -353,8 +353,14 @@ static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle)
|
||||||
/* complete initialization of a PNPACPI device includes having
|
/* complete initialization of a PNPACPI device includes having
|
||||||
* pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
|
* pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
|
||||||
*/
|
*/
|
||||||
|
static bool acpi_pnp_bus_match(struct device *dev)
|
||||||
|
{
|
||||||
|
return dev->bus == &pnp_bus_type;
|
||||||
|
}
|
||||||
|
|
||||||
static struct acpi_bus_type __initdata acpi_pnp_bus = {
|
static struct acpi_bus_type __initdata acpi_pnp_bus = {
|
||||||
.bus = &pnp_bus_type,
|
.name = "PNP",
|
||||||
|
.match = acpi_pnp_bus_match,
|
||||||
.find_device = acpi_pnp_find_device,
|
.find_device = acpi_pnp_find_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,14 @@ struct kmem_cache *scsi_sdb_cache;
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
#include <acpi/acpi_bus.h>
|
#include <acpi/acpi_bus.h>
|
||||||
|
|
||||||
|
static bool acpi_scsi_bus_match(struct device *dev)
|
||||||
|
{
|
||||||
|
return dev->bus == &scsi_bus_type;
|
||||||
|
}
|
||||||
|
|
||||||
int scsi_register_acpi_bus_type(struct acpi_bus_type *bus)
|
int scsi_register_acpi_bus_type(struct acpi_bus_type *bus)
|
||||||
{
|
{
|
||||||
bus->bus = &scsi_bus_type;
|
bus->match = acpi_scsi_bus_match;
|
||||||
return register_acpi_bus_type(bus);
|
return register_acpi_bus_type(bus);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(scsi_register_acpi_bus_type);
|
EXPORT_SYMBOL_GPL(scsi_register_acpi_bus_type);
|
||||||
|
|
|
@ -210,9 +210,14 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool usb_acpi_bus_match(struct device *dev)
|
||||||
|
{
|
||||||
|
return is_usb_device(dev) || is_usb_port(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static struct acpi_bus_type usb_acpi_bus = {
|
static struct acpi_bus_type usb_acpi_bus = {
|
||||||
.bus = &usb_bus_type,
|
.name = "USB",
|
||||||
.find_bridge = usb_acpi_find_device,
|
.match = usb_acpi_bus_match,
|
||||||
.find_device = usb_acpi_find_device,
|
.find_device = usb_acpi_find_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -437,7 +437,8 @@ void acpi_remove_dir(struct acpi_device *);
|
||||||
*/
|
*/
|
||||||
struct acpi_bus_type {
|
struct acpi_bus_type {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct bus_type *bus;
|
const char *name;
|
||||||
|
bool (*match)(struct device *dev);
|
||||||
/* For general devices under the bus */
|
/* For general devices under the bus */
|
||||||
int (*find_device) (struct device *, acpi_handle *);
|
int (*find_device) (struct device *, acpi_handle *);
|
||||||
/* For bridges, such as PCI root bridge, IDE controller */
|
/* For bridges, such as PCI root bridge, IDE controller */
|
||||||
|
|
Loading…
Reference in a new issue