+ revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device.patch added to -mm tree

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

 



The patch titled
     revert gregkh-driver-driver-core-remove-no-longer-used-struct-class_device
has been added to the -mm tree.  Its filename is
     revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: revert gregkh-driver-driver-core-remove-no-longer-used-struct-class_device
From: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>

This breaks git-scsi-misc.

Cc: Kai Makisara <kai.makisara@xxxxxxxxxxx>
Cc: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx>
Cc: Greg KH <greg@xxxxxxxxx>
Cc: Tony Jones <tonyj@xxxxxxx>
Cc: Stephen Rothwell <sfr@xxxxxxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
---

 drivers/base/base.h    |   11 
 drivers/base/class.c   |  638 ++++++++++++++++++++++++++++++++++++++-
 include/linux/device.h |   97 +++++
 3 files changed, 745 insertions(+), 1 deletion(-)

diff -puN drivers/base/base.h~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device drivers/base/base.h
--- a/drivers/base/base.h~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device
+++ a/drivers/base/base.h
@@ -64,6 +64,17 @@ extern void sysdev_shutdown(void);
 extern int sysdev_suspend(pm_message_t state);
 extern int sysdev_resume(void);
 
+static inline struct class_device *to_class_dev(struct kobject *obj)
+{
+	return container_of(obj, struct class_device, kobj);
+}
+
+static inline
+struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
+{
+	return container_of(_attr, struct class_device_attribute, attr);
+}
+
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
diff -puN drivers/base/class.c~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device drivers/base/class.c
--- a/drivers/base/class.c~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device
+++ a/drivers/base/class.c
@@ -179,13 +179,27 @@ static void class_create_release(struct 
 	kfree(cls);
 }
 
