All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <greg@kroah.com>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Subject: [PATCH 18/22] [PATCH] Driver core: allow struct device to have a dev_t
Date: Wed, 21 Jun 2006 12:46:01 -0700	[thread overview]
Message-ID: <1150919221158-git-send-email-greg@kroah.com> (raw)
In-Reply-To: <1150919218895-git-send-email-greg@kroah.com>

From: Greg Kroah-Hartman <gregkh@suse.de>

This is the first step in moving class_device to being replaced by
struct device.  It allows struct device to export a dev_t and makes it
easy to dynamically create and destroy struct device as long as they are
associated with a specific class.

Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/base/class.c   |    1 
 drivers/base/core.c    |  162 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |   14 ++++
 3 files changed, 176 insertions(+), 1 deletions(-)

diff --git a/drivers/base/class.c b/drivers/base/class.c
index 41a8e09..50e841a 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -142,6 +142,7 @@ int class_register(struct class * cls)
 	pr_debug("device class '%s': registering\n", cls->name);
 
 	INIT_LIST_HEAD(&cls->children);
+	INIT_LIST_HEAD(&cls->devices);
 	INIT_LIST_HEAD(&cls->interfaces);
 	init_MUTEX(&cls->sem);
 	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d5e15a0..252cf40 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -15,6 +15,7 @@ #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/kdev_t.h>
 
 #include <asm/semaphore.h>
 
@@ -98,6 +99,8 @@ static int dev_uevent_filter(struct kset
 		struct device *dev = to_dev(kobj);
 		if (dev->bus)
 			return 1;
+		if (dev->class)
+			return 1;
 	}
 	return 0;
 }
