diff options
Diffstat (limited to 'drivers/base/core.c')
| -rw-r--r-- | drivers/base/core.c | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index cf2a398aaaa1..d7fcf823a42a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -28,20 +28,6 @@ int (*platform_notify)(struct device * dev) = NULL; | |||
| 28 | int (*platform_notify_remove)(struct device * dev) = NULL; | 28 | int (*platform_notify_remove)(struct device * dev) = NULL; |
| 29 | 29 | ||
| 30 | /* | 30 | /* |
| 31 | * Detect the LANANA-assigned LOCAL/EXPERIMENTAL majors | ||
| 32 | */ | ||
| 33 | bool is_lanana_major(unsigned int major) | ||
| 34 | { | ||
| 35 | if (major >= 60 && major <= 63) | ||
| 36 | return 1; | ||
| 37 | if (major >= 120 && major <= 127) | ||
| 38 | return 1; | ||
| 39 | if (major >= 240 && major <= 254) | ||
| 40 | return 1; | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | /* | ||
| 45 | * sysfs bindings for devices. | 31 | * sysfs bindings for devices. |
| 46 | */ | 32 | */ |
| 47 | 33 | ||
| @@ -407,6 +393,35 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) | |||
| 407 | } | 393 | } |
| 408 | EXPORT_SYMBOL_GPL(device_remove_bin_file); | 394 | EXPORT_SYMBOL_GPL(device_remove_bin_file); |
| 409 | 395 | ||
| 396 | /** | ||
| 397 | * device_schedule_callback - helper to schedule a callback for a device | ||
| 398 | * @dev: device. | ||
| 399 | * @func: callback function to invoke later. | ||
| 400 | * | ||
| 401 | * Attribute methods must not unregister themselves or their parent device | ||
| 402 | * (which would amount to the same thing). Attempts to do so will deadlock, | ||
| 403 | * since unregistration is mutually exclusive with driver callbacks. | ||
| 404 | * | ||
| 405 | * Instead methods can call this routine, which will attempt to allocate | ||
| 406 | * and schedule a workqueue request to call back @func with @dev as its | ||
| 407 | * argument in the workqueue's process context. @dev will be pinned until | ||
| 408 | * @func returns. | ||
| 409 | * | ||
| 410 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | ||
| 411 | * be allocated. | ||
| 412 | * | ||
| 413 | * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an | ||
| 414 | * underlying sysfs routine (since it is intended for use by attribute | ||
| 415 | * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. | ||
| 416 | */ | ||
| 417 | int device_schedule_callback(struct device *dev, | ||
| 418 | void (*func)(struct device *)) | ||
| 419 | { | ||
| 420 | return sysfs_schedule_callback(&dev->kobj, | ||
| 421 | (void (*)(void *)) func, dev); | ||
| 422 | } | ||
| 423 | EXPORT_SYMBOL_GPL(device_schedule_callback); | ||
| 424 | |||
| 410 | static void klist_children_get(struct klist_node *n) | 425 | static void klist_children_get(struct klist_node *n) |
| 411 | { | 426 | { |
| 412 | struct device *dev = container_of(n, struct device, knode_parent); | 427 | struct device *dev = container_of(n, struct device, knode_parent); |
| @@ -584,17 +599,17 @@ int device_add(struct device *dev) | |||
| 584 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) | 599 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) |
| 585 | sysfs_create_link(&dev->class->subsys.kset.kobj, | 600 | sysfs_create_link(&dev->class->subsys.kset.kobj, |
| 586 | &dev->kobj, dev->bus_id); | 601 | &dev->kobj, dev->bus_id); |
| 587 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 588 | if (parent) { | 602 | if (parent) { |
| 589 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, | 603 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, |
| 590 | "device"); | 604 | "device"); |
| 605 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 591 | class_name = make_class_name(dev->class->name, | 606 | class_name = make_class_name(dev->class->name, |
| 592 | &dev->kobj); | 607 | &dev->kobj); |
| 593 | if (class_name) | 608 | if (class_name) |
| 594 | sysfs_create_link(&dev->parent->kobj, | 609 | sysfs_create_link(&dev->parent->kobj, |
| 595 | &dev->kobj, class_name); | 610 | &dev->kobj, class_name); |
| 596 | } | ||
| 597 | #endif | 611 | #endif |
| 612 | } | ||
| 598 | } | 613 | } |
| 599 | 614 | ||
| 600 | if ((error = device_add_attrs(dev))) | 615 | if ((error = device_add_attrs(dev))) |
| @@ -651,17 +666,17 @@ int device_add(struct device *dev) | |||
| 651 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) | 666 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) |
| 652 | sysfs_remove_link(&dev->class->subsys.kset.kobj, | 667 | sysfs_remove_link(&dev->class->subsys.kset.kobj, |
| 653 | dev->bus_id); | 668 | dev->bus_id); |
| 654 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 655 | if (parent) { | 669 | if (parent) { |
| 670 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 656 | char *class_name = make_class_name(dev->class->name, | 671 | char *class_name = make_class_name(dev->class->name, |
| 657 | &dev->kobj); | 672 | &dev->kobj); |
| 658 | if (class_name) | 673 | if (class_name) |
| 659 | sysfs_remove_link(&dev->parent->kobj, | 674 | sysfs_remove_link(&dev->parent->kobj, |
| 660 | class_name); | 675 | class_name); |
| 661 | kfree(class_name); | 676 | kfree(class_name); |
| 677 | #endif | ||
| 662 | sysfs_remove_link(&dev->kobj, "device"); | 678 | sysfs_remove_link(&dev->kobj, "device"); |
| 663 | } | 679 | } |
| 664 | #endif | ||
| 665 | 680 | ||
| 666 | down(&dev->class->sem); | 681 | down(&dev->class->sem); |
| 667 | /* notify any interfaces that the device is now gone */ | 682 | /* notify any interfaces that the device is now gone */ |
| @@ -761,17 +776,17 @@ void device_del(struct device * dev) | |||
| 761 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) | 776 | if (dev->kobj.parent != &dev->class->subsys.kset.kobj) |
| 762 | sysfs_remove_link(&dev->class->subsys.kset.kobj, | 777 | sysfs_remove_link(&dev->class->subsys.kset.kobj, |
| 763 | dev->bus_id); | 778 | dev->bus_id); |
| 764 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 765 | if (parent) { | 779 | if (parent) { |
| 780 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
| 766 | char *class_name = make_class_name(dev->class->name, | 781 | char *class_name = make_class_name(dev->class->name, |
| 767 | &dev->kobj); | 782 | &dev->kobj); |
| 768 | if (class_name) | 783 | if (class_name) |
| 769 | sysfs_remove_link(&dev->parent->kobj, | 784 | sysfs_remove_link(&dev->parent->kobj, |
| 770 | class_name); | 785 | class_name); |
| 771 | kfree(class_name); | 786 | kfree(class_name); |
| 787 | #endif | ||
| 772 | sysfs_remove_link(&dev->kobj, "device"); | 788 | sysfs_remove_link(&dev->kobj, "device"); |
| 773 | } | 789 | } |
| 774 | #endif | ||
| 775 | 790 | ||
| 776 | down(&dev->class->sem); | 791 | down(&dev->class->sem); |
| 777 | /* notify any interfaces that the device is now gone */ | 792 | /* notify any interfaces that the device is now gone */ |
| @@ -787,6 +802,13 @@ void device_del(struct device * dev) | |||
| 787 | device_remove_attrs(dev); | 802 | device_remove_attrs(dev); |
| 788 | bus_remove_device(dev); | 803 | bus_remove_device(dev); |
| 789 | 804 | ||
| 805 | /* | ||
| 806 | * Some platform devices are driven without driver attached | ||
| 807 | * and managed resources may have been acquired. Make sure | ||
| 808 | * all resources are released. | ||
| 809 | */ | ||
| 810 | devres_release_all(dev); | ||
| 811 | |||
| 790 | /* Notify the platform of the removal, in case they | 812 | /* Notify the platform of the removal, in case they |
| 791 | * need to do anything... | 813 | * need to do anything... |
| 792 | */ | 814 | */ |
| @@ -1058,14 +1080,14 @@ int device_rename(struct device *dev, char *new_name) | |||
| 1058 | 1080 | ||
| 1059 | return error; | 1081 | return error; |
| 1060 | } | 1082 | } |
| 1061 | 1083 | EXPORT_SYMBOL_GPL(device_rename); | |
| 1062 | 1084 | ||
| 1063 | static int device_move_class_links(struct device *dev, | 1085 | static int device_move_class_links(struct device *dev, |
| 1064 | struct device *old_parent, | 1086 | struct device *old_parent, |
| 1065 | struct device *new_parent) | 1087 | struct device *new_parent) |
| 1066 | { | 1088 | { |
| 1089 | int error = 0; | ||
| 1067 | #ifdef CONFIG_SYSFS_DEPRECATED | 1090 | #ifdef CONFIG_SYSFS_DEPRECATED |
| 1068 | int error; | ||
| 1069 | char *class_name; | 1091 | char *class_name; |
| 1070 | 1092 | ||
| 1071 | class_name = make_class_name(dev->class->name, &dev->kobj); | 1093 | class_name = make_class_name(dev->class->name, &dev->kobj); |
| @@ -1093,7 +1115,12 @@ out: | |||
| 1093 | kfree(class_name); | 1115 | kfree(class_name); |
| 1094 | return error; | 1116 | return error; |
| 1095 | #else | 1117 | #else |
| 1096 | return 0; | 1118 | if (old_parent) |
| 1119 | sysfs_remove_link(&dev->kobj, "device"); | ||
| 1120 | if (new_parent) | ||
| 1121 | error = sysfs_create_link(&dev->kobj, &new_parent->kobj, | ||
| 1122 | "device"); | ||
| 1123 | return error; | ||
| 1097 | #endif | 1124 | #endif |
| 1098 | } | 1125 | } |
| 1099 | 1126 | ||
