public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
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);


      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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox