Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / acpi / battery.c
index 9841720..95649d3 100644 (file)
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 
 #define PREFIX "ACPI: "
 
@@ -98,13 +95,12 @@ enum {
         * due to bad math.
         */
        ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
+       ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
 };
 
 struct acpi_battery {
        struct mutex lock;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct power_supply bat;
-#endif
        struct acpi_device *device;
        unsigned long update_time;
        int rate_now;
@@ -141,7 +137,6 @@ inline int acpi_battery_present(struct acpi_battery *battery)
        return battery->device->status.battery_present;
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int acpi_battery_technology(struct acpi_battery *battery)
 {
        if (!strcasecmp("NiCd", battery->type))
@@ -186,6 +181,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
                                     enum power_supply_property psp,
                                     union power_supply_propval *val)
 {
+       int ret = 0;
        struct acpi_battery *battery = to_acpi_battery(psy);
 
        if (acpi_battery_present(battery)) {
@@ -214,26 +210,44 @@ static int acpi_battery_get_property(struct power_supply *psy,
                val->intval = battery->cycle_count;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-               val->intval = battery->design_voltage * 1000;
+               if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->design_voltage * 1000;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = battery->voltage_now * 1000;
+               if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->voltage_now * 1000;
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
        case POWER_SUPPLY_PROP_POWER_NOW:
-               val->intval = battery->rate_now * 1000;
+               if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->rate_now * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
        case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-               val->intval = battery->design_capacity * 1000;
+               if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->design_capacity * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
        case POWER_SUPPLY_PROP_ENERGY_FULL:
-               val->intval = battery->full_charge_capacity * 1000;
+               if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->full_charge_capacity * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_NOW:
        case POWER_SUPPLY_PROP_ENERGY_NOW:
-               val->intval = battery->capacity_now * 1000;
+               if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
+                       ret = -ENODEV;
+               else
+                       val->intval = battery->capacity_now * 1000;
                break;
        case POWER_SUPPLY_PROP_MODEL_NAME:
                val->strval = battery->model_number;
@@ -245,9 +259,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
                val->strval = battery->serial_number;
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
-       return 0;
+       return ret;
 }
 
 static enum power_supply_property charge_battery_props[] = {
@@ -281,7 +295,6 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
-#endif
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -412,6 +425,8 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
                result = extract_package(battery, buffer.pointer,
                                info_offsets, ARRAY_SIZE(info_offsets));
        kfree(buffer.pointer);
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+               battery->full_charge_capacity = battery->design_capacity;
        return result;
 }
 
@@ -448,6 +463,10 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
            battery->rate_now != -1)
                battery->rate_now = abs((s16)battery->rate_now);
 
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
+           && battery->capacity_now >= 0 && battery->capacity_now <= 100)
+               battery->capacity_now = (battery->capacity_now *
+                               battery->full_charge_capacity) / 100;
        return result;
 }
 
@@ -492,7 +511,6 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
        return acpi_battery_set_alarm(battery);
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -552,7 +570,6 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
        power_supply_unregister(&battery->bat);
        battery->bat.dev = NULL;
 }
-#endif
 
 static void acpi_battery_quirks(struct acpi_battery *battery)
 {
@@ -561,6 +578,33 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
        }
 }
 
+/*
+ * According to the ACPI spec, some kinds of primary batteries can
+ * report percentage battery remaining capacity directly to OS.
+ * In this case, it reports the Last Full Charged Capacity == 100
+ * and BatteryPresentRate == 0xFFFFFFFF.
+ *
+ * Now we found some battery reports percentage remaining capacity
+ * even if it's rechargeable.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15979
+ *
+ * Handle this correctly so that they won't break userspace.
+ */
+static void acpi_battery_quirks2(struct acpi_battery *battery)
+{
+       if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+               return ;
+
+        if (battery->full_charge_capacity == 100 &&
+            battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+            battery->capacity_now >=0 && battery->capacity_now <= 100) {
+               set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
+               battery->full_charge_capacity = battery->design_capacity;
+               battery->capacity_now = (battery->capacity_now *
+                               battery->full_charge_capacity) / 100;
+       }
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
        int result, old_present = acpi_battery_present(battery);
@@ -568,9 +612,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
        if (result)
                return result;
        if (!acpi_battery_present(battery)) {
-#ifdef CONFIG_ACPI_SYSFS_POWER
                sysfs_remove_battery(battery);
-#endif
                battery->update_time = 0;
                return 0;
        }
@@ -582,11 +624,11 @@ static int acpi_battery_update(struct acpi_battery *battery)
                acpi_battery_quirks(battery);
                acpi_battery_init_alarm(battery);
        }
-#ifdef CONFIG_ACPI_SYSFS_POWER
        if (!battery->bat.dev)
                sysfs_add_battery(battery);
-#endif
-       return acpi_battery_get_state(battery);
+       result = acpi_battery_get_state(battery);
+       acpi_battery_quirks2(battery);
+       return result;
 }
 
 /* --------------------------------------------------------------------------
@@ -867,26 +909,20 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
 static void acpi_battery_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_battery *battery = acpi_driver_data(device);
-#ifdef CONFIG_ACPI_SYSFS_POWER
        struct device *old;
-#endif
 
        if (!battery)
                return;
-#ifdef CONFIG_ACPI_SYSFS_POWER
        old = battery->bat.dev;
-#endif
        acpi_battery_update(battery);
        acpi_bus_generate_proc_event(device, event,
                                     acpi_battery_present(battery));
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
-#ifdef CONFIG_ACPI_SYSFS_POWER
        /* acpi_battery_update could remove power_supply object */
        if (old && battery->bat.dev)
                power_supply_changed(&battery->bat);
-#endif
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -934,9 +970,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_remove_fs(device);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
        sysfs_remove_battery(battery);
-#endif
        mutex_destroy(&battery->lock);
        kfree(battery);
        return 0;