@@ -106,7 +109,11 @@ static const char *dev_uevent_name(struc
 {
 	struct device *dev = to_dev(kobj);
 
-	return dev->bus->name;
+	if (dev->bus)
+		return dev->bus->name;
+	if (dev->class)
+		return dev->class->name;
+	return NULL;
 }
 
 static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
@@ -117,6 +124,16 @@ static int dev_uevent(struct kset *kset,
 	int length = 0;
 	int retval = 0;
 
+	/* add the major/minor if present */
+	if (MAJOR(dev->devt)) {
+		add_uevent_var(envp, num_envp, &i,
+			       buffer, buffer_size, &length,
+			       "MAJOR=%u", MAJOR(dev->devt));
+		add_uevent_var(envp, num_envp, &i,
+			       buffer, buffer_size, &length,
+			       "MINOR=%u", MINOR(dev->devt));
+	}
+
 	/* add bus name of physical device */
 	if (dev->bus)
 		add_uevent_var(envp, num_envp, &i,
@@ -161,6 +178,12 @@ static ssize_t store_uevent(struct devic
 	return count;
 }
 
+static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return print_dev_t(buf, dev->devt);
+}
+
 /*
  *	devices_subsys - structure to be registered with kobject core.
  */
@@ -231,6 +254,7 @@ void device_initialize(struct device *de
 	klist_init(&dev->klist_children, klist_children_get,
 		   klist_children_put);
 	INIT_LIST_HEAD(&dev->dma_pools);
+	INIT_LIST_HEAD(&dev->node);
 	init_MUTEX(&dev->sem);
 	device_init_wakeup(dev, 0);
 }
@@ -274,6 +298,31 @@ int device_add(struct device *dev)
 	dev->uevent_attr.store = store_uevent;
 	device_create_file(dev, &dev->uevent_attr);
 
+	if (MAJOR(dev->devt)) {
+		struct device_attribute *attr;
+		attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+		if (!attr) {
+			error = -ENOMEM;
+			goto PMError;
+		}
+		attr->attr.name = "dev";
+		attr->attr.mode = S_IRUGO;
+		if (dev->driver)
+			attr->attr.owner = dev->driver->owner;
+		attr->show = show_dev;
+		error = device_create_file(dev, attr);
+		if (error) {
+			kfree(attr);
+			goto attrError;
+		}
+
+		dev->devt_attr = attr;
+	}
+
+	if (dev->class)
+		sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+				  dev->bus_id);
+
 	if ((error = device_pm_add(dev)))
 		goto PMError;
 	if ((error = bus_add_device(dev)))
@@ -292,6 +341,11 @@ int device_add(struct device *dev)
  BusError:
 	device_pm_remove(dev);
  PMError:
+	if (dev->devt_attr) {
+		device_remove_file(dev, dev->devt_attr);
+		kfree(dev->devt_attr);
+	}
+ attrError:
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
  Error:
@@ -366,6 +420,10 @@ void device_del(struct device * dev)
 
 	if (parent)
 		klist_del(&dev->knode_parent);
+	if (dev->devt_attr)
+		device_remove_file(dev, dev->devt_attr);
+	if (dev->class)
+		sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
 	device_remove_file(dev, &dev->uevent_attr);
 
 	/* Notify the platform of the removal, in case they
@@ -450,3 +508,105 @@ EXPORT_SYMBOL_GPL(put_device);
 
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
+
+
+static void device_create_release(struct device *dev)
+{
+	pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
+	kfree(dev);
+}
+
+/**
+ * device_create - creates a device and registers it with sysfs
+ * @cs: pointer to the struct class that this device should be registered to.
+ * @parent: pointer to the parent struct device of this new device, if any.
+ * @dev: the dev_t for the char device to be added.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by char device classes.  A struct
+ * 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 device is passed in, the newly
+ * created struct device will be a child of that device in sysfs.  The
+ * pointer to the struct 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 device *device_create(struct class *class, struct device *parent,
+			     dev_t devt, char *fmt, ...)
+{
+	va_list args;
+	struct device *dev = NULL;
+	int retval = -ENODEV;
+
+	if (class == NULL || IS_ERR(class))
+		goto error;
+	if (parent == NULL) {
+		printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
+		goto error;
+	}
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	dev->devt = devt;
+	dev->class = class;
+	dev->parent = parent;
+	dev->release = device_create_release;
+
+	va_start(args, fmt);
+	vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
+	va_end(args);
+	retval = device_register(dev);
+	if (retval)
+		goto error;
+
+	/* tie the class to the device */
+	down(&class->sem);
+	list_add_tail(&dev->node, &class->devices);
+	up(&class->sem);
+
+	return dev;
+
+error:
+	kfree(dev);
+	return ERR_PTR(retval);
+}
+EXPORT_SYMBOL_GPL(device_create);
+
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: the pointer to the struct class that this device was registered * with.
+ * @dev: 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 device_destroy(struct class *class, dev_t devt)
+{
+	struct device *dev = NULL;
+	struct device *dev_tmp;
+
+	down(&class->sem);
+	list_for_each_entry(dev_tmp, &class->devices, node) {
+		if (dev_tmp->devt == devt) {
+			dev = dev_tmp;
+			break;
+		}
+	}
+	up(&class->sem);
+
+	if (dev) {
+		list_del_init(&dev->node);
+		device_unregister(dev);
+	}
+}
+EXPORT_SYMBOL_GPL(device_destroy);
diff --git a/include/linux/device.h b/include/linux/device.h
index ade10dd..b473f42 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -142,6 +142,7 @@ struct class {
 
 	struct subsystem	subsys;
 	struct list_head	children;
+	struct list_head	devices;
 	struct list_head	interfaces;
 	struct semaphore	sem;	/* locks both the children and interfaces lists */
 
@@ -305,6 +306,7 @@ struct device {
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
 	struct device_attribute uevent_attr;
+	struct device_attribute *devt_attr;
 
 	struct semaphore	sem;	/* semaphore to synchronize calls to
 					 * its driver.
@@ -332,6 +334,11 @@ struct device {
 	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
 					     override */
 
+	/* class_device migration path */
+	struct list_head	node;
+	struct class		*class;		/* optional*/
+	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
+
 	void	(*release)(struct device * dev);
 };
 
@@ -373,6 +380,13 @@ extern int  device_attach(struct device 
 extern void driver_attach(struct device_driver * drv);
 extern void device_reprobe(struct device *dev);
 
+/*
+ * Easy functions for dynamically creating devices on the fly
+ */
+extern struct device *device_create(struct class *cls, struct device *parent,
+				    dev_t devt, char *fmt, ...)
+				    __attribute__((format(printf,4,5)));
+extern void device_destroy(struct class *cls, dev_t devt);
 
 /*
  * Platform "fixup" functions - allow the platform to have their say
-- 
1.4.0


  reply	other threads:[~2006-06-21 19:53 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-21 19:45 [GIT PATCH] Driver Core patches for 2.6.17 Greg KH
2006-06-21 19:45 ` [PATCH 1/22] [PATCH] kobject: make people pay attention to kobject_add errors Greg KH
2006-06-21 19:45   ` [PATCH 2/22] [PATCH] Add kernel<->userspace ABI stability documentation Greg KH
2006-06-21 19:45     ` [PATCH 3/22] [PATCH] CCISS: add device symlink to the block cciss block devices in sysfs Greg KH
2006-06-21 19:45       ` [PATCH 4/22] [PATCH] Driver core: bus device event delay Greg KH
2006-06-21 19:45         ` [PATCH 5/22] [PATCH] TTY: return class device pointer from tty_register_device() Greg KH
2006-06-21 19:45           ` [PATCH 6/22] [PATCH] i4l gigaset: move sysfs entry to tty class device Greg KH
2006-06-21 19:45             ` [PATCH 7/22] [PATCH] Driver core: class_device_add needs error checks Greg KH
2006-06-21 19:45               ` [PATCH 8/22] [PATCH] Driver Core: CONFIG_DEBUG_PM covers drivers/base/power too Greg KH
2006-06-21 19:45                 ` [PATCH 9/22] [PATCH] platform_bus learns about modalias Greg KH
2006-06-21 19:45                   ` [PATCH 10/22] [PATCH] Driver Core: remove unused exports Greg KH
2006-06-21 19:45                     ` [PATCH 11/22] [PATCH] Driver Core: Allow sysdev_class have attributes Greg KH
2006-06-21 19:45                       ` [PATCH 12/22] [PATCH] Driver Core: Fix platform_device_add to use device_add Greg KH
2006-06-21 19:45                         ` [PATCH 13/22] [PATCH] Driver Core: Add /sys/hypervisor when needed Greg KH
2006-06-21 19:45                           ` [PATCH 14/22] [PATCH] remove duplication from Documentation/power/devices.txt Greg KH
2006-06-21 19:45                             ` [PATCH 15/22] [PATCH] Driver core: PM_DEBUG device suspend() messages become informative Greg KH
2006-06-21 19:45                               ` [PATCH 16/22] [PATCH] firmware_class: s/semaphores/mutexes Greg KH
2006-06-21 19:46                                 ` [PATCH 17/22] [PATCH] Driver core: change make_class_name() to take kobjects Greg KH
2006-06-21 19:46                                   ` Greg KH [this message]
2006-06-21 19:46                                     ` [PATCH 19/22] [PATCH] Driver core: add generic "subsystem" link to all devices Greg KH
2006-06-21 19:46                                       ` [PATCH 20/22] [PATCH] Driver core: add proper symlinks for devices Greg KH
2006-06-21 19:46                                         ` [PATCH 21/22] [PATCH] Driver Core: Make dev_info and friends print the bus name if there is no driver Greg KH
2006-06-21 19:46                                           ` [PATCH 22/22] [PATCH] Driver model: add ISA bus Greg KH

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=1150919221158-git-send-email-greg@kroah.com \
    --to=greg@kroah.com \
    --cc=gregkh@suse.de \
    --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.