aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Vorontsov <cbouatmailru@gmail.com>2010-05-18 15:49:51 -0400
committerAnton Vorontsov <cbouatmailru@gmail.com>2010-05-19 04:14:28 -0400
commit5f487cd34f4337f9bc27ca19da72a39d1b0a0ab4 (patch)
treef3204e0cf64a7202c42d1f397fd978ccd61f8225
parenta1e50fd4452b2ed57376ece465a17276b59fad9c (diff)
power_supply: Use attribute groups
This fixes a race between power supply device and initial attributes creation, plus makes it possible to implement writable properties. [Daniel Mack - removed superflous return statement and dropped .mode attribute from POWER_SUPPLY_ATTR] Suggested-by: Greg KH <gregkh@suse.de> Suggested-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com> Tested-by: Daniel Mack <daniel@caiaq.de>
-rw-r--r--drivers/power/power_supply.h7
-rw-r--r--drivers/power/power_supply_core.c48
-rw-r--r--drivers/power/power_supply_sysfs.c115
-rw-r--r--include/linux/power_supply.h1
4 files changed, 75 insertions, 96 deletions
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index f38ba482be75..018de2b26998 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -12,15 +12,12 @@
12 12
13#ifdef CONFIG_SYSFS 13#ifdef CONFIG_SYSFS
14 14
15extern int power_supply_create_attrs(struct power_supply *psy); 15extern void power_supply_init_attrs(struct device_type *dev_type);
16extern void power_supply_remove_attrs(struct power_supply *psy);
17extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); 16extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
18 17
19#else 18#else
20 19
21static inline int power_supply_create_attrs(struct power_supply *psy) 20static inline void power_supply_init_attrs(struct device_type *dev_type) {}
22{ return 0; }
23static inline void power_supply_remove_attrs(struct power_supply *psy) {}
24#define power_supply_uevent NULL 21#define power_supply_uevent NULL
25 22
26#endif /* CONFIG_SYSFS */ 23#endif /* CONFIG_SYSFS */
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index cce75b40b435..91606bb55318 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/slab.h>
16#include <linux/device.h> 17#include <linux/device.h>
17#include <linux/err.h> 18#include <linux/err.h>
18#include <linux/power_supply.h> 19#include <linux/power_supply.h>
@@ -22,6 +23,8 @@
22struct class *power_supply_class; 23struct class *power_supply_class;
23EXPORT_SYMBOL_GPL(power_supply_class); 24EXPORT_SYMBOL_GPL(power_supply_class);
24 25
26static struct device_type power_supply_dev_type;
27
25static int __power_supply_changed_work(struct device *dev, void *data) 28static int __power_supply_changed_work(struct device *dev, void *data)
26{ 29{
27 struct power_supply *psy = (struct power_supply *)data; 30 struct power_supply *psy = (struct power_supply *)data;
@@ -144,22 +147,39 @@ struct power_supply *power_supply_get_by_name(char *name)
144} 147}
145EXPORT_SYMBOL_GPL(power_supply_get_by_name); 148EXPORT_SYMBOL_GPL(power_supply_get_by_name);
146 149
150static void power_supply_dev_release(struct device *dev)
151{
152 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
153 kfree(dev);
154}
155
147int power_supply_register(struct device *parent, struct power_supply *psy) 156int power_supply_register(struct device *parent, struct power_supply *psy)
148{ 157{
149 int rc = 0; 158 struct device *dev;
159 int rc;
150 160
151 psy->dev = device_create(power_supply_class, parent, 0, psy, 161 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
152 "%s", psy->name); 162 if (!dev)
153 if (IS_ERR(psy->dev)) { 163 return -ENOMEM;
154 rc = PTR_ERR(psy->dev);
155 goto dev_create_failed;
156 }
157 164
158 INIT_WORK(&psy->changed_work, power_supply_changed_work); 165 device_initialize(dev);
159 166
160 rc = power_supply_create_attrs(psy); 167 dev->class = power_supply_class;
168 dev->type = &power_supply_dev_type;
169 dev->parent = parent;
170 dev->release = power_supply_dev_release;
171 dev_set_drvdata(dev, psy);
172 psy->dev = dev;
173
174 rc = kobject_set_name(&dev->kobj, "%s", psy->name);
175 if (rc)
176 goto kobject_set_name_failed;
177
178 rc = device_add(dev);
161 if (rc) 179 if (rc)
162 goto create_attrs_failed; 180 goto device_add_failed;
181
182 INIT_WORK(&psy->changed_work, power_supply_changed_work);
163 183
164 rc = power_supply_create_triggers(psy); 184 rc = power_supply_create_triggers(psy);
165 if (rc) 185 if (rc)
@@ -170,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
170 goto success; 190 goto success;
171 191
172create_triggers_failed: 192create_triggers_failed:
173 power_supply_remove_attrs(psy);
174create_attrs_failed:
175 device_unregister(psy->dev); 193 device_unregister(psy->dev);
176dev_create_failed: 194kobject_set_name_failed:
195device_add_failed:
196 kfree(dev);
177success: 197success:
178 return rc; 198 return rc;
179} 199}
@@ -183,7 +203,6 @@ void power_supply_unregister(struct power_supply *psy)
183{ 203{
184 flush_scheduled_work(); 204 flush_scheduled_work();
185 power_supply_remove_triggers(psy); 205 power_supply_remove_triggers(psy);
186 power_supply_remove_attrs(psy);
187 device_unregister(psy->dev); 206 device_unregister(psy->dev);
188} 207}
189EXPORT_SYMBOL_GPL(power_supply_unregister); 208EXPORT_SYMBOL_GPL(power_supply_unregister);
@@ -196,6 +215,7 @@ static int __init power_supply_class_init(void)
196 return PTR_ERR(power_supply_class); 215 return PTR_ERR(power_supply_class);
197 216
198 power_supply_class->dev_uevent = power_supply_uevent; 217 power_supply_class->dev_uevent = power_supply_uevent;
218 power_supply_init_attrs(&power_supply_dev_type);
199 219
200 return 0; 220 return 0;
201} 221}
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 5b6e352ac7c1..7d7593cad7d9 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -31,7 +31,7 @@
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 = NULL, \
37} 37}
@@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[];
41static ssize_t power_supply_show_property(struct device *dev, 41static 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) {