Messages in this thread Patch in this message | | | Date | Fri, 8 Jul 2005 17:54:48 -0500 | From | Matt Domsch <> | Subject | [RFC][PATCH 2.6.13-rc1] driver core: subclasses |
| |
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 <Matt_Domsch@dell.com>
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 majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |