diff options
-rw-r--r-- | drivers/base/bus.c | 14 | ||||
-rw-r--r-- | drivers/base/core.c | 12 | ||||
-rw-r--r-- | drivers/base/dd.c | 10 | ||||
-rw-r--r-- | include/linux/device.h | 25 |
4 files changed, 61 insertions, 0 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7d8a7ce73fb3..ed3e8a2be64a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -724,6 +724,8 @@ int bus_register(struct bus_type * bus) | |||
724 | { | 724 | { |
725 | int retval; | 725 | int retval; |
726 | 726 | ||
727 | BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); | ||
728 | |||
727 | retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); | 729 | retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); |
728 | if (retval) | 730 | if (retval) |
729 | goto out; | 731 | goto out; |
@@ -782,6 +784,18 @@ void bus_unregister(struct bus_type * bus) | |||
782 | subsystem_unregister(&bus->subsys); | 784 | subsystem_unregister(&bus->subsys); |
783 | } | 785 | } |
784 | 786 | ||
787 | int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) | ||
788 | { | ||
789 | return blocking_notifier_chain_register(&bus->bus_notifier, nb); | ||
790 | } | ||
791 | EXPORT_SYMBOL_GPL(bus_register_notifier); | ||
792 | |||
793 | int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) | ||
794 | { | ||
795 | return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); | ||
796 | } | ||
797 | EXPORT_SYMBOL_GPL(bus_unregister_notifier); | ||
798 | |||
785 | int __init buses_init(void) | 799 | int __init buses_init(void) |
786 | { | 800 | { |
787 | return subsystem_register(&bus_subsys); | 801 | return subsystem_register(&bus_subsys); |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 002fde46d38d..d4f35d8902a2 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 | ||
@@ -428,6 +429,11 @@ int device_add(struct device *dev) | |||
428 | if (platform_notify) | 429 | if (platform_notify) |
429 | platform_notify(dev); | 430 | platform_notify(dev); |
430 | 431 | ||
432 | /* notify clients of device entry (new way) */ | ||
433 | if (dev->bus) | ||
434 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
435 | BUS_NOTIFY_ADD_DEVICE, dev); | ||
436 | |||
431 | dev->uevent_attr.attr.name = "uevent"; | 437 | dev->uevent_attr.attr.name = "uevent"; |
432 | dev->uevent_attr.attr.mode = S_IWUSR; | 438 | dev->uevent_attr.attr.mode = S_IWUSR; |
433 | if (dev->driver) | 439 | if (dev->driver) |
@@ -504,6 +510,9 @@ int device_add(struct device *dev) | |||
504 | BusError: | 510 | BusError: |
505 | device_pm_remove(dev); | 511 | device_pm_remove(dev); |
506 | PMError: | 512 | PMError: |
513 | if (dev->bus) | ||
514 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
515 | BUS_NOTIFY_DEL_DEVICE, dev); | ||
507 | device_remove_groups(dev); | 516 | device_remove_groups(dev); |
508 | GroupError: | 517 | GroupError: |
509 | device_remove_attrs(dev); | 518 | device_remove_attrs(dev); |
@@ -622,6 +631,9 @@ void device_del(struct device * dev) | |||
622 | */ | 631 | */ |
623 | if (platform_notify_remove) | 632 | if (platform_notify_remove) |
624 | platform_notify_remove(dev); | 633 | platform_notify_remove(dev); |
634 | if (dev->bus) | ||
635 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
636 | BUS_NOTIFY_DEL_DEVICE, dev); | ||
625 | bus_remove_device(dev); | 637 | bus_remove_device(dev); |
626 | device_pm_remove(dev); | 638 | device_pm_remove(dev); |
627 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); | 639 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); |
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c5d6bb4290ad..9c88b1e34bc3 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -52,6 +52,11 @@ int device_bind_driver(struct device *dev) | |||
52 | 52 | ||
53 | pr_debug("bound device '%s' to driver '%s'\n", | 53 | pr_debug("bound device '%s' to driver '%s'\n", |
54 | dev->bus_id, dev->driver->name); | 54 | dev->bus_id, dev->driver->name); |
55 | |||
56 | if (dev->bus) | ||
57 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
58 | BUS_NOTIFY_BOUND_DRIVER, dev); | ||
59 | |||
55 | klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); | 60 | klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); |
56 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 61 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
57 | kobject_name(&dev->kobj)); | 62 | kobject_name(&dev->kobj)); |
@@ -288,6 +293,11 @@ static void __device_release_driver(struct device * dev) | |||
288 | sysfs_remove_link(&dev->kobj, "driver"); | 293 | sysfs_remove_link(&dev->kobj, "driver"); |
289 | klist_remove(&dev->knode_driver); | 294 | klist_remove(&dev->knode_driver); |
290 | 295 | ||
296 | if (dev->bus) | ||
297 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
298 | BUS_NOTIFY_UNBIND_DRIVER, | ||
299 | dev); | ||
300 | |||
291 | if (dev->bus && dev->bus->remove) | 301 | if (dev->bus && dev->bus->remove) |
292 | dev->bus->remove(dev); | 302 | dev->bus->remove(dev); |
293 | else if (drv->remove) | 303 | else if (drv->remove) |
diff --git a/include/linux/device.h b/include/linux/device.h index 9d4f6a963936..b00e02711393 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -42,6 +42,8 @@ struct bus_type { | |||
42 | struct klist klist_devices; | 42 | struct klist klist_devices; |
43 | struct klist klist_drivers; | 43 | struct klist klist_drivers; |
44 | 44 | ||
45 | struct blocking_notifier_head bus_notifier; | ||
46 | |||
45 | struct bus_attribute * bus_attrs; | 47 | struct bus_attribute * bus_attrs; |
46 | struct device_attribute * dev_attrs; | 48 | struct device_attribute * dev_attrs; |
47 | struct driver_attribute * drv_attrs; | 49 | struct driver_attribute * drv_attrs; |
@@ -75,6 +77,29 @@ int __must_check bus_for_each_drv(struct bus_type *bus, | |||
75 | struct device_driver *start, void *data, | 77 | struct device_driver *start, void *data, |
76 | int (*fn)(struct device_driver *, void *)); | 78 | int (*fn)(struct device_driver *, void *)); |
77 | 79 | ||
80 | /* | ||
81 | * Bus notifiers: Get notified of addition/removal of devices | ||
82 | * and binding/unbinding of drivers to devices. | ||
83 | * In the long run, it should be a replacement for the platform | ||
84 | * notify hooks. | ||
85 | */ | ||
86 | struct notifier_block; | ||
87 | |||
88 | extern int bus_register_notifier(struct bus_type *bus, | ||
89 | struct notifier_block *nb); | ||
90 | extern int bus_unregister_notifier(struct bus_type *bus, | ||
91 | struct notifier_block *nb); | ||
92 | |||
93 | /* All 4 notifers below get called with the target struct device * | ||
94 | * as an argument. Note that those functions are likely to be called | ||
95 | * with the device semaphore held in the core, so be careful. | ||
96 | */ | ||
97 | #define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ | ||
98 | #define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */ | ||
99 | #define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */ | ||
100 | #define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be | ||
101 | unbound */ | ||
102 | |||
78 | /* driverfs interface for exporting bus attributes */ | 103 | /* driverfs interface for exporting bus attributes */ |
79 | 104 | ||
80 | struct bus_attribute { | 105 | struct bus_attribute { |