diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 241 |
1 files changed, 221 insertions, 20 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 68ad11af22b4..e4b530ef757d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
19 | #include <linux/kdev_t.h> | 19 | #include <linux/kdev_t.h> |
20 | #include <linux/notifier.h> | ||
20 | 21 | ||
21 | #include <asm/semaphore.h> | 22 | #include <asm/semaphore.h> |
22 | 23 | ||
@@ -153,20 +154,24 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
153 | "MINOR=%u", MINOR(dev->devt)); | 154 | "MINOR=%u", MINOR(dev->devt)); |
154 | } | 155 | } |
155 | 156 | ||
157 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
156 | /* add bus name (same as SUBSYSTEM, deprecated) */ | 158 | /* add bus name (same as SUBSYSTEM, deprecated) */ |
157 | if (dev->bus) | 159 | if (dev->bus) |
158 | add_uevent_var(envp, num_envp, &i, | 160 | add_uevent_var(envp, num_envp, &i, |
159 | buffer, buffer_size, &length, | 161 | buffer, buffer_size, &length, |
160 | "PHYSDEVBUS=%s", dev->bus->name); | 162 | "PHYSDEVBUS=%s", dev->bus->name); |
163 | #endif | ||
161 | 164 | ||
162 | /* add driver name (PHYSDEV* values are deprecated)*/ | 165 | /* add driver name (PHYSDEV* values are deprecated)*/ |
163 | if (dev->driver) { | 166 | if (dev->driver) { |
164 | add_uevent_var(envp, num_envp, &i, | 167 | add_uevent_var(envp, num_envp, &i, |
165 | buffer, buffer_size, &length, | 168 | buffer, buffer_size, &length, |
166 | "DRIVER=%s", dev->driver->name); | 169 | "DRIVER=%s", dev->driver->name); |
170 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
167 | add_uevent_var(envp, num_envp, &i, | 171 | add_uevent_var(envp, num_envp, &i, |
168 | buffer, buffer_size, &length, | 172 | buffer, buffer_size, &length, |
169 | "PHYSDEVDRIVER=%s", dev->driver->name); | 173 | "PHYSDEVDRIVER=%s", dev->driver->name); |
174 | #endif | ||
170 | } | 175 | } |
171 | 176 | ||
172 | /* terminate, set to next free slot, shrink available space */ | 177 | /* terminate, set to next free slot, shrink available space */ |
@@ -383,6 +388,52 @@ void device_initialize(struct device *dev) | |||
383 | device_init_wakeup(dev, 0); | 388 | device_init_wakeup(dev, 0); |
384 | } | 389 | } |
385 | 390 | ||
391 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
392 | static int setup_parent(struct device *dev, struct device *parent) | ||
393 | { | ||
394 | /* Set the parent to the class, not the parent device */ | ||
395 | /* this keeps sysfs from having a symlink to make old udevs happy */ | ||
396 | if (dev->class) | ||
397 | dev->kobj.parent = &dev->class->subsys.kset.kobj; | ||
398 | else if (parent) | ||
399 | dev->kobj.parent = &parent->kobj; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | #else | ||
404 | static int virtual_device_parent(struct device *dev) | ||
405 | { | ||
406 | if (!dev->class) | ||
407 | return -ENODEV; | ||
408 | |||
409 | if (!dev->class->virtual_dir) { | ||
410 | static struct kobject *virtual_dir = NULL; | ||
411 | |||
412 | if (!virtual_dir) | ||
413 | virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); | ||
414 | dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); | ||
415 | } | ||
416 | |||
417 | dev->kobj.parent = dev->class->virtual_dir; | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int setup_parent(struct device *dev, struct device *parent) | ||
422 | { | ||
423 | int error; | ||
424 | |||
425 | /* if this is a class device, and has no parent, create one */ | ||
426 | if ((dev->class) && (parent == NULL)) { | ||
427 | error = virtual_device_parent(dev); | ||
428 | if (error) | ||
429 | return error; | ||
430 | } else if (parent) | ||
431 | dev->kobj.parent = &parent->kobj; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | #endif | ||
436 | |||
386 | /** | 437 | /** |
387 | * device_add - add device to device hierarchy. | 438 | * device_add - add device to device hierarchy. |
388 | * @dev: device. | 439 | * @dev: device. |
@@ -405,29 +456,29 @@ int device_add(struct device *dev) | |||
405 | if (!dev || !strlen(dev->bus_id)) | 456 | if (!dev || !strlen(dev->bus_id)) |
406 | goto Error; | 457 | goto Error; |
407 | 458 | ||
408 | /* if this is a class device, and has no parent, create one */ | 459 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); |
409 | if ((dev->class) && (dev->parent == NULL)) { | ||
410 | error = virtual_device_parent(dev); | ||
411 | if (error) | ||
412 | goto Error; | ||
413 | } | ||
414 | 460 | ||
415 | parent = get_device(dev->parent); | 461 | parent = get_device(dev->parent); |
416 | 462 | ||
417 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); | 463 | error = setup_parent(dev, parent); |
464 | if (error) | ||
465 | goto Error; | ||
418 | 466 | ||
419 | /* first, register with generic layer. */ | 467 | /* first, register with generic layer. */ |
420 | kobject_set_name(&dev->kobj, "%s", dev->bus_id); | 468 | kobject_set_name(&dev->kobj, "%s", dev->bus_id); |
421 | if (parent) | 469 | error = kobject_add(&dev->kobj); |
422 | dev->kobj.parent = &parent->kobj; | 470 | if (error) |
423 | |||
424 | if ((error = kobject_add(&dev->kobj))) | ||
425 | goto Error; | 471 | goto Error; |
426 | 472 | ||
427 | /* notify platform of device entry */ | 473 | /* notify platform of device entry */ |
428 | if (platform_notify) | 474 | if (platform_notify) |
429 | platform_notify(dev); | 475 | platform_notify(dev); |
430 | 476 | ||
477 | /* notify clients of device entry (new way) */ | ||
478 | if (dev->bus) | ||
479 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
480 | BUS_NOTIFY_ADD_DEVICE, dev); | ||
481 | |||
431 | dev->uevent_attr.attr.name = "uevent"; | 482 | dev->uevent_attr.attr.name = "uevent"; |
432 | dev->uevent_attr.attr.mode = S_IWUSR; | 483 | dev->uevent_attr.attr.mode = S_IWUSR; |
433 | if (dev->driver) | 484 | if (dev->driver) |
@@ -461,13 +512,18 @@ int device_add(struct device *dev) | |||
461 | if (dev->class) { | 512 | if (dev->class) { |
462 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, | 513 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, |
463 | "subsystem"); | 514 | "subsystem"); |
464 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, | 515 | /* If this is not a "fake" compatible device, then create the |
465 | dev->bus_id); | 516 | * symlink from the class to the device. */ |
517 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) | ||
518 | sysfs_create_link(&dev->class->subsys.kset.kobj, | ||
519 | &dev->kobj, dev->bus_id); | ||
520 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
466 | if (parent) { | 521 | if (parent) { |
467 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); | 522 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); |
468 | class_name = make_class_name(dev->class->name, &dev->kobj); | 523 | class_name = make_class_name(dev->class->name, &dev->kobj); |
469 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); | 524 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); |
470 | } | 525 | } |
526 | #endif | ||
471 | } | 527 | } |
472 | 528 | ||
473 | if ((error = device_add_attrs(dev))) | 529 | if ((error = device_add_attrs(dev))) |
@@ -504,6 +560,9 @@ int device_add(struct device *dev) | |||
504 | BusError: | 560 | BusError: |
505 | device_pm_remove(dev); | 561 | device_pm_remove(dev); |
506 | PMError: | 562 | PMError: |
563 | if (dev->bus) | ||
564 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
565 | BUS_NOTIFY_DEL_DEVICE, dev); | ||
507 | device_remove_groups(dev); | 566 | device_remove_groups(dev); |
508 | GroupError: | 567 | GroupError: |
509 | device_remove_attrs(dev); | 568 | device_remove_attrs(dev); |
@@ -586,22 +645,31 @@ void put_device(struct device * dev) | |||
586 | void device_del(struct device * dev) | 645 | void device_del(struct device * dev) |
587 | { | 646 | { |
588 | struct device * parent = dev->parent; | 647 | struct device * parent = dev->parent; |
589 | char *class_name = NULL; | ||
590 | struct class_interface *class_intf; | 648 | struct class_interface *class_intf; |
591 | 649 | ||
592 | if (parent) | 650 | if (parent) |
593 | klist_del(&dev->knode_parent); | 651 | klist_del(&dev->knode_parent); |
594 | if (dev->devt_attr) | 652 | if (dev->devt_attr) { |
595 | device_remove_file(dev, dev->devt_attr); | 653 | device_remove_file(dev, dev->devt_attr); |
654 | kfree(dev->devt_attr); | ||
655 | } | ||
596 | if (dev->class) { | 656 | if (dev->class) { |
597 | sysfs_remove_link(&dev->kobj, "subsystem"); | 657 | sysfs_remove_link(&dev->kobj, "subsystem"); |
598 | sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); | 658 | /* If this is not a "fake" compatible device, remove the |
599 | class_name = make_class_name(dev->class->name, &dev->kobj); | 659 | * symlink from the class to the device. */ |
660 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) | ||
661 | sysfs_remove_link(&dev->class->subsys.kset.kobj, | ||
662 | dev->bus_id); | ||
663 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
600 | if (parent) { | 664 | if (parent) { |
601 | sysfs_remove_link(&dev->kobj, "device"); | 665 | char *class_name = make_class_name(dev->class->name, |
666 | &dev->kobj); | ||
602 | sysfs_remove_link(&dev->parent->kobj, class_name); | 667 | sysfs_remove_link(&dev->parent->kobj, class_name); |
668 | kfree(class_name); | ||
669 | sysfs_remove_link(&dev->kobj, "device"); | ||
603 | } | 670 | } |
604 | kfree(class_name); | 671 | #endif |
672 | |||
605 | down(&dev->class->sem); | 673 | down(&dev->class->sem); |
606 | /* notify any interfaces that the device is now gone */ | 674 | /* notify any interfaces that the device is now gone */ |
607 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | 675 | list_for_each_entry(class_intf, &dev->class->interfaces, node) |
@@ -614,13 +682,16 @@ void device_del(struct device * dev) | |||
614 | device_remove_file(dev, &dev->uevent_attr); | 682 | device_remove_file(dev, &dev->uevent_attr); |
615 | device_remove_groups(dev); | 683 | device_remove_groups(dev); |
616 | device_remove_attrs(dev); | 684 | device_remove_attrs(dev); |
685 | bus_remove_device(dev); | ||
617 | 686 | ||
618 | /* Notify the platform of the removal, in case they | 687 | /* Notify the platform of the removal, in case they |
619 | * need to do anything... | 688 | * need to do anything... |
620 | */ | 689 | */ |
621 | if (platform_notify_remove) | 690 | if (platform_notify_remove) |
622 | platform_notify_remove(dev); | 691 | platform_notify_remove(dev); |
623 | bus_remove_device(dev); | 692 | if (dev->bus) |
693 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
694 | BUS_NOTIFY_DEL_DEVICE, dev); | ||
624 | device_pm_remove(dev); | 695 | device_pm_remove(dev); |
625 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); | 696 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); |
626 | kobject_del(&dev->kobj); | 697 | kobject_del(&dev->kobj); |
@@ -679,12 +750,45 @@ int device_for_each_child(struct device * parent, void * data, | |||
679 | return error; | 750 | return error; |
680 | } | 751 | } |
681 | 752 | ||
753 | /** | ||
754 | * device_find_child - device iterator for locating a particular device. | ||
755 | * @parent: parent struct device | ||
756 | * @data: Data to pass to match function | ||
757 | * @match: Callback function to check device | ||
758 | * | ||
759 | * This is similar to the device_for_each_child() function above, but it | ||
760 | * returns a reference to a device that is 'found' for later use, as | ||
761 | * determined by the @match callback. | ||
762 | * | ||
763 | * The callback should return 0 if the device doesn't match and non-zero | ||
764 | * if it does. If the callback returns non-zero and a reference to the | ||
765 | * current device can be obtained, this function will return to the caller | ||
766 | * and not iterate over any more devices. | ||
767 | */ | ||
768 | struct device * device_find_child(struct device *parent, void *data, | ||
769 | int (*match)(struct device *, void *)) | ||
770 | { | ||
771 | struct klist_iter i; | ||
772 | struct device *child; | ||
773 | |||
774 | if (!parent) | ||
775 | return NULL; | ||
776 | |||
777 | klist_iter_init(&parent->klist_children, &i); | ||
778 | while ((child = next_device(&i))) | ||
779 | if (match(child, data) && get_device(child)) | ||
780 | break; | ||
781 | klist_iter_exit(&i); | ||
782 | return child; | ||
783 | } | ||
784 | |||
682 | int __init devices_init(void) | 785 | int __init devices_init(void) |
683 | { | 786 | { |
684 | return subsystem_register(&devices_subsys); | 787 | return subsystem_register(&devices_subsys); |
685 | } | 788 | } |
686 | 789 | ||
687 | EXPORT_SYMBOL_GPL(device_for_each_child); | 790 | EXPORT_SYMBOL_GPL(device_for_each_child); |
791 | EXPORT_SYMBOL_GPL(device_find_child); | ||
688 | 792 | ||
689 | EXPORT_SYMBOL_GPL(device_initialize); | 793 | EXPORT_SYMBOL_GPL(device_initialize); |
690 | EXPORT_SYMBOL_GPL(device_add); | 794 | EXPORT_SYMBOL_GPL(device_add); |
@@ -807,8 +911,10 @@ int device_rename(struct device *dev, char *new_name) | |||
807 | 911 | ||
808 | pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); | 912 | pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); |
809 | 913 | ||
914 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
810 | if ((dev->class) && (dev->parent)) | 915 | if ((dev->class) && (dev->parent)) |
811 | old_class_name = make_class_name(dev->class->name, &dev->kobj); | 916 | old_class_name = make_class_name(dev->class->name, &dev->kobj); |
917 | #endif | ||
812 | 918 | ||
813 | if (dev->class) { | 919 | if (dev->class) { |
814 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | 920 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); |
@@ -823,6 +929,7 @@ int device_rename(struct device *dev, char *new_name) | |||
823 | 929 | ||
824 | error = kobject_rename(&dev->kobj, new_name); | 930 | error = kobject_rename(&dev->kobj, new_name); |
825 | 931 | ||
932 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
826 | if (old_class_name) { | 933 | if (old_class_name) { |
827 | new_class_name = make_class_name(dev->class->name, &dev->kobj); | 934 | new_class_name = make_class_name(dev->class->name, &dev->kobj); |
828 | if (new_class_name) { | 935 | if (new_class_name) { |
@@ -831,6 +938,8 @@ int device_rename(struct device *dev, char *new_name) | |||
831 | sysfs_remove_link(&dev->parent->kobj, old_class_name); | 938 | sysfs_remove_link(&dev->parent->kobj, old_class_name); |
832 | } | 939 | } |
833 | } | 940 | } |
941 | #endif | ||
942 | |||
834 | if (dev->class) { | 943 | if (dev->class) { |
835 | sysfs_remove_link(&dev->class->subsys.kset.kobj, | 944 | sysfs_remove_link(&dev->class->subsys.kset.kobj, |
836 | old_symlink_name); | 945 | old_symlink_name); |
@@ -846,3 +955,95 @@ int device_rename(struct device *dev, char *new_name) | |||
846 | 955 | ||
847 | return error; | 956 | return error; |
848 | } | 957 | } |
958 | |||
959 | |||
960 | static int device_move_class_links(struct device *dev, | ||
961 | struct device *old_parent, | ||
962 | struct device *new_parent) | ||
963 | { | ||
964 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
965 | int error; | ||
966 | char *class_name; | ||
967 | |||
968 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
969 | if (!class_name) { | ||
970 | error = PTR_ERR(class_name); | ||
971 | class_name = NULL; | ||
972 | goto out; | ||
973 | } | ||
974 | if (old_parent) { | ||
975 | sysfs_remove_link(&dev->kobj, "device"); | ||
976 | sysfs_remove_link(&old_parent->kobj, class_name); | ||
977 | } | ||
978 | error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); | ||
979 | if (error) | ||
980 | goto out; | ||
981 | error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); | ||
982 | if (error) | ||
983 | sysfs_remove_link(&dev->kobj, "device"); | ||
984 | out: | ||
985 | kfree(class_name); | ||
986 | return error; | ||
987 | #else | ||
988 | return 0; | ||
989 | #endif | ||
990 | } | ||
991 | |||
992 | /** | ||
993 | * device_move - moves a device to a new parent | ||
994 | * @dev: the pointer to the struct device to be moved | ||
995 | * @new_parent: the new parent of the device | ||
996 | */ | ||
997 | int device_move(struct device *dev, struct device *new_parent) | ||
998 | { | ||
999 | int error; | ||
1000 | struct device *old_parent; | ||
1001 | |||
1002 | dev = get_device(dev); | ||
1003 | if (!dev) | ||
1004 | return -EINVAL; | ||
1005 | |||
1006 | if (!device_is_registered(dev)) { | ||
1007 | error = -EINVAL; | ||
1008 | goto out; | ||
1009 | } | ||
1010 | new_parent = get_device(new_parent); | ||
1011 | if (!new_parent) { | ||
1012 | error = -EINVAL; | ||
1013 | goto out; | ||
1014 | } | ||
1015 | pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, | ||
1016 | new_parent->bus_id); | ||
1017 | error = kobject_move(&dev->kobj, &new_parent->kobj); | ||
1018 | if (error) { | ||
1019 | put_device(new_parent); | ||
1020 | goto out; | ||
1021 | } | ||
1022 | old_parent = dev->parent; | ||
1023 | dev->parent = new_parent; | ||
1024 | if (old_parent) | ||
1025 | klist_remove(&dev->knode_parent); | ||
1026 | klist_add_tail(&dev->knode_parent, &new_parent->klist_children); | ||
1027 | if (!dev->class) | ||
1028 | goto out_put; | ||
1029 | error = device_move_class_links(dev, old_parent, new_parent); | ||
1030 | if (error) { | ||
1031 | /* We ignore errors on cleanup since we're hosed anyway... */ | ||
1032 | device_move_class_links(dev, new_parent, old_parent); | ||
1033 | if (!kobject_move(&dev->kobj, &old_parent->kobj)) { | ||
1034 | klist_remove(&dev->knode_parent); | ||
1035 | if (old_parent) | ||
1036 | klist_add_tail(&dev->knode_parent, | ||
1037 | &old_parent->klist_children); | ||
1038 | } | ||
1039 | put_device(new_parent); | ||
1040 | goto out; | ||
1041 | } | ||
1042 | out_put: | ||
1043 | put_device(old_parent); | ||
1044 | out: | ||
1045 | put_device(dev); | ||
1046 | return error; | ||
1047 | } | ||
1048 | |||
1049 | EXPORT_SYMBOL_GPL(device_move); | ||