Commit 28926b3d authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

driver core: rework driver class structures and logic

Removes the device_class, devclass_attribute, and device_interface structures
and replaces them with class, class_device, and class_interface structures.

This allows us to have multiple class_device structures per device structures
which mirrors the ways things really are within the kernel.  It also allows 
class_device structures to be created later than struct devices as they
are naturally created much later in the initialization process of a device.
parent 5d4d8070
# Makefile for the Linux device tree
obj-y := core.o sys.o interface.o power.o bus.o \
driver.o class.o intf.o platform.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o
obj-$(CONFIG_NUMA) += node.o memblk.o
obj-y += fs/
obj-$(CONFIG_HOTPLUG) += hotplug.o
extern struct semaphore device_sem;
extern struct semaphore devclass_sem;
extern int bus_add_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
......@@ -7,22 +6,3 @@ extern void bus_remove_device(struct device * dev);
extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
extern int devclass_add_device(struct device *);
extern void devclass_remove_device(struct device *);
extern int devclass_add_driver(struct device_driver *);
extern void devclass_remove_driver(struct device_driver *);
extern int interface_add_dev(struct device *);
extern void interface_remove_dev(struct device *);
#ifdef CONFIG_HOTPLUG
extern int class_hotplug(struct device *dev, const char *action);
#else
static inline int class_hotplug(struct device *dev, const char *action)
{
return 0;
}
#endif
......@@ -311,8 +311,7 @@ static int device_attach(struct device * dev)
* Walk the list of devices that the bus has on it and try to match
* the driver with each one.
* If bus_match() returns 0 and the @dev->driver is set, we've found
* a compatible pair, so we call devclass_add_device() to add the
* device to the class.
* a compatible pair.
*
* Note that we ignore the error from bus_match(), since it's perfectly
* valid for a driver not to bind to any devices.
......@@ -328,8 +327,7 @@ static void driver_attach(struct device_driver * drv)
list_for_each(entry,&bus->devices.list) {
struct device * dev = container_of(entry,struct device,bus_list);
if (!dev->driver) {
if (!bus_match(dev,drv))
devclass_add_device(dev);
bus_match(dev,drv);
}
}
}
......@@ -351,7 +349,6 @@ void device_release_driver(struct device * dev)
if (drv) {
sysfs_remove_link(&drv->kobj,dev->kobj.name);
list_del_init(&dev->driver_list);
devclass_remove_device(dev);
if (drv->remove)
drv->remove(dev);
dev->driver = NULL;
......@@ -443,7 +440,6 @@ int bus_add_driver(struct device_driver * drv)
}
down_write(&bus->subsys.rwsem);
if (!(error = devclass_add_driver(drv)))
driver_attach(drv);
up_write(&bus->subsys.rwsem);
......@@ -471,7 +467,6 @@ void bus_remove_driver(struct device_driver * drv)
down_write(&drv->bus->subsys.rwsem);
pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name);
driver_detach(drv);
devclass_remove_driver(drv);
up_write(&drv->bus->subsys.rwsem);
kobject_unregister(&drv->kobj);
put_bus(drv->bus);
......
/*
* class.c - basic device class management
*
* Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
*/
#undef DEBUG
......@@ -10,16 +12,14 @@
#include <linux/string.h>
#include "base.h"
#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
#define to_class(obj) container_of(obj,struct device_class,subsys.kset.kobj)
DECLARE_MUTEX(devclass_sem);
#define to_class_attr(_attr) container_of(_attr,struct class_attribute,attr)
#define to_class(obj) container_of(obj,struct class,subsys.kset.kobj)
static ssize_t
devclass_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(kobj);
struct class_attribute * class_attr = to_class_attr(attr);
struct class * dc = to_class(kobj);
ssize_t ret = 0;
if (class_attr->show)
......@@ -28,11 +28,11 @@ devclass_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
}
static ssize_t
devclass_attr_store(struct kobject * kobj, struct attribute * attr,
class_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count)
{
struct devclass_attribute * class_attr = to_class_attr(attr);
struct device_class * dc = to_class(kobj);
struct class_attribute * class_attr = to_class_attr(attr);
struct class * dc = to_class(kobj);
ssize_t ret = 0;
if (class_attr->store)
......@@ -41,242 +41,376 @@ devclass_attr_store(struct kobject * kobj, struct attribute * attr,
}
static struct sysfs_ops class_sysfs_ops = {
.show = devclass_attr_show,
.store = devclass_attr_store,
.show = class_attr_show,
.store = class_attr_store,
};
static struct kobj_type ktype_devclass = {
static struct kobj_type ktype_class = {
.sysfs_ops = &class_sysfs_ops,
};
/* Classes can't use the kobject hotplug logic, as
* they do not add new kobjects to the system */
static decl_subsys(class,&ktype_devclass,NULL);
/* Hotplug events for classes go to the class_obj subsys */
static decl_subsys(class,&ktype_class,NULL);
static int devclass_dev_link(struct device_class * cls, struct device * dev)
int class_create_file(struct class * cls, struct class_attribute * attr)
{
char linkname[16];
snprintf(linkname,16,"%u",dev->class_num);
return sysfs_create_link(&cls->devices.kobj,&dev->kobj,linkname);
int error;
if (cls) {
error = sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr);
} else
error = -EINVAL;
return error;
}
static void devclass_dev_unlink(struct device_class * cls, struct device * dev)
void class_remove_file(struct class * cls, struct class_attribute * attr)
{
char linkname[16];
snprintf(linkname,16,"%u",dev->class_num);
sysfs_remove_link(&cls->devices.kobj,linkname);
if (cls)
sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr);
}
static int devclass_drv_link(struct device_driver * drv)
struct class * class_get(struct class * cls)
{
char name[KOBJ_NAME_LEN * 3];
snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
return sysfs_create_link(&drv->devclass->drivers.kobj,&drv->kobj,name);
if (cls)
return container_of(subsys_get(&cls->subsys),struct class,subsys);
return NULL;
}
static void devclass_drv_unlink(struct device_driver * drv)
void class_put(struct class * cls)
{
char name[KOBJ_NAME_LEN * 3];
snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
return sysfs_remove_link(&drv->devclass->drivers.kobj,name);
subsys_put(&cls->subsys);
}
int class_register(struct class * cls)
{
pr_debug("device class '%s': registering\n",cls->name);
INIT_LIST_HEAD(&cls->children);
INIT_LIST_HEAD(&cls->interfaces);
strncpy(cls->subsys.kset.kobj.name,cls->name,KOBJ_NAME_LEN);
subsys_set_kset(cls,class_subsys);
subsystem_register(&cls->subsys);
return 0;
}
int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr)
void class_unregister(struct class * cls)
{
int error;
if (cls) {
error = sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr);
} else
error = -EINVAL;
pr_debug("device class '%s': unregistering\n",cls->name);
subsystem_unregister(&cls->subsys);
}
/* Class Device Stuff */
int class_device_create_file(struct class_device * class_dev,
struct class_device_attribute * attr)
{
int error = -EINVAL;
if (class_dev)
error = sysfs_create_file(&class_dev->kobj, &attr->attr);
return error;
}
void devclass_remove_file(struct device_class * cls, struct devclass_attribute * attr)
void class_device_remove_file(struct class_device * class_dev,
struct class_device_attribute * attr)
{
if (cls)
sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr);
if (class_dev)
sysfs_remove_file(&class_dev->kobj, &attr->attr);
}
static int class_device_dev_link(struct class_device * class_dev)
{
if (class_dev->dev)
return sysfs_create_link(&class_dev->kobj,
&class_dev->dev->kobj, "device");
return 0;
}
int devclass_add_driver(struct device_driver * drv)
static void class_device_dev_unlink(struct class_device * class_dev)
{
struct device_class * cls = get_devclass(drv->devclass);
int error = 0;
if (class_dev->dev)
sysfs_remove_link(&class_dev->kobj, "device");
}
if (cls) {
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: adding driver %s:%s\n",
cls->name,drv->bus->name,drv->name);
error = devclass_drv_link(drv);
if (!error)
list_add_tail(&drv->class_list,&cls->drivers.list);
up_write(&cls->subsys.rwsem);
}
return error;
#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
#define to_class_dev_attr(_attr) container_of(_attr,struct class_device_attribute,attr)
static ssize_t
class_device_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf)
{
struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
struct class_device * cd = to_class_dev(kobj);
ssize_t ret = 0;
if (class_dev_attr->show)
ret = class_dev_attr->show(cd,buf);
return ret;
}
void devclass_remove_driver(struct device_driver * drv)
static ssize_t
class_device_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count)
{
struct device_class * cls = drv->devclass;
if (cls) {
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing driver %s:%s\n",
cls->name,drv->bus->name,drv->name);
list_del_init(&drv->class_list);
devclass_drv_unlink(drv);
up_write(&cls->subsys.rwsem);
put_devclass(cls);
}
struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
struct class_device * cd = to_class_dev(kobj);
ssize_t ret = 0;
if (class_dev_attr->store)
ret = class_dev_attr->store(cd,buf,count);
return ret;
}
static struct sysfs_ops class_dev_sysfs_ops = {
.show = class_device_attr_show,
.store = class_device_attr_store,
};
static struct kobj_type ktype_class_device = {
.sysfs_ops = &class_dev_sysfs_ops,
};
static void enum_device(struct device_class * cls, struct device * dev)
static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
{
u32 val;
val = cls->devnum++;
dev->class_num = val;
devclass_dev_link(cls,dev);
struct kobj_type *ktype = get_ktype(kobj);
if (ktype == &ktype_class_device) {
struct class_device *class_dev = to_class_dev(kobj);
if (class_dev->class)
return 1;
}
return 0;
}
static void unenum_device(struct device_class * cls, struct device * dev)
static char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
{
devclass_dev_unlink(cls,dev);
dev->class_num = 0;
struct class_device *class_dev = to_class_dev(kobj);
return class_dev->class->name;
}
/**
* devclass_add_device - register device with device class
* @dev: device to be registered
*
* This is called when a device is either registered with the
* core, or after the a driver module is loaded and bound to
* the device.
* The class is determined by looking at @dev's driver, so one
* way or another, it must be bound to something. Once the
* class is determined, it's set to prevent against concurrent
* calls for the same device stomping on each other.
*
* /sbin/hotplug should be called once the device is added to
* class and all the interfaces.
*/
int devclass_add_device(struct device * dev)
static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct device_class * cls;
int error = 0;
down(&devclass_sem);
if (dev->driver) {
cls = get_devclass(dev->driver->devclass);
if (!cls)
goto Done;
pr_debug("device class %s: adding device %s\n",
cls->name,dev->name);
if (cls->add_device)
error = cls->add_device(dev);
if (error) {
put_devclass(cls);
goto Done;
struct class_device *class_dev = to_class_dev(kobj);
int retval = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (class_dev->class->hotplug) {
/* have the bus specific function add its stuff */
retval = class_dev->class->hotplug (class_dev, envp, num_envp,
buffer, buffer_size);
if (retval) {
pr_debug ("%s - hotplug() returned %d\n",
__FUNCTION__, retval);
}
}
down_write(&cls->subsys.rwsem);
enum_device(cls,dev);
list_add_tail(&dev->class_list,&cls->devices.list);
/* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "add");
return retval;
}
up_write(&cls->subsys.rwsem);
static struct kset_hotplug_ops class_hotplug_ops = {
.filter = class_hotplug_filter,
.name = class_hotplug_name,
.hotplug = class_hotplug,
};
interface_add_dev(dev);
}
Done:
up(&devclass_sem);
return error;
static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
void class_device_initialize(struct class_device *class_dev)
{
kobject_init(&class_dev->kobj);
INIT_LIST_HEAD(&class_dev->node);
}
void devclass_remove_device(struct device * dev)
int class_device_add(struct class_device *class_dev)
{
struct device_class * cls;
struct class * parent;
struct class_interface * class_intf;
struct list_head * entry;
int error;
down(&devclass_sem);
if (dev->driver) {
cls = dev->driver->devclass;
if (!cls)
goto Done;
class_dev = class_device_get(class_dev);
if (!class_dev || !strlen(class_dev->class_id))
return -EINVAL;
parent = class_get(class_dev->class);
if (class_dev->dev)
get_device(class_dev->dev);
pr_debug("CLASS: registering class device: ID = '%s'\n",
class_dev->class_id);
/* first, register with generic layer. */
strncpy(class_dev->kobj.name, class_dev->class_id, KOBJ_NAME_LEN);
kobj_set_kset_s(class_dev, class_subsys);
kobj_set_kset_s(class_dev, class_obj_subsys);
if (parent)
class_dev->kobj.parent = &parent->subsys.kset.kobj;
if ((error = kobject_add(&class_dev->kobj)))
goto register_done;
/* now take care of our own registration */
if (parent) {
down_write(&parent->subsys.rwsem);
list_add_tail(&class_dev->node, &parent->children);
list_for_each(entry, &parent->interfaces) {
class_intf = container_of(entry, struct class_interface, node);
if (class_intf->add)
class_intf->add(class_dev);
}
up_write(&parent->subsys.rwsem);
}
interface_remove_dev(dev);
class_device_dev_link(class_dev);
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing device %s\n",
cls->name,dev->name);
register_done:
if (error && parent)
class_put(parent);
class_device_put(class_dev);
return error;
}
unenum_device(cls,dev);
int class_device_register(struct class_device *class_dev)
{
class_device_initialize(class_dev);
return class_device_add(class_dev);
}
list_del(&dev->class_list);
void class_device_del(struct class_device *class_dev)
{
struct class * parent = class_dev->class;
struct class_interface * class_intf;
struct list_head * entry;
if (parent) {
down_write(&parent->subsys.rwsem);
list_del_init(&class_dev->node);
list_for_each(entry, &parent->interfaces) {
class_intf = container_of(entry, struct class_interface, node);
if (class_intf->remove)
class_intf->remove(class_dev);
}
up_write(&parent->subsys.rwsem);
}
/* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "remove");
if (class_dev->dev) {
class_device_dev_unlink(class_dev);
put_device(class_dev->dev);
}
up_write(&cls->subsys.rwsem);
kobject_del(&class_dev->kobj);
if (cls->remove_device)
cls->remove_device(dev);
put_devclass(cls);
}
Done:
up(&devclass_sem);
if (parent)
class_put(parent);
}
struct device_class * get_devclass(struct device_class * cls)
void class_device_unregister(struct class_device *class_dev)
{
return cls ? container_of(subsys_get(&cls->subsys),struct device_class,subsys) : NULL;
pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
class_dev->class_id);
class_device_del(class_dev);
class_device_put(class_dev);
}
void put_devclass(struct device_class * cls)
struct class_device * class_device_get(struct class_device *class_dev)
{
subsys_put(&cls->subsys);
if (class_dev)
return to_class_dev(kobject_get(&class_dev->kobj));
return NULL;
}
void class_device_put(struct class_device *class_dev)
{
kobject_put(&class_dev->kobj);
}
int devclass_register(struct device_class * cls)
int class_interface_register(struct class_interface *class_intf)
{
pr_debug("device class '%s': registering\n",cls->name);
strncpy(cls->subsys.kset.kobj.name,cls->name,KOBJ_NAME_LEN);
subsys_set_kset(cls,class_subsys);
subsystem_register(&cls->subsys);
struct class * parent;
struct class_device * class_dev;
struct list_head * entry;
snprintf(cls->devices.kobj.name,KOBJ_NAME_LEN,"devices");
cls->devices.subsys = &cls->subsys;
kset_register(&cls->devices);
if (!class_intf || !class_intf->class)
return -ENODEV;
snprintf(cls->drivers.kobj.name,KOBJ_NAME_LEN,"drivers");
cls->drivers.subsys = &cls->subsys;
kset_register(&cls->drivers);
parent = class_get(class_intf->class);
if (!parent)
return -EINVAL;
down_write(&parent->subsys.rwsem);
list_add_tail(&class_intf->node, &parent->interfaces);
if (class_intf->add) {
list_for_each(entry, &parent->children) {
class_dev = container_of(entry, struct class_device, node);
class_intf->add(class_dev);
}
}
up_write(&parent->subsys.rwsem);
return 0;
}
void devclass_unregister(struct device_class * cls)
void class_interface_unregister(struct class_interface *class_intf)
{
pr_debug("device class '%s': unregistering\n",cls->name);
kset_unregister(&cls->drivers);
kset_unregister(&cls->devices);
subsystem_unregister(&cls->subsys);
struct class * parent = class_intf->class;
struct list_head * entry;
if (!parent)
return;
down_write(&parent->subsys.rwsem);
list_del_init(&class_intf->node);
if (class_intf->remove) {
list_for_each(entry, &parent->children) {
struct class_device *class_dev = container_of(entry, struct class_device, node);
class_intf->remove(class_dev);
}
}
up_write(&parent->subsys.rwsem);
class_put(parent);
}
int __init classes_init(void)
{
return subsystem_register(&class_subsys);
}
int retval;
EXPORT_SYMBOL(devclass_create_file);
EXPORT_SYMBOL(devclass_remove_file);
EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister);
EXPORT_SYMBOL(get_devclass);
EXPORT_SYMBOL(put_devclass);
retval = subsystem_register(&class_subsys);
if (retval)
return retval;
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs... */
subsystem_init(&class_obj_subsys);
if (!class_obj_subsys.kset.subsys)
class_obj_subsys.kset.subsys = &class_obj_subsys;
return 0;
}
EXPORT_SYMBOL(class_create_file);
EXPORT_SYMBOL(class_remove_file);
EXPORT_SYMBOL(class_register);
EXPORT_SYMBOL(class_unregister);
EXPORT_SYMBOL(class_get);
EXPORT_SYMBOL(class_put);
EXPORT_SYMBOL(class_device_register);
EXPORT_SYMBOL(class_device_unregister);
EXPORT_SYMBOL(class_device_initialize);
EXPORT_SYMBOL(class_device_add);
EXPORT_SYMBOL(class_device_del);
EXPORT_SYMBOL(class_device_get);
EXPORT_SYMBOL(class_device_put);
EXPORT_SYMBOL(class_device_create_file);
EXPORT_SYMBOL(class_device_remove_file);
EXPORT_SYMBOL(class_interface_register);
EXPORT_SYMBOL(class_interface_unregister);
......@@ -185,7 +185,6 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->driver_list);
INIT_LIST_HEAD(&dev->bus_list);
INIT_LIST_HEAD(&dev->class_list);
}
/**
......@@ -235,7 +234,6 @@ int device_add(struct device *dev)
if (platform_notify)
platform_notify(dev);
devclass_add_device(dev);
register_done:
if (error && parent)
put_device(parent);
......
......@@ -82,7 +82,6 @@ void put_driver(struct device_driver * drv)
int driver_register(struct device_driver * drv)
{
INIT_LIST_HEAD(&drv->devices);
INIT_LIST_HEAD(&drv->class_list);
init_MUTEX_LOCKED(&drv->unload_sem);
return bus_add_driver(drv);
}
......
/*
* device.h - generic, centralized driver model
*
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
* Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
*
* This is a relatively simple centralized driver model.
* The data structures were mainly lifted directly from the PCI
......@@ -60,7 +60,8 @@ enum device_state {
struct device;
struct device_driver;
struct device_class;
struct class;
struct class_device;
struct bus_type {
char * name;
......@@ -116,11 +117,9 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
struct device_driver {
char * name;
struct bus_type * bus;
struct device_class * devclass;
struct semaphore unload_sem;
struct kobject kobj;
struct list_head class_list;
struct list_head devices;
int (*probe) (struct device * dev);
......@@ -160,74 +159,106 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
/*
* device classes
*/
struct device_class {
struct class {
char * name;
u32 devnum;
struct subsystem subsys;
struct kset devices;
struct kset drivers;
struct list_head children;
struct list_head interfaces;
int (*add_device)(struct device *);
void (*remove_device)(struct device *);
int (*hotplug)(struct device *dev, char **envp,
int (*hotplug)(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
};
extern int devclass_register(struct device_class *);
extern void devclass_unregister(struct device_class *);
extern int class_register(struct class *);
extern void class_unregister(struct class *);
extern struct device_class * get_devclass(struct device_class *);
extern void put_devclass(struct device_class *);
extern struct class * class_get(struct class *);
extern void class_put(struct class *);
struct devclass_attribute {
struct class_attribute {
struct attribute attr;
ssize_t (*show)(struct device_class *, char * buf);
ssize_t (*store)(struct device_class *, const char * buf, size_t count);
ssize_t (*show)(struct class *, char * buf);
ssize_t (*store)(struct class *, const char * buf, size_t count);
};
#define DEVCLASS_ATTR(_name,_str,_mode,_show,_store) \
struct devclass_attribute devclass_attr_##_name = { \
.attr = {.name = _str, .mode = _mode }, \
#define CLASS_ATTR(_name,_mode,_show,_store) \
struct class_attribute class_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
};
extern int devclass_create_file(struct device_class *, struct devclass_attribute *);
extern void devclass_remove_file(struct device_class *, struct devclass_attribute *);
extern int class_create_file(struct class *, struct class_attribute *);
extern void class_remove_file(struct class *, struct class_attribute *);
/*
* device interfaces
* These are the logical interfaces of device classes.
* These entities map directly to specific userspace interfaces, like
* device nodes.
* Interfaces are registered with the device class they belong to. When
* a device is registered with the class, each interface's add_device
* callback is called. It is up to the interface to decide whether or not
* it supports the device.
*/
struct class_device {
struct list_head node;
struct device_interface {
char * name;
struct device_class * devclass;
struct kobject kobj;
struct class * class; /* required */
struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */
struct kset kset;
u32 devnum;
char class_id[BUS_ID_SIZE]; /* unique to this class */
};
static inline void *
class_get_devdata (struct class_device *dev)
{
return dev->class_data;
}
static inline void
class_set_devdata (struct class_device *dev, void *data)
{
dev->class_data = data;
}
int (*add_device) (struct device *);
int (*remove_device) (struct device *);
extern int class_device_register(struct class_device *);
extern void class_device_unregister(struct class_device *);
extern void class_device_initialize(struct class_device *);
extern int class_device_add(struct class_device *);
extern void class_device_del(struct class_device *);
extern struct class_device * class_device_get(struct class_device *);
extern void class_device_put(struct class_device *);
struct class_device_attribute {
struct attribute attr;
ssize_t (*show)(struct class_device *, char * buf);
ssize_t (*store)(struct class_device *, const char * buf, size_t count);
};
#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute class_device_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
};
extern int interface_register(struct device_interface *);
extern void interface_unregister(struct device_interface *);
extern int class_device_create_file(struct class_device *, struct class_device_attribute *);
extern void class_device_remove_file(struct class_device *, struct class_device_attribute *);
struct class_interface {
struct list_head node;
struct class *class;
int (*add) (struct class_device *);
void (*remove) (struct class_device *);
};
extern int class_interface_register(struct class_interface *);
extern void class_interface_unregister(struct class_interface *);
struct device {
struct list_head node; /* node in sibling list */
struct list_head bus_list; /* node in bus's list */
struct list_head class_list;
struct list_head driver_list;
struct list_head children;
struct device * parent;
......@@ -240,10 +271,6 @@ struct device {
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
u32 class_num; /* class-enumerated value */
void * class_data; /* class-specific data */
void *platform_data; /* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */
......@@ -347,6 +374,7 @@ struct sys_device {
u32 id;
struct sys_root * root;
struct device dev;
struct class_device class_dev;
};
extern int sys_device_register(struct sys_device *);
......
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