Commit 77057f5a authored by Patrick Mochel's avatar Patrick Mochel

driver model: convert devices to use kobjects and sysfs.

- Define a device subsystem and register it on startup. 
- Fill it in with fields converted from driverfs-style fields.
- Convert device_{create,remove}_file() to create files in sysfs. 
- Add default device attributes to device subsystem.
- Make sure devices get proper kobject familial pointers and that the kobjects
  are registered. 
 
parent b835de74
...@@ -23,7 +23,76 @@ DECLARE_MUTEX(device_sem); ...@@ -23,7 +23,76 @@ DECLARE_MUTEX(device_sem);
spinlock_t device_lock = SPIN_LOCK_UNLOCKED; spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
#define to_dev(node) container_of(node,struct device,driver_list) struct subsystem device_subsys;
#define to_dev(obj) container_of(obj,struct device,kobj)
/*
* sysfs bindings for devices.
*/
#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
extern struct attribute * dev_default_attrs[];
static ssize_t
dev_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf, size_t count, loff_t off)
{
struct device_attribute * dev_attr = to_dev_attr(attr);
struct device * dev = to_dev(kobj);
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 kobject * kobj, 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_dev(kobj);
ssize_t ret = 0;
if (dev_attr->store)
ret = dev_attr->store(dev,buf,count,off);
return ret;
}
static struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
struct subsystem device_subsys = {
.kobj = {
.name = "devices",
},
.sysfs_ops = &dev_sysfs_ops,
.default_attrs = dev_default_attrs,
};
int device_create_file(struct device * dev, struct device_attribute * attr)
{
int error = 0;
if (get_device(dev)) {
error = sysfs_create_file(&dev->kobj,&attr->attr);
put_device(dev);
}
return error;
}
void device_remove_file(struct device * dev, struct device_attribute * attr)
{
if (get_device(dev)) {
sysfs_remove_file(&dev->kobj,&attr->attr);
put_device(dev);
}
}
int device_add(struct device *dev) int device_add(struct device *dev)
{ {
...@@ -44,6 +113,12 @@ int device_add(struct device *dev) ...@@ -44,6 +113,12 @@ int device_add(struct device *dev)
pr_debug("DEV: registering device: ID = '%s', name = %s\n", pr_debug("DEV: registering device: ID = '%s', name = %s\n",
dev->bus_id, dev->name); dev->bus_id, dev->name);
strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN);
if (dev->parent)
dev->kobj.parent = &dev->parent->kobj;
dev->kobj.subsys = &device_subsys;
kobject_register(&dev->kobj);
if ((error = device_make_dir(dev))) if ((error = device_make_dir(dev)))
goto register_done; goto register_done;
...@@ -69,6 +144,7 @@ int device_add(struct device *dev) ...@@ -69,6 +144,7 @@ int device_add(struct device *dev)
void device_initialize(struct device *dev) void device_initialize(struct device *dev)
{ {
kobject_init(&dev->kobj);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list); INIT_LIST_HEAD(&dev->g_list);
...@@ -184,9 +260,17 @@ void device_unregister(struct device * dev) ...@@ -184,9 +260,17 @@ void device_unregister(struct device * dev)
pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
dev->bus_id,dev->name); dev->bus_id,dev->name);
kobject_unregister(&dev->kobj);
put_device(dev); put_device(dev);
} }
static int __init device_subsys_init(void)
{
return subsystem_register(&device_subsys);
}
core_initcall(device_subsys_init);
EXPORT_SYMBOL(device_register); EXPORT_SYMBOL(device_register);
EXPORT_SYMBOL(device_unregister); EXPORT_SYMBOL(device_unregister);
EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(get_device);
......
...@@ -21,97 +21,6 @@ static struct driver_dir_entry device_root_dir = { ...@@ -21,97 +21,6 @@ static struct driver_dir_entry device_root_dir = {
.mode = (S_IRWXU | S_IRUGO | S_IXUGO), .mode = (S_IRWXU | S_IRUGO | S_IXUGO),
}; };
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
* @entry: entry describing file
*
* Allocate space for file entry, copy descriptor, and create.
*/
int device_create_file(struct device * dev, struct device_attribute * entry)
{
int error = -EINVAL;
if (get_device(dev)) {
error = driverfs_create_file(&entry->attr,&dev->dir);
put_device(dev);
}
return error;
}
/**
* device_remove_file - remove a device's file by name
* @dev: device requesting removal
* @name: name of the file
*
*/
void device_remove_file(struct device * dev, struct device_attribute * attr)
{
if (dev) {
get_device(dev);
driverfs_remove_file(&dev->dir,attr->attr.name);
put_device(dev);
}
}
/** /**
* device_remove_dir - remove a device's directory * device_remove_dir - remove a device's directory
* @dev: device in question * @dev: device in question
...@@ -213,24 +122,12 @@ int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * p ...@@ -213,24 +122,12 @@ int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * p
int device_make_dir(struct device * dev) int device_make_dir(struct device * dev)
{ {
struct driver_dir_entry * parent; struct driver_dir_entry * parent;
struct device_attribute * entry;
int error; int error;
int i;
parent = dev->parent ? &dev->parent->dir : &device_root_dir; parent = dev->parent ? &dev->parent->dir : &device_root_dir;
dev->dir.name = dev->bus_id; dev->dir.name = dev->bus_id;
dev->dir.ops = &dev_attr_ops;
if ((error = device_create_dir(&dev->dir,parent))) return device_create_dir(&dev->dir,parent);
return error;
for (i = 0; (entry = *(device_default_files + i)); i++) {
if ((error = device_create_file(dev,entry))) {
device_remove_dir(dev);
break;
}
}
return error;
} }
static int device_driverfs_init(void) static int device_driverfs_init(void)
......
...@@ -88,8 +88,8 @@ device_write_power(struct device * dev, const char * buf, size_t count, loff_t o ...@@ -88,8 +88,8 @@ device_write_power(struct device * dev, const char * buf, size_t count, loff_t o
static DEVICE_ATTR(power,S_IWUSR | S_IRUGO, static DEVICE_ATTR(power,S_IWUSR | S_IRUGO,
device_read_power,device_write_power); device_read_power,device_write_power);
struct device_attribute * device_default_files[] = { struct attribute * dev_default_attrs[] = {
&dev_attr_name, &dev_attr_name.attr,
&dev_attr_power, &dev_attr_power.attr,
NULL, NULL,
}; };
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/driverfs_fs.h> #include <linux/driverfs_fs.h>
#include <linux/kobject.h>
#define DEVICE_NAME_SIZE 80 #define DEVICE_NAME_SIZE 80
#define DEVICE_ID_SIZE 32 #define DEVICE_ID_SIZE 32
...@@ -275,6 +276,7 @@ struct device { ...@@ -275,6 +276,7 @@ struct device {
struct list_head intf_list; struct list_head intf_list;
struct device * parent; struct device * parent;
struct kobject kobj;
char name[DEVICE_NAME_SIZE]; /* descriptive ascii string */ char name[DEVICE_NAME_SIZE]; /* descriptive ascii string */
char bus_id[BUS_ID_SIZE]; /* position on parent bus */ char bus_id[BUS_ID_SIZE]; /* position on parent bus */
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#ifndef _DRIVER_FS_H_ #ifndef _DRIVER_FS_H_
#define _DRIVER_FS_H_ #define _DRIVER_FS_H_
#include <linux/sysfs.h>
struct driver_dir_entry; struct driver_dir_entry;
struct attribute; struct attribute;
...@@ -43,11 +45,6 @@ struct driver_dir_entry { ...@@ -43,11 +45,6 @@ struct driver_dir_entry {
struct driverfs_ops * ops; struct driverfs_ops * ops;
}; };
struct attribute {
char * name;
mode_t mode;
};
extern int extern int
driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
......
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#define KOBJ_NAME_LEN 16
struct kobject { struct kobject {
char name[16]; char name[KOBJ_NAME_LEN];
atomic_t refcount; atomic_t refcount;
struct list_head entry; struct list_head entry;
struct kobject * parent; struct kobject * parent;
......
...@@ -9,20 +9,18 @@ ...@@ -9,20 +9,18 @@
#ifndef _SYSFS_H_ #ifndef _SYSFS_H_
#define _SYSFS_H_ #define _SYSFS_H_
struct driver_dir_entry;
struct attribute;
struct kobject; struct kobject;
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t);
};
struct attribute { struct attribute {
char * name; char * name;
mode_t mode; mode_t mode;
}; };
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t);
};
extern int extern int
sysfs_create_dir(struct kobject *); sysfs_create_dir(struct kobject *);
......
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