Blame view

drivers/power/power_supply_sysfs.c 9.1 KB
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   *  Sysfs interface for the universal power supply monitor class
   *
   *  Copyright © 2007  David Woodhouse <dwmw2@infradead.org>
   *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
   *  Copyright © 2004  Szabolcs Gyurko
   *  Copyright © 2003  Ian Molton <spyro@f2s.com>
   *
   *  Modified: 2004, Oct     Szabolcs Gyurko
   *
   *  You may use this code as per GPL version 2
   */
  
  #include <linux/ctype.h>
51990e825   Paul Gortmaker   device.h: cleanup...
15
  #include <linux/device.h>
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
16
  #include <linux/power_supply.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
778f523dd   Paul Gortmaker   drivers: power_su...
18
  #include <linux/stat.h>
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
19

25f12141e   Adrian Bunk   [BATTERY] Every f...
20
  #include "power_supply.h"
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /*
   * 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 POWER_SUPPLY_ATTR(_name)					\
  {									\
5f487cd34   Anton Vorontsov   power_supply: Use...
35
  	.attr = { .name = #_name },					\
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
36
  	.show = power_supply_show_property,				\
0011d2d4a   Daniel Mack   power_supply: Add...
37
  	.store = power_supply_store_property,				\
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
38
39
40
41
42
43
44
  }
  
  static struct device_attribute power_supply_attrs[];
  
  static ssize_t power_supply_show_property(struct device *dev,
  					  struct device_attribute *attr,
  					  char *buf) {
5f487cd34   Anton Vorontsov   power_supply: Use...
45
  	static char *type_text[] = {
9b8872273   Kim, Milo   power_supply: Add...
46
  		"Unknown", "Battery", "UPS", "Mains", "USB",
6659b55da   Benson Leung   power_supply: Add...
47
48
  		"USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
  		"USB_PD", "USB_PD_DRP"
5f487cd34   Anton Vorontsov   power_supply: Use...
49
  	};
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
50
51
52
  	static char *status_text[] = {
  		"Unknown", "Charging", "Discharging", "Not charging", "Full"
  	};
ee8076ed3   Andres Salomon   power_supply: Add...
53
54
55
  	static char *charge_type[] = {
  		"Unknown", "N/A", "Trickle", "Fast"
  	};
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
56
57
  	static char *health_text[] = {
  		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
a05be9917   Ramakrishna Pallala   power_supply: Add...
58
59
  		"Unspecified failure", "Cold", "Watchdog timer expire",
  		"Safety timer expire"
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
60
61
  	};
  	static char *technology_text[] = {
c7cc930f9   Dmitry Eremin-Solenikov   power_supply: add...
62
63
  		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
  		"LiMn"
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
64
  	};
b294a290d   Andres Salomon   Revert "power: re...
65
66
67
  	static char *capacity_level_text[] = {
  		"Unknown", "Critical", "Low", "Normal", "High", "Full"
  	};
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
68
69
70
  	static char *scope_text[] = {
  		"Unknown", "System", "Device"
  	};
5f487cd34   Anton Vorontsov   power_supply: Use...
71
  	ssize_t ret = 0;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
72
73
74
  	struct power_supply *psy = dev_get_drvdata(dev);
  	const ptrdiff_t off = attr - power_supply_attrs;
  	union power_supply_propval value;
73b4a087b   Viresh Kumar   power-supply: Che...
75
  	if (off == POWER_SUPPLY_PROP_TYPE) {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
76
  		value.intval = psy->desc->type;
73b4a087b   Viresh Kumar   power-supply: Che...
77
  	} else {
ee8f334a9   Krzysztof Kozlowski   power_supply: sys...
78
  		ret = power_supply_get_property(psy, off, &value);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
79

73b4a087b   Viresh Kumar   power-supply: Che...
80
81
82
83
84
  		if (ret < 0) {
  			if (ret == -ENODATA)
  				dev_dbg(dev, "driver has no data for `%s' property
  ",
  					attr->attr.name);
e38053852   Rhyland Klein   power_supply: fix...
85
  			else if (ret != -ENODEV && ret != -EAGAIN)
73b4a087b   Viresh Kumar   power-supply: Che...
86
87
88
89
90
  				dev_err(dev, "driver failed to report `%s' property: %zd
  ",
  					attr->attr.name, ret);
  			return ret;
  		}
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
91
92
93
94
95
  	}
  
  	if (off == POWER_SUPPLY_PROP_STATUS)
  		return sprintf(buf, "%s
  ", status_text[value.intval]);
ee8076ed3   Andres Salomon   power_supply: Add...
96
97
98
  	else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
  		return sprintf(buf, "%s
  ", charge_type[value.intval]);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
99
100
101
102
103
104
  	else if (off == POWER_SUPPLY_PROP_HEALTH)
  		return sprintf(buf, "%s
  ", health_text[value.intval]);
  	else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
  		return sprintf(buf, "%s
  ", technology_text[value.intval]);
b294a290d   Andres Salomon   Revert "power: re...
105
106
107
  	else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
  		return sprintf(buf, "%s
  ", capacity_level_text[value.intval]);
5f487cd34   Anton Vorontsov   power_supply: Use...
108
109
110
  	else if (off == POWER_SUPPLY_PROP_TYPE)
  		return sprintf(buf, "%s
  ", type_text[value.intval]);
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
111
112
113
  	else if (off == POWER_SUPPLY_PROP_SCOPE)
  		return sprintf(buf, "%s
  ", scope_text[value.intval]);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
114
115
116
117
118
119
120
  	else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
  		return sprintf(buf, "%s
  ", value.strval);
  
  	return sprintf(buf, "%d
  ", value.intval);
  }
0011d2d4a   Daniel Mack   power_supply: Add...
121
122
123
124
125
126
127
128
129
130
  static ssize_t power_supply_store_property(struct device *dev,
  					   struct device_attribute *attr,
  					   const char *buf, size_t count) {
  	ssize_t ret;
  	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 */
