Commit d387d08c authored by spiiroin's avatar spiiroin

[battery-udev] Enablers for configurable charger types. JB#49693

For example pinephone exposes charger devices in a manner where the
name is prefixed with chiptype (e.g. "axp813-ac" / "axp20x-usb").
As mce does not recognize these, both wall charger and pc connection
gets treated as "other" type charger - which works to some extent but
triggers incorrect UI actions.

If direct match for power supply device type / name is not found, try
to eliminate chipname prefix so that for example names such as
"axp20x-usb" get treated as plain "usb".

To future proof things, make it possible to override build-in
defaults and heuristics via mce configuration files.
Signed-off-by: spiiroin's avatarSimo Piiroinen <simo.piiroinen@jollamobile.com>
parent f4dbf7e1
......@@ -1655,6 +1655,37 @@ const char *usb_cable_state_to_dbus(usb_cable_state_t state)
return res;
}
/** Convert human readable name to charger_type_t enum
*
* @param name human readable charger type name
*
* @return charger_type_t enumeration value, or CHARGER_TYPE_INVALID
*/
charger_type_t
charger_type_parse(const char *name)
{
charger_type_t type = CHARGER_TYPE_INVALID;
if( !name )
mce_log(LL_WARN, "invalid charger type: %s", "null");
else if( !strcmp(name, "none") )
type = CHARGER_TYPE_NONE;
else if( !strcmp(name, "usb") )
type = CHARGER_TYPE_USB;
else if( !strcmp(name, "dcp") )
type = CHARGER_TYPE_DCP;
else if( !strcmp(name, "hwdcp") )
type = CHARGER_TYPE_HVDCP;
else if( !strcmp(name, "cdp") )
type = CHARGER_TYPE_CDP;
else if( !strcmp(name, "wireless") )
type = CHARGER_TYPE_WIRELESS;
else if( !strcmp(name, "other") )
type = CHARGER_TYPE_OTHER;
else
mce_log(LL_WARN, "invalid charger type: %s", name);
return type;
}
/** Convert charger_type_t enum to human readable string
*
* @param type charger_type_t enumeration value
......@@ -1664,7 +1695,7 @@ const char *usb_cable_state_to_dbus(usb_cable_state_t state)
const char *
charger_type_repr(charger_type_t type)
{
const char *repr = "unknown";
const char *repr = "invalid";
switch( type ) {
case CHARGER_TYPE_NONE: repr = "none"; break;
case CHARGER_TYPE_USB: repr = "usb"; break;
......@@ -1689,6 +1720,7 @@ charger_type_to_dbus(charger_type_t type)
{
const char *repr = MCE_CHARGER_TYPE_OTHER;
switch( type ) {
case CHARGER_TYPE_INVALID:
case CHARGER_TYPE_NONE: repr = MCE_CHARGER_TYPE_NONE; break;
case CHARGER_TYPE_USB: repr = MCE_CHARGER_TYPE_USB; break;
case CHARGER_TYPE_DCP: repr = MCE_CHARGER_TYPE_DCP; break;
......
# Configuration file for MCE - udev battery plugin
[BatteryUDevChargerTypes]
# Charger type is derived primarily from POWER_SUPPLY_TYPE
# udev attribute, or if such property is not present from
# device name.
# The built-in defaults are as follows:
#ac=dcp
#unknown=none
#mains=dcp
#usb_hvdcp=hwdcp
#wireless=wireless
#cdp=cdp
#usb_aca=usb
#usb=usb
#usb_dcp=dcp
#usb_hvdcp_3=hwdcp
#usb_cdp=cdp
......@@ -358,6 +358,12 @@ const char *charger_state_to_dbus(charger_state_t state);
*/
typedef enum
{
/* Placeholder value for lookup failures etc
*/
CHARGER_TYPE_INVALID,
/* Value that signifies that no charger is connected
*/
CHARGER_TYPE_NONE,
/* Charger types that do not carry special meaning from
......@@ -377,6 +383,7 @@ typedef enum
CHARGER_TYPE_USB, // Standard Downstream Port
} charger_type_t;
charger_type_t charger_type_parse(const char *name);
const char *charger_type_repr(charger_type_t type);
const char *charger_type_to_dbus(charger_type_t type);
......
......@@ -72,6 +72,9 @@
/** INI-file group for blacklisting devices */
#define MCE_CONF_BATTERY_UDEV_DEVICE_BLACKLIST_GROUP "BatteryUDevDeviceBlacklist"
/** INI-file group for configuring charger types */
#define MCE_CONF_BATTERY_UDEV_DEVICE_CHARGERTYPE_GROUP "BatteryUDevChargerTypes"
/** Delay between udev notifications and battery state evaluation
*
* The purpose is to increase chances of getting battery and
......@@ -343,6 +346,9 @@ static GHashTable *udevproperty_type_lut = 0;
/** Lookup table for device blacklisting */
static GHashTable *udevdevice_blacklist_lut = 0;
/** Lookup table for determining charger types */
static GHashTable *udevdevice_chargertype_lut = 0;
/** How to treat unknown properties; default to ignoring them */
static property_type_t udevproperty_type_def = PROPERTY_TYPE_IGNORE;
......@@ -1101,10 +1107,44 @@ udevdevice_lookup_battery_state(const char *status)
*/
static charger_type_t
udevdevice_lookup_charger_type(const char *name)
{
charger_type_t type = CHARGER_TYPE_INVALID;
gchar *key = 0;
gpointer val;
if( !name || !udevdevice_chargertype_lut )
goto EXIT;
key = g_ascii_strdown(name, -1);
/* Try exact match 1st, then relaxed one which equates
* "chipname-ac" with plain "ac".
*/
val = g_hash_table_lookup(udevdevice_chargertype_lut, key);
if( !val ) {
const char *end = strrchr(key, '-');
if( end )
val = g_hash_table_lookup(udevdevice_chargertype_lut, end + 1);
}
type = GPOINTER_TO_INT(val);
EXIT:
if( type == CHARGER_TYPE_INVALID ) {
mce_log(LL_WARN, "unknown charger type: %s", name ?: "null");
type = CHARGER_TYPE_OTHER;
}
g_free(key);
mce_log(LL_DEBUG, "charger type: %s -> %s", name ?: "null", charger_type_repr(type));
return type;
}
static void
udevdevice_init_chargertype(void)
{
static const struct {
const char *name;
int value;
const char *name;
charger_type_t type;
} lut[] = {
/* Type map - adapted from statefs sources
*/
......@@ -1131,20 +1171,68 @@ udevdevice_lookup_charger_type(const char *name)
{ 0, 0 }
};
charger_type_t value = CHARGER_TYPE_OTHER;
if( name ) {
for( size_t i = 0; ; ++i ) {
if( lut[i].name == 0 ) {
mce_log(LL_WARN, "unknown charger type: %s", name);
break;
}
if( !g_ascii_strcasecmp(lut[i].name, name) ) {
value = lut[i].value;
break;
static const char grp[] = MCE_CONF_BATTERY_UDEV_DEVICE_CHARGERTYPE_GROUP;
if( udevdevice_chargertype_lut )
goto EXIT;
udevdevice_chargertype_lut =
g_hash_table_new_full(g_str_hash, g_str_equal, g_free, 0);
/* Seed with built-in values */
for( size_t i = 0; lut[i].name; ++i ) {
g_hash_table_insert(udevdevice_chargertype_lut,
g_ascii_strdown(lut[i].name, -1),
GINT_TO_POINTER(lut[i].type));
}
#if 0
/* Dump as ini-file for use as an example */
{
GHashTableIter iter;
gpointer key, val;
g_hash_table_iter_init(&iter, udevdevice_chargertype_lut);
printf("[%s]\n", grp);
while ( g_hash_table_iter_next (&iter, &key, &val) )
printf("#%s = %s\n", key, charger_type_repr(GPOINTER_TO_INT(val)));
}
#endif
/* Override with configuration */
if( mce_conf_has_group(grp) ) {
mce_log(LL_DEBUG, "using configured chargertypes");
gsize count = 0;
gchar **keys = mce_conf_get_keys(grp, &count);
for( gsize i = 0; i < count; ++i ) {
const gchar *name = keys[i];
gchar *value = mce_conf_get_string(grp, name, 0);
charger_type_t type = charger_type_parse(value);
if( type != CHARGER_TYPE_INVALID ) {
g_hash_table_insert(udevdevice_chargertype_lut,
g_ascii_strdown(name, -1),
GINT_TO_POINTER(type));
}
g_free(value);
}
g_strfreev(keys);
}
EXIT:
return;
}
/** Release device chargertype lookup table
*/
static void
udevdevice_quit_chargertype(void)
{
if( udevdevice_chargertype_lut ) {
g_hash_table_unref(udevdevice_chargertype_lut),
udevdevice_chargertype_lut = 0;
}
return value;
}
/** Initialize device blacklist lookup table
......@@ -1955,6 +2043,7 @@ G_MODULE_EXPORT const gchar *g_module_check_init(GModule *module)
(void)module;
udevdevice_init_blacklist();
udevdevice_init_chargertype();
udevproperty_init_types();
mcebat_dbus_init();
......@@ -1985,6 +2074,7 @@ G_MODULE_EXPORT void g_module_unload(GModule *module)
udevtracker_delete(udevtracker_object), udevtracker_object = 0;
udevproperty_quit_types();
udevdevice_quit_chargertype();
udevdevice_quit_blacklist();
mce_log(LL_DEBUG, "%s: unloaded", MODULE_NAME);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment