diff mbox

hp-wmi: improve rfkill support

Message ID 4A65A2F9.1060509@tuffmail.co.uk (mailing list archive)
State Accepted
Delegated to: Len Brown
Headers show

Commit Message

Alan Jenkins July 21, 2009, 11:14 a.m. UTC
1) Add support for reading the hardware blocked state.  Previously
   we read a combination of the hardware and software blocked states,
   reporting it as the software blocked state.  This caused some
   confusing behaviour.

2) The software state is persistent, mark it as such.

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

Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Tested-by: Maciej Rutecki <maciej.rutecki@gmail.com>
---

This code is the combination of two patches tested by Maciej.
There are no changes to that code, only an updated changelog.

I tested wifi on the G7000.  Maciej tested wifi and bluetooth.
wwan is as yet untested; we are assuming the interface follows
the same pattern as wifi and bluetooth.

 drivers/platform/x86/hp-wmi.c |  139 +++++++++++++++++++++++++----------------
 1 files changed, 84 insertions(+), 55 deletions(-)

Comments

Matthew Garrett July 21, 2009, 11:26 a.m. UTC | #1
On Tue, Jul 21, 2009 at 12:14:01PM +0100, Alan Jenkins wrote:
> 1) Add support for reading the hardware blocked state.  Previously
>    we read a combination of the hardware and software blocked states,
>    reporting it as the software blocked state.  This caused some
>    confusing behaviour.
> 
> 2) The software state is persistent, mark it as such.
> 
> 3) Check rfkill in the resume handler.  Both the hard and soft
>    blocked states may change over hibernation.
> 
> Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
> Tested-by: Maciej Rutecki <maciej.rutecki@gmail.com>
Acked-by: Matthew Garrett <mjg@redhat.com>
Maciej Rutecki July 23, 2009, 3:31 p.m. UTC | #2
2009/7/21 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:
> 1) Add support for reading the hardware blocked state.  Previously
>   we read a combination of the hardware and software blocked states,
>   reporting it as the software blocked state.  This caused some
>   confusing behaviour.
>
> 2) The software state is persistent, mark it as such.
>
> 3) Check rfkill in the resume handler.  Both the hard and soft
>   blocked states may change over hibernation.
>
> Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
> Tested-by: Maciej Rutecki <maciej.rutecki@gmail.com>

It's this patch is added to -rc4? I one case I have strange behaviour.

Before disable by button:
root@gumis:/home/maciek/Desktop# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
16: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
17: phy7: Wireless LAN
        Soft blocked: no
        Hard blocked: no
	
Disable by button:
root@gumis:/home/maciek/Desktop# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: yes
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: yes
        Hard blocked: no
17: phy7: Wireless LAN
        Soft blocked: no
        Hard blocked: yes
	
I do s2disk. After resume from suspend to disk (still disabled by button):
root@gumis:/home/maciek/Desktop# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: yes
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: yes
        Hard blocked: no
18: phy8: Wireless LAN
        Soft blocked: no
        Hard blocked: yes
	
Try enable by button:
root@gumis:/home/maciek/Desktop# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: yes
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: yes
        Hard blocked: no
18: phy8: Wireless LAN
        Soft blocked: no
        Hard blocked: yes
	
Nothing change (LED, wireless and bluetooth don't work). To enable it
I use this script rfkill.sh (I must use rfkill program):

#!/bin/sh
PROGRAM=/usr/local/sbin/rfkill
WIFI=`$PROGRAM list | grep -E 'Wireless|Bluetooth' | cut -d  ':' -f 1`

for DEVICE in $WIFI; do
  echo $DEVICE
  $PROGRAM unblock $DEVICE
done

Then works OK:
root@gumis:/home/maciek/Desktop# ./rfkill.sh
2
3
18
root@gumis:/home/maciek/Desktop# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
18: phy8: Wireless LAN
        Soft blocked: no
        Hard blocked: no
19: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
	
It's normal behaviour?
Alan Jenkins July 23, 2009, 6:27 p.m. UTC | #3
Maciej Rutecki wrote:
> 2009/7/21 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:
>   
>> 1) Add support for reading the hardware blocked state.  Previously
>>   we read a combination of the hardware and software blocked states,
>>   reporting it as the software blocked state.  This caused some
>>   confusing behaviour.
>>
>> 2) The software state is persistent, mark it as such.
>>
>> 3) Check rfkill in the resume handler.  Both the hard and soft
>>   blocked states may change over hibernation.
>>
>> Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
>> Tested-by: Maciej Rutecki <maciej.rutecki@gmail.com>
>>     
>
> It's this patch is added to -rc4?