+static void class_device_create_release(struct class_device *class_dev)
+{
+	pr_debug("%s called for %s\n", __func__, class_dev->class_id);
+	kfree(class_dev);
+}
+
+/* needed to allow these devices to have parent class devices */
+static int class_device_create_uevent(struct class_device *class_dev,
+				      struct kobj_uevent_env *env)
+{
+	pr_debug("%s called for %s\n", __func__, class_dev->class_id);
+	return 0;
+}
+
 /**
  * class_create - create a struct class structure
  * @owner: pointer to the module that is to "own" this struct class
  * @name: pointer to a string for the name of this class.
  *
  * This is used to create a struct class pointer that can then be used
- * in calls to device_create().
+ * in calls to class_device_create().
  *
  * Note, the pointer created here is to be destroyed when finished by
  * making a call to class_destroy().
@@ -204,6 +218,7 @@ struct class *class_create(struct module
 	cls->name = name;
 	cls->owner = owner;
 	cls->class_release = class_create_release;
+	cls->release = class_device_create_release;
 
 	retval = class_register(cls);
 	if (retval)
@@ -231,6 +246,113 @@ void class_destroy(struct class *cls)
 	class_unregister(cls);
 }
 
+/* Class Device Stuff */
+
+int class_device_create_file(struct class_device *class_dev,
+			     const struct class_device_attribute *attr)
+{
+	int error = -EINVAL;
+	if (class_dev)
+		error = sysfs_create_file(&class_dev->kobj, &attr->attr);
+	return error;
+}
+
+void class_device_remove_file(struct class_device *class_dev,
+			      const struct class_device_attribute *attr)
+{
+	if (class_dev)
+		sysfs_remove_file(&class_dev->kobj, &attr->attr);
+}
+
+int class_device_create_bin_file(struct class_device *class_dev,
+				 struct bin_attribute *attr)
+{
+	int error = -EINVAL;
+	if (class_dev)
+		error = sysfs_create_bin_file(&class_dev->kobj, attr);
+	return error;
+}
+
+void class_device_remove_bin_file(struct class_device *class_dev,
+				  struct bin_attribute *attr)
+{
+	if (class_dev)
+		sysfs_remove_bin_file(&class_dev->kobj, attr);
+}
+
+static ssize_t class_device_attr_show(struct kobject *kobj,
+				      struct attribute *attr, char *buf)
+{
+	struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+	struct class_device *cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->show)
+		ret = class_dev_attr->show(cd, buf);
+	return ret;
+}
+
+static ssize_t class_device_attr_store(struct kobject *kobj,
+				       struct attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+	struct class_device *cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->store)
+		ret = class_dev_attr->store(cd, buf, count);
+	return ret;
+}
+
+static struct sysfs_ops class_dev_sysfs_ops = {
+	.show	= class_device_attr_show,
+	.store	= class_device_attr_store,
+};
+
+static void class_dev_release(struct kobject *kobj)
+{
+	struct class_device *cd = to_class_dev(kobj);
+	struct class *cls = cd->class;
+
+	pr_debug("device class '%s': release.\n", cd->class_id);
+
+	if (cd->release)
+		cd->release(cd);
+	else if (cls->release)
+		cls->release(cd);
+	else {
+		printk(KERN_ERR "Class Device '%s' does not have a release() "
+			"function, it is broken and must be fixed.\n",
+			cd->class_id);
+		WARN_ON(1);
+	}
+}
+
+static struct kobj_type class_device_ktype = {
+	.sysfs_ops	= &class_dev_sysfs_ops,
+	.release	= class_dev_release,
+};
+
+static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	if (ktype == &class_device_ktype) {
+		struct class_device *class_dev = to_class_dev(kobj);
+		if (class_dev->class)
+			return 1;
+	}
+	return 0;
+}
+
+static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+
+	return class_dev->class->name;
+}
+
 #ifdef CONFIG_SYSFS_DEPRECATED
 char *make_class_name(const char *name, struct kobject *kobj)
 {
@@ -248,8 +370,445 @@ char *make_class_name(const char *name, 
 	strcat(class_name, kobject_name(kobj));
 	return class_name;
 }
+
+static int make_deprecated_class_device_links(struct class_device *class_dev)
+{
+	char *class_name;
+	int error;
+
+	if (!class_dev->dev)
+		return 0;
+
+	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
+	if (class_name)
+		error = sysfs_create_link(&class_dev->dev->kobj,
+					  &class_dev->kobj, class_name);
+	else
+		error = -ENOMEM;
+	kfree(class_name);
+	return error;
+}
+
+static void remove_deprecated_class_device_links(struct class_device *class_dev)
+{
+	char *class_name;
+
+	if (!class_dev->dev)
+		return;
+
+	class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
+	if (class_name)
+		sysfs_remove_link(&class_dev->dev->kobj, class_name);
+	kfree(class_name);
+}
+#else
+static inline int make_deprecated_class_device_links(struct class_device *cd)
+{ return 0; }
+static void remove_deprecated_class_device_links(struct class_device *cd)
+{ }
 #endif
 
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+			struct kobj_uevent_env *env)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+	struct device *dev = class_dev->dev;
+	int retval = 0;
+
+	pr_debug("%s - name = %s\n", __func__, class_dev->class_id);
+
+	if (MAJOR(class_dev->devt)) {
+		add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
+
+		add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
+	}
+
+	if (dev) {
+		const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+		if (path) {
+			add_uevent_var(env, "PHYSDEVPATH=%s", path);
+			kfree(path);
+		}
+
+		if (dev->bus)
+			add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
+
+		if (dev->driver)
+			add_uevent_var(env, "PHYSDEVDRIVER=%s",
+				       dev->driver->name);
+	}
+
+	if (class_dev->uevent) {
+		/* have the class device specific function add its stuff */
+		retval = class_dev->uevent(class_dev, env);
+		if (retval)
+			pr_debug("class_dev->uevent() returned %d\n", retval);
+	} else if (class_dev->class->uevent) {
+		/* have the class specific function add its stuff */
+		retval = class_dev->class->uevent(class_dev, env);
+		if (retval)
+			pr_debug("class->uevent() returned %d\n", retval);
+	}
+
+	return retval;
+}
+
+static struct kset_uevent_ops class_uevent_ops = {
+	.filter =	class_uevent_filter,
+	.name =		class_uevent_name,
+	.uevent =	class_uevent,
+};
+
+/*
+ * DO NOT copy how this is created, kset_create_and_add() should be
+ * called, but this is a hold-over from the old-way and will be deleted
+ * entirely soon.
+ */
+static struct kset class_obj_subsys = {
+	.uevent_ops = &class_uevent_ops,
+};
+
+static int class_device_add_attrs(struct class_device *cd)
+{
+	int i;
+	int error = 0;
+	struct class *cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
+			error = class_device_create_file(cd,
+						&cls->class_dev_attrs[i]);
+			if (error)
+				goto err;
+		}
+	}
+done:
+	return error;
+err:
+	while (--i >= 0)
+		class_device_remove_file(cd, &cls->class_dev_attrs[i]);
+	goto done;
+}
+
+static void class_device_remove_attrs(struct class_device *cd)
+{
+	int i;
+	struct class *cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
+			class_device_remove_file(cd, &cls->class_dev_attrs[i]);
+	}
+}
+
+static int class_device_add_groups(struct class_device *cd)
+{
+	int i;
+	int error = 0;
+
+	if (cd->groups) {
+		for (i = 0; cd->groups[i]; i++) {
+			error = sysfs_create_group(&cd->kobj, cd->groups[i]);
+			if (error) {
+				while (--i >= 0)
+					sysfs_remove_group(&cd->kobj,
+							   cd->groups[i]);
+				goto out;
+			}
+		}
+	}
+out:
+	return error;
+}
+
+static void class_device_remove_groups(struct class_device *cd)
+{
+	int i;
+	if (cd->groups)
+		for (i = 0; cd->groups[i]; i++)
+			sysfs_remove_group(&cd->kobj, cd->groups[i]);
+}
+
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	return print_dev_t(buf, class_dev->devt);
+}
+
+static struct class_device_attribute class_devt_attr =
+	__ATTR(dev, S_IRUGO, show_dev, NULL);
+
+static ssize_t store_uevent(struct class_device *class_dev,
+			    const char *buf, size_t count)
+{
+	kobject_uevent(&class_dev->kobj, KOBJ_ADD);
+	return count;
+}
+
+static struct class_device_attribute class_uevent_attr =
+	__ATTR(uevent, S_IWUSR, NULL, store_uevent);
+
+void class_device_initialize(struct class_device *class_dev)
+{
+	class_dev->kobj.kset = &class_obj_subsys;
+	kobject_init(&class_dev->kobj, &class_device_ktype);
+	INIT_LIST_HEAD(&class_dev->node);
+}
+
+int class_device_add(struct class_device *class_dev)
+{
+	struct class *parent_class = NULL;
+	struct class_device *parent_class_dev = NULL;
+	struct class_interface *class_intf;
+	int error = -EINVAL;
+
+	class_dev = class_device_get(class_dev);
+	if (!class_dev)
+		return -EINVAL;
+
+	if (!strlen(class_dev->class_id))
+		goto out1;
+
+	parent_class = class_get(class_dev->class);
+	if (!parent_class)
+		goto out1;
+
+	parent_class_dev = class_device_get(class_dev->parent);
+
+	pr_debug("CLASS: registering class device: ID = '%s'\n",
+		 class_dev->class_id);
+
+	/* first, register with generic layer. */
+	if (parent_class_dev)
+		class_dev->kobj.parent = &parent_class_dev->kobj;
+	else
+		class_dev->kobj.parent = &parent_class->subsys.kobj;
+
+	error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
+			    "%s", class_dev->class_id);
+	if (error)
+		goto out2;
+
+	/* add the needed attributes to this device */
+	error = sysfs_create_link(&class_dev->kobj,
+				  &parent_class->subsys.kobj, "subsystem");
+	if (error)
+		goto out3;
+
+	error = class_device_create_file(class_dev, &class_uevent_attr);
+	if (error)
+		goto out3;
+
+	if (MAJOR(class_dev->devt)) {
+		error = class_device_create_file(class_dev, &class_devt_attr);
+		if (error)
+			goto out4;
+	}
+
+	error = class_device_add_attrs(class_dev);
+	if (error)
+		goto out5;
+
+	if (class_dev->dev) {
+		error = sysfs_create_link(&class_dev->kobj,
+					  &class_dev->dev->kobj, "device");
+		if (error)
+			goto out6;
+	}
+
+	error = class_device_add_groups(class_dev);
+	if (error)
+		goto out7;
+
+	error = make_deprecated_class_device_links(class_dev);
+	if (error)
+		goto out8;
+
+	kobject_uevent(&class_dev->kobj, KOBJ_ADD);
+
+	/* notify any interfaces this device is now here */
+	down(&parent_class->sem);
+	list_add_tail(&class_dev->node, &parent_class->children);
+	list_for_each_entry(class_intf, &parent_class->interfaces, node) {
+		if (class_intf->add)
+			class_intf->add(class_dev, class_intf);
+	}
+	up(&parent_class->sem);
+
+	goto out1;
+
+ out8:
+	class_device_remove_groups(class_dev);
+ out7:
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, "device");
+ out6:
+	class_device_remove_attrs(class_dev);
+ out5:
+	if (MAJOR(class_dev->devt))
+		class_device_remove_file(class_dev, &class_devt_attr);
+ out4:
+	class_device_remove_file(class_dev, &class_uevent_attr);
+ out3:
+	kobject_del(&class_dev->kobj);
+ out2:
+	if (parent_class_dev)
+		class_device_put(parent_class_dev);
+	class_put(parent_class);
+ out1:
+	class_device_put(class_dev);
+	return error;
+}
+
+int class_device_register(struct class_device *class_dev)
+{
+	class_device_initialize(class_dev);
+	return class_device_add(class_dev);
+}
+
+/**
+ * class_device_create - creates a class device and registers it with sysfs
+ * @cls: pointer to the struct class that this device should be registered to.
+ * @parent: pointer to the parent struct class_device of this new device, if
+ * any.
+ * @devt: the dev_t for the char device to be added.
+ * @device: a pointer to a struct device that is assiociated with this class
+ * device.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by char device classes.  A struct
+ * class_device will be created in sysfs, registered to the specified
+ * class.
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct class_device is passed in, the newly
+ * created struct class_device will be a child of that device in sysfs.
+ * The pointer to the struct class_device will be returned from the
+ * call.  Any further sysfs files that might be required can be created
+ * using this pointer.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct class_device *class_device_create(struct class *cls,
+					 struct class_device *parent,
+					 dev_t devt,
+					 struct device *device,
+					 const char *fmt, ...)
+{
+	va_list args;
+	struct class_device *class_dev = NULL;
+	int retval = -ENODEV;
+
+	if (cls == NULL || IS_ERR(cls))
+		goto error;
+
+	class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
+	if (!class_dev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	class_dev->devt = devt;
+	class_dev->dev = device;
+	class_dev->class = cls;
+	class_dev->parent = parent;
+	class_dev->release = class_device_create_release;
+	class_dev->uevent = class_device_create_uevent;
+
+	va_start(args, fmt);
+	vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
+	va_end(args);
+	retval = class_device_register(class_dev);
+	if (retval)
+		goto error;
+
+	return class_dev;
+
+error:
+	kfree(class_dev);
+	return ERR_PTR(retval);
+}
+
+void class_device_del(struct class_device *class_dev)
+{
+	struct class *parent_class = class_dev->class;
+	struct class_device *parent_device = class_dev->parent;
+	struct class_interface *class_intf;
+
+	if (parent_class) {
+		down(&parent_class->sem);
+		list_del_init(&class_dev->node);
+		list_for_each_entry(class_intf, &parent_class->interfaces, node)
+			if (class_intf->remove)
+				class_intf->remove(class_dev, class_intf);
+		up(&parent_class->sem);
+	}
+
+	if (class_dev->dev) {
+		remove_deprecated_class_device_links(class_dev);
+		sysfs_remove_link(&class_dev->kobj, "device");
+	}
+	sysfs_remove_link(&class_dev->kobj, "subsystem");
+	class_device_remove_file(class_dev, &class_uevent_attr);
+	if (MAJOR(class_dev->devt))
+		class_device_remove_file(class_dev, &class_devt_attr);
+	class_device_remove_attrs(class_dev);
+	class_device_remove_groups(class_dev);
+
+	kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
+	kobject_del(&class_dev->kobj);
+
+	class_device_put(parent_device);
+	class_put(parent_class);
+}
+
+void class_device_unregister(struct class_device *class_dev)
+{
+	pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
+		 class_dev->class_id);
+	class_device_del(class_dev);
+	class_device_put(class_dev);
+}
+
+/**
+ * class_device_destroy - removes a class device that was created with class_device_create()
+ * @cls: the pointer to the struct class that this device was registered * with.
+ * @devt: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_create()
+ */
+void class_device_destroy(struct class *cls, dev_t devt)
+{
+	struct class_device *class_dev = NULL;
+	struct class_device *class_dev_tmp;
+
+	down(&cls->sem);
+	list_for_each_entry(class_dev_tmp, &cls->children, node) {
+		if (class_dev_tmp->devt == devt) {
+			class_dev = class_dev_tmp;
+			break;
+		}
+	}
+	up(&cls->sem);
+
+	if (class_dev)
+		class_device_unregister(class_dev);
+}
+
+struct class_device *class_device_get(struct class_device *class_dev)
+{
+	if (class_dev)
+		return to_class_dev(kobject_get(&class_dev->kobj));
+	return NULL;
+}
+
+void class_device_put(struct class_device *class_dev)
+{
+	if (class_dev)
+		kobject_put(&class_dev->kobj);
+}
+
 /**
  * class_for_each_device - device iterator
  * @class: the class we're iterating
@@ -338,9 +897,56 @@ struct device *class_find_device(struct 
 }
 EXPORT_SYMBOL_GPL(class_find_device);
 
+/**
+ * class_find_child - device iterator for locating a particular class_device
+ * @class: the class we're iterating
+ * @data: data for the match function
+ * @match: function to check class_device
+ *
+ * This function returns a reference to a class_device that is 'found' for
+ * later use, as determined by the @match callback.
+ *
+ * The callback should return 0 if the class_device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more class_devices.
+ *
+ * Note, you will need to drop the reference with class_device_put() after use.
+ *
+ * We hold class->sem in this function, so it can not be
+ * re-acquired in @match, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+struct class_device *class_find_child(struct class *class, void *data,
+				   int (*match)(struct class_device *, void *))
+{
+	struct class_device *dev;
+	int found = 0;
+
+	if (!class)
+		return NULL;
+
+	down(&class->sem);
+	list_for_each_entry(dev, &class->children, node) {
+		dev = class_device_get(dev);
+		if (dev) {
+			if (match(dev, data)) {
+				found = 1;
+				break;
+			} else
+				class_device_put(dev);
+		} else
+			break;
+	}
+	up(&class->sem);
+
+	return found ? dev : NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_child);
+
 int class_interface_register(struct class_interface *class_intf)
 {
 	struct class *parent;
+	struct class_device *class_dev;
 	struct device *dev;
 
 	if (!class_intf || !class_intf->class)
@@ -352,6 +958,10 @@ int class_interface_register(struct clas
 
 	down(&parent->sem);
 	list_add_tail(&class_intf->node, &parent->interfaces);
+	if (class_intf->add) {
+		list_for_each_entry(class_dev, &parent->children, node)
+			class_intf->add(class_dev, class_intf);
+	}
 	if (class_intf->add_dev) {
 		list_for_each_entry(dev, &parent->devices, node)
 			class_intf->add_dev(dev, class_intf);
@@ -364,6 +974,7 @@ int class_interface_register(struct clas
 void class_interface_unregister(struct class_interface *class_intf)
 {
 	struct class *parent = class_intf->class;
+	struct class_device *class_dev;
 	struct device *dev;
 
 	if (!parent)
@@ -371,6 +982,10 @@ void class_interface_unregister(struct c
 
 	down(&parent->sem);
 	list_del_init(&class_intf->node);
+	if (class_intf->remove) {
+		list_for_each_entry(class_dev, &parent->children, node)
+			class_intf->remove(class_dev, class_intf);
+	}
 	if (class_intf->remove_dev) {
 		list_for_each_entry(dev, &parent->devices, node)
 			class_intf->remove_dev(dev, class_intf);
@@ -385,6 +1000,13 @@ int __init classes_init(void)
 	class_kset = kset_create_and_add("class", NULL, NULL);
 	if (!class_kset)
 		return -ENOMEM;
+
+	/* ick, this is ugly, the things we go through to keep from showing up
+	 * in sysfs... */
+	kset_init(&class_obj_subsys);
+	kobject_set_name(&class_obj_subsys.kobj, "class_obj");
+	if (!class_obj_subsys.kobj.parent)
+		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
 	return 0;
 }
 
