diff mbox

[RFT] hp-wmi: improved rfkill support for wifi

Message ID 4A61FE7D.9080409@tuffmail.co.uk (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Alan Jenkins July 18, 2009, 4:55 p.m. UTC
I borrowed a HP G7000 last week.  The hp-wmi driver seemed a bit
confused about hard v.s. soft blocks on the wifi, so I fixed it based on
acpidump output [1].  I hope this will work on other HP model numbers,
but it would benefit from testing.  Any volunteers?

The wireless is toggled by a hardware button.  If your laptop is the
same, you should see a "2" in the output of "cat
/sys/class/rfkill/rfkill*/state" when the wireless is disabled.  "1"
means enabled, and "0" means "disabled by software".  Without this
patch, the driver would wrongly show "0" when the wireless was disabled
by the hardware button.

There are some other side-effects which the patch should fix.  I think
it should improve behaviour when you disable the wireless and reboot
into Windows, or vice versa.  Without the patch, it seemed that hp-wmi
would leave a "soft block" without being asked to.  After disabling the
wireless and rebooting into Windows, pressing the wireless button failed
to re-enable it.  Instead, the HP Wireless Assistant popup toggled
between "wireless disabled" and "wireless off".

[1] HP G7000 acpidump.out
<http://bugzilla.kernel.org/show_bug.cgi?id=13745#c1>

Thanks
Alan

----->
From 9446bad909bf4c6b3d6d57d2f364ac18616f9baa Mon Sep 17 00:00:00 2001
From: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Date: Sat, 18 Jul 2009 16:48:37 +0100
Subject: [PATCH] [PATCH] hp-wmi: improve wlan rfkill support

1) The platform appears to support both hardware and software block
   states.  The current code only reads the overall state, and reports
   it as the software state.  Fix it.

2) Since the software state appears to be persistent, mark it as such.

3) Check rfkill in the resume handler resume.  Both the hard and soft
   blocked states could change over hibernation.

Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
---
 drivers/platform/x86/hp-wmi.c |   27 +++++++++++++++++++++++----
 1 files changed, 23 insertions(+), 4 deletions(-)

Comments

Matthew Garrett July 18, 2009, 5:03 p.m. UTC | #1
On Sat, Jul 18, 2009 at 05:55:25PM +0100, Alan Jenkins wrote:
> I borrowed a HP G7000 last week.  The hp-wmi driver seemed a bit
> confused about hard v.s. soft blocks on the wifi, so I fixed it based on
> acpidump output [1].  I hope this will work on other HP model numbers,
> but it would benefit from testing.  Any volunteers?

This looks good. Would you mind doing the same for bluetooth and wwan? 
What documentation I have suggests they should have the same behaviour.
Maciej Rutecki July 18, 2009, 6:55 p.m. UTC | #2
2009/7/18 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:
> I borrowed a HP G7000 last week.  The hp-wmi driver seemed a bit
> confused about hard v.s. soft blocks on the wifi, so I fixed it based on
> acpidump output [1].  I hope this will work on other HP model numbers,
> but it would benefit from testing.  Any volunteers?

HP/Compaq nx6310
2.6.31-rc3+patch

When is enabled by button:
root@gumis:/sys/class/rfkill# ls
rfkill0  rfkill1  rfkill2  rfkill3
root@gumis:/sys/class/rfkill# cat rfkill*/name
phy0
hci0
hp-wifi
hp-bluetooth
root@gumis:/sys/class/rfkill# cat rfkill*/state
1
1
1
1

When disabled by button:
root@gumis:/sys/class/rfkill# ls
rfkill0  rfkill2  rfkill3
root@gumis:/sys/class/rfkill# cat rfkill*/name
phy0
hp-wifi
hp-bluetooth
root@gumis:/sys/class/rfkill# cat rfkill*/state
2
1
0

I enable again by button:
root@gumis:/sys/class/rfkill# ls
rfkill0  rfkill2  rfkill3  rfkill4
root@gumis:/sys/class/rfkill# cat rfkill*/name
phy0
hp-wifi
hp-bluetooth
hci0
root@gumis:/sys/class/rfkill# cat rfkill*/state
1
1
1
1

I disable "by software" in Windows XP (bluetooth and wireless):
root@gumis:/sys/class/rfkill# ls
rfkill0  rfkill1  rfkill2  rfkill3
root@gumis:/sys/class/rfkill# cat rfkill*/name
phy0
hp-wifi
hp-bluetooth
hci0
root@gumis:/sys/class/rfkill# cat rfkill*/state
2
0
1
1

Bluetooth works fine when I back to Linux, it seems be enabled during
boot. Wireless is disabled. I cannot connect to network. So I
re-enable it in Windows:
root@gumis:/sys/class/rfkill# ls
rfkill0  rfkill1  rfkill2  rfkill3
root@gumis:/sys/class/rfkill# cat rfkill*/name
phy0
hci0
hp-wifi
hp-bluetooth
root@gumis:/sys/class/rfkill# cat rfkill*/state
1
1
1
1

