diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 194 |
1 files changed, 180 insertions, 14 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index d2a2f8f2b4ed..479c12570881 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
18 | #include <linux/kdev_t.h> | 18 | #include <linux/kdev_t.h> |
19 | #include <linux/err.h> | ||
19 | #include "base.h" | 20 | #include "base.h" |
20 | 21 | ||
21 | #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) | 22 | #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) |
@@ -26,7 +27,7 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) | |||
26 | { | 27 | { |
27 | struct class_attribute * class_attr = to_class_attr(attr); | 28 | struct class_attribute * class_attr = to_class_attr(attr); |
28 | struct class * dc = to_class(kobj); | 29 | struct class * dc = to_class(kobj); |
29 | ssize_t ret = 0; | 30 | ssize_t ret = -EIO; |
30 | 31 | ||
31 | if (class_attr->show) | 32 | if (class_attr->show) |
32 | ret = class_attr->show(dc, buf); | 33 | ret = class_attr->show(dc, buf); |
@@ -39,7 +40,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr, | |||
39 | { | 40 | { |
40 | struct class_attribute * class_attr = to_class_attr(attr); | 41 | struct class_attribute * class_attr = to_class_attr(attr); |
41 | struct class * dc = to_class(kobj); | 42 | struct class * dc = to_class(kobj); |
42 | ssize_t ret = 0; | 43 | ssize_t ret = -EIO; |
43 | 44 | ||
44 | if (class_attr->store) | 45 | if (class_attr->store) |
45 | ret = class_attr->store(dc, buf, count); | 46 | ret = class_attr->store(dc, buf, count); |
@@ -162,6 +163,69 @@ void class_unregister(struct class * cls) | |||
162 | subsystem_unregister(&cls->subsys); | 163 | subsystem_unregister(&cls->subsys); |
163 | } | 164 | } |
164 | 165 | ||
166 | static void class_create_release(struct class *cls) | ||
167 | { | ||
168 | kfree(cls); | ||
169 | } | ||
170 | |||
171 | static void class_device_create_release(struct class_device *class_dev) | ||
172 | { | ||
173 | kfree(class_dev); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * class_create - create a struct class structure | ||
178 | * @owner: pointer to the module that is to "own" this struct class | ||
179 | * @name: pointer to a string for the name of this class. | ||
180 | * | ||
181 | * This is used to create a struct class pointer that can then be used | ||
182 | * in calls to class_device_create(). | ||
183 | * | ||
184 | * Note, the pointer created here is to be destroyed when finished by | ||
185 | * making a call to class_destroy(). | ||
186 | */ | ||
187 | struct class *class_create(struct module *owner, char *name) | ||
188 | { | ||
189 | struct class *cls; | ||
190 | int retval; | ||
191 | |||
192 | cls = kmalloc(sizeof(struct class), GFP_KERNEL); | ||
193 | if (!cls) { | ||
194 | retval = -ENOMEM; | ||
195 | goto error; | ||
196 | } | ||
197 | memset(cls, 0x00, sizeof(struct class)); | ||
198 | |||
199 | cls->name = name; | ||
200 | cls->owner = owner; | ||
201 | cls->class_release = class_create_release; | ||
202 | cls->release = class_device_create_release; | ||
203 | |||
204 | retval = class_register(cls); | ||
205 | if (retval) | ||
206 | goto error; | ||
207 | |||
208 | return cls; | ||
209 | |||
210 | error: | ||
211 | kfree(cls); | ||
212 | return ERR_PTR(retval); | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * class_destroy - destroys a struct class structure | ||
217 | * @cs: pointer to the struct class that is to be destroyed | ||
218 | * | ||
219 | * Note, the pointer to be destroyed must have been created with a call | ||
220 | * to class_create(). | ||
221 | */ | ||
222 | void class_destroy(struct class *cls) | ||
223 | { | ||
224 | if ((cls == NULL) || (IS_ERR(cls))) | ||
225 | return; | ||
226 | |||
227 | class_unregister(cls); | ||
228 | } | ||
165 | 229 | ||
166 | /* Class Device Stuff */ | 230 | /* Class Device Stuff */ |
167 | 231 | ||
@@ -262,7 +326,7 @@ static int class_hotplug_filter(struct kset *kset, struct kobject *kobj) | |||
262 | return 0; | 326 | return 0; |
263 | } | 327 | } |
264 | 328 | ||
265 | static char *class_hotplug_name(struct kset *kset, struct kobject *kobj) | 329 | static const char *class_hotplug_name(struct kset *kset, struct kobject *kobj) |
266 | { | 330 | { |
267 | struct class_device *class_dev = to_class_dev(kobj); | 331 | struct class_device *class_dev = to_class_dev(kobj); |
268 | 332 | ||
@@ -375,7 +439,6 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) | |||
375 | { | 439 | { |
376 | return print_dev_t(buf, class_dev->devt); | 440 | return print_dev_t(buf, class_dev->devt); |
377 | } | 441 | } |
378 | static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); | ||
379 | 442 | ||
380 | void class_device_initialize(struct class_device *class_dev) | 443 | void class_device_initialize(struct class_device *class_dev) |
381 | { | 444 | { |
@@ -412,7 +475,31 @@ int class_device_add(struct class_device *class_dev) | |||
412 | if ((error = kobject_add(&class_dev->kobj))) | 475 | if ((error = kobject_add(&class_dev->kobj))) |
413 | goto register_done; | 476 | goto register_done; |
414 | 477 | ||
415 | /* now take care of our own registration */ | 478 | /* add the needed attributes to this device */ |
479 | if (MAJOR(class_dev->devt)) { | ||
480 | struct class_device_attribute *attr; | ||
481 | attr = kmalloc(sizeof(*attr), GFP_KERNEL); | ||
482 | if (!attr) { | ||
483 | error = -ENOMEM; | ||
484 | kobject_del(&class_dev->kobj); | ||
485 | goto register_done; | ||
486 | } | ||
487 | memset(attr, sizeof(*attr), 0x00); | ||
488 | attr->attr.name = "dev"; | ||
489 | attr->attr.mode = S_IRUGO; | ||
490 | attr->attr.owner = parent->owner; | ||
491 | attr->show = show_dev; | ||
492 | attr->store = NULL; | ||
493 | class_device_create_file(class_dev, attr); | ||
494 | class_dev->devt_attr = attr; | ||
495 | } | ||
496 | |||
497 | class_device_add_attrs(class_dev); | ||
498 | if (class_dev->dev) | ||
499 | sysfs_create_link(&class_dev->kobj, | ||
500 | &class_dev->dev->kobj, "device"); | ||
501 | |||
502 | /* notify any interfaces this device is now here */ | ||
416 | if (parent) { | 503 | if (parent) { |
417 | down(&parent->sem); | 504 | down(&parent->sem); |
418 | list_add_tail(&class_dev->node, &parent->children); | 505 | list_add_tail(&class_dev->node, &parent->children); |
@@ -421,16 +508,8 @@ int class_device_add(struct class_device *class_dev) | |||
421 | class_intf->add(class_dev); | 508 | class_intf->add(class_dev); |
422 | up(&parent->sem); | 509 | up(&parent->sem); |
423 | } | 510 | } |
424 | |||
425 | if (MAJOR(class_dev->devt)) | ||
426 | class_device_create_file(class_dev, &class_device_attr_dev); | ||
427 | |||
428 | class_device_add_attrs(class_dev); | ||
429 | if (class_dev->dev) | ||
430 | sysfs_create_link(&class_dev->kobj, | ||
431 | &class_dev->dev->kobj, "device"); | ||
432 | |||
433 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); | 511 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); |
512 | |||
434 | register_done: | 513 | register_done: |
435 | if (error && parent) | 514 | if (error && parent) |
436 | class_put(parent); | 515 | class_put(parent); |
@@ -444,6 +523,58 @@ int class_device_register(struct class_device *class_dev) | |||
444 | return class_device_add(class_dev); | 523 | return class_device_add(class_dev); |
445 | } | 524 | } |
446 | 525 | ||
526 | /** | ||
527 | * class_device_create - creates a class device and registers it with sysfs | ||
528 | * @cs: pointer to the struct class that this device should be registered to. | ||
529 | * @dev: the dev_t for the char device to be added. | ||
530 | * @device: a pointer to a struct device that is assiociated with this class device. | ||
531 | * @fmt: string for the class device's name | ||
532 | * | ||
533 | * This function can be used by char device classes. A struct | ||
534 | * class_device will be created in sysfs, registered to the specified | ||
535 | * class. A "dev" file will be created, showing the dev_t for the | ||
536 | * device. The pointer to the struct class_device will be returned from | ||
537 | * the call. Any further sysfs files that might be required can be | ||
538 | * created using this pointer. | ||
539 | * | ||
540 | * Note: the struct class passed to this function must have previously | ||
541 | * been created with a call to class_create(). | ||
542 | */ | ||
543 | struct class_device *class_device_create(struct class *cls, dev_t devt, | ||
544 | struct device *device, char *fmt, ...) | ||
545 | { | ||
546 | va_list args; | ||
547 | struct class_device *class_dev = NULL; | ||
548 | int retval = -ENODEV; | ||
549 | |||
550 | if (cls == NULL || IS_ERR(cls)) | ||
551 | goto error; | ||
552 | |||
553 | class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); | ||
554 | if (!class_dev) { | ||
555 | retval = -ENOMEM; | ||
556 | goto error; | ||
557 | } | ||
558 | memset(class_dev, 0x00, sizeof(struct class_device)); | ||
559 | |||
560 | class_dev->devt = devt; | ||
561 | class_dev->dev = device; | ||
562 | class_dev->class = cls; | ||
563 | |||
564 | va_start(args, fmt); | ||
565 | vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args); | ||
566 | va_end(args); | ||
567 | retval = class_device_register(class_dev); | ||
568 | if (retval) | ||
569 | goto error; | ||
570 | |||
571 | return class_dev; | ||
572 | |||
573 | error: | ||
574 | kfree(class_dev); | ||
575 | return ERR_PTR(retval); | ||
576 | } | ||
577 | |||
447 | void class_device_del(struct class_device *class_dev) | 578 | void class_device_del(struct class_device *class_dev) |
448 | { | 579 | { |
449 | struct class * parent = class_dev->class; | 580 | struct class * parent = class_dev->class; |
@@ -460,6 +591,11 @@ void class_device_del(struct class_device *class_dev) | |||
460 | 591 | ||
461 | if (class_dev->dev) | 592 | if (class_dev->dev) |
462 | sysfs_remove_link(&class_dev->kobj, "device"); | 593 | sysfs_remove_link(&class_dev->kobj, "device"); |
594 | if (class_dev->devt_attr) { | ||
595 | class_device_remove_file(class_dev, class_dev->devt_attr); | ||
596 | kfree(class_dev->devt_attr); | ||
597 | class_dev->devt_attr = NULL; | ||
598 | } | ||
463 | class_device_remove_attrs(class_dev); | 599 | class_device_remove_attrs(class_dev); |
464 | 600 | ||
465 | kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); | 601 | kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); |
@@ -477,6 +613,32 @@ void class_device_unregister(struct class_device *class_dev) | |||
477 | class_device_put(class_dev); | 613 | class_device_put(class_dev); |
478 | } | 614 | } |
479 | 615 | ||
616 | /** | ||
617 | * class_device_destroy - removes a class device that was created with class_device_create() | ||
618 | * @cls: the pointer to the struct class that this device was registered * with. | ||
619 | * @dev: the dev_t of the device that was previously registered. | ||
620 | * | ||
621 | * This call unregisters and cleans up a class device that was created with a | ||
622 | * call to class_device_create() | ||
623 | */ | ||
624 | void class_device_destroy(struct class *cls, dev_t devt) | ||
625 | { | ||
626 | struct class_device *class_dev = NULL; | ||
627 | struct class_device *class_dev_tmp; | ||
628 | |||
629 | down(&cls->sem); | ||
630 | list_for_each_entry(class_dev_tmp, &cls->children, node) { | ||
631 | if (class_dev_tmp->devt == devt) { | ||
632 | class_dev = class_dev_tmp; | ||
633 | break; | ||
634 | } | ||
635 | } | ||
636 | up(&cls->sem); | ||
637 | |||
638 | if (class_dev) | ||
639 | class_device_unregister(class_dev); | ||
640 | } | ||
641 | |||
480 | int class_device_rename(struct class_device *class_dev, char *new_name) | 642 | int class_device_rename(struct class_device *class_dev, char *new_name) |
481 | { | 643 | { |
482 | int error = 0; | 644 | int error = 0; |
@@ -576,6 +738,8 @@ EXPORT_SYMBOL_GPL(class_register); | |||
576 | EXPORT_SYMBOL_GPL(class_unregister); | 738 | EXPORT_SYMBOL_GPL(class_unregister); |
577 | EXPORT_SYMBOL_GPL(class_get); | 739 | EXPORT_SYMBOL_GPL(class_get); |
578 | EXPORT_SYMBOL_GPL(class_put); | 740 | EXPORT_SYMBOL_GPL(class_put); |
741 | EXPORT_SYMBOL_GPL(class_create); | ||
742 | EXPORT_SYMBOL_GPL(class_destroy); | ||
579 | 743 | ||
580 | EXPORT_SYMBOL_GPL(class_device_register); | 744 | EXPORT_SYMBOL_GPL(class_device_register); |
581 | EXPORT_SYMBOL_GPL(class_device_unregister); | 745 | EXPORT_SYMBOL_GPL(class_device_unregister); |
@@ -584,6 +748,8 @@ EXPORT_SYMBOL_GPL(class_device_add); | |||
584 | EXPORT_SYMBOL_GPL(class_device_del); | 748 | EXPORT_SYMBOL_GPL(class_device_del); |
585 | EXPORT_SYMBOL_GPL(class_device_get); | 749 | EXPORT_SYMBOL_GPL(class_device_get); |
586 | EXPORT_SYMBOL_GPL(class_device_put); | 750 | EXPORT_SYMBOL_GPL(class_device_put); |
751 | EXPORT_SYMBOL_GPL(class_device_create); | ||
752 | EXPORT_SYMBOL_GPL(class_device_destroy); | ||
587 | EXPORT_SYMBOL_GPL(class_device_create_file); | 753 | EXPORT_SYMBOL_GPL(class_device_create_file); |
588 | EXPORT_SYMBOL_GPL(class_device_remove_file); | 754 | EXPORT_SYMBOL_GPL(class_device_remove_file); |
589 | EXPORT_SYMBOL_GPL(class_device_create_bin_file); | 755 | EXPORT_SYMBOL_GPL(class_device_create_bin_file); |