@@ -395,5 +1017,19 @@ EXPORT_SYMBOL_GPL(class_unregister);
 EXPORT_SYMBOL_GPL(class_create);
 EXPORT_SYMBOL_GPL(class_destroy);
 
+EXPORT_SYMBOL_GPL(class_device_register);
+EXPORT_SYMBOL_GPL(class_device_unregister);
+EXPORT_SYMBOL_GPL(class_device_initialize);
+EXPORT_SYMBOL_GPL(class_device_add);
+EXPORT_SYMBOL_GPL(class_device_del);
+EXPORT_SYMBOL_GPL(class_device_get);
+EXPORT_SYMBOL_GPL(class_device_put);
+EXPORT_SYMBOL_GPL(class_device_create);
+EXPORT_SYMBOL_GPL(class_device_destroy);
+EXPORT_SYMBOL_GPL(class_device_create_file);
+EXPORT_SYMBOL_GPL(class_device_remove_file);
+EXPORT_SYMBOL_GPL(class_device_create_bin_file);
+EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
+
 EXPORT_SYMBOL_GPL(class_interface_register);
 EXPORT_SYMBOL_GPL(class_interface_unregister);
diff -puN include/linux/device.h~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device include/linux/device.h
--- a/include/linux/device.h~revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device
+++ a/include/linux/device.h
@@ -35,6 +35,7 @@ struct device;
 struct device_driver;
 struct driver_private;
 struct class;
