Commit 0447d4d5 authored by Patrick Mochel's avatar Patrick Mochel

Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin

into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
parents 9af95a10 ba809e8a
...@@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data, ...@@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data,
int error = 0; int error = 0;
get_bus(bus); get_bus(bus);
spin_lock(&device_lock); down_write(&bus->rwsem);
list_for_each(node,&bus->devices) { 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) { if (dev) {
spin_unlock(&device_lock);
error = callback(dev,data); error = callback(dev,data);
if (prev) if (prev)
put_device(prev); put_device(prev);
prev = dev; prev = dev;
spin_lock(&device_lock);
if (error) if (error)
break; break;
} }
} }
spin_unlock(&device_lock);
if (prev) if (prev)
put_device(prev); put_device(prev);
up_write(&bus->rwsem);
put_bus(bus); put_bus(bus);
return error; return error;
} }
...@@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data, ...@@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
/* pin bus in memory */ /* pin bus in memory */
get_bus(bus); get_bus(bus);
down_write(&bus->rwsem);
spin_lock(&device_lock);
list_for_each(node,&bus->drivers) { list_for_each(node,&bus->drivers) {
struct device_driver * drv = get_driver(to_drv(node)); struct device_driver * drv = get_driver(to_drv(node));
if (drv) { if (drv) {
spin_unlock(&device_lock);
error = callback(drv,data); error = callback(drv,data);
if (prev) if (prev)
put_driver(prev); put_driver(prev);
prev = drv; prev = drv;
spin_lock(&device_lock);
if (error) if (error)
break; break;
} }
} }
spin_unlock(&device_lock);
if (prev) if (prev)
put_driver(prev); put_driver(prev);
up_write(&bus->rwsem);
put_bus(bus); put_bus(bus);
return error; return error;
} }
...@@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data, ...@@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
int bus_add_device(struct device * dev) int bus_add_device(struct device * dev)
{ {
if (dev->bus) { if (dev->bus) {
down_write(&dev->bus->rwsem);
pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
get_bus(dev->bus); get_bus(dev->bus);
spin_lock(&device_lock);
list_add_tail(&dev->bus_list,&dev->bus->devices); list_add_tail(&dev->bus_list,&dev->bus->devices);
spin_unlock(&device_lock); up_write(&dev->bus->rwsem);
device_bus_link(dev); device_bus_link(dev);
} }
return 0; return 0;
...@@ -131,17 +126,43 @@ int bus_add_device(struct device * dev) ...@@ -131,17 +126,43 @@ int bus_add_device(struct device * dev)
void bus_remove_device(struct device * dev) void bus_remove_device(struct device * dev)
{ {
if (dev->bus) { if (dev->bus) {
down_write(&dev->bus->rwsem);
list_del_init(&dev->bus_list);
device_remove_symlink(&dev->bus->device_dir,dev->bus_id); device_remove_symlink(&dev->bus->device_dir,dev->bus_id);
up_write(&dev->bus->rwsem);
put_bus(dev->bus); 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) int bus_register(struct bus_type * bus)
{ {
rwlock_init(&bus->lock); init_rwsem(&bus->rwsem);
INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers); INIT_LIST_HEAD(&bus->drivers);
atomic_set(&bus->refcount,2); atomic_set(&bus->refcount,2);
bus->present = 1;
spin_lock(&device_lock); spin_lock(&device_lock);
list_add_tail(&bus->node,&bus_driver_list); list_add_tail(&bus->node,&bus_driver_list);
...@@ -156,13 +177,14 @@ int bus_register(struct bus_type * bus) ...@@ -156,13 +177,14 @@ int bus_register(struct bus_type * bus)
return 0; 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)) spin_lock(&device_lock);
return; bus->present = 0;
list_del_init(&bus->node);
spin_unlock(&device_lock); 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); EXPORT_SYMBOL(bus_for_each_dev);
...@@ -170,4 +192,6 @@ EXPORT_SYMBOL(bus_for_each_drv); ...@@ -170,4 +192,6 @@ EXPORT_SYMBOL(bus_for_each_drv);
EXPORT_SYMBOL(bus_add_device); EXPORT_SYMBOL(bus_add_device);
EXPORT_SYMBOL(bus_remove_device); EXPORT_SYMBOL(bus_remove_device);
EXPORT_SYMBOL(bus_register); EXPORT_SYMBOL(bus_register);
EXPORT_SYMBOL(bus_unregister);
EXPORT_SYMBOL(get_bus);
EXPORT_SYMBOL(put_bus); EXPORT_SYMBOL(put_bus);
...@@ -81,29 +81,55 @@ void devclass_remove_device(struct device * dev) ...@@ -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) int devclass_register(struct device_class * cls)
{ {
INIT_LIST_HEAD(&cls->drivers); INIT_LIST_HEAD(&cls->drivers);
INIT_LIST_HEAD(&cls->intf_list); INIT_LIST_HEAD(&cls->intf_list);
atomic_set(&cls->refcount,2);
pr_debug("registering device class '%s'\n",cls->name); cls->present = 1;
pr_debug("device class '%s': registering\n",cls->name);
spin_lock(&device_lock); spin_lock(&device_lock);
list_add_tail(&cls->node,&class_list); list_add_tail(&cls->node,&class_list);
spin_unlock(&device_lock); spin_unlock(&device_lock);
devclass_make_dir(cls); devclass_make_dir(cls);
put_devclass(cls);
return 0; return 0;
} }
void devclass_unregister(struct device_class * cls) void devclass_unregister(struct device_class * cls)
{ {
pr_debug("unregistering device class '%s'\n",cls->name);
devclass_remove_dir(cls);
spin_lock(&device_lock); spin_lock(&device_lock);
list_del_init(&class_list); cls->present = 0;
spin_unlock(&device_lock); spin_unlock(&device_lock);
pr_debug("device class '%s': unregistering\n",cls->name);
put_devclass(cls);
} }
EXPORT_SYMBOL(devclass_register); EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister); EXPORT_SYMBOL(devclass_unregister);
EXPORT_SYMBOL(get_devclass);
EXPORT_SYMBOL(put_devclass);
...@@ -259,34 +259,21 @@ struct device * get_device(struct device * dev) ...@@ -259,34 +259,21 @@ struct device * get_device(struct device * dev)
*/ */
void put_device(struct device * dev) void put_device(struct device * dev)
{ {
struct device * parent;
if (!atomic_dec_and_lock(&dev->refcount,&device_lock)) if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
return; return;
parent = dev->parent; list_del_init(&dev->node);
dev->parent = NULL; list_del_init(&dev->g_list);
list_del_init(&dev->driver_list);
spin_unlock(&device_lock); spin_unlock(&device_lock);
BUG_ON(dev->present); BUG_ON(dev->present);
if (dev->release) device_del(dev);
dev->release(dev);
if (parent)
put_device(parent);
} }
void device_del(struct device * dev) void device_del(struct device * dev)
{ {
spin_lock(&device_lock); struct device * parent = dev->parent;
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);
/* Notify the platform of the removal, in case they /* Notify the platform of the removal, in case they
* need to do anything... * need to do anything...
...@@ -302,6 +289,12 @@ void device_del(struct device * dev) ...@@ -302,6 +289,12 @@ void device_del(struct device * dev)
/* remove the driverfs directory */ /* remove the driverfs directory */
device_remove_dir(dev); 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) ...@@ -315,22 +308,15 @@ void device_del(struct device * dev)
*/ */
void device_unregister(struct device * dev) void device_unregister(struct device * dev)
{ {
device_del(dev); spin_lock(&device_lock);
put_device(dev); dev->present = 0;
} spin_unlock(&device_lock);
static int __init device_init(void)
{
int error;
error = init_driverfs_fs(); pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
if (error) dev->bus_id,dev->name);
panic("DEV: could not initialize driverfs"); put_device(dev);
return 0;
} }
core_initcall(device_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);
......
...@@ -39,6 +39,43 @@ int driver_for_each_dev(struct device_driver * drv, void * data, ...@@ -39,6 +39,43 @@ int driver_for_each_dev(struct device_driver * drv, void * data,
return error; 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 * driver_register - register driver with bus
* @drv: driver to register * @drv: driver to register
...@@ -50,12 +87,13 @@ int driver_register(struct device_driver * drv) ...@@ -50,12 +87,13 @@ int driver_register(struct device_driver * drv)
if (!drv->bus) if (!drv->bus)
return -EINVAL; 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); get_bus(drv->bus);
atomic_set(&drv->refcount,2); atomic_set(&drv->refcount,2);
rwlock_init(&drv->lock); rwlock_init(&drv->lock);
INIT_LIST_HEAD(&drv->devices); INIT_LIST_HEAD(&drv->devices);
drv->present = 1;
spin_lock(&device_lock); spin_lock(&device_lock);
list_add(&drv->bus_list,&drv->bus->drivers); list_add(&drv->bus_list,&drv->bus->drivers);
spin_unlock(&device_lock); spin_unlock(&device_lock);
...@@ -65,39 +103,17 @@ int driver_register(struct device_driver * drv) ...@@ -65,39 +103,17 @@ int driver_register(struct device_driver * drv)
return 0; return 0;
} }
static void __remove_driver(struct device_driver * drv) void driver_unregister(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)
{ {
spin_lock(&device_lock); spin_lock(&device_lock);
atomic_set(&drv->refcount,0); drv->present = 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);
spin_unlock(&device_lock); 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_for_each_dev);
EXPORT_SYMBOL(driver_register); EXPORT_SYMBOL(driver_register);
EXPORT_SYMBOL(driver_unregister);
EXPORT_SYMBOL(get_driver);
EXPORT_SYMBOL(put_driver); EXPORT_SYMBOL(put_driver);
EXPORT_SYMBOL(remove_driver);
...@@ -509,11 +509,13 @@ static void put_mount(void) ...@@ -509,11 +509,13 @@ static void put_mount(void)
DBG("driverfs: mount_count = %d\n",mount_count); 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); return register_filesystem(&driverfs_fs_type);
} }
core_initcall(driverfs_init);
static struct dentry * get_dentry(struct dentry * parent, const char * name) static struct dentry * get_dentry(struct dentry * parent, const char * name)
{ {
struct qstr qstr; struct qstr qstr;
......
...@@ -54,8 +54,9 @@ struct device_class; ...@@ -54,8 +54,9 @@ struct device_class;
struct bus_type { struct bus_type {
char * name; char * name;
rwlock_t lock; struct rw_semaphore rwsem;
atomic_t refcount; atomic_t refcount;
u32 present;
struct list_head node; struct list_head node;
struct list_head devices; struct list_head devices;
...@@ -73,14 +74,9 @@ struct bus_type { ...@@ -73,14 +74,9 @@ struct bus_type {
extern int bus_register(struct bus_type * bus); 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) extern struct bus_type * get_bus(struct bus_type * bus);
{
BUG_ON(!atomic_read(&bus->refcount));
atomic_inc(&bus->refcount);
return bus;
}
extern void put_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, extern int bus_for_each_dev(struct bus_type * bus, void * data,
...@@ -114,6 +110,7 @@ struct device_driver { ...@@ -114,6 +110,7 @@ struct device_driver {
rwlock_t lock; rwlock_t lock;
atomic_t refcount; atomic_t refcount;
u32 present;
struct list_head bus_list; struct list_head bus_list;
struct list_head class_list; struct list_head class_list;
...@@ -131,16 +128,10 @@ struct device_driver { ...@@ -131,16 +128,10 @@ struct device_driver {
}; };
extern int driver_register(struct device_driver * drv); 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) extern struct device_driver * get_driver(struct device_driver * drv);
{
BUG_ON(!atomic_read(&drv->refcount));
atomic_inc(&drv->refcount);
return drv;
}
extern void put_driver(struct device_driver * drv); extern void put_driver(struct device_driver * drv);
extern void remove_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 * ...@@ -172,6 +163,9 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
*/ */
struct device_class { struct device_class {
char * name; char * name;
atomic_t refcount;
u32 present;
u32 devnum; u32 devnum;
struct list_head node; struct list_head node;
...@@ -189,6 +183,9 @@ struct device_class { ...@@ -189,6 +183,9 @@ struct device_class {
extern int devclass_register(struct device_class *); extern int devclass_register(struct device_class *);
extern void devclass_unregister(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 devclass_attribute {
struct attribute attr; struct attribute attr;
......
...@@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent, ...@@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent,
extern void extern void
driverfs_remove_file(struct driver_dir_entry *, const char * name); driverfs_remove_file(struct driver_dir_entry *, const char * name);
extern int init_driverfs_fs(void);
#endif /* _DDFS_H_ */ #endif /* _DDFS_H_ */
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