Regards
Alan Jenkins July 18, 2009, 8:46 p.m. UTC | #3
Maciej Rutecki wrote:
> 2009/7/18 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:
>   
>> I borrowed a HP G7000 last week.  The hp-wmi driver seemed a bit
>> confused about hard v.s. soft blocks on the wifi, so I fixed it based on
>> acpidump output [1].  I hope this will work on other HP model numbers,
>> but it would benefit from testing.  Any volunteers?
>>     
>
> HP/Compaq nx6310
> 2.6.31-rc3+patch
>
> When is enabled by button:
> root@gumis:/sys/class/rfkill# ls
> rfkill0  rfkill1  rfkill2  rfkill3
> root@gumis:/sys/class/rfkill# cat rfkill*/name
> phy0
> hci0
> hp-wifi
> hp-bluetooth
> root@gumis:/sys/class/rfkill# cat rfkill*/state
> 1
> 1
> 1
> 1
>
> When disabled by button:
> root@gumis:/sys/class/rfkill# ls
> rfkill0  rfkill2  rfkill3
> root@gumis:/sys/class/rfkill# cat rfkill*/name
> phy0
> hp-wifi
> hp-bluetooth
> root@gumis:/sys/class/rfkill# cat rfkill*/state
> 2
> 1
> 0
>
> I enable again by button:
> root@gumis:/sys/class/rfkill# ls
> rfkill0  rfkill2  rfkill3  rfkill4
> root@gumis:/sys/class/rfkill# cat rfkill*/name
> phy0
> hp-wifi
> hp-bluetooth
> hci0
> root@gumis:/sys/class/rfkill# cat rfkill*/state
> 1
> 1
> 1
> 1
>
> I disable "by software" in Windows XP (bluetooth and wireless):
> root@gumis:/sys/class/rfkill# ls
> rfkill0  rfkill1  rfkill2  rfkill3
> root@gumis:/sys/class/rfkill# cat rfkill*/name
> phy0
> hp-wifi
> hp-bluetooth
> hci0
> root@gumis:/sys/class/rfkill# cat rfkill*/state
> 2
> 0
> 1
> 1
>
> Bluetooth works fine when I back to Linux, it seems be enabled during
> boot. Wireless is disabled. I cannot connect to network. So I
> re-enable it in Windows:
> root@gumis:/sys/class/rfkill# ls
> rfkill0  rfkill1  rfkill2  rfkill3
> root@gumis:/sys/class/rfkill# cat rfkill*/name
> phy0
> hci0
> hp-wifi
> hp-bluetooth
> root@gumis:/sys/class/rfkill# cat rfkill*/state
> 1
> 1
> 1
> 1
>
> Regards
>   

Great detail!  That all fits with what I was expecting.

Linux can also do enabling "by software".  At the moment, you need to
download and compile a utility to poke /dev/rfkill.  I wouldn't bother
testing it, because I didn't change that bit :-).

I'll try extending this to bluetooth and wwan as Matthew suggested.  If
you have time to run "acpidump" and send me the output, that would help
me check the details.

Thanks for volunteering :-)
Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Corentin Chary July 18, 2009, 9:37 p.m. UTC | #4
On Sat, Jul 18, 2009 at 10:46 PM, Alan
Jenkins<alan-jenkins@tuffmail.co.uk> wrote:
> Maciej Rutecki wrote:
>> 2009/7/18 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:
>>
>>> I borrowed a HP G7000 last week.  The hp-wmi driver seemed a bit
>>> confused about hard v.s. soft blocks on the wifi, so I fixed it based on
>>> acpidump output [1].  I hope this will work on other HP model numbers,
>>> but it would benefit from testing.  Any volunteers?
>>>
>>
>> HP/Compaq nx6310
>> 2.6.31-rc3+patch
>>
>> When is enabled by button:
>> root@gumis:/sys/class/rfkill# ls
>> rfkill0  rfkill1  rfkill2  rfkill3
>> root@gumis:/sys/class/rfkill# cat rfkill*/name
>> phy0
>> hci0
>> hp-wifi
>> hp-bluetooth
>> root@gumis:/sys/class/rfkill# cat rfkill*/state
>> 1
>> 1
>> 1
>> 1
>>
>> When disabled by button:
>> root@gumis:/sys/class/rfkill# ls
>> rfkill0  rfkill2  rfkill3
>> root@gumis:/sys/class/rfkill# cat rfkill*/name
>> phy0
>> hp-wifi
>> hp-bluetooth
>> root@gumis:/sys/class/rfkill# cat rfkill*/state
>> 2
>> 1
>> 0
>>
>> I enable again by button:
>> root@gumis:/sys/class/rfkill# ls
>> rfkill0  rfkill2  rfkill3  rfkill4
>> root@gumis:/sys/class/rfkill# cat rfkill*/name
>> phy0
>> hp-wifi
>> hp-bluetooth
>> hci0
>> root@gumis:/sys/class/rfkill# cat rfkill*/state
>> 1
>> 1
>> 1
>> 1
>>
>> I disable "by software" in Windows XP (bluetooth and wireless):
>> root@gumis:/sys/class/rfkill# ls
>> rfkill0  rfkill1  rfkill2  rfkill3
>> root@gumis:/sys/class/rfkill# cat rfkill*/name
>> phy0
>> hp-wifi
>> hp-bluetooth
>> hci0
>> root@gumis:/sys/class/rfkill# cat rfkill*/state
>> 2
>> 0
>> 1
>> 1
>>
>> Bluetooth works fine when I back to Linux, it seems be enabled during
>> boot. Wireless is disabled. I cannot connect to network. So I
>> re-enable it in Windows:
>> root@gumis:/sys/class/rfkill# ls
>> rfkill0  rfkill1  rfkill2  rfkill3
>> root@gumis:/sys/class/rfkill# cat rfkill*/name
>> phy0
>> hci0
>> hp-wifi
>> hp-bluetooth
>> root@gumis:/sys/class/rfkill# cat rfkill*/state
>> 1
>> 1
>> 1
>> 1
>>
>> Regards
>>
>
> Great detail!  That all fits with what I was expecting.
>
> Linux can also do enabling "by software".  At the moment, you need to
> download and compile a utility to poke /dev/rfkill.  I wouldn't bother
> testing it, because I didn't change that bit :-).