+struct class_device;
 struct bus_type;
 struct bus_type_private;
 
@@ -189,10 +190,13 @@ struct class {
 	struct kset		class_dirs;
 	struct semaphore	sem; /* locks children, devices, interfaces */
 	struct class_attribute		*class_attrs;
+	struct class_device_attribute	*class_dev_attrs;
 	struct device_attribute		*dev_attrs;
 
+	int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
 	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
 
+	void (*release)(struct class_device *dev);
 	void (*class_release)(struct class *class);
 	void (*dev_release)(struct device *dev);
 
@@ -206,6 +210,9 @@ extern int class_for_each_device(struct 
 				 int (*fn)(struct device *dev, void *data));
 extern struct device *class_find_device(struct class *class, void *data,
 					int (*match)(struct device *, void *));
+extern struct class_device *class_find_child(struct class *class, void *data,
+				   int (*match)(struct class_device *, void *));
+
 
 struct class_attribute {
 	struct attribute attr;
@@ -221,10 +228,92 @@ extern int __must_check class_create_fil
 extern void class_remove_file(struct class *class,
 			      const struct class_attribute *attr);
 
+struct class_device_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct class_device *, char *buf);
+	ssize_t (*store)(struct class_device *, const char *buf, size_t count);
+};
+
+#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store)		\
+struct class_device_attribute class_device_attr_##_name = 	\
+	__ATTR(_name, _mode, _show, _store)
+
+extern int __must_check class_device_create_file(struct class_device *,
+				    const struct class_device_attribute *);
+
+/**
+ * struct class_device - class devices
+ * @class: pointer to the parent class for this class device.  This is required.
+ * @devt: for internal use by the driver core only.
+ * @node: for internal use by the driver core only.
+ * @kobj: for internal use by the driver core only.
+ * @groups: optional additional groups to be created
+ * @dev: if set, a symlink to the struct device is created in the sysfs
+ * directory for this struct class device.
+ * @class_data: pointer to whatever you want to store here for this struct
+ * class_device.  Use class_get_devdata() and class_set_devdata() to get and
+ * set this pointer.
+ * @parent: pointer to a struct class_device that is the parent of this struct
+ * class_device.  If NULL, this class_device will show up at the root of the
+ * struct class in sysfs (which is probably what you want to have happen.)
+ * @release: pointer to a release function for this struct class_device.  If
+ * set, this will be called instead of the class specific release function.
+ * Only use this if you want to override the default release function, like
+ * when you are nesting class_device structures.
+ * @uevent: pointer to a uevent function for this struct class_device.  If
+ * set, this will be called instead of the class specific uevent function.
+ * Only use this if you want to override the default uevent function, like
+ * when you are nesting class_device structures.
+ */
+struct class_device {
+	struct list_head	node;
+
+	struct kobject		kobj;
+	struct class		*class;
+	dev_t			devt;
+	struct device		*dev;
+	void			*class_data;
+	struct class_device	*parent;
+	struct attribute_group  **groups;
+
+	void (*release)(struct class_device *dev);
+	int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+	char class_id[BUS_ID_SIZE];
+};
+
+static inline void *class_get_devdata(struct class_device *dev)
+{
+	return dev->class_data;
+}
+
+static inline void class_set_devdata(struct class_device *dev, void *data)
+{
+	dev->class_data = data;
+}
+
+
+extern int __must_check class_device_register(struct class_device *);
+extern void class_device_unregister(struct class_device *);
+extern void class_device_initialize(struct class_device *);
+extern int __must_check class_device_add(struct class_device *);
+extern void class_device_del(struct class_device *);
+
+extern struct class_device *class_device_get(struct class_device *);
+extern void class_device_put(struct class_device *);
+
+extern void class_device_remove_file(struct class_device *,
+				     const struct class_device_attribute *);
+extern int __must_check class_device_create_bin_file(struct class_device *,
+					struct bin_attribute *);
+extern void class_device_remove_bin_file(struct class_device *,
+					 struct bin_attribute *);
+
 struct class_interface {
 	struct list_head	node;
 	struct class		*class;
 
+	int (*add)	(struct class_device *, struct class_interface *);
+	void (*remove)	(struct class_device *, struct class_interface *);
 	int (*add_dev)		(struct device *, struct class_interface *);
 	void (*remove_dev)	(struct device *, struct class_interface *);
 };