f107ae11f   Jingoo Han   power_supply: Rep...
131
  	ret = kstrtol(buf, 10, &long_val);
0011d2d4a   Daniel Mack   power_supply: Add...
132
133
134
135
  	if (ret < 0)
  		return ret;
  
  	value.intval = long_val;
a9f6a19b5   Krzysztof Kozlowski   power_supply: Use...
136
  	ret = power_supply_set_property(psy, off, &value);
0011d2d4a   Daniel Mack   power_supply: Add...
137
138
139
140
141
  	if (ret < 0)
  		return ret;
  
  	return count;
  }
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
142
143
144
145
  /* 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),
ee8076ed3   Andres Salomon   power_supply: Add...
146
  	POWER_SUPPLY_ATTR(charge_type),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
147
148
149
  	POWER_SUPPLY_ATTR(health),
  	POWER_SUPPLY_ATTR(present),
  	POWER_SUPPLY_ATTR(online),
b1b56872b   Ramakrishna Pallala   power_supply: Add...
150
  	POWER_SUPPLY_ATTR(authentic),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
151
  	POWER_SUPPLY_ATTR(technology),
c955fe8e0   Alexey Starikovskiy   POWER: Add suppor...
152
  	POWER_SUPPLY_ATTR(cycle_count),
c7cc930f9   Dmitry Eremin-Solenikov   power_supply: add...
153
154
  	POWER_SUPPLY_ATTR(voltage_max),
  	POWER_SUPPLY_ATTR(voltage_min),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
155
156
157
158
  	POWER_SUPPLY_ATTR(voltage_max_design),
  	POWER_SUPPLY_ATTR(voltage_min_design),
  	POWER_SUPPLY_ATTR(voltage_now),
  	POWER_SUPPLY_ATTR(voltage_avg),
a2ebfe2fc   Ramakrishna Pallala   power_supply: Add...
159
  	POWER_SUPPLY_ATTR(voltage_ocv),
a8adcc901   Ramakrishna Pallala   power_supply: Add...
160
  	POWER_SUPPLY_ATTR(voltage_boot),
fe3f6d097   Heikki Krogerus   power_supply: Int...
161
  	POWER_SUPPLY_ATTR(current_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
162
163
  	POWER_SUPPLY_ATTR(current_now),
  	POWER_SUPPLY_ATTR(current_avg),
a8adcc901   Ramakrishna Pallala   power_supply: Add...
164
  	POWER_SUPPLY_ATTR(current_boot),
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
165
166
  	POWER_SUPPLY_ATTR(power_now),
  	POWER_SUPPLY_ATTR(power_avg),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
167
168
169
170
171
172
  	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),
8e552c36d   Andres Salomon   power_supply: add...
173
  	POWER_SUPPLY_ATTR(charge_counter),
3824c4771   Ramakrishna Pallala   power_supply: Add...
174
  	POWER_SUPPLY_ATTR(constant_charge_current),
2815b786c   Ramakrishna Pallala   power_supply: Add...
175
  	POWER_SUPPLY_ATTR(constant_charge_current_max),
3824c4771   Ramakrishna Pallala   power_supply: Add...
176
  	POWER_SUPPLY_ATTR(constant_charge_voltage),
2815b786c   Ramakrishna Pallala   power_supply: Add...
177
  	POWER_SUPPLY_ATTR(constant_charge_voltage_max),
ea2ce92e4   Ramakrishna Pallala   power_supply: Add...
178
179
  	POWER_SUPPLY_ATTR(charge_control_limit),
  	POWER_SUPPLY_ATTR(charge_control_limit_max),
6bb1d272d   Jenny TC   power_supply: Add...
180
  	POWER_SUPPLY_ATTR(input_current_limit),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
181
182
183
184
185
186
187
  	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),
e908c4180   Ramakrishna Pallala   power_supply: Add...
188
189
  	POWER_SUPPLY_ATTR(capacity_alert_min),
  	POWER_SUPPLY_ATTR(capacity_alert_max),
b294a290d   Andres Salomon   Revert "power: re...
190
  	POWER_SUPPLY_ATTR(capacity_level),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
191
  	POWER_SUPPLY_ATTR(temp),
6bb1d272d   Jenny TC   power_supply: Add...
192
193
  	POWER_SUPPLY_ATTR(temp_max),
  	POWER_SUPPLY_ATTR(temp_min),
e908c4180   Ramakrishna Pallala   power_supply: Add...
194
195
  	POWER_SUPPLY_ATTR(temp_alert_min),
  	POWER_SUPPLY_ATTR(temp_alert_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
196
  	POWER_SUPPLY_ATTR(temp_ambient),
e908c4180   Ramakrishna Pallala   power_supply: Add...
197
198
  	POWER_SUPPLY_ATTR(temp_ambient_alert_min),
  	POWER_SUPPLY_ATTR(temp_ambient_alert_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
199
200
201
202
  	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),
5f487cd34   Anton Vorontsov   power_supply: Use...
203
  	POWER_SUPPLY_ATTR(type),
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
204
  	POWER_SUPPLY_ATTR(scope),
6bb1d272d   Jenny TC   power_supply: Add...
205
  	POWER_SUPPLY_ATTR(charge_term_current),
a8adcc901   Ramakrishna Pallala   power_supply: Add...
206
  	POWER_SUPPLY_ATTR(calibrate),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
207
208
209
  	/* Properties of type `const char *' */
  	POWER_SUPPLY_ATTR(model_name),
  	POWER_SUPPLY_ATTR(manufacturer),
