aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh2007-04-24 11:48:14 -0300
committerLen Brown2007-04-25 02:00:27 -0400
commit7252374a39d794879f5e47bcfa0a16e7599b27b5 (patch)
treef6a0801099b74b9d78ea1240d725b7aa2f6c6a0b /drivers/misc/thinkpad_acpi.c
parent176750d68801bfa4a88d1cf54174aa0347d7e5d8 (diff)
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.c86
1 files changed, 81 insertions, 5 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index a31d00d570cb..ca6d15cdc5f0 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;
+}
+
/****************************************************************************
****************************************************************************
*