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 # Makefile for the Linux device tree
obj-y := core.o sys.o interface.o power.o bus.o \ 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 cpu.o firmware.o init.o
obj-$(CONFIG_NUMA) += node.o memblk.o obj-$(CONFIG_NUMA) += node.o memblk.o
obj-y += fs/
obj-$(CONFIG_HOTPLUG) += hotplug.o
extern struct semaphore device_sem; extern struct semaphore device_sem;
extern struct semaphore devclass_sem;
extern int bus_add_device(struct device * dev); extern int bus_add_device(struct device * dev);
extern void bus_remove_device(struct device * dev); extern void bus_remove_device(struct device * dev);
...@@ -7,22 +6,3 @@ 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 int bus_add_driver(struct device_driver *);
extern void bus_remove_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) ...@@ -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 * Walk the list of devices that the bus has on it and try to match
* the driver with each one. * the driver with each one.
* If bus_match() returns 0 and the @dev->driver is set, we've found * 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 * a compatible pair.
* device to the class.
* *
* Note that we ignore the error from bus_match(), since it's perfectly * Note that we ignore the error from bus_match(), since it's perfectly
* valid for a driver not to bind to any devices. * valid for a driver not to bind to any devices.
...@@ -328,8 +327,7 @@ static void driver_attach(struct device_driver * drv) ...@@ -328,8 +327,7 @@ static void driver_attach(struct device_driver * drv)
list_for_each(entry,&bus->devices.list) { list_for_each(entry,&bus->devices.list) {
struct device * dev = container_of(entry,struct device,bus_list); struct device * dev = container_of(entry,struct device,bus_list);
if (!dev->driver) { if (!dev->driver) {
if (!bus_match(dev,drv)) bus_match(dev,drv);
devclass_add_device(dev);
} }
} }
} }
...@@ -351,7 +349,6 @@ void device_release_driver(struct device * dev) ...@@ -351,7 +349,6 @@ void device_release_driver(struct device * dev)
if (drv) { if (drv) {
sysfs_remove_link(&drv->kobj,dev->kobj.name); sysfs_remove_link(&drv->kobj,dev->kobj.name);
list_del_init(&dev->driver_list); list_del_init(&dev->driver_list);
devclass_remove_device(dev);
if (drv->remove) if (drv->remove)
drv->remove(dev); drv->remove(dev);
dev->driver = NULL; dev->driver = NULL;
...@@ -443,8 +440,7 @@ int bus_add_driver(struct device_driver * drv) ...@@ -443,8 +440,7 @@ int bus_add_driver(struct device_driver * drv)
} }
down_write(&bus->subsys.rwsem); down_write(&bus->subsys.rwsem);
if (!(error = devclass_add_driver(drv))) driver_attach(drv);
driver_attach(drv);
up_write(&bus->subsys.rwsem); up_write(&bus->subsys.rwsem);
if (error) { if (error) {
...@@ -471,7 +467,6 @@ void bus_remove_driver(struct device_driver * drv) ...@@ -471,7 +467,6 @@ void bus_remove_driver(struct device_driver * drv)
down_write(&drv->bus->subsys.rwsem); down_write(&drv->bus->subsys.rwsem);
pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name); pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name);
driver_detach(drv); driver_detach(drv);
devclass_remove_driver(drv);
up_write(&drv->bus->subsys.rwsem); up_write(&drv->bus->subsys.rwsem);
kobject_unregister(&drv->kobj); kobject_unregister(&drv->kobj);
put_bus(drv->bus); put_bus(drv->bus);
......
This diff is collapsed.
...@@ -185,7 +185,6 @@ void device_initialize(struct device *dev) ...@@ -185,7 +185,6 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->driver_list);
INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->bus_list);
INIT_LIST_HEAD(&dev->class_list);
} }
/** /**
...@@ -235,7 +234,6 @@ int device_add(struct device *dev) ...@@ -235,7 +234,6 @@ int device_add(struct device *dev)
if (platform_notify) if (platform_notify)
platform_notify(dev); platform_notify(dev);
devclass_add_device(dev);
register_done: register_done:
if (error && parent) if (error && parent)
put_device(parent); put_device(parent);
......
...@@ -82,7 +82,6 @@ void put_driver(struct device_driver * drv) ...@@ -82,7 +82,6 @@ void put_driver(struct device_driver * drv)
int driver_register(struct device_driver * drv) int driver_register(struct device_driver * drv)
{ {
INIT_LIST_HEAD(&drv->devices); INIT_LIST_HEAD(&drv->devices);
INIT_LIST_HEAD(&drv->class_list);
init_MUTEX_LOCKED(&drv->unload_sem); init_MUTEX_LOCKED(&drv->unload_sem);
return bus_add_driver(drv); return bus_add_driver(drv);
} }
......
/* /*
* device.h - generic, centralized driver model * 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. * This is a relatively simple centralized driver model.
* The data structures were mainly lifted directly from the PCI * The data structures were mainly lifted directly from the PCI
...@@ -60,7 +60,8 @@ enum device_state { ...@@ -60,7 +60,8 @@ enum device_state {
struct device; struct device;
struct device_driver; struct device_driver;
struct device_class; struct class;
struct class_device;
struct bus_type { struct bus_type {
char * name; char * name;
...@@ -116,11 +117,9 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); ...@@ -116,11 +117,9 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
struct device_driver { struct device_driver {
char * name; char * name;
struct bus_type * bus; struct bus_type * bus;
struct device_class * devclass;
struct semaphore unload_sem; struct semaphore unload_sem;
struct kobject kobj; struct kobject kobj;
struct list_head class_list;
struct list_head devices; struct list_head devices;
int (*probe) (struct device * dev); int (*probe) (struct device * dev);
...@@ -160,74 +159,106 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * ...@@ -160,74 +159,106 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
/* /*
* device classes * device classes
*/ */
struct device_class { struct class {
char * name; char * name;
u32 devnum;
struct subsystem subsys; struct subsystem subsys;
struct kset devices; struct list_head children;
struct kset drivers; struct list_head interfaces;
int (*add_device)(struct device *); int (*hotplug)(struct class_device *dev, char **envp,
void (*remove_device)(struct device *);
int (*hotplug)(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size); int num_envp, char *buffer, int buffer_size);
}; };
extern int devclass_register(struct device_class *); extern int class_register(struct class *);
extern void devclass_unregister(struct device_class *); extern void class_unregister(struct class *);
extern struct device_class * get_devclass(struct device_class *); extern struct class * class_get(struct class *);
extern void put_devclass(struct device_class *); extern void class_put(struct class *);
struct devclass_attribute { struct class_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct device_class *, char * buf); ssize_t (*show)(struct class *, char * buf);
ssize_t (*store)(struct device_class *, const char * buf, size_t count); ssize_t (*store)(struct class *, const char * buf, size_t count);
}; };
#define DEVCLASS_ATTR(_name,_str,_mode,_show,_store) \ #define CLASS_ATTR(_name,_mode,_show,_store) \
struct devclass_attribute devclass_attr_##_name = { \ struct class_attribute class_attr_##_name = { \
.attr = {.name = _str, .mode = _mode }, \ .attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \ .show = _show, \
.store = _store, \ .store = _store, \
}; };
extern int devclass_create_file(struct device_class *, struct devclass_attribute *); extern int class_create_file(struct class *, struct class_attribute *);
extern void devclass_remove_file(struct device_class *, struct devclass_attribute *); extern void class_remove_file(struct class *, struct class_attribute *);
/* struct class_device {
* device interfaces struct list_head node;
* 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 device_interface { struct kobject kobj;
char * name; struct class * class; /* required */
struct device_class * devclass; struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */
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;
}
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, \
};
struct kset kset; extern int class_device_create_file(struct class_device *, struct class_device_attribute *);
u32 devnum; extern void class_device_remove_file(struct class_device *, struct class_device_attribute *);
int (*add_device) (struct device *);
int (*remove_device) (struct device *); struct class_interface {
struct list_head node;
struct class *class;
int (*add) (struct class_device *);
void (*remove) (struct class_device *);
}; };
extern int interface_register(struct device_interface *); extern int class_interface_register(struct class_interface *);
extern void interface_unregister(struct device_interface *); extern void class_interface_unregister(struct class_interface *);
struct device { struct device {
struct list_head node; /* node in sibling list */ struct list_head node; /* node in sibling list */
struct list_head bus_list; /* node in bus's list */ struct list_head bus_list; /* node in bus's list */
struct list_head class_list;
struct list_head driver_list; struct list_head driver_list;
struct list_head children; struct list_head children;
struct device * parent; struct device * parent;
...@@ -240,14 +271,10 @@ struct device { ...@@ -240,14 +271,10 @@ struct device {
struct device_driver *driver; /* which driver has allocated this struct device_driver *driver; /* which driver has allocated this
device */ device */
void *driver_data; /* data private to the driver */ 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, void *platform_data; /* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */ BIOS data relevant to device) */
u32 power_state; /* Current operating state. In u32 power_state; /* Current operating state. In
ACPI-speak, this is D0-D3, D0 ACPI-speak, this is D0-D3, D0
being fully functional, and D3 being fully functional, and D3
being off. */ being off. */
...@@ -347,6 +374,7 @@ struct sys_device { ...@@ -347,6 +374,7 @@ struct sys_device {
u32 id; u32 id;
struct sys_root * root; struct sys_root * root;
struct device dev; struct device dev;
struct class_device class_dev;
}; };
extern int sys_device_register(struct sys_device *); 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