diff options
-rw-r--r-- | include/linux/rfkill.h | 7 | ||||
-rw-r--r-- | net/rfkill/rfkill.c | 70 |
2 files changed, 74 insertions, 3 deletions
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c0cab7d37828..98667becdee4 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h | |||
@@ -117,4 +117,11 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill) | |||
117 | #endif | 117 | #endif |
118 | } | 118 | } |
119 | 119 | ||
120 | /* rfkill notification chain */ | ||
121 | #define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill | ||
122 | switch has changed */ | ||
123 | |||
124 | int register_rfkill_notifier(struct notifier_block *nb); | ||
125 | int unregister_rfkill_notifier(struct notifier_block *nb); | ||
126 | |||
120 | #endif /* RFKILL_H */ | 127 | #endif /* RFKILL_H */ |
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index fb566902030a..a561e350a70a 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -46,6 +46,49 @@ MODULE_PARM_DESC(default_state, | |||
46 | 46 | ||
47 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; | 47 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; |
48 | 48 | ||
49 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * register_rfkill_notifier - Add notifier to rfkill notifier chain | ||
54 | * @nb: pointer to the new entry to add to the chain | ||
55 | * | ||
56 | * See blocking_notifier_chain_register() for return value and further | ||
57 | * observations. | ||
58 | * | ||
59 | * Adds a notifier to the rfkill notifier chain. The chain will be | ||
60 | * called with a pointer to the relevant rfkill structure as a parameter, | ||
61 | * refer to include/linux/rfkill.h for the possible events. | ||
62 | * | ||
63 | * Notifiers added to this chain are to always return NOTIFY_DONE. This | ||
64 | * chain is a blocking notifier chain: notifiers can sleep. | ||
65 | * | ||
66 | * Calls to this chain may have been done through a workqueue. One must | ||
67 | * assume unordered asynchronous behaviour, there is no way to know if | ||
68 | * actions related to the event that generated the notification have been | ||
69 | * carried out already. | ||
70 | */ | ||
71 | int register_rfkill_notifier(struct notifier_block *nb) | ||
72 | { | ||
73 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); | ||
76 | |||
77 | /** | ||
78 | * unregister_rfkill_notifier - remove notifier from rfkill notifier chain | ||
79 | * @nb: pointer to the entry to remove from the chain | ||
80 | * | ||
81 | * See blocking_notifier_chain_unregister() for return value and further | ||
82 | * observations. | ||
83 | * | ||
84 | * Removes a notifier from the rfkill notifier chain. | ||
85 | */ | ||
86 | int unregister_rfkill_notifier(struct notifier_block *nb) | ||
87 | { | ||
88 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); | ||
91 | |||
49 | 92 | ||
50 | static void rfkill_led_trigger(struct rfkill *rfkill, | 93 | static void rfkill_led_trigger(struct rfkill *rfkill, |
51 | enum rfkill_state state) | 94 | enum rfkill_state state) |
@@ -62,14 +105,25 @@ static void rfkill_led_trigger(struct rfkill *rfkill, | |||
62 | #endif /* CONFIG_RFKILL_LEDS */ | 105 | #endif /* CONFIG_RFKILL_LEDS */ |
63 | } | 106 | } |
64 | 107 | ||
108 | static void notify_rfkill_state_change(struct rfkill *rfkill) | ||
109 | { | ||
110 | blocking_notifier_call_chain(&rfkill_notifier_list, | ||
111 | RFKILL_STATE_CHANGED, | ||
112 | rfkill); | ||
113 | } | ||
114 | |||
65 | static void update_rfkill_state(struct rfkill *rfkill) | 115 | static void update_rfkill_state(struct rfkill *rfkill) |
66 | { | 116 | { |
67 | enum rfkill_state newstate; | 117 | enum rfkill_state newstate, oldstate; |
68 | 118 | ||
69 | if (rfkill->get_state) { | 119 | if (rfkill->get_state) { |
70 | mutex_lock(&rfkill->mutex); | 120 | mutex_lock(&rfkill->mutex); |
71 | if (!rfkill->get_state(rfkill->data, &newstate)) | 121 | if (!rfkill->get_state(rfkill->data, &newstate)) { |
122 | oldstate = rfkill->state; | ||
72 | rfkill->state = newstate; | 123 | rfkill->state = newstate; |
124 | if (oldstate != newstate) | ||
125 | notify_rfkill_state_change(rfkill); | ||
126 | } | ||
73 | mutex_unlock(&rfkill->mutex); | 127 | mutex_unlock(&rfkill->mutex); |
74 | } | 128 | } |
75 | } | 129 | } |
@@ -93,8 +147,10 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
93 | rfkill->state = state; | 147 | rfkill->state = state; |
94 | } | 148 | } |
95 | 149 | ||
96 | if (force || rfkill->state != oldstate) | 150 | if (force || rfkill->state != oldstate) { |
97 | rfkill_led_trigger(rfkill, rfkill->state); | 151 | rfkill_led_trigger(rfkill, rfkill->state); |
152 | notify_rfkill_state_change(rfkill); | ||
153 | } | ||
98 | 154 | ||
99 | return retval; | 155 | return retval; |
100 | } | 156 | } |
@@ -139,12 +195,20 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
139 | */ | 195 | */ |
140 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | 196 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) |
141 | { | 197 | { |
198 | enum rfkill_state oldstate; | ||
199 | |||
142 | if (state != RFKILL_STATE_OFF && | 200 | if (state != RFKILL_STATE_OFF && |
143 | state != RFKILL_STATE_ON) | 201 | state != RFKILL_STATE_ON) |
144 | return -EINVAL; | 202 | return -EINVAL; |
145 | 203 | ||
146 | mutex_lock(&rfkill->mutex); | 204 | mutex_lock(&rfkill->mutex); |
205 | |||
206 | oldstate = rfkill->state; | ||
147 | rfkill->state = state; | 207 | rfkill->state = state; |
208 | |||
209 | if (state != oldstate) | ||
210 | notify_rfkill_state_change(rfkill); | ||
211 | |||
148 | mutex_unlock(&rfkill->mutex); | 212 | mutex_unlock(&rfkill->mutex); |
149 | 213 | ||
150 | return 0; | 214 | return 0; |