Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1421317 > unrolled thread

[PATCH 0/7] asus-wireless: LED control

Started by"João Paulo Rechi Vita" <jprvita@gmail.com>
First post2016-06-13 23:00 +0200
Last post2016-06-19 09:20 +0200
Articles 4 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/7] asus-wireless: LED control "João Paulo Rechi Vita" <jprvita@gmail.com> - 2016-06-13 23:00 +0200
    [PATCH 4/7] asus-wmi: Add quirk_no_rfkill for the Asus U303LB "João Paulo Rechi Vita" <jprvita@gmail.com> - 2016-06-13 23:00 +0200
    [PATCH 1/7] asus-wireless: Toggle airplane mode LED "João Paulo Rechi Vita" <jprvita@gmail.com> - 2016-06-13 23:10 +0200
    Re: [PATCH 0/7] asus-wireless: LED control Corentin Chary <corentin.chary@gmail.com> - 2016-06-19 09:20 +0200

#1421317 — [PATCH 0/7] asus-wireless: LED control

From"João Paulo Rechi Vita" <jprvita@gmail.com>
Date2016-06-13 23:00 +0200
Subject[PATCH 0/7] asus-wireless: LED control
Message-ID<rJH7H-2Zc-3@gated-at.bofh.it>
This series adds support for controlling the airplane-mode indicator LED
present in some Asus laptops. It also creates a quirk in asus-wmi so it does not
create RFKill devices for platforms that use asus-wireless and where there is a
competition for the LED control (see "asus-wmi: Create quirk for airplane_mode
LED" for more details).

João Paulo Rechi Vita (7):
  asus-wireless: Toggle airplane mode LED
  asus-wmi: Create quirk for airplane_mode LED
  asus-wmi: Add quirk_no_rfkill for the Asus N552VW
  asus-wmi: Add quirk_no_rfkill for the Asus U303LB
  asus-wmi: Add quirk_no_rfkill for the Asus Z550MA
  asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF
  asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UA

 drivers/platform/x86/Kconfig         |  2 +
 drivers/platform/x86/asus-nb-wmi.c   | 49 ++++++++++++++++++-
 drivers/platform/x86/asus-wireless.c | 91 +++++++++++++++++++++++++++++++++++-
 drivers/platform/x86/asus-wmi.c      |  8 ++--
 drivers/platform/x86/asus-wmi.h      |  1 +
 5 files changed, 145 insertions(+), 6 deletions(-)

-- 
2.5.0

[toc] | [next] | [standalone]


#1421325 — [PATCH 4/7] asus-wmi: Add quirk_no_rfkill for the Asus U303LB

From"João Paulo Rechi Vita" <jprvita@gmail.com>
Date2016-06-13 23:00 +0200
Subject[PATCH 4/7] asus-wmi: Add quirk_no_rfkill for the Asus U303LB
Message-ID<rJH7J-2Zc-51@gated-at.bofh.it>
In reply to#1421317
The Asus U303LB has an airplane-mode indicator LED and the WMI WLAN user
bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store
the wlan state, which has a side-effect of driving the airplane mode
indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi
from registering RFKill switches at all for this laptop and allows
asus-wireless to drive the LED through the ASHS ACPI device.

Signed-off-by: João Paulo Rechi Vita <jprvita@endlessm.com>
Reported-by: Mousou Yuu <guogaishiwo@gmail.com>
---
 drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 31fcde1..efae467 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -328,6 +328,15 @@ static const struct dmi_system_id asus_quirks[] = {
 		},
 		.driver_data = &quirk_no_rfkill,
 	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK COMPUTER INC. U303LB",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "U303LB"),
+		},
+		.driver_data = &quirk_no_rfkill,
+	},
 	{},
 };
 
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1421331 — [PATCH 1/7] asus-wireless: Toggle airplane mode LED

