summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2010-03-24 14:38:37 +0100
committerJean Delvare <khali@linux-fr.org>2010-03-24 14:38:37 +0100
commit222e82ac9ffbd3b80ab1b0b1d2c8c60ddb47d69d (patch)
tree92b2f540b812a4ef69a6a6202ab784fd0238d23d /drivers/acpi
parentFix up prototype for sys_ipc breakage (diff)
downloadlinux-222e82ac9ffbd3b80ab1b0b1d2c8c60ddb47d69d.tar.xz
linux-222e82ac9ffbd3b80ab1b0b1d2c8c60ddb47d69d.zip
acpi: Support IBM SMBus CMI devices
On some old IBM workstations and desktop computers, the BIOS presents in the DSDT an SMBus object that is missing the HID identifier that the i2c-scmi driver looks for. Modify the ACPI device scan code to insert the missing HID if it finds an IBM system with such an object. Affected machines: IntelliStation Z20/Z30. Note that the i2c-i801 driver no longer works on these machines because of ACPI resource conflicts. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/scan.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fb7fc24fe727..189cbc2585fa 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/signal.h>
#include <linux/kthread.h>
+#include <linux/dmi.h>
#include <acpi/acpi_drivers.h>
@@ -1032,6 +1033,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
list_add_tail(&id->list, &device->pnp.ids);
}
+/*
+ * Old IBM workstations have a DSDT bug wherein the SMBus object
+ * lacks the SMBUS01 HID and the methods do not have the necessary "_"
+ * prefix. Work around this.
+ */
+static int acpi_ibm_smbus_match(struct acpi_device *device)
+{
+ acpi_handle h_dummy;
+ struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+ int result;
+
+ if (!dmi_name_in_vendors("IBM"))
+ return -ENODEV;
+
+ /* Look for SMBS object */
+ result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
+ if (result)
+ return result;
+
+ if (strcmp("SMBS", path.pointer)) {
+ result = -ENODEV;
+ goto out;
+ }
+
+ /* Does it have the necessary (but misnamed) methods? */
+ result = -ENODEV;
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
+ result = 0;
+out:
+ kfree(path.pointer);
+ return result;
+}
+
static void acpi_device_set_id(struct acpi_device *device)
{
acpi_status status;
@@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device)
acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device)))
acpi_add_id(device, ACPI_DOCK_HID);
+ else if (!acpi_ibm_smbus_match(device))
+ acpi_add_id(device, ACPI_SMBUS_IBM_HID);
break;
case ACPI_BUS_TYPE_POWER: