Commit d001c86c authored by Patrick Mochel's avatar Patrick Mochel

driverfs: add glue layer for drivers to export attributes via driverfs

This defines struct driver_attribute so device drivers themselves can export attributes 
via driverfs.

The macro DRIVER_ATTR is defined for declaring the attributes.

driver_{create,remove}_file are implemented for creating and removing files.

 
parent fa98bede
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/err.h>
#include "fs.h" #include "fs.h"
#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr)
#define to_drv(d) container_of(d, struct device_driver, dir)
/* driverfs ops for device attribute files */
static int
drv_attr_open(struct driver_dir_entry * dir)
{
struct device_driver * drv = to_drv(dir);
get_driver(drv);
return 0;
}
static int
drv_attr_close(struct driver_dir_entry * dir)
{
struct device_driver * drv = to_drv(dir);
put_driver(drv);
return 0;
}
static ssize_t
drv_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_drv(dir);
ssize_t ret = 0;
if (drv_attr->show)
ret = drv_attr->show(drv,buf,count,off);
return ret;
}
static ssize_t
drv_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
const char * buf, size_t count, loff_t off)
{
struct driver_attribute * drv_attr = to_drv_attr(attr);
struct device_driver * drv = to_drv(dir);
ssize_t ret = 0;
if (drv_attr->store)
ret = drv_attr->store(drv,buf,count,off);
return ret;
}
static struct driverfs_ops drv_attr_ops = {
open: drv_attr_open,
close: drv_attr_close,
show: drv_attr_show,
store: drv_attr_store,
};
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
{
int error;
if (get_driver(drv)) {
error = driverfs_create_file(&attr->attr,&drv->dir);
put_driver(drv);
} else
error = -EINVAL;
return error;
}
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
{
if (get_driver(drv)) {
driverfs_remove_file(&drv->dir,attr->attr.name);
put_driver(drv);
}
}
/** /**
* driver_make_dir - create a driverfs directory for a driver * driver_make_dir - create a driverfs directory for a driver
* @drv: driver in question * @drv: driver in question
...@@ -8,6 +86,8 @@ ...@@ -8,6 +86,8 @@
int driver_make_dir(struct device_driver * drv) int driver_make_dir(struct device_driver * drv)
{ {
drv->dir.name = drv->name; drv->dir.name = drv->name;
drv->dir.ops = &drv_attr_ops;
return device_create_dir(&drv->dir,&drv->bus->driver_dir); return device_create_dir(&drv->dir,&drv->bus->driver_dir);
} }
...@@ -16,3 +96,5 @@ void driver_remove_dir(struct device_driver * drv) ...@@ -16,3 +96,5 @@ void driver_remove_dir(struct device_driver * drv)
driverfs_remove_dir(&drv->dir); driverfs_remove_dir(&drv->dir);
} }
EXPORT_SYMBOL(driver_create_file);
EXPORT_SYMBOL(driver_remove_file);
...@@ -142,6 +142,24 @@ extern int driver_for_each_dev(struct device_driver * drv, void * data, ...@@ -142,6 +142,24 @@ extern int driver_for_each_dev(struct device_driver * drv, void * data,
int (*callback)(struct device * dev, void * data)); int (*callback)(struct device * dev, void * data));
/* driverfs interface for exporting driver attributes */
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off);
ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off);
};
#define DRIVER_ATTR(_name,_str,_mode,_show,_store) \
struct driver_attribute driver_attr_##_name = { \
.attr = {.name = _str, .mode = _mode }, \
.show = _show, \
.store = _store, \
};
extern int driver_create_file(struct device_driver *, struct driver_attribute *);
extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
struct device { struct device {
struct list_head g_list; /* node in depth-first order list */ struct list_head g_list; /* node in depth-first order list */
struct list_head node; /* node in sibling list */ struct list_head node; /* node in sibling list */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment