diff options
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r-- | net/rfkill/rfkill.c | 259 |
1 files changed, 209 insertions, 50 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 74aecc098bad..f949a482b007 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -37,14 +37,20 @@ MODULE_DESCRIPTION("RF switch support"); | |||
37 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
38 | 38 | ||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | 39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ |
40 | static DEFINE_MUTEX(rfkill_mutex); | 40 | static DEFINE_MUTEX(rfkill_global_mutex); |
41 | 41 | ||
42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; | 42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; |
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); | 43 | module_param_named(default_state, rfkill_default_state, uint, 0444); |
44 | MODULE_PARM_DESC(default_state, | 44 | MODULE_PARM_DESC(default_state, |
45 | "Default initial state for all radio types, 0 = radio off"); | 45 | "Default initial state for all radio types, 0 = radio off"); |
46 | 46 | ||
47 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; | 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)]; | ||
48 | 54 | ||
49 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | 55 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); |
50 | 56 | ||
@@ -70,6 +76,7 @@ static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | |||
70 | */ | 76 | */ |
71 | int register_rfkill_notifier(struct notifier_block *nb) | 77 | int register_rfkill_notifier(struct notifier_block *nb) |
72 | { | 78 | { |
79 | BUG_ON(!nb); | ||
73 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); | 80 | return blocking_notifier_chain_register(&rfkill_notifier_list, nb); |
74 | } | 81 | } |
75 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); | 82 | EXPORT_SYMBOL_GPL(register_rfkill_notifier); |
@@ -85,6 +92,7 @@ EXPORT_SYMBOL_GPL(register_rfkill_notifier); | |||
85 | */ | 92 | */ |
86 | int unregister_rfkill_notifier(struct notifier_block *nb) | 93 | int unregister_rfkill_notifier(struct notifier_block *nb) |
87 | { | 94 | { |
95 | BUG_ON(!nb); | ||
88 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); | 96 | return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); |
89 | } | 97 | } |
90 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); | 98 | EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); |
@@ -117,6 +125,7 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) | |||
117 | 125 | ||
118 | static void notify_rfkill_state_change(struct rfkill *rfkill) | 126 | static void notify_rfkill_state_change(struct rfkill *rfkill) |
119 | { | 127 | { |
128 | rfkill_led_trigger(rfkill, rfkill->state); | ||
120 | blocking_notifier_call_chain(&rfkill_notifier_list, | 129 | blocking_notifier_call_chain(&rfkill_notifier_list, |
121 | RFKILL_STATE_CHANGED, | 130 | RFKILL_STATE_CHANGED, |
122 | rfkill); | 131 | rfkill); |
@@ -195,6 +204,11 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
195 | * BLOCK even a transmitter that is already in state | 204 | * BLOCK even a transmitter that is already in state |
196 | * RFKILL_STATE_HARD_BLOCKED */ | 205 | * RFKILL_STATE_HARD_BLOCKED */ |
197 | break; | 206 | break; |
207 | default: | ||
208 | WARN(1, KERN_WARNING | ||
209 | "rfkill: illegal state %d passed as parameter " | ||
210 | "to rfkill_toggle_radio\n", state); | ||
211 | return -EINVAL; | ||
198 | } | 212 | } |
199 | 213 | ||
200 | if (force || state != rfkill->state) { | 214 | if (force || state != rfkill->state) { |
@@ -204,31 +218,36 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
204 | rfkill->state = state; | 218 | rfkill->state = state; |
205 | } | 219 | } |
206 | 220 | ||
207 | if (force || rfkill->state != oldstate) { | 221 | if (force || rfkill->state != oldstate) |
208 | rfkill_led_trigger(rfkill, rfkill->state); | ||
209 | notify_rfkill_state_change(rfkill); | 222 | notify_rfkill_state_change(rfkill); |
210 | } | ||
211 | 223 | ||
212 | return retval; | 224 | return retval; |
213 | } | 225 | } |
214 | 226 | ||
215 | /** | 227 | /** |
216 | * rfkill_switch_all - Toggle state of all switches of given type | 228 | * __rfkill_switch_all - Toggle state of all switches of given type |
217 | * @type: type of interfaces to be affected | 229 | * @type: type of interfaces to be affected |
218 | * @state: the new state | 230 | * @state: the new state |
219 | * | 231 | * |
220 | * This function toggles the state of all switches of given type, | 232 | * This function toggles the state of all switches of given type, |
221 | * unless a specific switch is claimed by userspace (in which case, | 233 | * unless a specific switch is claimed by userspace (in which case, |
222 | * that switch is left alone) or suspended. | 234 | * that switch is left alone) or suspended. |
235 | * | ||
236 | * Caller must have acquired rfkill_global_mutex. | ||
223 | */ | 237 | */ |
224 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | 238 | static void __rfkill_switch_all(const enum rfkill_type type, |
239 | const enum rfkill_state state) | ||
225 | { | 240 | { |
226 | struct rfkill *rfkill; | 241 | struct rfkill *rfkill; |
227 | 242 | ||
228 | mutex_lock(&rfkill_mutex); | 243 | if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), |
229 | 244 | KERN_WARNING | |
230 | rfkill_states[type] = state; | 245 | "rfkill: illegal state %d or type %d " |
246 | "passed as parameter to __rfkill_switch_all\n", | ||
247 | state, type)) | ||
248 | return; | ||
231 | 249 | ||
250 | rfkill_global_states[type].current_state = state; | ||
232 | list_for_each_entry(rfkill, &rfkill_list, node) { | 251 | list_for_each_entry(rfkill, &rfkill_list, node) { |
233 | if ((!rfkill->user_claim) && (rfkill->type == type)) { | 252 | if ((!rfkill->user_claim) && (rfkill->type == type)) { |
234 | mutex_lock(&rfkill->mutex); | 253 | mutex_lock(&rfkill->mutex); |
@@ -236,8 +255,21 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
236 | mutex_unlock(&rfkill->mutex); | 255 | mutex_unlock(&rfkill->mutex); |
237 | } | 256 | } |
238 | } | 257 | } |
258 | } | ||
239 | 259 | ||
240 | mutex_unlock(&rfkill_mutex); | 260 | /** |
261 | * rfkill_switch_all - Toggle state of all switches of given type | ||
262 | * @type: type of interfaces to be affected | ||
263 | * @state: the new state | ||
264 | * | ||
265 | * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). | ||
266 | * Please refer to __rfkill_switch_all() for details. | ||
267 | */ | ||
268 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | ||
269 | { | ||
270 | mutex_lock(&rfkill_global_mutex); | ||
271 | __rfkill_switch_all(type, state); | ||
272 | mutex_unlock(&rfkill_global_mutex); | ||
241 | } | 273 | } |
242 | EXPORT_SYMBOL(rfkill_switch_all); | 274 | EXPORT_SYMBOL(rfkill_switch_all); |
243 | 275 | ||
@@ -245,23 +277,53 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
245 | * rfkill_epo - emergency power off all transmitters | 277 | * rfkill_epo - emergency power off all transmitters |
246 | * | 278 | * |
247 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | 279 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, |
248 | * ignoring everything in its path but rfkill_mutex and rfkill->mutex. | 280 | * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. |
281 | * | ||
282 | * The global state before the EPO is saved and can be restored later | ||
283 | * using rfkill_restore_states(). | ||
249 | */ | 284 | */ |
250 | void rfkill_epo(void) | 285 | void rfkill_epo(void) |
251 | { | 286 | { |
252 | struct rfkill *rfkill; | 287 | struct rfkill *rfkill; |
288 | int i; | ||
289 | |||
290 | mutex_lock(&rfkill_global_mutex); | ||
253 | 291 | ||
254 | mutex_lock(&rfkill_mutex); | ||
255 | list_for_each_entry(rfkill, &rfkill_list, node) { | 292 | list_for_each_entry(rfkill, &rfkill_list, node) { |
256 | mutex_lock(&rfkill->mutex); | 293 | mutex_lock(&rfkill->mutex); |
257 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 294 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
258 | mutex_unlock(&rfkill->mutex); | 295 | mutex_unlock(&rfkill->mutex); |
259 | } | 296 | } |
260 | mutex_unlock(&rfkill_mutex); | 297 | for (i = 0; i < RFKILL_TYPE_MAX; i++) { |
298 | rfkill_global_states[i].default_state = | ||
299 | rfkill_global_states[i].current_state; | ||
300 | rfkill_global_states[i].current_state = | ||
301 | RFKILL_STATE_SOFT_BLOCKED; | ||
302 | } | ||
303 | mutex_unlock(&rfkill_global_mutex); | ||
261 | } | 304 | } |
262 | EXPORT_SYMBOL_GPL(rfkill_epo); | 305 | EXPORT_SYMBOL_GPL(rfkill_epo); |
263 | 306 | ||
264 | /** | 307 | /** |
308 | * rfkill_restore_states - restore global states | ||
309 | * | ||
310 | * Restore (and sync switches to) the global state from the | ||
311 | * states in rfkill_default_states. This can undo the effects of | ||
312 | * a call to rfkill_epo(). | ||
313 | */ | ||
314 | void rfkill_restore_states(void) | ||
315 | { | ||
316 | int i; | ||
317 | |||
318 | mutex_lock(&rfkill_global_mutex); | ||
319 | |||
320 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | ||
321 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); | ||
322 | mutex_unlock(&rfkill_global_mutex); | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(rfkill_restore_states); | ||
325 | |||
326 | /** | ||
265 | * rfkill_force_state - Force the internal rfkill radio state | 327 | * rfkill_force_state - Force the internal rfkill radio state |
266 | * @rfkill: pointer to the rfkill class to modify. | 328 | * @rfkill: pointer to the rfkill class to modify. |
267 | * @state: the current radio state the class should be forced to. | 329 | * @state: the current radio state the class should be forced to. |
@@ -282,9 +344,11 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | |||
282 | { | 344 | { |
283 | enum rfkill_state oldstate; | 345 | enum rfkill_state oldstate; |
284 | 346 | ||
285 | if (state != RFKILL_STATE_SOFT_BLOCKED && | 347 | BUG_ON(!rfkill); |
286 | state != RFKILL_STATE_UNBLOCKED && | 348 | if (WARN((state >= RFKILL_STATE_MAX), |
287 | state != RFKILL_STATE_HARD_BLOCKED) | 349 | KERN_WARNING |
350 | "rfkill: illegal state %d passed as parameter " | ||
351 | "to rfkill_force_state\n", state)) | ||
288 | return -EINVAL; | 352 | return -EINVAL; |
289 | 353 | ||
290 | mutex_lock(&rfkill->mutex); | 354 | mutex_lock(&rfkill->mutex); |
@@ -352,12 +416,16 @@ static ssize_t rfkill_state_store(struct device *dev, | |||
352 | const char *buf, size_t count) | 416 | const char *buf, size_t count) |
353 | { | 417 | { |
354 | struct rfkill *rfkill = to_rfkill(dev); | 418 | struct rfkill *rfkill = to_rfkill(dev); |
355 | unsigned int state = simple_strtoul(buf, NULL, 0); | 419 | unsigned long state; |
356 | int error; | 420 | int error; |
357 | 421 | ||
358 | if (!capable(CAP_NET_ADMIN)) | 422 | if (!capable(CAP_NET_ADMIN)) |
359 | return -EPERM; | 423 | return -EPERM; |
360 | 424 | ||
425 | error = strict_strtoul(buf, 0, &state); | ||
426 | if (error) | ||
427 | return error; | ||
428 | |||
361 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ | 429 | /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ |
362 | if (state != RFKILL_STATE_UNBLOCKED && | 430 | if (state != RFKILL_STATE_UNBLOCKED && |
363 | state != RFKILL_STATE_SOFT_BLOCKED) | 431 | state != RFKILL_STATE_SOFT_BLOCKED) |
@@ -385,7 +453,8 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
385 | const char *buf, size_t count) | 453 | const char *buf, size_t count) |
386 | { | 454 | { |
387 | struct rfkill *rfkill = to_rfkill(dev); | 455 | struct rfkill *rfkill = to_rfkill(dev); |
388 | bool claim = !!simple_strtoul(buf, NULL, 0); | 456 | unsigned long claim_tmp; |
457 | bool claim; | ||
389 | int error; | 458 | int error; |
390 | 459 | ||
391 | if (!capable(CAP_NET_ADMIN)) | 460 | if (!capable(CAP_NET_ADMIN)) |
@@ -394,11 +463,16 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
394 | if (rfkill->user_claim_unsupported) | 463 | if (rfkill->user_claim_unsupported) |
395 | return -EOPNOTSUPP; | 464 | return -EOPNOTSUPP; |
396 | 465 | ||
466 | error = strict_strtoul(buf, 0, &claim_tmp); | ||
467 | if (error) | ||
468 | return error; | ||
469 | claim = !!claim_tmp; | ||
470 | |||
397 | /* | 471 | /* |
398 | * Take the global lock to make sure the kernel is not in | 472 | * Take the global lock to make sure the kernel is not in |
399 | * the middle of rfkill_switch_all | 473 | * the middle of rfkill_switch_all |
400 | */ | 474 | */ |
401 | error = mutex_lock_interruptible(&rfkill_mutex); | 475 | error = mutex_lock_interruptible(&rfkill_global_mutex); |
402 | if (error) | 476 | if (error) |
403 | return error; | 477 | return error; |
404 | 478 | ||
@@ -406,14 +480,14 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
406 | if (!claim) { | 480 | if (!claim) { |
407 | mutex_lock(&rfkill->mutex); | 481 | mutex_lock(&rfkill->mutex); |
408 | rfkill_toggle_radio(rfkill, | 482 | rfkill_toggle_radio(rfkill, |
409 | rfkill_states[rfkill->type], | 483 | rfkill_global_states[rfkill->type].current_state, |
410 | 0); | 484 | 0); |
411 | mutex_unlock(&rfkill->mutex); | 485 | mutex_unlock(&rfkill->mutex); |
412 | } | 486 | } |
413 | rfkill->user_claim = claim; | 487 | rfkill->user_claim = claim; |
414 | } | 488 | } |
415 | 489 | ||
416 | mutex_unlock(&rfkill_mutex); | 490 | mutex_unlock(&rfkill_global_mutex); |
417 | 491 | ||
418 | return error ? error : count; | 492 | return error ? error : count; |
419 | } | 493 | } |
@@ -437,21 +511,9 @@ static void rfkill_release(struct device *dev) | |||
437 | #ifdef CONFIG_PM | 511 | #ifdef CONFIG_PM |
438 | static int rfkill_suspend(struct device *dev, pm_message_t state) | 512 | static int rfkill_suspend(struct device *dev, pm_message_t state) |
439 | { | 513 | { |
440 | struct rfkill *rfkill = to_rfkill(dev); | 514 | /* mark class device as suspended */ |
441 | 515 | if (dev->power.power_state.event != state.event) | |
442 | if (dev->power.power_state.event != state.event) { | ||
443 | if (state.event & PM_EVENT_SLEEP) { | ||
444 | /* Stop transmitter, keep state, no notifies */ | ||
445 | update_rfkill_state(rfkill); | ||
446 | |||
447 | mutex_lock(&rfkill->mutex); | ||
448 | rfkill->toggle_radio(rfkill->data, | ||
449 | RFKILL_STATE_SOFT_BLOCKED); | ||
450 | mutex_unlock(&rfkill->mutex); | ||
451 | } | ||
452 | |||
453 | dev->power.power_state = state; | 516 | dev->power.power_state = state; |
454 | } | ||
455 | 517 | ||
456 | return 0; | 518 | return 0; |
457 | } | 519 | } |
@@ -525,24 +587,60 @@ static struct class rfkill_class = { | |||
525 | .dev_uevent = rfkill_dev_uevent, | 587 | .dev_uevent = rfkill_dev_uevent, |
526 | }; | 588 | }; |
527 | 589 | ||
590 | static int rfkill_check_duplicity(const struct rfkill *rfkill) | ||
591 | { | ||
592 | struct rfkill *p; | ||
593 | unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
594 | |||
595 | memset(seen, 0, sizeof(seen)); | ||
596 | |||
597 | list_for_each_entry(p, &rfkill_list, node) { | ||
598 | if (WARN((p == rfkill), KERN_WARNING | ||
599 | "rfkill: illegal attempt to register " | ||
600 | "an already registered rfkill struct\n")) | ||
601 | return -EEXIST; | ||
602 | set_bit(p->type, seen); | ||
603 | } | ||
604 | |||
605 | /* 0: first switch of its kind */ | ||
606 | return test_bit(rfkill->type, seen); | ||
607 | } | ||
608 | |||
528 | static int rfkill_add_switch(struct rfkill *rfkill) | 609 | static int rfkill_add_switch(struct rfkill *rfkill) |
529 | { | 610 | { |
530 | mutex_lock(&rfkill_mutex); | 611 | int error; |
612 | |||
613 | mutex_lock(&rfkill_global_mutex); | ||
531 | 614 | ||
532 | rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0); | 615 | error = rfkill_check_duplicity(rfkill); |
616 | if (error < 0) | ||
617 | goto unlock_out; | ||
618 | |||
619 | if (!error) { | ||
620 | /* lock default after first use */ | ||
621 | set_bit(rfkill->type, rfkill_states_lockdflt); | ||
622 | rfkill_global_states[rfkill->type].current_state = | ||
623 | rfkill_global_states[rfkill->type].default_state; | ||
624 | } | ||
625 | |||
626 | rfkill_toggle_radio(rfkill, | ||
627 | rfkill_global_states[rfkill->type].current_state, | ||
628 | 0); | ||
533 | 629 | ||
534 | list_add_tail(&rfkill->node, &rfkill_list); | 630 | list_add_tail(&rfkill->node, &rfkill_list); |
535 | 631 | ||
536 | mutex_unlock(&rfkill_mutex); | 632 | error = 0; |
633 | unlock_out: | ||
634 | mutex_unlock(&rfkill_global_mutex); | ||
537 | 635 | ||
538 | return 0; | 636 | return error; |
539 | } | 637 | } |
540 | 638 | ||
541 | static void rfkill_remove_switch(struct rfkill *rfkill) | 639 | static void rfkill_remove_switch(struct rfkill *rfkill) |
542 | { | 640 | { |
543 | mutex_lock(&rfkill_mutex); | 641 | mutex_lock(&rfkill_global_mutex); |
544 | list_del_init(&rfkill->node); | 642 | list_del_init(&rfkill->node); |
545 | mutex_unlock(&rfkill_mutex); | 643 | mutex_unlock(&rfkill_global_mutex); |
546 | 644 | ||
547 | mutex_lock(&rfkill->mutex); | 645 | mutex_lock(&rfkill->mutex); |
548 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 646 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
@@ -562,11 +660,18 @@ static void rfkill_remove_switch(struct rfkill *rfkill) | |||
562 | * NOTE: If registration fails the structure shoudl be freed by calling | 660 | * NOTE: If registration fails the structure shoudl be freed by calling |
563 | * rfkill_free() otherwise rfkill_unregister() should be used. | 661 | * rfkill_free() otherwise rfkill_unregister() should be used. |
564 | */ | 662 | */ |
565 | struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type) | 663 | struct rfkill * __must_check rfkill_allocate(struct device *parent, |
664 | enum rfkill_type type) | ||
566 | { | 665 | { |
567 | struct rfkill *rfkill; | 666 | struct rfkill *rfkill; |
568 | struct device *dev; | 667 | struct device *dev; |
569 | 668 | ||
669 | if (WARN((type >= RFKILL_TYPE_MAX), | ||
670 | KERN_WARNING | ||
671 | "rfkill: illegal type %d passed as parameter " | ||
672 | "to rfkill_allocate\n", type)) | ||
673 | return NULL; | ||
674 | |||
570 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); | 675 | rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); |
571 | if (!rfkill) | 676 | if (!rfkill) |
572 | return NULL; | 677 | return NULL; |
@@ -633,15 +738,18 @@ static void rfkill_led_trigger_unregister(struct rfkill *rfkill) | |||
633 | * structure needs to be registered. Immediately from registration the | 738 | * structure needs to be registered. Immediately from registration the |
634 | * switch driver should be able to service calls to toggle_radio. | 739 | * switch driver should be able to service calls to toggle_radio. |
635 | */ | 740 | */ |
636 | int rfkill_register(struct rfkill *rfkill) | 741 | int __must_check rfkill_register(struct rfkill *rfkill) |
637 | { | 742 | { |
638 | static atomic_t rfkill_no = ATOMIC_INIT(0); | 743 | static atomic_t rfkill_no = ATOMIC_INIT(0); |
639 | struct device *dev = &rfkill->dev; | 744 | struct device *dev = &rfkill->dev; |
640 | int error; | 745 | int error; |
641 | 746 | ||
642 | if (!rfkill->toggle_radio) | 747 | if (WARN((!rfkill || !rfkill->toggle_radio || |
643 | return -EINVAL; | 748 | rfkill->type >= RFKILL_TYPE_MAX || |
644 | if (rfkill->type >= RFKILL_TYPE_MAX) | 749 | rfkill->state >= RFKILL_STATE_MAX), |
750 | KERN_WARNING | ||
751 | "rfkill: attempt to register a " | ||
752 | "badly initialized rfkill struct\n")) | ||
645 | return -EINVAL; | 753 | return -EINVAL; |
646 | 754 | ||
647 | snprintf(dev->bus_id, sizeof(dev->bus_id), | 755 | snprintf(dev->bus_id, sizeof(dev->bus_id), |
@@ -676,6 +784,7 @@ EXPORT_SYMBOL(rfkill_register); | |||
676 | */ | 784 | */ |
677 | void rfkill_unregister(struct rfkill *rfkill) | 785 | void rfkill_unregister(struct rfkill *rfkill) |
678 | { | 786 | { |
787 | BUG_ON(!rfkill); | ||
679 | device_del(&rfkill->dev); | 788 | device_del(&rfkill->dev); |
680 | rfkill_remove_switch(rfkill); | 789 | rfkill_remove_switch(rfkill); |
681 | rfkill_led_trigger_unregister(rfkill); | 790 | rfkill_led_trigger_unregister(rfkill); |
@@ -683,6 +792,56 @@ void rfkill_unregister(struct rfkill *rfkill) | |||
683 | } | 792 | } |
684 | EXPORT_SYMBOL(rfkill_unregister); | 793 | EXPORT_SYMBOL(rfkill_unregister); |
685 | 794 | ||
795 | /** | ||
796 | * rfkill_set_default - set initial value for a switch type | ||
797 | * @type - the type of switch to set the default state of | ||
798 | * @state - the new default state for that group of switches | ||
799 | * | ||
800 | * Sets the initial state rfkill should use for a given type. | ||
801 | * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED | ||
802 | * and RFKILL_STATE_UNBLOCKED. | ||
803 | * | ||
804 | * This function is meant to be used by platform drivers for platforms | ||
805 | * that can save switch state across power down/reboot. | ||
806 | * | ||
807 | * The default state for each switch type can be changed exactly once. | ||
808 | * After a switch of that type is registered, the default state cannot | ||
809 | * be changed anymore. This guards against multiple drivers it the | ||
810 | * same platform trying to set the initial switch default state, which | ||
811 | * is not allowed. | ||
812 | * | ||
813 | * Returns -EPERM if the state has already been set once or is in use, | ||
814 | * so drivers likely want to either ignore or at most printk(KERN_NOTICE) | ||
815 | * if this function returns -EPERM. | ||
816 | * | ||
817 | * Returns 0 if the new default state was set, or an error if it | ||
818 | * could not be set. | ||
819 | */ | ||
820 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | ||
821 | { | ||
822 | int error; | ||
823 | |||
824 | if (WARN((type >= RFKILL_TYPE_MAX || | ||
825 | (state != RFKILL_STATE_SOFT_BLOCKED && | ||
826 | state != RFKILL_STATE_UNBLOCKED)), | ||
827 | KERN_WARNING | ||
828 | "rfkill: illegal state %d or type %d passed as " | ||
829 | "parameter to rfkill_set_default\n", state, type)) | ||
830 | return -EINVAL; | ||
831 | |||
832 | mutex_lock(&rfkill_global_mutex); | ||
833 | |||
834 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { | ||
835 | rfkill_global_states[type].default_state = state; | ||
836 | error = 0; | ||
837 | } else | ||
838 | error = -EPERM; | ||
839 | |||
840 | mutex_unlock(&rfkill_global_mutex); | ||
841 | return error; | ||
842 | } | ||
843 | EXPORT_SYMBOL_GPL(rfkill_set_default); | ||
844 | |||
686 | /* | 845 | /* |
687 | * Rfkill module initialization/deinitialization. | 846 | * Rfkill module initialization/deinitialization. |
688 | */ | 847 | */ |
@@ -696,8 +855,8 @@ static int __init rfkill_init(void) | |||
696 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) | 855 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) |
697 | return -EINVAL; | 856 | return -EINVAL; |
698 | 857 | ||
699 | for (i = 0; i < ARRAY_SIZE(rfkill_states); i++) | 858 | for (i = 0; i < RFKILL_TYPE_MAX; i++) |
700 | rfkill_states[i] = rfkill_default_state; | 859 | rfkill_global_states[i].default_state = rfkill_default_state; |
701 | 860 | ||
702 | error = class_register(&rfkill_class); | 861 | error = class_register(&rfkill_class); |
703 | if (error) { | 862 | if (error) { |