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 @@
* class.c - basic device class management
*/
#undef DEBUG
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
......@@ -101,12 +103,12 @@ int devclass_add_driver(struct device_driver * drv)
{
struct device_class * cls = get_devclass(drv->devclass);
if (cls) {
down_write(&cls->rwsem);
down_write(&cls->subsys.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);
up_write(&cls->subsys.rwsem);
}
return 0;
}
......@@ -115,12 +117,12 @@ void devclass_remove_driver(struct device_driver * drv)
{
struct device_class * cls = drv->devclass;
if (cls) {
down_write(&cls->rwsem);
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing driver %s:%s\n",
cls->name,drv->bus->name,drv->name);
list_del_init(&drv->class_list);
devclass_drv_unlink(drv);
up_write(&cls->rwsem);
up_write(&cls->subsys.rwsem);
put_devclass(cls);
}
}
......@@ -163,7 +165,7 @@ int devclass_add_device(struct device * dev)
if (dev->driver) {
cls = get_devclass(dev->driver->devclass);
if (cls) {
down_write(&cls->rwsem);
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: adding device %s\n",
cls->name,dev->name);
if (cls->add_device)
......@@ -176,7 +178,7 @@ int devclass_add_device(struct device * dev)
/* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "add");
up_write(&cls->rwsem);
up_write(&cls->subsys.rwsem);
if (error)
put_devclass(cls);
}
......@@ -191,7 +193,7 @@ void devclass_remove_device(struct device * dev)
if (dev->driver) {
cls = dev->driver->devclass;
if (cls) {
down_write(&cls->rwsem);
down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing device %s\n",
cls->name,dev->name);
interface_remove(cls,dev);
......@@ -202,7 +204,7 @@ void devclass_remove_device(struct device * dev)
if (cls->remove_device)
cls->remove_device(dev);
up_write(&cls->rwsem);
up_write(&cls->subsys.rwsem);
put_devclass(cls);
}
}
......@@ -210,34 +212,20 @@ 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;
return cls ? container_of(subsys_get(&cls->subsys),struct device_class,subsys) : NULL;
}
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);
}
subsys_put(&cls->subsys);
}
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);
pr_debug("device class '%s': registering\n",cls->name);
strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN);
cls->subsys.parent = &class_subsys;
subsystem_register(&cls->subsys);
......@@ -250,23 +238,15 @@ int devclass_register(struct device_class * cls)
cls->drvsubsys.parent = &cls->subsys;
subsystem_register(&cls->drvsubsys);
spin_lock(&device_lock);
list_add_tail(&cls->node,&class_list);
spin_unlock(&device_lock);
put_devclass(cls);
return 0;
}
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);
subsystem_unregister(&cls->drvsubsys);
subsystem_unregister(&cls->devsubsys);
subsystem_unregister(&cls->subsys);
put_devclass(cls);
}
static int __init class_subsys_init(void)
......@@ -276,6 +256,8 @@ static int __init class_subsys_init(void)
core_initcall(class_subsys_init);
EXPORT_SYMBOL(devclass_create_file);
EXPORT_SYMBOL(devclass_remove_file);
EXPORT_SYMBOL(devclass_register);
EXPORT_SYMBOL(devclass_unregister);
EXPORT_SYMBOL(get_devclass);
......
......@@ -10,7 +10,7 @@
#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
......@@ -34,22 +34,18 @@ static void intf_dev_unlink(struct intf_data * data)
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) {
pr_debug("register interface '%s' with class '%s'\n",
intf->name,cls->name);
kobject_init(&intf->kobj);
strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN);
intf->kobj.subsys = &cls->subsys;
kobject_register(&intf->kobj);
spin_lock(&device_lock);
list_add_tail(&intf->node,&cls->intf_list);
spin_unlock(&device_lock);
return 0;
}
return -EINVAL;
} else
error = -EINVAL;
return error;
}
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",
intf->name,intf->devclass->name);
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)
......@@ -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);
list_for_each(node,&cls->intf_list) {
list_for_each(node,&cls->subsys.list) {
struct device_interface * intf = to_intf(node);
if (intf->add_device) {
error = intf->add_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);
spin_lock(&device_lock);
list_for_each_safe(node,next,&dev->intf_list) {
struct intf_data * intf_data = container_of(node,struct intf_data,node);
list_del_init(&intf_data->node);
spin_unlock(&device_lock);
intf_dev_unlink(intf_data);
pr_debug("%s ",intf_data->intf->name);
if (intf_data->intf->remove_device)
intf_data->intf->remove_device(intf_data);
spin_lock(&device_lock);
}
spin_unlock(&device_lock);
pr_debug("\n");
}
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);
data->intf_num = ++data->intf->devnum;
spin_unlock(&device_lock);
data->intf_num = data->intf->devnum++;
intf_dev_link(data);
up_write(&data->intf->devclass->subsys.rwsem);
return 0;
}
......
......@@ -153,19 +153,12 @@ 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;
u32 devnum;
struct subsystem subsys;
struct subsystem devsubsys;
struct subsystem drvsubsys;
struct list_head node;
struct list_head drivers;
struct list_head intf_list;
int (*add_device)(struct device *);
void (*remove_device)(struct device *);
......@@ -215,7 +208,6 @@ struct device_interface {
struct device_class * devclass;
struct kobject kobj;
struct list_head node;
struct list_head devices;
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