summaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorDavid Lechner <david@lechnology.com>2017-05-15 16:21:15 -0500
committerSebastian Reichel <sre@kernel.org>2017-06-08 13:05:27 +0200
commit105df60f207301631258c966d82d99f826508b41 (patch)
treea78c2aa2e0dbf22303c74412de68ce5657713346 /drivers/power
parent71399aa5d68bb3ed8c4caf8bfd71faae39555876 (diff)
downloadlinux-105df60f207301631258c966d82d99f826508b41.tar.bz2
power: supply: sysfs: parse string as enum when writing property
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>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/power_supply_sysfs.c124
1 files changed, 85 insertions, 39 deletions
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 07b484f995c1..b32c14183773 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -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;
@@ -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);
@@ -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)