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);
......
This diff is collapsed.
......@@ -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