Skip to content

Commit 984d6f3

Browse files
author
Jiri Kosina
committed
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)
2 parents e4aa247 + f631011 commit 984d6f3

2 files changed

Lines changed: 109 additions & 2 deletions

File tree

drivers/hid/hid-asus.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
/*
2424
*/
2525

26+
#include <linux/acpi.h>
2627
#include <linux/dmi.h>
2728
#include <linux/hid.h>
2829
#include <linux/module.h>
@@ -56,6 +57,16 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
5657
#define ROG_ALLY_X_MIN_MCU 313
5758
#define ROG_ALLY_MIN_MCU 319
5859

60+
/* Spurious HID codes sent by QUIRK_ROG_NKEY_KEYBOARD devices */
61+
#define ASUS_SPURIOUS_CODE_0XEA 0xea
62+
#define ASUS_SPURIOUS_CODE_0XEC 0xec
63+
#define ASUS_SPURIOUS_CODE_0X02 0x02
64+
#define ASUS_SPURIOUS_CODE_0X8A 0x8a
65+
#define ASUS_SPURIOUS_CODE_0X9E 0x9e
66+
67+
/* Special key codes */
68+
#define ASUS_FAN_CTRL_KEY_CODE 0xae
69+
5970
#define SUPPORT_KBD_BACKLIGHT BIT(0)
6071

6172
#define MAX_TOUCH_MAJOR 8
@@ -89,6 +100,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
89100
#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
90101
#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
91102
#define QUIRK_ROG_ALLY_XPAD BIT(13)
103+
#define QUIRK_HID_FN_LOCK BIT(14)
92104

93105
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
94106
QUIRK_NO_INIT_REPORTS | \
@@ -132,6 +144,8 @@ struct asus_drvdata {
132144
int battery_stat;
133145
bool battery_in_query;
134146
unsigned long battery_next_query;
147+
struct work_struct fn_lock_sync_work;
148+
bool fn_lock;
135149
};
136150

137151
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)
313327
return 0;
314328
}
315329

330+
/*
331+
* Send events to asus-wmi driver for handling special keys
332+
*/
333+
static int asus_wmi_send_event(struct asus_drvdata *drvdata, u8 code)
334+
{
335+
int err;
336+
u32 retval;
337+
338+
err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS,
339+
ASUS_WMI_METHODID_NOTIF, code, &retval);
340+
if (err) {
341+
pr_warn("Failed to notify asus-wmi: %d\n", err);
342+
return err;
343+
}
344+
345+
if (retval != 0) {
346+
pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval);
347+
return -EIO;
348+
}
349+
350+
return 0;
351+
}
352+
316353
static int asus_event(struct hid_device *hdev, struct hid_field *field,
317354
struct hid_usage *usage, __s32 value)
318355
{
319-
if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
356+
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
357+
358+
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR &&
320359
(usage->hid & HID_USAGE) != 0x00 &&
321360
(usage->hid & HID_USAGE) != 0xff && !usage->type) {
322361
hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
323362
usage->hid & HID_USAGE);
324363
}
325364

365+
if (drvdata->quirks & QUIRK_HID_FN_LOCK &&
366+
usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
367+
drvdata->fn_lock = !drvdata->fn_lock;
368+
schedule_work(&drvdata->fn_lock_sync_work);
369+
}
370+
326371
return 0;
327372
}
328373

@@ -347,6 +392,43 @@ static int asus_raw_event(struct hid_device *hdev,
347392
if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2)
348393
return -1;
349394
if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
395+
if (report->id == FEATURE_KBD_REPORT_ID) {
396+
/*
397+
* Fn+F5 fan control key - try to send WMI event to toggle fan mode.
398+
* If successful, block the event from reaching userspace.
399+
* If asus-wmi is unavailable or the call fails, let the event
400+
* pass to userspace so it can implement its own fan control.
401+
*/
402+
if (data[1] == ASUS_FAN_CTRL_KEY_CODE) {
403+
int ret = asus_wmi_send_event(drvdata, ASUS_FAN_CTRL_KEY_CODE);
404+
405+
if (ret == 0) {
406+
/* Successfully handled by asus-wmi, block event */
407+
return -1;
408+
}
409+
410+
/*
411+
* Warn if asus-wmi failed (but not if it's unavailable).
412+
* Let the event reach userspace in all failure cases.
413+
*/
414+
if (ret != -ENODEV)
415+
hid_warn(hdev, "Failed to notify asus-wmi: %d\n", ret);
416+
}
417+
418+
/*
419+
* ASUS ROG laptops send these codes during normal operation
420+
* with no discernable reason. Filter them out to avoid
421+
* unmapped warning messages.
422+
*/
423+
if (data[1] == ASUS_SPURIOUS_CODE_0XEA ||
424+
data[1] == ASUS_SPURIOUS_CODE_0XEC ||
425+
data[1] == ASUS_SPURIOUS_CODE_0X02 ||
426+
data[1] == ASUS_SPURIOUS_CODE_0X8A ||
427+
data[1] == ASUS_SPURIOUS_CODE_0X9E) {
428+
return -1;
429+
}
430+
}
431+
350432
/*
351433
* G713 and G733 send these codes on some keypresses, depending on
352434
* 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)
457539
return 0;
458540
}
459541

542+
static int asus_kbd_set_fn_lock(struct hid_device *hdev, bool enabled)
543+
{
544+
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xd0, 0x4e, !!enabled };
545+
546+
return asus_kbd_set_report(hdev, buf, sizeof(buf));
547+
}
548+
549+
static void asus_sync_fn_lock(struct work_struct *work)
550+
{
551+
struct asus_drvdata *drvdata =
552+
container_of(work, struct asus_drvdata, fn_lock_sync_work);
553+
554+
asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock);
555+
}
556+
460557
static void asus_schedule_work(struct asus_kbd_leds *led)
461558
{
462559
unsigned long flags;
@@ -928,6 +1025,12 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
9281025
asus_kbd_register_leds(hdev))
9291026
hid_warn(hdev, "Failed to initialize backlight.\n");
9301027

1028+
if (drvdata->quirks & QUIRK_HID_FN_LOCK) {
1029+
drvdata->fn_lock = true;
1030+
INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock);
1031+
asus_kbd_set_fn_lock(hdev, true);
1032+
}
1033+
9311034
return 0;
9321035
}
9331036

@@ -1259,6 +1362,9 @@ static void asus_remove(struct hid_device *hdev)
12591362
cancel_work_sync(&drvdata->kbd_backlight->work);
12601363
}
12611364

1365+
if (drvdata->quirks & QUIRK_HID_FN_LOCK)
1366+
cancel_work_sync(&drvdata->fn_lock_sync_work);
1367+
12621368
hid_hw_stop(hdev);
12631369
}
12641370

@@ -1386,7 +1492,7 @@ static const struct hid_device_id asus_devices[] = {
13861492
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
13871493
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
13881494
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2),
1389-
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
1495+
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_HID_FN_LOCK },
13901496
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
13911497
USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR),
13921498
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },

include/linux/platform_data/x86/asus-wmi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */
2828
#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
2929
#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
30+
#define ASUS_WMI_METHODID_NOTIF 0x00100021 /* Notify method */
3031

3132
#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
3233

0 commit comments

Comments
 (0)