Re: [PATCH 4/4] asus-wireless: Toggle airplane mode LED

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 27 December 2015 at 08:32, Andy Shevchenko <andy.shevchenko@xxxxxxxxx> wrote:
> On Sat, Dec 26, 2015 at 4:56 PM, João Paulo Rechi Vita
> <jprvita@xxxxxxxxx> wrote:
>> In the ASHS device we have the HSWC method, which basically 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 E202SA laptop, which does not have an airplane mode LED,
>> OWGD has an empty implementation and OWGS simply returns 0. On the Asus
>> X555UB 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 makes use of a newly implemented RFKill LED trigger to
>> trigger the LED when the system enters or exits "Airplane Mode", there
>> is, when all radios are blocked.
>>
>> Signed-off-by: João Paulo Rechi Vita <jprvita@xxxxxxxxxxxx>
>> ---
>>  drivers/platform/x86/Kconfig         |  2 +
>>  drivers/platform/x86/asus-wireless.c | 81 ++++++++++++++++++++++++++++++++++++
>>  2 files changed, 83 insertions(+)
>>
>> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
>> index d3a088b..3d8dc0b 100644
>> --- a/drivers/platform/x86/Kconfig
>> +++ b/drivers/platform/x86/Kconfig
>> @@ -592,6 +592,8 @@ config ASUS_WIRELESS
>>         depends on ACPI
>>         depends on INPUT
>>         default m
>> +       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 7928efd..489ef83 100644
>> --- a/drivers/platform/x86/asus-wireless.c
>> +++ b/drivers/platform/x86/asus-wireless.c
>> @@ -17,13 +17,76 @@
>>  #include <linux/acpi.h>
>>  #include <linux/input.h>
>>  #include <linux/pci_ids.h>
>> +#include <linux/leds.h>
>>
>>  #define ASUS_WIRELESS_MODULE_NAME "Asus Wireless Radio Control Driver"
>> +#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 *inputdev;
>> +       struct acpi_device *acpidev;
>
> You can get this easily from struct device.
>

If I'm understanding it correctly that only works when the acpi device
is a companion to a physical device, which is not the case here
(ACPI_COMPANION(acpi_device->dev)==NULL). I'm keeping this for now,
please let me know if I'm missing something.

>> +       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;
>> +
>> +       pr_debug("Evaluating method %s, parameter 0x%X\n", method, param);
>
> acpi_handle_* in such cases.
>

Ok.

>> +       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_SUCCESS(s))
>
> ACPI_FAILURE()
>

Ok.

>> +               pr_err("Failed to evaluate method %s, parameter 0x%X (%d)\n",
>> +                      method, param, s);
>> +       pr_debug("%s returned 0x%X\n", method, (uint) ret);
>> +       return ret;
>> +}
>> +
>> +static enum led_brightness asus_wireless_led_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(data->acpidev->handle, "HSWC",
>
> Usually we get a handle through specific macro ACPI_HANDLE from a
> struct device (see above).
>
>> +                                ASUS_WIRELESS_LED_STATUS);
>> +       if (s == ASUS_WIRELESS_LED_ON)
>> +               return LED_FULL;
>> +       return LED_OFF;
>> +}
>> +
>> +static void asus_wireless_led_update(struct work_struct *work)
>> +{
>> +       struct asus_wireless_data *data;
>> +
>> +       data = container_of(work, struct asus_wireless_data, led_work);
>> +       asus_wireless_method(data->acpidev->handle, "HSWC", data->led_state);
>
> Ditto.
>

These last two depend on ACPI_COMPANION as well. I'm changing this to
call acpi_device_handle() instead of accessing the pointer directly.

I will send an updated version shortly. Thanks again for your feedback.

--
João Paulo Rechi Vita
http://about.me/jprvita
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux