diff options
| author | David Brownell <david-b@pacbell.net> | 2008-02-23 00:54:24 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2008-02-23 01:32:56 -0500 |
| commit | 1071695f17daf050638e0bc550db647f8237c3bb (patch) | |
| tree | 4770e712c2293d0156fbb53bebc6fa059a8a99eb | |
| parent | 39273b58a409cd6d65c9732bdca00bacd1626672 (diff) | |
ACPI: crosslink ACPI and "real" device nodes
Add cross-links between ACPI device and "real" devices in sysfs,
exposing otherwise-hidden interrelationships between the various
device nodes for ACPI stuff. As a representative example, one
hardware device is exposed as two logical devices (PNP and ACPI):
.../pnp0/00:06/
.../LNXSYSTM:00/device:00/PNP0A03:00/device:15/PNP0B00:00/
The PNP device gets a "firmware_node" link pointing to the ACPI device,
and is what a Linux device driver binds to. The ACPI device has instead
a "physical_node" link pointing back to the PNP device. Other firmware
frameworks, like OpenFirmware, could do the same thing to couple their
firmware tables to the rest of the system.
(Based on a patch from Zhang Rui. This version is modified to not
depend on the patch makig ACPI initialize driver model wakeup flags.)
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/glue.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index eda0978b57c6..06f8634fe58b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
| @@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device); | |||
| 142 | 142 | ||
| 143 | static int acpi_bind_one(struct device *dev, acpi_handle handle) | 143 | static int acpi_bind_one(struct device *dev, acpi_handle handle) |
| 144 | { | 144 | { |
| 145 | struct acpi_device *acpi_dev; | ||
| 145 | acpi_status status; | 146 | acpi_status status; |
| 146 | 147 | ||
| 147 | if (dev->archdata.acpi_handle) { | 148 | if (dev->archdata.acpi_handle) { |
| @@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) | |||
| 157 | } | 158 | } |
| 158 | dev->archdata.acpi_handle = handle; | 159 | dev->archdata.acpi_handle = handle; |
| 159 | 160 | ||
| 161 | status = acpi_bus_get_device(handle, &acpi_dev); | ||
| 162 | if (!ACPI_FAILURE(status)) { | ||
| 163 | int ret; | ||
| 164 | |||
| 165 | ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, | ||
| 166 | "firmware_node"); | ||
| 167 | ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, | ||
| 168 | "physical_node"); | ||
| 169 | } | ||
| 170 | |||
| 160 | return 0; | 171 | return 0; |
| 161 | } | 172 | } |
| 162 | 173 | ||
| @@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev) | |||
| 165 | if (!dev->archdata.acpi_handle) | 176 | if (!dev->archdata.acpi_handle) |
| 166 | return 0; | 177 | return 0; |
| 167 | if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { | 178 | if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) { |
| 179 | struct acpi_device *acpi_dev; | ||
| 180 | |||
| 168 | /* acpi_get_physical_device increase refcnt by one */ | 181 | /* acpi_get_physical_device increase refcnt by one */ |
| 169 | put_device(dev); | 182 | put_device(dev); |
| 183 | |||
| 184 | if (!acpi_bus_get_device(dev->archdata.acpi_handle, | ||
| 185 | &acpi_dev)) { | ||
| 186 | sysfs_remove_link(&dev->kobj, "firmware_node"); | ||
| 187 | sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node"); | ||
| 188 | } | ||
| 189 | |||
| 170 | acpi_detach_data(dev->archdata.acpi_handle, | 190 | acpi_detach_data(dev->archdata.acpi_handle, |
| 171 | acpi_glue_data_handler); | 191 | acpi_glue_data_handler); |
| 172 | dev->archdata.acpi_handle = NULL; | 192 | dev->archdata.acpi_handle = NULL; |
