diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-11-17 08:00:23 -0500 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2013-11-20 18:50:48 -0500 |
commit | 04c9a3a06c47b337b90a91e458716262cc45b103 (patch) | |
tree | 3db67324dc6c1b5021e383d41e253261bc5638de /drivers/platform | |
parent | 4d39d88ceb83e88953a76df8b1fa10f43f328038 (diff) |
dell-laptop: Sync current block state to BIOS on hw switch change
This is necessary for 3 reasons:
1) To apply sw_state changes made while hw-blocked
2) To set all the blocked bits for hw-switch controlled radios to 1 when the
switch gets changed to off, this is necessary on some models to actually
turn the radio status LEDs off.
3) On some models non hw-switch controlled radios will have their block bit
cleared (potentially undoing a soft-block) on hw-switch toggle, this
restores the sw-block in this case.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 834f499a6aec..7f59624d805d 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -422,10 +422,16 @@ out: | |||
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | /* Must be called with the buffer held */ | ||
425 | static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, | 426 | static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, |
426 | int status) | 427 | int status) |
427 | { | 428 | { |
428 | if (!(status & BIT(0))) { | 429 | if (status & BIT(0)) { |
430 | /* Has hw-switch, sync sw_state to BIOS */ | ||
431 | int block = rfkill_blocked(rfkill); | ||
432 | buffer->input[0] = (1 | (radio << 8) | (block << 16)); | ||
433 | dell_send_request(buffer, 17, 11); | ||
434 | } else { | ||
429 | /* No hw-switch, sync BIOS state to sw_state */ | 435 | /* No hw-switch, sync BIOS state to sw_state */ |
430 | rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); | 436 | rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); |
431 | } | 437 | } |
@@ -445,9 +451,10 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) | |||
445 | get_buffer(); | 451 | get_buffer(); |
446 | dell_send_request(buffer, 17, 11); | 452 | dell_send_request(buffer, 17, 11); |
447 | status = buffer->output[1]; | 453 | status = buffer->output[1]; |
448 | release_buffer(); | ||
449 | 454 | ||
450 | dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status); | 455 | dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status); |
456 | |||
457 | release_buffer(); | ||
451 | } | 458 | } |
452 | 459 | ||
453 | static const struct rfkill_ops dell_rfkill_ops = { | 460 | static const struct rfkill_ops dell_rfkill_ops = { |
@@ -531,7 +538,6 @@ static void dell_update_rfkill(struct work_struct *ignored) | |||
531 | get_buffer(); | 538 | get_buffer(); |
532 | dell_send_request(buffer, 17, 11); | 539 | dell_send_request(buffer, 17, 11); |
533 | status = buffer->output[1]; | 540 | status = buffer->output[1]; |
534 | release_buffer(); | ||
535 | 541 | ||
536 | if (wifi_rfkill) { | 542 | if (wifi_rfkill) { |
537 | dell_rfkill_update_hw_state(wifi_rfkill, 1, status); | 543 | dell_rfkill_update_hw_state(wifi_rfkill, 1, status); |
@@ -545,6 +551,8 @@ static void dell_update_rfkill(struct work_struct *ignored) | |||
545 | dell_rfkill_update_hw_state(wwan_rfkill, 3, status); | 551 | dell_rfkill_update_hw_state(wwan_rfkill, 3, status); |
546 | dell_rfkill_update_sw_state(wwan_rfkill, 3, status); | 552 | dell_rfkill_update_sw_state(wwan_rfkill, 3, status); |
547 | } | 553 | } |
554 | |||
555 | release_buffer(); | ||
548 | } | 556 | } |
549 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | 557 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); |
550 | 558 | ||