7c2670bbb   maximilian attems   ACPI: battery: ad...
210
  	POWER_SUPPLY_ATTR(serial_number),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
211
  };
5f487cd34   Anton Vorontsov   power_supply: Use...
212
213
  static struct attribute *
  __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
214

587a1f165   Al Viro   switch ->is_visib...
215
  static umode_t power_supply_attr_is_visible(struct kobject *kobj,
5f487cd34   Anton Vorontsov   power_supply: Use...
216
217
  					   struct attribute *attr,
  					   int attrno)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
218
  {
5f487cd34   Anton Vorontsov   power_supply: Use...
219
220
  	struct device *dev = container_of(kobj, struct device, kobj);
  	struct power_supply *psy = dev_get_drvdata(dev);
587a1f165   Al Viro   switch ->is_visib...
221
  	umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
5f487cd34   Anton Vorontsov   power_supply: Use...
222
  	int i;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
223

bbabb158f   Daniel Mack   power_supply: Fix...
224
225
  	if (attrno == POWER_SUPPLY_PROP_TYPE)
  		return mode;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
226
227
  	for (i = 0; i < psy->desc->num_properties; i++) {
  		int property = psy->desc->properties[i];
0011d2d4a   Daniel Mack   power_supply: Add...
228
229
  
  		if (property == attrno) {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
230
  			if (psy->desc->property_is_writeable &&
5c6e3a97e   Krzysztof Kozlowski   power_supply: sys...
231
  			    psy->desc->property_is_writeable(psy, property) > 0)
0011d2d4a   Daniel Mack   power_supply: Add...
232
233
234
235
  				mode |= S_IWUSR;
  
  			return mode;
  		}
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
236
  	}
5f487cd34   Anton Vorontsov   power_supply: Use...
237
  	return 0;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
238
  }