No. 
<http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git&a=search&h=HEAD&st=commit&s=hp-wmi>

I didn't submit it for 2.6.31 because I didn't think it fixed a regression.

>  I one case I have strange behaviour.
>
> Before disable by button:
> root@gumis:/home/maciek/Desktop# rfkill list
> 2: hp-wifi: Wireless LAN
>         Soft blocked: no
>         Hard blocked: no
> 3: hp-bluetooth: Bluetooth
>         Soft blocked: no
>         Hard blocked: no
> 16: hci0: Bluetooth
>         Soft blocked: no
>         Hard blocked: no
> 17: phy7: Wireless LAN
>         Soft blocked: no
>         Hard blocked: no
> 	
> Disable by button:
> root@gumis:/home/maciek/Desktop# rfkill list
> 2: hp-wifi: Wireless LAN
>         Soft blocked: yes
>         Hard blocked: no
> 3: hp-bluetooth: Bluetooth
>         Soft blocked: yes
>         Hard blocked: no
> 17: phy7: Wireless LAN
>         Soft blocked: no
>         Hard blocked: yes
> 	
> I do s2disk. After resume from suspend to disk (still disabled by button):
> root@gumis:/home/maciek/Desktop# rfkill list
> 2: hp-wifi: Wireless LAN
>         Soft blocked: yes
>         Hard blocked: no
> 3: hp-bluetooth: Bluetooth
>         Soft blocked: yes
>         Hard blocked: no
> 18: phy8: Wireless LAN
>         Soft blocked: no
>         Hard blocked: yes
> 	
> Try enable by button:
> root@gumis:/home/maciek/Desktop# rfkill list
> 2: hp-wifi: Wireless LAN
>         Soft blocked: yes
>         Hard blocked: no
> 3: hp-bluetooth: Bluetooth
>         Soft blocked: yes
>         Hard blocked: no
> 18: phy8: Wireless LAN
>         Soft blocked: no
>         Hard blocked: yes
> 	
> Nothing change (LED, wireless and bluetooth don't work). To enable it
> I use this script rfkill.sh (I must use rfkill program):
>
> #!/bin/sh
> PROGRAM=/usr/local/sbin/rfkill
> WIFI=`$PROGRAM list | grep -E 'Wireless|Bluetooth' | cut -d  ':' -f 1`
>
> for DEVICE in $WIFI; do
>   echo $DEVICE
>   $PROGRAM unblock $DEVICE
> done
>
> Then works OK:
> root@gumis:/home/maciek/Desktop# ./rfkill.sh
> 2
> 3
> 18
> root@gumis:/home/maciek/Desktop# rfkill list
> 2: hp-wifi: Wireless LAN
>         Soft blocked: no
>         Hard blocked: no
> 3: hp-bluetooth: Bluetooth
>         Soft blocked: no
>         Hard blocked: no
> 18: phy8: Wireless LAN
>         Soft blocked: no
>         Hard blocked: no
> 19: hci0: Bluetooth
>         Soft blocked: no
>         Hard blocked: no
> 	
> It's normal behaviour?
>   

That's a bug.  You're saying this is in -rc4, without applying my patch?

I think I know exactly what is happening.  Apply my patch, and it will 
go away :-).

I'm not sure this is a new bug though.  It might be triggered by the big 
rfkill rewrite, but I don't see how that could happen.  Can you confirm 
if this happens in 2.6.30?

Thanks
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
Frans Pop July 23, 2009, 7:28 p.m. UTC | #4
Alan Jenkins wrote:
> 1) Add support for reading the hardware blocked state.  Previously
> we read a combination of the hardware and software blocked states,
> reporting it as the software blocked state.  This caused some
> confusing behaviour.
> 
> 2) The software state is persistent, mark it as such.
> 
> 3) Check rfkill in the resume handler.  Both the hard and soft
> blocked states may change over hibernation.

I've added this to my local branch for .31 for my HP 2510p.
Light testing (linux only) showed no problems with .31-rc4.

One question: is it expected that pressing the hardware kill switch only 
enables the block for phy0? I guess it's probably sufficient.

$ ./rfkill list # after pressing hardware switch
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: yes
1: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
2: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no

Looks like with bluetooth soft-blocked the wireless leds blink on wifi 
network traffic, while with bluetooth unblocked it stays on permanently.

Cheers,
FJP
--
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
Maciej Rutecki July 23, 2009, 7:36 p.m. UTC | #5
2009/7/23 Alan Jenkins <alan-jenkins@tuffmail.co.uk>:

>
> That's a bug.  You're saying this is in -rc4, without applying my patch?

Yes

>
> I think I know exactly what is happening.  Apply my patch, and it will go
> away :-).

Yes. I add Your patch to -rc4 and rfkill works OK:
Enable by button:
root@gumis:/home/maciek# rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
1: hci0: Bluetooth
        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

Disable by button:
root@gumis:/home/maciek# rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: yes
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no

After resume from s2disk:
root@gumis:/home/maciek# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
4: phy1: Wireless LAN
        Soft blocked: no
        Hard blocked: yes

(are some differences after and before s2disk)

Enable by button:
root@gumis:/home/maciek# rfkill list
2: hp-wifi: Wireless LAN
        Soft blocked: no
        Hard blocked: no
3: hp-bluetooth: Bluetooth
        Soft blocked: no
        Hard blocked: no
4: phy1: Wireless LAN
        Soft blocked: no
        Hard blocked: no
5: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no

And wifi/bluetooth works without manual enable. Thanks.

>
> I'm not sure this is a new bug though.  It might be triggered by the big
> rfkill rewrite, but I don't see how that could happen.  Can you confirm if
> this happens in 2.6.30?

2.6.30 works OK

>
> Thanks
> Alan
>


Regards
diff mbox

Patch

diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index ca50856..adb26d3 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -51,6 +51,12 @@  MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 #define HPWMI_WIRELESS_QUERY 0x5
 #define HPWMI_HOTKEY_QUERY 0xc
 
+enum hp_wmi_radio {
+	HPWMI_WIFI = 0,
+	HPWMI_BLUETOOTH = 1,
+	HPWMI_WWAN = 2,
+};
+
 static int __init hp_wmi_bios_setup(struct platform_device *device);
 static int __exit hp_wmi_bios_remove(struct platform_device *device);
 static int hp_wmi_resume_handler(struct platform_device *device);
@@ -170,8 +176,8 @@  static int hp_wmi_tablet_state(void)
 
 static int hp_wmi_set_block(void *data, bool blocked)
 {
-	unsigned long b = (unsigned long) data;
-	int query = BIT(b + 8) | ((!blocked) << b);
+	enum hp_wmi_radio r = (enum hp_wmi_radio) data;
+	int query = BIT(r + 8) | ((!blocked) << r);
 
 	return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
 }
@@ -180,31 +186,23 @@  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_get_sw_state(enum hp_wmi_radio r)
 {
 	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
+	int mask = 0x200 << (r * 8);
 
-	if (wireless & 0x100)
+	if (wireless & mask)
 		return false;
 	else
 		return true;
 }
 
-static bool hp_wmi_bluetooth_state(void)
+static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
 {
 	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
+	int mask = 0x800 << (r * 8);
 
-	if (wireless & 0x10000)
-		return false;
-	else
-		return true;
-}
-
-static bool hp_wmi_wwan_state(void)
-{
-	int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
-
-	if (wireless & 0x1000000)
+	if (wireless & mask)
 		return false;
 	else
 		return true;
@@ -329,49 +327,55 @@  static void hp_wmi_notify(u32 value, void *context)
 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 	static struct key_entry *key;
 	union acpi_object *obj;
+	int eventcode;
 
 	wmi_get_event_data(value, &response);
 
 	obj = (union acpi_object *)response.pointer;
 
-	if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
-		int eventcode = *((u8 *) obj->buffer.pointer);
-		if (eventcode == 0x4)
-			eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
-							 0);
-		key = hp_wmi_get_entry_by_scancode(eventcode);
-		if (key) {
-			switch (key->type) {
-			case KE_KEY:
-				input_report_key(hp_wmi_input_dev,
-						 key->keycode, 1);
-				input_sync(hp_wmi_input_dev);
-				input_report_key(hp_wmi_input_dev,
-						 key->keycode, 0);
-				input_sync(hp_wmi_input_dev);
-				break;
-			}
-		} else if (eventcode == 0x1) {
-			input_report_switch(hp_wmi_input_dev, SW_DOCK,
-					    hp_wmi_dock_state());
-			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
-					    hp_wmi_tablet_state());
+	if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
+		printk(KERN_INFO "HP WMI: Unknown response received\n");
+		return;
+	}
+
+	eventcode = *((u8 *) obj->buffer.pointer);
+	if (eventcode == 0x4)
+		eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
+						0);
+	key = hp_wmi_get_entry_by_scancode(eventcode);
+	if (key) {
+		switch (key->type) {
+		case KE_KEY:
+			input_report_key(hp_wmi_input_dev,
+					 key->keycode, 1);
+			input_sync(hp_wmi_input_dev);
+			input_report_key(hp_wmi_input_dev,
+					 key->keycode, 0);
 			input_sync(hp_wmi_input_dev);
-		} else if (eventcode == 0x5) {
-			if (wifi_rfkill)
-				rfkill_set_sw_state(wifi_rfkill,
-						    hp_wmi_wifi_state());
-			if (bluetooth_rfkill)
-				rfkill_set_sw_state(bluetooth_rfkill,
-						    hp_wmi_bluetooth_state());
-			if (wwan_rfkill)
-				rfkill_set_sw_state(wwan_rfkill,
-						    hp_wmi_wwan_state());
-		} else
-			printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
-			       eventcode);
+			break;
+		}
+	} else if (eventcode == 0x1) {
+		input_report_switch(hp_wmi_input_dev, SW_DOCK,
+				    hp_wmi_dock_state());
+		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+				    hp_wmi_tablet_state());
+		input_sync(hp_wmi_input_dev);
+	} else if (eventcode == 0x5) {
+		if (wifi_rfkill)
+			rfkill_set_states(wifi_rfkill,
+					  hp_wmi_get_sw_state(HPWMI_WIFI),
+					  hp_wmi_get_hw_state(HPWMI_WIFI));
+		if (bluetooth_rfkill)
+			rfkill_set_states(bluetooth_rfkill,
+					  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
+					  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
+		if (wwan_rfkill)
+			rfkill_set_states(wwan_rfkill,
+					  hp_wmi_get_sw_state(HPWMI_WWAN),
+					  hp_wmi_get_hw_state(HPWMI_WWAN));
 	} else
-		printk(KERN_INFO "HP WMI: Unknown response received\n");
+		printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
+			eventcode);
 }
 
 static int __init hp_wmi_input_setup(void)
@@ -450,7 +454,11 @@  static int __init hp_wmi_bios_setup(struct platform_device *device)
 		wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
 					   RFKILL_TYPE_WLAN,
 					   &hp_wmi_rfkill_ops,
-					   (void *) 0);
+					   (void *) HPWMI_WIFI);
+		rfkill_init_sw_state(wifi_rfkill,
+				     hp_wmi_get_sw_state(HPWMI_WIFI));
+		rfkill_set_hw_state(wifi_rfkill,
+				    hp_wmi_get_hw_state(HPWMI_WIFI));
 		err = rfkill_register(wifi_rfkill);
 		if (err)
 			goto register_wifi_error;
@@ -460,7 +468,11 @@  static int __init hp_wmi_bios_setup(struct platform_device *device)
 		bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
 						RFKILL_TYPE_BLUETOOTH,
 						&hp_wmi_rfkill_ops,
-						(void *) 1);
+						(void *) HPWMI_BLUETOOTH);
+		rfkill_init_sw_state(bluetooth_rfkill,
+				     hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
+		rfkill_set_hw_state(bluetooth_rfkill,
+				    hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
 		err = rfkill_register(bluetooth_rfkill);
 		if (err)
 			goto register_bluetooth_error;
@@ -470,7 +482,11 @@  static int __init hp_wmi_bios_setup(struct platform_device *device)
 		wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
 					   RFKILL_TYPE_WWAN,
 					   &hp_wmi_rfkill_ops,
-					   (void *) 2);
+					   (void *) HPWMI_WWAN);
+		rfkill_init_sw_state(wwan_rfkill,
+				     hp_wmi_get_sw_state(HPWMI_WWAN));
+		rfkill_set_hw_state(wwan_rfkill,
+				    hp_wmi_get_hw_state(HPWMI_WWAN));
 		err = rfkill_register(wwan_rfkill);
 		if (err)
 			goto register_wwan_err;
@@ -526,6 +542,19 @@  static int hp_wmi_resume_handler(struct platform_device *device)
 			    hp_wmi_tablet_state());
 	input_sync(hp_wmi_input_dev);
 
+	if (wifi_rfkill)
+		rfkill_set_states(wifi_rfkill,
+				  hp_wmi_get_sw_state(HPWMI_WIFI),
+				  hp_wmi_get_hw_state(HPWMI_WIFI));
+	if (bluetooth_rfkill)
+		rfkill_set_states(bluetooth_rfkill,
+				  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
+				  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
+	if (wwan_rfkill)
+		rfkill_set_states(wwan_rfkill,
+				  hp_wmi_get_sw_state(HPWMI_WWAN),
+				  hp_wmi_get_hw_state(HPWMI_WWAN));
+
 	return 0;
 }