From 3ffe04d886f663bd48cce815f77ff38e4d6fb061 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 30 Jul 2002 06:43:13 -0700 Subject: driverfs: Change the name of struct driver_file_entry to struct device_attribute It may seem gratuitous, but it's what we really want. driverfs files are meant to expose attributes of various kernel objects, so in that sense, the change adds more accurate meaning to the object. Plus, we will soon gain the ability to expose attributes of drivers (both device and bus) themselves, and we want to be able to have each mean something reasonable. This changes driverfs and the device model core (but none of the other users) --- include/linux/device.h | 2 +- include/linux/driverfs_fs.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index a6d10931ae7f..38048776fdd8 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -179,7 +179,7 @@ g_list_to_dev(struct list_head *g_list) */ extern int device_register(struct device * dev); -extern int device_create_file(struct device *device, struct driver_file_entry * entry); +extern int device_create_file(struct device *device, struct device_attribute * entry); extern void device_remove_file(struct device * dev, const char * name); /* diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index 758dc23f09f6..dceb539d91dc 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -34,7 +34,7 @@ struct driver_dir_entry { struct device; -struct driver_file_entry { +struct device_attribute { char * name; mode_t mode; @@ -49,7 +49,7 @@ extern void driverfs_remove_dir(struct driver_dir_entry * entry); extern int -driverfs_create_file(struct driver_file_entry * entry, +driverfs_create_file(struct device_attribute * entry, struct driver_dir_entry * parent); extern int -- cgit v1.2.3 From 5509cd3616bf58dd82b62b0e350e09bbc75ccf21 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 31 Jul 2002 00:08:54 -0700 Subject: driverfs: make device_remove_file take a struct device_attribute *, instead of just a char * (for consistency with device_create_file) --- drivers/base/fs.c | 5 ++--- include/linux/device.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/fs.c b/drivers/base/fs.c index 4aa4938461e8..972d9433dcde 100644 --- a/drivers/base/fs.c +++ b/drivers/base/fs.c @@ -42,11 +42,11 @@ int device_create_file(struct device * dev, struct device_attribute * entry) * @name: name of the file * */ -void device_remove_file(struct device * dev, const char * name) +void device_remove_file(struct device * dev, struct device_attribute * attr) { if (dev) { get_device(dev); - driverfs_remove_file(&dev->dir,name); + driverfs_remove_file(&dev->dir,attr->name); put_device(dev); } } @@ -61,7 +61,6 @@ void device_remove_dir(struct device * dev) driverfs_remove_dir(&dev->dir); } - static int get_devpath_length(struct device * dev) { int length = 1; diff --git a/include/linux/device.h b/include/linux/device.h index 38048776fdd8..670be49d1718 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -180,7 +180,7 @@ g_list_to_dev(struct list_head *g_list) extern int device_register(struct device * dev); extern int device_create_file(struct device *device, struct device_attribute * entry); -extern void device_remove_file(struct device * dev, const char * name); +extern void device_remove_file(struct device * dev, struct device_attribute * attr); /* * Platform "fixup" functions - allow the platform to have their say -- cgit v1.2.3 From 8d1290b87459b8fb52a9d9ed5f3c02e7c17aa03c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 31 Jul 2002 20:48:04 -0700 Subject: driverfs: Declare DEVICE_ATTR macro for initializing device attributes (hide internal format of the structure) --- include/linux/driverfs_fs.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index dceb539d91dc..2bfeb8d4acde 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -37,11 +37,18 @@ struct device; struct device_attribute { char * name; mode_t mode; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); }; +#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ +struct device_attribute dev_attr_##_name = { \ + .name = _str, \ + .mode = _mode, \ + .show = _show, \ + .store = _store, \ +}; + extern int driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); -- cgit v1.2.3 From 9bb83ce6ec5908758f0999362c0297720ca9b5ac Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 31 Jul 2002 21:17:11 -0700 Subject: driverfs: Add struct attribute driverfs can only handle passing struct device to read/write functions. In order to free it of this limitation, we need a common data structure for driverfs to pass around. The only thing that driverfs really needs are the name and mode of the file, which are now located in struct attribute. struct device_attribute gets a struct attribute member, which holds the name and mode. With the DEVICE_ATTR macro, users of the structure require no modification. device_create_file is modified to take a struct attribute parameter a to_dev_attr() macro is introduced to convert between a struct attribute to a struct device_attribute --- drivers/base/fs.c | 4 ++-- fs/driverfs/inode.c | 6 +++--- include/linux/driverfs_fs.h | 23 ++++++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/fs.c b/drivers/base/fs.c index 972d9433dcde..a50586b8c45a 100644 --- a/drivers/base/fs.c +++ b/drivers/base/fs.c @@ -30,7 +30,7 @@ int device_create_file(struct device * dev, struct device_attribute * entry) if (dev) { get_device(dev); - error = driverfs_create_file(entry,&dev->dir); + error = driverfs_create_file(&entry->attr,&dev->dir); put_device(dev); } return error; @@ -46,7 +46,7 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) { if (dev) { get_device(dev); - driverfs_remove_file(&dev->dir,attr->name); + driverfs_remove_file(&dev->dir,attr->attr.name); put_device(dev); } } diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index f533eb2c45ea..7df47ce2f4d3 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -282,7 +282,7 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) struct device * dev; dir = file->f_dentry->d_parent->d_fsdata; - entry = (struct device_attribute *)file->f_dentry->d_fsdata; + entry = to_dev_attr(file->f_dentry->d_fsdata); if (!entry) { DBG("%s: file entry is NULL\n",__FUNCTION__); return -ENOENT; @@ -349,7 +349,7 @@ driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *pp dir = file->f_dentry->d_parent->d_fsdata; - entry = (struct device_attribute *)file->f_dentry->d_fsdata; + entry = to_dev_attr(file->f_dentry->d_fsdata); if (!entry) { DBG("%s: file entry is NULL\n",__FUNCTION__); return -ENOENT; @@ -618,7 +618,7 @@ driverfs_create_dir(struct driver_dir_entry * entry, * @parent: directory to create it in */ int -driverfs_create_file(struct device_attribute * entry, +driverfs_create_file(struct attribute * entry, struct driver_dir_entry * parent) { struct dentry * dentry; diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index 2bfeb8d4acde..d00ee61fce07 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -32,23 +32,28 @@ struct driver_dir_entry { mode_t mode; }; +struct attribute { + char * name; + mode_t mode; +}; + struct device; struct device_attribute { - char * name; - mode_t mode; + struct attribute attr; ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); }; -#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = { \ - .name = _str, \ - .mode = _mode, \ - .show = _show, \ - .store = _store, \ +#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ +struct device_attribute dev_attr_##_name = { \ + .attr = {.name = _str, .mode = _mode }, \ + .show = _show, \ + .store = _store, \ }; +#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) + extern int driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); @@ -56,7 +61,7 @@ extern void driverfs_remove_dir(struct driver_dir_entry * entry); extern int -driverfs_create_file(struct device_attribute * entry, +driverfs_create_file(struct attribute * attr, struct driver_dir_entry * parent); extern int -- cgit v1.2.3 From 137973c1a3ee75e3d28af550a5e33737ac9acc5b Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 31 Jul 2002 22:07:33 -0700 Subject: driverfs: define struct driverfs_ops and remove struct device dependencies In order to read/write attributes, you have to deal directly with the object that owns them. driverfs really wants to be generic and not deal directly with those objects. So, we create an intermediate layer that subsystems must implement that converts between the generic objects and the specific objects that own the attributes. This allows allows attributes to be exported for any object type. In doing so, it places the responsibility on the subsystems to do the following: - define their own object-specific attribute structures - define their own driverfs_ops - set the ops pointer in struct driver_dir_entry when creating an object's directory - do object reference counting on open() and close() - call the show() and store() callbacks of their attribute structure - convert between the generic objects and the specific objects from the struct driver_dir_entry and struct attribute pointers (using container_of) The implementation of this layer for struct device is intended to be used as an example of the interface. Because this layer of abstraction is now in place, we can move the device attribute structure into include/linux/device.h, and driverfs should be free of references to it completely. --- drivers/base/fs.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ fs/driverfs/inode.c | 55 ++++++++++++++++--------------------------- include/linux/device.h | 18 ++++++++++++-- include/linux/driverfs_fs.h | 28 +++++++++------------- 4 files changed, 104 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/fs.c b/drivers/base/fs.c index a50586b8c45a..62df2c48be3f 100644 --- a/drivers/base/fs.c +++ b/drivers/base/fs.c @@ -17,6 +17,62 @@ extern struct device_attribute * device_default_files[]; +#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) + +#define to_device(d) container_of(d, struct device, dir) + + +/* driverfs ops for device attribute files */ + +static int +dev_attr_open(struct driver_dir_entry * dir) +{ + struct device * dev = to_device(dir); + get_device(dev); + return 0; +} + +static int +dev_attr_close(struct driver_dir_entry * dir) +{ + struct device * dev = to_device(dir); + put_device(dev); + return 0; +} + +static ssize_t +dev_attr_show(struct driver_dir_entry * dir, struct attribute * attr, + char * buf, size_t count, loff_t off) +{ + struct device_attribute * dev_attr = to_dev_attr(attr); + struct device * dev = to_device(dir); + ssize_t ret = 0; + + if (dev_attr->show) + ret = dev_attr->show(dev,buf,count,off); + return ret; +} + +static ssize_t +dev_attr_store(struct driver_dir_entry * dir, struct attribute * attr, + const char * buf, size_t count, loff_t off) +{ + struct device_attribute * dev_attr = to_dev_attr(attr); + struct device * dev = to_device(dir); + ssize_t ret = 0; + + if (dev_attr->store) + ret = dev_attr->store(dev,buf,count,off); + return ret; +} + +static struct driverfs_ops dev_attr_ops = { + open: dev_attr_open, + close: dev_attr_close, + show: dev_attr_show, + store: dev_attr_store, +}; + /** * device_create_file - create a driverfs file for a device * @dev: device requesting file @@ -159,6 +215,7 @@ int device_make_dir(struct device * dev) if (dev->parent) parent = &dev->parent->dir; dev->dir.name = dev->bus_id; + dev->dir.ops = &dev_attr_ops; if ((error = device_create_dir(&dev->dir,parent))) return error; diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index 7df47ce2f4d3..49b27f479355 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include @@ -275,26 +275,18 @@ static int driverfs_rmdir(struct inode *dir, struct dentry *dentry) static ssize_t driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct device_attribute * entry; + struct attribute * attr = file->f_dentry->d_fsdata; struct driver_dir_entry * dir; unsigned char *page; ssize_t retval = 0; - struct device * dev; dir = file->f_dentry->d_parent->d_fsdata; - entry = to_dev_attr(file->f_dentry->d_fsdata); - if (!entry) { - DBG("%s: file entry is NULL\n",__FUNCTION__); - return -ENOENT; - } - if (!entry->show) + if (!dir->ops->show) return 0; if (count > PAGE_SIZE) count = PAGE_SIZE; - dev = to_device(dir); - page = (unsigned char*)__get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -302,7 +294,7 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) while (count > 0) { ssize_t len; - len = entry->show(dev,page,count,*ppos); + len = dir->ops->show(dir,attr,page,count,*ppos); if (len <= 0) { if (len < 0) @@ -341,24 +333,13 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) static ssize_t driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct device_attribute * entry; + struct attribute * attr = file->f_dentry->d_fsdata; struct driver_dir_entry * dir; - struct device * dev; ssize_t retval = 0; char * page; dir = file->f_dentry->d_parent->d_fsdata; - entry = to_dev_attr(file->f_dentry->d_fsdata); - if (!entry) { - DBG("%s: file entry is NULL\n",__FUNCTION__); - return -ENOENT; - } - if (!entry->store) - return 0; - - dev = to_device(dir); - page = (char *)__get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -372,7 +353,7 @@ driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *pp while (count > 0) { ssize_t len; - len = entry->store(dev,page + retval,count,*ppos); + len = dir->ops->store(dir,attr,page + retval,count,*ppos); if (len <= 0) { if (len < 0) @@ -418,24 +399,28 @@ driverfs_file_lseek(struct file *file, loff_t offset, int orig) static int driverfs_open_file(struct inode * inode, struct file * filp) { struct driver_dir_entry * dir; - struct device * dev; + int error = 0; dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - if (!dir) - return -EFAULT; - dev = to_device(dir); - get_device(dev); - return 0; + if (dir) { + struct attribute * attr = filp->f_dentry->d_fsdata; + if (attr && dir->ops) { + if (dir->ops->open) + error = dir->ops->open(dir); + goto Done; + } + } + error = -EINVAL; + Done: + return error; } static int driverfs_release(struct inode * inode, struct file * filp) { struct driver_dir_entry * dir; - struct device * dev; - dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - dev = to_device(dir); - put_device(dev); + if (dir->ops->close) + dir->ops->close(dir); return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index 670be49d1718..5dfa05c2dd3a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -160,8 +160,6 @@ struct device { void (*release)(struct device * dev); }; -#define to_device(d) container_of(d, struct device, dir) - static inline struct device * list_to_dev(struct list_head *node) { @@ -179,6 +177,22 @@ g_list_to_dev(struct list_head *g_list) */ extern int device_register(struct device * dev); + +/* driverfs interface for exporting device attributes */ + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); + ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); +}; + +#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ +struct device_attribute dev_attr_##_name = { \ + .attr = {.name = _str, .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + extern int device_create_file(struct device *device, struct device_attribute * entry); extern void device_remove_file(struct device * dev, struct device_attribute * attr); diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index d00ee61fce07..d859f8c2e041 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -26,10 +26,21 @@ #ifndef _DRIVER_FS_H_ #define _DRIVER_FS_H_ +struct driver_dir_entry; +struct attribute; + +struct driverfs_ops { + int (*open)(struct driver_dir_entry *); + int (*close)(struct driver_dir_entry *); + ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t); + ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t); +}; + struct driver_dir_entry { char * name; struct dentry * dentry; mode_t mode; + struct driverfs_ops * ops; }; struct attribute { @@ -37,23 +48,6 @@ struct attribute { mode_t mode; }; -struct device; - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); -}; - -#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ - .show = _show, \ - .store = _store, \ -}; - -#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) - extern int driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); -- cgit v1.2.3