aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rfkill.h7
-rw-r--r--net/rfkill/rfkill.c70
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
124int register_rfkill_notifier(struct notifier_block *nb);
125int 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
47static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; 47static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
48 48
49static 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 */
71int register_rfkill_notifier(struct notifier_block *nb)
72{
73 return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
74}
75EXPORT_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 */
86int unregister_rfkill_notifier(struct notifier_block *nb)
87{
88 return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
89}
90EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
91
49 92
50static void rfkill_led_trigger(struct rfkill *rfkill, 93static 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
108static 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
65static void update_rfkill_state(struct rfkill *rfkill) 115static 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 */
140int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) 196int 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;