summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2002-10-16 02:24:19 -0700
committerPatrick Mochel <mochel@osdl.org>2002-10-16 02:24:19 -0700
commit0447d4d59e85bb0c177fcc858a4fef8671a6cf04 (patch)
tree3f0f0d336635672d3d55396d844d3e09eccd8499
parent9af95a1093ae2ae41813ec5f2ca092dc9749af04 (diff)
parentba809e8ac59030f8b8c1822f0ce6b3161cabc60b (diff)
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
-rw-r--r--drivers/base/bus.c60
-rw-r--r--drivers/base/class.c36
-rw-r--r--drivers/base/core.c48
-rw-r--r--drivers/base/driver.c74
-rw-r--r--fs/driverfs/inode.c4
-rw-r--r--include/linux/device.h29
-rw-r--r--include/linux/driverfs_fs.h2
7 files changed, 151 insertions, 102 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 7daffbfd9913..559956c29763 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data,
int error = 0;
get_bus(bus);
- spin_lock(&device_lock);
+ down_write(&bus->rwsem);
list_for_each(node,&bus->devices) {
- struct device * dev = get_device_locked(to_dev(node));
+ struct device * dev = get_device(to_dev(node));
if (dev) {
- spin_unlock(&device_lock);
error = callback(dev,data);
if (prev)
put_device(prev);
prev = dev;
- spin_lock(&device_lock);
if (error)
break;
}
}
- spin_unlock(&device_lock);
if (prev)
put_device(prev);
+ up_write(&bus->rwsem);
put_bus(bus);
return error;
}
@@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
/* pin bus in memory */
get_bus(bus);
-
- spin_lock(&device_lock);
+ down_write(&bus->rwsem);
list_for_each(node,&bus->drivers) {
struct device_driver * drv = get_driver(to_drv(node));
if (drv) {
- spin_unlock(&device_lock);
error = callback(drv,data);
if (prev)
put_driver(prev);
prev = drv;
- spin_lock(&device_lock);
if (error)
break;
}
}
- spin_unlock(&device_lock);
if (prev)
put_driver(prev);
+ up_write(&bus->rwsem);
put_bus(bus);
return error;
}
@@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
int bus_add_device(struct device * dev)
{
if (dev->bus) {
+ down_write(&dev->bus->rwsem);
pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
get_bus(dev->bus);
- spin_lock(&device_lock);
list_add_tail(&dev->bus_list,&dev->bus->devices);
- spin_unlock(&device_lock);
+ up_write(&dev->bus->rwsem);
device_bus_link(dev);
}
return 0;
@@ -131,17 +126,43 @@ int bus_add_device(struct device * dev)
void bus_remove_device(struct device * dev)
{
if (dev->bus) {
+ down_write(&dev->bus->rwsem);
+ list_del_init(&dev->bus_list);
device_remove_symlink(&dev->bus->device_dir,dev->bus_id);
+ up_write(&dev->bus->rwsem);
put_bus(dev->bus);
}
}
+struct bus_type * get_bus(struct bus_type * bus)
+{
+ struct bus_type * ret = bus;
+ spin_lock(&device_lock);
+ if (bus && bus->present && atomic_read(&bus->refcount))
+ atomic_inc(&bus->refcount);
+ else
+ ret = NULL;
+ spin_unlock(&device_lock);
+ return ret;
+}
+
+void put_bus(struct bus_type * bus)
+{
+ if (!atomic_dec_and_lock(&bus->refcount,&device_lock))
+ return;
+ list_del_init(&bus->node);
+ spin_unlock(&device_lock);
+ BUG_ON(bus->present);
+ bus_remove_dir(bus);
+}
+
int bus_register(struct bus_type * bus)
{
- rwlock_init(&bus->lock);
+ init_rwsem(&bus->rwsem);
INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers);
atomic_set(&bus->refcount,2);
+ bus->present = 1;
spin_lock(&device_lock);
list_add_tail(&bus->node,&bus_driver_list);
@@ -156,13 +177,14 @@ int bus_register(struct bus_type * bus)
return 0;
}
-void put_bus(struct bus_type * bus)
+void bus_unregister(struct bus_type * bus)
{
- if (!atomic_dec_and_lock(&bus->refcount,&device_lock))
- return;
- list_del_init(&bus->node);
+ spin_lock(&device_lock);
+ bus->present = 0;
spin_unlock(&device_lock);
- bus_remove_dir(bus);
+
+ pr_debug("bus %s: unregistering\n",bus->name);
+ put_bus(bus);
}
EXPORT_SYMBOL(bus_for_each_dev);
@@ -170,4 +192,6 @@ EXPORT_SYMBOL(bus_for_each_drv);
EXPORT_SYMBOL(bus_add_device);
EXPORT_SYMBOL(bus_remove_device);
EXPORT_SYMBOL(bus_register);
+EXPORT_SYMBOL(bus_unregister);
+EXPORT_SYMBOL(get_bus);
EXPORT_SYMBOL(put_bus);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index dfef9793871a..3c7024cc3efb 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -81,29 +81,55 @@ void devclass_remove_device(struct device * dev)
}
}
+struct device_class * get_devclass(struct device_class * cls)
+{
+ struct device_class * ret = cls;
+ spin_lock(&device_lock);
+ if (cls && cls->present && atomic_read(&cls->refcount) > 0)
+ atomic_inc(&cls->refcount);
+ else
+ ret = NULL;
+ spin_unlock(&device_lock);
+ return ret;
+}
+
+void put_devclass(struct device_class * cls)
+{
+ if (atomic_dec_and_lock(&cls->refcount,&device_lock)) {
+ list_del_init(&cls->node);
+ spin_unlock(&device_lock);
+ devclass_remove_dir(cls);
+ }
+}
+
+
int devclass_register(struct device_class * cls)
{
INIT_LIST_HEAD(&cls->drivers);
INIT_LIST_HEAD(&cls->intf_list);
-
- pr_debug("registering device class '%s'\n",cls->name);
+ atomic_set(&cls->refcount,2);
+ cls->present = 1;
+ pr_debug("device class '%s': registering\n",cls->name);
spin_lock(&device_lock);
list_add_tail(&cls->node,&class_list);
spin_unlock(&device_lock);
devclass_make_dir(cls);
+ put_devclass(cls);
return 0;
}
void devclass_unregister(struct device_class * cls)
{
- pr_debug("unregistering device class '%s'\n",cls->name);
- devclass_remove_dir(cls);
spin_lock(&device_lock);
- list_del_init(&class_list);
+ cls->present = 0;
spin_unlock(&device_lock);
+ pr_debug("device class '%s': unregistering\n",cls->name);
+ put_devclass(cls);
}
EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister);
+EXPORT_SYMBOL(get_devclass);
+EXPORT_SYMBOL(put_devclass);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 83c31723d844..a1a41f4b0a07 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -259,34 +259,21 @@ struct device * get_device(struct device * dev)
*/
void put_device(struct device * dev)
{
- struct device * parent;
if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
return;
- parent = dev->parent;
- dev->parent = NULL;
+ list_del_init(&dev->node);
+ list_del_init(&dev->g_list);
+ list_del_init(&dev->driver_list);
spin_unlock(&device_lock);
BUG_ON(dev->present);
- if (dev->release)
- dev->release(dev);
-
- if (parent)
- put_device(parent);
+ device_del(dev);
}
void device_del(struct device * dev)
{
- spin_lock(&device_lock);
- dev->present = 0;
- list_del_init(&dev->node);
- list_del_init(&dev->g_list);
- list_del_init(&dev->bus_list);
- list_del_init(&dev->driver_list);
- spin_unlock(&device_lock);
-
- pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
- dev->bus_id,dev->name);
+ struct device * parent = dev->parent;
/* Notify the platform of the removal, in case they
* need to do anything...
@@ -302,6 +289,12 @@ void device_del(struct device * dev)
/* remove the driverfs directory */
device_remove_dir(dev);
+
+ if (dev->release)
+ dev->release(dev);
+
+ if (parent)
+ put_device(parent);
}
/**
@@ -315,22 +308,15 @@ void device_del(struct device * dev)
*/
void device_unregister(struct device * dev)
{
- device_del(dev);
- put_device(dev);
-}
-
-static int __init device_init(void)
-{
- int error;
+ spin_lock(&device_lock);
+ dev->present = 0;
+ spin_unlock(&device_lock);
- error = init_driverfs_fs();
- if (error)
- panic("DEV: could not initialize driverfs");
- return 0;
+ pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
+ dev->bus_id,dev->name);
+ put_device(dev);
}
-core_initcall(device_init);
-
EXPORT_SYMBOL(device_register);
EXPORT_SYMBOL(device_unregister);
EXPORT_SYMBOL(get_device);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 221e525736bd..b19b06201dd5 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -39,6 +39,43 @@ int driver_for_each_dev(struct device_driver * drv, void * data,
return error;
}
+struct device_driver * get_driver(struct device_driver * drv)
+{
+ struct device_driver * ret = drv;
+ spin_lock(&device_lock);
+ if (drv && drv->present && atomic_read(&drv->refcount) > 0)
+ atomic_inc(&drv->refcount);
+ else
+ ret = NULL;
+ spin_unlock(&device_lock);
+ return ret;
+}
+
+
+void remove_driver(struct device_driver * drv)
+{
+ BUG();
+}
+
+/**
+ * put_driver - decrement driver's refcount and clean up if necessary
+ * @drv: driver in question
+ */
+void put_driver(struct device_driver * drv)
+{
+ struct bus_type * bus = drv->bus;
+ if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
+ return;
+ list_del_init(&drv->bus_list);
+ spin_unlock(&device_lock);
+ BUG_ON(drv->present);
+ driver_detach(drv);
+ driver_remove_dir(drv);
+ if (drv->release)
+ drv->release(drv);
+ put_bus(bus);
+}
+
/**
* driver_register - register driver with bus
* @drv: driver to register
@@ -50,12 +87,13 @@ int driver_register(struct device_driver * drv)
if (!drv->bus)
return -EINVAL;
- pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name);
+ pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name);
get_bus(drv->bus);
atomic_set(&drv->refcount,2);
rwlock_init(&drv->lock);
INIT_LIST_HEAD(&drv->devices);
+ drv->present = 1;
spin_lock(&device_lock);
list_add(&drv->bus_list,&drv->bus->drivers);
spin_unlock(&device_lock);
@@ -65,39 +103,17 @@ int driver_register(struct device_driver * drv)
return 0;
}
-static void __remove_driver(struct device_driver * drv)
-{
- pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
- driver_detach(drv);
- driver_remove_dir(drv);
- if (drv->release)
- drv->release(drv);
- put_bus(drv->bus);
-}
-
-void remove_driver(struct device_driver * drv)
+void driver_unregister(struct device_driver * drv)
{
spin_lock(&device_lock);
- atomic_set(&drv->refcount,0);
- list_del_init(&drv->bus_list);
- spin_unlock(&device_lock);
- __remove_driver(drv);
-}
-
-/**
- * put_driver - decrement driver's refcount and clean up if necessary
- * @drv: driver in question
- */
-void put_driver(struct device_driver * drv)
-{
- if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
- return;
- list_del_init(&drv->bus_list);
+ drv->present = 0;
spin_unlock(&device_lock);
- __remove_driver(drv);
+ pr_debug("driver %s:%s: unregistering\n",drv->bus->name,drv->name);
+ put_driver(drv);
}
EXPORT_SYMBOL(driver_for_each_dev);
EXPORT_SYMBOL(driver_register);
+EXPORT_SYMBOL(driver_unregister);
+EXPORT_SYMBOL(get_driver);
EXPORT_SYMBOL(put_driver);
-EXPORT_SYMBOL(remove_driver);
diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c
index 0f35e27e669c..b4b5aa9f6a55 100644
--- a/fs/driverfs/inode.c
+++ b/fs/driverfs/inode.c
@@ -509,11 +509,13 @@ static void put_mount(void)
DBG("driverfs: mount_count = %d\n",mount_count);
}
-int __init init_driverfs_fs(void)
+static int __init driverfs_init(void)
{
return register_filesystem(&driverfs_fs_type);
}
+core_initcall(driverfs_init);
+
static struct dentry * get_dentry(struct dentry * parent, const char * name)
{
struct qstr qstr;
diff --git a/include/linux/device.h b/include/linux/device.h
index 80a63939f924..c0f8d6c5e4bf 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -54,8 +54,9 @@ struct device_class;
struct bus_type {
char * name;
- rwlock_t lock;
+ struct rw_semaphore rwsem;
atomic_t refcount;
+ u32 present;
struct list_head node;
struct list_head devices;
@@ -73,14 +74,9 @@ struct bus_type {
extern int bus_register(struct bus_type * bus);
+extern void bus_unregister(struct bus_type * bus);
-static inline struct bus_type * get_bus(struct bus_type * bus)
-{
- BUG_ON(!atomic_read(&bus->refcount));
- atomic_inc(&bus->refcount);
- return bus;
-}
-
+extern struct bus_type * get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus);
extern int bus_for_each_dev(struct bus_type * bus, void * data,
@@ -114,6 +110,7 @@ struct device_driver {
rwlock_t lock;
atomic_t refcount;
+ u32 present;
struct list_head bus_list;
struct list_head class_list;
@@ -131,16 +128,10 @@ struct device_driver {
};
-
extern int driver_register(struct device_driver * drv);
+extern void driver_unregister(struct device_driver * drv);
-static inline struct device_driver * get_driver(struct device_driver * drv)
-{
- BUG_ON(!atomic_read(&drv->refcount));
- atomic_inc(&drv->refcount);
- return drv;
-}
-
+extern struct device_driver * get_driver(struct device_driver * drv);
extern void put_driver(struct device_driver * drv);
extern void remove_driver(struct device_driver * drv);
@@ -172,6 +163,9 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
*/
struct device_class {
char * name;
+ atomic_t refcount;
+ u32 present;
+
u32 devnum;
struct list_head node;
@@ -189,6 +183,9 @@ struct device_class {
extern int devclass_register(struct device_class *);
extern void devclass_unregister(struct device_class *);
+extern struct device_class * get_devclass(struct device_class *);
+extern void put_devclass(struct device_class *);
+
struct devclass_attribute {
struct attribute attr;
diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h
index d859f8c2e041..b4270e947a1e 100644
--- a/include/linux/driverfs_fs.h
+++ b/include/linux/driverfs_fs.h
@@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent,
extern void
driverfs_remove_file(struct driver_dir_entry *, const char * name);
-extern int init_driverfs_fs(void);
-
#endif /* _DDFS_H_ */