diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-10-15 21:26:48 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-10-15 21:26:48 -0700 |
| commit | 1067efac8c64c2608ececdca87e1329ba3ffa073 (patch) | |
| tree | 12ceffb169635b5ab96fdc6c228837029f94f4db | |
| parent | 2884fae053fb6a58f4f7c5985d574532b7ddd3d2 (diff) | |
driver model: change class reference counting to be like devices'.
device classes join the club of devices, buses, and drivers. They get a
->present flag, which is set on registration and cleared on unregistration.
They also get get_devclass() and put_devclass(), which, you guessed it,
bump the reference count. get_...() of course checks the present flag and
returns NULL if clear.
| -rw-r--r-- | drivers/base/class.c | 36 | ||||
| -rw-r--r-- | include/linux/device.h | 6 |
2 files changed, 37 insertions, 5 deletions
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/include/linux/device.h b/include/linux/device.h index 4b6b0cbe77ed..112fca2dd2d8 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -163,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; @@ -180,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; |