From"João Paulo Rechi Vita" <jprvita@gmail.com>
Date2016-06-13 23:10 +0200
Subject[PATCH 1/7] asus-wireless: Toggle airplane mode LED
Message-ID<rJHho-3ij-37@gated-at.bofh.it>
In reply to#1421317
In the ASHS device we have the HSWC method, which calls either OWGD or
OWGS, depending on its parameter:

	Device (ASHS)
	{
		Name (_HID, "ATK4002")  // _HID: Hardware ID
		Method (HSWC, 1, Serialized)
		{
			If ((Arg0 < 0x02))
			{
				OWGD (Arg0)
				Return (One)
			}
			If ((Arg0 == 0x02))
			{
				Local0 = OWGS ()
				If (Local0)
				{
					Return (0x05)
				}
				Else
				{
					Return (0x04)
				}
			}
			If ((Arg0 == 0x03))
			{
				Return (0xFF)
			}
			If ((Arg0 == 0x04))
			{
				OWGD (Zero)
				Return (One)
			}
			If ((Arg0 == 0x05))
			{
				OWGD (One)
				Return (One)
			}
			If ((Arg0 == 0x80))
			{
				Return (One)
			}
		}
		Method (_STA, 0, NotSerialized)  // _STA: Status
		{
			If ((MSOS () >= OSW8))
			{
				Return (0x0F)
			}
			Else
			{
				Return (Zero)
			}
		}
	}

On the Asus laptops that does not have an airplane mode LED, OWGD has an
empty implementation and OWGS simply returns 0. On the ones that have an
airplane mode LED these methods have the following implementation:

	Method (OWGD, 1, Serialized)
	{
		SGPL (0x0203000F, Arg0)
		SGPL (0x0203000F, Arg0)
	}

	Method (OWGS, 0, Serialized)
	{
		Store (RGPL (0x0203000F), Local0)
		Return (Local0)
	}

Where OWGD(1) sets the airplane mode LED ON, OWGD(0) set it off, and
OWGS() returns its state.

This commit exposes the airplane mode indicator LED to userspace under
the name asus-wireless::airplane, so it can be driven according to
userspace's policy.

Signed-off-by: João Paulo Rechi Vita <jprvita@endlessm.com>
---
 drivers/platform/x86/Kconfig         |  2 +
 drivers/platform/x86/asus-wireless.c | 91 +++++++++++++++++++++++++++++++++++-
 2 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index c06bb85..e9d0144 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -604,6 +604,8 @@ config ASUS_WIRELESS
 	tristate "Asus Wireless Radio Control Driver"
 	depends on ACPI
 	depends on INPUT
+	select NEW_LEDS
+	select LEDS_CLASS
 	---help---
 	  The Asus Wireless Radio Control handles the airplane mode hotkey
 	  present on some Asus laptops.
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 9ec721e..d617dfd 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -15,11 +15,78 @@
 #include <linux/acpi.h>
 #include <linux/input.h>
 #include <linux/pci_ids.h>
+#include <linux/leds.h>
+
+#define ASUS_WIRELESS_LED_STATUS 0x2
+#define ASUS_WIRELESS_LED_OFF 0x4
+#define ASUS_WIRELESS_LED_ON 0x5
 
 struct asus_wireless_data {
 	struct input_dev *idev;
+	struct acpi_device *adev;
+	struct workqueue_struct *wq;
+	struct work_struct led_work;
+	struct led_classdev led;
+	int led_state;
 };
 
