From patchwork Wed Oct 13 00:18:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhang Rui X-Patchwork-Id: 249461 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9D0LcLQ005508 for ; Wed, 13 Oct 2010 00:21:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752608Ab0JMAVh (ORCPT ); Tue, 12 Oct 2010 20:21:37 -0400 Received: from mga11.intel.com ([192.55.52.93]:19534 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752606Ab0JMAVg (ORCPT ); Tue, 12 Oct 2010 20:21:36 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 12 Oct 2010 17:21:36 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.57,322,1283756400"; d="scan'208";a="616115043" Received: from rui.sh.intel.com (HELO [10.239.51.31]) ([10.239.51.31]) by fmsmga002.fm.intel.com with ESMTP; 12 Oct 2010 17:21:35 -0700 Subject: [PATCH] ACPI battery: handle batteries tht report percentage remaining capacity correctly From: Zhang Rui To: "Brown, Len" Cc: "linux-acpi@vger.kernel.org" , "Zhang, Rui" , sitsofe@yahoo.com Date: Wed, 13 Oct 2010 08:18:41 +0800 Message-ID: <1286929121.2111.4092.camel@rui> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Wed, 13 Oct 2010 00:21:41 +0000 (UTC) Index: linux-2.6/drivers/acpi/battery.c =================================================================== --- linux-2.6.orig/drivers/acpi/battery.c +++ linux-2.6/drivers/acpi/battery.c @@ -98,6 +98,7 @@ enum { * due to bad math. */ ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, + ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, }; struct acpi_battery { @@ -412,6 +413,8 @@ static int acpi_battery_get_info(struct 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 +451,10 @@ static int acpi_battery_get_state(struct 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; } @@ -561,6 +568,33 @@ static void acpi_battery_quirks(struct a } } +/* + * 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); @@ -586,7 +620,9 @@ static int acpi_battery_update(struct ac 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; } /* --------------------------------------------------------------------------