diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2007-04-24 14:48:14 (GMT) |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-04-25 06:00:27 (GMT) |
commit | 7252374a39d794879f5e47bcfa0a16e7599b27b5 (patch) | |
tree | f6a0801099b74b9d78ea1240d725b7aa2f6c6a0b /drivers/misc/thinkpad_acpi.c | |
parent | 176750d68801bfa4a88d1cf54174aa0347d7e5d8 (diff) | |
download | linux-fsl-qoriq-7252374a39d794879f5e47bcfa0a16e7599b27b5.tar.xz |
ACPI: thinkpad-acpi: add infrastructure for the sysfs device attributes
Add infrastructure to deal with sysfs attributes and grouping, and helpers
for common sysfs parsing. Switch driver attributes to use them.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 86 |
1 files changed, 81 insertions, 5 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a31d00d..ca6d15c 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -520,12 +520,8 @@ static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, const char *buf, size_t count) { unsigned long t; - char *endp; - t = simple_strtoul(buf, &endp, 0); - while (*endp && isspace(*endp)) - endp++; - if (*endp) + if (parse_strtoul(buf, 0xffff, &t)) return -EINVAL; dbg_level = t; @@ -575,6 +571,86 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) driver_remove_file(drv, tpacpi_driver_attributes[i]); } +/************************************************************************* + * sysfs support helpers + */ + +struct attribute_set_obj { + struct attribute_set s; + struct attribute *a; +} __attribute__((packed)); + +static struct attribute_set *create_attr_set(unsigned int max_members, + const char* name) +{ + struct attribute_set_obj *sobj; + + if (max_members == 0) + return NULL; + + /* Allocates space for implicit NULL at the end too */ + sobj = kzalloc(sizeof(struct attribute_set_obj) + + max_members * sizeof(struct attribute *), + GFP_KERNEL); + if (!sobj) + return NULL; + sobj->s.max_members = max_members; + sobj->s.group.attrs = &sobj->a; + sobj->s.group.name = name; + + return &sobj->s; +} + +/* not multi-threaded safe, use it in a single thread per set */ +static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) +{ + if (!s || !attr) + return -EINVAL; + + if (s->members >= s->max_members) + return -ENOMEM; + + s->group.attrs[s->members] = attr; + s->members++; + + return 0; +} + +static int add_many_to_attr_set(struct attribute_set* s, + struct attribute **attr, + unsigned int count) +{ + int i, res; + + for (i = 0; i < count; i++) { + res = add_to_attr_set(s, attr[i]); + if (res) + return res; + } + + return 0; +} + +static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) +{ + sysfs_remove_group(kobj, &s->group); + destroy_attr_set(s); +} + +static int parse_strtoul(const char *buf, + unsigned long max, unsigned long *value) +{ + char *endp; + + *value = simple_strtoul(buf, &endp, 0); + while (*endp && isspace(*endp)) + endp++; + if (*endp || *value > max) + return -EINVAL; + + return 0; +} + /**************************************************************************** **************************************************************************** * |