diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-14 16:51:12 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-14 16:51:12 -0700 |
commit | cf45b5d4be20d0b0c235989c58ffd050051a3d48 (patch) | |
tree | 09e613963fddce5fdfa092a99a9b3a7eff7ec88a /driver | |
parent | e6b88ef30ffe1805ffd78a2b689e3f464577e63d (diff) | |
download | patches-cf45b5d4be20d0b0c235989c58ffd050051a3d48.tar.gz |
move device-class patch to driver/ to get it to be picked up.
Also add endpoint patches as they are starting to work...
Diffstat (limited to 'driver')
-rw-r--r-- | driver/device-class.patch | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/driver/device-class.patch b/driver/device-class.patch new file mode 100644 index 0000000000000..bc86f1385c447 --- /dev/null +++ b/driver/device-class.patch @@ -0,0 +1,305 @@ +From foo@baz Tue Apr 9 12:12:43 2002 +Date: Wed, 14 Jun 2006 12:14:34 -0700 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: Driver core: allow struct device to have a dev_t + +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 deletion(-) + +--- gregkh-2.6.orig/drivers/base/class.c ++++ gregkh-2.6/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); +--- gregkh-2.6.orig/drivers/base/core.c ++++ gregkh-2.6/drivers/base/core.c +@@ -15,6 +15,7 @@ + #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,19 @@ static int dev_uevent(struct kset *kset, + int length = 0; + int retval = 0; + ++ /* add the major/minor if present */ ++ if (dev->class) { ++ 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 +181,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 +257,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 +301,26 @@ 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 ((error = device_pm_add(dev))) + goto PMError; + if ((error = bus_add_device(dev))) +@@ -292,6 +339,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: +@@ -367,6 +419,8 @@ void device_del(struct device * dev) + + if (parent) + klist_del(&dev->knode_parent); ++ if (dev->devt_attr) ++ device_remove_file(dev, dev->devt_attr); + device_remove_file(dev, &dev->uevent_attr); + + /* Notify the platform of the removal, in case they +@@ -451,3 +505,109 @@ 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); ++ sysfs_create_link(&class->subsys.kset.kobj, &dev->kobj, dev->bus_id); ++ ++ 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) { ++ sysfs_remove_link(&class->subsys.kset.kobj, dev->bus_id); ++ list_del_init(&dev->node); ++ device_unregister(dev); ++ } ++} ++EXPORT_SYMBOL_GPL(device_destroy); ++ ++ +--- gregkh-2.6.orig/include/linux/device.h ++++ gregkh-2.6/include/linux/device.h +@@ -143,6 +143,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 */ + +@@ -306,6 +307,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. +@@ -333,6 +335,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); + }; + +@@ -374,6 +381,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 |