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>
This commit is contained in:
Anton Vorontsov
2010-05-18 21:49:51 +02:00
parent a1e50fd445
commit 5f487cd34f
4 changed files with 77 additions and 98 deletions

View File

@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/power_supply.h>
@ -22,6 +23,8 @@
struct class *power_supply_class;
EXPORT_SYMBOL_GPL(power_supply_class);
static struct device_type power_supply_dev_type;
static int __power_supply_changed_work(struct device *dev, void *data)
{
struct power_supply *psy = (struct power_supply *)data;
@ -144,23 +147,40 @@ struct power_supply *power_supply_get_by_name(char *name)
}
EXPORT_SYMBOL_GPL(power_supply_get_by_name);
static void power_supply_dev_release(struct device *dev)
{
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
kfree(dev);
}
int power_supply_register(struct device *parent, struct power_supply *psy)
{
int rc = 0;
struct device *dev;
int rc;
psy->dev = device_create(power_supply_class, parent, 0, psy,
"%s", psy->name);
if (IS_ERR(psy->dev)) {
rc = PTR_ERR(psy->dev);
goto dev_create_failed;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
device_initialize(dev);
dev->class = power_supply_class;
dev->type = &power_supply_dev_type;
dev->parent = parent;
dev->release = power_supply_dev_release;
dev_set_drvdata(dev, psy);
psy->dev = dev;
rc = kobject_set_name(&dev->kobj, "%s", psy->name);
if (rc)
goto kobject_set_name_failed;
rc = device_add(dev);
if (rc)
goto device_add_failed;
INIT_WORK(&psy->changed_work, power_supply_changed_work);
rc = power_supply_create_attrs(psy);
if (rc)
goto create_attrs_failed;
rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed;
@ -170,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto success;
create_triggers_failed:
power_supply_remove_attrs(psy);
create_attrs_failed:
device_unregister(psy->dev);
dev_create_failed:
kobject_set_name_failed:
device_add_failed:
kfree(dev);
success:
return rc;
}
@ -183,7 +203,6 @@ void power_supply_unregister(struct power_supply *psy)
{
flush_scheduled_work();
power_supply_remove_triggers(psy);
power_supply_remove_attrs(psy);
device_unregister(psy->dev);
}
EXPORT_SYMBOL_GPL(power_supply_unregister);
@ -196,6 +215,7 @@ static int __init power_supply_class_init(void)
return PTR_ERR(power_supply_class);
power_supply_class->dev_uevent = power_supply_uevent;
power_supply_init_attrs(&power_supply_dev_type);
return 0;
}