@@ -234,6 +323,13 @@ extern void class_interface_unregister(s
 
 extern struct class *class_create(struct module *owner, const char *name);
 extern void class_destroy(struct class *cls);
+extern struct class_device *class_device_create(struct class *cls,
+						struct class_device *parent,
+						dev_t devt,
+						struct device *device,
+						const char *fmt, ...)
+					__attribute__((format(printf, 5, 6)));
+extern void class_device_destroy(struct class *cls, dev_t devt);
 
 /*
  * The type of device, "struct device" is embedded in. A class
@@ -370,6 +466,7 @@ struct device {
 	spinlock_t		devres_lock;
 	struct list_head	devres_head;
 
+	/* class_device migration path */
 	struct list_head	node;
 	struct class		*class;
 	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
_

Patches currently in -mm which might be from akpm@xxxxxxxxxxxxxxxxxxxx are

origin.patch
lib-swiotlbc-avoid-endless-loops-fix.patch
git-x86.patch
arch-x86-kernel-ptracec-fix-defined-but-unused-warnings.patch
git-kgdb-light.patch
git-acpi.patch
git-acpi-fixup.patch
acpi-enable-c3-power-state-on-dell-inspiron-8200.patch
git-alsa-tiwai.patch
cifs-suppress-warning.patch
revert-gregkh-driver-video-add-the-go7007-driver.patch
revert-gregkh-driver-driver-core-remove-no-longer-used-struct-class_device.patch
pm-make-wakeup-flags-available-whenever-config_pm-is-set-checkpatch-fixes.patch
git-drm.patch
git-dvb.patch
drivers-media-video-pvrusb2-pvrusb2-sysfsc-fix-printk-warnings.patch
drivers-media-video-soc_camerac-reads-return-size_t.patch
git-hwmon.patch
git-gfs2-nmw.patch
git-hrt.patch
git-ieee1394.patch
drivers-input-touchscreen-ads7846c-fix-uninitialized-var-warning.patch
maple-add-driver-for-sega-dreamcast-controller.patch
git-kvm.patch
git-leds.patch
devres-implement-pcim_iomap_regions_request_all-fix.patch
devres-implement-pcim_iomap_regions_request_all-fix-fix.patch
drivers-atm-firestreamc-suppress-uninitialized-var-warning.patch
update-smc91x-driver-with-arm-versatile-board-info.patch
fs-nfs-callback_xdrc-suppress-uninitialiized-variable-warnings.patch
git-nfsd.patch
git-ocfs2.patch
drivers-pcmcia-soc_commonc-convert-soc_pcmcia_sockets_lock-into-a-mutex-and-make-it-static.patch
git-selinux.patch
revert-sched-make-sure-jiffies-is-up-to-date-before-calling-__update_rq_clock.patch
git-sh.patch
git-scsi-misc-revert-st-show-options-currently-set-in-sysfs.patch
scsi-aic94xx-cleanups.patch
scsi-fix-section-mismatch-in-aic94xx-fix.patch
scsi-chc-fix-shadowed-variable-warnings-checkpatch-fixes.patch
ipsc-fix-build-warning.patch
drivers-scsi-initioc-suppress-compile-warning.patch
drivers-scsi-hptiopc-fix-build-warning.patch
drivers-scsi-mvsasc-fix-build-warnings.patch
git-block-git-rejects.patch
git-unionfs.patch
fix-gregkh-usb-usb-add-usb-serial-spcp8x5-driver.patch
fix-gregkh-usb-usb-ohci-port-reset-paranoia-timeout.patch
drivers-usb-core-devioc-suppress-warning-with-64k-page_size.patch
git-v9fs.patch
git-watchdog.patch
git-semaphore-git-rejects.patch
x86-fix-aperture-vs-suspend-problem-checkpatch-fixes.patch
revert-pcie-utilize-pcie-transaction-pending-bit.patch
remove-sparse-warning-for-mmzoneh-checkpatch-fixes.patch
fix-invalidate_inode_pages2_range-to-not-clear-ret-checkpatch-fixes.patch
mm-make-mem_map-allocation-continuous-checkpatch-fixes.patch
vmscan-give-referenced-active-and-unmapped-pages-a-second-trip-around-the-lru.patch
vm-dont-run-touch_buffer-during-buffercache-lookups.patch
capabilities-implement-per-process-securebits-warning-fix.patch
lsm-introduce-inode_getsecid-and-ipc_getsecid-hooks-checkpatch-fixes.patch
lsm-audit-introduce-generic-audit-lsm-hooks-checkpatch-fixes.patch
selinux-use-new-audit-hooks-remove-redundant-exports-checkpatch-fixes.patch
audit-final-renamings-and-cleanup-checkpatch-fixes.patch
make-dev-kmem-a-config-option-fix.patch
misc-phantom-add-compat-ioctl-checkpatch-fixes.patch
kernel-add-clamp-and-clamp_t-macros.patch
sysrq-add-show-backtrace-on-all-cpus-function-checkpatch-fixes.patch
sysrq-add-show-backtrace-on-all-cpus-function-checkpatch-fixes-cleanup.patch
codafs-fix-build-warning.patch
lib-swiotlbc-cleanups.patch
r-o-bind-mounts-elevate-write-count-for-callers-of-vfs_mkdir-fix.patch
r-o-bind-mounts-elevate-write-count-for-xattr_permission-callers-fix.patch
r-o-bind-mounts-get-write-access-for-vfs_rename-callers-fix.patch
r-o-bind-mounts-check-mnt-instead-of-superblock-directly-fix.patch
r-o-bind-mounts-check-mnt-instead-of-superblock-directly-fix-2.patch
r-o-bind-mounts-get-callers-of-vfs_mknod-create-fix.patch
fs-inodec-use-hlist_for_each_entry-checkpatch-fixes.patch
add-rcu_assign_index-if-ever-needed-fix.patch
add-warn_on_secs-macro-simplification-fix.patch
uart_get_baud_rate-stop-mangling-termios-fix.patch
oprofile-change-cpu_buffer-from-array-to-per_cpu-variable-checkpatch-fixes.patch
vt-notifier-extension-for-accessibility-checkpatch-fixes.patch
kprobes-prevent-probing-of-preempt_schedule-fix.patch
kprobes-prevent-probing-of-preempt_schedule-checkpatch-fixes.patch
quota-various-style-cleanups-checkpatch-fixes.patch
quota-quota-core-changes-for-quotaon-on-remount-quota-ext3-make-ext3-handle-quotaon-on-remount-checkpatch-fixes.patch
quota-quota-core-changes-for-quotaon-on-remount-quota-ext4-make-ext4-handle-quotaon-on-remount-checkpatch-fixes.patch
rtc-isl1208-new-style-conversion-and-minor-bug-fixes-checkpatch-fixes.patch
rtc-pcf8563-new-style-conversion-checkpatch-fixes.patch
rtc-pcf8563-new-style-conversion-checkpatch-fixes-fix.patch
rtc-x1205-new-style-conversion-checkpatch-fixes.patch
gpiochip_reserve-fix.patch
fb-add-support-for-foreign-endianness-force-it-on.patch
fbcon-replace-mono_col-macro-with-static-inline-fix.patch
pnp-use-dev_printk-for-quirk-messages-fix.patch
fat_valid_media-remove-pointless-test.patch
cgroup-api-files-update-cpusets-to-use-cgroup-structured-file-api-fix.patch
add-a-document-describing-the-resource-counter-abstraction-v2-fix.patch
workqueues-shrink-cpu_populated_map-when-cpu-dies-fix.patch
ext4-is-broken.patch
ipc-use-ipc_buildid-directly-from-ipc_addid-cleanup.patch
ipmi-run-to-completion-fixes-checkpatch-fixes.patch
ipmi-style-fixes-in-the-system-interface-code-checkpatch-fixes.patch
elf-fix-shadowed-variables-in-fs-binfmt_elfc.patch
sgi-altix-mmtimer-allow-larger-number-of-timers-per-node-fix.patch
sgi-altix-mmtimer-allow-larger-number-of-timers-per-node-fix-2.patch
epcac-static-functions-and-integer-as-null-pointer-fixes-checkpatch-fixes.patch
keys-add-keyctl-function-to-get-a-security-label-fix.patch
procfs-task-exe-symlink-fix.patch
edd-add-default-mode-config_edd_off=n-override-with-edd=onoff-fix.patch
mm-bdi-export-bdi-attributes-in-sysfs-ia64-fix.patch
basic-braille-screen-reader-support-ppc-fix.patch
hfs-fix-warning-with-64k-page_size.patch
hfsplus-fix-warning-with-64k-page_size.patch
alloc_uid-cleanup.patch
reiser4.patch
jens-broke-reiser4patch-added-to-mm-tree.patch
page-owner-tracking-leak-detector.patch
nr_blockdev_pages-in_interrupt-warning.patch
slab-leaks3-default-y.patch
profile-likely-unlikely-macros.patch
profile-likely-unlikely-macros-fix.patch
put_bh-debug.patch
shrink_slab-handle-bad-shrinkers.patch
getblk-handle-2tb-devices.patch
getblk-handle-2tb-devices-fix.patch
undeprecate-pci_find_device.patch
w1-build-fix.patch

--
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux