[RFC][PATCH 2.6.13-rc1] driver core: subclasses

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greg,

The below patch is a first pass at implementing subclasses, for review
and comment.

As a test, I modified drivers/input/input.c to allocate a new class,
and register it as a subclass.

Before:

/sys/class/input/
/sys/class/input_device/

After:
/sys/class/input/input_device/

In this pass I'm not exporting the subclass_register/unregister
functions, but am expecting callers to use the new
class_subclass_create() call, and older callers to continue using
class_create() which is now static inline.

Callers to class_create() are expected to call class_destroy() on the
subclasses before the parent class.

Feedback appreciated.

Signed-off-by: Matt Domsch <[email protected]>

Thanks,
Matt

-- 
Matt Domsch
Software Architect
Dell Linux Solutions linux.dell.com & www.dell.com/linux
Linux on Dell mailing lists @ http://lists.us.dell.com

--- linux-2.6/drivers/base/class.c	2005-07-06 14:19:37.000000000 -0400
+++ linux-2.6/drivers/base/class.c	2005-07-08 18:41:19.000000000 -0400
@@ -133,6 +133,26 @@ static void remove_class_attrs(struct cl
 	}
 }
 
+static int class_subclass_register(struct class *subclass)
+{
+	struct class *parent;
+
+	if (!subclass)
+		return -ENODEV;
+
+	parent = class_get(subclass->parent);
+	if (!parent)
+		return -EINVAL;
+
+	subclass->subsys.kset.kobj.parent = &parent->subsys.kset.kobj;
+
+	down(&parent->sem);
+	list_add_tail(&parent->subclasses, &subclass->subclass_node);
+	up(&parent->sem);
+
+	return 0;
+}
+
 int class_register(struct class * cls)
 {
 	int error;
@@ -141,6 +161,8 @@ int class_register(struct class * cls)
 
 	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->interfaces);
+	INIT_LIST_HEAD(&cls->subclasses);
+	INIT_LIST_HEAD(&cls->subclass_node);
 	init_MUTEX(&cls->sem);
 	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
 	if (error)
@@ -148,6 +170,7 @@ int class_register(struct class * cls)
 
 	subsys_set_kset(cls, class_subsys);
 
+	class_subclass_register(cls);
 	error = subsystem_register(&cls->subsys);
 	if (!error) {
 		error = add_class_attrs(class_get(cls));
@@ -156,10 +179,25 @@ int class_register(struct class * cls)
 	return error;
 }
 
+static void class_subclass_unregister(struct class *subclass)
+{
+	struct class *parent = subclass->parent;
+
+	if (!parent)
+		return;
+
+	down(&parent->sem);
+	list_del_init(&subclass->subclass_node);
+	subclass->parent = NULL;
+	up(&parent->sem);
+	class_put(parent);
+}
+
 void class_unregister(struct class * cls)
 {
 	pr_debug("device class '%s': unregistering\n", cls->name);
 	remove_class_attrs(cls);
+	class_subclass_unregister(cls);
 	subsystem_unregister(&cls->subsys);
 }
 
@@ -184,7 +222,7 @@ static void class_device_create_release(
  * Note, the pointer created here is to be destroyed when finished by
  * making a call to class_destroy().
  */
-struct class *class_create(struct module *owner, char *name)
+struct class *class_subclass_create(struct module *owner, char *name, struct class *parent)
 {
 	struct class *cls;
 	int retval;
@@ -200,6 +238,7 @@ struct class *class_create(struct module
 	cls->owner = owner;
 	cls->class_release = class_create_release;
 	cls->release = class_device_create_release;
+	cls->parent = parent;
 
 	retval = class_register(cls);
 	if (retval)
@@ -738,8 +777,8 @@ EXPORT_SYMBOL_GPL(class_register);
 EXPORT_SYMBOL_GPL(class_unregister);
 EXPORT_SYMBOL_GPL(class_get);
 EXPORT_SYMBOL_GPL(class_put);
-EXPORT_SYMBOL_GPL(class_create);
+EXPORT_SYMBOL_GPL(class_subclass_create);
 EXPORT_SYMBOL_GPL(class_destroy);
 
 EXPORT_SYMBOL_GPL(class_device_register);
--- linux-2.6/include/linux/device.h	2005-07-06 14:21:20.000000000 -0400
+++ linux-2.6-input/include/linux/device.h	2005-07-08 18:39:16.000000000 -0400
@@ -155,11 +155,14 @@ struct device * driver_find_device(struc
 struct class {
 	const char		* name;
 	struct module		* owner;
+	struct class            * parent; /* for subclasses */
 
 	struct subsystem	subsys;
-	struct list_head	children;
+	struct list_head	children; /* for class_devices */
 	struct list_head	interfaces;
-	struct semaphore	sem;	/* locks both the children and interfaces lists */
+	struct list_head	subclasses;
+	struct list_head	subclass_node; /* parent->sem held when accessing */
+	struct semaphore	sem;	/* locks children, subclasses, interfaces lists */
 
 	struct class_attribute		* class_attrs;
 	struct class_device_attribute	* class_dev_attrs;
@@ -258,7 +261,11 @@ struct class_interface {
 extern int class_interface_register(struct class_interface *);
 extern void class_interface_unregister(struct class_interface *);
 
-extern struct class *class_create(struct module *owner, char *name);
+extern struct class *class_subclass_create(struct module *owner, char *name, struct class *parent);
+static inline struct class *class_create(struct module *owner, char *name)
+{
+	return class_subclass_create(owner, name, NULL);
+}
 extern void class_destroy(struct class *cls);
 extern struct class_device *class_device_create(struct class *cls, dev_t devt,
 						struct device *device, char *fmt, ...)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux