#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/suspend.h>
-#include <asm/unaligned.h>
#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
*/
ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
- /* On Lenovo Thinkpad models from 2010 and 2011, the power unit
- switches between mWh and mAh depending on whether the system
- is running on battery or not. When mAh is the unit, most
- reported values are incorrect and need to be adjusted by
- 10000/design_voltage. Verified on x201, t410, t410s, and x220.
- Pre-2010 and 2012 models appear to always report in mWh and
- are thus unaffected (tested with t42, t61, t500, x200, x300,
- and x230). Also, in mid-2012 Lenovo issued a BIOS update for
- the 2011 models that fixes the issue (tested on x220 with a
- post-1.29 BIOS), but as of Nov. 2012, no such update is
- available for the 2010 models. */
- ACPI_BATTERY_QUIRK_THINKPAD_MAH,
};
struct acpi_battery {
kfree(buffer.pointer);
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
battery->full_charge_capacity = battery->design_capacity;
- if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
- battery->power_unit && battery->design_voltage) {
- battery->design_capacity = battery->design_capacity *
- 10000 / battery->design_voltage;
- battery->full_charge_capacity = battery->full_charge_capacity *
- 10000 / battery->design_voltage;
- battery->design_capacity_warning =
- battery->design_capacity_warning *
- 10000 / battery->design_voltage;
- /* Curiously, design_capacity_low, unlike the rest of them,
- is correct. */
- /* capacity_granularity_* equal 1 on the systems tested, so
- it's impossible to tell if they would need an adjustment
- or not if their values were higher. */
- }
return result;
}
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
battery->capacity_now = (battery->capacity_now *
battery->full_charge_capacity) / 100;
- if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
- battery->power_unit && battery->design_voltage) {
- battery->capacity_now = battery->capacity_now *
- 10000 / battery->design_voltage;
- }
return result;
}
}
}
-static void find_battery(const struct dmi_header *dm, void *private)
-{
- struct acpi_battery *battery = (struct acpi_battery *)private;
- /* Note: the hardcoded offsets below have been extracted from
- the source code of dmidecode. */
- if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) {
- const u8 *dmi_data = (const u8 *)(dm + 1);
- int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6));
- if (dm->length >= 18)
- dmi_capacity *= dmi_data[17];
- if (battery->design_capacity * battery->design_voltage / 1000
- != dmi_capacity &&
- battery->design_capacity * 10 == dmi_capacity)
- set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
- &battery->flags);
- }
-}
-
/*
* According to the ACPI spec, some kinds of primary batteries can
* report percentage battery remaining capacity directly to OS.
battery->capacity_now = (battery->capacity_now *
battery->full_charge_capacity) / 100;
}
-
- if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
- return ;
-
- if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
- const char *s;
- s = dmi_get_system_info(DMI_PRODUCT_VERSION);
- if (s && !strnicmp(s, "ThinkPad", 8)) {
- dmi_walk(find_battery, battery);
- if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
- &battery->flags) &&
- battery->design_voltage) {
- battery->design_capacity =
- battery->design_capacity *
- 10000 / battery->design_voltage;
- battery->full_charge_capacity =
- battery->full_charge_capacity *
- 10000 / battery->design_voltage;
- battery->design_capacity_warning =
- battery->design_capacity_warning *
- 10000 / battery->design_voltage;
- battery->capacity_now = battery->capacity_now *
- 10000 / battery->design_voltage;
- }
- }
- }
}
static int acpi_battery_update(struct acpi_battery *battery)
static void acpi_battery_refresh(struct acpi_battery *battery)
{
- int power_unit;
-
if (!battery->bat.dev)
return;
- power_unit = battery->power_unit;
-
acpi_battery_get_info(battery);
-
- if (power_unit == battery->power_unit)
- return;
-
- /* The battery has changed its reporting units. */
+ /* The battery may have changed its reporting units. */
sysfs_remove_battery(battery);
sysfs_add_battery(battery);
}