Commit d9b24a11 authored by Patrick Mochel's avatar Patrick Mochel

driver model: add per-class rwsem and protect list accesses with it.

This is similar to struct bus_type's rwsem, though classes aren't doing 
anything nearly as fancy with it. We just make sure to take it when ever
we add or remove any devices or drivers. 
parent f21c8fc3
......@@ -10,27 +10,29 @@ static LIST_HEAD(class_list);
int devclass_add_driver(struct device_driver * drv)
{
if (drv->devclass) {
pr_debug("Registering driver %s:%s with class %s\n",
drv->bus->name,drv->name,drv->devclass->name);
spin_lock(&device_lock);
list_add_tail(&drv->class_list,&drv->devclass->drivers);
spin_unlock(&device_lock);
struct device_class * cls = get_devclass(drv->devclass);
if (cls) {
down_write(&cls->rwsem);
pr_debug("device class %s: adding driver %s:%s\n",
cls->name,drv->bus->name,drv->name);
list_add_tail(&drv->class_list,&cls->drivers);
devclass_drv_link(drv);
up_write(&cls->rwsem);
}
return 0;
}
void devclass_remove_driver(struct device_driver * drv)
{
if (drv->devclass) {
pr_debug("Removing driver %s:%s:%s\n",
drv->devclass->name,drv->bus->name,drv->name);
spin_lock(&device_lock);
struct device_class * cls = drv->devclass;
if (cls) {
down_write(&cls->rwsem);
pr_debug("device class %s: removing driver %s:%s\n",
cls->name,drv->bus->name,drv->name);
list_del_init(&drv->class_list);
spin_unlock(&device_lock);
devclass_drv_unlink(drv);
up_write(&cls->rwsem);
put_devclass(cls);
}
}
......@@ -38,9 +40,7 @@ void devclass_remove_driver(struct device_driver * drv)
static void enum_device(struct device_class * cls, struct device * dev)
{
u32 val;
spin_lock(&device_lock);
val = cls->devnum++;
spin_unlock(&device_lock);
dev->class_num = val;
devclass_dev_link(cls,dev);
}
......@@ -51,22 +51,44 @@ static void unenum_device(struct device_class * cls, struct device * dev)
dev->class_num = 0;
}
/**
* 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)
{
struct device_class * cls;
int error = 0;
if (dev->driver) {
cls = dev->driver->devclass;
cls = get_devclass(dev->driver->devclass);
if (cls) {
pr_debug("adding device '%s' to class '%s'\n",
dev->name,cls->name);
down_write(&cls->rwsem);
pr_debug("device class %s: adding device %s\n",
cls->name,dev->name);
if (cls->add_device)
error = cls->add_device(dev);
if (!error) {
enum_device(cls,dev);
interface_add(cls,dev);
}
/* notify userspace (call /sbin/hotplug) here */
up_write(&cls->rwsem);
if (error)
put_devclass(cls);
}
}
return error;
......@@ -74,14 +96,21 @@ int devclass_add_device(struct device * dev)
void devclass_remove_device(struct device * dev)
{
struct device_class * cls = dev->driver->devclass;
if (cls) {
pr_debug("removing device '%s' from class '%s'\n",
dev->name,cls->name);
interface_remove(cls,dev);
unenum_device(cls,dev);
if (cls->remove_device)
cls->remove_device(dev);
struct device_class * cls;
if (dev->driver) {
cls = dev->driver->devclass;
if (cls) {
down_write(&cls->rwsem);
pr_debug("device class %s: removing device %s\n",
cls->name,dev->name);
interface_remove(cls,dev);
unenum_device(cls,dev);
if (cls->remove_device)
cls->remove_device(dev);
up_write(&cls->rwsem);
put_devclass(cls);
}
}
}
......@@ -111,6 +140,7 @@ int devclass_register(struct device_class * cls)
{
INIT_LIST_HEAD(&cls->drivers);
INIT_LIST_HEAD(&cls->intf_list);
init_rwsem(&cls->rwsem);
atomic_set(&cls->refcount,2);
cls->present = 1;
pr_debug("device class '%s': registering\n",cls->name);
......
......@@ -163,6 +163,8 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
*/
struct device_class {
char * name;
struct rw_semaphore rwsem;
atomic_t refcount;
u32 present;
......
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