From: John Lenz <lenz@cs.wisc.edu>
To: Greg KH <greg@kroah.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: Backlight and LCD module patches [2]
Date: Sun, 22 Aug 2004 23:07:30 +0000 [thread overview]
Message-ID: <1093216050l.8554l.1l@hydra> (raw)
In-Reply-To: <20040813232739.GB5063@kroah.com> (from greg@kroah.com on Fri Aug 13 18:27:40 2004)
[-- Attachment #1: Type: text/plain, Size: 329 bytes --]
On 08/13/04 18:27:40, Greg KH wrote:
>
> Care to provide a proposed implementation of this functionality?
Here is an updated patch. The only difference between the previous one
and this one was a broken continue; statement. I tried to continue the
outer loop from inside an inner loop. Instead I just use a goto.
[-- Attachment #2: class_match.patch --]
[-- Type: text/x-patch, Size: 9328 bytes --]
#
# Patch managed by http://www.holgerschurig.de/patcher.html
#
--- linux/include/linux/device.h~class_match
+++ linux/include/linux/device.h
@@ -147,6 +147,7 @@
struct subsystem subsys;
struct list_head children;
struct list_head interfaces;
+ struct list_head matches;
struct class_attribute * class_attrs;
struct class_device_attribute * class_dev_attrs;
@@ -187,6 +188,8 @@
void * class_data; /* class-specific data */
char class_id[BUS_ID_SIZE]; /* unique to this class */
+
+ struct list_head matched_classes;
};
static inline void *
@@ -240,6 +243,16 @@
extern int class_interface_register(struct class_interface *);
extern void class_interface_unregister(struct class_interface *);
+struct class_match {
+ struct class* class1;
+ struct class* class2;
+
+ int (*match)(struct class_device *dev1, struct class_device *dev2);
+};
+
+extern int class_match_register(struct class_match *match);
+extern void class_match_unregister(struct class_match *match);
+
/* interface for class simple stuff */
extern struct class_simple *class_simple_create(struct module *owner, char *name);
extern void class_simple_destroy(struct class_simple *cs);
@@ -248,6 +261,7 @@
extern int class_simple_set_hotplug(struct class_simple *,
int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size));
extern void class_simple_device_remove(dev_t dev);
+extern void class_simple_set_match(struct class_simple *cs, struct class_match *match, int location);
struct device {
--- linux/drivers/base/class_simple.c~class_match
+++ linux/drivers/base/class_simple.c
@@ -214,3 +214,13 @@
}
}
EXPORT_SYMBOL(class_simple_device_remove);
+
+extern void class_simple_set_match(struct class_simple *cs, struct class_match *match, int location)
+{
+ if (location == 1) {
+ match->class1 = &cs->class;
+ } else if (location == 2) {
+ match->class2 = &cs->class;
+ }
+}
+EXPORT_SYMBOL(class_simple_set_match);
--- linux/drivers/base/class.c~class_match
+++ linux/drivers/base/class.c
@@ -139,6 +139,7 @@
INIT_LIST_HEAD(&cls->children);
INIT_LIST_HEAD(&cls->interfaces);
+ INIT_LIST_HEAD(&cls->matches);
error = kobject_set_name(&cls->subsys.kset.kobj, cls->name);
if (error)
return error;
@@ -306,6 +307,134 @@
static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
+static spinlock_t class_match_lock = SPIN_LOCK_UNLOCKED;
+
+struct class_match_node {
+ struct class_match *match;
+ struct class_device *dev;
+ struct list_head node;
+};
+/* Makes the calls to class_match->match functions and connects devices together */
+static void class_match_check(struct class_device *dev)
+{
+ struct class *parent = dev->class;
+ struct class_match_node *match_node, *other_match_node;
+
+ struct class *other_class;
+ struct class_device *other_device;
+
+ int ret;
+
+ spin_lock(&class_match_lock);
+
+ down_read(&parent->subsys.rwsem);
+ list_for_each_entry(match_node, &parent->matches, node) {
+ /* call the match() function and try and match devices together */
+ if (parent == match_node->match->class1) {
+ other_class = match_node->match->class2;
+ } else if (parent == match_node->match->class2) {
+ other_class = match_node->match->class1;
+ } else {
+ other_class = NULL;
+ }
+
+ if (other_class) {
+ down_read(&other_class->subsys.rwsem);
+
+ list_for_each_entry(other_device, &other_class->children, node) {
+ /* first check if this device is already matched... */
+ list_for_each_entry(other_match_node, &other_device->matched_classes, node) {
+ if (other_match_node->match == match_node->match) {
+ goto already_matched;
+ }
+ }
+
+ /* now call the match function */
+ if (parent == match_node->match->class1) {
+ ret = match_node->match->match(dev, other_device);
+ } else {
+ ret = match_node->match->match(other_device, dev);
+ }
+ if (ret) {
+
+ /* now add this to the matched_classes lists */
+ other_match_node = (struct class_match_node *) kmalloc(sizeof(struct class_match_node), GFP_KERNEL);
+ if (other_match_node) {
+ other_match_node->dev = other_device;
+ other_match_node->match = match_node->match;
+
+ list_add_tail(&other_match_node->node, &dev->matched_classes);
+ sysfs_create_link(&dev->kobj, &other_device->kobj, other_class->name);
+ }
+
+ other_match_node = (struct class_match_node *) kmalloc(sizeof(struct class_match_node), GFP_KERNEL);
+ if (other_match_node) {
+ other_match_node->dev = dev;
+ other_match_node->match = match_node->match;
+
+ list_add_tail(&other_match_node->node, &other_device->matched_classes);
+ sysfs_create_link(&other_device->kobj, &dev->kobj, parent->name);
+ }
+
+ break;
+ }
+already_matched:;
+ }
+ up_read(&other_class->subsys.rwsem);
+ }
+ }
+ up_read(&parent->subsys.rwsem);
+
+ spin_unlock(&class_match_lock);
+}
+
+static void class_match_unlink(struct class_device *class_dev)
+{
+ struct class * parent = class_dev->class;
+ struct class_match_node *match_node, *other_match_node, *temp_match_node;
+ struct class *other_class;
+
+ spin_lock(&class_match_lock);
+
+ down_read(&parent->subsys.rwsem);
+
+ /* remove symlinks from devices matched to this device */
+ list_for_each_entry(match_node, &class_dev->matched_classes, node) {
+ if (parent == match_node->match->class1) {
+ other_class = match_node->match->class2;
+ } else if (parent == match_node->match->class2) {
+ other_class = match_node->match->class1;
+ } else {
+ /* should never happen */
+ other_class = NULL;
+ }
+ if (other_class) {
+ list_for_each_entry_safe(other_match_node, temp_match_node, &match_node->dev->matched_classes, node) {
+ if (match_node->match == other_match_node->match) {
+ list_del(&other_match_node->node);
+ kfree(other_match_node);
+ sysfs_remove_link(&match_node->dev->kobj, parent->name);
+ break;
+ }
+ }
+ }
+ }
+
+ /* free entries in matched_classes */
+ list_for_each_entry_safe(match_node, temp_match_node, &class_dev->matched_classes, node) {
+ list_del(&match_node->node);
+ if (parent == match_node->match->class1) {
+ sysfs_remove_link(&class_dev->kobj, match_node->match->class2->name);
+ } else {
+ sysfs_remove_link(&class_dev->kobj, match_node->match->class1->name);
+ }
+ kfree(match_node);
+ }
+
+ up_read(&parent->subsys.rwsem);
+
+ spin_unlock(&class_match_lock);
+}
static int class_device_add_attrs(struct class_device * cd)
{
@@ -345,6 +474,7 @@
kobj_set_kset_s(class_dev, class_obj_subsys);
kobject_init(&class_dev->kobj);
INIT_LIST_HEAD(&class_dev->node);
+ INIT_LIST_HEAD(&class_dev->matched_classes);
}
int class_device_add(struct class_device *class_dev)
@@ -378,6 +508,7 @@
if (class_intf->add)
class_intf->add(class_dev);
up_write(&parent->subsys.rwsem);
+ class_match_check(class_dev);
}
class_device_add_attrs(class_dev);
class_device_dev_link(class_dev);
@@ -408,6 +539,7 @@
if (class_intf->remove)
class_intf->remove(class_dev);
up_write(&parent->subsys.rwsem);
+ class_match_unlink(class_dev);
}
class_device_dev_unlink(class_dev);
@@ -505,7 +637,64 @@
class_put(parent);
}
+int class_match_register(struct class_match *match)
+{
+ struct class_match_node *match_node;
+
+ if (!match)
+ return -ENODEV;
+ if (!match->class1 || !match->class2)
+ return -ENODEV;
+ if (!match->match || match->class1 == match->class2)
+ return -EINVAL;
+ spin_lock(&class_match_lock);
+
+ match_node = (struct class_match_node *) kmalloc(sizeof(struct class_match_node), GFP_KERNEL);
+ if (match_node) {
+ match_node->match = match;
+ match_node->dev = NULL;
+ down_write(&match->class1->subsys.rwsem);
+ list_add_tail(&match_node->node, &match->class1->matches);
+ up_write(&match->class1->subsys.rwsem);
+ } else {
+ return -ENOMEM;
+ }
+
+ match_node = (struct class_match_node *) kmalloc(sizeof(struct class_match_node), GFP_KERNEL);
+ if (match_node) {
+ match_node->match = match;
+ match_node->dev = NULL;
+ down_write(&match->class2->subsys.rwsem);
+ list_add_tail(&match_node->node, &match->class2->matches);
+ up_write(&match->class2->subsys.rwsem);
+ } else {
+ return -ENOMEM;
+ }
+
+ spin_unlock(&class_match_lock);
+
+ return 0;
+}
+
+void class_match_unregister(struct class_match *match)
+{
+ struct class_device *class_dev;
+
+ if (!match)
+ return;
+ if (!match->class1 || !match->class2)
+ return;
+ if (!match->match || match->class1 == match->class2)
+ return;
+
+ /* we only need to call class_match_unlink on one of the class devices */
+
+ down_read(&match->class1->subsys.rwsem);
+ list_for_each_entry(class_dev, &match->class1->children, node)
+ class_match_unlink(class_dev);
+ up_read(&match->class1->subsys.rwsem);
+}
int __init classes_init(void)
{
@@ -542,3 +731,5 @@
EXPORT_SYMBOL(class_interface_register);
EXPORT_SYMBOL(class_interface_unregister);
+EXPORT_SYMBOL(class_match_register);
+EXPORT_SYMBOL(class_match_unregister);
prev parent reply other threads:[~2004-08-22 23:09 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-06-17 18:35 Backlight and LCD module patches [2] Andrew Zabolotny
2004-06-25 15:33 ` Pavel Machek
2004-07-25 21:59 ` John Lenz
2004-07-28 18:11 ` Andrew Zabolotny
2004-07-29 23:25 ` John Lenz
2004-07-30 0:06 ` Andrew Zabolotny
2004-07-30 0:49 ` John Lenz
2004-07-30 20:02 ` Andrew Zabolotny
2004-07-31 22:17 ` John Lenz
2004-08-01 17:37 ` Andrew Zabolotny
2004-08-13 23:27 ` Greg KH
2004-08-21 2:51 ` John Lenz
2004-09-05 15:00 ` Greg KH
2004-09-06 7:32 ` John Lenz
2004-08-22 23:07 ` John Lenz [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1093216050l.8554l.1l@hydra \
--to=lenz@cs.wisc.edu \
--cc=greg@kroah.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.