From 5f487cd34f4337f9bc27ca19da72a39d1b0a0ab4 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 18 May 2010 21:49:51 +0200 Subject: 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 Suggested-by: Kay Sievers Signed-off-by: Anton Vorontsov Tested-by: Daniel Mack --- drivers/power/power_supply_sysfs.c | 115 ++++++++++++------------------------- 1 file changed, 38 insertions(+), 77 deletions(-) (limited to 'drivers/power/power_supply_sysfs.c') 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 @@ #define POWER_SUPPLY_ATTR(_name) \ { \ - .attr = { .name = #_name, .mode = 0444 }, \ + .attr = { .name = #_name }, \ .show = power_supply_show_property, \ .store = NULL, \ } @@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[]; static ssize_t power_supply_show_property(struct device *dev, struct device_attribute *attr, char *buf) { + static char *type_text[] = { + "Battery", "UPS", "Mains", "USB" + }; static char *status_text[] = { "Unknown", "Charging", "Discharging", "Not charging", "Full" }; @@ -58,12 +61,15 @@ static ssize_t power_supply_show_property(struct device *dev, static char *capacity_level_text[] = { "Unknown", "Critical", "Low", "Normal", "High", "Full" }; - ssize_t ret; + ssize_t ret = 0; struct power_supply *psy = dev_get_drvdata(dev); const ptrdiff_t off = attr - power_supply_attrs; union power_supply_propval value; - ret = psy->get_property(psy, off, &value); + if (off == POWER_SUPPLY_PROP_TYPE) + value.intval = psy->type; + else + ret = psy->get_property(psy, off, &value); if (ret < 0) { if (ret == -ENODATA) @@ -85,6 +91,8 @@ static ssize_t power_supply_show_property(struct device *dev, return sprintf(buf, "%s\n", technology_text[value.intval]); else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) return sprintf(buf, "%s\n", capacity_level_text[value.intval]); + else if (off == POWER_SUPPLY_PROP_TYPE) + return sprintf(buf, "%s\n", type_text[value.intval]); else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) return sprintf(buf, "%s\n", value.strval); @@ -132,67 +140,50 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(time_to_empty_avg), POWER_SUPPLY_ATTR(time_to_full_now), POWER_SUPPLY_ATTR(time_to_full_avg), + POWER_SUPPLY_ATTR(type), /* Properties of type `const char *' */ POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(serial_number), }; -static ssize_t power_supply_show_static_attrs(struct device *dev, - struct device_attribute *attr, - char *buf) { - static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; - struct power_supply *psy = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", type_text[psy->type]); -} - -static struct device_attribute power_supply_static_attrs[] = { - __ATTR(type, 0444, power_supply_show_static_attrs, NULL), -}; +static struct attribute * +__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1]; -int power_supply_create_attrs(struct power_supply *psy) +static mode_t power_supply_attr_is_visible(struct kobject *kobj, + struct attribute *attr, + int attrno) { - int rc = 0; - int i, j; - - for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) { - rc = device_create_file(psy->dev, - &power_supply_static_attrs[i]); - if (rc) - goto statics_failed; - } + struct device *dev = container_of(kobj, struct device, kobj); + struct power_supply *psy = dev_get_drvdata(dev); + int i; - for (j = 0; j < psy->num_properties; j++) { - rc = device_create_file(psy->dev, - &power_supply_attrs[psy->properties[j]]); - if (rc) - goto dynamics_failed; + for (i = 0; i < psy->num_properties; i++) { + if (psy->properties[i] == attrno) + return 0444; } - goto succeed; - -dynamics_failed: - while (j--) - device_remove_file(psy->dev, - &power_supply_attrs[psy->properties[j]]); -statics_failed: - while (i--) - device_remove_file(psy->dev, &power_supply_static_attrs[i]); -succeed: - return rc; + return 0; } -void power_supply_remove_attrs(struct power_supply *psy) +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) { int i; - for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) - device_remove_file(psy->dev, &power_supply_static_attrs[i]); + dev_type->groups = power_supply_attr_groups; - for (i = 0; i < psy->num_properties; i++) - device_remove_file(psy->dev, - &power_supply_attrs[psy->properties[i]]); + for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) + __power_supply_attrs[i] = &power_supply_attrs[i].attr; } static char *kstruprdup(const char *str, gfp_t gfp) @@ -236,36 +227,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) if (!prop_buf) return -ENOMEM; - for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) { - struct device_attribute *attr; - char *line; - - attr = &power_supply_static_attrs[j]; - - ret = power_supply_show_static_attrs(dev, attr, prop_buf); - if (ret < 0) - goto out; - - line = strchr(prop_buf, '\n'); - if (line) - *line = 0; - - attrname = kstruprdup(attr->attr.name, GFP_KERNEL); - if (!attrname) { - ret = -ENOMEM; - goto out; - } - - dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - - ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); - kfree(attrname); - if (ret) - goto out; - } - - dev_dbg(dev, "%zd dynamic props\n", psy->num_properties); - for (j = 0; j < psy->num_properties; j++) { struct device_attribute *attr; char *line; -- cgit v1.2.3