Blame view

drivers/power/power_supply_sysfs.c 8.73 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",
85efc8a18   Heikki Krogerus   power_supply: Add...
47
  		"USB_DCP", "USB_CDP", "USB_ACA"
5f487cd34   Anton Vorontsov   power_supply: Use...
48
  	};
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
49
50
51
  	static char *status_text[] = {
  		"Unknown", "Charging", "Discharging", "Not charging", "Full"
  	};
ee8076ed3   Andres Salomon   power_supply: Add...
52
53
54
  	static char *charge_type[] = {
  		"Unknown", "N/A", "Trickle", "Fast"
  	};
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
55
56
  	static char *health_text[] = {
  		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
a05be9917   Ramakrishna Pallala   power_supply: Add...
57
58
  		"Unspecified failure", "Cold", "Watchdog timer expire",
  		"Safety timer expire"
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
59
60
  	};
  	static char *technology_text[] = {
c7cc930f9   Dmitry Eremin-Solenikov   power_supply: add...
61
62
  		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
  		"LiMn"
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
63
  	};
b294a290d   Andres Salomon   Revert "power: re...
64
65
66
  	static char *capacity_level_text[] = {
  		"Unknown", "Critical", "Low", "Normal", "High", "Full"
  	};
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
67
68
69
  	static char *scope_text[] = {
  		"Unknown", "System", "Device"
  	};
5f487cd34   Anton Vorontsov   power_supply: Use...
70
  	ssize_t ret = 0;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
71
72
73
  	struct power_supply *psy = dev_get_drvdata(dev);
  	const ptrdiff_t off = attr - power_supply_attrs;
  	union power_supply_propval value;
5f487cd34   Anton Vorontsov   power_supply: Use...
74
75
76
77
  	if (off == POWER_SUPPLY_PROP_TYPE)
  		value.intval = psy->type;
  	else
  		ret = psy->get_property(psy, off, &value);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
