Check all battery variants when polling

On Thinkpads T410s sysfs may switch between energy_full/_now and
charge_full/_now files across suspend/resume. Instead of polling only
one set of files always try all variants when checking battery levels.
This fixes a battery level of 0 in GKrellM after resume.

Thanks to Joern Engel for tracking this down and for providing a patch
via the Debian bugtracker.

See also http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=630117
This commit is contained in:
Stefan Gehn 2013-07-29 20:23:15 +02:00
parent 9693241883
commit 3a487e3271
1 changed files with 59 additions and 104 deletions

View File

@ -1802,14 +1802,15 @@ acpi_battery_data(BatteryFile *bf)
#define SYSFS_TYPE_AC_ADAPTER "mains"
#define VARIANTS 5
typedef struct syspower
{
gint type;
gint id;
gint charge_units;
gint charge_units[VARIANTS];
gchar const *sysdir;
gchar const *sys_charge_full;
gchar const *sys_charge_now;
gchar const *sys_charge_full[VARIANTS];
gchar const *sys_charge_now[VARIANTS];
gboolean present;
gboolean ac_present;
gboolean charging;
@ -1873,7 +1874,6 @@ sysfs_power_data (struct syspower *sp)
gchar buf[128];
gchar *syszap;
gboolean charging;
gboolean stat_full;
time_left = -1;
charge_full = charge_now = 0;
@ -1910,15 +1910,26 @@ sysfs_power_data (struct syspower *sp)
if (present)
{
if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_full))
int i;
for (i = 0; i < VARIANTS; i++) {
if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_full[i]))
{
charge_full = strtoll (buf, NULL, 0);
}
if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_now))
else
{
continue;
}
if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_now[i]))
{
charge_now = strtoll (buf, NULL, 0);
}
if (sp->charge_units == CHGUNITS_PERCENT)
else
{
continue;
}
if (sp->charge_units[i] == CHGUNITS_PERCENT)
{
percent = charge_now;
}
@ -1927,6 +1938,8 @@ sysfs_power_data (struct syspower *sp)
if (charge_full > 0)
percent = charge_now * 100 / charge_full;
}
break;
}
/* Get charging status. */
*syszap = '\0';
@ -1934,7 +1947,6 @@ sysfs_power_data (struct syspower *sp)
if (read_sysfs_entry (buf, sizeof (buf), sysentry))
{
charging = !strcasecmp (buf, "charging");
stat_full = !strcasecmp (buf, "full");
}
}
@ -1952,12 +1964,10 @@ setup_sysfs_ac_power (gchar const *sysdir)
if (_GK.debug_level & DEBUG_BATTERY)
g_debug ("setup_sysfs_ac_power: %s\n", sysdir);
sp = g_new0 (syspower, 1);
memset(sp, 0, sizeof(*sp));
sp->type = PWRTYPE_MAINS;
sp->id = g_pwr_id++;
sp->charge_units = CHGUNITS_INVALID;
sp->sysdir = g_strdup (sysdir);
sp->sys_charge_full =
sp->sys_charge_now = NULL;
/* Add mains power sources to head of list. */
g_sysfs_power_list = g_list_prepend (g_sysfs_power_list, sp);
@ -1969,94 +1979,39 @@ static gboolean
setup_sysfs_battery (gchar const *sysdir)
{
syspower *sp;
gchar *sys_charge_full = NULL,
*sys_charge_now = NULL;
gint units;
gboolean retval = FALSE;
/*
* There are three flavors of reporting: 'energy', 'charge', and
* 'capacity'. Check for them in that order. (Apologies for the
* ugliness; you try coding an unrolled 'if ((A || B) && C)' and make it
* pretty.)
*/
if (_GK.debug_level & DEBUG_BATTERY)
g_debug ("setup_sysfs_battery: %s\n", sysdir);
units = CHGUNITS_uWH;
sys_charge_full = g_strconcat (sysdir, "/energy_full", NULL);
if (access (sys_charge_full, F_OK | R_OK))
{
g_free (sys_charge_full);
sys_charge_full = g_strconcat (sysdir, "/energy_full_design", NULL);
if (access (sys_charge_full, F_OK | R_OK))
{
goto try_charge; /* Look down */
}
}
sys_charge_now = g_strconcat (sysdir, "/energy_now", NULL);
if (!access (sys_charge_now, F_OK | R_OK))
goto done; /* Look down */
try_charge:
if (sys_charge_full) g_free (sys_charge_full), sys_charge_full = NULL;
if (sys_charge_now) g_free (sys_charge_now), sys_charge_now = NULL;
units = CHGUNITS_uAH;
sys_charge_full = g_strconcat (sysdir, "/charge_full", NULL);
if (access (sys_charge_full, F_OK | R_OK))
{
g_free (sys_charge_full);
sys_charge_full = g_strconcat (sysdir, "/charge_full_design", NULL);
if (access (sys_charge_full, F_OK | R_OK))
{
goto try_capacity; /* Look down */
}
}
sys_charge_now = g_strconcat (sysdir, "/charge_now", NULL);
if (!access (sys_charge_now, F_OK | R_OK))
goto done; /* Look down */
try_capacity:
if (sys_charge_full) g_free (sys_charge_full), sys_charge_full = NULL;
if (sys_charge_now) g_free (sys_charge_now), sys_charge_now = NULL;
/* This one's a little simpler... */
units = CHGUNITS_PERCENT;
/*
* FIXME: I have no idea if 'capacity_full' actually shows up, since
* 'capacity' always defines "full" as always 100%
*/
sys_charge_full = g_strconcat (sysdir, "/capacity_full", NULL);
if (access (sys_charge_full, F_OK | R_OK))
goto ackphft; /* Look down */
sys_charge_now = g_strconcat (sysdir, "/capacity_now", NULL);
if (access (sys_charge_now, F_OK | R_OK))
goto ackphft; /* Look down */
done:
sp = g_new0 (syspower, 1);
sp->type = PWRTYPE_BATTERY;
sp->id = g_pwr_id++;
sp->charge_units = units;
sp->sysdir = g_strdup (sysdir);
sp->sys_charge_full = sys_charge_full;
sp->sys_charge_now = sys_charge_now;
/*
* There are three flavors of reporting: 'energy', 'charge', and
* 'capacity'. Check for them in that order.
*/
sp->charge_units[0] = CHGUNITS_uWH;
sp->sys_charge_full[0] = g_strconcat (sysdir, "/energy_full", NULL);
sp->sys_charge_now[0] = g_strconcat (sysdir, "/energy_now", NULL);
sp->charge_units[1] = CHGUNITS_uWH;
sp->sys_charge_full[1] = g_strconcat (sysdir, "/energy_full_design", NULL);
sp->sys_charge_now[1] = g_strconcat (sysdir, "/energy_now", NULL);
sp->charge_units[2] = CHGUNITS_uAH;
sp->sys_charge_full[2] = g_strconcat (sysdir, "/charge_full", NULL);
sp->sys_charge_now[2] = g_strconcat (sysdir, "/charge_now", NULL);
sp->charge_units[3] = CHGUNITS_uAH;
sp->sys_charge_full[3] = g_strconcat (sysdir, "/charge_full_design", NULL);
sp->sys_charge_now[3] = g_strconcat (sysdir, "/charge_now", NULL);
sp->charge_units[4] = CHGUNITS_PERCENT;
sp->sys_charge_full[4] = g_strconcat (sysdir, "/capacity_full", NULL);
sp->sys_charge_now[4] = g_strconcat (sysdir, "/capacity_now", NULL);
/* Battery power sources are appended to the end of the list. */
g_sysfs_power_list = g_list_append (g_sysfs_power_list, sp);
if (_GK.debug_level & DEBUG_BATTERY)
g_debug ("setup_sysfs_battery: %s, %s\n",
sys_charge_full, sys_charge_now);
retval = TRUE;
if (0)
{
ackphft:
if (sys_charge_full) g_free (sys_charge_full);
if (sys_charge_now) g_free (sys_charge_now);
}
return retval;
return TRUE;
}
static gboolean