asus-wmi: record wlan status while controlled by userapp
authorAceLan Kao <acelan.kao@canonical.com>
Thu, 26 Jul 2012 09:13:31 +0000 (17:13 +0800)
committerMatthew Garrett <mjg@redhat.com>
Fri, 17 Aug 2012 21:34:39 +0000 (17:34 -0400)
If the user bit is set, that mean BIOS can't set and record the wlan
status, it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
(0x00010012) while we query the wlan status by id ASUS_WMI_DEVID_WLAN
(0x00010011) through WMI.
So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
(0x00010012) while setting the wlan status through WMI.
This is also the behavior that windows app will do.

Quote from ASUS application engineer
===
When you call WMIMethod(DSTS, 0x00010011) to get WLAN status, it may return

(1) 0x00050001 (On)
(2) 0x00050000 (Off)
(3) 0x00030001 (On)
(4) 0x00030000 (Off)
(5) 0x00000002 (Unknown)

(1), (2) means that the model has hardware GPIO for WLAN, you can call
WMIMethod(DEVS, 0x00010011, 1 or 0) to turn WLAN on/off.
(3), (4) means that the model doesn’t have hardware GPIO, you need to use
API or driver library to turn WLAN on/off, and call
WMIMethod(DEVS, 0x00010012, 1 or 0) to set WLAN LED status.
After you set WLAN LED status, you can see the WLAN status is changed with
WMIMethod(DSTS, 0x00010011). Because the status is recorded lastly
(ex: Windows), you can use it for synchronization.
(5) means that the model doesn’t have WLAN device.

WLAN is the ONLY special case with upper rule.

For other device, like Bluetooth, you just need use
WMIMethod(DSTS, 0x00010013) to get, and WMIMethod(DEVS, 0x00010013, 1 or 0)
to set.
===

Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h

index c7a36f6b058048eb092717eff06a9e413a6a2546..2eb9fe8e8efd038c7bb1d25ad4fbde2961ca8e1a 100644 (file)
@@ -101,6 +101,7 @@ MODULE_LICENSE("GPL");
 #define ASUS_WMI_DEVID_WIRELESS_LED    0x00010002
 #define ASUS_WMI_DEVID_CWAP            0x00010003
 #define ASUS_WMI_DEVID_WLAN            0x00010011
+#define ASUS_WMI_DEVID_WLAN_LED                0x00010012
 #define ASUS_WMI_DEVID_BLUETOOTH       0x00010013
 #define ASUS_WMI_DEVID_GPS             0x00010015
 #define ASUS_WMI_DEVID_WIMAX           0x00010017
@@ -731,8 +732,21 @@ static int asus_rfkill_set(void *data, bool blocked)
 {
        struct asus_rfkill *priv = data;
        u32 ctrl_param = !blocked;
+       u32 dev_id = priv->dev_id;
 
-       return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL);
+       /*
+        * If the user bit is set, BIOS can't set and record the wlan status,
+        * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
+        * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN).
+        * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
+        * while setting the wlan status through WMI.
+        * This is also the behavior that windows app will do.
+        */
+       if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
+            priv->asus->driver->wlan_ctrl_by_user)
+               dev_id = ASUS_WMI_DEVID_WLAN_LED;
+
+       return asus_wmi_set_devstate(dev_id, ctrl_param, NULL);
 }
 
 static void asus_rfkill_query(struct rfkill *rfkill, void *data)
@@ -1653,6 +1667,7 @@ static int asus_wmi_add(struct platform_device *pdev)
        struct asus_wmi *asus;
        acpi_status status;
        int err;
+       u32 result;
 
        asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
        if (!asus)
@@ -1711,6 +1726,10 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_debugfs;
 
+       asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
+       if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
+               asus->driver->wlan_ctrl_by_user = 1;
+
        return 0;
 
 fail_debugfs:
index 9c1da8b81bea50f9007eac48f82da8f0bb29a73d..4c9bd38bb0a26141c27ceca8749358cf60da1cfb 100644 (file)
@@ -46,6 +46,7 @@ struct quirk_entry {
 struct asus_wmi_driver {
        int                     brightness;
        int                     panel_power;
+       int                     wlan_ctrl_by_user;
 
        const char              *name;
        struct module           *owner;