Commit | Line | Data |
---|---|---|
3099e75a GKH |
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> | |
3099e75a | 15 | #include <linux/usb.h> |
4186ecf8 | 16 | #include <linux/mutex.h> |
3099e75a GKH |
17 | #include "usb.h" |
18 | ||
19 | ||
20 | static struct notifier_block *usb_notifier_list; | |
4186ecf8 | 21 | static DEFINE_MUTEX(usb_notifier_lock); |
3099e75a GKH |
22 | |
23 | static void usb_notifier_chain_register(struct notifier_block **list, | |
24 | struct notifier_block *n) | |
25 | { | |
4186ecf8 | 26 | mutex_lock(&usb_notifier_lock); |
3099e75a GKH |
27 | while (*list) { |
28 | if (n->priority > (*list)->priority) | |
29 | break; | |
30 | list = &((*list)->next); | |
31 | } | |
32 | n->next = *list; | |
33 | *list = n; | |
4186ecf8 | 34 | mutex_unlock(&usb_notifier_lock); |
3099e75a GKH |
35 | } |
36 | ||
37 | static void usb_notifier_chain_unregister(struct notifier_block **nl, | |
38 | struct notifier_block *n) | |
39 | { | |
4186ecf8 | 40 | mutex_lock(&usb_notifier_lock); |
3099e75a GKH |
41 | while ((*nl)!=NULL) { |
42 | if ((*nl)==n) { | |
43 | *nl = n->next; | |
44 | goto exit; | |
45 | } | |
46 | nl=&((*nl)->next); | |
47 | } | |
48 | exit: | |
4186ecf8 | 49 | mutex_unlock(&usb_notifier_lock); |
3099e75a GKH |
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 | ||
4186ecf8 | 58 | mutex_lock(&usb_notifier_lock); |
3099e75a GKH |
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: | |
4186ecf8 | 67 | mutex_unlock(&usb_notifier_lock); |
3099e75a GKH |
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 | } |