Signed-off-by: Andrew Morton --- drivers/base/bus.c | 14 ++++++++++++++ drivers/base/core.c | 12 ++++++++++++ drivers/base/dd.c | 10 ++++++++++ include/linux/device.h | 25 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+) diff -puN drivers/base/bus.c~gregkh-driver-driver-core-add-notification-of-bus-events drivers/base/bus.c --- a/drivers/base/bus.c~gregkh-driver-driver-core-add-notification-of-bus-events +++ a/drivers/base/bus.c @@ -724,6 +724,8 @@ int bus_register(struct bus_type * bus) { int retval; + BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name); if (retval) goto out; @@ -782,6 +784,18 @@ void bus_unregister(struct bus_type * bu subsystem_unregister(&bus->subsys); } +int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_register_notifier); + +int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); +} +EXPORT_SYMBOL_GPL(bus_unregister_notifier); + int __init buses_init(void) { return subsystem_register(&bus_subsys); diff -puN drivers/base/core.c~gregkh-driver-driver-core-add-notification-of-bus-events drivers/base/core.c --- a/drivers/base/core.c~gregkh-driver-driver-core-add-notification-of-bus-events +++ a/drivers/base/core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -428,6 +429,11 @@ int device_add(struct device *dev) if (platform_notify) platform_notify(dev); + /* notify clients of device entry (new way) */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_ADD_DEVICE, dev); + dev->uevent_attr.attr.name = "uevent"; dev->uevent_attr.attr.mode = S_IWUSR; if (dev->driver) @@ -504,6 +510,9 @@ int device_add(struct device *dev) BusError: device_pm_remove(dev); PMError: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); device_remove_groups(dev); GroupError: device_remove_attrs(dev); @@ -620,6 +629,9 @@ void device_del(struct device * dev) */ if (platform_notify_remove) platform_notify_remove(dev); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); bus_remove_device(dev); device_pm_remove(dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); diff -puN drivers/base/dd.c~gregkh-driver-driver-core-add-notification-of-bus-events drivers/base/dd.c --- a/drivers/base/dd.c~gregkh-driver-driver-core-add-notification-of-bus-events +++ a/drivers/base/dd.c @@ -52,6 +52,11 @@ int device_bind_driver(struct device *de pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); + + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_BOUND_DRIVER, dev); + klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); @@ -288,6 +293,11 @@ static void __device_release_driver(stru sysfs_remove_link(&dev->kobj, "driver"); klist_remove(&dev->knode_driver); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->bus_notifier, + BUS_NOTIFY_UNBIND_DRIVER, + dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) diff -puN include/linux/device.h~gregkh-driver-driver-core-add-notification-of-bus-events include/linux/device.h --- a/include/linux/device.h~gregkh-driver-driver-core-add-notification-of-bus-events +++ a/include/linux/device.h @@ -42,6 +42,8 @@ struct bus_type { struct klist klist_devices; struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; @@ -75,6 +77,29 @@ int __must_check bus_for_each_drv(struct struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *)); +/* + * Bus notifiers: Get notified of addition/removal of devices + * and binding/unbinding of drivers to devices. + * In the long run, it should be a replacement for the platform + * notify hooks. + */ +struct notifier_block; + +extern int bus_register_notifier(struct bus_type *bus, + struct notifier_block *nb); +extern int bus_unregister_notifier(struct bus_type *bus, + struct notifier_block *nb); + +/* All 4 notifers below get called with the target struct device * + * as an argument. Note that those functions are likely to be called + * with the device semaphore held in the core, so be careful. + */ +#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ +#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */ +#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */ +#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be + unbound */ + /* driverfs interface for exporting bus attributes */ struct bus_attribute { _