Commit b47b46a3 authored by Patrick Mochel's avatar Patrick Mochel

driver model: make classes and interfaces use kobject infrastructure.

Like the other objects, this allows a decent bit of cleanup. Details include:

- use rwsem in subsytem, instead of one in struct device_class.

- use refcount in struct kobject, instead of one in struct device_class.

- kill class's present flag. 

- kill class_list, since we can just use class_subsys's. 

- make interfaces instances of their class's subsystem. This allows us to 
kill struct device_class::intf_list, and struct device_interface::node.
parent 63ae7a91
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* class.c - basic device class management * class.c - basic device class management
*/ */
#undef DEBUG
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -101,12 +103,12 @@ int devclass_add_driver(struct device_driver * drv) ...@@ -101,12 +103,12 @@ int devclass_add_driver(struct device_driver * drv)
{ {
struct device_class * cls = get_devclass(drv->devclass); struct device_class * cls = get_devclass(drv->devclass);
if (cls) { if (cls) {
down_write(&cls->rwsem); down_write(&cls->subsys.rwsem);
pr_debug("device class %s: adding driver %s:%s\n", pr_debug("device class %s: adding driver %s:%s\n",
cls->name,drv->bus->name,drv->name); cls->name,drv->bus->name,drv->name);
list_add_tail(&drv->class_list,&cls->drivers); list_add_tail(&drv->class_list,&cls->drivers);
devclass_drv_link(drv); devclass_drv_link(drv);
up_write(&cls->rwsem); up_write(&cls->subsys.rwsem);
} }
return 0; return 0;
} }
...@@ -115,12 +117,12 @@ void devclass_remove_driver(struct device_driver * drv) ...@@ -115,12 +117,12 @@ void devclass_remove_driver(struct device_driver * drv)
{ {
struct device_class * cls = drv->devclass; struct device_class * cls = drv->devclass;
if (cls) { if (cls) {
down_write(&cls->rwsem); down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing driver %s:%s\n", pr_debug("device class %s: removing driver %s:%s\n",
cls->name,drv->bus->name,drv->name); cls->name,drv->bus->name,drv->name);
list_del_init(&drv->class_list); list_del_init(&drv->class_list);
devclass_drv_unlink(drv); devclass_drv_unlink(drv);
up_write(&cls->rwsem); up_write(&cls->subsys.rwsem);
put_devclass(cls); put_devclass(cls);
} }
} }
...@@ -163,7 +165,7 @@ int devclass_add_device(struct device * dev) ...@@ -163,7 +165,7 @@ int devclass_add_device(struct device * dev)
if (dev->driver) { if (dev->driver) {
cls = get_devclass(dev->driver->devclass); cls = get_devclass(dev->driver->devclass);
if (cls) { if (cls) {
down_write(&cls->rwsem); down_write(&cls->subsys.rwsem);
pr_debug("device class %s: adding device %s\n", pr_debug("device class %s: adding device %s\n",
cls->name,dev->name); cls->name,dev->name);
if (cls->add_device) if (cls->add_device)
...@@ -176,7 +178,7 @@ int devclass_add_device(struct device * dev) ...@@ -176,7 +178,7 @@ int devclass_add_device(struct device * dev)
/* notify userspace (call /sbin/hotplug) */ /* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "add"); class_hotplug (dev, "add");
up_write(&cls->rwsem); up_write(&cls->subsys.rwsem);
if (error) if (error)
put_devclass(cls); put_devclass(cls);
} }
...@@ -191,7 +193,7 @@ void devclass_remove_device(struct device * dev) ...@@ -191,7 +193,7 @@ void devclass_remove_device(struct device * dev)
if (dev->driver) { if (dev->driver) {
cls = dev->driver->devclass; cls = dev->driver->devclass;
if (cls) { if (cls) {
down_write(&cls->rwsem); down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing device %s\n", pr_debug("device class %s: removing device %s\n",
cls->name,dev->name); cls->name,dev->name);
interface_remove(cls,dev); interface_remove(cls,dev);
...@@ -202,7 +204,7 @@ void devclass_remove_device(struct device * dev) ...@@ -202,7 +204,7 @@ void devclass_remove_device(struct device * dev)
if (cls->remove_device) if (cls->remove_device)
cls->remove_device(dev); cls->remove_device(dev);
up_write(&cls->rwsem); up_write(&cls->subsys.rwsem);
put_devclass(cls); put_devclass(cls);
} }
} }
...@@ -210,34 +212,20 @@ void devclass_remove_device(struct device * dev) ...@@ -210,34 +212,20 @@ void devclass_remove_device(struct device * dev)
struct device_class * get_devclass(struct device_class * cls) struct device_class * get_devclass(struct device_class * cls)
{ {
struct device_class * ret = cls; return cls ? container_of(subsys_get(&cls->subsys),struct device_class,subsys) : NULL;
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) void put_devclass(struct device_class * cls)
{ {
if (atomic_dec_and_lock(&cls->refcount,&device_lock)) { subsys_put(&cls->subsys);
list_del_init(&cls->node);
spin_unlock(&device_lock);
}
} }
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_rwsem(&cls->rwsem);
atomic_set(&cls->refcount,2);
cls->present = 1;
pr_debug("device class '%s': registering\n",cls->name);
pr_debug("device class '%s': registering\n",cls->name);
strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN); strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN);
cls->subsys.parent = &class_subsys; cls->subsys.parent = &class_subsys;
subsystem_register(&cls->subsys); subsystem_register(&cls->subsys);
...@@ -250,23 +238,15 @@ int devclass_register(struct device_class * cls) ...@@ -250,23 +238,15 @@ int devclass_register(struct device_class * cls)
cls->drvsubsys.parent = &cls->subsys; cls->drvsubsys.parent = &cls->subsys;
subsystem_register(&cls->drvsubsys); subsystem_register(&cls->drvsubsys);
spin_lock(&device_lock);
list_add_tail(&cls->node,&class_list);
spin_unlock(&device_lock);
put_devclass(cls);
return 0; return 0;
} }
void devclass_unregister(struct device_class * cls) void devclass_unregister(struct device_class * cls)
{ {
spin_lock(&device_lock);
cls->present = 0;
spin_unlock(&device_lock);
pr_debug("device class '%s': unregistering\n",cls->name); pr_debug("device class '%s': unregistering\n",cls->name);
subsystem_unregister(&cls->drvsubsys); subsystem_unregister(&cls->drvsubsys);
subsystem_unregister(&cls->devsubsys); subsystem_unregister(&cls->devsubsys);
subsystem_unregister(&cls->subsys); subsystem_unregister(&cls->subsys);
put_devclass(cls);
} }
static int __init class_subsys_init(void) static int __init class_subsys_init(void)
...@@ -276,6 +256,8 @@ static int __init class_subsys_init(void) ...@@ -276,6 +256,8 @@ static int __init class_subsys_init(void)
core_initcall(class_subsys_init); core_initcall(class_subsys_init);
EXPORT_SYMBOL(devclass_create_file);
EXPORT_SYMBOL(devclass_remove_file);
EXPORT_SYMBOL(devclass_register); EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister); EXPORT_SYMBOL(devclass_unregister);
EXPORT_SYMBOL(get_devclass); EXPORT_SYMBOL(get_devclass);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include "base.h" #include "base.h"
#define to_intf(node) container_of(node,struct device_interface,node) #define to_intf(node) container_of(node,struct device_interface,kobj.entry)
/** /**
* intf_dev_link - symlink from interface's directory to device's directory * intf_dev_link - symlink from interface's directory to device's directory
...@@ -34,22 +34,18 @@ static void intf_dev_unlink(struct intf_data * data) ...@@ -34,22 +34,18 @@ static void intf_dev_unlink(struct intf_data * data)
int interface_register(struct device_interface * intf) int interface_register(struct device_interface * intf)
{ {
struct device_class * cls = intf->devclass; struct device_class * cls = get_devclass(intf->devclass);
int error = 0;
if (cls) { if (cls) {
pr_debug("register interface '%s' with class '%s'\n", pr_debug("register interface '%s' with class '%s'\n",
intf->name,cls->name); intf->name,cls->name);
kobject_init(&intf->kobj);
strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN); strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN);
intf->kobj.subsys = &cls->subsys; intf->kobj.subsys = &cls->subsys;
kobject_register(&intf->kobj); kobject_register(&intf->kobj);
} else
spin_lock(&device_lock); error = -EINVAL;
list_add_tail(&intf->node,&cls->intf_list); return error;
spin_unlock(&device_lock);
return 0;
}
return -EINVAL;
} }
void interface_unregister(struct device_interface * intf) void interface_unregister(struct device_interface * intf)
...@@ -57,9 +53,6 @@ void interface_unregister(struct device_interface * intf) ...@@ -57,9 +53,6 @@ void interface_unregister(struct device_interface * intf)
pr_debug("unregistering interface '%s' from class '%s'\n", pr_debug("unregistering interface '%s' from class '%s'\n",
intf->name,intf->devclass->name); intf->name,intf->devclass->name);
kobject_unregister(&intf->kobj); kobject_unregister(&intf->kobj);
spin_lock(&device_lock);
list_del_init(&intf->node);
spin_unlock(&device_lock);
} }
int interface_add(struct device_class * cls, struct device * dev) int interface_add(struct device_class * cls, struct device * dev)
...@@ -69,7 +62,7 @@ int interface_add(struct device_class * cls, struct device * dev) ...@@ -69,7 +62,7 @@ int interface_add(struct device_class * cls, struct device * dev)
pr_debug("adding '%s' to %s class interfaces\n",dev->name,cls->name); pr_debug("adding '%s' to %s class interfaces\n",dev->name,cls->name);
list_for_each(node,&cls->intf_list) { list_for_each(node,&cls->subsys.list) {
struct device_interface * intf = to_intf(node); struct device_interface * intf = to_intf(node);
if (intf->add_device) { if (intf->add_device) {
error = intf->add_device(dev); error = intf->add_device(dev);
...@@ -89,30 +82,25 @@ void interface_remove(struct device_class * cls, struct device * dev) ...@@ -89,30 +82,25 @@ void interface_remove(struct device_class * cls, struct device * dev)
pr_debug("remove '%s' from %s class interfaces: ",dev->name,cls->name); pr_debug("remove '%s' from %s class interfaces: ",dev->name,cls->name);
spin_lock(&device_lock);
list_for_each_safe(node,next,&dev->intf_list) { list_for_each_safe(node,next,&dev->intf_list) {
struct intf_data * intf_data = container_of(node,struct intf_data,node); struct intf_data * intf_data = container_of(node,struct intf_data,node);
list_del_init(&intf_data->node); list_del_init(&intf_data->node);
spin_unlock(&device_lock);
intf_dev_unlink(intf_data); intf_dev_unlink(intf_data);
pr_debug("%s ",intf_data->intf->name); pr_debug("%s ",intf_data->intf->name);
if (intf_data->intf->remove_device) if (intf_data->intf->remove_device)
intf_data->intf->remove_device(intf_data); intf_data->intf->remove_device(intf_data);
spin_lock(&device_lock);
} }
spin_unlock(&device_lock);
pr_debug("\n"); pr_debug("\n");
} }
int interface_add_data(struct intf_data * data) int interface_add_data(struct intf_data * data)
{ {
spin_lock(&device_lock); down_write(&data->intf->devclass->subsys.rwsem);
list_add_tail(&data->node,&data->dev->intf_list); list_add_tail(&data->node,&data->dev->intf_list);
data->intf_num = ++data->intf->devnum; data->intf_num = data->intf->devnum++;
spin_unlock(&device_lock);
intf_dev_link(data); intf_dev_link(data);
up_write(&data->intf->devclass->subsys.rwsem);
return 0; return 0;
} }
......
...@@ -153,19 +153,12 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * ...@@ -153,19 +153,12 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
*/ */
struct device_class { struct device_class {
char * name; char * name;
struct rw_semaphore rwsem;
atomic_t refcount;
u32 present;
u32 devnum; u32 devnum;
struct subsystem subsys; struct subsystem subsys;
struct subsystem devsubsys; struct subsystem devsubsys;
struct subsystem drvsubsys; struct subsystem drvsubsys;
struct list_head node;
struct list_head drivers; struct list_head drivers;
struct list_head intf_list;
int (*add_device)(struct device *); int (*add_device)(struct device *);
void (*remove_device)(struct device *); void (*remove_device)(struct device *);
...@@ -215,7 +208,6 @@ struct device_interface { ...@@ -215,7 +208,6 @@ struct device_interface {
struct device_class * devclass; struct device_class * devclass;
struct kobject kobj; struct kobject kobj;
struct list_head node;
struct list_head devices; struct list_head devices;
u32 devnum; u32 devnum;
......
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