diff options
Diffstat (limited to 'drivers/power/power_supply_sysfs.c')
-rw-r--r-- | drivers/power/power_supply_sysfs.c | 147 |
1 files changed, 71 insertions, 76 deletions
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 5b6e352ac7c..9d30eeb8c81 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
@@ -31,9 +31,9 @@ | |||
31 | 31 | ||
32 | #define POWER_SUPPLY_ATTR(_name) \ | 32 | #define POWER_SUPPLY_ATTR(_name) \ |
33 | { \ | 33 | { \ |
34 | .attr = { .name = #_name, .mode = 0444 }, \ | 34 | .attr = { .name = #_name }, \ |
35 | .show = power_supply_show_property, \ | 35 | .show = power_supply_show_property, \ |
36 | .store = NULL, \ | 36 | .store = power_supply_store_property, \ |
37 | } | 37 | } |
38 | 38 | ||
39 | static struct device_attribute power_supply_attrs[]; | 39 | static struct device_attribute power_supply_attrs[]; |
@@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[]; | |||
41 | static ssize_t power_supply_show_property(struct device *dev, | 41 | static ssize_t power_supply_show_property(struct device *dev, |
42 | struct device_attribute *attr, | 42 | struct device_attribute *attr, |
43 | char *buf) { | 43 | char *buf) { |
44 | static char *type_text[] = { | ||
45 | "Battery", "UPS", "Mains", "USB" | ||
46 | }; | ||
44 | static char *status_text[] = { | 47 | static char *status_text[] = { |
45 | "Unknown", "Charging", "Discharging", "Not charging", "Full" | 48 | "Unknown", "Charging", "Discharging", "Not charging", "Full" |
46 | }; | 49 | }; |
@@ -58,12 +61,15 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
58 | static char *capacity_level_text[] = { | 61 | static char *capacity_level_text[] = { |
59 | "Unknown", "Critical", "Low", "Normal", "High", "Full" | 62 | "Unknown", "Critical", "Low", "Normal", "High", "Full" |
60 | }; | 63 | }; |
61 | ssize_t ret; | 64 | ssize_t ret = 0; |
62 | struct power_supply *psy = dev_get_drvdata(dev); | 65 | struct power_supply *psy = dev_get_drvdata(dev); |
63 | const ptrdiff_t off = attr - power_supply_attrs; | 66 | const ptrdiff_t off = attr - power_supply_attrs; |
64 | union power_supply_propval value; | 67 | union power_supply_propval value; |
65 | 68 | ||
66 | ret = psy->get_property(psy, off, &value); | 69 | if (off == POWER_SUPPLY_PROP_TYPE) |
70 | value.intval = psy->type; | ||
71 | else | ||
72 | ret = psy->get_property(psy, off, &value); | ||
67 | 73 | ||
68 | if (ret < 0) { | 74 | if (ret < 0) { |
69 | if (ret == -ENODATA) | 75 | if (ret == -ENODATA) |
@@ -85,12 +91,37 @@ static ssize_t power_supply_show_property(struct device *dev, | |||
85 | return sprintf(buf, "%s\n", technology_text[value.intval]); | 91 | return sprintf(buf, "%s\n", technology_text[value.intval]); |
86 | else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) | 92 | else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) |
87 | return sprintf(buf, "%s\n", capacity_level_text[value.intval]); | 93 | return sprintf(buf, "%s\n", capacity_level_text[value.intval]); |
94 | else if (off == POWER_SUPPLY_PROP_TYPE) | ||
95 | return sprintf(buf, "%s\n", type_text[value.intval]); | ||
88 | else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) | 96 | else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) |
89 | return sprintf(buf, "%s\n", value.strval); | 97 | return sprintf(buf, "%s\n", value.strval); |
90 | 98 | ||
91 | return sprintf(buf, "%d\n", value.intval); | 99 | return sprintf(buf, "%d\n", value.intval); |
92 | } | 100 | } |
93 | 101 | ||
102 | static ssize_t power_supply_store_property(struct device *dev, | ||
103 | struct device_attribute *attr, | ||
104 | const char *buf, size_t count) { | ||
105 | ssize_t ret; | ||
106 | struct power_supply *psy = dev_get_drvdata(dev); | ||
107 | const ptrdiff_t off = attr - power_supply_attrs; | ||
108 | union power_supply_propval value; | ||
109 | long long_val; | ||
110 | |||
111 | /* TODO: support other types than int */ | ||
112 | ret = strict_strtol(buf, 10, &long_val); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | value.intval = long_val; | ||
117 | |||
118 | ret = psy->set_property(psy, off, &value); | ||
119 | if (ret < 0) | ||
120 | return ret; | ||
121 | |||
122 | return count; | ||
123 | } | ||
124 | |||
94 | /* Must be in the same order as POWER_SUPPLY_PROP_* */ | 125 | /* Must be in the same order as POWER_SUPPLY_PROP_* */ |
95 | static struct device_attribute power_supply_attrs[] = { | 126 | static struct device_attribute power_supply_attrs[] = { |
96 | /* Properties of type `int' */ | 127 | /* Properties of type `int' */ |
@@ -132,67 +163,61 @@ static struct device_attribute power_supply_attrs[] = { | |||
132 | POWER_SUPPLY_ATTR(time_to_empty_avg), | 163 | POWER_SUPPLY_ATTR(time_to_empty_avg), |
133 | POWER_SUPPLY_ATTR(time_to_full_now), | 164 | POWER_SUPPLY_ATTR(time_to_full_now), |
134 | POWER_SUPPLY_ATTR(time_to_full_avg), | 165 | POWER_SUPPLY_ATTR(time_to_full_avg), |
166 | POWER_SUPPLY_ATTR(type), | ||
135 | /* Properties of type `const char *' */ | 167 | /* Properties of type `const char *' */ |
136 | POWER_SUPPLY_ATTR(model_name), | 168 | POWER_SUPPLY_ATTR(model_name), |
137 | POWER_SUPPLY_ATTR(manufacturer), | 169 | POWER_SUPPLY_ATTR(manufacturer), |
138 | POWER_SUPPLY_ATTR(serial_number), | 170 | POWER_SUPPLY_ATTR(serial_number), |
139 | }; | 171 | }; |
140 | 172 | ||
141 | static ssize_t power_supply_show_static_attrs(struct device *dev, | 173 | static struct attribute * |
142 | struct device_attribute *attr, | 174 | __power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1]; |
143 | char *buf) { | 175 | |
144 | static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; | 176 | static mode_t power_supply_attr_is_visible(struct kobject *kobj, |
177 | struct attribute *attr, | ||
178 | int attrno) | ||
179 | { | ||
180 | struct device *dev = container_of(kobj, struct device, kobj); | ||
145 | struct power_supply *psy = dev_get_drvdata(dev); | 181 | struct power_supply *psy = dev_get_drvdata(dev); |
182 | mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; | ||
183 | int i; | ||
146 | 184 | ||
147 | return sprintf(buf, "%s\n", type_text[psy->type]); | 185 | if (attrno == POWER_SUPPLY_PROP_TYPE) |
148 | } | 186 | return mode; |
149 | 187 | ||
150 | static struct device_attribute power_supply_static_attrs[] = { | 188 | for (i = 0; i < psy->num_properties; i++) { |
151 | __ATTR(type, 0444, power_supply_show_static_attrs, NULL), | 189 | int property = psy->properties[i]; |
152 | }; | ||
153 | 190 | ||
154 | int power_supply_create_attrs(struct power_supply *psy) | 191 | if (property == attrno) { |
155 | { | 192 | if (psy->property_is_writeable && |
156 | int rc = 0; | 193 | psy->property_is_writeable(psy, property) > 0) |
157 | int i, j; | 194 | mode |= S_IWUSR; |
158 | |||
159 | for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) { | ||
160 | rc = device_create_file(psy->dev, | ||
161 | &power_supply_static_attrs[i]); | ||
162 | if (rc) | ||
163 | goto statics_failed; | ||
164 | } | ||
165 | 195 | ||
166 | for (j = 0; j < psy->num_properties; j++) { | 196 | return mode; |
167 | rc = device_create_file(psy->dev, | 197 | } |
168 | &power_supply_attrs[psy->properties[j]]); | ||
169 | if (rc) | ||
170 | goto dynamics_failed; | ||
171 | } | 198 | } |
172 | 199 | ||
173 | goto succeed; | 200 | return 0; |
174 | |||
175 | dynamics_failed: | ||
176 | while (j--) | ||
177 | device_remove_file(psy->dev, | ||
178 | &power_supply_attrs[psy->properties[j]]); | ||
179 | statics_failed: | ||
180 | while (i--) | ||
181 | device_remove_file(psy->dev, &power_supply_static_attrs[i]); | ||
182 | succeed: | ||
183 | return rc; | ||
184 | } | 201 | } |
185 | 202 | ||
186 | void power_supply_remove_attrs(struct power_supply *psy) | 203 | static struct attribute_group power_supply_attr_group = { |
204 | .attrs = __power_supply_attrs, | ||
205 | .is_visible = power_supply_attr_is_visible, | ||
206 | }; | ||
207 | |||
208 | static const struct attribute_group *power_supply_attr_groups[] = { | ||
209 | &power_supply_attr_group, | ||
210 | NULL, | ||
211 | }; | ||
212 | |||
213 | void power_supply_init_attrs(struct device_type *dev_type) | ||
187 | { | 214 | { |
188 | int i; | 215 | int i; |
189 | 216 | ||
190 | for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) | 217 | dev_type->groups = power_supply_attr_groups; |
191 | device_remove_file(psy->dev, &power_supply_static_attrs[i]); | ||
192 | 218 | ||
193 | for (i = 0; i < psy->num_properties; i++) | 219 | for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) |
194 | device_remove_file(psy->dev, | 220 | __power_supply_attrs[i] = &power_supply_attrs[i].attr; |
195 | &power_supply_attrs[psy->properties[i]]); | ||
196 | } | 221 | } |
197 | 222 | ||
198 | static char *kstruprdup(const char *str, gfp_t gfp) | 223 | static char *kstruprdup(const char *str, gfp_t gfp) |
@@ -236,36 +261,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
236 | if (!prop_buf) | 261 | if (!prop_buf) |
237 | return -ENOMEM; | 262 | return -ENOMEM; |
238 | 263 | ||
239 | for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) { | ||
240 | struct device_attribute *attr; | ||
241 | char *line; | ||
242 | |||
243 | attr = &power_supply_static_attrs[j]; | ||
244 | |||
245 | ret = power_supply_show_static_attrs(dev, attr, prop_buf); | ||
246 | if (ret < 0) | ||
247 | goto out; | ||
248 | |||
249 | line = strchr(prop_buf, '\n'); | ||
250 | if (line) | ||
251 | *line = 0; | ||
252 | |||
253 | attrname = kstruprdup(attr->attr.name, GFP_KERNEL); | ||
254 | if (!attrname) { | ||
255 | ret = -ENOMEM; | ||
256 | goto out; | ||
257 | } | ||
258 | |||
259 | dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); | ||
260 | |||
261 | ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); | ||
262 | kfree(attrname); | ||
263 | if (ret) | ||
264 | goto out; | ||
265 | } | ||
266 | |||
267 | dev_dbg(dev, "%zd dynamic props\n", psy->num_properties); | ||
268 | |||
269 | for (j = 0; j < psy->num_properties; j++) { | 264 | for (j = 0; j < psy->num_properties; j++) { |
270 | struct device_attribute *attr; | 265 | struct device_attribute *attr; |
271 | char *line; | 266 | char *line; |