+static u64 asus_wireless_method(acpi_handle handle, const char *method,
+				int param)
+{
+	union acpi_object obj;
+	struct acpi_object_list p;
+	acpi_status s;
+	u64 ret;
+
+	acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n",
+			  method, param);
+	obj.type = ACPI_TYPE_INTEGER;
+	obj.integer.value = param;
+	p.count = 1;
+	p.pointer = &obj;
+
+	s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret);
+	if (ACPI_FAILURE(s))
+		acpi_handle_err(handle,
+				"Failed to eval method %s, param %#x (%d)\n",
+				method, param, s);
+	acpi_handle_debug(handle, "%s returned %#x\n", method, (uint) ret);
+	return ret;
+}
+
+static enum led_brightness led_state_get(struct led_classdev *led)
+{
+	struct asus_wireless_data *data;
+	int s;
+
+	data = container_of(led, struct asus_wireless_data, led);
+	s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
+				 ASUS_WIRELESS_LED_STATUS);
+	if (s == ASUS_WIRELESS_LED_ON)
+		return LED_FULL;
+	return LED_OFF;
+}
+
+static void led_state_update(struct work_struct *work)
+{
+	struct asus_wireless_data *data;
+
+	data = container_of(work, struct asus_wireless_data, led_work);
+	asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
+			     data->led_state);
+}
+
+static void led_state_set(struct led_classdev *led,
+				  enum led_brightness value)
+{
+	struct asus_wireless_data *data;
+
+	data = container_of(led, struct asus_wireless_data, led);
+	data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF :
+					     ASUS_WIRELESS_LED_ON;
+	queue_work(data->wq, &data->led_work);
+}
+
 static void asus_wireless_notify(struct acpi_device *adev, u32 event)
 {
 	struct asus_wireless_data *data = acpi_driver_data(adev);
@@ -37,6 +104,7 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event)
 static int asus_wireless_add(struct acpi_device *adev)
 {
 	struct asus_wireless_data *data;
+	int err;
 
 	data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -52,11 +120,32 @@ static int asus_wireless_add(struct acpi_device *adev)
 	data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK;
 	set_bit(EV_KEY, data->idev->evbit);
 	set_bit(KEY_RFKILL, data->idev->keybit);
-	return input_register_device(data->idev);
+	err = input_register_device(data->idev);
+	if (err)
+		return err;
+
+	data->adev = adev;
+	data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
+	if (!data->wq)
+		return -ENOMEM;
+	INIT_WORK(&data->led_work, led_state_update);
+	data->led.name = "asus-wireless::airplane";
+	data->led.brightness_set = led_state_set;
+	data->led.brightness_get = led_state_get;
+	data->led.flags = LED_CORE_SUSPENDRESUME;
+	data->led.max_brightness = 1;
+	err = devm_led_classdev_register(&adev->dev, &data->led);
+	if (err)
+		destroy_workqueue(data->wq);
+	return err;
 }
 
 static int asus_wireless_remove(struct acpi_device *adev)
 {
+	struct asus_wireless_data *data = acpi_driver_data(adev);
+
+	if (data->wq)
+		destroy_workqueue(data->wq);
 	return 0;
 }
 
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1425944

FromCorentin Chary <corentin.chary@gmail.com>
Date2016-06-19 09:20 +0200
Message-ID<rLFbr-7ts-9@gated-at.bofh.it>
In reply to#1421317
On Mon, Jun 13, 2016 at 10:57 PM, João Paulo Rechi Vita
<jprvita@gmail.com> wrote:
> This series adds support for controlling the airplane-mode indicator LED
> present in some Asus laptops. It also creates a quirk in asus-wmi so it does not
> create RFKill devices for platforms that use asus-wireless and where there is a
> competition for the LED control (see "asus-wmi: Create quirk for airplane_mode
> LED" for more details).
>
> João Paulo Rechi Vita (7):
>   asus-wireless: Toggle airplane mode LED
>   asus-wmi: Create quirk for airplane_mode LED
>   asus-wmi: Add quirk_no_rfkill for the Asus N552VW
>   asus-wmi: Add quirk_no_rfkill for the Asus U303LB
>   asus-wmi: Add quirk_no_rfkill for the Asus Z550MA
>   asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF
>   asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UA
>
>  drivers/platform/x86/Kconfig         |  2 +
>  drivers/platform/x86/asus-nb-wmi.c   | 49 ++++++++++++++++++-
>  drivers/platform/x86/asus-wireless.c | 91 +++++++++++++++++++++++++++++++++++-
>  drivers/platform/x86/asus-wmi.c      |  8 ++--
>  drivers/platform/x86/asus-wmi.h      |  1 +
>  5 files changed, 145 insertions(+), 6 deletions(-)
>
> --
> 2.5.0
>

Looks good to me. I hope that we can get rid of all these quirks in
the near future.

Reviewed-by: Corentin Chary <corentin.chary@gmail.com>

-- 
Corentin Chary
http://xf.iksaif.net

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web