Skip to content

Commit 2cabeaf

Browse files
MathewKingsre
authored andcommitted
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 <[email protected]> Signed-off-by: Sebastian Reichel <[email protected]>
1 parent 72d9cd9 commit 2cabeaf

File tree

1 file changed

+132
-128
lines changed

1 file changed

+132
-128
lines changed

drivers/power/supply/power_supply_sysfs.c

Lines changed: 132 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,20 @@
1818

1919
#include "power_supply.h"
2020

21-
/*
22-
* This is because the name "current" breaks the device attr macro.
23-
* The "current" word resolves to "(get_current())" so instead of
24-
* "current" "(get_current())" appears in the sysfs.
25-
*
26-
* The source of this definition is the device.h which calls __ATTR
27-
* macro in sysfs.h which calls the __stringify macro.
28-
*
29-
* Only modification that the name is not tried to be resolved
30-
* (as a macro let's say).
31-
*/
21+
#define MAX_PROP_NAME_LEN 30
3222

33-
#define POWER_SUPPLY_ATTR(_name) \
34-
{ \
35-
.attr = { .name = #_name }, \
36-
.show = power_supply_show_property, \
37-
.store = power_supply_store_property, \
38-
}
23+
struct power_supply_attr {
24+
const char *prop_name;
25+
char attr_name[MAX_PROP_NAME_LEN + 1];
26+
struct device_attribute dev_attr;
27+
};
3928

40-
static struct device_attribute power_supply_attrs[];
29+
#define POWER_SUPPLY_ATTR(_name) \
30+
[POWER_SUPPLY_PROP_ ## _name] = \
31+
{ \
32+
.prop_name = #_name, \
33+
.attr_name = #_name "\0", \
34+
}
4135

4236
static const char * const power_supply_type_text[] = {
4337
"Unknown", "Battery", "UPS", "Mains", "USB",
@@ -77,6 +71,91 @@ static const char * const power_supply_scope_text[] = {
7771
"Unknown", "System", "Device"
7872
};
7973

74+
static struct power_supply_attr power_supply_attrs[] = {
75+
/* Properties of type `int' */
76+
POWER_SUPPLY_ATTR(STATUS),
77+
POWER_SUPPLY_ATTR(CHARGE_TYPE),
78+
POWER_SUPPLY_ATTR(HEALTH),
79+
POWER_SUPPLY_ATTR(PRESENT),
80+
POWER_SUPPLY_ATTR(ONLINE),
81+
POWER_SUPPLY_ATTR(AUTHENTIC),
82+
POWER_SUPPLY_ATTR(TECHNOLOGY),
83+
POWER_SUPPLY_ATTR(CYCLE_COUNT),
84+
POWER_SUPPLY_ATTR(VOLTAGE_MAX),
85+
POWER_SUPPLY_ATTR(VOLTAGE_MIN),
86+
POWER_SUPPLY_ATTR(VOLTAGE_MAX_DESIGN),
87+
POWER_SUPPLY_ATTR(VOLTAGE_MIN_DESIGN),
88+
POWER_SUPPLY_ATTR(VOLTAGE_NOW),
89+
POWER_SUPPLY_ATTR(VOLTAGE_AVG),
90+
POWER_SUPPLY_ATTR(VOLTAGE_OCV),
91+
POWER_SUPPLY_ATTR(VOLTAGE_BOOT),
92+
POWER_SUPPLY_ATTR(CURRENT_MAX),
93+
POWER_SUPPLY_ATTR(CURRENT_NOW),
94+
POWER_SUPPLY_ATTR(CURRENT_AVG),
95+
POWER_SUPPLY_ATTR(CURRENT_BOOT),
96+
POWER_SUPPLY_ATTR(POWER_NOW),
97+
POWER_SUPPLY_ATTR(POWER_AVG),
98+
POWER_SUPPLY_ATTR(CHARGE_FULL_DESIGN),
99+
POWER_SUPPLY_ATTR(CHARGE_EMPTY_DESIGN),
100+
POWER_SUPPLY_ATTR(CHARGE_FULL),
101+
POWER_SUPPLY_ATTR(CHARGE_EMPTY),
102+
POWER_SUPPLY_ATTR(CHARGE_NOW),
103+
POWER_SUPPLY_ATTR(CHARGE_AVG),
104+
POWER_SUPPLY_ATTR(CHARGE_COUNTER),
105+
POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT),
106+
POWER_SUPPLY_ATTR(CONSTANT_CHARGE_CURRENT_MAX),
107+
POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE),
108+
POWER_SUPPLY_ATTR(CONSTANT_CHARGE_VOLTAGE_MAX),
109+
POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT),
110+
POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT_MAX),
111+
POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD),
112+
POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD),
113+
POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT),
114+
POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT),
115+
POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT),
116+
POWER_SUPPLY_ATTR(ENERGY_FULL_DESIGN),
117+
POWER_SUPPLY_ATTR(ENERGY_EMPTY_DESIGN),
118+
POWER_SUPPLY_ATTR(ENERGY_FULL),
119+
POWER_SUPPLY_ATTR(ENERGY_EMPTY),
120+
POWER_SUPPLY_ATTR(ENERGY_NOW),
121+
POWER_SUPPLY_ATTR(ENERGY_AVG),
122+
POWER_SUPPLY_ATTR(CAPACITY),
123+
POWER_SUPPLY_ATTR(CAPACITY_ALERT_MIN),
124+
POWER_SUPPLY_ATTR(CAPACITY_ALERT_MAX),
125+
POWER_SUPPLY_ATTR(CAPACITY_LEVEL),
126+
POWER_SUPPLY_ATTR(TEMP),
127+
POWER_SUPPLY_ATTR(TEMP_MAX),
128+
POWER_SUPPLY_ATTR(TEMP_MIN),
129+
POWER_SUPPLY_ATTR(TEMP_ALERT_MIN),
130+
POWER_SUPPLY_ATTR(TEMP_ALERT_MAX),
131+
POWER_SUPPLY_ATTR(TEMP_AMBIENT),
132+
POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MIN),
133+
POWER_SUPPLY_ATTR(TEMP_AMBIENT_ALERT_MAX),
134+
POWER_SUPPLY_ATTR(TIME_TO_EMPTY_NOW),
135+
POWER_SUPPLY_ATTR(TIME_TO_EMPTY_AVG),
136+
POWER_SUPPLY_ATTR(TIME_TO_FULL_NOW),
137+
POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG),
138+
POWER_SUPPLY_ATTR(TYPE),
139+
POWER_SUPPLY_ATTR(USB_TYPE),
140+
POWER_SUPPLY_ATTR(SCOPE),
141+
POWER_SUPPLY_ATTR(PRECHARGE_CURRENT),
142+
POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT),
143+
POWER_SUPPLY_ATTR(CALIBRATE),
144+
/* Properties of type `const char *' */
145+
POWER_SUPPLY_ATTR(MODEL_NAME),
146+
POWER_SUPPLY_ATTR(MANUFACTURER),
147+
POWER_SUPPLY_ATTR(SERIAL_NUMBER),
148+
};
149+
150+
static struct attribute *
151+
__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
152+
153+
static enum power_supply_property dev_attr_psp(struct device_attribute *attr)
154+
{
155+
return container_of(attr, struct power_supply_attr, dev_attr) -
156+
power_supply_attrs;
157+
}
158+
80159
static ssize_t power_supply_show_usb_type(struct device *dev,
81160
const struct power_supply_desc *desc,
82161
union power_supply_propval *value,
@@ -116,7 +195,7 @@ static ssize_t power_supply_show_property(struct device *dev,
116195
char *buf) {
117196
ssize_t ret;
118197
struct power_supply *psy = dev_get_drvdata(dev);
119-
enum power_supply_property psp = attr - power_supply_attrs;
198+
enum power_supply_property psp = dev_attr_psp(attr);
120199
union power_supply_propval value;
121200

122201
if (psp == POWER_SUPPLY_PROP_TYPE) {
@@ -184,7 +263,7 @@ static ssize_t power_supply_store_property(struct device *dev,
184263
const char *buf, size_t count) {
185264
ssize_t ret;
186265
struct power_supply *psy = dev_get_drvdata(dev);
187-
enum power_supply_property psp = attr - power_supply_attrs;
266+
enum power_supply_property psp = dev_attr_psp(attr);
188267
union power_supply_propval value;
189268

190269
switch (psp) {
@@ -233,86 +312,6 @@ static ssize_t power_supply_store_property(struct device *dev,
233312
return count;
234313
}
235314

236-
/* Must be in the same order as POWER_SUPPLY_PROP_* */
237-
static struct device_attribute power_supply_attrs[] = {
238-
/* Properties of type `int' */
239-
POWER_SUPPLY_ATTR(status),
240-
POWER_SUPPLY_ATTR(charge_type),
241-
POWER_SUPPLY_ATTR(health),
242-
POWER_SUPPLY_ATTR(present),
243-
POWER_SUPPLY_ATTR(online),
244-
POWER_SUPPLY_ATTR(authentic),
245-
POWER_SUPPLY_ATTR(technology),
246-
POWER_SUPPLY_ATTR(cycle_count),
247-
POWER_SUPPLY_ATTR(voltage_max),
248-
POWER_SUPPLY_ATTR(voltage_min),
249-
POWER_SUPPLY_ATTR(voltage_max_design),
250-
POWER_SUPPLY_ATTR(voltage_min_design),
251-
POWER_SUPPLY_ATTR(voltage_now),
252-
POWER_SUPPLY_ATTR(voltage_avg),
253-
POWER_SUPPLY_ATTR(voltage_ocv),
254-
POWER_SUPPLY_ATTR(voltage_boot),
255-
POWER_SUPPLY_ATTR(current_max),
256-
POWER_SUPPLY_ATTR(current_now),
257-
POWER_SUPPLY_ATTR(current_avg),
258-
POWER_SUPPLY_ATTR(current_boot),
259-
POWER_SUPPLY_ATTR(power_now),
260-
POWER_SUPPLY_ATTR(power_avg),
261-
POWER_SUPPLY_ATTR(charge_full_design),
262-
POWER_SUPPLY_ATTR(charge_empty_design),
263-
POWER_SUPPLY_ATTR(charge_full),
264-
POWER_SUPPLY_ATTR(charge_empty),
265-
POWER_SUPPLY_ATTR(charge_now),
266-
POWER_SUPPLY_ATTR(charge_avg),
267-
POWER_SUPPLY_ATTR(charge_counter),
268-
POWER_SUPPLY_ATTR(constant_charge_current),
269-
POWER_SUPPLY_ATTR(constant_charge_current_max),
270-
POWER_SUPPLY_ATTR(constant_charge_voltage),
271-
POWER_SUPPLY_ATTR(constant_charge_voltage_max),
272-
POWER_SUPPLY_ATTR(charge_control_limit),
273-
POWER_SUPPLY_ATTR(charge_control_limit_max),
274-
POWER_SUPPLY_ATTR(charge_control_start_threshold),
275-
POWER_SUPPLY_ATTR(charge_control_end_threshold),
276-
POWER_SUPPLY_ATTR(input_current_limit),
277-
POWER_SUPPLY_ATTR(input_voltage_limit),
278-
POWER_SUPPLY_ATTR(input_power_limit),
279-
POWER_SUPPLY_ATTR(energy_full_design),
280-
POWER_SUPPLY_ATTR(energy_empty_design),
281-
POWER_SUPPLY_ATTR(energy_full),
282-
POWER_SUPPLY_ATTR(energy_empty),
283-
POWER_SUPPLY_ATTR(energy_now),
284-
POWER_SUPPLY_ATTR(energy_avg),
285-
POWER_SUPPLY_ATTR(capacity),
286-
POWER_SUPPLY_ATTR(capacity_alert_min),
287-
POWER_SUPPLY_ATTR(capacity_alert_max),
288-
POWER_SUPPLY_ATTR(capacity_level),
289-
POWER_SUPPLY_ATTR(temp),
290-
POWER_SUPPLY_ATTR(temp_max),
291-
POWER_SUPPLY_ATTR(temp_min),
292-
POWER_SUPPLY_ATTR(temp_alert_min),
293-
POWER_SUPPLY_ATTR(temp_alert_max),
294-
POWER_SUPPLY_ATTR(temp_ambient),
295-
POWER_SUPPLY_ATTR(temp_ambient_alert_min),
296-
POWER_SUPPLY_ATTR(temp_ambient_alert_max),
297-
POWER_SUPPLY_ATTR(time_to_empty_now),
298-
POWER_SUPPLY_ATTR(time_to_empty_avg),
299-
POWER_SUPPLY_ATTR(time_to_full_now),
300-
POWER_SUPPLY_ATTR(time_to_full_avg),
301-
POWER_SUPPLY_ATTR(type),
302-
POWER_SUPPLY_ATTR(usb_type),
303-
POWER_SUPPLY_ATTR(scope),
304-
POWER_SUPPLY_ATTR(precharge_current),
305-
POWER_SUPPLY_ATTR(charge_term_current),
306-
POWER_SUPPLY_ATTR(calibrate),
307-
/* Properties of type `const char *' */
308-
POWER_SUPPLY_ATTR(model_name),
309-
POWER_SUPPLY_ATTR(manufacturer),
310-
POWER_SUPPLY_ATTR(serial_number),
311-
};
312-
313-
static struct attribute *
314-
__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
315-
316315
static umode_t power_supply_attr_is_visible(struct kobject *kobj,
317316
struct attribute *attr,
318317
int attrno)
@@ -322,6 +321,9 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
322321
umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
323322
int i;
324323

324+
if (!power_supply_attrs[attrno].prop_name)
325+
return 0;
326+
325327
if (attrno == POWER_SUPPLY_PROP_TYPE)
326328
return mode;
327329

@@ -350,39 +352,45 @@ static const struct attribute_group *power_supply_attr_groups[] = {
350352
NULL,
351353
};
352354

353-
void power_supply_init_attrs(struct device_type *dev_type)
355+
static void str_to_lower(char *str)
354356
{
355-
int i;
356-
357-
dev_type->groups = power_supply_attr_groups;
358-
359-
for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
360-
__power_supply_attrs[i] = &power_supply_attrs[i].attr;
357+
while (*str) {
358+
*str = tolower(*str);
359+
str++;
360+
}
361361
}
362362

363-
static char *kstruprdup(const char *str, gfp_t gfp)
363+
void power_supply_init_attrs(struct device_type *dev_type)
364364
{
365-
char *ret, *ustr;
365+
int i;
366366

367-
ustr = ret = kmalloc(strlen(str) + 1, gfp);
367+
dev_type->groups = power_supply_attr_groups;
368368

369-
if (!ret)
370-
return NULL;
369+
for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) {
370+
struct device_attribute *attr;
371371

372-
while (*str)
373-
*ustr++ = toupper(*str++);
372+
if (!power_supply_attrs[i].prop_name) {
373+
pr_warn("%s: Property %d skipped because is is missing from power_supply_attrs\n",
374+
__func__, i);
375+
sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
376+
} else {
377+
str_to_lower(power_supply_attrs[i].attr_name);
378+
}
374379

375-
*ustr = 0;
380+
attr = &power_supply_attrs[i].dev_attr;
376381

377-
return ret;
382+
attr->attr.name = power_supply_attrs[i].attr_name;
383+
attr->show = power_supply_show_property;
384+
attr->store = power_supply_store_property;
385+
__power_supply_attrs[i] = &attr->attr;
386+
}
378387
}
379388

380389
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
381390
{
382391
struct power_supply *psy = dev_get_drvdata(dev);
383392
int ret = 0, j;
384393
char *prop_buf;
385-
char *attrname;
386394

387395
if (!psy || !psy->desc) {
388396
dev_dbg(dev, "No power supply yet\n");
@@ -398,12 +406,14 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
398406
return -ENOMEM;
399407

400408
for (j = 0; j < psy->desc->num_properties; j++) {
401-
struct device_attribute *attr;
409+
struct power_supply_attr *pwr_attr;
410+
struct device_attribute *dev_attr;
402411
char *line;
403412

404-
attr = &power_supply_attrs[psy->desc->properties[j]];
413+
pwr_attr = &power_supply_attrs[psy->desc->properties[j]];
414+
dev_attr = &pwr_attr->dev_attr;
405415

406-
ret = power_supply_show_property(dev, attr, prop_buf);
416+
ret = power_supply_show_property(dev, dev_attr, prop_buf);
407417
if (ret == -ENODEV || ret == -ENODATA) {
408418
/* When a battery is absent, we expect -ENODEV. Don't abort;
409419
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)
418428
if (line)
419429
*line = 0;
420430

421-
attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
422-
if (!attrname) {
423-
ret = -ENOMEM;
424-
goto out;
425-
}
426-
427-
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
428-
kfree(attrname);
431+
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s",
432+
pwr_attr->prop_name, prop_buf);
429433
if (ret)
430434
goto out;
431435
}

0 commit comments

Comments
 (0)