summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/asus-wireless.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-27 00:23:08 (GMT)
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-27 00:23:08 (GMT)
commit27b79027bc112a63ad4004eb83c6acacae08a0de (patch)
treeabce98b7d4598c6c212954a84cb3b41b7c33ddf3 /drivers/platform/x86/asus-wireless.c
parentf7e68169941a26cb1ad764d53ef13721e6fe439a (diff)
parent332e081225fc2a657aa587c42943d5f5a7dae88b (diff)
downloadlinux-27b79027bc112a63ad4004eb83c6acacae08a0de.tar.xz
Merge tag 'platform-drivers-x86-v4.8-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x8 platform driver updates from Darren Hart: "Several new quirks and tweaks for new platforms to existing laptop drivers. A new ACPI virtual power button driver, similar to the intel-hid driver. A rework of the dell keymap, using a single sparse keymap for all machines. A few fixes and cleanups. Summary: intel-vbtn: - new driver for Intel Virtual Button intel_pmc_core: - Convert to DEFINE_DEBUGFS_ATTRIBUTE fujitsu-laptop: - Rework brightness of eco led asus-wmi: - Add quirk_no_rfkill_wapf4 for the Asus X456UA - Add quirk_no_rfkill_wapf4 for the Asus X456UF - Add quirk_no_rfkill for the Asus Z550MA - Add quirk_no_rfkill for the Asus U303LB - Add quirk_no_rfkill for the Asus N552VW - Create quirk for airplane_mode LED - Add ambient light sensor toggle key asus-wireless: - Toggle airplane mode LED intel_telemetry: - Remove Monitor MWAIT feature dependency intel-hid: - Remove duplicated acpi_remove_notify_handler fujitsu-laptop: - Add support for eco LED - Support touchpad toggle hotkey on Skylake-based models - Remove unused macros - Use module name in debug messages hp-wmi: - Fix wifi cannot be hard-unblocked toshiba_acpi: - Bump driver version and update copyright year - Remove the position sysfs entry - Add IIO interface for accelerometer axis data dell-wmi: - Add a WMI event code for display on/off - Generate one sparse keymap for all machines - Add information about other WMI event codes - Sort WMI event codes and update comments - Ignore WMI event code 0xe045" * tag 'platform-drivers-x86-v4.8-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (26 commits) intel-vbtn: new driver for Intel Virtual Button intel_pmc_core: Convert to DEFINE_DEBUGFS_ATTRIBUTE fujitsu-laptop: Rework brightness of eco led asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UA asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF asus-wmi: Add quirk_no_rfkill for the Asus Z550MA asus-wmi: Add quirk_no_rfkill for the Asus U303LB asus-wmi: Add quirk_no_rfkill for the Asus N552VW asus-wmi: Create quirk for airplane_mode LED asus-wireless: Toggle airplane mode LED intel_telemetry: Remove Monitor MWAIT feature dependency intel-hid: Remove duplicated acpi_remove_notify_handler asus-wmi: Add ambient light sensor toggle key fujitsu-laptop: Add support for eco LED fujitsu-laptop: Support touchpad toggle hotkey on Skylake-based models fujitsu-laptop: Remove unused macros fujitsu-laptop: Use module name in debug messages hp-wmi: Fix wifi cannot be hard-unblocked toshiba_acpi: Bump driver version and update copyright year toshiba_acpi: Remove the position sysfs entry ...
Diffstat (limited to 'drivers/platform/x86/asus-wireless.c')
-rw-r--r--drivers/platform/x86/asus-wireless.c91
1 files changed, 90 insertions, 1 deletions
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 9ec721e..9f31bc1 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)
+{
+ struct acpi_object_list p;
+ union acpi_object obj;
+ 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;
}