mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-05 00:04:34 -04:00
Merge branch 'for-6.20/asus' into for-linus
- Support for WMI (Fn+F5) fan control for Asus ROG laptops (Ionut Nechita) - fn-lock support for Asus ProArt P16 (Connor Belli)
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
@@ -56,6 +57,16 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define ROG_ALLY_X_MIN_MCU 313
|
||||
#define ROG_ALLY_MIN_MCU 319
|
||||
|
||||
/* Spurious HID codes sent by QUIRK_ROG_NKEY_KEYBOARD devices */
|
||||
#define ASUS_SPURIOUS_CODE_0XEA 0xea
|
||||
#define ASUS_SPURIOUS_CODE_0XEC 0xec
|
||||
#define ASUS_SPURIOUS_CODE_0X02 0x02
|
||||
#define ASUS_SPURIOUS_CODE_0X8A 0x8a
|
||||
#define ASUS_SPURIOUS_CODE_0X9E 0x9e
|
||||
|
||||
/* Special key codes */
|
||||
#define ASUS_FAN_CTRL_KEY_CODE 0xae
|
||||
|
||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
||||
|
||||
#define MAX_TOUCH_MAJOR 8
|
||||
@@ -89,6 +100,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
|
||||
#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
|
||||
#define QUIRK_ROG_ALLY_XPAD BIT(13)
|
||||
#define QUIRK_HID_FN_LOCK BIT(14)
|
||||
|
||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
||||
QUIRK_NO_INIT_REPORTS | \
|
||||
@@ -132,6 +144,8 @@ struct asus_drvdata {
|
||||
int battery_stat;
|
||||
bool battery_in_query;
|
||||
unsigned long battery_next_query;
|
||||
struct work_struct fn_lock_sync_work;
|
||||
bool fn_lock;
|
||||
};
|
||||
|
||||
static int asus_report_battery(struct asus_drvdata *, u8 *, int);
|
||||
@@ -313,16 +327,47 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send events to asus-wmi driver for handling special keys
|
||||
*/
|
||||
static int asus_wmi_send_event(struct asus_drvdata *drvdata, u8 code)
|
||||
{
|
||||
int err;
|
||||
u32 retval;
|
||||
|
||||
err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS,
|
||||
ASUS_WMI_METHODID_NOTIF, code, &retval);
|
||||
if (err) {
|
||||
pr_warn("Failed to notify asus-wmi: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (retval != 0) {
|
||||
pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asus_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
|
||||
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR &&
|
||||
(usage->hid & HID_USAGE) != 0x00 &&
|
||||
(usage->hid & HID_USAGE) != 0xff && !usage->type) {
|
||||
hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
|
||||
usage->hid & HID_USAGE);
|
||||
}
|
||||
|
||||
if (drvdata->quirks & QUIRK_HID_FN_LOCK &&
|
||||
usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
|
||||
drvdata->fn_lock = !drvdata->fn_lock;
|
||||
schedule_work(&drvdata->fn_lock_sync_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -347,6 +392,43 @@ static int asus_raw_event(struct hid_device *hdev,
|
||||
if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2)
|
||||
return -1;
|
||||
if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
||||
if (report->id == FEATURE_KBD_REPORT_ID) {
|
||||
/*
|
||||
* Fn+F5 fan control key - try to send WMI event to toggle fan mode.
|
||||
* If successful, block the event from reaching userspace.
|
||||
* If asus-wmi is unavailable or the call fails, let the event
|
||||
* pass to userspace so it can implement its own fan control.
|
||||
*/
|
||||
if (data[1] == ASUS_FAN_CTRL_KEY_CODE) {
|
||||
int ret = asus_wmi_send_event(drvdata, ASUS_FAN_CTRL_KEY_CODE);
|
||||
|
||||
if (ret == 0) {
|
||||
/* Successfully handled by asus-wmi, block event */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Warn if asus-wmi failed (but not if it's unavailable).
|
||||
* Let the event reach userspace in all failure cases.
|
||||
*/
|
||||
if (ret != -ENODEV)
|
||||
hid_warn(hdev, "Failed to notify asus-wmi: %d\n", ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* ASUS ROG laptops send these codes during normal operation
|
||||
* with no discernable reason. Filter them out to avoid
|
||||
* unmapped warning messages.
|
||||
*/
|
||||
if (data[1] == ASUS_SPURIOUS_CODE_0XEA ||
|
||||
data[1] == ASUS_SPURIOUS_CODE_0XEC ||
|
||||
data[1] == ASUS_SPURIOUS_CODE_0X02 ||
|
||||
data[1] == ASUS_SPURIOUS_CODE_0X8A ||
|
||||
data[1] == ASUS_SPURIOUS_CODE_0X9E) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* G713 and G733 send these codes on some keypresses, depending on
|
||||
* the key pressed it can trigger a shutdown event if not caught.
|
||||
@@ -457,6 +539,21 @@ static int asus_kbd_disable_oobe(struct hid_device *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asus_kbd_set_fn_lock(struct hid_device *hdev, bool enabled)
|
||||
{
|
||||
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xd0, 0x4e, !!enabled };
|
||||
|
||||
return asus_kbd_set_report(hdev, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void asus_sync_fn_lock(struct work_struct *work)
|
||||
{
|
||||
struct asus_drvdata *drvdata =
|
||||
container_of(work, struct asus_drvdata, fn_lock_sync_work);
|
||||
|
||||
asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock);
|
||||
}
|
||||
|
||||
static void asus_schedule_work(struct asus_kbd_leds *led)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -928,6 +1025,12 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
asus_kbd_register_leds(hdev))
|
||||
hid_warn(hdev, "Failed to initialize backlight.\n");
|
||||
|
||||
if (drvdata->quirks & QUIRK_HID_FN_LOCK) {
|
||||
drvdata->fn_lock = true;
|
||||
INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock);
|
||||
asus_kbd_set_fn_lock(hdev, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1259,6 +1362,9 @@ static void asus_remove(struct hid_device *hdev)
|
||||
cancel_work_sync(&drvdata->kbd_backlight->work);
|
||||
}
|
||||
|
||||
if (drvdata->quirks & QUIRK_HID_FN_LOCK)
|
||||
cancel_work_sync(&drvdata->fn_lock_sync_work);
|
||||
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
@@ -1386,7 +1492,7 @@ static const struct hid_device_id asus_devices[] = {
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_HID_FN_LOCK },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#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_METHODID_NOTIF 0x00100021 /* Notify method */
|
||||
|
||||
#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user