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