Merge branch 'acpica' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[safe/jmp/linux-2.6] / drivers / acpi / battery.c
index f8c3d1b..58d2c91 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/types.h>
 #include <linux/jiffies.h>
 #include <linux/async.h>
+#include <linux/dmi.h>
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 #include <linux/proc_fs.h>
@@ -87,6 +88,10 @@ static const struct acpi_device_id battery_device_ids[] = {
 
 MODULE_DEVICE_TABLE(acpi, battery_device_ids);
 
+/* For buggy DSDTs that report negative 16-bit values for either charging
+ * or discharging current and/or report 0 as 65536 due to bad math.
+ */
+#define QUIRK_SIGNED16_CURRENT 0x0001
 
 struct acpi_battery {
        struct mutex lock;
@@ -114,6 +119,7 @@ struct acpi_battery {
        int state;
        int power_unit;
        u8 alarm_present;
+       long quirks;
 };
 
 #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
@@ -318,8 +324,8 @@ static int extract_package(struct acpi_battery *battery,
                                strncpy(ptr, element->string.pointer, 32);
                        else if (element->type == ACPI_TYPE_INTEGER) {
                                strncpy(ptr, (u8 *)&element->integer.value,
-                                       sizeof(acpi_integer));
-                               ptr[sizeof(acpi_integer)] = 0;
+                                       sizeof(u64));
+                               ptr[sizeof(u64)] = 0;
                        } else
                                *ptr = 0; /* don't have value */
                } else {
@@ -392,6 +398,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
                                 state_offsets, ARRAY_SIZE(state_offsets));
        battery->update_time = jiffies;
        kfree(buffer.pointer);
+
+       if ((battery->quirks & QUIRK_SIGNED16_CURRENT) &&
+           battery->rate_now != -1)
+               battery->rate_now = abs((s16)battery->rate_now);
+
        return result;
 }
 
@@ -497,6 +508,14 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
 }
 #endif
 
+static void acpi_battery_quirks(struct acpi_battery *battery)
+{
+       battery->quirks = 0;
+       if (dmi_name_in_vendors("Acer") && battery->power_unit) {
+               battery->quirks |= QUIRK_SIGNED16_CURRENT;
+       }
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
        int result, old_present = acpi_battery_present(battery);
@@ -515,6 +534,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
                result = acpi_battery_get_info(battery);
                if (result)
                        return result;
+               acpi_battery_quirks(battery);
                acpi_battery_init_alarm(battery);
        }
 #ifdef CONFIG_ACPI_SYSFS_POWER
@@ -811,7 +831,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
 #ifdef CONFIG_ACPI_SYSFS_POWER
-       /* acpi_batter_update could remove power_supply object */
+       /* acpi_battery_update could remove power_supply object */
        if (battery->bat.dev)
                kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
 #endif