Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6] / drivers / usb / core / notify.c
1 /*
2  * All the USB notify logic
3  *
4  * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
5  *
6  * notifier functions originally based on those in kernel/sys.c
7  * but fixed up to not be so broken.
8  *
9  */
10
11
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/notifier.h>
15 #ifdef CONFIG_USB_DEBUG
16         #define DEBUG
17 #else
18         #undef DEBUG
19 #endif
20 #include <linux/usb.h>
21
22 #include "usb.h"
23
24
25 static struct notifier_block *usb_notifier_list;
26 static DECLARE_MUTEX(usb_notifier_lock);
27
28 static void usb_notifier_chain_register(struct notifier_block **list,
29                                         struct notifier_block *n)
30 {
31         down(&usb_notifier_lock);
32         while (*list) {
33                 if (n->priority > (*list)->priority)
34                         break;
35                 list = &((*list)->next);
36         }
37         n->next = *list;
38         *list = n;
39         up(&usb_notifier_lock);
40 }
41
42 static void usb_notifier_chain_unregister(struct notifier_block **nl,
43                                    struct notifier_block *n)
44 {
45         down(&usb_notifier_lock);
46         while ((*nl)!=NULL) {
47                 if ((*nl)==n) {
48                         *nl = n->next;
49                         goto exit;
50                 }
51                 nl=&((*nl)->next);
52         }
53 exit:
54         up(&usb_notifier_lock);
55 }
56
57 static int usb_notifier_call_chain(struct notifier_block **n,
58                                    unsigned long val, void *v)
59 {
60         int ret=NOTIFY_DONE;
61         struct notifier_block *nb = *n;
62
63         down(&usb_notifier_lock);
64         while (nb) {
65                 ret = nb->notifier_call(nb,val,v);
66                 if (ret&NOTIFY_STOP_MASK) {
67                         goto exit;
68                 }
69                 nb = nb->next;
70         }
71 exit:
72         up(&usb_notifier_lock);
73         return ret;
74 }
75
76 /**
77  * usb_register_notify - register a notifier callback whenever a usb change happens
78  * @nb: pointer to the notifier block for the callback events.
79  *
80  * These changes are either USB devices or busses being added or removed.
81  */
82 void usb_register_notify(struct notifier_block *nb)
83 {
84         usb_notifier_chain_register(&usb_notifier_list, nb);
85 }
86 EXPORT_SYMBOL_GPL(usb_register_notify);
87
88 /**
89  * usb_unregister_notify - unregister a notifier callback
90  * @nb: pointer to the notifier block for the callback events.
91  *
92  * usb_register_notifier() must have been previously called for this function
93  * to work properly.
94  */
95 void usb_unregister_notify(struct notifier_block *nb)
96 {
97         usb_notifier_chain_unregister(&usb_notifier_list, nb);
98 }
99 EXPORT_SYMBOL_GPL(usb_unregister_notify);
100
101
102 void usb_notify_add_device(struct usb_device *udev)
103 {
104         usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
105 }
106
107 void usb_notify_remove_device(struct usb_device *udev)
108 {
109         usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
110 }
111
112 void usb_notify_add_bus(struct usb_bus *ubus)
113 {
114         usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
115 }
116
117 void usb_notify_remove_bus(struct usb_bus *ubus)
118 {
119         usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
120 }