Skip to content

Commit

Permalink
power: supply: sysfs: parse string as enum when writing property
Browse files Browse the repository at this point in the history
This fixes the TODO to parse strings and convert them to enum values
when writing to a power_supply class property sysfs attribute.

There is at least one driver that has a writable enum property that
previously could only be written as an integer, so a fallback to writing
enums as integers instead of strings is provided so we don't break existing
userspace programs.

Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
  • Loading branch information
dlech authored and sre committed Jun 8, 2017
1 parent 71399aa commit 105df60
Showing 1 changed file with 85 additions and 39 deletions.
124 changes: 85 additions & 39 deletions drivers/power/supply/power_supply_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,42 @@

static struct device_attribute power_supply_attrs[];

static const char * const power_supply_type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
"USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
"USB_PD", "USB_PD_DRP", "BrickID"
};

static const char * const power_supply_status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
};

static const char * const power_supply_charge_type_text[] = {
"Unknown", "N/A", "Trickle", "Fast"
};

static const char * const power_supply_health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
"Unspecified failure", "Cold", "Watchdog timer expire",
"Safety timer expire"
};

static const char * const power_supply_technology_text[] = {
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
"LiMn"
};

static const char * const power_supply_capacity_level_text[] = {
"Unknown", "Critical", "Low", "Normal", "High", "Full"
};

static const char * const power_supply_scope_text[] = {
"Unknown", "System", "Device"
};

static ssize_t power_supply_show_property(struct device *dev,
struct device_attribute *attr,
char *buf) {
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
"USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
"USB_PD", "USB_PD_DRP", "BrickID"
};
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"
};
static char *charge_type[] = {
"Unknown", "N/A", "Trickle", "Fast"
};
static char *health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
"Unspecified failure", "Cold", "Watchdog timer expire",
"Safety timer expire"
};
static char *technology_text[] = {
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
"LiMn"
};
static char *capacity_level_text[] = {
"Unknown", "Critical", "Low", "Normal", "High", "Full"
};
static char *scope_text[] = {
"Unknown", "System", "Device"
};
ssize_t ret = 0;
struct power_supply *psy = dev_get_drvdata(dev);
const ptrdiff_t off = attr - power_supply_attrs;
Expand All @@ -91,19 +98,26 @@ static ssize_t power_supply_show_property(struct device *dev,
}

if (off == POWER_SUPPLY_PROP_STATUS)
return sprintf(buf, "%s\n", status_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_status_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
return sprintf(buf, "%s\n", charge_type[value.intval]);
return sprintf(buf, "%s\n",
power_supply_charge_type_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_HEALTH)
return sprintf(buf, "%s\n", health_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_health_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
return sprintf(buf, "%s\n", technology_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_technology_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_capacity_level_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_TYPE)
return sprintf(buf, "%s\n", type_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_type_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_SCOPE)
return sprintf(buf, "%s\n", scope_text[value.intval]);
return sprintf(buf, "%s\n",
power_supply_scope_text[value.intval]);
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
return sprintf(buf, "%s\n", value.strval);

Expand All @@ -117,14 +131,46 @@ static ssize_t power_supply_store_property(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
const ptrdiff_t off = attr - power_supply_attrs;
union power_supply_propval value;
long long_val;

/* TODO: support other types than int */
ret = kstrtol(buf, 10, &long_val);
if (ret < 0)
return ret;
/* maybe it is a enum property? */
switch (off) {
case POWER_SUPPLY_PROP_STATUS:
ret = sysfs_match_string(power_supply_status_text, buf);
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
ret = sysfs_match_string(power_supply_charge_type_text, buf);
break;
case POWER_SUPPLY_PROP_HEALTH:
ret = sysfs_match_string(power_supply_health_text, buf);
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
ret = sysfs_match_string(power_supply_technology_text, buf);
break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
ret = sysfs_match_string(power_supply_capacity_level_text, buf);
break;
case POWER_SUPPLY_PROP_SCOPE:
ret = sysfs_match_string(power_supply_scope_text, buf);
break;
default:
ret = -EINVAL;
}

/*
* If no match was found, then check to see if it is an integer.
* Integer values are valid for enums in addition to the text value.
*/
if (ret < 0) {
long long_val;

ret = kstrtol(buf, 10, &long_val);
if (ret < 0)
return ret;

ret = long_val;
}

value.intval = long_val;
value.intval = ret;

ret = power_supply_set_property(psy, off, &value);
if (ret < 0)
Expand Down

0 comments on commit 105df60

Please sign in to comment.