summaryrefslogtreecommitdiff
path: root/drivers/power/supply/power_supply_sysfs.c
diff options
context:
space:
mode:
authorMathew King <mathewk@chromium.org>2020-05-04 14:29:27 -0600
committerSebastian Reichel <sre@kernel.org>2020-05-07 00:53:38 +0200
commit2cabeaf151294eceaa0f0e0fab2fe9fe66868869 (patch)
treee768ae3538d6d01fad2ad395b7c01f1bf476fe00 /drivers/power/supply/power_supply_sysfs.c
parent72d9cd9cdc18b53c1df935dc9d40ea7bf057387f (diff)
power: supply: core: Cleanup power supply sysfs attribute list
Make the device attribute list used to create sysfs attributes more robust by decoupling the list order from order of the enum defined in power_supply.h. This is done by using a designated initializer in the POWER_SUPPLY_ATTR macro. Signed-off-by: Mathew King <mathewk@chromium.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power/supply/power_supply_sysfs.c')
-rw-r--r--drivers/power/supply/power_supply_sysfs.c260
1 files changed, 132 insertions, 128 deletions
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 51de3f47b25d..cfc2550f494c 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -18,26 +18,20 @@
#include "power_supply.h"
-/*
- * This is because the name "current" breaks the device attr macro.
- * The "current" word resolves to "(get_current())" so instead of
- * "current" "(get_current())" appears in the sysfs.
- *
- * The source of this definition is the device.h which calls __ATTR
- * macro in sysfs.h which calls the __stringify macro.
- *
- * Only modification that the name is not tried to be resolved
- * (as a macro let's say).
- */
+#define MAX_PROP_NAME_LEN 30
-#define POWER_SUPPLY_ATTR(_name) \
-{ \
- .attr = { .name = #_name }, \
- .show = power_supply_show_property, \
- .store = power_supply_store_property, \
-}
+struct power_supply_attr {
+ const char *prop_name;
+ char attr_name[MAX_PROP_NAME_LEN + 1];
+ struct device_attribute dev_attr;
+};
-static struct device_attribute power_supply_attrs[];
+#define POWER_SUPPLY_ATTR(_name) \
+[POWER_SUPPLY_PROP_ ## _name] = \
+{ \
+ .prop_name = #_name, \
+ .attr_name = #_name "\0", \
+}
static const char * const power_supply_type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
@@ -77,6 +71,91 @@ static const char * const power_supply_scope_text[] = {
"Unknown", "System", "Device"
};
+static struct power_supply_attr power_supply_attrs[] = {
+ /* Properties of type `int' */
+ POWER_SUPPLY_ATTR(STATUS),
+ POWER_SUPPLY_ATTR(CHARGE_TYPE),
+ POWER_SUPPLY_ATTR(HEALTH),
+ POWER_SUPPLY_ATTR(PRESENT),
+ POWER_SUPPLY_ATTR(ONLINE),
+ POWER_SUPPLY_ATTR(AUTHENTIC),
+ POWER_SUPPLY_ATTR(TECHNOLOGY),
+ POWER_SUPPLY_ATTR(CYCLE_COUNT),
+ POWER_SUPPLY_ATTR(VOLTAGE_MAX),
+ POWER_SUPPLY_ATTR(VOLTAGE_MIN),
+ POWER_SUPPLY_ATTR(VOLTAGE_MAX_DESIGN),
+ POWER_SUPPLY_ATTR(VOLTAGE_MIN_DESIGN),
+ POWER_SUPPLY_ATTR(VOLTAGE_NOW),
+ POWER_SUPPLY_ATTR(VOLTAGE_AVG),
+ POWER_SUPPLY_ATTR(VOLTAGE_OCV),
+ POWER_SUPPLY_ATTR(VOLTAGE_BOOT),
+ POWER_SUPPLY_ATTR(CURRENT_MAX),
+ POWER_SUPPLY_ATTR(CURRENT_NOW),
+ POWER_SUPPLY_ATTR(CURRENT_AVG),
+ POWER_SUPPLY_ATTR(CURRENT_BOOT),
+ POWER_SUPPLY_ATTR(POWER_NOW),
+ POWER_SUPPLY_ATTR(POWER_AVG),
+ POWER_SUPPLY_ATTR(CHARGE_FULL_DESIGN),
+ POWER_SUPPLY_ATTR(CHARGE_EMPTY_DESIGN),
+ POWER_SUPPLY_ATTR(CHARGE_FULL),
+ POWER_SUPPLY_ATTR(CHARGE_EMPTY),
+ POWER_SUPPLY_ATTR(CHARGE_NOW),
+ POWER_SUPPLY_ATTR(CHARGE_AVG),
+ POWER_SUPPLY_ATTR(CHARGE_COUNTER),
+ POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT),
+ POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT_MAX),
+ POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE),
+ POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE_MAX),
+ POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT),
+ POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT_MAX),
+ POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
+ POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD),
+ POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT),
+ POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT),
+ POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT),
+ POWER_SUPPLY_ATTR(ENERGY_FULL_DESIGN),
+ POWER_SUPPLY_ATTR(ENERGY_EMPTY_DESIGN),
+ POWER_SUPPLY_ATTR(ENERGY_FULL),
+ POWER_SUPPLY_ATTR(ENERGY_EMPTY),
+ POWER_SUPPLY_ATTR(ENERGY_NOW),
+ POWER_SUPPLY_ATTR(ENERGY_AVG),
+ POWER_SUPPLY_ATTR(CAPACITY),
+ POWER_SUPPLY_ATTR(CAPACITY_ALERT_MIN),
+ POWER_SUPPLY_ATTR(CAPACITY_ALERT_MAX),
+ POWER_SUPPLY_ATTR(CAPACITY_LEVEL),
+ POWER_SUPPLY_ATTR(TEMP),
+ POWER_SUPPLY_ATTR(TEMP_MAX),
+ POWER_SUPPLY_ATTR(TEMP_MIN),
+ POWER_SUPPLY_ATTR(TEMP_ALERT_MIN),
+ POWER_SUPPLY_ATTR(TEMP_ALERT_MAX),
+ POWER_SUPPLY_ATTR(TEMP_AMBIENT),
+ POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MIN),
+ POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MAX),
+ POWER_SUPPLY_ATTR(TIME_TO_EMPTY_NOW),
+ POWER_SUPPLY_ATTR(TIME_TO_EMPTY_AVG),
+ POWER_SUPPLY_ATTR(TIME_TO_FULL_NOW),
+ POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG),
+ POWER_SUPPLY_ATTR(TYPE),
+ POWER_SUPPLY_ATTR(USB_TYPE),
+ POWER_SUPPLY_ATTR(SCOPE),
+ POWER_SUPPLY_ATTR(PRECHARGE_CURRENT),
+ POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT),
+ POWER_SUPPLY_ATTR(CALIBRATE),
+ /* Properties of type `const char *' */
+ POWER_SUPPLY_ATTR(MODEL_NAME),
+ POWER_SUPPLY_ATTR(MANUFACTURER),
+ POWER_SUPPLY_ATTR(SERIAL_NUMBER),
+};
+
+static struct attribute *
+__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
+
+static enum power_supply_property dev_attr_psp(struct device_attribute *attr)
+{
+ return container_of(attr, struct power_supply_attr, dev_attr) -
+ power_supply_attrs;
+}
+
static ssize_t power_supply_show_usb_type(struct device *dev,
const struct power_supply_desc *desc,
union power_supply_propval *value,
@@ -116,7 +195,7 @@ static ssize_t power_supply_show_property(struct device *dev,
char *buf) {
ssize_t ret;
struct power_supply *psy = dev_get_drvdata(dev);
- enum power_supply_property psp = attr - power_supply_attrs;
+ enum power_supply_property psp = dev_attr_psp(attr);
union power_supply_propval value;
if (psp == POWER_SUPPLY_PROP_TYPE) {
@@ -184,7 +263,7 @@ static ssize_t power_supply_store_property(struct device *dev,
const char *buf, size_t count) {
ssize_t ret;
struct power_supply *psy = dev_get_drvdata(dev);
- enum power_supply_property psp = attr - power_supply_attrs;
+ enum power_supply_property psp = dev_attr_psp(attr);
union power_supply_propval value;
switch (psp) {
@@ -233,86 +312,6 @@ static ssize_t power_supply_store_property(struct device *dev,
return count;
}
-/* Must be in the same order as POWER_SUPPLY_PROP_* */
-static struct device_attribute power_supply_attrs[] = {
- /* Properties of type `int' */
- POWER_SUPPLY_ATTR(status),
- POWER_SUPPLY_ATTR(charge_type),
- POWER_SUPPLY_ATTR(health),
- POWER_SUPPLY_ATTR(present),
- POWER_SUPPLY_ATTR(online),
- POWER_SUPPLY_ATTR(authentic),
- POWER_SUPPLY_ATTR(technology),
- POWER_SUPPLY_ATTR(cycle_count),
- POWER_SUPPLY_ATTR(voltage_max),
- POWER_SUPPLY_ATTR(voltage_min),
- POWER_SUPPLY_ATTR(voltage_max_design),
- POWER_SUPPLY_ATTR(voltage_min_design),
- POWER_SUPPLY_ATTR(voltage_now),
- POWER_SUPPLY_ATTR(voltage_avg),
- POWER_SUPPLY_ATTR(voltage_ocv),
- POWER_SUPPLY_ATTR(voltage_boot),
- POWER_SUPPLY_ATTR(current_max),
- POWER_SUPPLY_ATTR(current_now),
- POWER_SUPPLY_ATTR(current_avg),
- POWER_SUPPLY_ATTR(current_boot),
- POWER_SUPPLY_ATTR(power_now),
- POWER_SUPPLY_ATTR(power_avg),
- POWER_SUPPLY_ATTR(charge_full_design),
- POWER_SUPPLY_ATTR(charge_empty_design),
- POWER_SUPPLY_ATTR(charge_full),
- POWER_SUPPLY_ATTR(charge_empty),
- POWER_SUPPLY_ATTR(charge_now),
- POWER_SUPPLY_ATTR(charge_avg),
- POWER_SUPPLY_ATTR(charge_counter),
- POWER_SUPPLY_ATTR(constant_charge_current),
- POWER_SUPPLY_ATTR(constant_charge_current_max),
- POWER_SUPPLY_ATTR(constant_charge_voltage),
- POWER_SUPPLY_ATTR(constant_charge_voltage_max),
- POWER_SUPPLY_ATTR(charge_control_limit),
- POWER_SUPPLY_ATTR(charge_control_limit_max),
- POWER_SUPPLY_ATTR(charge_control_start_threshold),
- POWER_SUPPLY_ATTR(charge_control_end_threshold),
- POWER_SUPPLY_ATTR(input_current_limit),
- POWER_SUPPLY_ATTR(input_voltage_limit),
- POWER_SUPPLY_ATTR(input_power_limit),
- POWER_SUPPLY_ATTR(energy_full_design),
- POWER_SUPPLY_ATTR(energy_empty_design),
- POWER_SUPPLY_ATTR(energy_full),
- POWER_SUPPLY_ATTR(energy_empty),
- POWER_SUPPLY_ATTR(energy_now),
- POWER_SUPPLY_ATTR(energy_avg),
- POWER_SUPPLY_ATTR(capacity),
- POWER_SUPPLY_ATTR(capacity_alert_min),
- POWER_SUPPLY_ATTR(capacity_alert_max),
- POWER_SUPPLY_ATTR(capacity_level),
- POWER_SUPPLY_ATTR(temp),
- POWER_SUPPLY_ATTR(temp_max),
- POWER_SUPPLY_ATTR(temp_min),
- POWER_SUPPLY_ATTR(temp_alert_min),
- POWER_SUPPLY_ATTR(temp_alert_max),
- POWER_SUPPLY_ATTR(temp_ambient),
- POWER_SUPPLY_ATTR(temp_ambient_alert_min),
- POWER_SUPPLY_ATTR(temp_ambient_alert_max),
- POWER_SUPPLY_ATTR(time_to_empty_now),
- POWER_SUPPLY_ATTR(time_to_empty_avg),
- POWER_SUPPLY_ATTR(time_to_full_now),
- POWER_SUPPLY_ATTR(time_to_full_avg),
- POWER_SUPPLY_ATTR(type),
- POWER_SUPPLY_ATTR(usb_type),
- POWER_SUPPLY_ATTR(scope),
- POWER_SUPPLY_ATTR(precharge_current),
- POWER_SUPPLY_ATTR(charge_term_current),
- POWER_SUPPLY_ATTR(calibrate),
- /* Properties of type `const char *' */
- POWER_SUPPLY_ATTR(model_name),
- POWER_SUPPLY_ATTR(manufacturer),
- POWER_SUPPLY_ATTR(serial_number),
-};
-
-static struct attribute *
-__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
-
static umode_t power_supply_attr_is_visible(struct kobject *kobj,
struct attribute *attr,
int attrno)
@@ -322,6 +321,9 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
int i;
+ if (!power_supply_attrs[attrno].prop_name)
+ return 0;
+
if (attrno == POWER_SUPPLY_PROP_TYPE)
return mode;
@@ -350,31 +352,38 @@ static const struct attribute_group *power_supply_attr_groups[] = {
NULL,
};
-void power_supply_init_attrs(struct device_type *dev_type)
+static void str_to_lower(char *str)
{
- int i;
-
- dev_type->groups = power_supply_attr_groups;
-
- for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
- __power_supply_attrs[i] = &power_supply_attrs[i].attr;
+ while (*str) {
+ *str = tolower(*str);
+ str++;
+ }
}
-static char *kstruprdup(const char *str, gfp_t gfp)
+void power_supply_init_attrs(struct device_type *dev_type)
{
- char *ret, *ustr;
+ int i;
- ustr = ret = kmalloc(strlen(str) + 1, gfp);
+ dev_type->groups = power_supply_attr_groups;
- if (!ret)
- return NULL;
+ for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) {
+ struct device_attribute *attr;
- while (*str)
- *ustr++ = toupper(*str++);
+ if (!power_supply_attrs[i].prop_name) {
+ pr_warn("%s: Property %d skipped because is is missing from power_supply_attrs\n",
+ __func__, i);
+ sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
+ } else {
+ str_to_lower(power_supply_attrs[i].attr_name);
+ }
- *ustr = 0;
+ attr = &power_supply_attrs[i].dev_attr;
- return ret;
+ attr->attr.name = power_supply_attrs[i].attr_name;
+ attr->show = power_supply_show_property;
+ attr->store = power_supply_store_property;
+ __power_supply_attrs[i] = &attr->attr;
+ }
}
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -382,7 +391,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
struct power_supply *psy = dev_get_drvdata(dev);
int ret = 0, j;
char *prop_buf;
- char *attrname;
if (!psy || !psy->desc) {
dev_dbg(dev, "No power supply yet\n");
@@ -398,12 +406,14 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
return -ENOMEM;
for (j = 0; j < psy->desc->num_properties; j++) {
- struct device_attribute *attr;
+ struct power_supply_attr *pwr_attr;
+ struct device_attribute *dev_attr;
char *line;
- attr = &power_supply_attrs[psy->desc->properties[j]];
+ pwr_attr = &power_supply_attrs[psy->desc->properties[j]];
+ dev_attr = &pwr_attr->dev_attr;
- ret = power_supply_show_property(dev, attr, prop_buf);
+ ret = power_supply_show_property(dev, dev_attr, prop_buf);
if (ret == -ENODEV || ret == -ENODATA) {
/* When a battery is absent, we expect -ENODEV. Don't abort;
send the uevent with at least the the PRESENT=0 property */
@@ -418,14 +428,8 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
if (line)
*line = 0;
- attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
- if (!attrname) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
- kfree(attrname);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s",
+ pwr_attr->prop_name, prop_buf);
if (ret)
goto out;
}