5f487cd34   Anton Vorontsov   power_supply: Use...
239
240
241
242
243
244
245
246
247
248
249
  static struct attribute_group power_supply_attr_group = {
  	.attrs = __power_supply_attrs,
  	.is_visible = power_supply_attr_is_visible,
  };
  
  static const struct attribute_group *power_supply_attr_groups[] = {
  	&power_supply_attr_group,
  	NULL,
  };
  
  void power_supply_init_attrs(struct device_type *dev_type)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
250
251
  {
  	int i;
5f487cd34   Anton Vorontsov   power_supply: Use...
252
  	dev_type->groups = power_supply_attr_groups;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
253

5f487cd34   Anton Vorontsov   power_supply: Use...
254
255
  	for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
  		__power_supply_attrs[i] = &power_supply_attrs[i].attr;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  }
  
  static char *kstruprdup(const char *str, gfp_t gfp)
  {
  	char *ret, *ustr;
  
  	ustr = ret = kmalloc(strlen(str) + 1, gfp);
  
  	if (!ret)
  		return NULL;
  
  	while (*str)
  		*ustr++ = toupper(*str++);
  
  	*ustr = 0;
  
  	return ret;
  }
7eff2e7a8   Kay Sievers   Driver core: chan...
274
  int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
275
276
  {
  	struct power_supply *psy = dev_get_drvdata(dev);
7eff2e7a8   Kay Sievers   Driver core: chan...
277
  	int ret = 0, j;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
278
279
280
281
282
  	char *prop_buf;
  	char *attrname;
  
  	dev_dbg(dev, "uevent
  ");
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
283
  	if (!psy || !psy->desc) {
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
284
285
286
287
  		dev_dbg(dev, "No power supply yet
  ");
  		return ret;
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
288
289
  	dev_dbg(dev, "POWER_SUPPLY_NAME=%s
  ", psy->desc->name);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
290

297d716f6   Krzysztof Kozlowski   power_supply: Cha...
291
  	ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
292
293
294
295
296
297
  	if (ret)
  		return ret;
  
  	prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
  	if (!prop_buf)
  		return -ENOMEM;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
298
  	for (j = 0; j < psy->desc->num_properties; j++) {
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
299
300
  		struct device_attribute *attr;
  		char *line;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
301
  		attr = &power_supply_attrs[psy->desc->properties[j]];
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
302
303
  
  		ret = power_supply_show_property(dev, attr, prop_buf);
f722e17fd   Lars-Peter Clausen   power_supply: Ign...
304
  		if (ret == -ENODEV || ret == -ENODATA) {
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  			/* When a battery is absent, we expect -ENODEV. Don't abort;
  			   send the uevent with at least the the PRESENT=0 property */
  			ret = 0;
  			continue;
  		}
  
  		if (ret < 0)
  			goto out;
  
  		line = strchr(prop_buf, '
  ');
  		if (line)
  			*line = 0;
  
  		attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
  		if (!attrname) {
  			ret = -ENOMEM;
  			goto out;
  		}
  
  		dev_dbg(dev, "prop %s=%s
  ", attrname, prop_buf);
7eff2e7a8   Kay Sievers   Driver core: chan...
327
  		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
328
329
330
331
332
333
334
335
336
337
  		kfree(attrname);
  		if (ret)
  			goto out;
  	}
  
  out:
  	free_page((unsigned long)prop_buf);
  
  	return ret;
  }