From e636c8d336489bf3eed5878299e6cc045bbad077 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:17:29 +0000
Subject: [PATCH] debug lk
---
kernel/drivers/platform/x86/asus-wmi.c | 1449 +++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 931 insertions(+), 518 deletions(-)
diff --git a/kernel/drivers/platform/x86/asus-wmi.c b/kernel/drivers/platform/x86/asus-wmi.c
index 339b753..db369cf 100644
--- a/kernel/drivers/platform/x86/asus-wmi.c
+++ b/kernel/drivers/platform/x86/asus-wmi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Asus PC WMI hotkey driver
*
@@ -8,20 +9,6 @@
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -39,14 +26,18 @@
#include <linux/rfkill.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/power_supply.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/platform_data/x86/asus-wmi.h>
#include <linux/platform_device.h>
-#include <linux/thermal.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
+#include <linux/units.h>
+
+#include <acpi/battery.h>
#include <acpi/video.h>
#include "asus-wmi.h"
@@ -65,102 +56,50 @@
#define NOTIFY_BRNUP_MAX 0x1f
#define NOTIFY_BRNDOWN_MIN 0x20
#define NOTIFY_BRNDOWN_MAX 0x2e
+#define NOTIFY_FNLOCK_TOGGLE 0x4e
+#define NOTIFY_KBD_DOCK_CHANGE 0x75
#define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7
+#define NOTIFY_KBD_FBM 0x99
+#define NOTIFY_KBD_TTP 0xae
-/* WMI Methods */
-#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
-#define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */
-#define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */
-#define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */
-#define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */
-#define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */
-#define ASUS_WMI_METHODID_AGFN 0x4E464741 /* FaN? */
-#define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */
-#define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */
-#define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */
-#define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */
-#define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */
-#define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */
-#define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/
-#define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */
-#define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */
-#define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */
-#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */
-#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
-#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
-
-#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
-
-/* Wireless */
-#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
-#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
-#define ASUS_WMI_DEVID_WWAN3G 0x00010019
-#define ASUS_WMI_DEVID_UWB 0x00010021
-
-/* Leds */
-/* 0x000200XX and 0x000400XX */
-#define ASUS_WMI_DEVID_LED1 0x00020011
-#define ASUS_WMI_DEVID_LED2 0x00020012
-#define ASUS_WMI_DEVID_LED3 0x00020013
-#define ASUS_WMI_DEVID_LED4 0x00020014
-#define ASUS_WMI_DEVID_LED5 0x00020015
-#define ASUS_WMI_DEVID_LED6 0x00020016
-
-/* Backlight and Brightness */
-#define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */
-#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
-#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
-#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
-#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
-#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
-
-/* Misc */
-#define ASUS_WMI_DEVID_CAMERA 0x00060013
-
-/* Storage */
-#define ASUS_WMI_DEVID_CARDREADER 0x00080013
-
-/* Input */
-#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
-#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
-
-/* Fan, Thermal */
-#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
-#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
-
-/* Power */
-#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
-
-/* Deep S3 / Resume on LID open */
-#define ASUS_WMI_DEVID_LID_RESUME 0x00120031
-
-/* DSTS masks */
-#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
-#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
-#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
-#define ASUS_WMI_DSTS_USER_BIT 0x00020000
-#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
-#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
-#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
-#define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F
+#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
#define ASUS_FAN_DESC "cpu_fan"
#define ASUS_FAN_MFUN 0x13
#define ASUS_FAN_SFUN_READ 0x06
#define ASUS_FAN_SFUN_WRITE 0x07
+
+/* Based on standard hwmon pwmX_enable values */
+#define ASUS_FAN_CTRL_FULLSPEED 0
#define ASUS_FAN_CTRL_MANUAL 1
#define ASUS_FAN_CTRL_AUTO 2
+#define ASUS_FAN_BOOST_MODE_NORMAL 0
+#define ASUS_FAN_BOOST_MODE_OVERBOOST 1
+#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK 0x01
+#define ASUS_FAN_BOOST_MODE_SILENT 2
+#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
+#define ASUS_FAN_BOOST_MODES_MASK 0x03
+
+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0
+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
+
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
+
+#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
+#define ASUS_ACPI_UID_ATK "ATK"
+
+#define WMI_EVENT_QUEUE_SIZE 0x10
+#define WMI_EVENT_QUEUE_END 0x1
+#define WMI_EVENT_MASK 0xFFFF
+/* The WMI hotkey event value is always the same. */
+#define WMI_EVENT_VALUE_ATK 0xFF
+
+#define WMI_EVENT_MASK 0xFFFF
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
@@ -177,6 +116,9 @@
struct bios_args {
u32 arg0;
u32 arg1;
+ u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */
+ u32 arg4;
+ u32 arg5;
} __packed;
/*
@@ -192,7 +134,7 @@
} __packed;
/* struct used for calling fan read and write methods */
-struct fan_args {
+struct agfn_fan_args {
struct agfn_args agfn; /* common fields */
u8 fan; /* fan number: 0: set auto mode 1: 1st fan */
u32 speed; /* read: RPM/100 - write: 0-255 */
@@ -220,10 +162,17 @@
u32 dev_id;
};
+enum fan_type {
+ FAN_TYPE_NONE = 0,
+ FAN_TYPE_AGFN, /* deprecated on newer platforms */
+ FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */
+};
+
struct asus_wmi {
int dsts_id;
int spec;
int sfun;
+ bool wmi_event_queue;
struct input_dev *inputdev;
struct backlight_device *backlight_device;
@@ -239,7 +188,6 @@
int lightbar_led_wk;
struct workqueue_struct *led_workqueue;
struct work_struct tpd_led_work;
- struct work_struct kbd_led_work;
struct work_struct wlan_led_work;
struct work_struct lightbar_led_work;
@@ -250,64 +198,42 @@
struct asus_rfkill gps;
struct asus_rfkill uwb;
- bool asus_hwmon_fan_manual_mode;
- int asus_hwmon_num_fans;
- int asus_hwmon_pwm;
+ enum fan_type fan_type;
+ int fan_pwm_mode;
+ int agfn_pwm;
- struct hotplug_slot *hotplug_slot;
+ bool fan_boost_mode_available;
+ u8 fan_boost_mode_mask;
+ u8 fan_boost_mode;
+
+ bool throttle_thermal_policy_available;
+ u8 throttle_thermal_policy_mode;
+
+ // The RSOC controls the maximum charging percentage.
+ bool battery_rsoc_available;
+
+ struct hotplug_slot hotplug_slot;
struct mutex hotplug_lock;
struct mutex wmi_lock;
struct workqueue_struct *hotplug_workqueue;
struct work_struct hotplug_work;
+
+ bool fnlock_locked;
struct asus_wmi_debug debug;
struct asus_wmi_driver *driver;
};
-static int asus_wmi_input_init(struct asus_wmi *asus)
-{
- int err;
+/* WMI ************************************************************************/
- asus->inputdev = input_allocate_device();
- if (!asus->inputdev)
- return -ENOMEM;
-
- asus->inputdev->name = asus->driver->input_name;
- asus->inputdev->phys = asus->driver->input_phys;
- asus->inputdev->id.bustype = BUS_HOST;
- asus->inputdev->dev.parent = &asus->platform_device->dev;
- set_bit(EV_REP, asus->inputdev->evbit);
-
- err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
- if (err)
- goto err_free_dev;
-
- err = input_register_device(asus->inputdev);
- if (err)
- goto err_free_dev;
-
- return 0;
-
-err_free_dev:
- input_free_device(asus->inputdev);
- return err;
-}
-
-static void asus_wmi_input_exit(struct asus_wmi *asus)
-{
- if (asus->inputdev)
- input_unregister_device(asus->inputdev);
-
- asus->inputdev = NULL;
-}
-
-static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
- u32 *retval)
+static int asus_wmi_evaluate_method3(u32 method_id,
+ u32 arg0, u32 arg1, u32 arg2, u32 *retval)
{
struct bios_args args = {
.arg0 = arg0,
.arg1 = arg1,
+ .arg2 = arg2,
};
struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -319,7 +245,7 @@
&input, &output);
if (ACPI_FAILURE(status))
- goto exit;
+ return -EIO;
obj = (union acpi_object *)output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
@@ -330,33 +256,34 @@
kfree(obj);
-exit:
- if (ACPI_FAILURE(status))
- return -EIO;
-
if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
return -ENODEV;
return 0;
}
+int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
+{
+ return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
+}
+EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
+
static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args)
{
struct acpi_buffer input;
u64 phys_addr;
u32 retval;
- u32 status = -1;
+ u32 status;
/*
* Copy to dma capable address otherwise memory corruption occurs as
* bios has to be able to access it.
*/
- input.pointer = kzalloc(args.length, GFP_DMA | GFP_KERNEL);
+ input.pointer = kmemdup(args.pointer, args.length, GFP_DMA | GFP_KERNEL);
input.length = args.length;
if (!input.pointer)
return -ENOMEM;
phys_addr = virt_to_phys(input.pointer);
- memcpy(input.pointer, args.pointer, args.length);
status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_AGFN,
phys_addr, 0, &retval);
@@ -390,7 +317,6 @@
int err;
err = asus_wmi_get_devstate(asus, dev_id, &retval);
-
if (err < 0)
return err;
@@ -411,9 +337,161 @@
ASUS_WMI_DSTS_STATUS_BIT);
}
-/*
- * LEDs
- */
+static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
+{
+ u32 retval;
+ int status = asus_wmi_get_devstate(asus, dev_id, &retval);
+
+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
+}
+
+/* Input **********************************************************************/
+
+static int asus_wmi_input_init(struct asus_wmi *asus)
+{
+ int err, result;
+
+ asus->inputdev = input_allocate_device();
+ if (!asus->inputdev)
+ return -ENOMEM;
+
+ asus->inputdev->name = asus->driver->input_name;
+ asus->inputdev->phys = asus->driver->input_phys;
+ asus->inputdev->id.bustype = BUS_HOST;
+ asus->inputdev->dev.parent = &asus->platform_device->dev;
+ set_bit(EV_REP, asus->inputdev->evbit);
+
+ err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
+ if (err)
+ goto err_free_dev;
+
+ if (asus->driver->quirks->use_kbd_dock_devid) {
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
+ if (result >= 0) {
+ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
+ } else if (result != -ENODEV) {
+ pr_err("Error checking for keyboard-dock: %d\n", result);
+ }
+ }
+
+ err = input_register_device(asus->inputdev);
+ if (err)
+ goto err_free_dev;
+
+ return 0;
+
+err_free_dev:
+ input_free_device(asus->inputdev);
+ return err;
+}
+
+static void asus_wmi_input_exit(struct asus_wmi *asus)
+{
+ if (asus->inputdev)
+ input_unregister_device(asus->inputdev);
+
+ asus->inputdev = NULL;
+}
+
+/* Battery ********************************************************************/
+
+/* The battery maximum charging percentage */
+static int charge_end_threshold;
+
+static ssize_t charge_control_end_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value, ret, rv;
+
+ ret = kstrtouint(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ if (value < 0 || value > 100)
+ return -EINVAL;
+
+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, value, &rv);
+ if (ret)
+ return ret;
+
+ if (rv != 1)
+ return -EIO;
+
+ /* There isn't any method in the DSDT to read the threshold, so we
+ * save the threshold.
+ */
+ charge_end_threshold = value;
+ return count;
+}
+
+static ssize_t charge_control_end_threshold_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", charge_end_threshold);
+}
+
+static DEVICE_ATTR_RW(charge_control_end_threshold);
+
+static int asus_wmi_battery_add(struct power_supply *battery)
+{
+ /* The WMI method does not provide a way to specific a battery, so we
+ * just assume it is the first battery.
+ * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
+ * battery is named BATT.
+ */
+ if (strcmp(battery->desc->name, "BAT0") != 0 &&
+ strcmp(battery->desc->name, "BAT1") != 0 &&
+ strcmp(battery->desc->name, "BATC") != 0 &&
+ strcmp(battery->desc->name, "BATT") != 0)
+ return -ENODEV;
+
+ if (device_create_file(&battery->dev,
+ &dev_attr_charge_control_end_threshold))
+ return -ENODEV;
+
+ /* The charge threshold is only reset when the system is power cycled,
+ * and we can't get the current threshold so let set it to 100% when
+ * a battery is added.
+ */
+ asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
+ charge_end_threshold = 100;
+
+ return 0;
+}
+
+static int asus_wmi_battery_remove(struct power_supply *battery)
+{
+ device_remove_file(&battery->dev,
+ &dev_attr_charge_control_end_threshold);
+ return 0;
+}
+
+static struct acpi_battery_hook battery_hook = {
+ .add_battery = asus_wmi_battery_add,
+ .remove_battery = asus_wmi_battery_remove,
+ .name = "ASUS Battery Extension",
+};
+
+static void asus_wmi_battery_init(struct asus_wmi *asus)
+{
+ asus->battery_rsoc_available = false;
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) {
+ asus->battery_rsoc_available = true;
+ battery_hook_register(&battery_hook);
+ }
+}
+
+static void asus_wmi_battery_exit(struct asus_wmi *asus)
+{
+ if (asus->battery_rsoc_available)
+ battery_hook_unregister(&battery_hook);
+}
+
+/* LEDs ***********************************************************************/
+
/*
* These functions actually update the LED's, and are called from a
* workqueue. By doing this as separate work rather than when the LED
@@ -456,16 +534,12 @@
return read_tpd_led_state(asus);
}
-static void kbd_led_update(struct work_struct *work)
+static void kbd_led_update(struct asus_wmi *asus)
{
int ctrl_param = 0;
- struct asus_wmi *asus;
-
- asus = container_of(work, struct asus_wmi, kbd_led_work);
ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
- led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk);
}
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
@@ -485,15 +559,14 @@
if (retval == 0x8000)
retval = 0;
- if (retval >= 0) {
- if (level)
- *level = retval & 0x7F;
- if (env)
- *env = (retval >> 8) & 0x7F;
- retval = 0;
- }
+ if (retval < 0)
+ return retval;
- return retval;
+ if (level)
+ *level = retval & 0x7F;
+ if (env)
+ *env = (retval >> 8) & 0x7F;
+ return 0;
}
static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
@@ -504,19 +577,26 @@
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
max_level = asus->kbd_led.max_brightness;
- if (value > max_level)
- value = max_level;
- else if (value < 0)
- value = 0;
-
- asus->kbd_led_wk = value;
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ asus->kbd_led_wk = clamp_val(value, 0, max_level);
+ kbd_led_update(asus);
}
static void kbd_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
+ /* Prevent disabling keyboard backlight on module unregister */
+ if (led_cdev->flags & LED_UNREGISTERING)
+ return;
+
do_kbd_led_set(led_cdev, value);
+}
+
+static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
+{
+ struct led_classdev *led_cdev = &asus->kbd_led;
+
+ do_kbd_led_set(led_cdev, value);
+ led_classdev_notify_brightness_hw_changed(led_cdev, asus->kbd_led_wk);
}
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
@@ -527,7 +607,6 @@
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
retval = kbd_led_read(asus, &value, NULL);
-
if (retval < 0)
return retval;
@@ -541,15 +620,6 @@
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
return result & ASUS_WMI_DSTS_UNKNOWN_BIT;
-}
-
-static int wlan_led_presence(struct asus_wmi *asus)
-{
- u32 result;
-
- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
-
- return result & ASUS_WMI_DSTS_PRESENCE_BIT;
}
static void wlan_led_update(struct work_struct *work)
@@ -618,25 +688,13 @@
return result & ASUS_WMI_DSTS_LIGHTBAR_MASK;
}
-static int lightbar_led_presence(struct asus_wmi *asus)
-{
- u32 result;
-
- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
-
- return result & ASUS_WMI_DSTS_PRESENCE_BIT;
-}
-
static void asus_wmi_led_exit(struct asus_wmi *asus)
{
- if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
- led_classdev_unregister(&asus->kbd_led);
- if (!IS_ERR_OR_NULL(asus->tpd_led.dev))
- led_classdev_unregister(&asus->tpd_led);
- if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
- led_classdev_unregister(&asus->wlan_led);
- if (!IS_ERR_OR_NULL(asus->lightbar_led.dev))
- led_classdev_unregister(&asus->lightbar_led);
+ led_classdev_unregister(&asus->kbd_led);
+ led_classdev_unregister(&asus->tpd_led);
+ led_classdev_unregister(&asus->wlan_led);
+ led_classdev_unregister(&asus->lightbar_led);
+
if (asus->led_workqueue)
destroy_workqueue(asus->led_workqueue);
}
@@ -663,10 +721,7 @@
goto error;
}
- led_val = kbd_led_read(asus, NULL, NULL);
- if (led_val >= 0) {
- INIT_WORK(&asus->kbd_led_work, kbd_led_update);
-
+ if (!kbd_led_read(asus, &led_val, NULL)) {
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
@@ -680,7 +735,8 @@
goto error;
}
- if (wlan_led_presence(asus) && (asus->driver->quirks->wapf > 0)) {
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED)
+ && (asus->driver->quirks->wapf > 0)) {
INIT_WORK(&asus->wlan_led_work, wlan_led_update);
asus->wlan_led.name = "asus::wlan";
@@ -697,7 +753,7 @@
goto error;
}
- if (lightbar_led_presence(asus)) {
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_LIGHTBAR)) {
INIT_WORK(&asus->lightbar_led_work, lightbar_led_update);
asus->lightbar_led.name = "asus::lightbar";
@@ -716,6 +772,7 @@
return rv;
}
+/* RF *************************************************************************/
/*
* PCI hotplug (for wlan rfkill)
@@ -747,7 +804,7 @@
if (asus->wlan.rfkill)
rfkill_set_sw_state(asus->wlan.rfkill, blocked);
- if (asus->hotplug_slot) {
+ if (asus->hotplug_slot.ops) {
bus = pci_find_bus(0, 1);
if (!bus) {
pr_warn("Unable to find PCI bus 1?\n");
@@ -819,15 +876,13 @@
acpi_handle handle;
status = acpi_get_handle(NULL, node, &handle);
-
- if (ACPI_SUCCESS(status)) {
- status = acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- asus_rfkill_notify, asus);
- if (ACPI_FAILURE(status))
- pr_warn("Failed to register notify on %s\n", node);
- } else
+ if (ACPI_FAILURE(status))
return -ENODEV;
+
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ asus_rfkill_notify, asus);
+ if (ACPI_FAILURE(status))
+ pr_warn("Failed to register notify on %s\n", node);
return 0;
}
@@ -838,21 +893,20 @@
acpi_handle handle;
status = acpi_get_handle(NULL, node, &handle);
+ if (ACPI_FAILURE(status))
+ return;
- if (ACPI_SUCCESS(status)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- asus_rfkill_notify);
- if (ACPI_FAILURE(status))
- pr_err("Error removing rfkill notify handler %s\n",
- node);
- }
+ status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ asus_rfkill_notify);
+ if (ACPI_FAILURE(status))
+ pr_err("Error removing rfkill notify handler %s\n", node);
}
static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
u8 *value)
{
- struct asus_wmi *asus = hotplug_slot->private;
+ struct asus_wmi *asus = container_of(hotplug_slot,
+ struct asus_wmi, hotplug_slot);
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
if (result < 0)
@@ -862,8 +916,7 @@
return 0;
}
-static struct hotplug_slot_ops asus_hotplug_slot_ops = {
- .owner = THIS_MODULE,
+static const struct hotplug_slot_ops asus_hotplug_slot_ops = {
.get_adapter_status = asus_get_adapter_status,
.get_power_status = asus_get_adapter_status,
};
@@ -893,21 +946,9 @@
INIT_WORK(&asus->hotplug_work, asus_hotplug_work);
- asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
- if (!asus->hotplug_slot)
- goto error_slot;
+ asus->hotplug_slot.ops = &asus_hotplug_slot_ops;
- asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
- GFP_KERNEL);
- if (!asus->hotplug_slot->info)
- goto error_info;
-
- asus->hotplug_slot->private = asus;
- asus->hotplug_slot->ops = &asus_hotplug_slot_ops;
- asus_get_adapter_status(asus->hotplug_slot,
- &asus->hotplug_slot->info->adapter_status);
-
- ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi");
+ ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi");
if (ret) {
pr_err("Unable to register hotplug slot - %d\n", ret);
goto error_register;
@@ -916,11 +957,7 @@
return 0;
error_register:
- kfree(asus->hotplug_slot->info);
-error_info:
- kfree(asus->hotplug_slot);
- asus->hotplug_slot = NULL;
-error_slot:
+ asus->hotplug_slot.ops = NULL;
destroy_workqueue(asus->hotplug_workqueue);
error_workqueue:
return ret;
@@ -1048,11 +1085,8 @@
* asus_unregister_rfkill_notifier()
*/
asus_rfkill_hotplug(asus);
- if (asus->hotplug_slot) {
- pci_hp_deregister(asus->hotplug_slot);
- kfree(asus->hotplug_slot->info);
- kfree(asus->hotplug_slot);
- }
+ if (asus->hotplug_slot.ops)
+ pci_hp_deregister(&asus->hotplug_slot);
if (asus->hotplug_workqueue)
destroy_workqueue(asus->hotplug_workqueue);
@@ -1157,6 +1191,8 @@
return result;
}
+/* Quirks *********************************************************************/
+
static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
{
struct pci_dev *xhci_pdev;
@@ -1176,6 +1212,8 @@
pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
cpu_to_le32(ports_available));
+ pci_dev_put(xhci_pdev);
+
pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
orig_ports_available, ports_available);
}
@@ -1189,13 +1227,12 @@
asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL);
}
-/*
- * Hwmon device
- */
-static int asus_hwmon_agfn_fan_speed_read(struct asus_wmi *asus, int fan,
+/* Hwmon device ***************************************************************/
+
+static int asus_agfn_fan_speed_read(struct asus_wmi *asus, int fan,
int *speed)
{
- struct fan_args args = {
+ struct agfn_fan_args args = {
.agfn.len = sizeof(args),
.agfn.mfun = ASUS_FAN_MFUN,
.agfn.sfun = ASUS_FAN_SFUN_READ,
@@ -1219,10 +1256,10 @@
return 0;
}
-static int asus_hwmon_agfn_fan_speed_write(struct asus_wmi *asus, int fan,
+static int asus_agfn_fan_speed_write(struct asus_wmi *asus, int fan,
int *speed)
{
- struct fan_args args = {
+ struct agfn_fan_args args = {
.agfn.len = sizeof(args),
.agfn.mfun = ASUS_FAN_MFUN,
.agfn.sfun = ASUS_FAN_SFUN_WRITE,
@@ -1242,7 +1279,7 @@
return -ENXIO;
if (speed && fan == 1)
- asus->asus_hwmon_pwm = *speed;
+ asus->agfn_pwm = *speed;
return 0;
}
@@ -1251,77 +1288,60 @@
* Check if we can read the speed of one fan. If true we assume we can also
* control it.
*/
-static int asus_hwmon_get_fan_number(struct asus_wmi *asus, int *num_fans)
+static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus)
{
int status;
- int speed = 0;
+ int speed;
+ u32 value;
- *num_fans = 0;
+ status = asus_agfn_fan_speed_read(asus, 1, &speed);
+ if (status != 0)
+ return false;
- status = asus_hwmon_agfn_fan_speed_read(asus, 1, &speed);
- if (!status)
- *num_fans = 1;
+ status = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
+ if (status != 0)
+ return false;
- return 0;
+ /*
+ * We need to find a better way, probably using sfun,
+ * bits or spec ...
+ * Currently we disable it if:
+ * - ASUS_WMI_UNSUPPORTED_METHOD is returned
+ * - reverved bits are non-zero
+ * - sfun and presence bit are not set
+ */
+ return !(value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
+ || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)));
}
-static int asus_hwmon_fan_set_auto(struct asus_wmi *asus)
+static int asus_fan_set_auto(struct asus_wmi *asus)
{
int status;
+ u32 retval;
- status = asus_hwmon_agfn_fan_speed_write(asus, 0, NULL);
- if (status)
+ switch (asus->fan_type) {
+ case FAN_TYPE_SPEC83:
+ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ 0, &retval);
+ if (status)
+ return status;
+
+ if (retval != 1)
+ return -EIO;
+ break;
+
+ case FAN_TYPE_AGFN:
+ status = asus_agfn_fan_speed_write(asus, 0, NULL);
+ if (status)
+ return -ENXIO;
+ break;
+
+ default:
return -ENXIO;
+ }
- asus->asus_hwmon_fan_manual_mode = false;
return 0;
-}
-
-static int asus_hwmon_fan_rpm_show(struct device *dev, int fan)
-{
- struct asus_wmi *asus = dev_get_drvdata(dev);
- int value;
- int ret;
-
- /* no speed readable on manual mode */
- if (asus->asus_hwmon_fan_manual_mode)
- return -ENXIO;
-
- ret = asus_hwmon_agfn_fan_speed_read(asus, fan+1, &value);
- if (ret) {
- pr_warn("reading fan speed failed: %d\n", ret);
- return -ENXIO;
- }
-
- return value;
-}
-
-static void asus_hwmon_pwm_show(struct asus_wmi *asus, int fan, int *value)
-{
- int err;
-
- if (asus->asus_hwmon_pwm >= 0) {
- *value = asus->asus_hwmon_pwm;
- return;
- }
-
- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, value);
- if (err < 0)
- return;
-
- *value &= 0xFF;
-
- if (*value == 1) /* Low Speed */
- *value = 85;
- else if (*value == 2)
- *value = 170;
- else if (*value == 3)
- *value = 255;
- else if (*value) {
- pr_err("Unknown fan speed %#x\n", *value);
- *value = -1;
- }
}
static ssize_t pwm1_show(struct device *dev,
@@ -1329,9 +1349,33 @@
char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ int err;
int value;
- asus_hwmon_pwm_show(asus, 0, &value);
+ /* If we already set a value then just return it */
+ if (asus->agfn_pwm >= 0)
+ return sprintf(buf, "%d\n", asus->agfn_pwm);
+
+ /*
+ * If we haven't set already set a value through the AGFN interface,
+ * we read a current value through the (now-deprecated) FAN_CTRL device.
+ */
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
+ if (err < 0)
+ return err;
+
+ value &= 0xFF;
+
+ if (value == 1) /* Low Speed */
+ value = 85;
+ else if (value == 2)
+ value = 170;
+ else if (value == 3)
+ value = 255;
+ else if (value) {
+ pr_err("Unknown fan speed %#x\n", value);
+ value = -1;
+ }
return sprintf(buf, "%d\n", value);
}
@@ -1345,17 +1389,16 @@
int ret;
ret = kstrtouint(buf, 10, &value);
-
if (ret)
return ret;
value = clamp(value, 0, 255);
- state = asus_hwmon_agfn_fan_speed_write(asus, 1, &value);
+ state = asus_agfn_fan_speed_write(asus, 1, &value);
if (state)
pr_warn("Setting fan speed failed: %d\n", state);
else
- asus->asus_hwmon_fan_manual_mode = true;
+ asus->fan_pwm_mode = ASUS_FAN_CTRL_MANUAL;
return count;
}
@@ -1364,10 +1407,37 @@
struct device_attribute *attr,
char *buf)
{
- int value = asus_hwmon_fan_rpm_show(dev, 0);
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ int value;
+ int ret;
+
+ switch (asus->fan_type) {
+ case FAN_TYPE_SPEC83:
+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ &value);
+ if (ret < 0)
+ return ret;
+
+ value &= 0xffff;
+ break;
+
+ case FAN_TYPE_AGFN:
+ /* no speed readable on manual mode */
+ if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL)
+ return -ENXIO;
+
+ ret = asus_agfn_fan_speed_read(asus, 1, &value);
+ if (ret) {
+ pr_warn("reading fan speed failed: %d\n", ret);
+ return -ENXIO;
+ }
+ break;
+
+ default:
+ return -ENXIO;
+ }
return sprintf(buf, "%d\n", value < 0 ? -1 : value*100);
-
}
static ssize_t pwm1_enable_show(struct device *dev,
@@ -1376,10 +1446,16 @@
{
struct asus_wmi *asus = dev_get_drvdata(dev);
- if (asus->asus_hwmon_fan_manual_mode)
- return sprintf(buf, "%d\n", ASUS_FAN_CTRL_MANUAL);
-
- return sprintf(buf, "%d\n", ASUS_FAN_CTRL_AUTO);
+ /*
+ * Just read back the cached pwm mode.
+ *
+ * For the CPU_FAN device, the spec indicates that we should be
+ * able to read the device status and consult bit 19 to see if we
+ * are in Full On or Automatic mode. However, this does not work
+ * in practice on X532FL at least (the bit is always 0) and there's
+ * also nothing in the DSDT to indicate that this behaviour exists.
+ */
+ return sprintf(buf, "%d\n", asus->fan_pwm_mode);
}
static ssize_t pwm1_enable_store(struct device *dev,
@@ -1389,21 +1465,50 @@
struct asus_wmi *asus = dev_get_drvdata(dev);
int status = 0;
int state;
+ int value;
int ret;
+ u32 retval;
ret = kstrtouint(buf, 10, &state);
-
if (ret)
return ret;
- if (state == ASUS_FAN_CTRL_MANUAL)
- asus->asus_hwmon_fan_manual_mode = true;
- else
- status = asus_hwmon_fan_set_auto(asus);
+ if (asus->fan_type == FAN_TYPE_SPEC83) {
+ switch (state) { /* standard documented hwmon values */
+ case ASUS_FAN_CTRL_FULLSPEED:
+ value = 1;
+ break;
+ case ASUS_FAN_CTRL_AUTO:
+ value = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
- if (status)
- return status;
+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ value, &retval);
+ if (ret)
+ return ret;
+ if (retval != 1)
+ return -EIO;
+ } else if (asus->fan_type == FAN_TYPE_AGFN) {
+ switch (state) {
+ case ASUS_FAN_CTRL_MANUAL:
+ break;
+
+ case ASUS_FAN_CTRL_AUTO:
+ status = asus_fan_set_auto(asus);
+ if (status)
+ return status;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ asus->fan_pwm_mode = state;
return count;
}
@@ -1423,13 +1528,11 @@
int err;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value);
-
if (err < 0)
return err;
- value = DECI_KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000;
-
- return sprintf(buf, "%d\n", value);
+ return sprintf(buf, "%ld\n",
+ deci_kelvin_to_millicelsius(value & 0xFFFF));
}
/* Fan1 */
@@ -1455,58 +1558,34 @@
struct attribute *attr, int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct asus_wmi *asus = platform_get_drvdata(pdev);
- int dev_id = -1;
- int fan_attr = -1;
+ struct asus_wmi *asus = dev_get_drvdata(dev->parent);
u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
- bool ok = true;
- if (attr == &dev_attr_pwm1.attr)
- dev_id = ASUS_WMI_DEVID_FAN_CTRL;
- else if (attr == &dev_attr_temp1_input.attr)
- dev_id = ASUS_WMI_DEVID_THERMAL_CTRL;
-
-
- if (attr == &dev_attr_fan1_input.attr
+ if (attr == &dev_attr_pwm1.attr) {
+ if (asus->fan_type != FAN_TYPE_AGFN)
+ return 0;
+ } else if (attr == &dev_attr_fan1_input.attr
|| attr == &dev_attr_fan1_label.attr
- || attr == &dev_attr_pwm1.attr
|| attr == &dev_attr_pwm1_enable.attr) {
- fan_attr = 1;
- }
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return 0;
+ } else if (attr == &dev_attr_temp1_input.attr) {
+ int err = asus_wmi_get_devstate(asus,
+ ASUS_WMI_DEVID_THERMAL_CTRL,
+ &value);
- if (dev_id != -1) {
- int err = asus_wmi_get_devstate(asus, dev_id, &value);
-
- if (err < 0 && fan_attr == -1)
+ if (err < 0)
return 0; /* can't return negative here */
- }
- if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) {
/*
- * We need to find a better way, probably using sfun,
- * bits or spec ...
- * Currently we disable it if:
- * - ASUS_WMI_UNSUPPORTED_METHOD is returned
- * - reverved bits are non-zero
- * - sfun and presence bit are not set
+ * If the temperature value in deci-Kelvin is near the absolute
+ * zero temperature, something is clearly wrong
*/
- if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
- || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
- ok = false;
- else
- ok = fan_attr <= asus->asus_hwmon_num_fans;
- } else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) {
- /* If value is zero, something is clearly wrong */
- if (!value)
- ok = false;
- } else if (fan_attr <= asus->asus_hwmon_num_fans && fan_attr != -1) {
- ok = true;
- } else {
- ok = false;
+ if (value == 0 || value == 1)
+ return 0;
}
- return ok ? attr->mode : 0;
+ return attr->mode;
}
static const struct attribute_group hwmon_attribute_group = {
@@ -1517,11 +1596,12 @@
static int asus_wmi_hwmon_init(struct asus_wmi *asus)
{
+ struct device *dev = &asus->platform_device->dev;
struct device *hwmon;
- hwmon = hwmon_device_register_with_groups(&asus->platform_device->dev,
- "asus", asus,
- hwmon_attribute_groups);
+ hwmon = devm_hwmon_device_register_with_groups(dev, "asus", asus,
+ hwmon_attribute_groups);
+
if (IS_ERR(hwmon)) {
pr_err("Could not register asus hwmon device\n");
return PTR_ERR(hwmon);
@@ -1529,12 +1609,246 @@
return 0;
}
-/*
- * Backlight
- */
+static int asus_wmi_fan_init(struct asus_wmi *asus)
+{
+ asus->fan_type = FAN_TYPE_NONE;
+ asus->agfn_pwm = -1;
+
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
+ asus->fan_type = FAN_TYPE_SPEC83;
+ else if (asus_wmi_has_agfn_fan(asus))
+ asus->fan_type = FAN_TYPE_AGFN;
+
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return -ENODEV;
+
+ asus_fan_set_auto(asus);
+ asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO;
+ return 0;
+}
+
+/* Fan mode *******************************************************************/
+
+static int fan_boost_mode_check_present(struct asus_wmi *asus)
+{
+ u32 result;
+ int err;
+
+ asus->fan_boost_mode_available = false;
+
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE,
+ &result);
+ if (err) {
+ if (err == -ENODEV)
+ return 0;
+ else
+ return err;
+ }
+
+ if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
+ (result & ASUS_FAN_BOOST_MODES_MASK)) {
+ asus->fan_boost_mode_available = true;
+ asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK;
+ }
+
+ return 0;
+}
+
+static int fan_boost_mode_write(struct asus_wmi *asus)
+{
+ int err;
+ u8 value;
+ u32 retval;
+
+ value = asus->fan_boost_mode;
+
+ pr_info("Set fan boost mode: %u\n", value);
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value,
+ &retval);
+ if (err) {
+ pr_warn("Failed to set fan boost mode: %d\n", err);
+ return err;
+ }
+
+ if (retval != 1) {
+ pr_warn("Failed to set fan boost mode (retval): 0x%x\n",
+ retval);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fan_boost_mode_switch_next(struct asus_wmi *asus)
+{
+ u8 mask = asus->fan_boost_mode_mask;
+
+ if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) {
+ if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST;
+ else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
+ } else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+ if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
+ else
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
+ } else {
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
+ }
+
+ return fan_boost_mode_write(asus);
+}
+
+static ssize_t fan_boost_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
+}
+
+static ssize_t fan_boost_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result;
+ u8 new_mode;
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ u8 mask = asus->fan_boost_mode_mask;
+
+ result = kstrtou8(buf, 10, &new_mode);
+ if (result < 0) {
+ pr_warn("Trying to store invalid value\n");
+ return result;
+ }
+
+ if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+ if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK))
+ return -EINVAL;
+ } else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) {
+ if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK))
+ return -EINVAL;
+ } else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) {
+ return -EINVAL;
+ }
+
+ asus->fan_boost_mode = new_mode;
+ fan_boost_mode_write(asus);
+
+ return count;
+}
+
+// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
+static DEVICE_ATTR_RW(fan_boost_mode);
+
+/* Throttle thermal policy ****************************************************/
+
+static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
+{
+ u32 result;
+ int err;
+
+ asus->throttle_thermal_policy_available = false;
+
+ err = asus_wmi_get_devstate(asus,
+ ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
+ &result);
+ if (err) {
+ if (err == -ENODEV)
+ return 0;
+ return err;
+ }
+
+ if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
+ asus->throttle_thermal_policy_available = true;
+
+ return 0;
+}
+
+static int throttle_thermal_policy_write(struct asus_wmi *asus)
+{
+ int err;
+ u8 value;
+ u32 retval;
+
+ value = asus->throttle_thermal_policy_mode;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
+ value, &retval);
+ if (err) {
+ pr_warn("Failed to set throttle thermal policy: %d\n", err);
+ return err;
+ }
+
+ if (retval != 1) {
+ pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
+ retval);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
+{
+ if (!asus->throttle_thermal_policy_available)
+ return 0;
+
+ asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+ return throttle_thermal_policy_write(asus);
+}
+
+static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
+{
+ u8 new_mode = asus->throttle_thermal_policy_mode + 1;
+
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+
+ asus->throttle_thermal_policy_mode = new_mode;
+ return throttle_thermal_policy_write(asus);
+}
+
+static ssize_t throttle_thermal_policy_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ u8 mode = asus->throttle_thermal_policy_mode;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t throttle_thermal_policy_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result;
+ u8 new_mode;
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou8(buf, 10, &new_mode);
+ if (result < 0)
+ return result;
+
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ return -EINVAL;
+
+ asus->throttle_thermal_policy_mode = new_mode;
+ throttle_thermal_policy_write(asus);
+
+ return count;
+}
+
+// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
+static DEVICE_ATTR_RW(throttle_thermal_policy);
+
+/* Backlight ******************************************************************/
+
static int read_backlight_power(struct asus_wmi *asus)
{
int ret;
+
if (asus->driver->quirks->store_backlight_power)
ret = !asus->driver->panel_power;
else
@@ -1553,7 +1867,6 @@
int err;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
-
if (err < 0)
return err;
@@ -1573,7 +1886,6 @@
int err;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
-
if (err < 0)
return err;
@@ -1663,7 +1975,6 @@
return max;
power = read_backlight_power(asus);
-
if (power == -ENODEV)
power = FB_BLANK_UNBLANK;
else if (power < 0)
@@ -1713,108 +2024,200 @@
return 0;
}
-static void asus_wmi_notify(u32 value, void *context)
+/* Fn-lock ********************************************************************/
+
+static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
{
- struct asus_wmi *asus = context;
+ u32 result;
+
+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result);
+
+ return (result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
+ !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED);
+}
+
+static void asus_wmi_fnlock_update(struct asus_wmi *asus)
+{
+ int mode = asus->fnlock_locked;
+
+ asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
+}
+
+/* WMI events *****************************************************************/
+
+static int asus_wmi_get_event_code(u32 value)
+{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int code;
- int orig_code;
- unsigned int key_value = 1;
- bool autorelease = 1;
status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_err("bad event status 0x%x\n", status);
- return;
+ if (ACPI_FAILURE(status)) {
+ pr_warn("Failed to get WMI notify code: %s\n",
+ acpi_format_exception(status));
+ return -EIO;
}
obj = (union acpi_object *)response.pointer;
- if (!obj || obj->type != ACPI_TYPE_INTEGER)
- goto exit;
+ if (obj && obj->type == ACPI_TYPE_INTEGER)
+ code = (int)(obj->integer.value & WMI_EVENT_MASK);
+ else
+ code = -EIO;
- code = obj->integer.value;
+ kfree(obj);
+ return code;
+}
+
+static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+{
+ unsigned int key_value = 1;
+ bool autorelease = 1;
+ int result, orig_code;
+
orig_code = code;
if (asus->driver->key_filter) {
asus->driver->key_filter(asus->driver, &code, &key_value,
&autorelease);
if (code == ASUS_WMI_KEY_IGNORE)
- goto exit;
+ return;
}
if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
code = ASUS_WMI_BRN_UP;
- else if (code >= NOTIFY_BRNDOWN_MIN &&
- code <= NOTIFY_BRNDOWN_MAX)
+ else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
code = ASUS_WMI_BRN_DOWN;
if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
asus_wmi_backlight_notify(asus, orig_code);
- goto exit;
+ return;
}
}
if (code == NOTIFY_KBD_BRTUP) {
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
- goto exit;
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
+ return;
}
if (code == NOTIFY_KBD_BRTDWN) {
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1);
- goto exit;
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk - 1);
+ return;
}
if (code == NOTIFY_KBD_BRTTOGGLE) {
if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
- do_kbd_led_set(&asus->kbd_led, 0);
+ kbd_led_set_by_kbd(asus, 0);
else
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
- goto exit;
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
+ return;
}
- if (is_display_toggle(code) &&
- asus->driver->quirks->no_display_toggle)
- goto exit;
+ if (code == NOTIFY_FNLOCK_TOGGLE) {
+ asus->fnlock_locked = !asus->fnlock_locked;
+ asus_wmi_fnlock_update(asus);
+ return;
+ }
+
+ if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
+ result = asus_wmi_get_devstate_simple(asus,
+ ASUS_WMI_DEVID_KBD_DOCK);
+ if (result >= 0) {
+ input_report_switch(asus->inputdev, SW_TABLET_MODE,
+ !result);
+ input_sync(asus->inputdev);
+ }
+ return;
+ }
+
+ if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
+ fan_boost_mode_switch_next(asus);
+ return;
+ }
+
+ if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
+ throttle_thermal_policy_switch_next(asus);
+ return;
+ }
+
+ if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
+ return;
if (!sparse_keymap_report_event(asus->inputdev, code,
key_value, autorelease))
pr_info("Unknown key %x pressed\n", code);
-
-exit:
- kfree(obj);
}
-/*
- * Sys helpers
- */
-static int parse_arg(const char *buf, unsigned long count, int *val)
+static void asus_wmi_notify(u32 value, void *context)
{
- if (!count)
- return 0;
- if (sscanf(buf, "%i", val) != 1)
- return -EINVAL;
- return count;
+ struct asus_wmi *asus = context;
+ int code;
+ int i;
+
+ for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
+ code = asus_wmi_get_event_code(value);
+ if (code < 0) {
+ pr_warn("Failed to get notify code: %d\n", code);
+ return;
+ }
+
+ if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
+ return;
+
+ asus_wmi_handle_event_code(code, asus);
+
+ /*
+ * Double check that queue is present:
+ * ATK (with queue) uses 0xff, ASUSWMI (without) 0xd2.
+ */
+ if (!asus->wmi_event_queue || value != WMI_EVENT_VALUE_ATK)
+ return;
+ }
+
+ pr_warn("Failed to process event queue, last code: 0x%x\n", code);
}
+
+static int asus_wmi_notify_queue_flush(struct asus_wmi *asus)
+{
+ int code;
+ int i;
+
+ for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
+ code = asus_wmi_get_event_code(WMI_EVENT_VALUE_ATK);
+ if (code < 0) {
+ pr_warn("Failed to get event during flush: %d\n", code);
+ return code;
+ }
+
+ if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
+ return 0;
+ }
+
+ pr_warn("Failed to flush event queue\n");
+ return -EIO;
+}
+
+/* Sysfs **********************************************************************/
static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
const char *buf, size_t count)
{
u32 retval;
- int rv, err, value;
+ int err, value;
value = asus_wmi_get_devstate_simple(asus, devid);
if (value < 0)
return value;
- rv = parse_arg(buf, count, &value);
- err = asus_wmi_set_devstate(devid, value, &retval);
+ err = kstrtoint(buf, 0, &value);
+ if (err)
+ return err;
+ err = asus_wmi_set_devstate(devid, value, &retval);
if (err < 0)
return err;
- return rv;
+ return count;
}
static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
@@ -1863,8 +2266,10 @@
{
int value, rv;
- if (!count || sscanf(buf, "%i", &value) != 1)
- return -EINVAL;
+ rv = kstrtoint(buf, 0, &value);
+ if (rv)
+ return rv;
+
if (value < 0 || value > 2)
return -EINVAL;
@@ -1884,6 +2289,8 @@
&dev_attr_touchpad.attr,
&dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr,
+ &dev_attr_fan_boost_mode.attr,
+ &dev_attr_throttle_thermal_policy.attr,
NULL
};
@@ -1905,6 +2312,10 @@
devid = ASUS_WMI_DEVID_LID_RESUME;
else if (attr == &dev_attr_als_enable.attr)
devid = ASUS_WMI_DEVID_ALS_ENABLE;
+ else if (attr == &dev_attr_fan_boost_mode.attr)
+ ok = asus->fan_boost_mode_available;
+ else if (attr == &dev_attr_throttle_thermal_policy.attr)
+ ok = asus->throttle_thermal_policy_available;
if (devid != -1)
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -1927,11 +2338,12 @@
return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
}
-/*
- * Platform device
- */
+/* Platform device ************************************************************/
+
static int asus_wmi_platform_init(struct asus_wmi *asus)
{
+ struct device *dev = &asus->platform_device->dev;
+ char *wmi_uid;
int rv;
/* INIT enable hotkeys on some models */
@@ -1961,11 +2373,41 @@
* Note, on most Eeepc, there is no way to check if a method exist
* or note, while on notebooks, they returns 0xFFFFFFFE on failure,
* but once again, SPEC may probably be used for that kind of things.
+ *
+ * Additionally at least TUF Gaming series laptops return nothing for
+ * unknown methods, so the detection in this way is not possible.
+ *
+ * There is strong indication that only ACPI WMI devices that have _UID
+ * equal to "ASUSWMI" use DCTS whereas those with "ATK" use DSTS.
*/
- if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
+ wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID);
+ if (!wmi_uid)
+ return -ENODEV;
+
+ if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) {
+ dev_info(dev, "Detected ASUSWMI, use DCTS\n");
+ asus->dsts_id = ASUS_WMI_METHODID_DCTS;
+ } else {
+ dev_info(dev, "Detected %s, not ASUSWMI, use DSTS\n", wmi_uid);
asus->dsts_id = ASUS_WMI_METHODID_DSTS;
- else
- asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
+ }
+
+ /*
+ * Some devices can have multiple event codes stored in a queue before
+ * the module load if it was unloaded intermittently after calling
+ * the INIT method (enables event handling). The WMI notify handler is
+ * expected to retrieve all event codes until a retrieved code equals
+ * queue end marker (One or Ones). Old codes are flushed from the queue
+ * upon module load. Not enabling this when it should be has minimal
+ * visible impact so fall back if anything goes wrong.
+ */
+ wmi_uid = wmi_get_acpi_device_uid(asus->driver->event_guid);
+ if (wmi_uid && !strcmp(wmi_uid, ASUS_ACPI_UID_ATK)) {
+ dev_info(dev, "Detected ATK, enable event queue\n");
+
+ if (!asus_wmi_notify_queue_flush(asus))
+ asus->wmi_event_queue = true;
+ }
/* CWAP allow to define the behavior of the Fn+F2 key,
* this method doesn't seems to be present on Eee PCs */
@@ -1973,17 +2415,11 @@
asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
asus->driver->quirks->wapf, NULL);
- return asus_wmi_sysfs_init(asus->platform_device);
+ return 0;
}
-static void asus_wmi_platform_exit(struct asus_wmi *asus)
-{
- asus_wmi_sysfs_exit(asus->platform_device);
-}
+/* debugfs ********************************************************************/
-/*
- * debugfs
- */
struct asus_wmi_debugfs_node {
struct asus_wmi *asus;
char *name;
@@ -1997,7 +2433,6 @@
u32 retval = -1;
err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
-
if (err < 0)
return err;
@@ -2014,7 +2449,6 @@
err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
&retval);
-
if (err < 0)
return err;
@@ -2084,74 +2518,33 @@
debugfs_remove_recursive(asus->debug.root);
}
-static int asus_wmi_debugfs_init(struct asus_wmi *asus)
+static void asus_wmi_debugfs_init(struct asus_wmi *asus)
{
- struct dentry *dent;
int i;
asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
- if (!asus->debug.root) {
- pr_err("failed to create debugfs directory\n");
- goto error_debugfs;
- }
- dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.method_id);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.method_id);
- dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.dev_id);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.dev_id);
- dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.ctrl_param);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.ctrl_param);
for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) {
struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i];
node->asus = asus;
- dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
- asus->debug.root, node,
- &asus_wmi_debugfs_io_ops);
- if (!dent) {
- pr_err("failed to create debug file: %s\n", node->name);
- goto error_debugfs;
- }
+ debugfs_create_file(node->name, S_IFREG | S_IRUGO,
+ asus->debug.root, node,
+ &asus_wmi_debugfs_io_ops);
}
-
- return 0;
-
-error_debugfs:
- asus_wmi_debugfs_exit(asus);
- return -ENOMEM;
}
-static int asus_wmi_fan_init(struct asus_wmi *asus)
-{
- int status;
+/* Init / exit ****************************************************************/
- asus->asus_hwmon_pwm = -1;
- asus->asus_hwmon_num_fans = -1;
- asus->asus_hwmon_fan_manual_mode = false;
-
- status = asus_hwmon_get_fan_number(asus, &asus->asus_hwmon_num_fans);
- if (status) {
- asus->asus_hwmon_num_fans = 0;
- pr_warn("Could not determine number of fans: %d\n", status);
- return -ENXIO;
- }
-
- pr_info("Number of fans: %d\n", asus->asus_hwmon_num_fans);
- return 0;
-}
-
-/*
- * WMI Driver
- */
static int asus_wmi_add(struct platform_device *pdev)
{
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
@@ -2178,12 +2571,25 @@
if (err)
goto fail_platform;
+ err = fan_boost_mode_check_present(asus);
+ if (err)
+ goto fail_fan_boost_mode;
+
+ err = throttle_thermal_policy_check_present(asus);
+ if (err)
+ goto fail_throttle_thermal_policy;
+ else
+ throttle_thermal_policy_set_default(asus);
+
+ err = asus_wmi_sysfs_init(asus->platform_device);
+ if (err)
+ goto fail_sysfs;
+
err = asus_wmi_input_init(asus);
if (err)
goto fail_input;
err = asus_wmi_fan_init(asus); /* probably no problems on error */
- asus_hwmon_fan_set_auto(asus);
err = asus_wmi_hwmon_init(asus);
if (err)
@@ -2228,6 +2634,11 @@
} else if (asus->driver->quirks->wmi_backlight_set_devstate)
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
+ if (asus_wmi_has_fnlock_key(asus)) {
+ asus->fnlock_locked = true;
+ asus_wmi_fnlock_update(asus);
+ }
+
status = wmi_install_notify_handler(asus->driver->event_guid,
asus_wmi_notify, asus);
if (ACPI_FAILURE(status)) {
@@ -2236,14 +2647,12 @@
goto fail_wmi_handler;
}
- err = asus_wmi_debugfs_init(asus);
- if (err)
- goto fail_debugfs;
+ asus_wmi_battery_init(asus);
+
+ asus_wmi_debugfs_init(asus);
return 0;
-fail_debugfs:
- wmi_remove_notify_handler(asus->driver->event_guid);
fail_wmi_handler:
asus_wmi_backlight_exit(asus);
fail_backlight:
@@ -2254,7 +2663,10 @@
fail_hwmon:
asus_wmi_input_exit(asus);
fail_input:
- asus_wmi_platform_exit(asus);
+ asus_wmi_sysfs_exit(asus->platform_device);
+fail_sysfs:
+fail_throttle_thermal_policy:
+fail_fan_boost_mode:
fail_platform:
kfree(asus);
return err;
@@ -2271,16 +2683,16 @@
asus_wmi_led_exit(asus);
asus_wmi_rfkill_exit(asus);
asus_wmi_debugfs_exit(asus);
- asus_wmi_platform_exit(asus);
- asus_hwmon_fan_set_auto(asus);
+ asus_wmi_sysfs_exit(asus->platform_device);
+ asus_fan_set_auto(asus);
+ asus_wmi_battery_exit(asus);
kfree(asus);
return 0;
}
-/*
- * Platform driver - hibernate/resume callbacks
- */
+/* Platform driver - hibernate/resume callbacks *******************************/
+
static int asus_hotk_thaw(struct device *device)
{
struct asus_wmi *asus = dev_get_drvdata(device);
@@ -2305,8 +2717,10 @@
struct asus_wmi *asus = dev_get_drvdata(device);
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ kbd_led_update(asus);
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
return 0;
}
@@ -2341,8 +2755,10 @@
rfkill_set_sw_state(asus->uwb.rfkill, bl);
}
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ kbd_led_update(asus);
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
return 0;
}
@@ -2352,6 +2768,8 @@
.resume = asus_hotk_resume,
};
+/* Registration ***************************************************************/
+
static int asus_wmi_probe(struct platform_device *pdev)
{
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
@@ -2359,12 +2777,12 @@
int ret;
if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
- pr_warn("Management GUID not found\n");
+ pr_warn("ASUS Management GUID not found\n");
return -ENODEV;
}
if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) {
- pr_warn("Event GUID not found\n");
+ pr_warn("ASUS Event GUID not found\n");
return -ENODEV;
}
@@ -2414,11 +2832,6 @@
static int __init asus_wmi_init(void)
{
- if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
- pr_info("Asus Management GUID not found\n");
- return -ENODEV;
- }
-
pr_info("ASUS WMI generic driver loaded\n");
return 0;
}
--
Gitblit v1.6.2