ACPI / SBS: Disable smart battery manager on Apple
[sfrench/cifs-2.6.git] / drivers / acpi / sbs.c
index b1df4eee8657b6d6f0b3c27331e0bfa6901350f0..32aeceae10e3e21ae476739853b37320ec1932b0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/power_supply.h>
+#include <linux/dmi.h>
 
 #include "sbshc.h"
 #include "battery.h"
@@ -61,6 +62,8 @@ static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
 
+static bool sbs_manager_broken;
+
 #define MAX_SBS_BAT                    4
 #define ACPI_SBS_BLOCK_MAX             32
 
@@ -494,16 +497,21 @@ static int acpi_battery_read(struct acpi_battery *battery)
                                  ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
        } else if (battery->id == 0)
                battery->present = 1;
+
        if (result || !battery->present)
                return result;
 
        if (saved_present != battery->present) {
                battery->update_time = 0;
                result = acpi_battery_get_info(battery);
-               if (result)
+               if (result) {
+                       battery->present = 0;
                        return result;
+               }
        }
        result = acpi_battery_get_state(battery);
+       if (result)
+               battery->present = 0;
        return result;
 }
 
@@ -535,6 +543,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
        result = power_supply_register(&sbs->device->dev, &battery->bat);
        if (result)
                goto end;
+
        result = device_create_file(battery->bat.dev, &alarm_attr);
        if (result)
                goto end;
@@ -613,12 +622,31 @@ static void acpi_sbs_callback(void *context)
        }
 }
 
+static int disable_sbs_manager(const struct dmi_system_id *d)
+{
+       sbs_manager_broken = true;
+       return 0;
+}
+
+static struct dmi_system_id acpi_sbs_dmi_table[] = {
+       {
+               .callback = disable_sbs_manager,
+               .ident = "Apple",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.")
+               },
+       },
+       { },
+};
+
 static int acpi_sbs_add(struct acpi_device *device)
 {
        struct acpi_sbs *sbs;
        int result = 0;
        int id;
 
+       dmi_check_system(acpi_sbs_dmi_table);
+
        sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
        if (!sbs) {
                result = -ENOMEM;
@@ -637,14 +665,21 @@ static int acpi_sbs_add(struct acpi_device *device)
        if (result && result != -ENODEV)
                goto end;
 
-       result = acpi_manager_get_info(sbs);
-       if (!result) {
-               sbs->manager_present = 1;
-               for (id = 0; id < MAX_SBS_BAT; ++id)
-                       if ((sbs->batteries_supported & (1 << id)))
-                               acpi_battery_add(sbs, id);
-       } else
+       result = 0;
+
+       if (!sbs_manager_broken) {
+               result = acpi_manager_get_info(sbs);
+               if (!result) {
+                       sbs->manager_present = 0;
+                       for (id = 0; id < MAX_SBS_BAT; ++id)
+                               if ((sbs->batteries_supported & (1 << id)))
+                                       acpi_battery_add(sbs, id);
+               }
+       }
+
+       if (!sbs->manager_present)
                acpi_battery_add(sbs, 0);
+
        acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
       end:
        if (result)