{
int retval;
+ BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+
retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
if (retval)
goto out;
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);
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kdev_t.h>
+#include <linux/notifier.h>
#include <asm/semaphore.h>
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)
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);
*/
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);
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));
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)
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;
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 {