Blame view
drivers/power/power_supply_sysfs.c
7.86 KB
4a11b59d8 [BATTERY] Univers... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * 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> #include <linux/power_supply.h> |
5a0e3ad6a include cleanup: ... |
16 |
#include <linux/slab.h> |
4a11b59d8 [BATTERY] Univers... |
17 |
|
25f12141e [BATTERY] Every f... |
18 |
#include "power_supply.h" |
4a11b59d8 [BATTERY] Univers... |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * 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 power_supply: Use... |
33 |
.attr = { .name = #_name }, \ |
4a11b59d8 [BATTERY] Univers... |
34 |
.show = power_supply_show_property, \ |
0011d2d4a power_supply: Add... |
35 |
.store = power_supply_store_property, \ |
4a11b59d8 [BATTERY] Univers... |
36 37 38 39 40 41 42 |
} static struct device_attribute power_supply_attrs[]; static ssize_t power_supply_show_property(struct device *dev, struct device_attribute *attr, char *buf) { |
5f487cd34 power_supply: Use... |
43 |
static char *type_text[] = { |
85efc8a18 power_supply: Add... |
44 45 |
"Battery", "UPS", "Mains", "USB", "USB_DCP", "USB_CDP", "USB_ACA" |
5f487cd34 power_supply: Use... |
46 |
}; |
4a11b59d8 [BATTERY] Univers... |
47 48 49 |
static char *status_text[] = { "Unknown", "Charging", "Discharging", "Not charging", "Full" }; |
ee8076ed3 power_supply: Add... |
50 51 52 |
static char *charge_type[] = { "Unknown", "N/A", "Trickle", "Fast" }; |
4a11b59d8 [BATTERY] Univers... |
53 54 |
static char *health_text[] = { "Unknown", "Good", "Overheat", "Dead", "Over voltage", |
7e386e6e0 power_supply: Add... |
55 |
"Unspecified failure", "Cold", |
4a11b59d8 [BATTERY] Univers... |
56 57 |
}; static char *technology_text[] = { |
c7cc930f9 power_supply: add... |
58 59 |
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd", "LiMn" |
4a11b59d8 [BATTERY] Univers... |
60 |
}; |
b294a290d Revert "power: re... |
61 62 63 |
static char *capacity_level_text[] = { "Unknown", "Critical", "Low", "Normal", "High", "Full" }; |
5f487cd34 power_supply: Use... |
64 |
ssize_t ret = 0; |
4a11b59d8 [BATTERY] Univers... |
65 66 67 |
struct power_supply *psy = dev_get_drvdata(dev); const ptrdiff_t off = attr - power_supply_attrs; union power_supply_propval value; |
5f487cd34 power_supply: Use... |
68 69 70 71 |
if (off == POWER_SUPPLY_PROP_TYPE) value.intval = psy->type; else ret = psy->get_property(psy, off, &value); |
4a11b59d8 [BATTERY] Univers... |
72 73 |
if (ret < 0) { |
9d233e8bb power_supply_sysf... |
74 75 76 77 78 |
if (ret == -ENODATA) dev_dbg(dev, "driver has no data for `%s' property ", attr->attr.name); else if (ret != -ENODEV) |
4a11b59d8 [BATTERY] Univers... |
79 80 81 82 83 84 85 86 87 |
dev_err(dev, "driver failed to report `%s' property ", attr->attr.name); return ret; } if (off == POWER_SUPPLY_PROP_STATUS) return sprintf(buf, "%s ", status_text[value.intval]); |
ee8076ed3 power_supply: Add... |
88 89 90 |
else if (off == POWER_SUPPLY_PROP_CHARGE_TYPE) return sprintf(buf, "%s ", charge_type[value.intval]); |
4a11b59d8 [BATTERY] Univers... |
91 92 93 94 95 96 |
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 Revert "power: re... |
97 98 99 |
else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) return sprintf(buf, "%s ", capacity_level_text[value.intval]); |
5f487cd34 power_supply: Use... |
100 101 102 |
else if (off == POWER_SUPPLY_PROP_TYPE) return sprintf(buf, "%s ", type_text[value.intval]); |
4a11b59d8 [BATTERY] Univers... |
103 104 105 106 107 108 109 |
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) return sprintf(buf, "%s ", value.strval); return sprintf(buf, "%d ", value.intval); } |
0011d2d4a power_supply: Add... |
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
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 */ ret = strict_strtol(buf, 10, &long_val); if (ret < 0) return ret; value.intval = long_val; ret = psy->set_property(psy, off, &value); if (ret < 0) return ret; return count; } |
4a11b59d8 [BATTERY] Univers... |
132 133 134 135 |
/* 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 power_supply: Add... |
136 |
POWER_SUPPLY_ATTR(charge_type), |
4a11b59d8 [BATTERY] Univers... |
137 138 139 140 |
POWER_SUPPLY_ATTR(health), POWER_SUPPLY_ATTR(present), POWER_SUPPLY_ATTR(online), POWER_SUPPLY_ATTR(technology), |
c955fe8e0 POWER: Add suppor... |
141 |
POWER_SUPPLY_ATTR(cycle_count), |
c7cc930f9 power_supply: add... |
142 143 |
POWER_SUPPLY_ATTR(voltage_max), POWER_SUPPLY_ATTR(voltage_min), |
4a11b59d8 [BATTERY] Univers... |
144 145 146 147 |
POWER_SUPPLY_ATTR(voltage_max_design), POWER_SUPPLY_ATTR(voltage_min_design), POWER_SUPPLY_ATTR(voltage_now), POWER_SUPPLY_ATTR(voltage_avg), |
fe3f6d097 power_supply: Int... |
148 |
POWER_SUPPLY_ATTR(current_max), |
4a11b59d8 [BATTERY] Univers... |
149 150 |
POWER_SUPPLY_ATTR(current_now), POWER_SUPPLY_ATTR(current_avg), |
7faa144a5 ACPI: battery: ad... |
151 152 |
POWER_SUPPLY_ATTR(power_now), POWER_SUPPLY_ATTR(power_avg), |
4a11b59d8 [BATTERY] Univers... |
153 154 155 156 157 158 |
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 power_supply: add... |
159 |
POWER_SUPPLY_ATTR(charge_counter), |
4a11b59d8 [BATTERY] Univers... |
160 161 162 163 164 165 166 |
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), |
b294a290d Revert "power: re... |
167 |
POWER_SUPPLY_ATTR(capacity_level), |
4a11b59d8 [BATTERY] Univers... |
168 169 170 171 172 173 |
POWER_SUPPLY_ATTR(temp), POWER_SUPPLY_ATTR(temp_ambient), 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 power_supply: Use... |
174 |
POWER_SUPPLY_ATTR(type), |
4a11b59d8 [BATTERY] Univers... |
175 176 177 |
/* Properties of type `const char *' */ POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(manufacturer), |
7c2670bbb ACPI: battery: ad... |
178 |
POWER_SUPPLY_ATTR(serial_number), |
4a11b59d8 [BATTERY] Univers... |
179 |
}; |
5f487cd34 power_supply: Use... |
180 181 |
static struct attribute * __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1]; |
4a11b59d8 [BATTERY] Univers... |
182 |
|
5f487cd34 power_supply: Use... |
183 184 185 |
static mode_t power_supply_attr_is_visible(struct kobject *kobj, struct attribute *attr, int attrno) |
4a11b59d8 [BATTERY] Univers... |
186 |
{ |
5f487cd34 power_supply: Use... |
187 188 |
struct device *dev = container_of(kobj, struct device, kobj); struct power_supply *psy = dev_get_drvdata(dev); |
bbabb158f power_supply: Fix... |
189 |
mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; |
5f487cd34 power_supply: Use... |
190 |
int i; |
4a11b59d8 [BATTERY] Univers... |
191 |
|
bbabb158f power_supply: Fix... |
192 193 |
if (attrno == POWER_SUPPLY_PROP_TYPE) return mode; |
5f487cd34 power_supply: Use... |
194 |
for (i = 0; i < psy->num_properties; i++) { |
0011d2d4a power_supply: Add... |
195 196 197 |
int property = psy->properties[i]; if (property == attrno) { |
0011d2d4a power_supply: Add... |
198 199 200 201 202 203 |
if (psy->property_is_writeable && psy->property_is_writeable(psy, property) > 0) mode |= S_IWUSR; return mode; } |
4a11b59d8 [BATTERY] Univers... |
204 |
} |
5f487cd34 power_supply: Use... |
205 |
return 0; |
4a11b59d8 [BATTERY] Univers... |
206 |
} |
5f487cd34 power_supply: Use... |
207 208 209 210 211 212 213 214 215 216 217 |
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 [BATTERY] Univers... |
218 219 |
{ int i; |
5f487cd34 power_supply: Use... |
220 |
dev_type->groups = power_supply_attr_groups; |
4a11b59d8 [BATTERY] Univers... |
221 |
|
5f487cd34 power_supply: Use... |
222 223 |
for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) __power_supply_attrs[i] = &power_supply_attrs[i].attr; |
4a11b59d8 [BATTERY] Univers... |
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
} 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 Driver core: chan... |
242 |
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) |
4a11b59d8 [BATTERY] Univers... |
243 244 |
{ struct power_supply *psy = dev_get_drvdata(dev); |
7eff2e7a8 Driver core: chan... |
245 |
int ret = 0, j; |
4a11b59d8 [BATTERY] Univers... |
246 247 248 249 250 |
char *prop_buf; char *attrname; dev_dbg(dev, "uevent "); |
56fa18e8f power_supply: Fix... |
251 |
if (!psy || !psy->dev) { |
4a11b59d8 [BATTERY] Univers... |
252 253 254 255 256 257 258 |
dev_dbg(dev, "No power supply yet "); return ret; } dev_dbg(dev, "POWER_SUPPLY_NAME=%s ", psy->name); |
7eff2e7a8 Driver core: chan... |
259 |
ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); |
4a11b59d8 [BATTERY] Univers... |
260 261 262 263 264 265 |
if (ret) return ret; prop_buf = (char *)get_zeroed_page(GFP_KERNEL); if (!prop_buf) return -ENOMEM; |
4a11b59d8 [BATTERY] Univers... |
266 267 268 269 270 271 272 |
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 power_supply: Ign... |
273 |
if (ret == -ENODEV || ret == -ENODATA) { |
4a11b59d8 [BATTERY] Univers... |
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
/* 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 Driver core: chan... |
296 |
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); |
4a11b59d8 [BATTERY] Univers... |
297 298 299 300 301 302 303 304 305 306 |
kfree(attrname); if (ret) goto out; } out: free_page((unsigned long)prop_buf); return ret; } |