Commit | Line | Data |
---|---|---|
cf4328cd | 1 | /* |
fe242cfd | 2 | * Copyright (C) 2006 - 2007 Ivo van Doorn |
cf4328cd ID |
3 | * Copyright (C) 2007 Dmitry Torokhov |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the | |
17 | * Free Software Foundation, Inc., | |
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | */ | |
20 | ||
21 | #include <linux/kernel.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/init.h> | |
24 | #include <linux/workqueue.h> | |
25 | #include <linux/capability.h> | |
26 | #include <linux/list.h> | |
27 | #include <linux/mutex.h> | |
28 | #include <linux/rfkill.h> | |
29 | ||
27366223 MB |
30 | /* Get declaration of rfkill_switch_all() to shut up sparse. */ |
31 | #include "rfkill-input.h" | |
32 | ||
33 | ||
cf4328cd ID |
34 | MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>"); |
35 | MODULE_VERSION("1.0"); | |
36 | MODULE_DESCRIPTION("RF switch support"); | |
37 | MODULE_LICENSE("GPL"); | |
38 | ||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | |
15635744 | 40 | static DEFINE_MUTEX(rfkill_global_mutex); |
cf4328cd | 41 | |
5005657c | 42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; |
e954b0b8 HMH |
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); |
44 | MODULE_PARM_DESC(default_state, | |
45 | "Default initial state for all radio types, 0 = radio off"); | |
46 | ||
99619201 HMH |
47 | struct rfkill_gsw_state { |
48 | enum rfkill_state current_state; | |
49 | enum rfkill_state default_state; | |
50 | }; | |
51 | ||
52 | static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; | |
53 | static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | |
d003922d | 54 | static bool rfkill_epo_lock_active; |
cf4328cd | 55 | |
79399a8d HMH |
56 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); |
57 | ||
58 | ||
59 | /** | |
60 | * register_rfkill_notifier - Add notifier to rfkill notifier chain | |
61 | * @nb: pointer to the new entry to add to the chain | |
62 | * | |
63 | * See blocking_notifier_chain_register() for return value and further | |
64 | * observations. | |
65 | * | |
66 | * Adds a notifier to the rfkill notifier chain. The chain will be | |
67 | * called with a pointer to the relevant rfkill structure as a parameter, | |
68 | * refer to include/linux/rfkill.h for the possible events. | |
69 | * | |
70 | * Notifiers added to this chain are to always return NOTIFY_DONE. This | |
71 | * chain is a blocking notifier chain: notifiers can sleep. | |
72 | * | |
73 | * Calls to this chain may have been done through a workqueue. One must | |
74 | * assume unordered asynchronous behaviour, there is no way to know if | |
75 | * actions related to the event that generated the notification have been | |
76 | * carried out already. | |
77 | */ | |
78 | int register_rfkill_notifier(struct notifier_block *nb) | |
79 | { | |
f745ba03 | 80 | BUG_ON(!nb); |
79399a8d HMH |
81 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); |
82 | } | |
83 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); | |
84 | ||
85 | /** | |
86 | * unregister_rfkill_notifier - remove notifier from rfkill notifier chain | |
87 | * @nb: pointer to the entry to remove from the chain | |
88 | * | |
89 | * See blocking_notifier_chain_unregister() for return value and further | |
90 | * observations. | |
91 | * | |
92 | * Removes a notifier from the rfkill notifier chain. | |
93 | */ | |
94 | int unregister_rfkill_notifier(struct notifier_block *nb) | |
95 | { | |
f745ba03 | 96 | BUG_ON(!nb); |
79399a8d HMH |
97 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); |
98 | } | |
99 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); | |
100 | ||
135900c1 MB |
101 | |
102 | static void rfkill_led_trigger(struct rfkill *rfkill, | |
103 | enum rfkill_state state) | |
104 | { | |
105 | #ifdef CONFIG_RFKILL_LEDS | |
106 | struct led_trigger *led = &rfkill->led_trigger; | |
107 | ||
108 | if (!led->name) | |
109 | return; | |
5005657c | 110 | if (state != RFKILL_STATE_UNBLOCKED) |
135900c1 MB |
111 | led_trigger_event(led, LED_OFF); |
112 | else | |
113 | led_trigger_event(led, LED_FULL); | |
114 | #endif /* CONFIG_RFKILL_LEDS */ | |
115 | } | |
116 | ||
96185664 DB |
117 | #ifdef CONFIG_RFKILL_LEDS |
118 | static void rfkill_led_trigger_activate(struct led_classdev *led) | |
119 | { | |
120 | struct rfkill *rfkill = container_of(led->trigger, | |
121 | struct rfkill, led_trigger); | |
122 | ||
123 | rfkill_led_trigger(rfkill, rfkill->state); | |
124 | } | |
125 | #endif /* CONFIG_RFKILL_LEDS */ | |
126 | ||
79399a8d HMH |
127 | static void notify_rfkill_state_change(struct rfkill *rfkill) |
128 | { | |
417bd25a | 129 | rfkill_led_trigger(rfkill, rfkill->state); |
79399a8d HMH |
130 | blocking_notifier_call_chain(&rfkill_notifier_list, |
131 | RFKILL_STATE_CHANGED, | |
132 | rfkill); | |
133 | } | |
134 | ||
801e49af HMH |
135 | static void update_rfkill_state(struct rfkill *rfkill) |
136 | { | |
79399a8d | 137 | enum rfkill_state newstate, oldstate; |
801e49af HMH |
138 | |
139 | if (rfkill->get_state) { | |
140 | mutex_lock(&rfkill->mutex); | |
79399a8d HMH |
141 | if (!rfkill->get_state(rfkill->data, &newstate)) { |
142 | oldstate = rfkill->state; | |
801e49af | 143 | rfkill->state = newstate; |
79399a8d HMH |
144 | if (oldstate != newstate) |
145 | notify_rfkill_state_change(rfkill); | |
146 | } | |
801e49af HMH |
147 | mutex_unlock(&rfkill->mutex); |
148 | } | |
149 | } | |
150 | ||
5005657c HMH |
151 | /** |
152 | * rfkill_toggle_radio - wrapper for toggle_radio hook | |
5005657c HMH |
153 | * @rfkill: the rfkill struct to use |
154 | * @force: calls toggle_radio even if cache says it is not needed, | |
155 | * and also makes sure notifications of the state will be | |
156 | * sent even if it didn't change | |
157 | * @state: the new state to call toggle_radio() with | |
158 | * | |
0f687e9a HMH |
159 | * Calls rfkill->toggle_radio, enforcing the API for toggle_radio |
160 | * calls and handling all the red tape such as issuing notifications | |
161 | * if the call is successful. | |
162 | * | |
e10e0dfe HMH |
163 | * Suspended devices are not touched at all, and -EAGAIN is returned. |
164 | * | |
435307a3 HMH |
165 | * Note that the @force parameter cannot override a (possibly cached) |
166 | * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of | |
5005657c HMH |
167 | * RFKILL_STATE_HARD_BLOCKED implements either get_state() or |
168 | * rfkill_force_state(), so the cache either is bypassed or valid. | |
169 | * | |
170 | * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED | |
171 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to | |
172 | * give the driver a hint that it should double-BLOCK the transmitter. | |
173 | * | |
064af111 | 174 | * Caller must have acquired rfkill->mutex. |
5005657c | 175 | */ |
cf4328cd | 176 | static int rfkill_toggle_radio(struct rfkill *rfkill, |
526324b6 HMH |
177 | enum rfkill_state state, |
178 | int force) | |
cf4328cd | 179 | { |
7f4c5341 | 180 | int retval = 0; |
801e49af HMH |
181 | enum rfkill_state oldstate, newstate; |
182 | ||
e10e0dfe HMH |
183 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) |
184 | return -EBUSY; | |
185 | ||
801e49af HMH |
186 | oldstate = rfkill->state; |
187 | ||
526324b6 | 188 | if (rfkill->get_state && !force && |
801e49af HMH |
189 | !rfkill->get_state(rfkill->data, &newstate)) |
190 | rfkill->state = newstate; | |
cf4328cd | 191 | |
5005657c HMH |
192 | switch (state) { |
193 | case RFKILL_STATE_HARD_BLOCKED: | |
194 | /* typically happens when refreshing hardware state, | |
195 | * such as on resume */ | |
196 | state = RFKILL_STATE_SOFT_BLOCKED; | |
197 | break; | |
198 | case RFKILL_STATE_UNBLOCKED: | |
199 | /* force can't override this, only rfkill_force_state() can */ | |
200 | if (rfkill->state == RFKILL_STATE_HARD_BLOCKED) | |
201 | return -EPERM; | |
202 | break; | |
203 | case RFKILL_STATE_SOFT_BLOCKED: | |
204 | /* nothing to do, we want to give drivers the hint to double | |
205 | * BLOCK even a transmitter that is already in state | |
206 | * RFKILL_STATE_HARD_BLOCKED */ | |
207 | break; | |
96c87607 | 208 | default: |
f745ba03 HMH |
209 | WARN(1, KERN_WARNING |
210 | "rfkill: illegal state %d passed as parameter " | |
211 | "to rfkill_toggle_radio\n", state); | |
96c87607 | 212 | return -EINVAL; |
5005657c HMH |
213 | } |
214 | ||
526324b6 | 215 | if (force || state != rfkill->state) { |
cf4328cd | 216 | retval = rfkill->toggle_radio(rfkill->data, state); |
5005657c HMH |
217 | /* never allow a HARD->SOFT downgrade! */ |
218 | if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) | |
cf4328cd ID |
219 | rfkill->state = state; |
220 | } | |
221 | ||
417bd25a | 222 | if (force || rfkill->state != oldstate) |
79399a8d | 223 | notify_rfkill_state_change(rfkill); |
801e49af | 224 | |
cf4328cd ID |
225 | return retval; |
226 | } | |
227 | ||
228 | /** | |
99619201 | 229 | * __rfkill_switch_all - Toggle state of all switches of given type |
435307a3 | 230 | * @type: type of interfaces to be affected |
cf4328cd ID |
231 | * @state: the new state |
232 | * | |
435307a3 HMH |
233 | * This function toggles the state of all switches of given type, |
234 | * unless a specific switch is claimed by userspace (in which case, | |
e10e0dfe | 235 | * that switch is left alone) or suspended. |
99619201 | 236 | * |
15635744 | 237 | * Caller must have acquired rfkill_global_mutex. |
cf4328cd | 238 | */ |
99619201 HMH |
239 | static void __rfkill_switch_all(const enum rfkill_type type, |
240 | const enum rfkill_state state) | |
cf4328cd ID |
241 | { |
242 | struct rfkill *rfkill; | |
243 | ||
f745ba03 HMH |
244 | if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), |
245 | KERN_WARNING | |
246 | "rfkill: illegal state %d or type %d " | |
247 | "passed as parameter to __rfkill_switch_all\n", | |
248 | state, type)) | |
96c87607 HMH |
249 | return; |
250 | ||
99619201 | 251 | rfkill_global_states[type].current_state = state; |
cf4328cd | 252 | list_for_each_entry(rfkill, &rfkill_list, node) { |
064af111 HMH |
253 | if ((!rfkill->user_claim) && (rfkill->type == type)) { |
254 | mutex_lock(&rfkill->mutex); | |
526324b6 | 255 | rfkill_toggle_radio(rfkill, state, 0); |
064af111 HMH |
256 | mutex_unlock(&rfkill->mutex); |
257 | } | |
cf4328cd | 258 | } |
99619201 | 259 | } |
cf4328cd | 260 | |
99619201 HMH |
261 | /** |
262 | * rfkill_switch_all - Toggle state of all switches of given type | |
263 | * @type: type of interfaces to be affected | |
264 | * @state: the new state | |
265 | * | |
15635744 | 266 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). |
99619201 | 267 | * Please refer to __rfkill_switch_all() for details. |
d003922d HMH |
268 | * |
269 | * Does nothing if the EPO lock is active. | |
99619201 HMH |
270 | */ |
271 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |
272 | { | |
15635744 | 273 | mutex_lock(&rfkill_global_mutex); |
d003922d HMH |
274 | if (!rfkill_epo_lock_active) |
275 | __rfkill_switch_all(type, state); | |
15635744 | 276 | mutex_unlock(&rfkill_global_mutex); |
cf4328cd ID |
277 | } |
278 | EXPORT_SYMBOL(rfkill_switch_all); | |
279 | ||
4081f00d HMH |
280 | /** |
281 | * rfkill_epo - emergency power off all transmitters | |
282 | * | |
e10e0dfe | 283 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, |
15635744 | 284 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. |
99619201 HMH |
285 | * |
286 | * The global state before the EPO is saved and can be restored later | |
287 | * using rfkill_restore_states(). | |
4081f00d HMH |
288 | */ |
289 | void rfkill_epo(void) | |
290 | { | |
291 | struct rfkill *rfkill; | |
99619201 | 292 | int i; |
4081f00d | 293 | |
15635744 HMH |
294 | mutex_lock(&rfkill_global_mutex); |
295 | ||
d003922d | 296 | rfkill_epo_lock_active = true; |
4081f00d | 297 | list_for_each_entry(rfkill, &rfkill_list, node) { |
064af111 | 298 | mutex_lock(&rfkill->mutex); |
5005657c | 299 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
064af111 | 300 | mutex_unlock(&rfkill->mutex); |
4081f00d | 301 | } |
99619201 HMH |
302 | for (i = 0; i < RFKILL_TYPE_MAX; i++) { |
303 | rfkill_global_states[i].default_state = | |
304 | rfkill_global_states[i].current_state; | |
305 | rfkill_global_states[i].current_state = | |
306 | RFKILL_STATE_SOFT_BLOCKED; | |
307 | } | |
15635744 | 308 | mutex_unlock(&rfkill_global_mutex); |
4081f00d HMH |
309 | } |
310 | EXPORT_SYMBOL_GPL(rfkill_epo); | |
311 | ||
99619201 HMH |
312 | /** |
313 | * rfkill_restore_states - restore global states | |
314 | * | |
315 | * Restore (and sync switches to) the global state from the | |
316 | * states in rfkill_default_states. This can undo the effects of | |
317 | * a call to rfkill_epo(). | |
318 | */ | |
319 | void rfkill_restore_states(void) | |
320 | { | |
321 | int i; | |
322 | ||
15635744 HMH |
323 | mutex_lock(&rfkill_global_mutex); |
324 | ||
d003922d | 325 | rfkill_epo_lock_active = false; |
99619201 HMH |
326 | for (i = 0; i < RFKILL_TYPE_MAX; i++) |
327 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); | |
15635744 | 328 | mutex_unlock(&rfkill_global_mutex); |
99619201 HMH |
329 | } |
330 | EXPORT_SYMBOL_GPL(rfkill_restore_states); | |
331 | ||
d003922d HMH |
332 | /** |
333 | * rfkill_remove_epo_lock - unlock state changes | |
334 | * | |
335 | * Used by rfkill-input manually unlock state changes, when | |
336 | * the EPO switch is deactivated. | |
337 | */ | |
338 | void rfkill_remove_epo_lock(void) | |
339 | { | |
340 | mutex_lock(&rfkill_global_mutex); | |
341 | rfkill_epo_lock_active = false; | |
342 | mutex_unlock(&rfkill_global_mutex); | |
343 | } | |
344 | EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock); | |
345 | ||
346 | /** | |
347 | * rfkill_is_epo_lock_active - returns true EPO is active | |
348 | * | |
349 | * Returns 0 (false) if there is NOT an active EPO contidion, | |
350 | * and 1 (true) if there is an active EPO contition, which | |
351 | * locks all radios in one of the BLOCKED states. | |
352 | * | |
353 | * Can be called in atomic context. | |
354 | */ | |
355 | bool rfkill_is_epo_lock_active(void) | |
356 | { | |
357 | return rfkill_epo_lock_active; | |
358 | } | |
359 | EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active); | |
360 | ||
68d2413b HMH |
361 | /** |
362 | * rfkill_get_global_state - returns global state for a type | |
363 | * @type: the type to get the global state of | |
364 | * | |
365 | * Returns the current global state for a given wireless | |
366 | * device type. | |
367 | */ | |
368 | enum rfkill_state rfkill_get_global_state(const enum rfkill_type type) | |
369 | { | |
370 | return rfkill_global_states[type].current_state; | |
371 | } | |
372 | EXPORT_SYMBOL_GPL(rfkill_get_global_state); | |
373 | ||
801e49af HMH |
374 | /** |
375 | * rfkill_force_state - Force the internal rfkill radio state | |
376 | * @rfkill: pointer to the rfkill class to modify. | |
377 | * @state: the current radio state the class should be forced to. | |
378 | * | |
379 | * This function updates the internal state of the radio cached | |
380 | * by the rfkill class. It should be used when the driver gets | |
381 | * a notification by the firmware/hardware of the current *real* | |
382 | * state of the radio rfkill switch. | |
383 | * | |
2fd9b221 HMH |
384 | * Devices which are subject to external changes on their rfkill |
385 | * state (such as those caused by a hardware rfkill line) MUST | |
386 | * have their driver arrange to call rfkill_force_state() as soon | |
387 | * as possible after such a change. | |
388 | * | |
389 | * This function may not be called from an atomic context. | |
801e49af HMH |
390 | */ |
391 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | |
392 | { | |
79399a8d HMH |
393 | enum rfkill_state oldstate; |
394 | ||
f745ba03 HMH |
395 | BUG_ON(!rfkill); |
396 | if (WARN((state >= RFKILL_STATE_MAX), | |
397 | KERN_WARNING | |
398 | "rfkill: illegal state %d passed as parameter " | |
399 | "to rfkill_force_state\n", state)) | |
801e49af HMH |
400 | return -EINVAL; |
401 | ||
402 | mutex_lock(&rfkill->mutex); | |
79399a8d HMH |
403 | |
404 | oldstate = rfkill->state; | |
801e49af | 405 | rfkill->state = state; |
79399a8d HMH |
406 | |
407 | if (state != oldstate) | |
408 | notify_rfkill_state_change(rfkill); | |
409 | ||
801e49af HMH |
410 | mutex_unlock(&rfkill->mutex); |
411 | ||
412 | return 0; | |
413 | } | |
414 | EXPORT_SYMBOL(rfkill_force_state); | |
415 | ||
cf4328cd ID |
416 | static ssize_t rfkill_name_show(struct device *dev, |
417 | struct device_attribute *attr, | |
418 | char *buf) | |
419 | { | |
420 | struct rfkill *rfkill = to_rfkill(dev); | |
421 | ||
422 | return sprintf(buf, "%s\n", rfkill->name); | |
423 | } | |
424 | ||
99c632e5 | 425 | static const char *rfkill_get_type_str(enum rfkill_type type) |
cf4328cd | 426 | { |
99c632e5 | 427 | switch (type) { |
cf4328cd | 428 | case RFKILL_TYPE_WLAN: |
99c632e5 | 429 | return "wlan"; |
cf4328cd | 430 | case RFKILL_TYPE_BLUETOOTH: |
99c632e5 | 431 | return "bluetooth"; |
e0665486 | 432 | case RFKILL_TYPE_UWB: |
99c632e5 | 433 | return "ultrawideband"; |
303d9bf6 | 434 | case RFKILL_TYPE_WIMAX: |
99c632e5 | 435 | return "wimax"; |
477576a0 | 436 | case RFKILL_TYPE_WWAN: |
99c632e5 | 437 | return "wwan"; |
cf4328cd ID |
438 | default: |
439 | BUG(); | |
440 | } | |
99c632e5 HMH |
441 | } |
442 | ||
443 | static ssize_t rfkill_type_show(struct device *dev, | |
444 | struct device_attribute *attr, | |
445 | char *buf) | |
446 | { | |
447 | struct rfkill *rfkill = to_rfkill(dev); | |
cf4328cd | 448 | |
99c632e5 | 449 | return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); |
cf4328cd ID |
450 | } |
451 | ||
452 | static ssize_t rfkill_state_show(struct device *dev, | |
453 | struct device_attribute *attr, | |
454 | char *buf) | |
455 | { | |
456 | struct rfkill *rfkill = to_rfkill(dev); | |
457 | ||
801e49af | 458 | update_rfkill_state(rfkill); |
cf4328cd ID |
459 | return sprintf(buf, "%d\n", rfkill->state); |
460 | } | |
461 | ||
462 | static ssize_t rfkill_state_store(struct device *dev, | |
463 | struct device_attribute *attr, | |
464 | const char *buf, size_t count) | |
465 | { | |
466 | struct rfkill *rfkill = to_rfkill(dev); | |
849e0576 | 467 | unsigned long state; |
cf4328cd ID |
468 | int error; |
469 | ||
470 | if (!capable(CAP_NET_ADMIN)) | |
471 | return -EPERM; | |
472 | ||
849e0576 HMH |
473 | error = strict_strtoul(buf, 0, &state); |
474 | if (error) | |
475 | return error; | |
476 | ||
5005657c HMH |
477 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ |
478 | if (state != RFKILL_STATE_UNBLOCKED && | |
479 | state != RFKILL_STATE_SOFT_BLOCKED) | |
480 | return -EINVAL; | |
481 | ||
cf4b4aab HMH |
482 | error = mutex_lock_killable(&rfkill->mutex); |
483 | if (error) | |
484 | return error; | |
d003922d HMH |
485 | |
486 | if (!rfkill_epo_lock_active) | |
487 | error = rfkill_toggle_radio(rfkill, state, 0); | |
488 | else | |
489 | error = -EPERM; | |
490 | ||
7f4c5341 | 491 | mutex_unlock(&rfkill->mutex); |
cf4328cd | 492 | |
7f4c5341 | 493 | return error ? error : count; |
cf4328cd ID |
494 | } |
495 | ||
496 | static ssize_t rfkill_claim_show(struct device *dev, | |
497 | struct device_attribute *attr, | |
498 | char *buf) | |
499 | { | |
500 | struct rfkill *rfkill = to_rfkill(dev); | |
501 | ||
01b510b9 | 502 | return sprintf(buf, "%d\n", rfkill->user_claim); |
cf4328cd ID |
503 | } |
504 | ||
505 | static ssize_t rfkill_claim_store(struct device *dev, | |
506 | struct device_attribute *attr, | |
507 | const char *buf, size_t count) | |
508 | { | |
509 | struct rfkill *rfkill = to_rfkill(dev); | |
849e0576 HMH |
510 | unsigned long claim_tmp; |
511 | bool claim; | |
cf4328cd ID |
512 | int error; |
513 | ||
514 | if (!capable(CAP_NET_ADMIN)) | |
515 | return -EPERM; | |
516 | ||
064af111 HMH |
517 | if (rfkill->user_claim_unsupported) |
518 | return -EOPNOTSUPP; | |
519 | ||
849e0576 HMH |
520 | error = strict_strtoul(buf, 0, &claim_tmp); |
521 | if (error) | |
522 | return error; | |
523 | claim = !!claim_tmp; | |
524 | ||
cf4328cd ID |
525 | /* |
526 | * Take the global lock to make sure the kernel is not in | |
527 | * the middle of rfkill_switch_all | |
528 | */ | |
cf4b4aab | 529 | error = mutex_lock_killable(&rfkill_global_mutex); |
cf4328cd ID |
530 | if (error) |
531 | return error; | |
532 | ||
533 | if (rfkill->user_claim != claim) { | |
d003922d | 534 | if (!claim && !rfkill_epo_lock_active) { |
064af111 | 535 | mutex_lock(&rfkill->mutex); |
cf4328cd | 536 | rfkill_toggle_radio(rfkill, |
99619201 HMH |
537 | rfkill_global_states[rfkill->type].current_state, |
538 | 0); | |
064af111 HMH |
539 | mutex_unlock(&rfkill->mutex); |
540 | } | |
cf4328cd ID |
541 | rfkill->user_claim = claim; |
542 | } | |
543 | ||
15635744 | 544 | mutex_unlock(&rfkill_global_mutex); |
cf4328cd | 545 | |
20405c08 | 546 | return error ? error : count; |
cf4328cd ID |
547 | } |
548 | ||
549 | static struct device_attribute rfkill_dev_attrs[] = { | |
550 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), | |
551 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), | |
c81de6ad | 552 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), |
cf4328cd ID |
553 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), |
554 | __ATTR_NULL | |
555 | }; | |
556 | ||
557 | static void rfkill_release(struct device *dev) | |
558 | { | |
559 | struct rfkill *rfkill = to_rfkill(dev); | |
560 | ||
561 | kfree(rfkill); | |
562 | module_put(THIS_MODULE); | |
563 | } | |
564 | ||
565 | #ifdef CONFIG_PM | |
566 | static int rfkill_suspend(struct device *dev, pm_message_t state) | |
567 | { | |
bed7aac9 HMH |
568 | /* mark class device as suspended */ |
569 | if (dev->power.power_state.event != state.event) | |
cf4328cd | 570 | dev->power.power_state = state; |
cf4328cd ID |
571 | |
572 | return 0; | |
573 | } | |
574 | ||
575 | static int rfkill_resume(struct device *dev) | |
576 | { | |
577 | struct rfkill *rfkill = to_rfkill(dev); | |
578 | ||
579 | if (dev->power.power_state.event != PM_EVENT_ON) { | |
580 | mutex_lock(&rfkill->mutex); | |
581 | ||
e10e0dfe HMH |
582 | dev->power.power_state.event = PM_EVENT_ON; |
583 | ||
17670799 HMH |
584 | /* |
585 | * If we are under EPO, kick transmitter offline, | |
586 | * otherwise restore to pre-suspend state. | |
587 | * | |
588 | * Issue a notification in any case | |
589 | */ | |
590 | rfkill_toggle_radio(rfkill, | |
591 | rfkill_epo_lock_active ? | |
592 | RFKILL_STATE_SOFT_BLOCKED : | |
593 | rfkill->state, | |
594 | 1); | |
cf4328cd ID |
595 | |
596 | mutex_unlock(&rfkill->mutex); | |
597 | } | |
598 | ||
cf4328cd ID |
599 | return 0; |
600 | } | |
601 | #else | |
602 | #define rfkill_suspend NULL | |
603 | #define rfkill_resume NULL | |
604 | #endif | |
605 | ||
ffb67c34 HMH |
606 | static int rfkill_blocking_uevent_notifier(struct notifier_block *nb, |
607 | unsigned long eventid, | |
608 | void *data) | |
609 | { | |
610 | struct rfkill *rfkill = (struct rfkill *)data; | |
611 | ||
612 | switch (eventid) { | |
613 | case RFKILL_STATE_CHANGED: | |
614 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | |
615 | break; | |
616 | default: | |
617 | break; | |
618 | } | |
619 | ||
620 | return NOTIFY_DONE; | |
621 | } | |
622 | ||
623 | static struct notifier_block rfkill_blocking_uevent_nb = { | |
624 | .notifier_call = rfkill_blocking_uevent_notifier, | |
625 | .priority = 0, | |
626 | }; | |
627 | ||
628 | static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | |
629 | { | |
630 | struct rfkill *rfkill = to_rfkill(dev); | |
631 | int error; | |
632 | ||
633 | error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); | |
634 | if (error) | |
635 | return error; | |
636 | error = add_uevent_var(env, "RFKILL_TYPE=%s", | |
637 | rfkill_get_type_str(rfkill->type)); | |
638 | if (error) | |
639 | return error; | |
640 | error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state); | |
641 | return error; | |
642 | } | |
643 | ||
cf4328cd ID |
644 | static struct class rfkill_class = { |
645 | .name = "rfkill", | |
646 | .dev_release = rfkill_release, | |
647 | .dev_attrs = rfkill_dev_attrs, | |
648 | .suspend = rfkill_suspend, | |
649 | .resume = rfkill_resume, | |
ffb67c34 | 650 | .dev_uevent = rfkill_dev_uevent, |
cf4328cd ID |
651 | }; |
652 | ||
02589f60 HMH |
653 | static int rfkill_check_duplicity(const struct rfkill *rfkill) |
654 | { | |
655 | struct rfkill *p; | |
656 | unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | |
657 | ||
658 | memset(seen, 0, sizeof(seen)); | |
659 | ||
660 | list_for_each_entry(p, &rfkill_list, node) { | |
f745ba03 HMH |
661 | if (WARN((p == rfkill), KERN_WARNING |
662 | "rfkill: illegal attempt to register " | |
663 | "an already registered rfkill struct\n")) | |
02589f60 | 664 | return -EEXIST; |
02589f60 HMH |
665 | set_bit(p->type, seen); |
666 | } | |
667 | ||
668 | /* 0: first switch of its kind */ | |
4a9d9167 | 669 | return (test_bit(rfkill->type, seen)) ? 1 : 0; |
02589f60 HMH |
670 | } |
671 | ||
cf4328cd ID |
672 | static int rfkill_add_switch(struct rfkill *rfkill) |
673 | { | |
02589f60 HMH |
674 | int error; |
675 | ||
15635744 | 676 | mutex_lock(&rfkill_global_mutex); |
cf4328cd | 677 | |
02589f60 HMH |
678 | error = rfkill_check_duplicity(rfkill); |
679 | if (error < 0) | |
680 | goto unlock_out; | |
681 | ||
99619201 HMH |
682 | if (!error) { |
683 | /* lock default after first use */ | |
684 | set_bit(rfkill->type, rfkill_states_lockdflt); | |
685 | rfkill_global_states[rfkill->type].current_state = | |
686 | rfkill_global_states[rfkill->type].default_state; | |
687 | } | |
688 | ||
689 | rfkill_toggle_radio(rfkill, | |
690 | rfkill_global_states[rfkill->type].current_state, | |
691 | 0); | |
fd4484af HMH |
692 | |
693 | list_add_tail(&rfkill->node, &rfkill_list); | |
cf4328cd | 694 | |
02589f60 HMH |
695 | error = 0; |
696 | unlock_out: | |
15635744 | 697 | mutex_unlock(&rfkill_global_mutex); |
7319f1e6 | 698 | |
02589f60 | 699 | return error; |
cf4328cd ID |
700 | } |
701 | ||
702 | static void rfkill_remove_switch(struct rfkill *rfkill) | |
703 | { | |
15635744 | 704 | mutex_lock(&rfkill_global_mutex); |
cf4328cd | 705 | list_del_init(&rfkill->node); |
15635744 | 706 | mutex_unlock(&rfkill_global_mutex); |
064af111 HMH |
707 | |
708 | mutex_lock(&rfkill->mutex); | |
709 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | |
710 | mutex_unlock(&rfkill->mutex); | |
cf4328cd ID |
711 | } |
712 | ||
713 | /** | |
714 | * rfkill_allocate - allocate memory for rfkill structure. | |
715 | * @parent: device that has rf switch on it | |
234a0ca6 | 716 | * @type: type of the switch (RFKILL_TYPE_*) |
cf4328cd ID |
717 | * |
718 | * This function should be called by the network driver when it needs | |
435307a3 HMH |
719 | * rfkill structure. Once the structure is allocated the driver should |
720 | * finish its initialization by setting the name, private data, enable_radio | |
cf4328cd | 721 | * and disable_radio methods and then register it with rfkill_register(). |
435307a3 | 722 | * |
cf4328cd ID |
723 | * NOTE: If registration fails the structure shoudl be freed by calling |
724 | * rfkill_free() otherwise rfkill_unregister() should be used. | |
725 | */ | |
77fba13c HMH |
726 | struct rfkill * __must_check rfkill_allocate(struct device *parent, |
727 | enum rfkill_type type) | |
cf4328cd ID |
728 | { |
729 | struct rfkill *rfkill; | |
730 | struct device *dev; | |
731 | ||
f745ba03 HMH |
732 | if (WARN((type >= RFKILL_TYPE_MAX), |
733 | KERN_WARNING | |
734 | "rfkill: illegal type %d passed as parameter " | |
735 | "to rfkill_allocate\n", type)) | |
736 | return NULL; | |
737 | ||
cf4328cd | 738 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); |
d007da1f | 739 | if (!rfkill) |
cf4328cd ID |
740 | return NULL; |
741 | ||
742 | mutex_init(&rfkill->mutex); | |
743 | INIT_LIST_HEAD(&rfkill->node); | |
744 | rfkill->type = type; | |
745 | ||
746 | dev = &rfkill->dev; | |
747 | dev->class = &rfkill_class; | |
748 | dev->parent = parent; | |
749 | device_initialize(dev); | |
750 | ||
751 | __module_get(THIS_MODULE); | |
752 | ||
753 | return rfkill; | |
754 | } | |
755 | EXPORT_SYMBOL(rfkill_allocate); | |
756 | ||
757 | /** | |
758 | * rfkill_free - Mark rfkill structure for deletion | |
759 | * @rfkill: rfkill structure to be destroyed | |
760 | * | |
435307a3 | 761 | * Decrements reference count of the rfkill structure so it is destroyed. |
cf4328cd ID |
762 | * Note that rfkill_free() should _not_ be called after rfkill_unregister(). |
763 | */ | |
764 | void rfkill_free(struct rfkill *rfkill) | |
765 | { | |
766 | if (rfkill) | |
767 | put_device(&rfkill->dev); | |
768 | } | |
769 | EXPORT_SYMBOL(rfkill_free); | |
770 | ||
135900c1 MB |
771 | static void rfkill_led_trigger_register(struct rfkill *rfkill) |
772 | { | |
773 | #ifdef CONFIG_RFKILL_LEDS | |
774 | int error; | |
775 | ||
7c4f4578 DB |
776 | if (!rfkill->led_trigger.name) |
777 | rfkill->led_trigger.name = rfkill->dev.bus_id; | |
96185664 DB |
778 | if (!rfkill->led_trigger.activate) |
779 | rfkill->led_trigger.activate = rfkill_led_trigger_activate; | |
135900c1 MB |
780 | error = led_trigger_register(&rfkill->led_trigger); |
781 | if (error) | |
782 | rfkill->led_trigger.name = NULL; | |
783 | #endif /* CONFIG_RFKILL_LEDS */ | |
784 | } | |
785 | ||
786 | static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | |
787 | { | |
788 | #ifdef CONFIG_RFKILL_LEDS | |
37f55e9d | 789 | if (rfkill->led_trigger.name) { |
135900c1 | 790 | led_trigger_unregister(&rfkill->led_trigger); |
37f55e9d HMH |
791 | rfkill->led_trigger.name = NULL; |
792 | } | |
135900c1 MB |
793 | #endif |
794 | } | |
795 | ||
cf4328cd ID |
796 | /** |
797 | * rfkill_register - Register a rfkill structure. | |
798 | * @rfkill: rfkill structure to be registered | |
799 | * | |
800 | * This function should be called by the network driver when the rfkill | |
801 | * structure needs to be registered. Immediately from registration the | |
802 | * switch driver should be able to service calls to toggle_radio. | |
803 | */ | |
77fba13c | 804 | int __must_check rfkill_register(struct rfkill *rfkill) |
cf4328cd ID |
805 | { |
806 | static atomic_t rfkill_no = ATOMIC_INIT(0); | |
807 | struct device *dev = &rfkill->dev; | |
808 | int error; | |
809 | ||
f745ba03 HMH |
810 | if (WARN((!rfkill || !rfkill->toggle_radio || |
811 | rfkill->type >= RFKILL_TYPE_MAX || | |
812 | rfkill->state >= RFKILL_STATE_MAX), | |
813 | KERN_WARNING | |
814 | "rfkill: attempt to register a " | |
815 | "badly initialized rfkill struct\n")) | |
96c87607 | 816 | return -EINVAL; |
cf4328cd | 817 | |
8a8f1c04 MB |
818 | snprintf(dev->bus_id, sizeof(dev->bus_id), |
819 | "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); | |
820 | ||
821 | rfkill_led_trigger_register(rfkill); | |
822 | ||
cf4328cd | 823 | error = rfkill_add_switch(rfkill); |
632041f3 EP |
824 | if (error) { |
825 | rfkill_led_trigger_unregister(rfkill); | |
cf4328cd | 826 | return error; |
632041f3 | 827 | } |
cf4328cd | 828 | |
cf4328cd ID |
829 | error = device_add(dev); |
830 | if (error) { | |
831 | rfkill_remove_switch(rfkill); | |
37f55e9d | 832 | rfkill_led_trigger_unregister(rfkill); |
cf4328cd ID |
833 | return error; |
834 | } | |
835 | ||
836 | return 0; | |
837 | } | |
838 | EXPORT_SYMBOL(rfkill_register); | |
839 | ||
840 | /** | |
c8fcd905 | 841 | * rfkill_unregister - Unregister a rfkill structure. |
cf4328cd ID |
842 | * @rfkill: rfkill structure to be unregistered |
843 | * | |
844 | * This function should be called by the network driver during device | |
845 | * teardown to destroy rfkill structure. Note that rfkill_free() should | |
846 | * _not_ be called after rfkill_unregister(). | |
847 | */ | |
848 | void rfkill_unregister(struct rfkill *rfkill) | |
849 | { | |
f745ba03 | 850 | BUG_ON(!rfkill); |
cf4328cd ID |
851 | device_del(&rfkill->dev); |
852 | rfkill_remove_switch(rfkill); | |
8a8f1c04 | 853 | rfkill_led_trigger_unregister(rfkill); |
cf4328cd ID |
854 | put_device(&rfkill->dev); |
855 | } | |
856 | EXPORT_SYMBOL(rfkill_unregister); | |
857 | ||
99619201 HMH |
858 | /** |
859 | * rfkill_set_default - set initial value for a switch type | |
860 | * @type - the type of switch to set the default state of | |
861 | * @state - the new default state for that group of switches | |
862 | * | |
863 | * Sets the initial state rfkill should use for a given type. | |
864 | * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED | |
865 | * and RFKILL_STATE_UNBLOCKED. | |
866 | * | |
867 | * This function is meant to be used by platform drivers for platforms | |
868 | * that can save switch state across power down/reboot. | |
869 | * | |
870 | * The default state for each switch type can be changed exactly once. | |
871 | * After a switch of that type is registered, the default state cannot | |
872 | * be changed anymore. This guards against multiple drivers it the | |
873 | * same platform trying to set the initial switch default state, which | |
874 | * is not allowed. | |
875 | * | |
876 | * Returns -EPERM if the state has already been set once or is in use, | |
877 | * so drivers likely want to either ignore or at most printk(KERN_NOTICE) | |
878 | * if this function returns -EPERM. | |
879 | * | |
880 | * Returns 0 if the new default state was set, or an error if it | |
881 | * could not be set. | |
882 | */ | |
883 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | |
884 | { | |
885 | int error; | |
886 | ||
f745ba03 HMH |
887 | if (WARN((type >= RFKILL_TYPE_MAX || |
888 | (state != RFKILL_STATE_SOFT_BLOCKED && | |
889 | state != RFKILL_STATE_UNBLOCKED)), | |
890 | KERN_WARNING | |
891 | "rfkill: illegal state %d or type %d passed as " | |
892 | "parameter to rfkill_set_default\n", state, type)) | |
99619201 HMH |
893 | return -EINVAL; |
894 | ||
15635744 | 895 | mutex_lock(&rfkill_global_mutex); |
99619201 HMH |
896 | |
897 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { | |
898 | rfkill_global_states[type].default_state = state; | |
68d2413b | 899 | rfkill_global_states[type].current_state = state; |
99619201 HMH |
900 | error = 0; |
901 | } else | |
902 | error = -EPERM; | |
903 | ||
15635744 | 904 | mutex_unlock(&rfkill_global_mutex); |
99619201 HMH |
905 | return error; |
906 | } | |
907 | EXPORT_SYMBOL_GPL(rfkill_set_default); | |
908 | ||
cf4328cd ID |
909 | /* |
910 | * Rfkill module initialization/deinitialization. | |
911 | */ | |
912 | static int __init rfkill_init(void) | |
913 | { | |
914 | int error; | |
915 | int i; | |
916 | ||
5005657c HMH |
917 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ |
918 | if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED && | |
919 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) | |
e954b0b8 HMH |
920 | return -EINVAL; |
921 | ||
99619201 HMH |
922 | for (i = 0; i < RFKILL_TYPE_MAX; i++) |
923 | rfkill_global_states[i].default_state = rfkill_default_state; | |
cf4328cd ID |
924 | |
925 | error = class_register(&rfkill_class); | |
926 | if (error) { | |
927 | printk(KERN_ERR "rfkill: unable to register rfkill class\n"); | |
928 | return error; | |
929 | } | |
930 | ||
ffb67c34 HMH |
931 | register_rfkill_notifier(&rfkill_blocking_uevent_nb); |
932 | ||
cf4328cd ID |
933 | return 0; |
934 | } | |
935 | ||
936 | static void __exit rfkill_exit(void) | |
937 | { | |
ffb67c34 | 938 | unregister_rfkill_notifier(&rfkill_blocking_uevent_nb); |
cf4328cd ID |
939 | class_unregister(&rfkill_class); |
940 | } | |
941 | ||
2bf236d5 | 942 | subsys_initcall(rfkill_init); |
cf4328cd | 943 | module_exit(rfkill_exit); |