#include "sysfs.h"
-#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
-#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
+#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
/*
* Subsystem file operations.
static ssize_t
subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
{
- struct subsystem * s = to_subsys(kobj);
+ struct kset *kset = to_kset(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = -EIO;
if (sattr->show)
- ret = sattr->show(s,page);
+ ret = sattr->show(kset, page);
return ret;
}
subsys_attr_store(struct kobject * kobj, struct attribute * attr,
const char * page, size_t count)
{
- struct subsystem * s = to_subsys(kobj);
+ struct kset *kset = to_kset(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = -EIO;
if (sattr->store)
- ret = sattr->store(s,page,count);
+ ret = sattr->store(kset, page, count);
return ret;
}
return ret;
}
-
-/**
- * flush_read_buffer - push buffer to userspace.
- * @buffer: data buffer for file.
- * @buf: user-passed buffer.
- * @count: number of bytes requested.
- * @ppos: file position.
- *
- * Copy the buffer we filled in fill_read_buffer() to userspace.
- * This is done at the reader's leisure, copying and advancing
- * the amount they specify each time.
- * This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf,
- size_t count, loff_t * ppos)
-{
- int error;
-
- if (*ppos > buffer->count)
- return 0;
-
- if (count > (buffer->count - *ppos))
- count = buffer->count - *ppos;
-
- error = copy_to_user(buf,buffer->page + *ppos,count);
- if (!error)
- *ppos += count;
- return error ? -EFAULT : count;
-}
-
/**
* sysfs_read_file - read an attribute.
* @file: file pointer.
ssize_t retval = 0;
down(&buffer->sem);
- if (buffer->orphaned) {
- retval = -ENODEV;
- goto out;
- }
if (buffer->needs_read_fill) {
- if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
+ if (buffer->orphaned)
+ retval = -ENODEV;
+ else
+ retval = fill_read_buffer(file->f_path.dentry,buffer);
+ if (retval)
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
__FUNCTION__, count, *ppos, buffer->page);
- retval = flush_read_buffer(buffer,buf,count,ppos);
+ retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+ buffer->count);
out:
up(&buffer->sem);
return retval;
}
EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
+struct sysfs_schedule_callback_struct {
+ struct kobject *kobj;
+ void (*func)(void *);
+ void *data;
+ struct module *owner;
+ struct work_struct work;
+};
+
+static void sysfs_schedule_callback_work(struct work_struct *work)
+{
+ struct sysfs_schedule_callback_struct *ss = container_of(work,
+ struct sysfs_schedule_callback_struct, work);
+
+ (ss->func)(ss->data);
+ kobject_put(ss->kobj);
+ module_put(ss->owner);
+ kfree(ss);
+}
+
+/**
+ * sysfs_schedule_callback - helper to schedule a callback for a kobject
+ * @kobj: object we're acting for.
+ * @func: callback function to invoke later.
+ * @data: argument to pass to @func.
+ * @owner: module owning the callback code
+ *
+ * sysfs attribute methods must not unregister themselves or their parent
+ * kobject (which would amount to the same thing). Attempts to do so will
+ * deadlock, since unregistration is mutually exclusive with driver
+ * callbacks.
+ *
+ * Instead methods can call this routine, which will attempt to allocate
+ * and schedule a workqueue request to call back @func with @data as its
+ * argument in the workqueue's process context. @kobj will be pinned
+ * until @func returns.
+ *
+ * Returns 0 if the request was submitted, -ENOMEM if storage could not
+ * be allocated, -ENODEV if a reference to @owner isn't available.
+ */
+int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
+ void *data, struct module *owner)
+{
+ struct sysfs_schedule_callback_struct *ss;
+
+ if (!try_module_get(owner))
+ return -ENODEV;
+ ss = kmalloc(sizeof(*ss), GFP_KERNEL);
+ if (!ss) {
+ module_put(owner);
+ return -ENOMEM;
+ }
+ kobject_get(kobj);
+ ss->kobj = kobj;
+ ss->func = func;
+ ss->data = data;
+ ss->owner = owner;
+ INIT_WORK(&ss->work, sysfs_schedule_callback_work);
+ schedule_work(&ss->work);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
+
EXPORT_SYMBOL_GPL(sysfs_create_file);
EXPORT_SYMBOL_GPL(sysfs_remove_file);