From patchwork Tue Nov 2 02:50:40 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Len Brown X-Patchwork-Id: 296552 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 oA22ovB0007574 for ; Tue, 2 Nov 2010 02:50:59 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754194Ab0KBCuy (ORCPT ); Mon, 1 Nov 2010 22:50:54 -0400 Received: from vms173011pub.verizon.net ([206.46.173.11]:50402 "EHLO vms173011pub.verizon.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754083Ab0KBCuy (ORCPT ); Mon, 1 Nov 2010 22:50:54 -0400 Received: from localhost.localdomain ([unknown] [74.104.161.234]) by vms173011.mailsrvcs.net (Sun Java(tm) System Messaging Server 7u2-7.02 32bit (built Apr 16 2009)) with ESMTPA id <0LB8006FHL8JGKB4@vms173011.mailsrvcs.net> for linux-acpi@vger.kernel.org; Mon, 01 Nov 2010 21:50:43 -0500 (CDT) Received: from localhost.localdomain (x980 [127.0.0.1]) by localhost.localdomain (8.14.4/8.14.4) with ESMTP id oA22ofEB015784; Mon, 01 Nov 2010 22:50:42 -0400 Received: from localhost (lenb@localhost) by localhost.localdomain (8.14.4/8.14.4/Submit) with ESMTP id oA22oe8c015779; Mon, 01 Nov 2010 22:50:41 -0400 X-Authentication-warning: localhost.localdomain: lenb owned process doing -bs Date: Mon, 01 Nov 2010 22:50:40 -0400 (EDT) From: Len Brown X-X-Sender: lenb@localhost.localdomain To: stable@kernel.org Cc: linux-acpi@vger.kernel.org Subject: [PATCH 2.6.35..2.6.36.stable] ACPI battery: support percentage battery remaining capacity Message-id: User-Agent: Alpine 2.00 (LFD 1167 2008-08-23) MIME-version: 1.0 Content-type: TEXT/PLAIN; charset=US-ASCII 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]); Tue, 02 Nov 2010 02:50:59 +0000 (UTC) Index: linux-2.6.35.y/drivers/acpi/battery.c =================================================================== --- linux-2.6.35.y.orig/drivers/acpi/battery.c +++ linux-2.6.35.y/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 { @@ -413,6 +414,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; } @@ -449,6 +452,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; } @@ -562,6 +569,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); @@ -587,7 +621,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; } /* --------------------------------------------------------------------------