summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/hcd.c2
-rw-r--r--drivers/usb/core/hub.c3
-rw-r--r--drivers/usb/core/notify.c120
-rw-r--r--drivers/usb/core/usb.h6
-rw-r--r--include/linux/usb.h8
6 files changed, 140 insertions, 1 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index d5503cf0bf7..dd1c4d2a0c3 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -3,7 +3,7 @@
#
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
- config.o file.o buffer.o sysfs.o devio.o
+ config.o file.o buffer.o sysfs.o devio.o notify.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 9ad3912a5ed..b700b6cdb68 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -792,6 +792,7 @@ static int usb_register_bus(struct usb_bus *bus)
list_add (&bus->bus_list, &usb_bus_list);
up (&usb_bus_list_lock);
+ usb_notify_add_bus(bus);
usbfs_add_bus (bus);
usbmon_notify_bus_add (bus);
@@ -820,6 +821,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
list_del (&bus->bus_list);
up (&usb_bus_list_lock);
+ usb_notify_remove_bus(bus);
usbmon_notify_bus_remove (bus);
usbfs_remove_bus (bus);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 273e6ccca21..4f1a8c8cf92 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1128,6 +1128,8 @@ void usb_disconnect(struct usb_device **pdev)
*/
usb_disable_device(udev, 0);
+ usb_notify_remove_device(udev);
+
/* Free the device number, remove the /proc/bus/usb entry and
* the sysfs attributes, and delete the parent's children[]
* (or root_hub) pointer.
@@ -1371,6 +1373,7 @@ int usb_new_device(struct usb_device *udev)
}
/* USB device state == configured ... usable */
+ usb_notify_add_device(udev);
/* add a /proc/bus/usb entry */
usbdev_add(udev);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
new file mode 100644
index 00000000000..37da059eced
--- /dev/null
+++ b/drivers/usb/core/notify.c
@@ -0,0 +1,120 @@
+/*
+ * All the USB notify logic
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * notifier functions originally based on those in kernel/sys.c
+ * but fixed up to not be so broken.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb.h"
+
+
+static struct notifier_block *usb_notifier_list;
+static DECLARE_MUTEX(usb_notifier_lock);
+
+static void usb_notifier_chain_register(struct notifier_block **list,
+ struct notifier_block *n)
+{
+ down(&usb_notifier_lock);
+ while (*list) {
+ if (n->priority > (*list)->priority)
+ break;
+ list = &((*list)->next);
+ }
+ n->next = *list;
+ *list = n;
+ up(&usb_notifier_lock);
+}
+
+static void usb_notifier_chain_unregister(struct notifier_block **nl,
+ struct notifier_block *n)
+{
+ down(&usb_notifier_lock);
+ while ((*nl)!=NULL) {
+ if ((*nl)==n) {
+ *nl = n->next;
+ goto exit;
+ }
+ nl=&((*nl)->next);
+ }
+exit:
+ up(&usb_notifier_lock);
+}
+
+static int usb_notifier_call_chain(struct notifier_block **n,
+ unsigned long val, void *v)
+{
+ int ret=NOTIFY_DONE;
+ struct notifier_block *nb = *n;
+
+ down(&usb_notifier_lock);
+ while (nb) {
+ ret = nb->notifier_call(nb,val,v);
+ if (ret&NOTIFY_STOP_MASK) {
+ goto exit;
+ }
+ nb = nb->next;
+ }
+exit:
+ up(&usb_notifier_lock);
+ return ret;
+}
+
+/**
+ * usb_register_notify - register a notifier callback whenever a usb change happens
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * These changes are either USB devices or busses being added or removed.
+ */
+void usb_register_notify(struct notifier_block *nb)
+{
+ usb_notifier_chain_register(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_register_notify);
+
+/**
+ * usb_unregister_notify - unregister a notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * usb_register_notifier() must have been previously called for this function
+ * to work properly.
+ */
+void usb_unregister_notify(struct notifier_block *nb)
+{
+ usb_notifier_chain_unregister(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_unregister_notify);
+
+
+void usb_notify_add_device(struct usb_device *udev)
+{
+ usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
+}
+
+void usb_notify_remove_device(struct usb_device *udev)
+{
+ usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
+}
+
+void usb_notify_add_bus(struct usb_bus *ubus)
+{
+ usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
+}
+
+void usb_notify_remove_bus(struct usb_bus *ubus)
+{
+ usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
+}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 3dc8096c0f9..811cf4482e0 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -80,3 +80,9 @@ struct dev_state {
unsigned long ifclaimed;
};
+/* internal notify stuff */
+extern void usb_notify_add_device(struct usb_device *udev);
+extern void usb_notify_remove_device(struct usb_device *udev);
+extern void usb_notify_add_bus(struct usb_bus *ubus);
+extern void usb_notify_remove_bus(struct usb_bus *ubus);
+
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 207b1ad9d99..a2d923fd54f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1135,6 +1135,14 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
/* -------------------------------------------------------------------------- */
+/* Events from the usb core */
+#define USB_DEVICE_ADD 0x0001
+#define USB_DEVICE_REMOVE 0x0002
+#define USB_BUS_ADD 0x0003
+#define USB_BUS_REMOVE 0x0004
+extern void usb_register_notify(struct notifier_block *nb);
+extern void usb_unregister_notify(struct notifier_block *nb);
+
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg)
#else