aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorAlan Jenkins <alan-jenkins@tuffmail.co.uk>2009-04-27 03:23:39 -0400
committerLen Brown <len.brown@intel.com>2009-05-14 11:21:36 -0400
commit978605c4fd8e7470f225eec7b5aab69d8796afcc (patch)
tree215902c8dc001de803bdb6edabe4db3ed1facd70 /drivers/platform
parent64b86b6583db832b28bb54575e32b9e2a1a7d84f (diff)
eeepc-laptop: Work around rfkill firmware bug
1) Buggy firmware can change the RFKILL state by itself. This is easily detected. The RFKILL API states that in such cases, we should call rfkill_force_state() to notify the core. I have reported the bug to Asus. I believe this is the right thing to do for robustness, even if this particular firmware bug is fixed. 2) The same bug causes the wireless toggle key to be reported as 0x11 instead of 0x10. 0x11 is otherwise unused, so it should be safe to add this as a new keycode. The bug is triggered by removing the laptop battery while hibernated. On resume, the wireless toggle key causes the firmware to toggle the wireless state itself. (Also, the key is reported as 0x11 when the current wireless state is OFF). This is very poor behaviour because the OS can't predict whether the firmware is controlling the RFKILL state. Without this workaround, the bug means users have to press the wireless toggle key twice to enable, due to the OS/firmware conflict. (Assuming rfkill-input or equivalent is being used). The workaround avoids this. I believe that acpid scripts which toggle the value of the sysfs state file when the toggle key is pressed will be rendered ineffective by the bug, regardless of this workaround. If they simply toggle the state, when the firmware has already toggled it, then you will never see a state change. Tested on "EEEPC 4G" only. Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/eeepc-laptop.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index f54cfeac5221..57f21f0a5655 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -158,6 +158,7 @@ enum { KE_KEY, KE_END };
158static struct key_entry eeepc_keymap[] = { 158static struct key_entry eeepc_keymap[] = {
159 /* Sleep already handled via generic ACPI code */ 159 /* Sleep already handled via generic ACPI code */
160 {KE_KEY, 0x10, KEY_WLAN }, 160 {KE_KEY, 0x10, KEY_WLAN },
161 {KE_KEY, 0x11, KEY_WLAN },
161 {KE_KEY, 0x12, KEY_PROG1 }, 162 {KE_KEY, 0x12, KEY_PROG1 },
162 {KE_KEY, 0x13, KEY_MUTE }, 163 {KE_KEY, 0x13, KEY_MUTE },
163 {KE_KEY, 0x14, KEY_VOLUMEDOWN }, 164 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
@@ -528,6 +529,7 @@ static int notify_brn(void)
528 529
529static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 530static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
530{ 531{
532 enum rfkill_state state;
531 struct pci_dev *dev; 533 struct pci_dev *dev;
532 struct pci_bus *bus = pci_find_bus(0, 1); 534 struct pci_bus *bus = pci_find_bus(0, 1);
533 535
@@ -539,7 +541,9 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
539 return; 541 return;
540 } 542 }
541 543
542 if (get_acpi(CM_ASL_WLAN) == 1) { 544 eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
545
546 if (state == RFKILL_STATE_UNBLOCKED) {
543 dev = pci_get_slot(bus, 0); 547 dev = pci_get_slot(bus, 0);
544 if (dev) { 548 if (dev) {
545 /* Device already present */ 549 /* Device already present */
@@ -559,6 +563,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
559 pci_dev_put(dev); 563 pci_dev_put(dev);
560 } 564 }
561 } 565 }
566
567 rfkill_force_state(ehotk->eeepc_wlan_rfkill, state);
562} 568}
563 569
564static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 570static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)