78
79
  
  	if (ret < 0) {
9d233e8bb   Anton Vorontsov   power_supply_sysf...
80
81
82
83
84
  		if (ret == -ENODATA)
  			dev_dbg(dev, "driver has no data for `%s' property
  ",
  				attr->attr.name);
  		else if (ret != -ENODEV)
85b5fbf78   Randy Dunlap   power_supply: Fix...
85
86
  			dev_err(dev, "driver failed to report `%s' property: %zd
  ",
35c3ae5ee   Mark Brown   wm831x_power: Onl...
87
  				attr->attr.name, ret);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
88
89
90
91
92
93
  		return ret;
  	}
  
  	if (off == POWER_SUPPLY_PROP_STATUS)
  		return sprintf(buf, "%s
  ", status_text[value.intval]);
ee8076ed3   Andres Salomon   power_supply: Add...
94
95
96
  	else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
  		return sprintf(buf, "%s
  ", charge_type[value.intval]);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
97
98
99
100
101
102
  	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...
103
104
105
  	else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
  		return sprintf(buf, "%s
  ", capacity_level_text[value.intval]);
5f487cd34   Anton Vorontsov   power_supply: Use...
106
107
108
  	else if (off == POWER_SUPPLY_PROP_TYPE)
  		return sprintf(buf, "%s
  ", type_text[value.intval]);
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
109
110
111
  	else if (off == POWER_SUPPLY_PROP_SCOPE)
  		return sprintf(buf, "%s
  ", scope_text[value.intval]);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
112
113
114
115
116
117
118
  	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...
119
120
121
122
123
124
125
126
127
128
  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...
129
  	ret = kstrtol(buf, 10, &long_val);
0011d2d4a   Daniel Mack   power_supply: Add...
130
131
132
133
134
135
136
137
138
139
140
  	if (ret < 0)
  		return ret;
  
  	value.intval = long_val;
  
  	ret = psy->set_property(psy, off, &value);
  	if (ret < 0)
  		return ret;
  
  	return count;
  }
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
141
142
143
144
  /* 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...
145
  	POWER_SUPPLY_ATTR(charge_type),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
146
147
148
  	POWER_SUPPLY_ATTR(health),
  	POWER_SUPPLY_ATTR(present),
  	POWER_SUPPLY_ATTR(online),
b1b56872b   Ramakrishna Pallala   power_supply: Add...
149
  	POWER_SUPPLY_ATTR(authentic),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
150
  	POWER_SUPPLY_ATTR(technology),
c955fe8e0   Alexey Starikovskiy   POWER: Add suppor...
151
  	POWER_SUPPLY_ATTR(cycle_count),
c7cc930f9   Dmitry Eremin-Solenikov   power_supply: add...
152
153
  	POWER_SUPPLY_ATTR(voltage_max),
  	POWER_SUPPLY_ATTR(voltage_min),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
154
155
156
157
  	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...
158
  	POWER_SUPPLY_ATTR(voltage_ocv),
fe3f6d097   Heikki Krogerus   power_supply: Int...
159
  	POWER_SUPPLY_ATTR(current_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
160
161
  	POWER_SUPPLY_ATTR(current_now),
  	POWER_SUPPLY_ATTR(current_avg),
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
162
163
  	POWER_SUPPLY_ATTR(power_now),
  	POWER_SUPPLY_ATTR(power_avg),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
164
165
166
167
168
169
  	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...
170
  	POWER_SUPPLY_ATTR(charge_counter),
3824c4771   Ramakrishna Pallala   power_supply: Add...
171
  	POWER_SUPPLY_ATTR(constant_charge_current),
2815b786c   Ramakrishna Pallala   power_supply: Add...
172
  	POWER_SUPPLY_ATTR(constant_charge_current_max),
3824c4771   Ramakrishna Pallala   power_supply: Add...
173
  	POWER_SUPPLY_ATTR(constant_charge_voltage),
2815b786c   Ramakrishna Pallala   power_supply: Add...
174
  	POWER_SUPPLY_ATTR(constant_charge_voltage_max),
ea2ce92e4   Ramakrishna Pallala   power_supply: Add...
175
176
  	POWER_SUPPLY_ATTR(charge_control_limit),
  	POWER_SUPPLY_ATTR(charge_control_limit_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
177
178
179
180
181
182
183
  	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...
184
185
  	POWER_SUPPLY_ATTR(capacity_alert_min),
  	POWER_SUPPLY_ATTR(capacity_alert_max),
b294a290d   Andres Salomon   Revert "power: re...
186
  	POWER_SUPPLY_ATTR(capacity_level),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
187
  	POWER_SUPPLY_ATTR(temp),
e908c4180   Ramakrishna Pallala   power_supply: Add...
188
189
  	POWER_SUPPLY_ATTR(temp_alert_min),
  	POWER_SUPPLY_ATTR(temp_alert_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
190
  	POWER_SUPPLY_ATTR(temp_ambient),
e908c4180   Ramakrishna Pallala   power_supply: Add...
191
192
  	POWER_SUPPLY_ATTR(temp_ambient_alert_min),
  	POWER_SUPPLY_ATTR(temp_ambient_alert_max),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
193
194
195
196
  	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...
197
  	POWER_SUPPLY_ATTR(type),
25a0bc2df   Jeremy Fitzhardinge   power_supply: add...
198
  	POWER_SUPPLY_ATTR(scope),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
199
200
201
  	/* Properties of type `const char *' */
  	POWER_SUPPLY_ATTR(model_name),
  	POWER_SUPPLY_ATTR(manufacturer),
7c2670bbb   maximilian attems   ACPI: battery: ad...
202
  	POWER_SUPPLY_ATTR(serial_number),
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
203
  };
5f487cd34   Anton Vorontsov   power_supply: Use...
204
205
  static struct attribute *
  __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
206

587a1f165   Al Viro   switch ->is_visib...
207
  static umode_t power_supply_attr_is_visible(struct kobject *kobj,
5f487cd34   Anton Vorontsov   power_supply: Use...
208
209
  					   struct attribute *attr,
  					   int attrno)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
210
  {
5f487cd34   Anton Vorontsov   power_supply: Use...
211
212
  	struct device *dev = container_of(kobj, struct device, kobj);
  	struct power_supply *psy = dev_get_drvdata(dev);
587a1f165   Al Viro   switch ->is_visib...
213
  	umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
5f487cd34   Anton Vorontsov   power_supply: Use...
214
  	int i;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
215

bbabb158f   Daniel Mack   power_supply: Fix...
216
217
  	if (attrno == POWER_SUPPLY_PROP_TYPE)
  		return mode;
5f487cd34   Anton Vorontsov   power_supply: Use...
218
  	for (i = 0; i < psy->num_properties; i++) {
0011d2d4a   Daniel Mack   power_supply: Add...
219
220
221
  		int property = psy->properties[i];
  
  		if (property == attrno) {
0011d2d4a   Daniel Mack   power_supply: Add...
222
223
224
225
226
227
  			if (psy->property_is_writeable &&
  			    psy->property_is_writeable(psy, property) > 0)
  				mode |= S_IWUSR;
  
  			return mode;
  		}
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
228
  	}
5f487cd34   Anton Vorontsov   power_supply: Use...
229
  	return 0;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
230
  }
5f487cd34   Anton Vorontsov   power_supply: Use...
231
232
233
234
235
236
237
238
239
240
241
  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...
242
243
  {
  	int i;
5f487cd34   Anton Vorontsov   power_supply: Use...
244
  	dev_type->groups = power_supply_attr_groups;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
245

5f487cd34   Anton Vorontsov   power_supply: Use...
246
247
  	for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
  		__power_supply_attrs[i] = &power_supply_attrs[i].attr;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  }
  
  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...
266
  int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
267
268
  {
  	struct power_supply *psy = dev_get_drvdata(dev);
7eff2e7a8   Kay Sievers   Driver core: chan...
269
  	int ret = 0, j;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
270
271
272
273
274
  	char *prop_buf;
  	char *attrname;
  
  	dev_dbg(dev, "uevent
  ");
56fa18e8f   Dmitry Eremin-Solenikov   power_supply: Fix...
275
  	if (!psy || !psy->dev) {
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
276
277
278
279
280
281
282
  		dev_dbg(dev, "No power supply yet
  ");
  		return ret;
  	}
  
  	dev_dbg(dev, "POWER_SUPPLY_NAME=%s
  ", psy->name);
7eff2e7a8   Kay Sievers   Driver core: chan...
283
  	ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
284
285
286
287
288
289
  	if (ret)
  		return ret;
  
  	prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
  	if (!prop_buf)
  		return -ENOMEM;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
290
291
292
293
294
295
296
  	for (j = 0; j < psy->num_properties; j++) {
  		struct device_attribute *attr;
  		char *line;
  
  		attr = &power_supply_attrs[psy->properties[j]];
  
  		ret = power_supply_show_property(dev, attr, prop_buf);
f722e17fd   Lars-Peter Clausen   power_supply: Ign...
297
  		if (ret == -ENODEV || ret == -ENODATA) {
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  			/* 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...
320
  		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
321
322
323
324
325
326
327
328
329
330
  		kfree(attrname);
  		if (ret)
  			goto out;
  	}
  
  out:
  	free_page((unsigned long)prop_buf);
  
  	return ret;
  }