Utility is here
http://git.sipsolutions.net/?p=rfkill.git
And a patch to restore write access to /sys/class/rfkill/*/state file is here
http://lkml.org/lkml/2009/7/10/339


> I'll try extending this to bluetooth and wwan as Matthew suggested.  If
> you have time to run "acpidump" and send me the output, that would help
> me check the details.

I have an HP 8710p, so if you want acpidump and test on another
hardware, just ask :).
Maciej Rutecki July 19, 2009, 8:15 a.m. UTC | #5
2009/7/18 Corentin Chary <corentin.chary@gmail.com>:
>> Linux can also do enabling "by software".  At the moment, you need to
>> download and compile a utility to poke /dev/rfkill.  I wouldn't bother
>> testing it, because I didn't change that bit :-).
>
> Utility is here
> http://git.sipsolutions.net/?p=rfkill.git
> And a patch to restore write access to /sys/class/rfkill/*/state file is here
> http://lkml.org/lkml/2009/7/10/339

Great tool.

Block bluetooth:
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill block 3
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: yes
        Hard blocked: no

root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill unblock 3
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
5: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no

Block wireless:
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill block 0
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill list
0: phy0: Wireless LAN
        Soft blocked: yes
        Hard blocked: no
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
5: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill unblock 0
root@gumis:/home/maciek/zrodelka/rfkill/rfkill# ./rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
5: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
	
Works very nice on my laptop

Thanks!
diff mbox

Patch

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index ca50856..517ac47 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -180,11 +180,21 @@  static const struct rfkill_ops hp_wmi_rfkill_ops = {
 	.set_block = hp_wmi_set_block,
 };
 
-static bool hp_wmi_wifi_state(void)
+static bool hp_wmi_wifi_sw_state(void)
 {
 	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
 
-	if (wireless & 0x100)
+	if (wireless & 0x200)
+		return false;
+	else
+		return true;
+}
+
+static bool hp_wmi_wifi_hw_state(void)
+{
+	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
+
+	if (wireless & 0x800)
 		return false;
 	else
 		return true;
@@ -359,8 +369,9 @@  static void hp_wmi_notify(u32 value, void *context)
 			input_sync(hp_wmi_input_dev);
 		} else if (eventcode == 0x5) {
 			if (wifi_rfkill)
-				rfkill_set_sw_state(wifi_rfkill,
-						    hp_wmi_wifi_state());
+				rfkill_set_states(wifi_rfkill,
+						  hp_wmi_wifi_sw_state(),
+						  hp_wmi_wifi_hw_state());
 			if (bluetooth_rfkill)
 				rfkill_set_sw_state(bluetooth_rfkill,
 						    hp_wmi_bluetooth_state());
@@ -451,6 +462,10 @@  static int __init hp_wmi_bios_setup(struct platform_device *device)
 					   RFKILL_TYPE_WLAN,
 					   &hp_wmi_rfkill_ops,
 					   (void *) 0);
+		rfkill_init_sw_state(wifi_rfkill,
+				     hp_wmi_wifi_sw_state());
+		rfkill_set_hw_state(wifi_rfkill,
+				    hp_wmi_wifi_hw_state());
 		err = rfkill_register(wifi_rfkill);
 		if (err)
 			goto register_wifi_error;
@@ -526,6 +541,10 @@  static int hp_wmi_resume_handler(struct platform_device *device)
 			    hp_wmi_tablet_state());
 	input_sync(hp_wmi_input_dev);
 
+	rfkill_set_states(wifi_rfkill,
+			  hp_wmi_wifi_sw_state(),
+			  hp_wmi_wifi_hw_state());
+
 	return 0;
 }