Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[sfrench/cifs-2.6.git] / 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 #include <linux/usb.h>
16 #include <linux/mutex.h>
17 #include "usb.h"
18
19
20 static struct notifier_block *usb_notifier_list;
21 static DEFINE_MUTEX(usb_notifier_lock);
22
23 static void usb_notifier_chain_register(struct notifier_block **list,
24                                         struct notifier_block *n)
25 {
26         mutex_lock(&usb_notifier_lock);
27         while (*list) {
28                 if (n->priority > (*list)->priority)
29                         break;
30                 list = &((*list)->next);
31         }
32         n->next = *list;
33         *list = n;
34         mutex_unlock(&usb_notifier_lock);
35 }
36
37 static void usb_notifier_chain_unregister(struct notifier_block **nl,
38                                    struct notifier_block *n)
39 {
40         mutex_lock(&usb_notifier_lock);
41         while ((*nl)!=NULL) {
42                 if ((*nl)==n) {
43                         *nl = n->next;
44                         goto exit;
45                 }
46                 nl=&((*nl)->next);
47         }
48 exit:
49         mutex_unlock(&usb_notifier_lock);
50 }
51
52 static int usb_notifier_call_chain(struct notifier_block **n,
53                                    unsigned long val, void *v)
54 {
55         int ret=NOTIFY_DONE;
56         struct notifier_block *nb = *n;
57
58         mutex_lock(&usb_notifier_lock);
59         while (nb) {
60                 ret = nb->notifier_call(nb,val,v);
61                 if (ret&NOTIFY_STOP_MASK) {
62                         goto exit;
63                 }
64                 nb = nb->next;
65         }
66 exit:
67         mutex_unlock(&usb_notifier_lock);
68         return ret;
69 }
70
71 /**
72  * usb_register_notify - register a notifier callback whenever a usb change happens
73  * @nb: pointer to the notifier block for the callback events.
74  *
75  * These changes are either USB devices or busses being added or removed.
76  */
77 void usb_register_notify(struct notifier_block *nb)
78 {
79         usb_notifier_chain_register(&usb_notifier_list, nb);
80 }
81 EXPORT_SYMBOL_GPL(usb_register_notify);
82
83 /**
84  * usb_unregister_notify - unregister a notifier callback
85  * @nb: pointer to the notifier block for the callback events.
86  *
87  * usb_register_notifier() must have been previously called for this function
88  * to work properly.
89  */
90 void usb_unregister_notify(struct notifier_block *nb)
91 {
92         usb_notifier_chain_unregister(&usb_notifier_list, nb);
93 }
94 EXPORT_SYMBOL_GPL(usb_unregister_notify);
95
96
97 void usb_notify_add_device(struct usb_device *udev)
98 {
99         usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
100 }
101
102 void usb_notify_remove_device(struct usb_device *udev)
103 {
104         usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
105 }
106
107 void usb_notify_add_bus(struct usb_bus *ubus)
108 {
109         usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
110 }
111
112 void usb_notify_remove_bus(struct usb_bus *ubus)
113 {
114         usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
115 }