Merge branches 'battery', 'bugzilla-14667', 'bugzilla-15096', 'bugzilla-15480', ...
[sfrench/cifs-2.6.git] / drivers / acpi / scan.c
index fb7fc24fe72725817ee38e970dc9b90f07998522..0338f513a010064b14b1bc8adb6a30fd0d44e4db 100644 (file)
@@ -4,10 +4,12 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/acpi.h>
 #include <linux/signal.h>
 #include <linux/kthread.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi_drivers.h>
 
@@ -1032,6 +1034,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;
@@ -1044,12 +1081,6 @@ static void acpi_device_set_id(struct acpi_device *device)
                if (ACPI_IS_ROOT_DEVICE(device)) {
                        acpi_add_id(device, ACPI_SYSTEM_HID);
                        break;
-               } else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
-                       /* \_SB_, the only root-level namespace device */
-                       acpi_add_id(device, ACPI_BUS_HID);
-                       strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
-                       strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
-                       break;
                }
 
                status = acpi_get_object_info(device->handle, &info);
@@ -1082,6 +1113,14 @@ 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);
+               else if (!acpi_device_hid(device) &&
+                        ACPI_IS_ROOT_DEVICE(device->parent)) {
+                       acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
+                       strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
+                       strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
+               }
 
                break;
        case ACPI_BUS_TYPE_POWER: