aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-06-14 15:14:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 15:40:49 -0400
commit23681e479129854305da1da32f7f1eaf635ef22c (patch)
tree5677e3d851e8d65feeb64c9852e4dbb60e75ff41 /drivers/base/core.c
parentaa49b9136e3d44cc264811d77eef4ded88456717 (diff)
[PATCH] 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>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c162
1 files changed, 161 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d5e15a03584e..252cf403f891 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/string.h> 17#include <linux/string.h>
18#include <linux/kdev_t.h>
18 19
19#include <asm/semaphore.h> 20#include <asm/semaphore.h>
20 21
@@ -98,6 +99,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
98 struct device *dev = to_dev(kobj); 99 struct device *dev = to_dev(kobj);
99 if (dev->bus) 100 if (dev->bus)
100 return 1; 101 return 1;
102 if (dev->class)
103 return 1;
101 } 104 }
102 return 0; 105 return 0;
103} 106}
@@ -106,7 +109,11 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
106{ 109{
107 struct device *dev = to_dev(kobj); 110 struct device *dev = to_dev(kobj);
108 111
109 return dev->bus->name; 112 if (dev->bus)
113 return dev->bus->name;
114 if (dev->class)
115 return dev->class->name;
116 return NULL;
110} 117}
111 118
112static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, 119static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
@@ -117,6 +124,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
117 int length = 0; 124 int length = 0;
118 int retval = 0; 125 int retval = 0;
119 126
127 /* add the major/minor if present */
128 if (MAJOR(dev->devt)) {
129 add_uevent_var(envp, num_envp, &i,
130 buffer, buffer_size, &length,
131 "MAJOR=%u", MAJOR(dev->devt));
132 add_uevent_var(envp, num_envp, &i,
133 buffer, buffer_size, &length,
134 "MINOR=%u", MINOR(dev->devt));
135 }
136
120 /* add bus name of physical device */ 137 /* add bus name of physical device */
121 if (dev->bus) 138 if (dev->bus)
122 add_uevent_var(envp, num_envp, &i, 139 add_uevent_var(envp, num_envp, &i,
@@ -161,6 +178,12 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
161 return count; 178 return count;
162} 179}
163 180
181static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
182 char *buf)
183{
184 return print_dev_t(buf, dev->devt);
185}
186
164/* 187/*
165 * devices_subsys - structure to be registered with kobject core. 188 * devices_subsys - structure to be registered with kobject core.
166 */ 189 */
@@ -231,6 +254,7 @@ void device_initialize(struct device *dev)
231 klist_init(&dev->klist_children, klist_children_get, 254 klist_init(&dev->klist_children, klist_children_get,
232 klist_children_put); 255 klist_children_put);
233 INIT_LIST_HEAD(&dev->dma_pools); 256 INIT_LIST_HEAD(&dev->dma_pools);
257 INIT_LIST_HEAD(&dev->node);
234 init_MUTEX(&dev->sem); 258 init_MUTEX(&dev->sem);
235 device_init_wakeup(dev, 0); 259 device_init_wakeup(dev, 0);
236} 260}
@@ -274,6 +298,31 @@ int device_add(struct device *dev)
274 dev->uevent_attr.store = store_uevent; 298 dev->uevent_attr.store = store_uevent;
275 device_create_file(dev, &dev->uevent_attr); 299 device_create_file(dev, &dev->uevent_attr);
276 300
301 if (MAJOR(dev->devt)) {
302 struct device_attribute *attr;
303 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
304 if (!attr) {
305 error = -ENOMEM;
306 goto PMError;
307 }
308 attr->attr.name = "dev";
309 attr->attr.mode = S_IRUGO;
310 if (dev->driver)
311 attr->attr.owner = dev->driver->owner;
312 attr->show = show_dev;
313 error = device_create_file(dev, attr);
314 if (error) {
315 kfree(attr);
316 goto attrError;
317 }
318
319 dev->devt_attr = attr;
320 }
321
322 if (dev->class)
323 sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
324 dev->bus_id);
325
277 if ((error = device_pm_add(dev))) 326 if ((error = device_pm_add(dev)))
278 goto PMError; 327 goto PMError;
279 if ((error = bus_add_device(dev))) 328 if ((error = bus_add_device(dev)))
@@ -292,6 +341,11 @@ int device_add(struct device *dev)
292 BusError: 341 BusError:
293 device_pm_remove(dev); 342 device_pm_remove(dev);
294 PMError: 343 PMError:
344 if (dev->devt_attr) {
345 device_remove_file(dev, dev->devt_attr);
346 kfree(dev->devt_attr);
347 }
348 attrError:
295 kobject_uevent(&dev->kobj, KOBJ_REMOVE); 349 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
296 kobject_del(&dev->kobj); 350 kobject_del(&dev->kobj);
297 Error: 351 Error:
@@ -366,6 +420,10 @@ void device_del(struct device * dev)
366 420
367 if (parent) 421 if (parent)
368 klist_del(&dev->knode_parent); 422 klist_del(&dev->knode_parent);
423 if (dev->devt_attr)
424 device_remove_file(dev, dev->devt_attr);
425 if (dev->class)
426 sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
369 device_remove_file(dev, &dev->uevent_attr); 427 device_remove_file(dev, &dev->uevent_attr);
370 428
371 /* Notify the platform of the removal, in case they 429 /* Notify the platform of the removal, in case they
@@ -450,3 +508,105 @@ EXPORT_SYMBOL_GPL(put_device);
450 508
451EXPORT_SYMBOL_GPL(device_create_file); 509EXPORT_SYMBOL_GPL(device_create_file);
452EXPORT_SYMBOL_GPL(device_remove_file); 510EXPORT_SYMBOL_GPL(device_remove_file);
511
512
513static void device_create_release(struct device *dev)
514{
515 pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
516 kfree(dev);
517}
518
519/**
520 * device_create - creates a device and registers it with sysfs
521 * @cs: pointer to the struct class that this device should be registered to.
522 * @parent: pointer to the parent struct device of this new device, if any.
523 * @dev: the dev_t for the char device to be added.
524 * @fmt: string for the class device's name
525 *
526 * This function can be used by char device classes. A struct
527 * device will be created in sysfs, registered to the specified
528 * class.
529 * A "dev" file will be created, showing the dev_t for the device, if
530 * the dev_t is not 0,0.
531 * If a pointer to a parent struct device is passed in, the newly
532 * created struct device will be a child of that device in sysfs. The
533 * pointer to the struct device will be returned from the call. Any
534 * further sysfs files that might be required can be created using this
535 * pointer.
536 *
537 * Note: the struct class passed to this function must have previously
538 * been created with a call to class_create().
539 */
540struct device *device_create(struct class *class, struct device *parent,
541 dev_t devt, char *fmt, ...)
542{
543 va_list args;
544 struct device *dev = NULL;
545 int retval = -ENODEV;
546
547 if (class == NULL || IS_ERR(class))
548 goto error;
549 if (parent == NULL) {
550 printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
551 goto error;
552 }
553
554 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
555 if (!dev) {
556 retval = -ENOMEM;
557 goto error;
558 }
559
560 dev->devt = devt;
561 dev->class = class;
562 dev->parent = parent;
563 dev->release = device_create_release;
564
565 va_start(args, fmt);
566 vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
567 va_end(args);
568 retval = device_register(dev);
569 if (retval)
570 goto error;
571
572 /* tie the class to the device */
573 down(&class->sem);
574 list_add_tail(&dev->node, &class->devices);
575 up(&class->sem);
576
577 return dev;
578
579error:
580 kfree(dev);
581 return ERR_PTR(retval);
582}
583EXPORT_SYMBOL_GPL(device_create);
584
585/**
586 * device_destroy - removes a device that was created with device_create()
587 * @class: the pointer to the struct class that this device was registered * with.
588 * @dev: the dev_t of the device that was previously registered.
589 *
590 * This call unregisters and cleans up a class device that was created with a
591 * call to class_device_create()
592 */
593void device_destroy(struct class *class, dev_t devt)
594{
595 struct device *dev = NULL;
596 struct device *dev_tmp;
597
598 down(&class->sem);
599 list_for_each_entry(dev_tmp, &class->devices, node) {
600 if (dev_tmp->devt == devt) {
601 dev = dev_tmp;
602 break;
603 }
604 }
605 up(&class->sem);
606
607 if (dev) {
608 list_del_init(&dev->node);
609 device_unregister(dev);
610 }
611}
612EXPORT_SYMBOL_GPL(device_destroy);