From 047e589c8b3afbe92382f9c3072d100bcc590d72 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Sun, 8 Sep 2024 01:51:44 +0200 Subject: kernel 6.10.7 --- ...d-ally-x-dmi-quirk-for-controller-suspend.patch | 28 - .../0001-patch_realtek-Fix-ROG-ALLY-X-audio.patch | 50 - SOURCES/Patchlist.changelog | 24 + SOURCES/asus-linux.patch | 6459 ++++++++++++++------ SOURCES/dcn32-dcn301-dcn321-mpo-reverts.patch | 4 +- SOURCES/kernel-aarch64-16k-debug-fedora.config | 2 + SOURCES/kernel-aarch64-16k-fedora.config | 2 + SOURCES/kernel-aarch64-64k-debug-rhel.config | 2 + SOURCES/kernel-aarch64-64k-rhel.config | 2 + SOURCES/kernel-aarch64-debug-fedora.config | 2 + SOURCES/kernel-aarch64-debug-rhel.config | 2 + SOURCES/kernel-aarch64-fedora.config | 2 + SOURCES/kernel-aarch64-rhel.config | 2 + SOURCES/kernel-aarch64-rt-debug-rhel.config | 2 + SOURCES/kernel-aarch64-rt-rhel.config | 2 + SOURCES/kernel-ppc64le-debug-fedora.config | 2 + SOURCES/kernel-ppc64le-debug-rhel.config | 2 + SOURCES/kernel-ppc64le-fedora.config | 2 + SOURCES/kernel-ppc64le-rhel.config | 2 + SOURCES/kernel-s390x-debug-fedora.config | 2 + SOURCES/kernel-s390x-debug-rhel.config | 2 + SOURCES/kernel-s390x-fedora.config | 2 + SOURCES/kernel-s390x-rhel.config | 2 + SOURCES/kernel-s390x-zfcpdump-rhel.config | 2 + SOURCES/kernel-x86_64-debug-fedora.config | 2 + SOURCES/kernel-x86_64-debug-rhel.config | 2 + SOURCES/kernel-x86_64-fedora.config | 2 + SOURCES/kernel-x86_64-rhel.config | 2 + SOURCES/kernel-x86_64-rt-debug-rhel.config | 2 + SOURCES/kernel-x86_64-rt-rhel.config | 2 + SOURCES/kernel.changelog | 14 + SOURCES/linux-surface.patch | 223 +- SOURCES/patch-6.10-redhat.patch | 191 +- SOURCES/t2linux.patch | 4 +- ...-0004-HID-asus-add-ROG-Ally-xpad-settings.patch | 2320 ------- 35 files changed, 4763 insertions(+), 4604 deletions(-) delete mode 100644 SOURCES/0001-add-ally-x-dmi-quirk-for-controller-suspend.patch delete mode 100644 SOURCES/0001-patch_realtek-Fix-ROG-ALLY-X-audio.patch delete mode 100644 SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch (limited to 'SOURCES') diff --git a/SOURCES/0001-add-ally-x-dmi-quirk-for-controller-suspend.patch b/SOURCES/0001-add-ally-x-dmi-quirk-for-controller-suspend.patch deleted file mode 100644 index bffa8c5..0000000 --- a/SOURCES/0001-add-ally-x-dmi-quirk-for-controller-suspend.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 79d958eccfa4a1cfbb552032e9542f03333005e7 Mon Sep 17 00:00:00 2001 -From: antheas -Date: Mon, 15 Jul 2024 00:00:45 +0300 -Subject: [PATCH] add ally x dmi quirk for controller suspend - ---- - drivers/platform/x86/asus-wmi.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index 3f9b6285c9a6..8e362726b703 100644 ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -4645,8 +4645,10 @@ static int asus_wmi_add(struct platform_device *pdev) - asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); - asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); - asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); -- asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) -- && dmi_match(DMI_BOARD_NAME, "RC71L"); -+ asus->ally_mcu_usb_switch = -+ acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) && -+ (dmi_match(DMI_BOARD_NAME, "RC71L") || -+ dmi_match(DMI_BOARD_NAME, "RC72LA")); - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) - asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; --- -2.45.2 diff --git a/SOURCES/0001-patch_realtek-Fix-ROG-ALLY-X-audio.patch b/SOURCES/0001-patch_realtek-Fix-ROG-ALLY-X-audio.patch deleted file mode 100644 index bcb222a..0000000 --- a/SOURCES/0001-patch_realtek-Fix-ROG-ALLY-X-audio.patch +++ /dev/null @@ -1,50 +0,0 @@ -From ac9fa29b679959fc58c9180942a74e6687a63584 Mon Sep 17 00:00:00 2001 -From: Jonathan LoBue -Date: Thu, 25 Jul 2024 08:22:38 -0700 -Subject: [PATCH] ALSA: hda/realtek: tas2781: Fix ROG ALLY X audio - -Fix the loading of the proper TI TAS2781 amplifier -for the ROG ALLY X, while keeping the other Realtek -codec and pin portions from original ROG ALLY. - -Add proper credit and tag lines before submitting... -This patch is for sharing and testing (6.10.1) ---- - sound/pci/hda/patch_realtek.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index 766f0b1..8d118df 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -7409,6 +7409,7 @@ enum { - ALC285_FIXUP_THINKPAD_X1_GEN7, - ALC285_FIXUP_THINKPAD_HEADSET_JACK, - ALC294_FIXUP_ASUS_ALLY, -+ ALC294_FIXUP_ASUS_ALLY_X, - ALC294_FIXUP_ASUS_ALLY_PINS, - ALC294_FIXUP_ASUS_ALLY_VERBS, - ALC294_FIXUP_ASUS_ALLY_SPEAKER, -@@ -8875,6 +8876,12 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS - }, -+ [ALC294_FIXUP_ASUS_ALLY_X] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = tas2781_fixup_i2c, -+ .chained = true, -+ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS -+ }, - [ALC294_FIXUP_ASUS_ALLY_PINS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { -@@ -10306,6 +10313,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), - SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY), -+ SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X), - SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), - SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), --- -2.45.2 diff --git a/SOURCES/Patchlist.changelog b/SOURCES/Patchlist.changelog index b93cf59..f1b9625 100644 --- a/SOURCES/Patchlist.changelog +++ b/SOURCES/Patchlist.changelog @@ -1,3 +1,27 @@ +https://gitlab.com/cki-project/kernel-ark/-/commit/378f837843ce9ccefbf401f707cda2c10c03b258 + 378f837843ce9ccefbf401f707cda2c10c03b258 Revert the F39 commits which should not have pushed + +https://gitlab.com/cki-project/kernel-ark/-/commit/617f0465246a2629c0ce735529f0addaacba0604 + 617f0465246a2629c0ce735529f0addaacba0604 KVM: PPC: Book3S HV nestedv2: Keep nested guest HASHPKEYR in sync + +https://gitlab.com/cki-project/kernel-ark/-/commit/713ce2b8136985b1a7ff2ec6dc3c75ebbf4e3ddd + 713ce2b8136985b1a7ff2ec6dc3c75ebbf4e3ddd KVM: PPC: Book3S HV: Add one-reg interface for HASHPKEYR register + +https://gitlab.com/cki-project/kernel-ark/-/commit/3a7a0b70797b9e19312547345f0fd84595458302 + 3a7a0b70797b9e19312547345f0fd84595458302 KVM: PPC: Book3S HV nestedv2: Keep nested guest HASHKEYR in sync + +https://gitlab.com/cki-project/kernel-ark/-/commit/aab7db47edcfacd592b7483fa0371bf8d23e8b6f + aab7db47edcfacd592b7483fa0371bf8d23e8b6f KVM: PPC: Book3S HV: Add one-reg interface for HASHKEYR register + +https://gitlab.com/cki-project/kernel-ark/-/commit/1d5f5405eb8b0023aefe21d56558d742e2b558ea + 1d5f5405eb8b0023aefe21d56558d742e2b558ea KVM: PPC: Book3S HV nestedv2: Keep nested guest DEXCR in sync + +https://gitlab.com/cki-project/kernel-ark/-/commit/3eec751027838fde380aee0676b2bb9806a01a75 + 3eec751027838fde380aee0676b2bb9806a01a75 KVM: PPC: Book3S HV: Add one-reg interface for DEXCR register + +https://gitlab.com/cki-project/kernel-ark/-/commit/c3be1c8ba3dc3a70fb65546e836193ce584de02b + c3be1c8ba3dc3a70fb65546e836193ce584de02b Revert "cpupower: Bump soname version" + https://gitlab.com/cki-project/kernel-ark/-/commit/d42657488c703c24d1fffaecced0b3b82d30b393 d42657488c703c24d1fffaecced0b3b82d30b393 selinux: revert our use of vma_is_initial_heap() diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch index d7817b7..e22d980 100644 --- a/SOURCES/asus-linux.patch +++ b/SOURCES/asus-linux.patch @@ -1,2087 +1,4589 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sun, 10 Mar 2024 15:14:37 +1300 -Subject: [PATCH] asus-linux +From: Jan200101 +Date: Sun, 8 Sep 2024 01:49:57 +0200 +Subject: [PATCH] asus-linux 6.10.6 Signed-off-by: Jan200101 --- - .../ABI/testing/sysfs-platform-asus-wmi | 23 +- - drivers/hid/hid-asus.c | 7 + - drivers/hid/hid-ids.h | 1 + - drivers/platform/x86/Kconfig | 14 + - drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/asus-bios.c | 983 ++++++++++++++++++ - drivers/platform/x86/asus-bios.h | 288 +++++ - drivers/platform/x86/asus-wmi.c | 754 +++++++------- - include/linux/platform_data/x86/asus-wmi.h | 65 ++ - 9 files changed, 1735 insertions(+), 401 deletions(-) - create mode 100644 drivers/platform/x86/asus-bios.c - create mode 100644 drivers/platform/x86/asus-bios.h + drivers/hid/Kconfig | 9 + + drivers/hid/Makefile | 1 + + drivers/hid/hid-asus-ally.c | 2284 +++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 544 +++++ + drivers/hid/hid-asus.c | 29 + + drivers/hid/hid-ids.h | 3 + + drivers/platform/x86/Kconfig | 14 + + drivers/platform/x86/Makefile | 1 + + drivers/platform/x86/amd/pmf/pmf-quirks.c | 9 +- + drivers/platform/x86/asus-armoury.c | 1049 +++++++++ + drivers/platform/x86/asus-armoury.h | 259 +++ + drivers/platform/x86/asus-wmi.c | 254 ++- + drivers/platform/x86/intel/int3472/Makefile | 9 +- + drivers/platform/x86/intel/int3472/common.c | 7 + + include/linux/platform_data/x86/asus-wmi.h | 56 + + sound/pci/hda/patch_realtek.c | 8 + + 16 files changed, 4466 insertions(+), 70 deletions(-) + create mode 100644 drivers/hid/hid-asus-ally.c + create mode 100644 drivers/hid/hid-asus-ally.h + create mode 100644 drivers/platform/x86/asus-armoury.c + create mode 100644 drivers/platform/x86/asus-armoury.h -diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi -index 28144371a0f1..984a04f32fd0 100644 ---- a/Documentation/ABI/testing/sysfs-platform-asus-wmi -+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi -@@ -142,8 +142,8 @@ Contact: "Luke Jones" - Description: - Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD. - Shown on Intel+Nvidia or AMD+Nvidia based systems: -- -- * min=5, max=250 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//ppt_pl2_sppt - Date: Jun 2023 -@@ -152,8 +152,8 @@ Contact: "Luke Jones" - Description: - Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT, - on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems: -- -- * min=5, max=250 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//ppt_fppt - Date: Jun 2023 -@@ -161,7 +161,8 @@ KernelVersion: 6.5 - Contact: "Luke Jones" - Description: - Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only: -- * min=5, max=250 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//ppt_apu_sppt - Date: Jun 2023 -@@ -169,7 +170,8 @@ KernelVersion: 6.5 - Contact: "Luke Jones" - Description: - Set the APU SPPT limit. Shown on full AMD systems only: -- * min=5, max=130 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//ppt_platform_sppt - Date: Jun 2023 -@@ -177,7 +179,8 @@ KernelVersion: 6.5 - Contact: "Luke Jones" - Description: - Set the platform SPPT limit. Shown on full AMD systems only: -- * min=5, max=130 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//nv_dynamic_boost - Date: Jun 2023 -@@ -185,7 +188,8 @@ KernelVersion: 6.5 - Contact: "Luke Jones" - Description: - Set the dynamic boost limit of the Nvidia dGPU: -- * min=5, max=25 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//nv_temp_target - Date: Jun 2023 -@@ -193,7 +197,8 @@ KernelVersion: 6.5 - Contact: "Luke Jones" - Description: - Set the target temperature limit of the Nvidia dGPU: -- * min=75, max=87 -+ * min/max varies, read *_min/*_max sysfs entries -+ * -1 resets to default - - What: /sys/devices/platform//boot_sound - Date: Apr 2024 -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index 37e6d25593c2..af57a5f03193 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -492,12 +492,19 @@ static void asus_kbd_backlight_work(struct work_struct *work) - */ - static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) - { -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); - u32 value; - int ret; - - if (!IS_ENABLED(CONFIG_ASUS_WMI)) - return false; - -+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && -+ dmi_check_system(asus_use_hid_led_dmi_ids)) { -+ hid_info(hdev, "using HID for asus::kbd_backlight\n"); -+ return false; -+ } -+ - ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, - ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value); - hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value); -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 72d56ee7ce1b..8291699ec56c 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -209,6 +209,7 @@ - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 - #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 -+#define USB_DEVICE_ID_ASUSTEK_ROG_RAIKIRI_PAD 0x1abb - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe - #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b - #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 -diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 665fa9524986..b4a5a5bec7f3 100644 ---- a/drivers/platform/x86/Kconfig -+++ b/drivers/platform/x86/Kconfig -@@ -265,6 +265,18 @@ config ASUS_WIRELESS - If you choose to compile this driver as a module the module will be - called asus-wireless. +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 08446c89eff6..ea0dbe9111c4 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -164,6 +164,15 @@ config HID_ASUS + - GL553V series + - GL753V series -+config ASUS_BIOS -+ tristate "ASUS BIOS Driver" -+ depends on ACPI_WMI -+ depends on ASUS_WMI -+ select FW_ATTR_CLASS -+ help -+ Say Y here if you have a WMI aware Asus laptop and would like to use the -+ firmware_attributes API. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called asus-bios. -+ - config ASUS_WMI - tristate "ASUS WMI Driver" - depends on ACPI_WMI -@@ -276,6 +288,8 @@ config ASUS_WMI - depends on HOTPLUG_PCI - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on SERIO_I8042 || SERIO_I8042 = n -+ select ASUS_BIOS -+ select ASUS_WMI_BIOS - select INPUT_SPARSEKMAP - select LEDS_CLASS - select NEW_LEDS -diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index e1b142947067..d9b5b3f3b241 100644 ---- a/drivers/platform/x86/Makefile -+++ b/drivers/platform/x86/Makefile -@@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o - # ASUS - obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o - obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o -+obj-$(CONFIG_ASUS_BIOS) += asus-bios.o - obj-$(CONFIG_ASUS_WMI) += asus-wmi.o - obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o - obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o -diff --git a/drivers/platform/x86/asus-bios.c b/drivers/platform/x86/asus-bios.c ++config HID_ASUS_ALLY ++ tristate "Asus Ally gamepad configuration support" ++ depends on USB_HID ++ depends on LEDS_CLASS ++ depends on LEDS_CLASS_MULTICOLOR ++ select POWER_SUPPLY ++ help ++ Support for configuring the Asus ROG Ally gamepad using attributes. ++ + config HID_AUREAL + tristate "Aureal" + help +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index ce71b53ea6c5..98b346d8f783 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o + obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o + obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o + obj-$(CONFIG_HID_ASUS) += hid-asus.o ++obj-$(CONFIG_HID_ASUS_ALLY) += hid-asus-ally.o + obj-$(CONFIG_HID_AUREAL) += hid-aureal.o + obj-$(CONFIG_HID_BELKIN) += hid-belkin.o + obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c new file mode 100644 -index 000000000000..bd4c408fd062 +index 000000000000..fd3d23b2c284 --- /dev/null -+++ b/drivers/platform/x86/asus-bios.c -@@ -0,0 +1,983 @@ ++++ b/drivers/hid/hid-asus-ally.c +@@ -0,0 +1,2284 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Asus BIOS attributes driver ++ * HID driver for Asus ROG laptops and Ally + * -+ * Copyright(C) 2010 Intel Corporation. -+ * Copyright(C) 2024-2024 Luke Jones ++ * Copyright (c) 2023 Luke Jones + */ + -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include ++#include "linux/delay.h" ++#include "linux/device.h" ++#include "linux/err.h" ++#include "linux/input-event-codes.h" ++#include "linux/kstrtox.h" ++#include "linux/printk.h" ++#include "linux/slab.h" ++#include "linux/stddef.h" ++#include "linux/sysfs.h" ++#include +#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "asus-bios.h" -+#include "asus-wmi.h" -+#include "firmware_attributes_class.h" ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++#include "hid-asus-ally.h" ++ ++#define READY_MAX_TRIES 3 ++#define FEATURE_REPORT_ID 0x0d ++#define FEATURE_ROG_ALLY_REPORT_ID 0x5a ++#define FEATURE_ROG_ALLY_CODE_PAGE 0xD1 ++#define FEATURE_ROG_ALLY_REPORT_SIZE 64 ++#define ALLY_X_INPUT_REPORT_USB 0x0B ++#define ALLY_X_INPUT_REPORT_USB_SIZE 16 ++ ++#define ALLY_CFG_INTF_IN_ADDRESS 0x83 ++#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 ++#define ALLY_X_INTERFACE_ADDRESS 0x87 ++ ++#define FEATURE_KBD_LED_REPORT_ID1 0x5d ++#define FEATURE_KBD_LED_REPORT_ID2 0x5e ++ ++enum ROG_ALLY_TYPE { ++ ROG_ALLY_TYPE, ++ ROG_ALLY_TYPE_X, ++}; + -+MODULE_AUTHOR("Luke Jones "); -+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); -+MODULE_LICENSE("GPL"); ++static const struct hid_device_id rog_ally_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), ++ .driver_data = ROG_ALLY_TYPE }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), ++ .driver_data = ROG_ALLY_TYPE_X }, ++ {} ++}; + -+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" ++struct KeyCode { ++ const char *label; ++ u8 code; ++}; + -+MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); ++static const struct KeyCode gamepad_codes[] = { ++ { "PAD_A", 0x01 }, { "PAD_B", 0x02 }, { "PAD_X", 0x03 }, ++ { "PAD_Y", 0x04 }, { "PAD_LB", 0x05 }, { "PAD_RB", 0x06 }, ++ { "PAD_LS", 0x07 }, { "PAD_RS", 0x08 }, { "PAD_DPAD_UP", 0x09 }, ++ { "PAD_DPAD_DOWN", 0x0a }, { "PAD_DPAD_LEFT", 0x0b }, { "PAD_DPAD_RIGHT", 0x0c }, ++ { "PAD_VIEW", 0x11 }, { "PAD_MENU", 0x12 }, { "PAD_XBOX", 0x13 } ++}; + -+#define ASUS_MINI_LED_MODE_MASK 0x03 -+/* Standard modes for devices with only on/off */ -+#define ASUS_MINI_LED_OFF 0x00 -+#define ASUS_MINI_LED_ON 0x01 -+/* New mode on some devices, define here to clarify remapping later */ -+#define ASUS_MINI_LED_STRONG_MODE 0x02 -+/* New modes for devices with 3 mini-led mode types */ -+#define ASUS_MINI_LED_2024_WEAK 0x00 -+#define ASUS_MINI_LED_2024_STRONG 0x01 -+#define ASUS_MINI_LED_2024_OFF 0x02 ++static const struct KeyCode keyboard_codes[] = { { "KB_M1", 0x8f }, ++ { "KB_M2", 0x8e }, ++ { "KB_ESC", 0x76 }, ++ { "KB_F1", 0x50 }, ++ { "KB_F2", 0x60 }, ++ { "KB_F3", 0x40 }, ++ { "KB_F4", 0x0c }, ++ { "KB_F5", 0x03 }, ++ { "KB_F6", 0x0b }, ++ { "KB_F7", 0x80 }, ++ { "KB_F8", 0x0a }, ++ { "KB_F9", 0x01 }, ++ { "KB_F10", 0x09 }, ++ { "KB_F11", 0x78 }, ++ { "KB_F12", 0x07 }, ++ { "KB_F14", 0x10 }, ++ { "KB_F15", 0x18 }, ++ { "KB_BACKTICK", 0x0e }, ++ { "KB_1", 0x16 }, ++ { "KB_2", 0x1e }, ++ { "KB_3", 0x26 }, ++ { "KB_4", 0x25 }, ++ { "KB_5", 0x2e }, ++ { "KB_6", 0x36 }, ++ { "KB_7", 0x3d }, ++ { "KB_8", 0x3e }, ++ { "KB_9", 0x46 }, ++ { "KB_0", 0x45 }, ++ { "KB_HYPHEN", 0x4e }, ++ { "KB_EQUALS", 0x55 }, ++ { "KB_BACKSPACE", 0x66 }, ++ { "KB_TAB", 0x0d }, ++ { "KB_Q", 0x15 }, ++ { "KB_W", 0x1d }, ++ { "KB_E", 0x24 }, ++ { "KB_R", 0x2d }, ++ { "KB_T", 0x2d }, ++ { "KB_Y", 0x35 }, ++ { "KB_U", 0x3c }, ++ { "KB_I", 0x43 }, ++ { "KB_O", 0x44 }, ++ { "KB_P", 0x4d }, ++ { "KB_LBRACKET", 0x54 }, ++ { "KB_RBRACKET", 0x5b }, ++ { "KB_BACKSLASH", 0x5d }, ++ { "KB_CAPS", 0x58 }, ++ { "KB_A", 0x1c }, ++ { "KB_S", 0x1b }, ++ { "KB_D", 0x23 }, ++ { "KB_F", 0x2b }, ++ { "KB_G", 0x34 }, ++ { "KB_H", 0x33 }, ++ { "KB_J", 0x3b }, ++ { "KB_K", 0x42 }, ++ { "KB_L", 0x4b }, ++ { "KB_SEMI", 0x4c }, ++ { "KB_QUOTE", 0x52 }, ++ { "KB_RET", 0x5a }, ++ { "KB_LSHIFT", 0x88 }, ++ { "KB_Z", 0x1a }, ++ { "KB_X", 0x22 }, ++ { "KB_C", 0x21 }, ++ { "KB_V", 0x2a }, ++ { "KB_B", 0x32 }, ++ { "KB_N", 0x31 }, ++ { "KB_M", 0x3a }, ++ { "KB_COMMA", 0x41 }, ++ { "KB_PERIOD", 0x49 }, ++ { "KB_FWDSLASH", 0x4a }, ++ { "KB_RSHIFT", 0x89 }, ++ { "KB_LCTL", 0x8c }, ++ { "KB_META", 0x82 }, ++ { "KB_LALT", 0xba }, ++ { "KB_SPACE", 0x29 }, ++ { "KB_RALT", 0x8b }, ++ { "KB_MENU", 0x84 }, ++ { "KB_RCTL", 0x8d }, ++ { "KB_PRNTSCN", 0xc3 }, ++ { "KB_SCRLCK", 0x7e }, ++ { "KB_PAUSE", 0x91 }, ++ { "KB_INS", 0xc2 }, ++ { "KB_HOME", 0x94 }, ++ { "KB_PGUP", 0x96 }, ++ { "KB_DEL", 0xc0 }, ++ { "KB_END", 0x95 }, ++ { "KB_PGDWN", 0x97 }, ++ { "KB_UP_ARROW", 0x99 }, ++ { "KB_DOWN_ARROW", 0x98 }, ++ { "KB_LEFT_ARROW", 0x91 }, ++ { "KB_RIGHT_ARROW", 0x9b }, ++ { "NUMPAD_LOCK", 0x77 }, ++ { "NUMPAD_FWDSLASH", 0x90 }, ++ { "NUMPAD_ASTERISK", 0x7c }, ++ { "NUMPAD_HYPHEN", 0x7b }, ++ { "NUMPAD_0", 0x70 }, ++ { "NUMPAD_1", 0x69 }, ++ { "NUMPAD_2", 0x72 }, ++ { "NUMPAD_3", 0x7a }, ++ { "NUMPAD_4", 0x6b }, ++ { "NUMPAD_5", 0x73 }, ++ { "NUMPAD_6", 0x74 }, ++ { "NUMPAD_7", 0x6c }, ++ { "NUMPAD_8", 0x75 }, ++ { "NUMPAD_9", 0x7d }, ++ { "NUMPAD_PLUS", 0x79 }, ++ { "NUMPAD_ENTER", 0x81 }, ++ { "NUMPAD_PERIOD", 0x71 } }; ++ ++static const struct KeyCode mouse_codes[] = { { "MOUSE_LCLICK", 0x01 }, ++ { "MOUSE_RCLICK", 0x02 }, ++ { "MOUSE_MCLICK", 0x03 }, ++ { "MOUSE_WHEEL_UP", 0x04 }, ++ { "MOUSE_WHEEL_DOWN", 0x05 } }; ++ ++static const struct KeyCode media_codes[] = { ++ { "MEDIA_SCREENSHOT", 0x16 }, { "MEDIA_SHOW_KEYBOARD", 0x19 }, ++ { "MEDIA_SHOW_DESKTOP", 0x1c }, { "MEDIA_START_RECORDING", 0x1e }, ++ { "MEDIA_MIC_OFF", 0x01 }, { "MEDIA_VOL_DOWN", 0x02 }, ++ { "MEDIA_VOL_UP", 0x03 } ++}; + -+enum cpu_core_type { -+ CPU_CORE_PERF = 0, -+ CPU_CORE_POWER, ++/* The hatswitch outputs integers, we use them to index this X|Y pair */ ++static const int hat_values[][2] = { ++ { 0, 0 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, ++ { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 }, +}; + -+enum cpu_core_value { -+ CPU_CORE_DEFAULT = 0, -+ CPU_CORE_MIN, -+ CPU_CORE_MAX, -+ CPU_CORE_CURRENT, ++/* rumble packet structure */ ++struct ff_data { ++ u8 enable; ++ u8 magnitude_left; ++ u8 magnitude_right; ++ u8 magnitude_strong; ++ u8 magnitude_weak; ++ u8 pulse_sustain_10ms; ++ u8 pulse_release_10ms; ++ u8 loop_count; ++} __packed; ++ ++struct ff_report { ++ u8 report_id; ++ struct ff_data ff; ++} __packed; ++ ++struct ally_x_input_report { ++ uint16_t x, y; ++ uint16_t rx, ry; ++ uint16_t z, rz; ++ uint8_t buttons[4]; ++} __packed; ++ ++struct ally_x_device { ++ struct input_dev *input; ++ struct hid_device *hdev; ++ spinlock_t lock; ++ ++ struct ff_report *ff_packet; ++ struct work_struct output_worker; ++ bool output_worker_initialized; ++ /* Prevent multiple queued event due to the enforced delay in worker */ ++ bool update_qam_btn; ++ /* Set if the QAM and AC buttons emit Xbox and Xbox+A */ ++ bool qam_btns_steam_mode; ++ bool update_ff; +}; + -+/* Default limits for tunables available on ASUS ROG laptops */ -+#define PPT_CPU_LIMIT_MIN 5 -+#define PPT_CPU_LIMIT_MAX 150 -+#define PPT_CPU_LIMIT_DEFAULT 80 -+#define PPT_PLATFORM_MIN 5 -+#define PPT_PLATFORM_MAX 100 -+#define PPT_PLATFORM_DEFAULT 80 -+#define NVIDIA_BOOST_MIN 5 -+#define NVIDIA_BOOST_MAX 25 -+#define NVIDIA_TEMP_MIN 75 -+#define NVIDIA_TEMP_MAX 87 -+#define NVIDIA_GPU_POWER_MAX 70 ++struct ally_rgb_leds { ++ struct hid_device *hdev; ++ /* Need two dev here to enable the 3 step brightness */ ++ struct led_classdev led_bright_dev; ++ struct led_classdev_mc led_rgb_dev; ++ struct work_struct work; ++ spinlock_t lock; ++ ++ bool removed; ++ ++ /* Update the main brightness 0-2 using a single raw write */ ++ bool update_bright; ++ unsigned int brightness; ++ ++ /* Update the RGB only to keep write efficient */ ++ bool update_rgb; ++ uint8_t gamepad_red; ++ uint8_t gamepad_green; ++ uint8_t gamepad_blue; ++}; + -+/* Tunables provided by ASUS for gaming laptops */ -+struct rog_tunables { -+ u32 cpu_default; -+ u32 cpu_max; ++/* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ ++struct ally_gamepad_cfg { ++ struct hid_device *hdev; ++ struct input_dev *input; + -+ u32 platform_default; -+ u32 platform_max; ++ enum xpad_mode mode; ++ /* ++ * index: [joysticks/triggers][left(2 bytes), right(2 bytes)] ++ * joysticks: 2 bytes: inner, outer ++ * triggers: 2 bytes: lower, upper ++ * min/max: 0-64 ++ */ ++ u8 deadzones[xpad_mode_mouse][2][4]; ++ /* ++ * index: left, right ++ * max: 64 ++ */ ++ u8 vibration_intensity[xpad_mode_mouse][2]; ++ /* ++ * index: [joysticks][2 byte stepping per point] ++ * - 4 points of 2 bytes each ++ * - byte 0 of pair = stick move % ++ * - byte 1 of pair = stick response % ++ * - min/max: 1-63 ++ */ ++ bool supports_response_curves; ++ u8 response_curve[xpad_mode_mouse][2][8]; ++ /* ++ * left = byte 0, right = byte 1 ++ */ ++ bool supports_anti_deadzones; ++ u8 anti_deadzones[xpad_mode_mouse][2]; ++ /* ++ * index: [mode][phys pair][b1, b1 secondary, b2, b2 secondary, blocks of 11] ++ */ ++ u8 key_mapping[xpad_mode_mouse][btn_pair_lt_rt][MAPPING_BLOCK_LEN]; ++ /* ++ * index: [mode][button index] ++ */ ++ u8 turbo_btns[xpad_mode_mouse][TURBO_BLOCK_LEN]; ++ /* ++ * index: [joystick side][Y-stable, Y-min, Y-max, X-stable, X-min, X-max] ++ */ ++ u32 js_calibrations[2][6]; ++ /* ++ * index: [trigger side][stable, max] ++ */ ++ u32 tr_calibrations[2][2]; ++}; + -+ u32 ppt_pl1_spl; // cpu -+ u32 ppt_pl2_sppt; // cpu -+ u32 ppt_apu_sppt; // plat -+ u32 ppt_platform_sppt; // plat -+ u32 ppt_fppt; // cpu ++static struct ally_drvdata { ++ struct hid_device *hdev; ++ struct ally_x_device *ally_x; ++ struct ally_gamepad_cfg *gamepad_cfg; ++ struct ally_rgb_leds *led_rgb; ++} drvdata; + -+ u32 nv_boost_default; -+ u32 nv_boost_max; -+ u32 nv_dynamic_boost; ++static int asus_dev_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size) ++{ ++ return hid_hw_raw_request(hdev, FEATURE_REPORT_ID, out_buf, out_buf_size, ++ HID_FEATURE_REPORT, HID_REQ_GET_REPORT); ++} + -+ u32 nv_temp_default; -+ u32 nv_temp_max; -+ u32 nv_temp_target; ++static int asus_dev_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size) ++{ ++ unsigned char *dmabuf; ++ int ret; + -+ u32 min_perf_cores; -+ u32 max_perf_cores; -+ u32 max_power_cores; -+}; ++ dmabuf = kmemdup(buf, buf_size, GFP_KERNEL); ++ if (!dmabuf) ++ return -ENOMEM; + -+static const struct class *fw_attr_class; ++ ret = hid_hw_raw_request(hdev, buf[0], dmabuf, buf_size, HID_FEATURE_REPORT, ++ HID_REQ_SET_REPORT); ++ kfree(dmabuf); + -+struct asus_bios_priv { -+ struct device *fw_attr_dev; -+ struct kset *fw_attr_kset; ++ return ret; ++} + -+ struct rog_tunables *rog_tunables; -+ u32 mini_led_dev_id; -+ u32 gpu_mux_dev_id; -+ bool dgpu_disable_available; -+ bool egpu_enable_available; ++/**************************************************************************************************/ ++/* ROG Ally gamepad i/o and force-feedback */ ++/**************************************************************************************************/ ++static int ally_x_raw_event(struct ally_x_device *ally_x, struct hid_report *report, u8 *data, ++ int size) ++{ ++ struct ally_x_input_report *in_report; ++ unsigned long flags; ++ u8 byte; ++ ++ if (data[0] == 0x0B) { ++ in_report = (struct ally_x_input_report *)&data[1]; ++ ++ input_report_abs(ally_x->input, ABS_X, in_report->x); ++ input_report_abs(ally_x->input, ABS_Y, in_report->y); ++ input_report_abs(ally_x->input, ABS_RX, in_report->rx); ++ input_report_abs(ally_x->input, ABS_RY, in_report->ry); ++ input_report_abs(ally_x->input, ABS_Z, in_report->z); ++ input_report_abs(ally_x->input, ABS_RZ, in_report->rz); ++ ++ byte = in_report->buttons[0]; ++ input_report_key(ally_x->input, BTN_A, byte & BIT(0)); ++ input_report_key(ally_x->input, BTN_B, byte & BIT(1)); ++ input_report_key(ally_x->input, BTN_X, byte & BIT(2)); ++ input_report_key(ally_x->input, BTN_Y, byte & BIT(3)); ++ input_report_key(ally_x->input, BTN_TL, byte & BIT(4)); ++ input_report_key(ally_x->input, BTN_TR, byte & BIT(5)); ++ input_report_key(ally_x->input, BTN_SELECT, byte & BIT(6)); ++ input_report_key(ally_x->input, BTN_START, byte & BIT(7)); ++ ++ byte = in_report->buttons[1]; ++ input_report_key(ally_x->input, BTN_THUMBL, byte & BIT(0)); ++ input_report_key(ally_x->input, BTN_THUMBR, byte & BIT(1)); ++ input_report_key(ally_x->input, BTN_MODE, byte & BIT(2)); ++ ++ byte = in_report->buttons[2]; ++ input_report_abs(ally_x->input, ABS_HAT0X, hat_values[byte][0]); ++ input_report_abs(ally_x->input, ABS_HAT0Y, hat_values[byte][1]); ++ } ++ /* ++ * The MCU used on Ally provides many devices: gamepad, keyboord, mouse, other. ++ * The AC and QAM buttons route through another interface making it difficult to ++ * use the events unless we grab those and use them here. Only works for Ally X. ++ */ ++ else if (data[0] == 0x5A) { ++ if (ally_x->qam_btns_steam_mode) { ++ spin_lock_irqsave(&ally_x->lock, flags); ++ if (data[1] == 0x38 && !ally_x->update_qam_btn) { ++ ally_x->update_qam_btn = true; ++ if (ally_x->output_worker_initialized) ++ schedule_work(&ally_x->output_worker); ++ } ++ spin_unlock_irqrestore(&ally_x->lock, flags); ++ /* Left/XBox button. Long press does ctrl+alt+del which we can't catch */ ++ input_report_key(ally_x->input, BTN_MODE, data[1] == 0xA6); ++ } else { ++ input_report_key(ally_x->input, KEY_F16, data[1] == 0xA6); ++ input_report_key(ally_x->input, KEY_PROG1, data[1] == 0x38); ++ } ++ /* QAM long press */ ++ input_report_key(ally_x->input, KEY_F17, data[1] == 0xA7); ++ /* QAM long press released */ ++ input_report_key(ally_x->input, KEY_F18, data[1] == 0xA8); ++ } + -+ struct mutex mutex; -+} asus_bios = { -+ .mutex = __MUTEX_INITIALIZER(asus_bios.mutex), -+}; ++ input_sync(ally_x->input); + -+static struct fw_attrs_group { -+ u32 pending_reboot; -+} fw_attrs = { -+ .pending_reboot = 0, -+}; ++ return 0; ++} + -+/* WMI helper methods */ -+static bool asus_wmi_is_present(u32 dev_id) ++static struct input_dev *ally_x_alloc_input_dev(struct hid_device *hdev, ++ const char *name_suffix) +{ -+ u32 retval; -+ int status = asus_wmi_get_devstate_dsts(dev_id, &retval); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); ++ struct input_dev *input_dev; + -+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); ++ input_dev = devm_input_allocate_device(&hdev->dev); ++ if (!input_dev) ++ return ERR_PTR(-ENOMEM); ++ ++ input_dev->id.bustype = hdev->bus; ++ input_dev->id.vendor = hdev->vendor; ++ input_dev->id.product = hdev->product; ++ input_dev->id.version = hdev->version; ++ input_dev->uniq = hdev->uniq; ++ input_dev->name = "ASUS ROG Ally X Gamepad"; ++ ++ input_set_drvdata(input_dev, hdev); ++ ++ return input_dev; +} + -+static void asus_set_reboot_and_signal_event(void) ++static int ally_x_play_effect(struct input_dev *idev, void *data, struct ff_effect *effect) +{ -+ fw_attrs.pending_reboot = 1; -+ kobject_uevent(&asus_bios.fw_attr_dev->kobj, KOBJ_CHANGE); ++ struct ally_x_device *ally_x = drvdata.ally_x; ++ unsigned long flags; ++ ++ if (effect->type != FF_RUMBLE) ++ return 0; ++ ++ spin_lock_irqsave(&ally_x->lock, flags); ++ ally_x->ff_packet->ff.magnitude_strong = effect->u.rumble.strong_magnitude / 512; ++ ally_x->ff_packet->ff.magnitude_weak = effect->u.rumble.weak_magnitude / 512; ++ ally_x->update_ff = true; ++ spin_unlock_irqrestore(&ally_x->lock, flags); ++ ++ if (ally_x->output_worker_initialized) ++ schedule_work(&ally_x->output_worker); ++ ++ return 0; +} + -+static ssize_t pending_reboot_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) ++static void ally_x_work(struct work_struct *work) +{ -+ return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot); ++ struct ally_x_device *ally_x = container_of(work, struct ally_x_device, output_worker); ++ struct ff_report *ff_report = NULL; ++ bool update_qam = false; ++ bool update_ff = false; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ally_x->lock, flags); ++ update_ff = ally_x->update_ff; ++ if (ally_x->update_ff) { ++ ff_report = kmemdup(ally_x->ff_packet, sizeof(*ally_x->ff_packet), GFP_KERNEL); ++ ally_x->update_ff = false; ++ } ++ update_qam = ally_x->update_qam_btn; ++ spin_unlock_irqrestore(&ally_x->lock, flags); ++ ++ if (update_ff && ff_report) { ++ ff_report->ff.magnitude_left = ff_report->ff.magnitude_strong; ++ ff_report->ff.magnitude_right = ff_report->ff.magnitude_weak; ++ asus_dev_set_report(ally_x->hdev, (u8 *)ff_report, sizeof(*ff_report)); ++ } ++ kfree(ff_report); ++ ++ if (update_qam) { ++ /* ++ * The sleeps here are required to allow steam to register the button combo. ++ */ ++ usleep_range(1000, 2000); ++ input_report_key(ally_x->input, BTN_MODE, 1); ++ input_sync(ally_x->input); ++ ++ msleep(80); ++ input_report_key(ally_x->input, BTN_A, 1); ++ input_sync(ally_x->input); ++ ++ msleep(80); ++ input_report_key(ally_x->input, BTN_A, 0); ++ input_sync(ally_x->input); ++ ++ msleep(80); ++ input_report_key(ally_x->input, BTN_MODE, 0); ++ input_sync(ally_x->input); ++ ++ spin_lock_irqsave(&ally_x->lock, flags); ++ ally_x->update_qam_btn = false; ++ spin_unlock_irqrestore(&ally_x->lock, flags); ++ } +} + -+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); ++static struct input_dev *ally_x_setup_input(struct hid_device *hdev) ++{ ++ int ret, abs_min = 0, js_abs_max = 65535, tr_abs_max = 1023; ++ struct input_dev *input; ++ ++ input = ally_x_alloc_input_dev(hdev, NULL); ++ if (IS_ERR(input)) ++ return ERR_CAST(input); ++ ++ input_set_abs_params(input, ABS_X, abs_min, js_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_Y, abs_min, js_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_RX, abs_min, js_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_RY, abs_min, js_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_Z, abs_min, tr_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_RZ, abs_min, tr_abs_max, 0, 0); ++ input_set_abs_params(input, ABS_HAT0X, -1, 1, 0, 0); ++ input_set_abs_params(input, ABS_HAT0Y, -1, 1, 0, 0); ++ input_set_capability(input, EV_KEY, BTN_A); ++ input_set_capability(input, EV_KEY, BTN_B); ++ input_set_capability(input, EV_KEY, BTN_X); ++ input_set_capability(input, EV_KEY, BTN_Y); ++ input_set_capability(input, EV_KEY, BTN_TL); ++ input_set_capability(input, EV_KEY, BTN_TR); ++ input_set_capability(input, EV_KEY, BTN_SELECT); ++ input_set_capability(input, EV_KEY, BTN_START); ++ input_set_capability(input, EV_KEY, BTN_MODE); ++ input_set_capability(input, EV_KEY, BTN_THUMBL); ++ input_set_capability(input, EV_KEY, BTN_THUMBR); ++ ++ input_set_capability(input, EV_KEY, KEY_PROG1); ++ input_set_capability(input, EV_KEY, KEY_F16); ++ input_set_capability(input, EV_KEY, KEY_F17); ++ input_set_capability(input, EV_KEY, KEY_F18); ++ ++ input_set_capability(input, EV_FF, FF_RUMBLE); ++ input_ff_create_memless(input, NULL, ally_x_play_effect); ++ ++ ret = input_register_device(input); ++ if (ret) ++ return ERR_PTR(ret); + -+static bool asus_bios_requires_reboot(struct kobj_attribute *attr) { -+ return !strcmp(attr->attr.name, "gpu_mux_mode") || -+ !strcmp(attr->attr.name, "panel_hd_mode"); ++ return input; +} + -+/* -+ * Generic store function for use with many ROG tunables -+ */ -+static ssize_t attr_int_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count, -+ u32 min, u32 max, u32 *store_value, u32 wmi_dev) ++static ssize_t ally_x_qam_mode_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ int result, value; ++ struct ally_x_device *ally_x = drvdata.ally_x; + -+ result = kstrtoint(buf, 10, &value); -+ if (result) -+ return result; ++ return sysfs_emit(buf, "%d\n", ally_x->qam_btns_steam_mode); ++} + -+ if (value < min || value > max) -+ return -EINVAL; ++static ssize_t ally_x_qam_mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ally_x_device *ally_x = drvdata.ally_x; ++ bool val; ++ int ret; + -+ asus_wmi_set_devstate(wmi_dev, value, &result); -+ if (result) { -+ pr_err("Failed to set %s: %d\n", attr->attr.name, result); -+ return result; -+ } ++ ret = kstrtobool(buf, &val); ++ if (ret < 0) ++ return ret; + -+ if (result > 1) { -+ pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result); -+ return -EIO; ++ ally_x->qam_btns_steam_mode = val; ++ ++ return count; ++} ++ALLY_DEVICE_ATTR_RW(ally_x_qam_mode, qam_mode); ++ ++static struct ally_x_device *ally_x_create(struct hid_device *hdev) ++{ ++ uint8_t max_output_report_size; ++ struct ally_x_device *ally_x; ++ struct ff_report *report; ++ int ret; ++ ++ ally_x = devm_kzalloc(&hdev->dev, sizeof(*ally_x), GFP_KERNEL); ++ if (!ally_x) ++ return ERR_PTR(-ENOMEM); ++ ++ ally_x->hdev = hdev; ++ INIT_WORK(&ally_x->output_worker, ally_x_work); ++ spin_lock_init(&ally_x->lock); ++ ally_x->output_worker_initialized = true; ++ ally_x->qam_btns_steam_mode = ++ true; /* Always default to steam mode, it can be changed by userspace attr */ ++ ++ max_output_report_size = sizeof(struct ally_x_input_report); ++ report = devm_kzalloc(&hdev->dev, sizeof(*report), GFP_KERNEL); ++ if (!report) { ++ ret = -ENOMEM; ++ goto free_ally_x; + } + -+ if (store_value != NULL) -+ *store_value = value; -+ sysfs_notify(kobj, NULL, attr->attr.name); ++ /* None of these bytes will change for the FF command for now */ ++ report->report_id = 0x0D; ++ report->ff.enable = 0x0F; /* Enable all by default */ ++ report->ff.pulse_sustain_10ms = 0xFF; /* Duration */ ++ report->ff.pulse_release_10ms = 0x00; /* Start Delay */ ++ report->ff.loop_count = 0xEB; /* Loop Count */ ++ ally_x->ff_packet = report; ++ ++ ally_x->input = ally_x_setup_input(hdev); ++ if (IS_ERR(ally_x->input)) { ++ ret = PTR_ERR(ally_x->input); ++ goto free_ff_packet; ++ } + -+ if (asus_bios_requires_reboot(attr)) -+ asus_set_reboot_and_signal_event(); ++ if (sysfs_create_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr)) { ++ ret = -ENODEV; ++ goto unregister_input; ++ } + -+ return count; ++ ally_x->update_ff = true; ++ if (ally_x->output_worker_initialized) ++ schedule_work(&ally_x->output_worker); ++ ++ hid_info(hdev, "Registered Ally X controller using %s\n", ++ dev_name(&ally_x->input->dev)); ++ return ally_x; ++ ++unregister_input: ++ input_unregister_device(ally_x->input); ++free_ff_packet: ++ kfree(ally_x->ff_packet); ++free_ally_x: ++ kfree(ally_x); ++ return ERR_PTR(ret); +} + -+/* Mini-LED mode **************************************************************/ -+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static void ally_x_remove(struct hid_device *hdev) +{ -+ u32 value; -+ int err; -+ -+ err = asus_wmi_get_devstate_dsts(asus_bios.mini_led_dev_id, &value); -+ if (err) -+ return err; ++ struct ally_x_device *ally_x = drvdata.ally_x; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ally_x->lock, flags); ++ ally_x->output_worker_initialized = false; ++ spin_unlock_irqrestore(&ally_x->lock, flags); ++ cancel_work_sync(&ally_x->output_worker); ++ sysfs_remove_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr); ++} + -+ value = value & ASUS_MINI_LED_MODE_MASK; ++/**************************************************************************************************/ ++/* ROG Ally configuration */ ++/**************************************************************************************************/ ++static int __gamepad_write_all_to_mcu(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg); + -+ /* -+ * Remap the mode values to match previous generation mini-led. The last gen -+ * WMI 0 == off, while on this version WMI 2 ==off (flipped). -+ */ -+ if (asus_bios.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (value) { -+ case ASUS_MINI_LED_2024_WEAK: -+ value = ASUS_MINI_LED_ON; -+ break; -+ case ASUS_MINI_LED_2024_STRONG: -+ value = ASUS_MINI_LED_STRONG_MODE; -+ break; -+ case ASUS_MINI_LED_2024_OFF: -+ value = ASUS_MINI_LED_OFF; -+ break; ++static int process_key_code(const struct KeyCode *codes, int code_count, const char *buf_copy, ++ u8 *out, int out_idx) ++{ ++ for (int i = 0; i < code_count; i++) { ++ if (strcmp(buf_copy, codes[i].label) == 0) { ++ out[out_idx] = codes[i].code; ++ return 0; // Found + } + } -+ -+ return sysfs_emit(buf, "%d\n", value); ++ return -EINVAL; // Not found +} + -+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++static int __string_to_key_code(const char *buf, u8 *out, int out_len) +{ -+ int result, err; -+ u32 mode; -+ -+ result = kstrtou32(buf, 10, &mode); -+ if (result) -+ return result; ++ char buf_copy[32]; ++ u8 *save_buf; + -+ if (asus_bios.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && -+ mode > ASUS_MINI_LED_ON) -+ return -EINVAL; -+ if (asus_bios.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && -+ mode > ASUS_MINI_LED_STRONG_MODE) ++ if (out_len != BTN_CODE_LEN) + return -EINVAL; + -+ /* -+ * Remap the mode values so expected behaviour is the same as the last -+ * generation of mini-LED with 0 == off, 1 == on. -+ */ -+ if (asus_bios.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (mode) { -+ case ASUS_MINI_LED_OFF: -+ mode = ASUS_MINI_LED_2024_OFF; -+ break; -+ case ASUS_MINI_LED_ON: -+ mode = ASUS_MINI_LED_2024_WEAK; -+ break; -+ case ASUS_MINI_LED_STRONG_MODE: -+ mode = ASUS_MINI_LED_2024_STRONG; -+ break; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(asus_bios.mini_led_dev_id, mode, &result); -+ if (err) { -+ pr_warn("Failed to set mini-LED: %d\n", err); -+ return err; -+ } ++ save_buf = kzalloc(out_len, GFP_KERNEL); ++ if (!save_buf) ++ return -ENOMEM; ++ memcpy(save_buf, out, out_len); ++ memset(out, 0, out_len); /* always clear before adjusting */ ++ ++ strscpy(buf_copy, buf); ++ buf_copy[strcspn(buf_copy, "\n")] = 0; ++ ++ /* Gamepad group */ ++ out[0] = 0x01; ++ if (process_key_code(gamepad_codes, ARRAY_SIZE(gamepad_codes), buf_copy, out, 1) == 0) ++ goto success; ++ ++ /* Keyboard group */ ++ out[0] = 0x02; ++ if (process_key_code(keyboard_codes, ARRAY_SIZE(keyboard_codes), buf_copy, out, 2) == 0) ++ goto success; ++ ++ /* Mouse group */ ++ out[0] = 0x03; ++ if (process_key_code(mouse_codes, ARRAY_SIZE(mouse_codes), buf_copy, out, 4) == 0) ++ goto success; ++ ++ /* Media group */ ++ out[0] = 0x05; ++ if (process_key_code(media_codes, ARRAY_SIZE(media_codes), buf_copy, out, 3) == 0) ++ goto success; ++ ++ /* Restore bytes if invalid input */ ++ memcpy(out, save_buf, out_len); ++ kfree(save_buf); ++ return -EINVAL; ++ ++success: ++ kfree(save_buf); ++ return 0; ++} + -+ if (result > 1) { -+ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); -+ return -EIO; ++static const char *key_code_to_string(const struct KeyCode *codes, int code_count, u8 code) ++{ ++ for (int i = 0; i < code_count; i++) { ++ if (codes[i].code == code) ++ return codes[i].label; + } ++ return ""; ++} + -+ sysfs_notify(kobj, NULL, attr->attr.name); ++static u8 *__get_btn_block(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, ++ enum btn_pair_side side, bool secondary) ++{ ++ int offs; + -+ return count; ++ offs = side ? MAPPING_BLOCK_LEN / 2 : 0; ++ offs = secondary ? offs + BTN_CODE_LEN : offs; ++ return ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1] + offs; +} + -+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static const char *__btn_map_to_string(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, ++ enum btn_pair_side side, bool secondary) +{ -+ switch (asus_bios.mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ return sysfs_emit(buf, "0;1\n"); -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ return sysfs_emit(buf, "0;1;2\n"); ++ u8 *out_arg = __get_btn_block(ally_cfg, pair, side, secondary); ++ ++ switch (out_arg[0]) { ++ case 0x01: // Gamepad buttons ++ return key_code_to_string(gamepad_codes, ARRAY_SIZE(gamepad_codes), out_arg[1]); ++ case 0x02: // Keyboard keys ++ return key_code_to_string(keyboard_codes, ARRAY_SIZE(keyboard_codes), ++ out_arg[2]); ++ case 0x03: // Mouse buttons ++ return key_code_to_string(mouse_codes, ARRAY_SIZE(mouse_codes), out_arg[4]); ++ case 0x05: // Media controls ++ return key_code_to_string(media_codes, ARRAY_SIZE(media_codes), out_arg[3]); ++ default: ++ return ""; + } -+ -+ return sysfs_emit(buf, "0\n"); +} + -+ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); ++/* ASUS ROG Ally device specific attributes */ + -+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++/* This should be called before any attempts to set device functions */ ++static int __gamepad_check_ready(struct hid_device *hdev) +{ -+ int result, err; -+ u32 optimus; -+ -+ err = kstrtou32(buf, 10, &optimus); -+ if (err) -+ return err; ++ int ret, count; ++ u8 *hidbuf; + -+ if (optimus > 1) -+ return -EINVAL; ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; + -+ if (asus_bios.dgpu_disable_available) { -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result); -+ if (err) -+ return err; -+ if (err && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); -+ return err; -+ } ++ ret = 0; ++ for (count = 0; count < READY_MAX_TRIES; count++) { ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_check_ready; ++ hidbuf[3] = 01; ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret); ++ ++ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0; ++ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret); ++ ++ ret = hidbuf[2] == xpad_cmd_check_ready; ++ if (ret) ++ break; ++ usleep_range( ++ 1000, ++ 2000); /* don't spam the entire loop in less than USB response time */ + } + -+ if (asus_bios.egpu_enable_available) { -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result); -+ if (err) -+ return err; -+ if (result && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); -+ return err; -+ } -+ } ++ if (count == READY_MAX_TRIES) ++ hid_warn(hdev, "ROG Ally never responded with a ready\n"); + -+ err = asus_wmi_set_devstate(asus_bios.gpu_mux_dev_id, optimus, &result); -+ if (err) { -+ pr_err("%s Failed to set GPU MUX mode: %d\nn", __func__, err); -+ return err; -+ } -+ /* !1 is considered a fail by ASUS */ -+ if (result != 1) { -+ pr_warn("%s Failed to set GPU MUX mode (result): 0x%x\n", __func__, result); -+ return -EIO; -+ } ++ kfree(hidbuf); ++ return ret; ++} + -+ sysfs_notify(kobj, NULL, attr->attr.name); ++/* BUTTON REMAPPING *******************************************************************************/ ++static void __btn_pair_to_pkt(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, u8 *out, ++ int out_len) ++{ ++ out[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ out[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ out[2] = xpad_cmd_set_mapping; ++ out[3] = pair; ++ out[4] = xpad_cmd_len_mapping; ++ memcpy(&out[5], &ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1], ++ MAPPING_BLOCK_LEN); ++} + -+ return count; ++/* Store the button setting in driver data. Does not apply to device until __gamepad_set_mapping */ ++static int __gamepad_mapping_store(struct ally_gamepad_cfg *ally_cfg, const char *buf, ++ enum btn_pair pair, int side, bool secondary) ++{ ++ u8 *out_arg; ++ ++ out_arg = __get_btn_block(ally_cfg, pair, side, secondary); ++ ++ return __string_to_key_code(buf, out_arg, BTN_CODE_LEN); +} -+WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_bios.gpu_mux_dev_id); -+ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); + -+/* -+ * A user may be required to store the value twice, typcial store first, then -+ * rescan PCI bus to activate power, then store a second time to save correctly. -+ * The reason for this is that an extra code path in the ACPI is enabled when -+ * the device and bus are powered. -+ */ -+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++/* Apply the mapping pair to the device */ ++static int __gamepad_set_mapping(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, ++ enum btn_pair pair) +{ -+ int result, err; -+ u32 disable; ++ u8 *hidbuf; ++ int ret; + -+ result = kstrtou32(buf, 10, &disable); -+ if (result) -+ return result; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; + -+ if (disable > 1) -+ return -EINVAL; ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; + -+ if (asus_bios.gpu_mux_dev_id) { -+ err = asus_wmi_get_devstate_dsts(asus_bios.gpu_mux_dev_id, &result); -+ if (err) -+ return err; -+ if (!result && disable) { -+ err = -ENODEV; -+ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } ++ __btn_pair_to_pkt(ally_cfg, pair, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); + -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); -+ if (err) { -+ pr_warn("Failed to set dgpu disable: %d\n", err); -+ return err; -+ } ++ kfree(hidbuf); + -+ if (result > 1) { -+ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); -+ return -EIO; -+ } ++ return ret; ++} + -+ sysfs_notify(kobj, NULL, attr->attr.name); ++static ssize_t btn_mapping_apply_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ struct hid_device *hdev = to_hid_device(dev); ++ int ret; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ ret = __gamepad_write_all_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; + + return count; +} -+WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU); -+ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU"); ++ALLY_DEVICE_ATTR_WO(btn_mapping_apply, apply_all); + -+/* The ACPI call to enable the eGPU also disables the internal dGPU */ -+static ssize_t egpu_enable_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++/* BUTTON TURBO ***********************************************************************************/ ++static int __btn_turbo_index(enum btn_pair pair, int side) +{ -+ int result, err; -+ u32 enable; ++ return (pair - 1) * (2 * TURBO_BLOCK_STEP) + (side * TURBO_BLOCK_STEP); ++}; + -+ err = kstrtou32(buf, 10, &enable); -+ if (err) -+ return err; ++static int __gamepad_turbo_show(struct device *dev, enum btn_pair pair, int side) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; + -+ if (enable > 1) -+ return -EINVAL; ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result); -+ if (err) { -+ pr_warn("Failed to get egpu connection status: %d\n", err); -+ return err; -+ } ++ return ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)]; ++}; + -+ if (asus_bios.gpu_mux_dev_id) { -+ err = asus_wmi_get_devstate_dsts(asus_bios.gpu_mux_dev_id, &result); -+ if (err) { -+ pr_warn("Failed to get gpu mux status: %d\n", result); -+ return result; -+ } -+ if (!result && enable) { -+ err = -ENODEV; -+ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } ++static int __gamepad_turbo_store(struct device *dev, const char *buf, enum btn_pair pair, ++ int side) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int ret, val; + -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); -+ if (err) { -+ pr_warn("Failed to set egpu state: %d\n", err); -+ return err; -+ } ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ if (result > 1) { -+ pr_warn("Failed to set egpu state (retval): 0x%x\n", result); -+ return -EIO; -+ } ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ if (val < 0 || val > 16) ++ return -EINVAL; + -+ sysfs_notify(kobj, NULL, attr->attr.name); ++ ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)] = val; + -+ return count; ++ return 0; ++}; ++ ++/* button map attributes, regular and macro*/ ++ALLY_BTN_MAPPING(m2, btn_pair_m1_m2, btn_pair_side_left); ++ALLY_BTN_MAPPING(m1, btn_pair_m1_m2, btn_pair_side_right); ++ALLY_BTN_MAPPING(a, btn_pair_a_b, btn_pair_side_left); ++ALLY_BTN_MAPPING(b, btn_pair_a_b, btn_pair_side_right); ++ALLY_BTN_MAPPING(x, btn_pair_x_y, btn_pair_side_left); ++ALLY_BTN_MAPPING(y, btn_pair_x_y, btn_pair_side_right); ++ALLY_BTN_MAPPING(lb, btn_pair_lb_rb, btn_pair_side_left); ++ALLY_BTN_MAPPING(rb, btn_pair_lb_rb, btn_pair_side_right); ++ALLY_BTN_MAPPING(ls, btn_pair_ls_rs, btn_pair_side_left); ++ALLY_BTN_MAPPING(rs, btn_pair_ls_rs, btn_pair_side_right); ++ALLY_BTN_MAPPING(lt, btn_pair_lt_rt, btn_pair_side_left); ++ALLY_BTN_MAPPING(rt, btn_pair_lt_rt, btn_pair_side_right); ++ALLY_BTN_MAPPING(dpad_u, btn_pair_dpad_u_d, btn_pair_side_left); ++ALLY_BTN_MAPPING(dpad_d, btn_pair_dpad_u_d, btn_pair_side_right); ++ALLY_BTN_MAPPING(dpad_l, btn_pair_dpad_l_r, btn_pair_side_left); ++ALLY_BTN_MAPPING(dpad_r, btn_pair_dpad_l_r, btn_pair_side_right); ++ALLY_BTN_MAPPING(view, btn_pair_view_menu, btn_pair_side_left); ++ALLY_BTN_MAPPING(menu, btn_pair_view_menu, btn_pair_side_right); ++ ++static void __gamepad_mapping_xpad_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ memcpy(&ally_cfg->key_mapping[0][0], &XPAD_DEF1, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][1], &XPAD_DEF2, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][2], &XPAD_DEF3, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][3], &XPAD_DEF4, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][4], &XPAD_DEF5, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][5], &XPAD_DEF6, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][6], &XPAD_DEF7, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][7], &XPAD_DEF8, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[0][8], &XPAD_DEF9, MAPPING_BLOCK_LEN); +} -+WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU); -+ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); + -+/* Device memory available to APU */ ++static void __gamepad_mapping_wasd_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ memcpy(&ally_cfg->key_mapping[1][0], &WASD_DEF1, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][1], &WASD_DEF2, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][2], &WASD_DEF3, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][3], &WASD_DEF4, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][4], &WASD_DEF5, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][5], &WASD_DEF6, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][6], &WASD_DEF7, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][7], &WASD_DEF8, MAPPING_BLOCK_LEN); ++ memcpy(&ally_cfg->key_mapping[1][8], &WASD_DEF9, MAPPING_BLOCK_LEN); ++} + -+static ssize_t apu_mem_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t btn_mapping_reset_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ int err; -+ u32 mem; ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; + -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem); -+ if (err) -+ return err; ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ switch (mem) { -+ case 256: -+ mem = 0; ++ switch (ally_cfg->mode) { ++ case xpad_mode_game: ++ __gamepad_mapping_xpad_default(ally_cfg); + break; -+ case 258: -+ mem = 1; -+ break; -+ case 259: -+ mem = 2; -+ break; -+ case 260: -+ mem = 3; -+ break; -+ case 261: -+ mem = 4; -+ break; -+ case 262: -+ /* This is out of order and looks wrong but is correct */ -+ mem = 8; -+ break; -+ case 263: -+ mem = 5; -+ break; -+ case 264: -+ mem = 6; -+ break; -+ case 265: -+ mem = 7; ++ case xpad_mode_wasd: ++ __gamepad_mapping_wasd_default(ally_cfg); + break; + default: -+ mem = 4; ++ __gamepad_mapping_xpad_default(ally_cfg); + break; + } + -+ return sysfs_emit(buf, "%d\n", mem); ++ return count; +} + -+static ssize_t apu_mem_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping); ++ ++/* GAMEPAD MODE ***********************************************************************************/ ++static ssize_t __gamepad_set_mode(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, ++ int val) +{ -+ int result, err; -+ u32 requested, mem; ++ u8 *hidbuf; ++ int ret; + -+ result = kstrtou32(buf, 10, &requested); -+ if (result) -+ return result; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; + -+ switch (requested) { -+ case 0: -+ mem = 0; -+ break; -+ case 1: -+ mem = 258; -+ break; -+ case 2: -+ mem = 259; -+ break; -+ case 3: -+ mem = 260; -+ break; -+ case 4: -+ mem = 261; -+ break; -+ case 5: -+ mem = 263; -+ break; -+ case 6: -+ mem = 264; -+ break; -+ case 7: -+ mem = 265; -+ break; -+ case 8: -+ /* This is outof order and looks wrong but is correct */ -+ mem = 262; -+ break; -+ default: -+ return -EIO; -+ } ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; + -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result); -+ if (err) { -+ pr_warn("Failed to set apu_mem: %d\n", err); -+ return err; -+ } ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_mode; ++ hidbuf[3] = xpad_cmd_len_mode; ++ hidbuf[4] = val; + -+ pr_info("APU memory changed to %dGB, reboot required\n", requested); -+ sysfs_notify(kobj, NULL, attr->attr.name); ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; + -+ asus_set_reboot_and_signal_event(); ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; + -+ return count; ++ ret = __gamepad_write_all_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ goto report_fail; ++ ++report_fail: ++ kfree(hidbuf); ++ return ret; +} + -+static ssize_t apu_mem_possible_values_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t gamepad_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ -+ return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n"); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ return sysfs_emit(buf, "%d\n", ally_cfg->mode); +} -+ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory for the APU to use"); + -+static int asus_bios_set_max_cores(void) ++static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ u32 cores; -+ int err; ++ struct hid_device *hdev = to_hid_device(dev); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int ret, val; + -+ asus_bios.rog_tunables->min_perf_cores = 4; -+ asus_bios.rog_tunables->max_perf_cores = 4; -+ asus_bios.rog_tunables->max_power_cores = 8; ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores); -+ if (err) -+ return err; ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; + -+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ asus_bios.rog_tunables->max_power_cores = (cores & 0xff00) >> 8; -+ asus_bios.rog_tunables->max_perf_cores = cores & 0xff; ++ if (val < xpad_mode_game || val > xpad_mode_mouse) ++ return -EINVAL; + -+ return 0; -+} ++ ally_cfg->mode = val; + -+static ssize_t cores_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf, -+ enum cpu_core_type core_type, -+ enum cpu_core_value core_value) -+{ -+ u32 cores; -+ int err; ++ ret = __gamepad_set_mode(hdev, ally_cfg, val); ++ if (ret < 0) ++ return ret; + -+ switch (core_value) { -+ case CPU_CORE_DEFAULT: -+ case CPU_CORE_MAX: -+ if (core_type == CPU_CORE_PERF) -+ return sysfs_emit(buf, "%d\n", asus_bios.rog_tunables->max_perf_cores); -+ else -+ return sysfs_emit(buf, "%d\n", asus_bios.rog_tunables->max_power_cores); -+ case CPU_CORE_MIN: -+ if (core_type == CPU_CORE_PERF) -+ return sysfs_emit(buf, "%d\n", asus_bios.rog_tunables->min_perf_cores); -+ else -+ return sysfs_emit(buf, "%d\n", 0); -+ default: -+ break; -+ } ++ return count; ++} + -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores); -+ if (err) -+ return err; ++DEVICE_ATTR_RW(gamepad_mode); + -+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ if (core_type == CPU_CORE_PERF) -+ cores &= 0xff; -+ else -+ cores = (cores & 0xff00) >> 8; -+ return sysfs_emit(buf, "%d\n", cores); ++/* VIBRATION INTENSITY ****************************************************************************/ ++static ssize_t gamepad_vibration_intensity_index_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "left right\n"); +} + -+static ssize_t cores_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, -+ enum cpu_core_type core_type) ++ALLY_DEVICE_ATTR_RO(gamepad_vibration_intensity_index, vibration_intensity_index); ++ ++static ssize_t __gamepad_write_vibe_intensity_to_mcu(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) +{ -+ int result, err; -+ u32 cores, currentv, min, max; ++ u8 *hidbuf; ++ int ret; + -+ result = kstrtou32(buf, 10, &cores); -+ if (result) -+ return result; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; + -+ if (core_type == CPU_CORE_PERF) { -+ min = asus_bios.rog_tunables->min_perf_cores; -+ max = asus_bios.rog_tunables->max_perf_cores; -+ } else { -+ min = 0; -+ max = asus_bios.rog_tunables->max_power_cores; -+ } -+ if (cores < min || cores > max) -+ return -EINVAL; ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; + -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, ¤tv); -+ if (err) -+ return err; ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_vibe_intensity; ++ hidbuf[3] = xpad_cmd_len_vibe_intensity; ++ hidbuf[4] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left]; ++ hidbuf[5] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right]; + -+ if (core_type == CPU_CORE_PERF) -+ cores |= (currentv & 0xff00); -+ else -+ cores |= currentv & 0xff; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; + -+ if (cores == currentv) -+ return 0; ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; + -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, cores, &result); -+ if (err) { -+ pr_warn("Failed to set perfromance core count: %d\n", err); -+ return err; -+ } ++report_fail: ++ kfree(hidbuf); ++ return ret; ++} + -+ if (result > 1) { -+ pr_warn("Failed to set performance core count (result): 0x%x\n", result); -+ return -EIO; -+ } ++static ssize_t gamepad_vibration_intensity_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; + -+ pr_info("CPU core count changed, reboot required\n"); -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ asus_set_reboot_and_signal_event(); ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ return 0; ++ return sysfs_emit( ++ buf, "%d %d\n", ++ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left], ++ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right]); +} + -+static ssize_t cores_performance_min_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t gamepad_vibration_intensity_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN); ++ struct hid_device *hdev = to_hid_device(dev); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ u32 left, right; ++ int ret; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ if (sscanf(buf, "%d %d", &left, &right) != 2) ++ return -EINVAL; ++ ++ if (left > 64 || right > 64) ++ return -EINVAL; ++ ++ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left] = left; ++ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right] = right; ++ ++ ret = __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ++ return count; +} + -+static ssize_t cores_performance_max_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); ++ ++/* ROOT LEVEL ATTRS *******************************************************************************/ ++static struct attribute *gamepad_device_attrs[] = { ++ &dev_attr_gamepad_mode.attr, ++ &dev_attr_btn_mapping_reset.attr, ++ &dev_attr_btn_mapping_apply.attr, ++ &dev_attr_gamepad_vibration_intensity.attr, ++ &dev_attr_gamepad_vibration_intensity_index.attr, ++ NULL ++}; ++ ++static const struct attribute_group ally_controller_attr_group = { ++ .attrs = gamepad_device_attrs, ++}; ++ ++/* ANALOGUE DEADZONES *****************************************************************************/ ++static ssize_t __gamepad_set_deadzones(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX); ++ u8 *hidbuf; ++ int ret; ++ ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_js_dz; ++ hidbuf[3] = xpad_cmd_len_deadzone; ++ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][0][0]; ++ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][0][1]; ++ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][0][2]; ++ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][0][3]; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto end; ++ ++ hidbuf[2] = xpad_cmd_set_tr_dz; ++ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][1][0]; ++ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][1][1]; ++ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][1][2]; ++ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][1][3]; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto end; ++ ++end: ++ kfree(hidbuf); ++ return ret; +} + -+static ssize_t cores_performance_default_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t __gamepad_store_deadzones(struct ally_gamepad_cfg *ally_cfg, enum xpad_axis axis, ++ const char *buf) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT); ++ int cmd, side, is_tr; ++ u32 inner, outer; ++ ++ if (sscanf(buf, "%d %d", &inner, &outer) != 2) ++ return -EINVAL; ++ ++ if (inner > 64 || outer > 64 || inner > outer) ++ return -EINVAL; ++ ++ is_tr = axis > xpad_axis_xy_right; ++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 2 : 0; ++ cmd = is_tr ? xpad_cmd_set_js_dz : xpad_cmd_set_tr_dz; ++ ++ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side] = inner; ++ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side + 1] = outer; ++ ++ return 0; +} + -+static ssize_t cores_performance_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT); ++ return sysfs_emit(buf, "inner outer\n"); +} + -+static ssize_t cores_performance_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index); ++ ++ALLY_AXIS_DEADZONE(xpad_axis_xy_left, deadzone); ++ALLY_AXIS_DEADZONE(xpad_axis_xy_right, deadzone); ++ALLY_AXIS_DEADZONE(xpad_axis_z_left, deadzone); ++ALLY_AXIS_DEADZONE(xpad_axis_z_right, deadzone); ++ ++/* ANTI-DEADZONES *********************************************************************************/ ++static ssize_t __gamepad_write_js_ADZ_to_mcu(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) +{ -+ int err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF); -+ if (err) -+ return err; ++ u8 *hidbuf; ++ int ret; + -+ return count; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_adz; ++ hidbuf[3] = xpad_cmd_len_adz; ++ hidbuf[4] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left]; ++ hidbuf[5] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right]; ++ ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; ++ ++report_fail: ++ kfree(hidbuf); ++ return ret; +} -+ATTR_GROUP_CORES_RW(cores_performance, "cores_performance", ASUS_WMI_DEVID_CORES, "Set the max available performance cores"); + -+static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t __gamepad_js_ADZ_store(struct device *dev, const char *buf, ++ enum btn_pair_side side) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int ret, val; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ ++ if (val < 0 || val > 32) ++ return -EINVAL; ++ ++ ally_cfg->anti_deadzones[ally_cfg->mode - 1][side] = val; ++ ++ return ret; +} + -+static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t xpad_axis_xy_left_ADZ_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ return sysfs_emit(buf, "%d\n", ++ ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left]); +} + -+static ssize_t cores_efficiency_default_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++static ssize_t xpad_axis_xy_left_ADZ_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT); ++ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_left); ++ ++ if (ret) ++ return ret; ++ ++ return count; +} + -+static ssize_t cores_efficiency_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) ++ALLY_DEVICE_ATTR_RW(xpad_axis_xy_left_ADZ, anti_deadzone); ++ ++static ssize_t xpad_axis_xy_right_ADZ_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ return sysfs_emit(buf, "%d\n", ++ ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right]); +} + -+static ssize_t cores_efficiency_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) ++static ssize_t xpad_axis_xy_right_ADZ_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+ int err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER); -+ if (err) -+ return err; ++ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_right); ++ ++ if (ret) ++ return ret; + + return count; +} -+ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency", ASUS_WMI_DEVID_CORES, "Set the max available efficiency cores"); + -+/* Simple attribute creation */ -+ATTR_GROUP_ENUM_INT_RW(thermal_policy, "thermal_policy", ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, 0, 3, "0;1;2", "Fan stuff todo"); -+ATTR_GROUP_PPT_RW(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, -+ cpu_default, 5, cpu_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_PPT_RW(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, -+ cpu_default, 5, cpu_max, 1, "Set the CPU fast package limit"); -+ATTR_GROUP_PPT_RW(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT, -+ platform_default, 5, platform_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_PPT_RW(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT, -+ platform_default, 5, platform_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_PPT_RW(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, -+ cpu_default, 5, cpu_max, 1, "Set the CPU slow package limit"); -+ -+ATTR_GROUP_PPT_RW(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST, -+ nv_boost_default, 5, nv_boost_max, 1, "Set the Nvidia dynamic boost limit"); -+ATTR_GROUP_PPT_RW(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET, -+ nv_temp_default, 75, nv_temp_max, 1, "Set the Nvidia max thermal limit"); -+ATTR_GROUP_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP, "Read the base TGP value") -+ATTR_GROUP_INT_RW(dgpu_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, -+ 70, 0, NVIDIA_GPU_POWER_MAX, 1, "Set the additional TGP on top of the base TGP"); -+ -+ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, 0, 0, "0;1;2", "Show the current mode of charging"); -+ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, "Set the boot POST sound"); -+ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, "Set MCU powersaving mode"); -+ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, "Set the panel refresh overdrive"); -+ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, "Set the panel HD mode to UHD<0> or FHD<1>"); -+ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, "Show the eGPU connection status"); ++ALLY_DEVICE_ATTR_RW(xpad_axis_xy_right_ADZ, anti_deadzone); + -+static int asus_fw_attr_add(void) ++/* JS RESPONSE CURVES *****************************************************************************/ ++static ssize_t rc_point_index_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "move response\n"); ++} ++ ++ALLY_DEVICE_ATTR_RO(rc_point_index, rc_point_index); ++ ++static ssize_t __gamepad_write_response_curves_to_mcu(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) +{ ++ u8 *hidbuf; + int ret; -+ ret = fw_attributes_class_get(&fw_attr_class); -+ if (ret) -+ goto fail_class_created; -+ else -+ asus_bios.fw_attr_dev = device_create(fw_attr_class, NULL, -+ MKDEV(0, 0), NULL, "%s", DRIVER_NAME); + -+ if (IS_ERR(asus_bios.fw_attr_dev)) { -+ ret = PTR_ERR(asus_bios.fw_attr_dev); -+ goto fail_class_created; -+ } ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; + -+ asus_bios.fw_attr_kset = kset_create_and_add("attributes", NULL, -+ &asus_bios.fw_attr_dev->kobj); -+ if (!asus_bios.fw_attr_dev) { -+ ret = -ENOMEM; -+ pr_debug("Failed to create and add attributes\n"); -+ goto err_destroy_classdev; -+ } ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; + -+ /* Add any firmware_attributes required */ -+ ret = sysfs_create_file(&asus_bios.fw_attr_kset->kobj, &pending_reboot.attr); -+ if (ret) { -+ pr_warn("Failed to create sysfs level attributes\n"); -+ goto fail_class_created; -+ } ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_response_curve; ++ hidbuf[3] = xpad_cmd_len_response_curve; ++ hidbuf[4] = 0x01; ++ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_left], ++ 8); + -+ // TODO: logging -+ asus_bios.mini_led_dev_id = 0; -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) { -+ asus_bios.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &mini_led_mode_attr_group); -+ } -+ else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) { -+ asus_bios.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &mini_led_mode_attr_group); -+ } ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; + -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) { -+ asus_bios.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) { -+ asus_bios.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+ } ++ hidbuf[4] = 0x02; ++ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_right], ++ 8); + -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) { -+ asus_bios.dgpu_disable_available = true; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &dgpu_disable_attr_group); -+ } -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) { -+ asus_bios.egpu_enable_available = true; -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &egpu_enable_attr_group); -+ } -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU_CONNECTED)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &egpu_connected_attr_group); ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; + -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_CORES_MAX) && !asus_bios_set_max_cores()){ -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &cores_performance_attr_group); -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &cores_efficiency_attr_group); -+ } ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; ++ ++report_fail: ++ kfree(hidbuf); ++ return ret; ++} ++ ++static ssize_t __gamepad_store_response_curve(struct device *dev, const char *buf, ++ enum btn_pair_side side, int point) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ u32 move, response; ++ int idx; + -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &thermal_policy_attr_group); -+ -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PPT_PL1_SPL)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &ppt_pl1_spl_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PPT_PL2_SPPT)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &ppt_pl2_sppt_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PPT_APU_SPPT)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &ppt_apu_sppt_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PPT_PLAT_SPPT)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &ppt_platform_sppt_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PPT_FPPT)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &ppt_fppt_attr_group); -+ -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_NV_DYN_BOOST)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &nv_dynamic_boost_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_NV_THERM_TARGET)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &nv_temp_target_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU_BASE_TGP)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &dgpu_base_tgp_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU_SET_TGP)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &dgpu_tgp_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_APU_MEM)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &apu_mem_attr_group); -+ -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_CHARGE_MODE)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &charge_mode_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_BOOT_SOUND)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &boot_sound_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_MCU_POWERSAVE)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &mcu_powersave_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PANEL_OD)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &panel_od_attr_group); -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_PANEL_HD)) -+ sysfs_create_group(&asus_bios.fw_attr_kset->kobj, &panel_hd_mode_attr_group); ++ idx = (point - 1) * 2; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ if (sscanf(buf, "%d %d", &move, &response) != 2) ++ return -EINVAL; ++ ++ if (move > 64 || response > 64) ++ return -EINVAL; ++ ++ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx] = move; ++ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx + 1] = response; + + return 0; ++} + -+err_destroy_classdev: -+ device_destroy(fw_attr_class, MKDEV(0, 0)); ++ALLY_JS_RC_POINT(left, 1, rc_point_); ++ALLY_JS_RC_POINT(left, 2, rc_point_); ++ALLY_JS_RC_POINT(left, 3, rc_point_); ++ALLY_JS_RC_POINT(left, 4, rc_point_); + -+fail_class_created: -+ fw_attributes_class_put(); ++ALLY_JS_RC_POINT(right, 1, rc_point_); ++ALLY_JS_RC_POINT(right, 2, rc_point_); ++ALLY_JS_RC_POINT(right, 3, rc_point_); ++ALLY_JS_RC_POINT(right, 4, rc_point_); ++ ++/* CALIBRATIONS ***********************************************************************************/ ++static int __gamepad_get_calibration(struct hid_device *hdev) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ u8 *hidbuf; ++ int ret, i; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ for (i = 0; i < 2; i++) { ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = 0xD0; ++ hidbuf[2] = 0x03; ++ hidbuf[3] = i + 1; // 0x01 JS, 0x02 TR ++ hidbuf[4] = 0x20; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) { ++ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret); ++ goto cleanup; ++ } ++ ++ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0 || hidbuf[5] != 1) { ++ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret); ++ goto cleanup; ++ } ++ ++ if (i == 0) { ++ /* Joystick calibration */ ++ /* [left][index] is Y: stable, min, max. X: stable, min, max */ ++ ally_cfg->js_calibrations[0][3] = (hidbuf[6] << 8) | hidbuf[7]; ++ ally_cfg->js_calibrations[0][4] = (hidbuf[8] << 8) | hidbuf[9]; ++ ally_cfg->js_calibrations[0][5] = (hidbuf[10] << 8) | hidbuf[11]; ++ ally_cfg->js_calibrations[0][0] = (hidbuf[12] << 8) | hidbuf[13]; ++ ally_cfg->js_calibrations[0][1] = (hidbuf[14] << 8) | hidbuf[15]; ++ ally_cfg->js_calibrations[0][2] = (hidbuf[16] << 8) | hidbuf[17]; ++ /* [right][index] is Y: stable, min, max. X: stable, min, max */ ++ ally_cfg->js_calibrations[1][0] = (hidbuf[24] << 8) | hidbuf[25]; ++ ally_cfg->js_calibrations[1][1] = (hidbuf[26] << 8) | hidbuf[27]; ++ ally_cfg->js_calibrations[1][2] = (hidbuf[28] << 8) | hidbuf[29]; ++ ally_cfg->js_calibrations[1][3] = (hidbuf[18] << 8) | hidbuf[19]; ++ ally_cfg->js_calibrations[1][4] = (hidbuf[20] << 8) | hidbuf[21]; ++ ally_cfg->js_calibrations[1][5] = (hidbuf[22] << 8) | hidbuf[23]; ++ } else { ++ /* Trigger calibration */ ++ /* [left/right][stable/max] */ ++ ally_cfg->tr_calibrations[0][0] = (hidbuf[6] << 8) | hidbuf[7]; ++ ally_cfg->tr_calibrations[0][1] = (hidbuf[8] << 8) | hidbuf[9]; ++ ally_cfg->tr_calibrations[1][0] = (hidbuf[10] << 8) | hidbuf[11]; ++ ally_cfg->tr_calibrations[1][1] = (hidbuf[12] << 8) | hidbuf[13]; ++ } ++ } ++ ++cleanup: ++ kfree(hidbuf); + return ret; +} + -+/* Init / exit ****************************************************************/ -+ -+/* Set up the min/max and defaults for ROG tunables */ -+static void init_rog_tunables(struct rog_tunables *rog) ++static ssize_t __gamepad_write_cal_to_mcu(struct device *dev, enum xpad_axis axis) +{ -+ const char *product; -+ u32 max_boost = NVIDIA_BOOST_MAX; -+ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT; -+ u32 cpu_max = PPT_CPU_LIMIT_MAX; -+ u32 platform_default = PPT_PLATFORM_DEFAULT; -+ u32 platform_max = PPT_PLATFORM_MAX; ++ struct hid_device *hdev = to_hid_device(dev); ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ u8 *c, side, pkt_len, data_len; ++ int ret, cal, checksum = 0; ++ u8 *hidbuf; ++ int *head; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ /* -+ * ASUS product_name contains everything required, e.g, -+ * "ROG Flow X16 GV601VV_GV601VV_00185149B" -+ */ -+ product = dmi_get_system_info(DMI_PRODUCT_NAME); ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; + -+ if (strstr(product, "GA402R")) { -+ cpu_default = 125; -+ } else if (strstr(product, "13QY")) { -+ cpu_max = 250; -+ } else if (strstr(product, "X13")) { -+ cpu_max = 75; -+ cpu_default = 50; -+ } else if (strstr(product, "RC71")) { -+ cpu_max = 50; -+ cpu_default = 30; -+ } else if (strstr(product, "G814") -+ || strstr(product, "G614") -+ || strstr(product, "G834") -+ || strstr(product, "G634")) { -+ cpu_max = 175; -+ } else if (strstr(product, "GA402X") -+ || strstr(product, "GA403") -+ || strstr(product, "FA507N") -+ || strstr(product, "FA507X") -+ || strstr(product, "FA707N") -+ || strstr(product, "FA707X")) { -+ cpu_max = 90; ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; ++ pkt_len = axis > xpad_axis_xy_right ? 0x06 : 0x0E; ++ data_len = axis > xpad_axis_xy_right ? 2 : 6; ++ head = axis > xpad_axis_xy_right ? ally_cfg->tr_calibrations[side] : ++ ally_cfg->js_calibrations[side]; ++ ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_calibration; ++ hidbuf[3] = pkt_len; ++ hidbuf[4] = 0x01; /* second command (write calibration) */ ++ hidbuf[5] = axis; ++ c = &hidbuf[6]; /* pointer to data start */ ++ ++ for (size_t i = 0; i < data_len; i++) { ++ cal = head[i]; ++ *c = (u8)((cal & 0xff00) >> 8); ++ checksum += *c; ++ c += 1; ++ *c = (u8)(cal & 0xff); ++ checksum += *c; ++ c += 1; + } + -+ if (strstr(product, "GZ301ZE")) -+ max_boost = 5; -+ else if (strstr(product, "FX507ZC4")) -+ max_boost = 15; -+ else if (strstr(product, "GU605")) -+ max_boost = 20; ++ hidbuf[6 + data_len * 2] = checksum; + -+ /* ensure defaults for tunables */ -+ rog->cpu_default = cpu_default; -+ rog->cpu_max = cpu_max; ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; + -+ rog->platform_default = platform_default; -+ rog->platform_max = platform_max; ++ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_calibration; ++ hidbuf[3] = xpad_cmd_len_calibration3; ++ hidbuf[4] = 0x03; /* second command (apply the calibration that was written) */ + -+ rog->ppt_pl1_spl = cpu_default; -+ rog->ppt_pl2_sppt = cpu_default; -+ rog->ppt_apu_sppt = cpu_default; ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto report_fail; + -+ rog->ppt_platform_sppt = platform_default; -+ rog->ppt_fppt = platform_default; ++report_fail: ++ kfree(hidbuf); ++ return ret; ++} + -+ rog->nv_boost_default = NVIDIA_BOOST_MAX; -+ rog->nv_boost_max = max_boost; -+ rog->nv_dynamic_boost = NVIDIA_BOOST_MIN; ++static ssize_t __gamepad_cal_store(struct device *dev, const char *buf, enum xpad_axis axis) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ u32 x_stable, x_min, x_max, y_stable, y_min, y_max, side; + -+ rog->nv_temp_default = NVIDIA_TEMP_MAX; -+ rog->nv_temp_max = NVIDIA_TEMP_MAX; -+ rog->nv_temp_target = NVIDIA_TEMP_MIN; ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) { ++ if (sscanf(buf, "%d %d %d %d %d %d", &x_stable, &x_min, &x_max, &y_stable, ++ &y_min, &y_max) != 6) ++ return -EINVAL; ++ ++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; ++ /* stored in reverse order for easy copy to packet */ ++ ally_cfg->js_calibrations[side][0] = y_stable; ++ ally_cfg->js_calibrations[side][1] = y_min; ++ ally_cfg->js_calibrations[side][2] = y_max; ++ ally_cfg->js_calibrations[side][3] = x_stable; ++ ally_cfg->js_calibrations[side][4] = x_min; ++ ally_cfg->js_calibrations[side][5] = x_max; ++ ++ return __gamepad_write_cal_to_mcu(dev, axis); ++ } ++ if (sscanf(buf, "%d %d", &x_stable, &x_max) != 2) ++ return -EINVAL; ++ ++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; ++ /* stored in reverse order for easy copy to packet */ ++ ally_cfg->tr_calibrations[side][0] = x_stable; ++ ally_cfg->tr_calibrations[side][1] = x_max; + ++ return __gamepad_write_cal_to_mcu(dev, axis); +} + -+static int __init asus_fw_init(void) ++static ssize_t __gamepad_cal_show(struct device *dev, char *buf, enum xpad_axis axis) +{ -+ int err; ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int side = (axis == xpad_axis_xy_right || axis == xpad_axis_z_right) ? 1 : 0; + -+ mutex_lock(&asus_bios.mutex); ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; + -+ asus_bios.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL); -+ if (!asus_bios.rog_tunables) { -+ mutex_unlock(&asus_bios.mutex); -+ return -ENOMEM; ++ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) { ++ return sysfs_emit( ++ buf, "%d %d %d %d %d %d\n", ally_cfg->js_calibrations[side][3], ++ ally_cfg->js_calibrations[side][4], ally_cfg->js_calibrations[side][5], ++ ally_cfg->js_calibrations[side][0], ally_cfg->js_calibrations[side][1], ++ ally_cfg->js_calibrations[side][2]); + } -+ init_rog_tunables(asus_bios.rog_tunables); + -+ err = asus_fw_attr_add(); -+ mutex_unlock(&asus_bios.mutex); -+ if (err) -+ return err; ++ return sysfs_emit(buf, "%d %d\n", ally_cfg->tr_calibrations[side][0], ++ ally_cfg->tr_calibrations[side][1]); ++} + -+ return 0; ++ALLY_CAL_ATTR(xpad_axis_xy_left_cal, xpad_axis_xy_left, calibration); ++ALLY_CAL_ATTR(xpad_axis_xy_right_cal, xpad_axis_xy_right, calibration); ++ALLY_CAL_ATTR(xpad_axis_z_left_cal, xpad_axis_z_left, calibration); ++ALLY_CAL_ATTR(xpad_axis_z_right_cal, xpad_axis_z_right, calibration); ++ ++static ssize_t xpad_axis_xy_cal_index_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "x_stable x_min x_max y_stable y_min y_max\n"); +} + -+static void __exit asus_fw_exit(void) ++ALLY_DEVICE_ATTR_RO(xpad_axis_xy_cal_index, calibration_index); ++ ++static ssize_t xpad_axis_z_cal_index_show(struct device *dev, struct device_attribute *attr, ++ char *buf) +{ -+ mutex_lock(&asus_bios.mutex); ++ return sysfs_emit(buf, "z_stable z_max\n"); ++} + -+ sysfs_remove_file(&asus_bios.fw_attr_kset->kobj, &pending_reboot.attr); -+ kset_unregister(asus_bios.fw_attr_kset); -+ device_destroy(fw_attr_class, MKDEV(0, 0)); -+ fw_attributes_class_put(); ++ALLY_DEVICE_ATTR_RO(xpad_axis_z_cal_index, calibration_index); + -+ mutex_unlock(&asus_bios.mutex); ++static ssize_t __gamepad_cal_reset(struct device *dev, const char *buf, enum xpad_axis axis) ++{ ++ struct hid_device *hdev = to_hid_device(dev); ++ u8 *hidbuf; ++ int ret; ++ ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ /* Write the reset value, then apply it */ ++ for (u8 cmd = 0x02; cmd <= 0x03; cmd++) { ++ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_calibration; ++ hidbuf[3] = (cmd == 0x02) ? xpad_cmd_len_calibration2 : ++ xpad_cmd_len_calibration3; ++ hidbuf[4] = cmd; ++ hidbuf[5] = axis; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ break; ++ } ++ ++ __gamepad_get_calibration(hdev); ++ ++ kfree(hidbuf); ++ return ret; +} + -+module_init(asus_fw_init); -+module_exit(asus_fw_exit); -diff --git a/drivers/platform/x86/asus-bios.h b/drivers/platform/x86/asus-bios.h -new file mode 100644 -index 000000000000..7016ec14efc1 ---- /dev/null -+++ b/drivers/platform/x86/asus-bios.h -@@ -0,0 +1,288 @@ -+/* SPDX-License-Identifier: GPL-2.0 -+ * -+ * Definitions for kernel modules using asus-bios driver -+ * -+ * Copyright (c) 2024 Luke Jones -+ */ ++ALLY_CAL_RESET_ATTR(xpad_axis_xy_left_cal_reset, xpad_axis_xy_left, calibration_reset); ++ALLY_CAL_RESET_ATTR(xpad_axis_xy_right_cal_reset, xpad_axis_xy_right, calibration_reset); ++ALLY_CAL_RESET_ATTR(xpad_axis_z_left_cal_reset, xpad_axis_z_left, calibration_reset); ++ALLY_CAL_RESET_ATTR(xpad_axis_z_right_cal_reset, xpad_axis_z_right, calibration_reset); ++ ++static struct attribute *gamepad_axis_xy_left_attrs[] = { ++ &dev_attr_xpad_axis_xy_left_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_xpad_axis_xy_left_ADZ.attr, ++ &dev_attr_xpad_axis_xy_left_cal_reset.attr, ++ &dev_attr_xpad_axis_xy_left_cal.attr, ++ &dev_attr_xpad_axis_xy_cal_index.attr, ++ &dev_attr_rc_point_left_1.attr, ++ &dev_attr_rc_point_left_2.attr, ++ &dev_attr_rc_point_left_3.attr, ++ &dev_attr_rc_point_left_4.attr, ++ &dev_attr_rc_point_index.attr, ++ NULL ++}; ++static const struct attribute_group ally_controller_axis_xy_left_attr_group = { ++ .name = "axis_xy_left", ++ .attrs = gamepad_axis_xy_left_attrs, ++}; + -+#ifndef _ASUS_BIOSCFG_H_ -+#define _ASUS_BIOSCFG_H_ ++static struct attribute *gamepad_axis_xy_right_attrs[] = { ++ &dev_attr_xpad_axis_xy_right_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_xpad_axis_xy_right_ADZ.attr, ++ &dev_attr_xpad_axis_xy_right_cal_reset.attr, ++ &dev_attr_xpad_axis_xy_right_cal.attr, ++ &dev_attr_xpad_axis_xy_cal_index.attr, ++ &dev_attr_rc_point_right_1.attr, ++ &dev_attr_rc_point_right_2.attr, ++ &dev_attr_rc_point_right_3.attr, ++ &dev_attr_rc_point_right_4.attr, ++ &dev_attr_rc_point_index.attr, ++ NULL ++}; ++static const struct attribute_group ally_controller_axis_xy_right_attr_group = { ++ .name = "axis_xy_right", ++ .attrs = gamepad_axis_xy_right_attrs, ++}; + -+#include "firmware_attributes_class.h" -+#include ++static struct attribute *gamepad_axis_z_left_attrs[] = { ++ &dev_attr_xpad_axis_z_left_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_xpad_axis_z_left_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr, ++ &dev_attr_xpad_axis_z_left_cal_reset.attr, NULL ++}; ++static const struct attribute_group ally_controller_axis_z_left_attr_group = { ++ .name = "axis_z_left", ++ .attrs = gamepad_axis_z_left_attrs, ++}; ++ ++static struct attribute *gamepad_axis_z_right_attrs[] = { ++ &dev_attr_xpad_axis_z_right_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_xpad_axis_z_right_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr, ++ &dev_attr_xpad_axis_z_right_cal_reset.attr, NULL ++}; ++static const struct attribute_group ally_controller_axis_z_right_attr_group = { ++ .name = "axis_z_right", ++ .attrs = gamepad_axis_z_right_attrs, ++}; + -+#define DRIVER_NAME "asus-bioscfg" ++static const struct attribute_group *gamepad_device_attr_groups[] = { ++ &ally_controller_attr_group, ++ &ally_controller_axis_xy_left_attr_group, ++ &ally_controller_axis_xy_right_attr_group, ++ &ally_controller_axis_z_left_attr_group, ++ &ally_controller_axis_z_right_attr_group, ++ &btn_mapping_m1_attr_group, ++ &btn_mapping_m2_attr_group, ++ &btn_mapping_a_attr_group, ++ &btn_mapping_b_attr_group, ++ &btn_mapping_x_attr_group, ++ &btn_mapping_y_attr_group, ++ &btn_mapping_lb_attr_group, ++ &btn_mapping_rb_attr_group, ++ &btn_mapping_ls_attr_group, ++ &btn_mapping_rs_attr_group, ++ &btn_mapping_dpad_u_attr_group, ++ &btn_mapping_dpad_d_attr_group, ++ &btn_mapping_dpad_l_attr_group, ++ &btn_mapping_dpad_r_attr_group, ++ &btn_mapping_view_attr_group, ++ &btn_mapping_menu_attr_group, ++ NULL ++}; + -+static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count, -+ u32 min, u32 max, u32 *store_value, u32 wmi_dev); ++static int __gamepad_write_all_to_mcu(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) ++{ ++ u8 *hidbuf; ++ int ret; + ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_u_d); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_l_r); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_ls_rs); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lb_rb); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_a_b); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_x_y); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_view_menu); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2); ++ if (ret < 0) ++ return ret; ++ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lt_rt); ++ if (ret < 0) ++ return ret; ++ __gamepad_set_deadzones(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ __gamepad_write_js_ADZ_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ __gamepad_write_response_curves_to_mcu(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; ++ ++ /* set turbo */ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; ++ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; ++ hidbuf[2] = xpad_cmd_set_turbo; ++ hidbuf[3] = xpad_cmd_len_turbo; ++ memcpy(&hidbuf[4], ally_cfg->turbo_btns[ally_cfg->mode - 1], TURBO_BLOCK_LEN); ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ++ kfree(hidbuf); ++ return ret; ++} + -+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) ++static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) +{ -+ return sysfs_emit(buf, "integer\n"); ++ struct ally_gamepad_cfg *ally_cfg; ++ struct input_dev *input_dev; ++ int i, err; ++ ++ ally_cfg = devm_kzalloc(&hdev->dev, sizeof(*ally_cfg), GFP_KERNEL); ++ if (!ally_cfg) ++ return ERR_PTR(-ENOMEM); ++ ally_cfg->hdev = hdev; ++ ++ input_dev = devm_input_allocate_device(&hdev->dev); ++ if (!input_dev) { ++ err = -ENOMEM; ++ goto free_ally_cfg; ++ } ++ ally_cfg->input = input_dev; ++ ++ input_dev->id.bustype = hdev->bus; ++ input_dev->id.vendor = hdev->vendor; ++ input_dev->id.product = hdev->product; ++ input_dev->id.version = hdev->version; ++ input_dev->uniq = hdev->uniq; ++ input_dev->name = "ASUS ROG Ally Config"; ++ input_set_capability(input_dev, EV_KEY, KEY_PROG1); ++ input_set_capability(input_dev, EV_KEY, KEY_F16); ++ input_set_capability(input_dev, EV_KEY, KEY_F17); ++ input_set_capability(input_dev, EV_KEY, KEY_F18); ++ ++ input_set_drvdata(input_dev, hdev); ++ ++ err = input_register_device(input_dev); ++ if (err) ++ goto free_input_dev; ++ ++ ally_cfg->mode = xpad_mode_game; ++ for (i = 0; i < xpad_mode_mouse; i++) { ++ ally_cfg->deadzones[i][0][1] = 64; ++ ally_cfg->deadzones[i][0][3] = 64; ++ ally_cfg->deadzones[i][1][1] = 64; ++ ally_cfg->deadzones[i][1][3] = 64; ++ ally_cfg->response_curve[i][0][0] = 0x14; ++ ally_cfg->response_curve[i][0][1] = 0x14; ++ ally_cfg->response_curve[i][0][2] = 0x28; ++ ally_cfg->response_curve[i][0][3] = 0x28; ++ ally_cfg->response_curve[i][0][4] = 0x3c; ++ ally_cfg->response_curve[i][0][5] = 0x3c; ++ ally_cfg->response_curve[i][0][6] = 0x63; ++ ally_cfg->response_curve[i][0][7] = 0x63; ++ ally_cfg->response_curve[i][1][0] = 0x14; ++ ally_cfg->response_curve[i][1][1] = 0x14; ++ ally_cfg->response_curve[i][1][2] = 0x28; ++ ally_cfg->response_curve[i][1][3] = 0x28; ++ ally_cfg->response_curve[i][1][4] = 0x3c; ++ ally_cfg->response_curve[i][1][5] = 0x3c; ++ ally_cfg->response_curve[i][1][6] = 0x63; ++ ally_cfg->response_curve[i][1][7] = 0x63; ++ ally_cfg->vibration_intensity[i][0] = 64; ++ ally_cfg->vibration_intensity[i][1] = 64; ++ } ++ drvdata.gamepad_cfg = ally_cfg; ++ ++ /* ignore all errors for this as they are related to USB HID I/O */ ++ __gamepad_mapping_xpad_default(ally_cfg); ++ __gamepad_mapping_wasd_default(ally_cfg); ++ /* these calls will never error so ignore the return */ ++ __gamepad_mapping_store(ally_cfg, KB_M2, btn_pair_m1_m2, btn_pair_side_left, false); ++ __gamepad_mapping_store(ally_cfg, KB_M1, btn_pair_m1_m2, btn_pair_side_right, false); ++ __gamepad_set_mode(hdev, ally_cfg, xpad_mode_game); ++ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2); ++ /* ensure we have data for users to start from */ ++ __gamepad_get_calibration(hdev); ++ ++ if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { ++ err = -ENODEV; ++ goto unregister_input_dev; ++ } ++ ++ return ally_cfg; ++ ++unregister_input_dev: ++ input_unregister_device(input_dev); ++ ally_cfg->input = NULL; // Prevent double free when kfree(ally_cfg) happens ++ ++free_input_dev: ++ devm_kfree(&hdev->dev, input_dev); ++ ++free_ally_cfg: ++ devm_kfree(&hdev->dev, ally_cfg); ++ return ERR_PTR(err); +} + -+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) ++static void ally_cfg_remove(struct hid_device *hdev) +{ -+ return sysfs_emit(buf, "enumeration\n"); ++ __gamepad_set_mode(hdev, drvdata.gamepad_cfg, xpad_mode_mouse); ++ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups); +} + -+#define __ASUS_ATTR_RO(_func, _name) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _func##_##_name##_show, \ ++/**************************************************************************************************/ ++/* ROG Ally LED control */ ++/**************************************************************************************************/ ++static void ally_schedule_work(struct ally_rgb_leds *led) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&led->lock, flags); ++ if (!led->removed) ++ schedule_work(&led->work); ++ spin_unlock_irqrestore(&led->lock, flags); ++ pr_warn("5"); +} + -+#define __ASUS_ATTR_RO_AS(_name, _show) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _show, \ ++static void ally_led_do_brightness(struct work_struct *work) ++{ ++ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work); ++ u8 buf1[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xb4, 0x00, 0x00, 0x00 }; ++ u8 buf[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 }; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&led->lock, flags); ++ if (!led->update_bright) { ++ spin_unlock_irqrestore(&led->lock, flags); ++ return; ++ } ++ led->update_bright = false; ++ buf[4] = led->brightness; ++ spin_unlock_irqrestore(&led->lock, flags); ++ ++ if (asus_dev_set_report(led->hdev, buf, sizeof(buf)) < 0) ++ hid_err(led->hdev, "Ally failed to set backlight\n"); ++ if (asus_dev_set_report(led->hdev, buf1, sizeof(buf1)) < 0) ++ hid_err(led->hdev, "Ally failed to set backlight\n"); +} + -+#define __ASUS_ATTR_RW(_func, _name) __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store) ++static void ally_led_do_rgb(struct work_struct *work) ++{ ++ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work); ++ unsigned long flags; ++ int ret; + -+#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ -+static ssize_t _attr##_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ return attr_int_store(kobj, attr, buf, count, _min, _max, NULL, _wmi); \ ++ u8 buf[16] = { [0] = FEATURE_ROG_ALLY_REPORT_ID, ++ [1] = FEATURE_ROG_ALLY_CODE_PAGE, ++ [2] = xpad_cmd_set_leds, ++ [3] = xpad_cmd_len_leds }; ++ ++ spin_lock_irqsave(&led->lock, flags); ++ if (!led->update_rgb) { ++ spin_unlock_irqrestore(&led->lock, flags); ++ return; ++ } ++ for (int i = 0; i < 4; i++) { ++ buf[4 + i * 3] = led->gamepad_red; ++ buf[5 + i * 3] = led->gamepad_green; ++ buf[6 + i * 3] = led->gamepad_blue; ++ } ++ led->update_rgb = false; ++ spin_unlock_irqrestore(&led->lock, flags); ++ ++ ret = asus_dev_set_report(led->hdev, buf, sizeof(buf)); ++ if (ret < 0) ++ hid_err(led->hdev, "Ally failed to set gamepad backlight: %d\n", ret); +} + -+#define WMI_SHOW_INT(_attr, _fmt, _wmi) \ -+static ssize_t _attr##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ u32 result; \ -+ int err; \ -+ err = asus_wmi_get_devstate_dsts(_wmi, &result); \ -+ if (err) \ -+ return err; \ -+ return sysfs_emit(buf, _fmt, \ -+ result & ~ASUS_WMI_DSTS_PRESENCE_BIT); \ ++static void ally_led_work(struct work_struct *work) ++{ ++ ally_led_do_brightness(work); ++ ally_led_do_rgb(work); +} + -+/* Create functions and attributes for use in other macros or on their own */ ++static void ally_backlight_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct ally_rgb_leds *led = ++ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev); ++ unsigned long flags; + -+#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi) \ -+static ssize_t _attr##_current_value_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ return attr_int_store(kobj, attr, buf, count, \ -+ _min, asus_bios.rog_tunables->_max, \ -+ &asus_bios.rog_tunables->_attr, _wmi); \ -+} \ -+static ssize_t _attr##_current_value_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, "%u\n", asus_bios.rog_tunables->_attr); \ -+} \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RW(_attr, current_value); ++ spin_lock_irqsave(&led->lock, flags); ++ led->update_bright = true; ++ led->brightness = brightness; ++ spin_unlock_irqrestore(&led->lock, flags); + -+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ -+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, "%d\n", asus_bios.rog_tunables->_val); \ -+} \ -+static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop); ++ ally_schedule_work(led); ++} + -+#define __ATTR_CURRENT_INT_RO(_attr, _wmi) \ -+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RO(_attr, current_value); ++static enum led_brightness ally_backlight_get(struct led_classdev *led_cdev) ++{ ++ struct ally_rgb_leds *led = ++ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev); ++ enum led_brightness brightness; ++ unsigned long flags; + -+#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi) \ -+__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \ -+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RW(_attr, current_value); ++ spin_lock_irqsave(&led->lock, flags); ++ brightness = led->brightness; ++ spin_unlock_irqrestore(&led->lock, flags); + -+/* Shows a formatted static variable */ -+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ -+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, _fmt, _val); \ -+} \ -+static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop); ++ return brightness; ++} + -+/* Requires current_value show&|store */ -+#define __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++static void ally_set_rgb_brightness(struct led_classdev *cdev, enum led_brightness brightness) ++{ ++ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); ++ struct ally_rgb_leds *led = container_of(mc_cdev, struct ally_rgb_leds, led_rgb_dev); ++ unsigned long flags; ++ ++ led_mc_calc_color_components(mc_cdev, brightness); ++ spin_lock_irqsave(&led->lock, flags); ++ led->update_rgb = true; ++ led->gamepad_red = mc_cdev->subled_info[0].brightness; ++ led->gamepad_green = mc_cdev->subled_info[1].brightness; ++ led->gamepad_blue = mc_cdev->subled_info[2].brightness; ++ spin_unlock_irqrestore(&led->lock, flags); ++ ++ ally_schedule_work(led); ++} + -+/* Int style min/max range, base macro. Requires current_value show&|store */ -+#define __ATTR_GROUP_INT(_attrname, _fsname, _default, \ -+ _min, _max, _incstep, _dispname)\ -+__ATTR_SHOW_FMT(default_value, _attrname, "%d\n", _default); \ -+__ATTR_SHOW_FMT(min_value, _attrname, "%d\n", _min); \ -+__ATTR_SHOW_FMT(max_value, _attrname, "%d\n", _max); \ -+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep); \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++static int ally_gamepad_register_brightness(struct hid_device *hdev, ++ struct ally_rgb_leds *led_rgb) ++{ ++ struct led_classdev *led_cdev; + -+/* Boolean style enumeration, base macro. Requires adding show/store */ -+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++ led_cdev = &led_rgb->led_bright_dev; ++ led_cdev->name = "ally:kbd_backlight"; /* Let a desktop control it also */ ++ led_cdev->max_brightness = 3; ++ led_cdev->brightness_set = ally_backlight_set; ++ led_cdev->brightness_get = ally_backlight_get; + -+#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ -+__ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+__ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname); ++ return devm_led_classdev_register(&hdev->dev, &led_rgb->led_bright_dev); ++} + -+#define ATTR_GROUP_INT_RW(_attrname, _fsname, _wmi, _default, _min, \ -+ _max, _incstep, _dispname) \ -+__ATTR_CURRENT_INT_RW(_attrname, _min, _max, _wmi); \ -+__ATTR_GROUP_INT(_attrname, _fsname, _default, _min, _max, _incstep, _dispname); ++static int ally_gamepad_register_rgb_leds(struct hid_device *hdev, ++ struct ally_rgb_leds *led_rgb) ++{ ++ struct mc_subled *mc_led_info; ++ struct led_classdev *led_cdev; + -+#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ -+__ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname); ++ mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info), ++ GFP_KERNEL | __GFP_ZERO); ++ if (!mc_led_info) ++ return -ENOMEM; + -+#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ -+__ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi); \ -+__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname); ++ mc_led_info[0].color_index = LED_COLOR_ID_RED; ++ mc_led_info[1].color_index = LED_COLOR_ID_GREEN; ++ mc_led_info[2].color_index = LED_COLOR_ID_BLUE; + -+/* -+ * Requires _current_value_show(), _current_value_show() -+ */ -+#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname) \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname); ++ led_rgb->led_rgb_dev.subled_info = mc_led_info; ++ led_rgb->led_rgb_dev.num_colors = 3; + -+#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _min, \ -+ _max, _possible, _dispname) \ -+__ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+__ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname); ++ led_cdev = &led_rgb->led_rgb_dev.led_cdev; ++ led_cdev->name = "ally:rgb:gamepad"; ++ led_cdev->brightness = 128; ++ led_cdev->max_brightness = 255; ++ led_cdev->brightness_set = ally_set_rgb_brightness; + -+#define ATTR_GROUP_ENUM_INT_RW(_attrname, _fsname, _wmi, _min, \ -+ _max, _possible, _dispname) \ -+__ATTR_CURRENT_INT_RW(_attrname, _min, _max, _wmi); \ -+__ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname); ++ return devm_led_classdev_multicolor_register(&hdev->dev, &led_rgb->led_rgb_dev); ++} + -+/* -+ * Requires _current_value_show(), _current_value_show() -+ * and _possible_values_show() -+ */ -+#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+static struct kobj_attribute attr_##_attrname##_possible_values = \ -+ __ASUS_ATTR_RO(_attrname, possible_values); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++static struct ally_rgb_leds *ally_gamepad_rgb_create(struct hid_device *hdev) ++{ ++ struct ally_rgb_leds *led_rgb; ++ int ret; + -+/* CPU core attributes need a little different in setup */ -+#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _wmi, _dispname)\ -+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+static struct kobj_attribute attr_##_attrname##_default_value = \ -+ __ASUS_ATTR_RO(_attrname, default_value); \ -+static struct kobj_attribute attr_##_attrname##_min_value = \ -+ __ASUS_ATTR_RO(_attrname, min_value); \ -+static struct kobj_attribute attr_##_attrname##_max_value = \ -+ __ASUS_ATTR_RO(_attrname, max_value); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++ led_rgb = devm_kzalloc(&hdev->dev, sizeof(struct ally_rgb_leds), GFP_KERNEL); ++ if (!led_rgb) ++ return ERR_PTR(-ENOMEM); + -+/* ROG PPT attributes need a little different in setup */ -+#define ATTR_GROUP_PPT_RW(_attrname, _fsname, _wmi, _default, \ -+ _min, _max, _incstep, _dispname) \ -+__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi); \ -+__ROG_TUNABLE_SHOW(default_value, _attrname, _default); \ -+__ATTR_SHOW_FMT(min_value, _attrname, "%d\n", _min); \ -+__ROG_TUNABLE_SHOW(max_value, _attrname, _max); \ -+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep); \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+}; ++ ret = ally_gamepad_register_rgb_leds(hdev, led_rgb); ++ if (ret < 0) { ++ cancel_work_sync(&led_rgb->work); ++ devm_kfree(&hdev->dev, led_rgb); ++ return ERR_PTR(ret); ++ } + -+#endif /* _ASUS_BIOSCFG_H_ */ -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index bc9c5db38324..9c80aa073758 100644 ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -97,6 +97,11 @@ module_param(fnlock_default, bool, 0444); - #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 - #define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 - -+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 -+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 -+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 -+#define ASUS_THROTTLE_THERMAL_POLICY_FULLSPEED 3 ++ ret = ally_gamepad_register_brightness(hdev, led_rgb); ++ if (ret < 0) { ++ cancel_work_sync(&led_rgb->work); ++ devm_kfree(&hdev->dev, led_rgb); ++ return ERR_PTR(ret); ++ } + - #define USB_INTEL_XUSB2PR 0xD0 - #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 - -@@ -112,11 +117,13 @@ module_param(fnlock_default, bool, 0444); - /* Mask to determine if setting temperature or percentage */ - #define FAN_CURVE_PWM_MASK 0x04 - --/* Limits for tunables available on ASUS ROG laptops */ --#define PPT_TOTAL_MIN 5 --#define PPT_TOTAL_MAX 250 --#define PPT_CPU_MIN 5 --#define PPT_CPU_MAX 130 -+/* Default limits for tunables available on ASUS ROG laptops */ -+#define PPT_CPU_LIMIT_MIN 5 -+#define PPT_CPU_LIMIT_MAX 150 -+#define PPT_CPU_LIMIT_DEFAULT 80 -+#define PPT_PLATFORM_MIN 5 -+#define PPT_PLATFORM_MAX 100 -+#define PPT_PLATFORM_DEFAULT 80 - #define NVIDIA_BOOST_MIN 5 - #define NVIDIA_BOOST_MAX 25 - #define NVIDIA_TEMP_MIN 75 -@@ -219,6 +226,29 @@ struct fan_curve_data { - u8 percents[FAN_CURVE_POINTS]; - }; - -+/* Tunables provided by ASUS for gaming laptops */ -+struct rog_tunables { -+ u32 cpu_default; -+ u32 cpu_max; ++ led_rgb->hdev = hdev; ++ led_rgb->brightness = 3; ++ led_rgb->removed = false; + -+ u32 platform_default; -+ u32 platform_max; ++ INIT_WORK(&led_rgb->work, ally_led_work); ++ spin_lock_init(&led_rgb->lock); + -+ u32 ppt_pl1_spl; // total -+ u32 ppt_pl2_sppt; // total -+ u32 ppt_apu_sppt; // cpu -+ u32 ppt_platform_sppt; // cpu -+ u32 ppt_fppt; // total ++ return led_rgb; ++} + -+ u32 nv_boost_default; -+ u32 nv_boost_max; -+ u32 nv_dynamic_boost; ++static void ally_rgb_remove(struct hid_device *hdev) ++{ ++ struct ally_rgb_leds *led_rgb = drvdata.led_rgb; ++ unsigned long flags; + -+ u32 nv_temp_default; -+ u32 nv_temp_max; -+ u32 nv_temp_target; -+}; ++ spin_lock_irqsave(&led_rgb->lock, flags); ++ led_rgb->removed = true; ++ spin_unlock_irqrestore(&led_rgb->lock, flags); ++ cancel_work_sync(&led_rgb->work); ++} + - struct asus_wmi { - int dsts_id; - int spec; -@@ -273,20 +303,13 @@ struct asus_wmi { - bool dgpu_disable_available; - u32 gpu_mux_dev; - -- /* Tunables provided by ASUS for gaming laptops */ -- u32 ppt_pl2_sppt; -- u32 ppt_pl1_spl; -- u32 ppt_apu_sppt; -- u32 ppt_platform_sppt; -- u32 ppt_fppt; -- u32 nv_dynamic_boost; -- u32 nv_temp_target; -+ struct rog_tunables rog_tunables; - - u32 kbd_rgb_dev; - bool kbd_rgb_state_available; - -- bool throttle_thermal_policy_available; - u8 throttle_thermal_policy_mode; -+ u32 throttle_thermal_policy_dev; - - bool cpu_fan_curve_available; - bool gpu_fan_curve_available; -@@ -334,20 +357,29 @@ static int asus_wmi_evaluate_method3(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; ++/**************************************************************************************************/ ++/* ROG Ally driver init */ ++/**************************************************************************************************/ ++static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, ++ int size) ++{ ++ struct ally_gamepad_cfg *cfg = drvdata.gamepad_cfg; ++ struct ally_x_device *ally_x = drvdata.ally_x; ++ ++ if (ally_x) { ++ if ((hdev->bus == BUS_USB && report->id == ALLY_X_INPUT_REPORT_USB && ++ size == ALLY_X_INPUT_REPORT_USB_SIZE) || ++ (cfg && data[0] == 0x5A)) { ++ ally_x_raw_event(ally_x, report, data, size); ++ } else { ++ return -1; ++ } + } - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - -+ pr_debug("Result: 0x%08x\n", tmp); - if (retval) - *retval = tmp; - - kfree(obj); - -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); - return -ENODEV; ++ if (cfg && !ally_x) { ++ input_report_key(cfg->input, KEY_PROG1, data[1] == 0x38); ++ input_report_key(cfg->input, KEY_F16, data[1] == 0xA6); ++ input_report_key(cfg->input, KEY_F17, data[1] == 0xA7); ++ input_report_key(cfg->input, KEY_F18, data[1] == 0xA8); ++ input_sync(cfg->input); + } - - return 0; - } -@@ -377,20 +409,29 @@ static int asus_wmi_evaluate_method5(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2, arg3, arg4); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; ++ ++ return 0; ++} ++ ++static int ally_gamepad_init(struct hid_device *hdev, u8 report_id) ++{ ++ const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, 0x65, ++ 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; ++ int ret; ++ ++ ret = asus_dev_set_report(hdev, buf, sizeof(buf)); ++ if (ret < 0) ++ hid_err(hdev, "Ally failed to send init command: %d\n", ret); ++ ++ return ret; ++} ++ ++static int ally_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); ++ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint; ++ int ret; ++ ++ if (ep->desc.bEndpointAddress != ALLY_CFG_INTF_IN_ADDRESS && ++ ep->desc.bEndpointAddress != ALLY_X_INTERFACE_ADDRESS) ++ return -ENODEV; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "Parse failed\n"); ++ return ret; + } - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - -+ pr_debug("Result: %x\n", tmp); - if (retval) - *retval = tmp; - - kfree(obj); - -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); - return -ENODEV; ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); ++ if (ret) { ++ hid_err(hdev, "Failed to start HID device\n"); ++ return ret; + } - - return 0; - } -@@ -416,8 +457,13 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; ++ ++ ret = hid_hw_open(hdev); ++ if (ret) { ++ hid_err(hdev, "Failed to open HID device\n"); ++ goto err_stop; + } - - obj = (union acpi_object *)output.pointer; - -@@ -453,8 +499,11 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, - - kfree(obj); - -- if (err) -+ if (err) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, err); - return err; ++ ++ /* Initialize MCU even before alloc */ ++ ret = ally_gamepad_init(hdev, FEATURE_REPORT_ID); ++ if (ret < 0) ++ return ret; ++ ++ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1); ++ if (ret < 0) ++ return ret; ++ ++ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2); ++ if (ret < 0) ++ return ret; ++ ++ drvdata.hdev = hdev; ++ hid_set_drvdata(hdev, &drvdata); ++ ++ /* This should almost always exist */ ++ if (ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS) { ++ drvdata.led_rgb = ally_gamepad_rgb_create(hdev); ++ if (IS_ERR(drvdata.led_rgb)) ++ hid_err(hdev, "Failed to create Ally gamepad LEDs.\n"); ++ else ++ hid_info(hdev, "Created Ally RGB LED controls.\n"); ++ ++ ally_gamepad_cfg_create(hdev); // assigns self ++ if (IS_ERR(drvdata.gamepad_cfg)) ++ hid_err(hdev, "Failed to create Ally gamepad attributes.\n"); ++ else ++ hid_info(hdev, "Created Ally gamepad attributes.\n"); ++ ++ if (IS_ERR(drvdata.led_rgb) && IS_ERR(drvdata.gamepad_cfg)) ++ goto err_close; + } - - return 0; - } -@@ -503,12 +552,28 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) - return 0; - } - --static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, -+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) -+{ -+ int err; + -+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); -+ if (err) -+ return err; ++ /* May or may not exist */ ++ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS) { ++ drvdata.ally_x = ally_x_create(hdev); ++ if (IS_ERR(drvdata.ally_x)) { ++ hid_err(hdev, "Failed to create Ally X gamepad.\n"); ++ drvdata.ally_x = NULL; ++ goto err_close; ++ } ++ hid_info(hdev, "Created Ally X controller.\n"); + -+ if (*retval == ~0) -+ return -ENODEV; ++ // Not required since we send this inputs ep through the gamepad input dev ++ if (drvdata.gamepad_cfg && drvdata.gamepad_cfg->input) { ++ input_unregister_device(drvdata.gamepad_cfg->input); ++ hid_info(hdev, "Ally X removed unrequired input dev.\n"); ++ } ++ } + + return 0; ++ ++err_close: ++ hid_hw_close(hdev); ++err_stop: ++ hid_hw_stop(hdev); ++ return ret; +} -+EXPORT_SYMBOL_GPL(asus_wmi_get_devstate_dsts); + -+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) - { - return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, - ctrl_param, retval); - } -+EXPORT_SYMBOL_GPL(asus_wmi_set_devstate); - - /* Helper for special devices with magic return codes */ - static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, -@@ -542,6 +607,7 @@ 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); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); - - return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); - } -@@ -625,6 +691,98 @@ static void asus_wmi_input_exit(struct asus_wmi *asus) - asus->inputdev = NULL; - } - -+/* Helper macros for generalised WMI calls */ ++static void ally_remove(struct hid_device *hdev) ++{ ++ if (drvdata.ally_x) ++ ally_x_remove(hdev); ++ if (drvdata.led_rgb) ++ ally_rgb_remove(hdev); ++ if (drvdata.gamepad_cfg) ++ ally_cfg_remove(hdev); ++ hid_hw_close(hdev); ++ hid_hw_stop(hdev); ++} + -+/* Generic store function for use with many ROG tunables */ -+static ssize_t rog_tunable_store(struct asus_wmi *asus, -+ struct attribute *attr, -+ const char *buf, size_t count, -+ u32 min, u32 max, u32 defaultv, -+ u32 *store_value, u32 wmi_dev) ++static int ally_resume(struct hid_device *hdev) +{ -+ int result, err, value; ++ int ret; + -+ result = kstrtoint(buf, 10, &value); -+ if (result) -+ return result; ++ ret = ally_gamepad_init(hdev, FEATURE_REPORT_ID); ++ if (ret < 0) ++ return ret; + -+ if (value == -1 ) -+ value = defaultv; -+ if (value < min || value > max) -+ return -EINVAL; ++ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1); ++ if (ret < 0) ++ return ret; + -+ err = asus_wmi_set_devstate(wmi_dev, value, &result); -+ if (err) { -+ pr_err("Failed to set %s: %d\n", attr->name, err); -+ return err; ++ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2); ++ if (ret < 0) ++ return ret; ++ ++ if (drvdata.ally_x && drvdata.ally_x->output_worker_initialized) ++ schedule_work(&drvdata.ally_x->output_worker); ++ ++ return ret; ++} ++ ++MODULE_DEVICE_TABLE(hid, rog_ally_devices); ++ ++static struct hid_driver rog_ally_cfg = { ++ .name = "asus_rog_ally", ++ .id_table = rog_ally_devices, ++ .probe = ally_probe, ++ .remove = ally_remove, ++ .raw_event = ally_raw_event, ++ .resume = ally_resume, ++}; ++ ++static int __init rog_ally_cfg_init(void) ++{ ++ return hid_register_driver(&rog_ally_cfg); ++} ++ ++static void __exit rog_ally_cfg_exit(void) ++{ ++ hid_unregister_driver(&rog_ally_cfg); ++} ++ ++module_init(rog_ally_cfg_init); ++module_exit(rog_ally_cfg_exit); ++ ++MODULE_AUTHOR("Luke D. Jones"); ++MODULE_DESCRIPTION("HID Driver for ASUS ROG Ally gamepad configuration."); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +new file mode 100644 +index 000000000000..252d9f126e32 +--- /dev/null ++++ b/drivers/hid/hid-asus-ally.h +@@ -0,0 +1,544 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * HID driver for Asus ROG laptops and Ally ++ * ++ * Copyright (c) 2023 Luke Jones ++ */ ++ ++#include ++#include ++ ++#define ALLY_X_INTERFACE_ADDRESS 0x87 ++ ++#define BTN_CODE_LEN 11 ++#define MAPPING_BLOCK_LEN 44 ++ ++#define TURBO_BLOCK_LEN 32 ++#define TURBO_BLOCK_STEP 2 ++ ++#define PAD_A "pad_a" ++#define PAD_B "pad_b" ++#define PAD_X "pad_x" ++#define PAD_Y "pad_y" ++#define PAD_LB "pad_lb" ++#define PAD_RB "pad_rb" ++#define PAD_LS "pad_ls" ++#define PAD_RS "pad_rs" ++#define PAD_DPAD_UP "pad_dpad_up" ++#define PAD_DPAD_DOWN "pad_dpad_down" ++#define PAD_DPAD_LEFT "pad_dpad_left" ++#define PAD_DPAD_RIGHT "pad_dpad_right" ++#define PAD_VIEW "pad_view" ++#define PAD_MENU "pad_menu" ++#define PAD_XBOX "pad_xbox" ++ ++#define KB_M1 "kb_m1" ++#define KB_M2 "kb_m2" ++#define KB_ESC "kb_esc" ++#define KB_F1 "kb_f1" ++#define KB_F2 "kb_f2" ++#define KB_F3 "kb_f3" ++#define KB_F4 "kb_f4" ++#define KB_F5 "kb_f5" ++#define KB_F6 "kb_f6" ++#define KB_F7 "kb_f7" ++#define KB_F8 "kb_f8" ++#define KB_F9 "kb_f9" ++#define KB_F10 "kb_f10" ++#define KB_F11 "kb_f11" ++#define KB_F12 "kb_f12" ++#define KB_F14 "kb_f14" ++#define KB_F15 "kb_f15" ++ ++#define KB_BACKTICK "kb_backtick" ++#define KB_1 "kb_1" ++#define KB_2 "kb_2" ++#define KB_3 "kb_3" ++#define KB_4 "kb_4" ++#define KB_5 "kb_5" ++#define KB_6 "kb_6" ++#define KB_7 "kb_7" ++#define KB_8 "kb_8" ++#define KB_9 "kb_9" ++#define KB_0 "kb_0" ++#define KB_HYPHEN "kb_hyphen" ++#define KB_EQUALS "kb_equals" ++#define KB_BACKSPACE "kb_backspace" ++ ++#define KB_TAB "kb_tab" ++#define KB_Q "kb_q" ++#define KB_W "kb_w" ++#define KB_E "kb_e" ++#define KB_R "kb_r" ++#define KB_T "kb_t" ++#define KB_Y "kb_y" ++#define KB_U "kb_u" ++#define KB_I "kb_i" ++#define KB_O "kb_o" ++#define KB_P "kb_p" ++#define KB_LBRACKET "kb_lbracket" ++#define KB_RBRACKET "kb_rbracket" ++#define KB_BACKSLASH "kb_bkslash" ++ ++#define KB_CAPS "kb_caps" ++#define KB_A "kb_a" ++#define KB_S "kb_s" ++#define KB_D "kb_d" ++#define KB_F "kb_f" ++#define KB_G "kb_g" ++#define KB_H "kb_h" ++#define KB_J "kb_j" ++#define KB_K "kb_k" ++#define KB_L "kb_l" ++#define KB_SEMI "kb_semicolon" ++#define KB_QUOTE "kb_quote" ++#define KB_RET "kb_enter" ++ ++#define KB_LSHIFT "kb_lshift" ++#define KB_Z "kb_z" ++#define KB_X "kb_x" ++#define KB_C "kb_c" ++#define KB_V "kb_v" ++#define KB_B "kb_b" ++#define KB_N "kb_n" ++#define KB_M "kb_m" ++#define KB_COMMA "kb_comma" ++#define KB_PERIOD "kb_period" ++#define KB_FWDSLASH "kb_fwdslash" ++#define KB_RSHIFT "kb_rshift" ++ ++#define KB_LCTL "kb_lctl" ++#define KB_META "kb_meta" ++#define KB_LALT "kb_lalt" ++#define KB_SPACE "kb_space" ++#define KB_RALT "kb_ralt" ++#define KB_MENU "kb_menu" ++#define KB_RCTL "kb_rctl" ++ ++#define KB_PRNTSCN "kb_prntscn" ++#define KB_SCRLCK "kb_scrlck" ++#define KB_PAUSE "kb_pause" ++#define KB_INS "kb_ins" ++#define KB_HOME "kb_home" ++#define KB_PGUP "kb_pgup" ++#define KB_DEL "kb_del" ++#define KB_END "kb_end" ++#define KB_PGDWN "kb_pgdwn" ++ ++#define KB_UP_ARROW "kb_up_arrow" ++#define KB_DOWN_ARROW "kb_down_arrow" ++#define KB_LEFT_ARROW "kb_left_arrow" ++#define KB_RIGHT_ARROW "kb_right_arrow" ++ ++#define NUMPAD_LOCK "numpad_lock" ++#define NUMPAD_FWDSLASH "numpad_fwdslash" ++#define NUMPAD_ASTERISK "numpad_asterisk" ++#define NUMPAD_HYPHEN "numpad_hyphen" ++#define NUMPAD_0 "numpad_0" ++#define NUMPAD_1 "numpad_1" ++#define NUMPAD_2 "numpad_2" ++#define NUMPAD_3 "numpad_3" ++#define NUMPAD_4 "numpad_4" ++#define NUMPAD_5 "numpad_5" ++#define NUMPAD_6 "numpad_6" ++#define NUMPAD_7 "numpad_7" ++#define NUMPAD_8 "numpad_8" ++#define NUMPAD_9 "numpad_9" ++#define NUMPAD_PLUS "numpad_plus" ++#define NUMPAD_ENTER "numpad_enter" ++#define NUMPAD_PERIOD "numpad_." ++ ++#define MOUSE_LCLICK "rat_lclick" ++#define MOUSE_RCLICK "rat_rclick" ++#define MOUSE_MCLICK "rat_mclick" ++#define MOUSE_WHEEL_UP "rat_wheel_up" ++#define MOUSE_WHEEL_DOWN "rat_wheel_down" ++ ++#define MEDIA_SCREENSHOT "media_screenshot" ++#define MEDIA_SHOW_KEYBOARD "media_show_keyboard" ++#define MEDIA_SHOW_DESKTOP "media_show_desktop" ++#define MEDIA_START_RECORDING "media_start_recording" ++#define MEDIA_MIC_OFF "media_mic_off" ++#define MEDIA_VOL_DOWN "media_vol_down" ++#define MEDIA_VOL_UP "media_vol_up" ++ ++/* required so we can have nested attributes with same name but different functions */ ++#define ALLY_DEVICE_ATTR_RW(_name, _sysfs_name) \ ++ struct device_attribute dev_attr_##_name = \ ++ __ATTR(_sysfs_name, 0644, _name##_show, _name##_store) ++ ++#define ALLY_DEVICE_ATTR_RO(_name, _sysfs_name) \ ++ struct device_attribute dev_attr_##_name = \ ++ __ATTR(_sysfs_name, 0444, _name##_show, NULL) ++ ++#define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ ++ struct device_attribute dev_attr_##_name = \ ++ __ATTR(_sysfs_name, 0200, NULL, _name##_store) ++ ++/* response curve macros */ ++#define ALLY_RESP_CURVE_SHOW(_name, _point_n) \ ++ static ssize_t _name##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ int idx = (_point_n - 1) * 2; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ return sysfs_emit( \ ++ buf, "%d %d\n", \ ++ ally_cfg->response_curve[ally_cfg->mode] \ ++ [btn_pair_side_left][idx], \ ++ ally_cfg->response_curve[ally_cfg->mode] \ ++ [btn_pair_side_right] \ ++ [idx + 1]); \ + } + -+ if (result > 1) { -+ pr_err("Failed to set %s (result): 0x%x\n", attr->name, result); -+ return -EIO; ++#define ALLY_RESP_CURVE_STORE(_name, _side, _point_n) \ ++ static ssize_t _name##_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ int ret = __gamepad_store_response_curve( \ ++ dev, buf, btn_pair_side_##_side, _point_n); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ + } + -+ if (store_value != NULL) -+ *store_value = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, attr->name); ++/* _point_n must start at 1 */ ++#define ALLY_JS_RC_POINT(_side, _point_n, _sysfs_label) \ ++ ALLY_RESP_CURVE_SHOW(rc_point_##_side##_##_point_n, _point_n); \ ++ ALLY_RESP_CURVE_STORE(rc_point_##_side##_##_point_n, _side, _point_n); \ ++ ALLY_DEVICE_ATTR_RW(rc_point_##_side##_##_point_n, \ ++ _sysfs_label##_point_n) ++ ++/* deadzone macros */ ++#define ALLY_AXIS_DEADZONE_SHOW(_axis) \ ++ static ssize_t _axis##_deadzone_show( \ ++ struct device *dev, struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ int side, is_tr; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ is_tr = _axis > xpad_axis_xy_right; \ ++ side = _axis == xpad_axis_xy_right || \ ++ _axis == xpad_axis_z_right ? \ ++ 2 : \ ++ 0; \ ++ return sysfs_emit( \ ++ buf, "%d %d\n", \ ++ ally_cfg->deadzones[ally_cfg->mode][is_tr][side], \ ++ ally_cfg->deadzones[ally_cfg->mode][is_tr][side + 1]); \ ++ } + -+ return count; -+} ++#define ALLY_AXIS_DEADZONE_STORE(_axis) \ ++ static ssize_t _axis##_deadzone_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ int ret = __gamepad_store_deadzones(ally_cfg, _axis, buf); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ ++ } ++ ++#define ALLY_AXIS_DEADZONE(_axis, _sysfs_label) \ ++ ALLY_AXIS_DEADZONE_SHOW(_axis); \ ++ ALLY_AXIS_DEADZONE_STORE(_axis); \ ++ ALLY_DEVICE_ATTR_RW(_axis##_deadzone, _sysfs_label) ++ ++/* button specific macros */ ++#define ALLY_BTN_SHOW(_fname, _pair, _side, _secondary) \ ++ static ssize_t _fname##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ return sysfs_emit(buf, "%s\n", \ ++ __btn_map_to_string(ally_cfg, _pair, _side, \ ++ _secondary)); \ ++ } ++ ++#define ALLY_BTN_STORE(_fname, _pair, _side, _secondary) \ ++ static ssize_t _fname##_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ int ret = __gamepad_mapping_store(ally_cfg, buf, _pair, _side, \ ++ _secondary); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ ++ } ++ ++#define ALLY_BTN_TURBO_SHOW(_fname, _pair, _side) \ ++ static ssize_t _fname##_turbo_show( \ ++ struct device *dev, struct device_attribute *attr, char *buf) \ ++ { \ ++ return sysfs_emit(buf, "%d\n", \ ++ __gamepad_turbo_show(dev, _pair, _side)); \ ++ } ++ ++#define ALLY_BTN_TURBO_STORE(_fname, _pair, _side) \ ++ static ssize_t _fname##_turbo_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ int ret = __gamepad_turbo_store(dev, buf, _pair, _side); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ ++ } ++ ++#define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ ++ static struct attribute *_fname##_attrs[] = { \ ++ &dev_attr_##_fname.attr, &dev_attr_##_fname##_macro.attr, \ ++ &dev_attr_##_fname##_turbo.attr, NULL \ ++ }; \ ++ static const struct attribute_group _fname##_attr_group = { \ ++ .name = __stringify(_name), \ ++ .attrs = _fname##_attrs, \ ++ } ++ ++#define ALLY_BTN_MAPPING(_fname, _pair, _side) \ ++ ALLY_BTN_SHOW(btn_mapping_##_fname, _pair, _side, false); \ ++ ALLY_BTN_STORE(btn_mapping_##_fname, _pair, _side, false); \ ++ ALLY_BTN_SHOW(btn_mapping_##_fname##_macro, _pair, _side, true); \ ++ ALLY_BTN_STORE(btn_mapping_##_fname##_macro, _pair, _side, true); \ ++ ALLY_BTN_TURBO_SHOW(btn_mapping_##_fname, _pair, _side); \ ++ ALLY_BTN_TURBO_STORE(btn_mapping_##_fname, _pair, _side); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname, remap); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_macro, macro_remap); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_turbo, turbo); \ ++ ALLY_BTN_ATTRS_GROUP(btn_##_fname, btn_mapping_##_fname) ++ ++/* calibration macros */ ++#define ALLY_CAL_STORE(_fname, _axis) \ ++ static ssize_t _fname##_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ int ret = __gamepad_cal_store(dev, buf, _axis); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ ++ } ++ ++#define ALLY_CAL_SHOW(_fname, _axis) \ ++ static ssize_t _fname##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ return __gamepad_cal_show(dev, buf, _axis); \ ++ } ++ ++#define ALLY_CAL_ATTR(_fname, _axis, _sysfs_label) \ ++ ALLY_CAL_STORE(_fname, _axis); \ ++ ALLY_CAL_SHOW(_fname, _axis); \ ++ ALLY_DEVICE_ATTR_RW(_fname, _sysfs_label) ++ ++#define ALLY_CAL_RESET_STORE(_fname, _axis) \ ++ static ssize_t _fname##_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ int ret = __gamepad_cal_reset(dev, buf, _axis); \ ++ if (ret < 0) \ ++ return ret; \ ++ return count; \ ++ } ++ ++#define ALLY_CAL_RESET_ATTR(_fname, _axis, _sysfs_label) \ ++ ALLY_CAL_RESET_STORE(_fname, _axis); \ ++ ALLY_DEVICE_ATTR_WO(_fname, _sysfs_label) ++ ++/* ++ * The following blocks of packets exist to make setting a default boot config ++ * easier. They were directly captured from setting the gamepad up. ++ */ ++ ++/* Default blocks for the xpad mode */ ++static const u8 XPAD_DEF1[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF2[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00, ++ 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF3[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF4[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF5[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF6[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00, ++ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF7[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF8[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 XPAD_DEF9[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++ ++/* default blocks for the wasd mode */ ++static const u8 WASD_DEF1[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00 ++}; ++static const u8 WASD_DEF2[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF3[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF4[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF5[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF6[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF7[MAPPING_BLOCK_LEN] = { ++ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF8[MAPPING_BLOCK_LEN] = { ++ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 WASD_DEF9[MAPPING_BLOCK_LEN] = { ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x0d, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++ ++/* ++ * the xpad_mode is used inside the mode setting packet and is used ++ * for indexing (xpad_mode - 1) ++ */ ++enum xpad_mode { ++ xpad_mode_game = 0x01, ++ xpad_mode_wasd = 0x02, ++ xpad_mode_mouse = 0x03, ++}; ++ ++/* the xpad_cmd determines which feature is set or queried */ ++enum xpad_cmd { ++ xpad_cmd_set_mode = 0x01, ++ xpad_cmd_set_mapping = 0x02, ++ xpad_cmd_set_js_dz = 0x04, /* deadzones */ ++ xpad_cmd_set_tr_dz = 0x05, /* deadzones */ ++ xpad_cmd_set_vibe_intensity = 0x06, ++ xpad_cmd_set_leds = 0x08, ++ xpad_cmd_check_ready = 0x0A, ++ xpad_cmd_set_calibration = 0x0D, ++ xpad_cmd_set_turbo = 0x0F, ++ xpad_cmd_set_response_curve = 0x13, ++ xpad_cmd_set_adz = 0x18, ++}; ++ ++/* the xpad_cmd determines which feature is set or queried */ ++enum xpad_cmd_len { ++ xpad_cmd_len_mode = 0x01, ++ xpad_cmd_len_mapping = 0x2c, ++ xpad_cmd_len_deadzone = 0x04, ++ xpad_cmd_len_vibe_intensity = 0x02, ++ xpad_cmd_len_leds = 0x0C, ++ xpad_cmd_len_calibration2 = 0x01, ++ xpad_cmd_len_calibration3 = 0x01, ++ xpad_cmd_len_turbo = 0x20, ++ xpad_cmd_len_response_curve = 0x09, ++ xpad_cmd_len_adz = 0x02, ++}; ++ ++/* ++ * the xpad_mode is used in various set and query HID packets and is ++ * used for indexing (xpad_axis - 1) ++ */ ++enum xpad_axis { ++ xpad_axis_xy_left = 0x01, ++ xpad_axis_xy_right = 0x02, ++ xpad_axis_z_left = 0x03, ++ xpad_axis_z_right = 0x04, ++}; ++ ++enum btn_pair { ++ btn_pair_dpad_u_d = 0x01, ++ btn_pair_dpad_l_r = 0x02, ++ btn_pair_ls_rs = 0x03, ++ btn_pair_lb_rb = 0x04, ++ btn_pair_a_b = 0x05, ++ btn_pair_x_y = 0x06, ++ btn_pair_view_menu = 0x07, ++ btn_pair_m1_m2 = 0x08, ++ btn_pair_lt_rt = 0x09, ++}; ++ ++enum btn_pair_side { ++ btn_pair_side_left = 0x00, ++ btn_pair_side_right = 0x01, ++}; +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 37e6d25593c2..9f83a770de8d 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); + #define FEATURE_KBD_LED_REPORT_ID1 0x5d + #define FEATURE_KBD_LED_REPORT_ID2 0x5e + ++#define ALLY_CFG_INTF_IN_ADDRESS 0x83 ++#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 ++#define ALLY_X_INTERFACE_ADDRESS 0x87 ++ + #define SUPPORT_KBD_BACKLIGHT BIT(0) + + #define MAX_TOUCH_MAJOR 8 +@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); + #define QUIRK_MEDION_E1239T BIT(10) + #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) + #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) ++#define QUIRK_ROG_ALLY_XPAD BIT(13) + + #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ + QUIRK_NO_INIT_REPORTS | \ +@@ -492,12 +497,19 @@ static void asus_kbd_backlight_work(struct work_struct *work) + */ + static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) + { ++ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + u32 value; + int ret; + + if (!IS_ENABLED(CONFIG_ASUS_WMI)) + return false; + ++ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && ++ dmi_check_system(asus_use_hid_led_dmi_ids)) { ++ hid_info(hdev, "using HID for asus::kbd_backlight\n"); ++ return false; ++ } ++ + ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, + ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value); + hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value); +@@ -996,6 +1008,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + + drvdata->quirks = id->driver_data; + ++ /* Ignore these endpoints as they will be used by other drivers */ ++ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { ++ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); ++ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint; ++ ++ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS || ++ ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS || ++ ep->desc.bEndpointAddress == ALLY_CFG_INTF_OUT_ADDRESS) ++ return -ENODEV; ++ } ++ + /* + * T90CHI's keyboard dock returns same ID values as T100CHI's dock. + * Thus, identify T90CHI dock with product name string. +@@ -1247,6 +1270,12 @@ 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_ALLY), ++ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD}, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, ++ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), ++ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, ++ USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 72d56ee7ce1b..57f1f1bc5eb6 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -209,7 +209,10 @@ + #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 + #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 + #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 ++#define USB_DEVICE_ID_ASUSTEK_ROG_RAIKIRI_PAD 0x1abb + #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe ++#define USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD 0x1a83 ++#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c + #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b + #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 + +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index ddfccc226751..d13c4085c228 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -265,6 +265,19 @@ config ASUS_WIRELESS + If you choose to compile this driver as a module the module will be + called asus-wireless. + ++config ASUS_ARMOURY ++ tristate "ASUS Armoury (firmware) Driver" ++ depends on ACPI_WMI ++ depends on ASUS_WMI ++ select FW_ATTR_CLASS ++ help ++ Say Y here if you have a WMI aware Asus laptop and would like to use the ++ firmware_attributes API to control various settings typically exposed in ++ the ASUS Armoury Crate application available on Windows. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called asus-armoury. + -+#define ROG_TUNABLE_STORE(_fname, _min, _max, _default, _wmi) \ -+static ssize_t _fname##_store(struct device *dev, \ -+ struct device_attribute *attr, const char *buf, size_t count) \ -+{ \ -+ struct asus_wmi *asus = dev_get_drvdata(dev); \ -+ return rog_tunable_store(asus, &attr->attr, buf, count, \ -+ _min, asus->rog_tunables._max, asus->rog_tunables._default, \ -+ &asus->rog_tunables._fname, _wmi); \ -+} -+ -+#define ROG_TUNABLE_SHOW(_fname) \ -+static ssize_t _fname##_show(struct device *dev, struct device_attribute *attr, char *buf) \ -+{ \ -+ struct asus_wmi *asus = dev_get_drvdata(dev); \ -+ return sysfs_emit(buf, "%u\n", asus->rog_tunables._fname); \ -+} -+ -+#define ROG_TUNABLE_MIN_SHOW(_fname, _minv) \ -+static ssize_t _fname##_min_show(struct device *dev, struct device_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, "%u\n", _minv); \ -+} -+ -+#define ROG_TUNABLE_MAX_SHOW(_fname, _maxv) \ -+static ssize_t _fname##_max_show(struct device *dev, struct device_attribute *attr, char *buf) \ -+{ \ -+ struct asus_wmi *asus = dev_get_drvdata(dev); \ -+ return sysfs_emit(buf, "%u\n", asus->rog_tunables._maxv); \ -+} -+ -+#define ROG_ATTR_RW(_fname, _minv, _maxv, _defaultv, _wmi) \ -+ROG_TUNABLE_MIN_SHOW(_fname, _minv); \ -+ROG_TUNABLE_MAX_SHOW(_fname, _maxv); \ -+ROG_TUNABLE_STORE(_fname, _minv, _maxv, _defaultv, _wmi);\ -+ROG_TUNABLE_SHOW(_fname); \ -+static DEVICE_ATTR_RO(_fname##_min); \ -+static DEVICE_ATTR_RO(_fname##_max); \ -+static DEVICE_ATTR_RW(_fname) -+ -+ROG_ATTR_RW(ppt_platform_sppt, -+ PPT_PLATFORM_MIN, platform_max, platform_default, ASUS_WMI_DEVID_PPT_PLAT_SPPT); -+ROG_ATTR_RW(ppt_pl2_sppt, -+ PPT_CPU_LIMIT_MIN, cpu_max, cpu_default, ASUS_WMI_DEVID_PPT_PL2_SPPT); -+ROG_ATTR_RW(ppt_apu_sppt, -+ PPT_PLATFORM_MIN, platform_max, platform_default, ASUS_WMI_DEVID_PPT_APU_SPPT); -+ROG_ATTR_RW(ppt_pl1_spl, -+ PPT_CPU_LIMIT_MIN, cpu_max, cpu_default, ASUS_WMI_DEVID_PPT_PL1_SPL); -+ROG_ATTR_RW(ppt_fppt, -+ PPT_CPU_LIMIT_MIN, cpu_max, cpu_default, ASUS_WMI_DEVID_PPT_FPPT); -+ROG_ATTR_RW(nv_dynamic_boost, -+ NVIDIA_BOOST_MIN, nv_boost_max, nv_boost_default, ASUS_WMI_DEVID_NV_DYN_BOOST); -+ROG_ATTR_RW(nv_temp_target, -+ NVIDIA_TEMP_MIN, nv_temp_max, nv_temp_default, ASUS_WMI_DEVID_NV_THERM_TARGET); -+ - /* Tablet mode ****************************************************************/ - - static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) -@@ -995,306 +1153,6 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = { - NULL, + config ASUS_WMI + tristate "ASUS WMI Driver" + depends on ACPI_WMI +@@ -276,6 +289,7 @@ config ASUS_WMI + depends on HOTPLUG_PCI + depends on ACPI_VIDEO || ACPI_VIDEO = n + depends on SERIO_I8042 || SERIO_I8042 = n ++ select ASUS_ARMOURY + select INPUT_SPARSEKMAP + select LEDS_CLASS + select NEW_LEDS +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index e1b142947067..fe3e7e7dede8 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o + # ASUS + obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o + obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o ++obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o + obj-$(CONFIG_ASUS_WMI) += asus-wmi.o + obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o + obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o +diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c +index 0b2eb0ae85fe..460444cda1b2 100644 +--- a/drivers/platform/x86/amd/pmf/pmf-quirks.c ++++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c +@@ -29,6 +29,14 @@ static const struct dmi_system_id fwbug_list[] = { + }, + .driver_data = &quirk_no_sps_bug, + }, ++ { ++ .ident = "ROG Ally X", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "RC72LA"), ++ }, ++ .driver_data = &quirk_no_sps_bug, ++ }, + {} }; --/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ --static ssize_t ppt_pl2_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_pl2_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_pl2_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt"); -- -- return count; --} -- --static ssize_t ppt_pl2_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); --} --static DEVICE_ATTR_RW(ppt_pl2_sppt); -- --/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/ --static ssize_t ppt_pl1_spl_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; +@@ -48,4 +56,3 @@ void amd_pmf_quirks_init(struct amd_pmf_dev *dev) + dmi_id->ident); + } + } - -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_pl1_spl: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_pl1_spl = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl"); -- -- return count; --} --static ssize_t ppt_pl1_spl_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); --} --static DEVICE_ATTR_RW(ppt_pl1_spl); -- --/* Tunable: PPT APU FPPT ******************************************************/ --static ssize_t ppt_fppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_fppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_fppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt"); -- -- return count; --} -- --static ssize_t ppt_fppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_fppt); --} --static DEVICE_ATTR_RW(ppt_fppt); -- --/* Tunable: PPT APU SPPT *****************************************************/ --static ssize_t ppt_apu_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_apu_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_apu_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt"); -- -- return count; --} -- --static ssize_t ppt_apu_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); --} --static DEVICE_ATTR_RW(ppt_apu_sppt); -- --/* Tunable: PPT platform SPPT ************************************************/ --static ssize_t ppt_platform_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_platform_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_platform_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt"); -- -- return count; --} -- --static ssize_t ppt_platform_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); --} --static DEVICE_ATTR_RW(ppt_platform_sppt); -- --/* Tunable: NVIDIA dynamic boost *********************************************/ --static ssize_t nv_dynamic_boost_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result); -- if (err) { -- pr_warn("Failed to set nv_dynamic_boost: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->nv_dynamic_boost = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost"); -- -- return count; --} -- --static ssize_t nv_dynamic_boost_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); --} --static DEVICE_ATTR_RW(nv_dynamic_boost); -- --/* Tunable: NVIDIA temperature target ****************************************/ --static ssize_t nv_temp_target_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result); -- if (err) { -- pr_warn("Failed to set nv_temp_target: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->nv_temp_target = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target"); -- -- return count; --} -- --static ssize_t nv_temp_target_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%u\n", asus->nv_temp_target); --} --static DEVICE_ATTR_RW(nv_temp_target); -- - /* Ally MCU Powersave ********************************************************/ - static ssize_t mcu_powersave_show(struct device *dev, - struct device_attribute *attr, char *buf) -@@ -1685,7 +1544,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus) +diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c +new file mode 100644 +index 000000000000..aa784b6b9483 +--- /dev/null ++++ b/drivers/platform/x86/asus-armoury.c +@@ -0,0 +1,1049 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes ++ * class to expose the various WMI functions that many gaming and some ++ * non-gaming ASUS laptops have available. ++ * These typically don't fit anywhere else in the sysfs such as under LED class, ++ * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool. ++ * ++ * Copyright(C) 2010 Intel Corporation. ++ * Copyright(C) 2024-2024 Luke Jones ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "asus-armoury.h" ++#include "firmware_attributes_class.h" ++ ++#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" ++ ++#define ASUS_MINI_LED_MODE_MASK 0x03 ++/* Standard modes for devices with only on/off */ ++#define ASUS_MINI_LED_OFF 0x00 ++#define ASUS_MINI_LED_ON 0x01 ++/* New mode on some devices, define here to clarify remapping later */ ++#define ASUS_MINI_LED_STRONG_MODE 0x02 ++/* New modes for devices with 3 mini-led mode types */ ++#define ASUS_MINI_LED_2024_WEAK 0x00 ++#define ASUS_MINI_LED_2024_STRONG 0x01 ++#define ASUS_MINI_LED_2024_OFF 0x02 ++ ++enum cpu_core_type { ++ CPU_CORE_PERF = 0, ++ CPU_CORE_POWER, ++}; ++ ++enum cpu_core_value { ++ CPU_CORE_DEFAULT = 0, ++ CPU_CORE_MIN, ++ CPU_CORE_MAX, ++ CPU_CORE_CURRENT, ++}; ++ ++/* Default limits for tunables available on ASUS ROG laptops */ ++#define PPT_CPU_LIMIT_MIN 5 ++#define PPT_CPU_LIMIT_MAX 150 ++#define PPT_CPU_LIMIT_DEFAULT 80 ++#define PPT_PLATFORM_MIN 5 ++#define PPT_PLATFORM_MAX 100 ++#define PPT_PLATFORM_DEFAULT 80 ++#define NVIDIA_BOOST_MIN 5 ++#define NVIDIA_BOOST_MAX 25 ++#define NVIDIA_TEMP_MIN 75 ++#define NVIDIA_TEMP_MAX 87 ++#define NVIDIA_POWER_MIN 0 ++#define NVIDIA_POWER_MAX 70 ++#define NVIDIA_POWER_DEFAULT 70 ++ ++/* Tunables provided by ASUS for gaming laptops */ ++struct rog_tunables { ++ u32 cpu_default; ++ u32 cpu_min; ++ u32 cpu_max; ++ ++ u32 platform_default; ++ u32 platform_min; ++ u32 platform_max; ++ ++ u32 ppt_pl1_spl; // cpu ++ u32 ppt_pl2_sppt; // cpu ++ u32 ppt_apu_sppt; // plat ++ u32 ppt_platform_sppt; // plat ++ u32 ppt_fppt; // cpu ++ ++ u32 nv_boost_default; ++ u32 nv_boost_min; ++ u32 nv_boost_max; ++ u32 nv_dynamic_boost; ++ ++ u32 nv_temp_default; ++ u32 nv_temp_min; ++ u32 nv_temp_max; ++ u32 nv_temp_target; ++ ++ u32 dgpu_tgp_default; ++ u32 dgpu_tgp_min; ++ u32 dgpu_tgp_max; ++ u32 dgpu_tgp; ++ ++ u32 min_perf_cores; ++ u32 max_perf_cores; ++ u32 max_power_cores; ++}; ++ ++static const struct class *fw_attr_class; ++ ++struct asus_armoury_priv { ++ struct device *fw_attr_dev; ++ struct kset *fw_attr_kset; ++ ++ struct rog_tunables *rog_tunables; ++ u32 mini_led_dev_id; ++ u32 gpu_mux_dev_id; ++ ++ struct mutex mutex; ++}; ++ ++static struct asus_armoury_priv asus_armoury = { ++ .mutex = __MUTEX_INITIALIZER(asus_armoury.mutex) ++}; ++ ++struct fw_attrs_group { ++ u32 pending_reboot; ++}; ++ ++static struct fw_attrs_group fw_attrs = { ++ .pending_reboot = 0, ++}; ++ ++struct asus_attr_group { ++ const struct attribute_group *attr_group; ++ u32 wmi_devid; ++}; ++ ++/** ++ * asus_wmi_is_present() - determine if a WMI interface is available. ++ * @dev_id: The WMI function ID to use. ++ * ++ * Returns: Boolean state. Note that an error will also return false. ++ */ ++static bool asus_wmi_is_present(u32 dev_id) ++{ ++ u32 retval; ++ int status; ++ ++ status = asus_wmi_get_devstate_dsts(dev_id, &retval); ++ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); ++ ++ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); ++} ++ ++static void asus_set_reboot_and_signal_event(void) ++{ ++ fw_attrs.pending_reboot = 1; ++ kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); ++} ++ ++static ssize_t pending_reboot_show(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "%u\n", fw_attrs.pending_reboot); ++} ++ ++static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); ++ ++static bool asus_bios_requires_reboot(struct kobj_attribute *attr) ++{ ++ return !strcmp(attr->attr.name, "gpu_mux_mode") || ++ !strcmp(attr->attr.name, "cores_performance") || ++ !strcmp(attr->attr.name, "cores_efficiency") || ++ !strcmp(attr->attr.name, "panel_hd_mode"); ++} ++ ++/** ++ * attr_int_store() - Generic store function for use with most WMI functions. ++ * @kobj: Pointer to the driver object. ++ * @kobj_attribute: Pointer the the attribute calling this function. ++ * @buf: The buffer to read from, this is parsed to `int` type. ++ * @count: ++ * @min: Minimum accepted value. Below this returns -EINVAL. ++ * @max: Maximum accepted value. Above this returns -EINVAL. ++ * @store_value: Pointer to where the parsed value should be stored. ++ * @wmi_dev: The WMI function ID to use. ++ * ++ * The WMI functions available on most ASUS laptops return a 1 as "success", and ++ * a 0 as failed. However some functions can return n > 1 for additional errors. ++ * attr_int_store() currently treats all values which are not 1 as errors, ignoring ++ * the possible differences in WMI error returns. ++ * ++ * Returns: Either count, or an error. ++ */ ++static ssize_t attr_int_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count, ++ u32 min, u32 max, u32 *store_value, u32 wmi_dev) ++{ ++ u32 result, value; ++ int err; ++ ++ err = kstrtouint(buf, 10, &value); ++ if (err) ++ return err; ++ ++ if (value < min || value > max) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(wmi_dev, value, &result); ++ if (err) { ++ pr_err("Failed to set %s: %d\n", attr->attr.name, err); ++ return err; ++ } ++ ++ if (result != 1) { ++ pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result); ++ return -EIO; ++ } ++ ++ if (store_value != NULL) ++ *store_value = value; ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ if (asus_bios_requires_reboot(attr)) ++ asus_set_reboot_and_signal_event(); ++ ++ return count; ++} ++ ++/* Mini-LED mode **************************************************************/ ++static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ u32 value; ++ int err; ++ ++ err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value); ++ if (err) ++ return err; ++ ++ value = value & ASUS_MINI_LED_MODE_MASK; ++ ++ /* ++ * Remap the mode values to match previous generation mini-led. The last gen ++ * WMI 0 == off, while on this version WMI 2 ==off (flipped). ++ */ ++ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { ++ switch (value) { ++ case ASUS_MINI_LED_2024_WEAK: ++ value = ASUS_MINI_LED_ON; ++ break; ++ case ASUS_MINI_LED_2024_STRONG: ++ value = ASUS_MINI_LED_STRONG_MODE; ++ break; ++ case ASUS_MINI_LED_2024_OFF: ++ value = ASUS_MINI_LED_OFF; ++ break; ++ } ++ } ++ ++ return sysfs_emit(buf, "%u\n", value); ++} ++ ++static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 mode; ++ ++ err = kstrtou32(buf, 10, &mode); ++ if (err) ++ return err; ++ ++ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && ++ mode > ASUS_MINI_LED_ON) ++ return -EINVAL; ++ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && ++ mode > ASUS_MINI_LED_STRONG_MODE) ++ return -EINVAL; ++ ++ /* ++ * Remap the mode values so expected behaviour is the same as the last ++ * generation of mini-LED with 0 == off, 1 == on. ++ */ ++ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { ++ switch (mode) { ++ case ASUS_MINI_LED_OFF: ++ mode = ASUS_MINI_LED_2024_OFF; ++ break; ++ case ASUS_MINI_LED_ON: ++ mode = ASUS_MINI_LED_2024_WEAK; ++ break; ++ case ASUS_MINI_LED_STRONG_MODE: ++ mode = ASUS_MINI_LED_2024_STRONG; ++ break; ++ } ++ } ++ ++ err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result); ++ if (err) { ++ pr_warn("Failed to set mini-LED: %d\n", err); ++ return err; ++ } ++ ++ if (result != 1) { ++ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ return count; ++} ++ ++static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ switch (asus_armoury.mini_led_dev_id) { ++ case ASUS_WMI_DEVID_MINI_LED_MODE: ++ return sysfs_emit(buf, "0;1\n"); ++ case ASUS_WMI_DEVID_MINI_LED_MODE2: ++ return sysfs_emit(buf, "0;1;2\n"); ++ } ++ ++ return sysfs_emit(buf, "0\n"); ++} ++ ++ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); ++ ++static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 optimus; ++ ++ err = kstrtou32(buf, 10, &optimus); ++ if (err) ++ return err; ++ ++ if (optimus > 1) ++ return -EINVAL; ++ ++ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) { ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result); ++ if (err) ++ return err; ++ if (result && !optimus) { ++ err = -ENODEV; ++ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); ++ return err; ++ } ++ } ++ ++ if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) { ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result); ++ if (err) ++ return err; ++ if (result && !optimus) { ++ err = -ENODEV; ++ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); ++ return err; ++ } ++ } ++ ++ err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result); ++ if (err) { ++ pr_err("Failed to set GPU MUX mode: %d\nn", err); ++ return err; ++ } ++ /* !1 is considered a fail by ASUS */ ++ if (result != 1) { ++ pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ return count; ++} ++WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id); ++ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); ++ ++/* ++ * A user may be required to store the value twice, typcial store first, then ++ * rescan PCI bus to activate power, then store a second time to save correctly. ++ * The reason for this is that an extra code path in the ACPI is enabled when ++ * the device and bus are powered. ++ */ ++static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 disable; ++ ++ err = kstrtou32(buf, 10, &disable); ++ if (err) ++ return err; ++ ++ if (disable > 1) ++ return -EINVAL; ++ ++ if (asus_armoury.gpu_mux_dev_id) { ++ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result); ++ if (err) ++ return err; ++ if (!result && disable) { ++ err = -ENODEV; ++ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); ++ return err; ++ } ++ } ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); ++ if (err) { ++ pr_warn("Failed to set dgpu disable: %d\n", err); ++ return err; ++ } ++ ++ if (result != 1) { ++ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ return count; ++} ++WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU); ++ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU"); ++ ++/* The ACPI call to enable the eGPU also disables the internal dGPU */ ++static ssize_t egpu_enable_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 enable; ++ ++ err = kstrtou32(buf, 10, &enable); ++ if (err) ++ return err; ++ ++ if (enable > 1) ++ return -EINVAL; ++ ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result); ++ if (err) { ++ pr_warn("Failed to get egpu connection status: %d\n", err); ++ return err; ++ } ++ ++ if (asus_armoury.gpu_mux_dev_id) { ++ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result); ++ if (err) { ++ pr_warn("Failed to get gpu mux status: %d\n", result); ++ return result; ++ } ++ if (!result && enable) { ++ err = -ENODEV; ++ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); ++ return err; ++ } ++ } ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); ++ if (err) { ++ pr_warn("Failed to set egpu state: %d\n", err); ++ return err; ++ } ++ ++ if (result != 1) { ++ pr_warn("Failed to set egpu state (retval): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ return count; ++} ++WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU); ++ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); ++ ++/* Device memory available to APU */ ++ ++static ssize_t apu_mem_current_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ int err; ++ u32 mem; ++ ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem); ++ if (err) ++ return err; ++ ++ switch (mem) { ++ case 256: ++ mem = 0; ++ break; ++ case 258: ++ mem = 1; ++ break; ++ case 259: ++ mem = 2; ++ break; ++ case 260: ++ mem = 3; ++ break; ++ case 261: ++ mem = 4; ++ break; ++ case 262: ++ /* This is out of order and looks wrong but is correct */ ++ mem = 8; ++ break; ++ case 263: ++ mem = 5; ++ break; ++ case 264: ++ mem = 6; ++ break; ++ case 265: ++ mem = 7; ++ break; ++ default: ++ mem = 4; ++ break; ++ } ++ ++ return sysfs_emit(buf, "%d\n", mem); ++} ++ ++static ssize_t apu_mem_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 requested, mem; ++ ++ result = kstrtou32(buf, 10, &requested); ++ if (result) ++ return result; ++ ++ switch (requested) { ++ case 0: ++ mem = 0; ++ break; ++ case 1: ++ mem = 258; ++ break; ++ case 2: ++ mem = 259; ++ break; ++ case 3: ++ mem = 260; ++ break; ++ case 4: ++ mem = 261; ++ break; ++ case 5: ++ mem = 263; ++ break; ++ case 6: ++ mem = 264; ++ break; ++ case 7: ++ mem = 265; ++ break; ++ case 8: ++ /* This is outof order and looks wrong but is correct */ ++ mem = 262; ++ break; ++ default: ++ return -EIO; ++ } ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result); ++ if (err) { ++ pr_warn("Failed to set apu_mem: %d\n", err); ++ return err; ++ } ++ ++ pr_info("APU memory changed to %dGB, reboot required\n", requested); ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ ++ asus_set_reboot_and_signal_event(); ++ ++ return count; ++} ++ ++static ssize_t apu_mem_possible_values_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n"); ++} ++ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory for the APU to use"); ++ ++static int init_max_cpu_cores(void) ++{ ++ u32 cores; ++ int err; ++ ++ asus_armoury.rog_tunables->min_perf_cores = 4; ++ asus_armoury.rog_tunables->max_perf_cores = 4; ++ asus_armoury.rog_tunables->max_power_cores = 8; ++ ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores); ++ if (err) ++ return err; ++ ++ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; ++ asus_armoury.rog_tunables->max_power_cores = (cores & 0xff00) >> 8; ++ asus_armoury.rog_tunables->max_perf_cores = cores & 0xff; ++ ++ return 0; ++} ++ ++static ssize_t cores_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf, ++ enum cpu_core_type core_type, ++ enum cpu_core_value core_value) ++{ ++ u32 cores; ++ int err; ++ ++ switch (core_value) { ++ case CPU_CORE_DEFAULT: ++ case CPU_CORE_MAX: ++ if (core_type == CPU_CORE_PERF) ++ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_perf_cores); ++ else ++ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_power_cores); ++ case CPU_CORE_MIN: ++ if (core_type == CPU_CORE_PERF) ++ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->min_perf_cores); ++ else ++ return sysfs_emit(buf, "%d\n", 0); ++ default: ++ break; ++ } ++ ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores); ++ if (err) ++ return err; ++ ++ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; ++ if (core_type == CPU_CORE_PERF) ++ cores &= 0xff; ++ else ++ cores = (cores & 0xff00) >> 8; ++ return sysfs_emit(buf, "%d\n", cores); ++} ++ ++static ssize_t cores_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buf, ++ enum cpu_core_type core_type) ++{ ++ int result, err; ++ u32 cores, currentv, min, max; ++ ++ result = kstrtou32(buf, 10, &cores); ++ if (result) ++ return result; ++ ++ if (core_type == CPU_CORE_PERF) { ++ min = asus_armoury.rog_tunables->min_perf_cores; ++ max = asus_armoury.rog_tunables->max_perf_cores; ++ } else { ++ min = 0; ++ max = asus_armoury.rog_tunables->max_power_cores; ++ } ++ if (cores < min || cores > max) ++ return -EINVAL; ++ ++ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, ¤tv); ++ if (err) ++ return err; ++ ++ if (core_type == CPU_CORE_PERF) ++ cores |= (currentv & 0xff00); ++ else ++ cores |= currentv & 0xff; ++ ++ if (cores == currentv) ++ return 0; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, cores, &result); ++ if (err) { ++ pr_warn("Failed to set CPU core count: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set CPU core count (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ pr_info("CPU core count changed, reboot required\n"); ++ sysfs_notify(kobj, NULL, attr->attr.name); ++ asus_set_reboot_and_signal_event(); ++ ++ return 0; ++} ++ ++static ssize_t cores_performance_min_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN); ++} ++ ++static ssize_t cores_performance_max_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX); ++} ++ ++static ssize_t cores_performance_default_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT); ++} ++ ++static ssize_t cores_performance_current_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT); ++} ++ ++static ssize_t cores_performance_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int err; ++ ++ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF); ++ if (err) ++ return err; ++ ++ return count; ++} ++ATTR_GROUP_CORES_RW(cores_performance, "cores_performance", ++ "Set the max available performance cores"); ++ ++static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN); ++} ++ ++static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX); ++} ++ ++static ssize_t cores_efficiency_default_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT); ++} ++ ++static ssize_t cores_efficiency_current_value_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT); ++} ++ ++static ssize_t cores_efficiency_current_value_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int err; ++ ++ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER); ++ if (err) ++ return err; ++ ++ return count; ++} ++ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency", ++ "Set the max available efficiency cores"); ++ ++/* Simple attribute creation */ ++ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, ++ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, ++ cpu_default, cpu_min, cpu_max, 1, "Set the CPU fast package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT, ++ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT, ++ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, ++ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit"); ++ ++ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST, ++ nv_boost_default, nv_boost_min, nv_boost_max, 1, "Set the Nvidia dynamic boost limit"); ++ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET, ++ nv_temp_default, nv_boost_min, nv_temp_max, 1, "Set the Nvidia max thermal limit"); ++ATTR_GROUP_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP, ++ "Read the base TGP value"); ++ATTR_GROUP_ROG_TUNABLE(dgpu_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, ++ dgpu_tgp_default, dgpu_tgp_min, dgpu_tgp_max, 1, ++ "Set the additional TGP on top of the base TGP"); ++ ++ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, ++ "0;1;2", "Show the current mode of charging"); ++ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, ++ "Set the boot POST sound"); ++ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, ++ "Set MCU powersaving mode"); ++ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, ++ "Set the panel refresh overdrive"); ++ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, ++ "Set the panel HD mode to UHD<0> or FHD<1>"); ++ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, ++ "Show the eGPU connection status"); ++ ++/* If an attribute does not require any special case handling add it here */ ++static const struct asus_attr_group armoury_attr_groups[] = { ++ { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, ++ { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, ++ { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, ++ ++ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, ++ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, ++ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, ++ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, ++ { &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT }, ++ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, ++ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, ++ { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, ++ { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, ++ { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, ++ { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX }, ++ { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX }, ++ ++ { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, ++ { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, ++ { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, ++ { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, ++ { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, ++}; ++ ++static int asus_fw_attr_add(void) ++{ ++ int err; ++ ++ err = fw_attributes_class_get(&fw_attr_class); ++ if (err) ++ goto fail_class_created; ++ ++ asus_armoury.fw_attr_dev = device_create(fw_attr_class, NULL, ++ MKDEV(0, 0), NULL, "%s", DRIVER_NAME); ++ ++ if (IS_ERR(asus_armoury.fw_attr_dev)) { ++ err = PTR_ERR(asus_armoury.fw_attr_dev); ++ goto fail_class_created; ++ } ++ ++ asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, ++ &asus_armoury.fw_attr_dev->kobj); ++ if (!asus_armoury.fw_attr_dev) { ++ err = -ENOMEM; ++ pr_debug("Failed to create and add attributes\n"); ++ goto err_destroy_classdev; ++ } ++ ++ err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); ++ if (err) { ++ pr_warn("Failed to create sysfs level attributes\n"); ++ goto fail_class_created; ++ } ++ ++ err = 0; ++ asus_armoury.mini_led_dev_id = 0; ++ if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) { ++ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, ++ &mini_led_mode_attr_group); ++ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) { ++ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, ++ &mini_led_mode_attr_group); ++ } ++ if (err) ++ pr_warn("Failed to create sysfs-group for mini_led\n"); ++ ++ err = 0; ++ asus_armoury.gpu_mux_dev_id = 0; ++ if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) { ++ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); ++ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) { ++ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); ++ } ++ if (err) ++ pr_warn("Failed to create sysfs-group for gpu_mux\n"); ++ ++ for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { ++ if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid)) ++ continue; ++ ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, ++ armoury_attr_groups[i].attr_group); ++ if (err) ++ pr_warn("Failed to create sysfs-group for %s\n", ++ armoury_attr_groups[i].attr_group->name); ++ else ++ pr_debug("Created sysfs-group for %s\n", ++ armoury_attr_groups[i].attr_group->name); ++ } ++ ++ return 0; ++ ++err_destroy_classdev: ++ device_destroy(fw_attr_class, MKDEV(0, 0)); ++ ++fail_class_created: ++ fw_attributes_class_put(); ++ return err; ++} ++ ++/* Init / exit ****************************************************************/ ++ ++/* Set up the min/max and defaults for ROG tunables */ ++static void init_rog_tunables(struct rog_tunables *rog) ++{ ++ const char *product; ++ u32 max_boost = NVIDIA_BOOST_MAX; ++ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT; ++ u32 cpu_max = PPT_CPU_LIMIT_MAX; ++ u32 platform_default = PPT_PLATFORM_DEFAULT; ++ u32 platform_max = PPT_PLATFORM_MAX; ++ ++ /* ++ * ASUS product_name contains everything required, e.g, ++ * "ROG Flow X16 GV601VV_GV601VV_00185149B" ++ */ ++ product = dmi_get_system_info(DMI_PRODUCT_NAME); ++ ++ if (strstr(product, "GA402R")) { ++ cpu_default = 125; ++ } else if (strstr(product, "13QY")) { ++ cpu_max = 250; ++ } else if (strstr(product, "X13")) { ++ cpu_max = 75; ++ cpu_default = 50; ++ } else if (strstr(product, "RC71")) { ++ cpu_max = 50; ++ cpu_default = 30; ++ } else if (strstr(product, "G814") ++ || strstr(product, "G614") ++ || strstr(product, "G834") ++ || strstr(product, "G634")) { ++ cpu_max = 175; ++ } else if (strstr(product, "GA402X") ++ || strstr(product, "GA403") ++ || strstr(product, "FA507N") ++ || strstr(product, "FA507X") ++ || strstr(product, "FA707N") ++ || strstr(product, "FA707X")) { ++ cpu_max = 90; ++ } ++ ++ if (strstr(product, "GZ301ZE")) ++ max_boost = 5; ++ else if (strstr(product, "FX507ZC4")) ++ max_boost = 15; ++ else if (strstr(product, "GU605")) ++ max_boost = 20; ++ ++ /* ensure defaults for tunables */ ++ rog->cpu_default = cpu_default; ++ rog->cpu_min = PPT_CPU_LIMIT_MIN; ++ rog->cpu_max = cpu_max; ++ ++ rog->platform_default = platform_default; ++ rog->platform_max = PPT_PLATFORM_MIN; ++ rog->platform_max = platform_max; ++ ++ rog->ppt_pl1_spl = cpu_default; ++ rog->ppt_pl2_sppt = cpu_default; ++ rog->ppt_apu_sppt = cpu_default; ++ ++ rog->ppt_platform_sppt = platform_default; ++ rog->ppt_fppt = platform_default; ++ ++ rog->nv_boost_default = NVIDIA_BOOST_MAX; ++ rog->nv_boost_max = NVIDIA_BOOST_MIN; ++ rog->nv_boost_max = max_boost; ++ rog->nv_dynamic_boost = NVIDIA_BOOST_MIN; ++ ++ rog->nv_temp_default = NVIDIA_TEMP_MAX; ++ rog->nv_temp_max = NVIDIA_TEMP_MIN; ++ rog->nv_temp_max = NVIDIA_TEMP_MAX; ++ rog->nv_temp_target = NVIDIA_TEMP_MIN; ++ ++ rog->dgpu_tgp_default = NVIDIA_POWER_DEFAULT; ++ rog->dgpu_tgp_min = NVIDIA_POWER_MIN; ++ rog->dgpu_tgp_max = NVIDIA_POWER_MAX; ++ rog->dgpu_tgp = NVIDIA_POWER_MAX; ++ ++} ++ ++static int __init asus_fw_init(void) ++{ ++ int err; ++ ++ fw_attrs.pending_reboot = 0; ++ ++ mutex_lock(&asus_armoury.mutex); ++ ++ asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL); ++ if (!asus_armoury.rog_tunables) { ++ mutex_unlock(&asus_armoury.mutex); ++ return -ENOMEM; ++ } ++ init_rog_tunables(asus_armoury.rog_tunables); ++ init_max_cpu_cores(); ++ ++ err = asus_fw_attr_add(); ++ mutex_unlock(&asus_armoury.mutex); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void __exit asus_fw_exit(void) ++{ ++ mutex_lock(&asus_armoury.mutex); ++ ++ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); ++ kset_unregister(asus_armoury.fw_attr_kset); ++ device_destroy(fw_attr_class, MKDEV(0, 0)); ++ fw_attributes_class_put(); ++ ++ mutex_unlock(&asus_armoury.mutex); ++} ++ ++module_init(asus_fw_init); ++module_exit(asus_fw_exit); ++ ++MODULE_AUTHOR("Luke Jones "); ++MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); +diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h +new file mode 100644 +index 000000000000..25b2c055930e +--- /dev/null ++++ b/drivers/platform/x86/asus-armoury.h +@@ -0,0 +1,259 @@ ++/* SPDX-License-Identifier: GPL-2.0 ++ * ++ * Definitions for kernel modules using asus-armoury driver ++ * ++ * Copyright (c) 2024 Luke Jones ++ */ ++ ++#ifndef _ASUS_BIOSCFG_H_ ++#define _ASUS_BIOSCFG_H_ ++ ++#include "firmware_attributes_class.h" ++#include ++ ++#define DRIVER_NAME "asus-armoury" ++ ++static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count, ++ u32 min, u32 max, u32 *store_value, u32 wmi_dev); ++ ++ ++static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "integer\n"); ++} ++ ++static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "enumeration\n"); ++} ++ ++#define __ASUS_ATTR_RO(_func, _name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = _func##_##_name##_show, \ ++} ++ ++#define __ASUS_ATTR_RO_AS(_name, _show) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = _show, \ ++} ++ ++#define __ASUS_ATTR_RW(_func, _name) __ATTR(_name, 0644, \ ++ _func##_##_name##_show, _func##_##_name##_store) ++ ++#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ ++static ssize_t _attr##_store(struct kobject *kobj, \ ++ struct kobj_attribute *attr, \ ++ const char *buf, size_t count) \ ++{ \ ++ return attr_int_store(kobj, attr, buf, count, _min, _max, NULL, _wmi); \ ++} ++ ++#define WMI_SHOW_INT(_attr, _fmt, _wmi) \ ++static ssize_t _attr##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ u32 result; \ ++ int err; \ ++ err = asus_wmi_get_devstate_dsts(_wmi, &result); \ ++ if (err) \ ++ return err; \ ++ return sysfs_emit(buf, _fmt, \ ++ result & ~ASUS_WMI_DSTS_PRESENCE_BIT); \ ++} ++ ++/* Create functions and attributes for use in other macros or on their own */ ++ ++#define __ATTR_CURRENT_INT_RO(_attr, _wmi) \ ++WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ ++static struct kobj_attribute attr_##_attr##_current_value = \ ++ __ASUS_ATTR_RO(_attr, current_value) ++ ++#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi) \ ++__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \ ++WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ ++static struct kobj_attribute attr_##_attr##_current_value = \ ++ __ASUS_ATTR_RW(_attr, current_value) ++ ++/* Shows a formatted static variable */ ++#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ ++static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ return sysfs_emit(buf, _fmt, _val); \ ++} \ ++static struct kobj_attribute attr_##_attrname##_##_prop = \ ++ __ASUS_ATTR_RO(_attrname, _prop) ++ ++/* Requires current_value show&|store */ ++#define __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) \ ++__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ ++static struct kobj_attribute attr_##_attrname##_type = \ ++ __ASUS_ATTR_RO_AS(type, int_type_show); \ ++static struct attribute *_attrname##_attrs[] = { \ ++ &attr_##_attrname##_current_value.attr, \ ++ &attr_##_attrname##_display_name.attr, \ ++ &attr_##_attrname##_type.attr, \ ++ NULL \ ++}; \ ++static const struct attribute_group _attrname##_attr_group = { \ ++ .name = _fsname, \ ++ .attrs = _attrname##_attrs \ ++} ++ ++/* Boolean style enumeration, base macro. Requires adding show/store */ ++#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ ++__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ ++__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ ++static struct kobj_attribute attr_##_attrname##_type = \ ++ __ASUS_ATTR_RO_AS(type, enum_type_show); \ ++static struct attribute *_attrname##_attrs[] = { \ ++ &attr_##_attrname##_current_value.attr, \ ++ &attr_##_attrname##_display_name.attr, \ ++ &attr_##_attrname##_possible_values.attr, \ ++ &attr_##_attrname##_type.attr, \ ++ NULL \ ++}; \ ++static const struct attribute_group _attrname##_attr_group = { \ ++ .name = _fsname, \ ++ .attrs = _attrname##_attrs \ ++} ++ ++#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ ++ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ ++ __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) ++ ++#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ ++ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ ++ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) ++ ++#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ ++ __ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi); \ ++ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) ++ ++/* ++ * Requires _current_value_show(), _current_value_show() ++ */ ++#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname) \ ++static struct kobj_attribute attr_##_attrname##_current_value = \ ++ __ASUS_ATTR_RW(_attrname, current_value); \ ++ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) ++ ++#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, \ ++ _possible, _dispname) \ ++ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ ++ __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) ++ ++/* ++ * Requires _current_value_show(), _current_value_show() ++ * and _possible_values_show() ++ */ ++#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname) \ ++__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ ++static struct kobj_attribute attr_##_attrname##_current_value = \ ++ __ASUS_ATTR_RW(_attrname, current_value); \ ++static struct kobj_attribute attr_##_attrname##_possible_values = \ ++ __ASUS_ATTR_RO(_attrname, possible_values); \ ++static struct kobj_attribute attr_##_attrname##_type = \ ++ __ASUS_ATTR_RO_AS(type, enum_type_show); \ ++static struct attribute *_attrname##_attrs[] = { \ ++ &attr_##_attrname##_current_value.attr, \ ++ &attr_##_attrname##_display_name.attr, \ ++ &attr_##_attrname##_possible_values.attr, \ ++ &attr_##_attrname##_type.attr, \ ++ NULL \ ++}; \ ++static const struct attribute_group _attrname##_attr_group = { \ ++ .name = _fsname, \ ++ .attrs = _attrname##_attrs \ ++} ++ ++/* CPU core attributes need a little different in setup */ ++#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname) \ ++__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ ++__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ ++static struct kobj_attribute attr_##_attrname##_current_value = \ ++ __ASUS_ATTR_RW(_attrname, current_value); \ ++static struct kobj_attribute attr_##_attrname##_default_value = \ ++ __ASUS_ATTR_RO(_attrname, default_value); \ ++static struct kobj_attribute attr_##_attrname##_min_value = \ ++ __ASUS_ATTR_RO(_attrname, min_value); \ ++static struct kobj_attribute attr_##_attrname##_max_value = \ ++ __ASUS_ATTR_RO(_attrname, max_value); \ ++static struct kobj_attribute attr_##_attrname##_type = \ ++ __ASUS_ATTR_RO_AS(type, int_type_show); \ ++static struct attribute *_attrname##_attrs[] = { \ ++ &attr_##_attrname##_current_value.attr, \ ++ &attr_##_attrname##_default_value.attr, \ ++ &attr_##_attrname##_min_value.attr, \ ++ &attr_##_attrname##_max_value.attr, \ ++ &attr_##_attrname##_scalar_increment.attr, \ ++ &attr_##_attrname##_display_name.attr, \ ++ &attr_##_attrname##_type.attr, \ ++ NULL \ ++}; \ ++static const struct attribute_group _attrname##_attr_group = { \ ++ .name = _fsname, \ ++ .attrs = _attrname##_attrs \ ++} ++ ++/* ++ * ROG PPT attributes need a little different in setup as they ++ * require rog_tunables members. ++ */ ++ ++#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi) \ ++static ssize_t _attr##_current_value_store(struct kobject *kobj, \ ++ struct kobj_attribute *attr, \ ++ const char *buf, size_t count) \ ++{ \ ++ return attr_int_store(kobj, attr, buf, count, \ ++ asus_armoury.rog_tunables->_min, \ ++ asus_armoury.rog_tunables->_max, \ ++ &asus_armoury.rog_tunables->_attr, _wmi); \ ++} \ ++static ssize_t _attr##_current_value_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ return sysfs_emit(buf, "%u\n", asus_armoury.rog_tunables->_attr);\ ++} \ ++static struct kobj_attribute attr_##_attr##_current_value = \ ++ __ASUS_ATTR_RW(_attr, current_value) ++ ++#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ ++static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ ++ struct kobj_attribute *attr, char *buf) \ ++{ \ ++ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->_val);\ ++} \ ++static struct kobj_attribute attr_##_attrname##_##_prop = \ ++ __ASUS_ATTR_RO(_attrname, _prop) ++ ++#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, \ ++ _min, _max, _incstep, _dispname) \ ++__ROG_TUNABLE_SHOW(default_value, _attrname, _default); \ ++__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi); \ ++__ROG_TUNABLE_SHOW(min_value, _attrname, _min); \ ++__ROG_TUNABLE_SHOW(max_value, _attrname, _max); \ ++__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep); \ ++__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ ++static struct kobj_attribute attr_##_attrname##_type = \ ++ __ASUS_ATTR_RO_AS(type, int_type_show); \ ++static struct attribute *_attrname##_attrs[] = { \ ++ &attr_##_attrname##_current_value.attr, \ ++ &attr_##_attrname##_default_value.attr, \ ++ &attr_##_attrname##_min_value.attr, \ ++ &attr_##_attrname##_max_value.attr, \ ++ &attr_##_attrname##_scalar_increment.attr, \ ++ &attr_##_attrname##_display_name.attr, \ ++ &attr_##_attrname##_type.attr, \ ++ NULL \ ++}; \ ++static const struct attribute_group _attrname##_attr_group = { \ ++ .name = _fsname, \ ++ .attrs = _attrname##_attrs \ ++} ++ ++#endif /* _ASUS_BIOSCFG_H_ */ +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index bc9c5db38324..9faebd12bd49 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -97,6 +97,12 @@ module_param(fnlock_default, bool, 0444); + #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 + #define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 + ++#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 ++#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 ++#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 ++ ++#define PLATFORM_PROFILE_MAX 2 ++ + #define USB_INTEL_XUSB2PR 0xD0 + #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + +@@ -146,6 +152,20 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; + + static int throttle_thermal_policy_write(struct asus_wmi *); + ++static const struct dmi_system_id asus_ally_mcu_quirk[] = { ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "RC71L"), ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "RC72L"), ++ }, ++ }, ++ { }, ++}; ++ + static bool ashs_present(void) + { + int i = 0; +@@ -285,8 +305,8 @@ struct asus_wmi { + u32 kbd_rgb_dev; + bool kbd_rgb_state_available; + +- bool throttle_thermal_policy_available; + u8 throttle_thermal_policy_mode; ++ u32 throttle_thermal_policy_dev; + + bool cpu_fan_curve_available; + bool gpu_fan_curve_available; +@@ -334,20 +354,29 @@ static int asus_wmi_evaluate_method3(u32 method_id, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, + &input, &output); + +- if (ACPI_FAILURE(status)) ++ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n", ++ __func__, method_id, arg0, arg1, arg2); ++ if (ACPI_FAILURE(status)) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, -EIO); + return -EIO; ++ } + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32) obj->integer.value; + ++ pr_debug("Result: 0x%08x\n", tmp); + if (retval) + *retval = tmp; + + kfree(obj); + +- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) ++ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, -ENODEV); + return -ENODEV; ++ } + + return 0; + } +@@ -377,20 +406,29 @@ static int asus_wmi_evaluate_method5(u32 method_id, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, + &input, &output); + +- if (ACPI_FAILURE(status)) ++ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", ++ __func__, method_id, arg0, arg1, arg2, arg3, arg4); ++ if (ACPI_FAILURE(status)) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, -EIO); + return -EIO; ++ } + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32) obj->integer.value; + ++ pr_debug("Result: %x\n", tmp); + if (retval) + *retval = tmp; + + kfree(obj); + +- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) ++ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, -ENODEV); + return -ENODEV; ++ } + + return 0; + } +@@ -416,8 +454,13 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, + &input, &output); + +- if (ACPI_FAILURE(status)) ++ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n", ++ __func__, method_id, arg0, arg1); ++ if (ACPI_FAILURE(status)) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, -EIO); + return -EIO; ++ } + + obj = (union acpi_object *)output.pointer; + +@@ -453,8 +496,11 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, + + kfree(obj); + +- if (err) ++ if (err) { ++ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", ++ __func__, method_id, arg0, err); + return err; ++ } + + return 0; + } +@@ -503,12 +549,56 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) + return 0; + } + +-static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, +- u32 *retval) ++/** ++ * asus_wmi_get_devstate_dsts() - Get the WMI function state. ++ * @dev_id: The WMI function to call. ++ * @retval: A pointer to where to store the value returned from WMI. ++ * ++ * The returned WMI function state can also be used to determine if the WMI ++ * function is supported by checking if the asus_wmi_get_devstate_dsts() ++ * returns an error. ++ * ++ * On success the return value is 0, and the retval is a valid value returned ++ * by the successful WMI function call. An error value is returned only if the ++ * WMI function failed, or if it returns "unsupported" which is typically a 0 ++ * (no return, and no 'supported' bit set), or a 0xFFFFFFFE (~1) which if not ++ * caught here can result in unexpected behaviour later. ++ */ ++int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) ++{ ++ int err; ++ ++ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); ++ if (err) ++ return err; ++ /* Be explicit about retval */ ++ if (*retval == 0xFFFFFFFE || *retval == 0) ++ return -ENODEV; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(asus_wmi_get_devstate_dsts); ++ ++/** ++ * asus_wmi_set_devstate() - Set the WMI function state. ++ * @dev_id: The WMI function to call. ++ * @ctrl_param: The argument to be used for this WMI function. ++ * @retval: A pointer to where to store the value returned from WMI. ++ * ++ * The returned WMI function state if not checked here for error as ++ * asus_wmi_set_devstate() is not called unless first paired with a call to ++ * asus_wmi_get_devstate_dsts() to check that the WMI function is supported. ++ * ++ * On success the return value is 0, and the retval is a valid value returned ++ * by the successful WMI function call. An error value is returned only if the ++ * WMI function failed. ++ */ ++int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) + { + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, + ctrl_param, retval); + } ++EXPORT_SYMBOL_GPL(asus_wmi_set_devstate); + + /* Helper for special devices with magic return codes */ + static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, +@@ -542,6 +632,7 @@ 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); ++ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); + + return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); + } +@@ -1685,7 +1776,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus) goto error; } @@ -2091,20 +4593,7 @@ index bc9c5db38324..9c80aa073758 100644 asus->kbd_led_wk = led_val; asus->kbd_led.name = "asus::kbd_backlight"; asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; -@@ -2312,10 +2172,10 @@ static ssize_t mini_led_mode_store(struct device *dev, - return result; - - if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && -- mode > ASUS_MINI_LED_ON) -+ mode > ASUS_MINI_LED_ON) - return -EINVAL; - if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && -- mode > ASUS_MINI_LED_STRONG_MODE) -+ mode > ASUS_MINI_LED_STRONG_MODE) - return -EINVAL; - - /* -@@ -3127,7 +2987,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) +@@ -3127,7 +3219,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) int err, fan_idx; u8 mode = 0; @@ -2113,7 +4602,7 @@ index bc9c5db38324..9c80aa073758 100644 mode = asus->throttle_thermal_policy_mode; /* DEVID_PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ if (mode == 2) -@@ -3334,7 +3194,7 @@ static ssize_t fan_curve_enable_store(struct device *dev, +@@ -3334,7 +3426,7 @@ static ssize_t fan_curve_enable_store(struct device *dev, * For machines with throttle this is the only way to reset fans * to default mode of operation (does not erase curve data). */ @@ -2122,7 +4611,7 @@ index bc9c5db38324..9c80aa073758 100644 err = throttle_thermal_policy_write(asus); if (err) return err; -@@ -3551,8 +3411,8 @@ static const struct attribute_group asus_fan_curve_attr_group = { +@@ -3551,8 +3643,8 @@ static const struct attribute_group asus_fan_curve_attr_group = { __ATTRIBUTE_GROUPS(asus_fan_curve_attr); /* @@ -2133,7 +4622,7 @@ index bc9c5db38324..9c80aa073758 100644 */ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) { -@@ -3562,18 +3422,27 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) +@@ -3562,18 +3654,27 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, ASUS_WMI_DEVID_CPU_FAN_CURVE); @@ -2164,7 +4653,7 @@ index bc9c5db38324..9c80aa073758 100644 if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available -@@ -3593,38 +3462,31 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) +@@ -3593,38 +3694,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) } /* Throttle thermal policy ****************************************************/ @@ -2197,33 +4686,16 @@ index bc9c5db38324..9c80aa073758 100644 - u8 value; + u8 value = asus->throttle_thermal_policy_mode; u32 retval; -+ bool vivo; + int err; - value = asus->throttle_thermal_policy_mode; -+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ if (vivo) { -+ switch (value) { -+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -+ value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -+ value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -+ value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; -+ break; -+ default: -+ break; -+ } -+ } - +- - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, + err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, &retval); sysfs_notify(&asus->platform_device->dev.kobj, NULL, -@@ -3654,7 +3516,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) +@@ -3654,7 +3730,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) static int throttle_thermal_policy_set_default(struct asus_wmi *asus) { @@ -2232,54 +4704,100 @@ index bc9c5db38324..9c80aa073758 100644 return 0; asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -@@ -3664,9 +3526,14 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus) - static int throttle_thermal_policy_switch_next(struct asus_wmi *asus) - { +@@ -3666,7 +3742,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus) u8 new_mode = asus->throttle_thermal_policy_mode + 1; -+ bool vivo; int err; - if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) -+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ if (!vivo && new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) -+ new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -+ -+ if (vivo && new_mode > ASUS_THROTTLE_THERMAL_POLICY_FULLSPEED) ++ if (new_mode > PLATFORM_PROFILE_MAX) new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; asus->throttle_thermal_policy_mode = new_mode; -@@ -3699,13 +3566,17 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, - struct asus_wmi *asus = dev_get_drvdata(dev); - u8 new_mode; - int result; -+ bool vivo; - int err; - - result = kstrtou8(buf, 10, &new_mode); +@@ -3705,7 +3781,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, if (result < 0) return result; - if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) -+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ if (vivo && new_mode > ASUS_THROTTLE_THERMAL_POLICY_FULLSPEED) -+ return -EINVAL; -+ else if (!vivo && new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) ++ if (new_mode > PLATFORM_PROFILE_MAX) return -EINVAL; asus->throttle_thermal_policy_mode = new_mode; -@@ -3722,7 +3593,10 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, +@@ -3722,10 +3798,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, return count; } -// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent +/* + * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent -+ * VIVOBOOK: 3 - fans full speed + */ static DEVICE_ATTR_RW(throttle_thermal_policy); /* Platform profile ***********************************************************/ -@@ -3788,7 +3662,7 @@ static int platform_profile_setup(struct asus_wmi *asus) ++static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode) ++{ ++ bool vivo; ++ ++ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; ++ ++ if (vivo) { ++ switch (mode) { ++ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: ++ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; ++ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: ++ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; ++ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: ++ return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; ++ } ++ } ++ ++ return mode; ++} ++ ++static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode) ++{ ++ bool vivo; ++ ++ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; ++ ++ if (vivo) { ++ switch (mode) { ++ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; ++ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; ++ case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_SILENT; ++ } ++ } ++ ++ return mode; ++} ++ + static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) + { +@@ -3733,10 +3851,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + int tp; + + asus = container_of(pprof, struct asus_wmi, platform_profile_handler); +- + tp = asus->throttle_thermal_policy_mode; + +- switch (tp) { ++ switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) { + case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: + *profile = PLATFORM_PROFILE_BALANCED; + break; +@@ -3775,7 +3892,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, + return -EOPNOTSUPP; + } + +- asus->throttle_thermal_policy_mode = tp; ++ asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp); + return throttle_thermal_policy_write(asus); + } + +@@ -3788,7 +3905,7 @@ static int platform_profile_setup(struct asus_wmi *asus) * Not an error if a component platform_profile relies on is unavailable * so early return, skipping the setup of platform_profile. */ @@ -2288,7 +4806,7 @@ index bc9c5db38324..9c80aa073758 100644 return 0; dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); -@@ -3803,8 +3677,13 @@ static int platform_profile_setup(struct asus_wmi *asus) +@@ -3803,8 +3920,13 @@ static int platform_profile_setup(struct asus_wmi *asus) asus->platform_profile_handler.choices); err = platform_profile_register(&asus->platform_profile_handler); @@ -2303,7 +4821,7 @@ index bc9c5db38324..9c80aa073758 100644 asus->platform_profile_support = true; return 0; -@@ -4203,7 +4082,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) +@@ -4203,7 +4325,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { if (asus->fan_boost_mode_available) fan_boost_mode_switch_next(asus); @@ -2312,79 +4830,16 @@ index bc9c5db38324..9c80aa073758 100644 throttle_thermal_policy_switch_next(asus); return; -@@ -4329,13 +4208,27 @@ static struct attribute *platform_attributes[] = { - &dev_attr_als_enable.attr, - &dev_attr_fan_boost_mode.attr, - &dev_attr_throttle_thermal_policy.attr, -- &dev_attr_ppt_pl2_sppt.attr, - &dev_attr_ppt_pl1_spl.attr, -+ &dev_attr_ppt_pl1_spl_min.attr, -+ &dev_attr_ppt_pl1_spl_max.attr, -+ &dev_attr_ppt_pl2_sppt.attr, -+ &dev_attr_ppt_pl2_sppt_min.attr, -+ &dev_attr_ppt_pl2_sppt_max.attr, - &dev_attr_ppt_fppt.attr, -+ &dev_attr_ppt_fppt_min.attr, -+ &dev_attr_ppt_fppt_max.attr, - &dev_attr_ppt_apu_sppt.attr, -+ &dev_attr_ppt_apu_sppt_min.attr, -+ &dev_attr_ppt_apu_sppt_max.attr, - &dev_attr_ppt_platform_sppt.attr, -+ &dev_attr_ppt_platform_sppt_min.attr, -+ &dev_attr_ppt_platform_sppt_max.attr, - &dev_attr_nv_dynamic_boost.attr, -+ &dev_attr_nv_dynamic_boost_min.attr, -+ &dev_attr_nv_dynamic_boost_max.attr, - &dev_attr_nv_temp_target.attr, -+ &dev_attr_nv_temp_target_min.attr, -+ &dev_attr_nv_temp_target_max.attr, - &dev_attr_mcu_powersave.attr, - &dev_attr_boot_sound.attr, - &dev_attr_panel_od.attr, -@@ -4375,20 +4268,34 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, +@@ -4375,7 +4497,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, 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; -- else if (attr == &dev_attr_ppt_pl2_sppt.attr) + ok = asus->throttle_thermal_policy_dev != 0; -+ else if (attr == &dev_attr_ppt_pl2_sppt.attr -+ || attr == &dev_attr_ppt_pl2_sppt_min.attr -+ || attr == &dev_attr_ppt_pl2_sppt_max.attr) + else if (attr == &dev_attr_ppt_pl2_sppt.attr) devid = ASUS_WMI_DEVID_PPT_PL2_SPPT; -- else if (attr == &dev_attr_ppt_pl1_spl.attr) -+ else if (attr == &dev_attr_ppt_pl1_spl.attr -+ || attr == &dev_attr_ppt_pl1_spl_min.attr -+ || attr == &dev_attr_ppt_pl1_spl_max.attr) - devid = ASUS_WMI_DEVID_PPT_PL1_SPL; -- else if (attr == &dev_attr_ppt_fppt.attr) -+ else if (attr == &dev_attr_ppt_fppt.attr -+ || attr == &dev_attr_ppt_fppt_min.attr -+ || attr == &dev_attr_ppt_fppt_max.attr) - devid = ASUS_WMI_DEVID_PPT_FPPT; -- else if (attr == &dev_attr_ppt_apu_sppt.attr) -+ else if (attr == &dev_attr_ppt_apu_sppt.attr -+ || attr == &dev_attr_ppt_apu_sppt_min.attr -+ || attr == &dev_attr_ppt_apu_sppt_max.attr) - devid = ASUS_WMI_DEVID_PPT_APU_SPPT; -- else if (attr == &dev_attr_ppt_platform_sppt.attr) -+ else if (attr == &dev_attr_ppt_platform_sppt.attr -+ || attr == &dev_attr_ppt_platform_sppt_min.attr -+ || attr == &dev_attr_ppt_platform_sppt_max.attr) - devid = ASUS_WMI_DEVID_PPT_PLAT_SPPT; -- else if (attr == &dev_attr_nv_dynamic_boost.attr) -+ else if (attr == &dev_attr_nv_dynamic_boost.attr -+ || attr == &dev_attr_nv_dynamic_boost_min.attr -+ || attr == &dev_attr_nv_dynamic_boost_max.attr) - devid = ASUS_WMI_DEVID_NV_DYN_BOOST; -- else if (attr == &dev_attr_nv_temp_target.attr) -+ else if (attr == &dev_attr_nv_temp_target.attr -+ || attr == &dev_attr_nv_temp_target_min.attr -+ || attr == &dev_attr_nv_temp_target_max.attr) - devid = ASUS_WMI_DEVID_NV_THERM_TARGET; - else if (attr == &dev_attr_mcu_powersave.attr) - devid = ASUS_WMI_DEVID_MCU_POWERSAVE; -@@ -4401,8 +4308,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + else if (attr == &dev_attr_ppt_pl1_spl.attr) +@@ -4401,8 +4523,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, else if (attr == &dev_attr_available_mini_led_mode.attr) ok = asus->mini_led_dev_id != 0; @@ -2396,102 +4851,16 @@ index bc9c5db38324..9c80aa073758 100644 return ok ? attr->mode : 0; } -@@ -4612,6 +4521,77 @@ static void asus_wmi_debugfs_init(struct asus_wmi *asus) - - /* Init / exit ****************************************************************/ - -+/* Set up the min/max and defaults for ROG tunables */ -+static void init_rog_tunables(struct asus_wmi *asus) -+{ -+ const char *product; -+ u32 max_boost = NVIDIA_BOOST_MAX; -+ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT; -+ u32 cpu_max = PPT_CPU_LIMIT_MAX; -+ u32 platform_default = PPT_PLATFORM_DEFAULT; -+ u32 platform_max = PPT_PLATFORM_MAX; -+ -+ /* -+ * ASUS product_name contains everything required, e.g, -+ * "ROG Flow X16 GV601VV_GV601VV_00185149B" -+ */ -+ product = dmi_get_system_info(DMI_PRODUCT_NAME); -+ -+ if (strstr(product, "GA402R")) { -+ cpu_default = 125; -+ } else if (strstr(product, "13QY")) { -+ cpu_max = 250; -+ } else if (strstr(product, "X13")) { -+ cpu_max = 75; -+ cpu_default = 50; -+ } else if (strstr(product, "RC71")) { -+ cpu_max = 50; -+ cpu_default = 30; -+ } else if (strstr(product, "G814") -+ || strstr(product, "G614") -+ || strstr(product, "G834") -+ || strstr(product, "G634")) { -+ cpu_max = 175; -+ } else if (strstr(product, "GA402X") -+ || strstr(product, "GA403") -+ || strstr(product, "FA507N") -+ || strstr(product, "FA507X") -+ || strstr(product, "FA707N") -+ || strstr(product, "FA707X")) { -+ cpu_max = 90; -+ } -+ -+ if (strstr(product, "GZ301ZE")) -+ max_boost = 5; -+ else if (strstr(product, "FX507ZC4")) -+ max_boost = 15; -+ else if (strstr(product, "GU605")) -+ max_boost = 20; -+ -+ /* ensure defaults for tunables */ -+ asus->rog_tunables.cpu_default = cpu_default; -+ asus->rog_tunables.cpu_max = cpu_max; -+ -+ asus->rog_tunables.platform_default = platform_default; -+ asus->rog_tunables.platform_max = platform_max; -+ -+ asus->rog_tunables.ppt_pl1_spl = cpu_default; -+ asus->rog_tunables.ppt_pl2_sppt = cpu_default; -+ asus->rog_tunables.ppt_apu_sppt = cpu_default; -+ -+ asus->rog_tunables.ppt_platform_sppt = platform_default; -+ asus->rog_tunables.ppt_fppt = platform_default; -+ -+ asus->rog_tunables.nv_boost_default = NVIDIA_BOOST_MAX; -+ asus->rog_tunables.nv_boost_max = max_boost; -+ asus->rog_tunables.nv_dynamic_boost = NVIDIA_BOOST_MIN; -+ -+ asus->rog_tunables.nv_temp_default = NVIDIA_TEMP_MAX; -+ asus->rog_tunables.nv_temp_max = NVIDIA_TEMP_MAX; -+ asus->rog_tunables.nv_temp_target = NVIDIA_TEMP_MIN; -+ -+} -+ - static int asus_wmi_add(struct platform_device *pdev) - { - struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); -@@ -4637,15 +4617,7 @@ static int asus_wmi_add(struct platform_device *pdev) - if (err) - goto fail_platform; - -- /* ensure defaults for tunables */ -- asus->ppt_pl2_sppt = 5; -- asus->ppt_pl1_spl = 5; -- asus->ppt_apu_sppt = 5; -- asus->ppt_platform_sppt = 5; -- asus->ppt_fppt = 5; -- asus->nv_dynamic_boost = 5; -- asus->nv_temp_target = 75; -- -+ init_rog_tunables(asus); - asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); +@@ -4650,7 +4774,7 @@ static int asus_wmi_add(struct platform_device *pdev) asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); -@@ -4667,18 +4639,17 @@ static int asus_wmi_add(struct platform_device *pdev) + asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) +- && dmi_match(DMI_BOARD_NAME, "RC71L"); ++ && dmi_check_system(asus_ally_mcu_quirk); + + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) + asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; +@@ -4667,18 +4791,17 @@ static int asus_wmi_add(struct platform_device *pdev) else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; @@ -2516,7 +4885,7 @@ index bc9c5db38324..9c80aa073758 100644 goto fail_platform_profile_setup; err = asus_wmi_sysfs_init(asus->platform_device); -@@ -4771,7 +4742,6 @@ static int asus_wmi_add(struct platform_device *pdev) +@@ -4771,7 +4894,6 @@ static int asus_wmi_add(struct platform_device *pdev) fail_input: asus_wmi_sysfs_exit(asus->platform_device); fail_sysfs: @@ -2524,8 +4893,52 @@ index bc9c5db38324..9c80aa073758 100644 fail_custom_fan_curve: fail_platform_profile_setup: if (asus->platform_profile_support) +diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile +index 9f16cb514397..a8aba07bf1dc 100644 +--- a/drivers/platform/x86/intel/int3472/Makefile ++++ b/drivers/platform/x86/intel/int3472/Makefile +@@ -1,4 +1,7 @@ + obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \ +- intel_skl_int3472_tps68470.o +-intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o +-intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o ++ intel_skl_int3472_tps68470.o \ ++ intel_skl_int3472_common.o ++intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o ++intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o ++ ++intel_skl_int3472_common-y += common.o +diff --git a/drivers/platform/x86/intel/int3472/common.c b/drivers/platform/x86/intel/int3472/common.c +index 9db2bb0bbba4..b3a2578e06c1 100644 +--- a/drivers/platform/x86/intel/int3472/common.c ++++ b/drivers/platform/x86/intel/int3472/common.c +@@ -29,6 +29,7 @@ union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *i + + return obj; + } ++EXPORT_SYMBOL_GPL(skl_int3472_get_acpi_buffer); + + int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) + { +@@ -52,6 +53,7 @@ int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) + kfree(obj); + return ret; + } ++EXPORT_SYMBOL_GPL(skl_int3472_fill_cldb); + + /* sensor_adev_ret may be NULL, name_ret must not be NULL */ + int skl_int3472_get_sensor_adev_and_name(struct device *dev, +@@ -80,3 +82,8 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev, + + return ret; + } ++EXPORT_SYMBOL_GPL(skl_int3472_get_sensor_adev_and_name); ++ ++MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver library"); ++MODULE_AUTHOR("Daniel Scally "); ++MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 3eb5cd6773ad..870f4bb57100 100644 +index 3eb5cd6773ad..a23cc8624218 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -4,6 +4,7 @@ @@ -2581,20 +4994,11 @@ index 3eb5cd6773ad..870f4bb57100 100644 static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) { -@@ -160,4 +181,48 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, +@@ -160,4 +181,39 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, } #endif +/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */ -+#if IS_ENABLED(CONFIG_ASUS_WMI) -+bool asus_use_hid_led(void); -+#else -+static inline bool asus_use_hid_led(void) -+{ -+ return true; -+} -+#endif -+ +static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = { + { + .matches = { @@ -2626,7 +5030,40 @@ index 3eb5cd6773ad..870f4bb57100 100644 + DMI_MATCH(DMI_BOARD_NAME, "RC71L"), + }, + }, -+ NULL, ++ { }, +}; + #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 3840565ef8b0..5641b40b9cdc 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7409,6 +7409,7 @@ enum { + ALC285_FIXUP_THINKPAD_X1_GEN7, + ALC285_FIXUP_THINKPAD_HEADSET_JACK, + ALC294_FIXUP_ASUS_ALLY, ++ ALC294_FIXUP_ASUS_ALLY_X, + ALC294_FIXUP_ASUS_ALLY_PINS, + ALC294_FIXUP_ASUS_ALLY_VERBS, + ALC294_FIXUP_ASUS_ALLY_SPEAKER, +@@ -8875,6 +8876,12 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS + }, ++ [ALC294_FIXUP_ASUS_ALLY_X] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = tas2781_fixup_i2c, ++ .chained = true, ++ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS ++ }, + [ALC294_FIXUP_ASUS_ALLY_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -10307,6 +10314,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), + SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), + SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY), ++ SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X), + SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), + SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), diff --git a/SOURCES/dcn32-dcn301-dcn321-mpo-reverts.patch b/SOURCES/dcn32-dcn301-dcn321-mpo-reverts.patch index 0899cdb..35084b7 100644 --- a/SOURCES/dcn32-dcn301-dcn321-mpo-reverts.patch +++ b/SOURCES/dcn32-dcn301-dcn321-mpo-reverts.patch @@ -91,8 +91,8 @@ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/ index 9a3cc0514a36..adde6c7b09f6 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c -@@ -1779,7 +1779,7 @@ static bool dcn321_resource_construct( - dc->caps.color.mpc.ocsc = 1; +@@ -1782,7 +1782,7 @@ + dc->config.use_pipe_ctx_sync_logic = true; dc->config.dc_mode_clk_limit_support = true; - dc->config.enable_windowed_mpo_odm = true; diff --git a/SOURCES/kernel-aarch64-16k-debug-fedora.config b/SOURCES/kernel-aarch64-16k-debug-fedora.config index b46564f..1ce8390 100644 --- a/SOURCES/kernel-aarch64-16k-debug-fedora.config +++ b/SOURCES/kernel-aarch64-16k-debug-fedora.config @@ -10185,3 +10185,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-16k-fedora.config b/SOURCES/kernel-aarch64-16k-fedora.config index 9fbc21c..24594e0 100644 --- a/SOURCES/kernel-aarch64-16k-fedora.config +++ b/SOURCES/kernel-aarch64-16k-fedora.config @@ -10156,3 +10156,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-64k-debug-rhel.config b/SOURCES/kernel-aarch64-64k-debug-rhel.config index 4060a6b..a404466 100644 --- a/SOURCES/kernel-aarch64-64k-debug-rhel.config +++ b/SOURCES/kernel-aarch64-64k-debug-rhel.config @@ -8206,3 +8206,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-64k-rhel.config b/SOURCES/kernel-aarch64-64k-rhel.config index 058a619..abb7ae0 100644 --- a/SOURCES/kernel-aarch64-64k-rhel.config +++ b/SOURCES/kernel-aarch64-64k-rhel.config @@ -8181,3 +8181,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-debug-fedora.config b/SOURCES/kernel-aarch64-debug-fedora.config index 30d1b95..4ba469b 100644 --- a/SOURCES/kernel-aarch64-debug-fedora.config +++ b/SOURCES/kernel-aarch64-debug-fedora.config @@ -10184,3 +10184,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-debug-rhel.config b/SOURCES/kernel-aarch64-debug-rhel.config index c5845c6..7dba0fe 100644 --- a/SOURCES/kernel-aarch64-debug-rhel.config +++ b/SOURCES/kernel-aarch64-debug-rhel.config @@ -8202,3 +8202,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-fedora.config b/SOURCES/kernel-aarch64-fedora.config index c05da35..3c67f6a 100644 --- a/SOURCES/kernel-aarch64-fedora.config +++ b/SOURCES/kernel-aarch64-fedora.config @@ -10155,3 +10155,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-rhel.config b/SOURCES/kernel-aarch64-rhel.config index 8277598..4450f4a 100644 --- a/SOURCES/kernel-aarch64-rhel.config +++ b/SOURCES/kernel-aarch64-rhel.config @@ -8177,3 +8177,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-rt-debug-rhel.config b/SOURCES/kernel-aarch64-rt-debug-rhel.config index cb2f7f9..673311a 100644 --- a/SOURCES/kernel-aarch64-rt-debug-rhel.config +++ b/SOURCES/kernel-aarch64-rt-debug-rhel.config @@ -8262,3 +8262,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-aarch64-rt-rhel.config b/SOURCES/kernel-aarch64-rt-rhel.config index 378957a..a932510 100644 --- a/SOURCES/kernel-aarch64-rt-rhel.config +++ b/SOURCES/kernel-aarch64-rt-rhel.config @@ -8237,3 +8237,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-ppc64le-debug-fedora.config b/SOURCES/kernel-ppc64le-debug-fedora.config index 75b508c..0cd84a4 100644 --- a/SOURCES/kernel-ppc64le-debug-fedora.config +++ b/SOURCES/kernel-ppc64le-debug-fedora.config @@ -8416,3 +8416,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-ppc64le-debug-rhel.config b/SOURCES/kernel-ppc64le-debug-rhel.config index cf747f1..f1fd5f1 100644 --- a/SOURCES/kernel-ppc64le-debug-rhel.config +++ b/SOURCES/kernel-ppc64le-debug-rhel.config @@ -7664,3 +7664,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-ppc64le-fedora.config b/SOURCES/kernel-ppc64le-fedora.config index 415aa28..d0470d8 100644 --- a/SOURCES/kernel-ppc64le-fedora.config +++ b/SOURCES/kernel-ppc64le-fedora.config @@ -8385,3 +8385,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-ppc64le-rhel.config b/SOURCES/kernel-ppc64le-rhel.config index 25ac725..5fd266b 100644 --- a/SOURCES/kernel-ppc64le-rhel.config +++ b/SOURCES/kernel-ppc64le-rhel.config @@ -7641,3 +7641,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-s390x-debug-fedora.config b/SOURCES/kernel-s390x-debug-fedora.config index 091dc10..59ccfe6 100644 --- a/SOURCES/kernel-s390x-debug-fedora.config +++ b/SOURCES/kernel-s390x-debug-fedora.config @@ -8354,3 +8354,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-s390x-debug-rhel.config b/SOURCES/kernel-s390x-debug-rhel.config index 88a84d0..f47ccc6 100644 --- a/SOURCES/kernel-s390x-debug-rhel.config +++ b/SOURCES/kernel-s390x-debug-rhel.config @@ -7646,3 +7646,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-s390x-fedora.config b/SOURCES/kernel-s390x-fedora.config index 2479547..dd3adc9 100644 --- a/SOURCES/kernel-s390x-fedora.config +++ b/SOURCES/kernel-s390x-fedora.config @@ -8323,3 +8323,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-s390x-rhel.config b/SOURCES/kernel-s390x-rhel.config index c9435cd..20d1a61 100644 --- a/SOURCES/kernel-s390x-rhel.config +++ b/SOURCES/kernel-s390x-rhel.config @@ -7623,3 +7623,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-s390x-zfcpdump-rhel.config b/SOURCES/kernel-s390x-zfcpdump-rhel.config index cab9fb5..582dc9b 100644 --- a/SOURCES/kernel-s390x-zfcpdump-rhel.config +++ b/SOURCES/kernel-s390x-zfcpdump-rhel.config @@ -7645,3 +7645,5 @@ CONFIG_HID_APPLETB_BL=m CONFIG_HID_APPLETB_KBD=m CONFIG_HID_APPLE_MAGIC_BACKLIGHT=m CONFIG_APPLE_BCE=m +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-debug-fedora.config b/SOURCES/kernel-x86_64-debug-fedora.config index 94664db..b691f1b 100644 --- a/SOURCES/kernel-x86_64-debug-fedora.config +++ b/SOURCES/kernel-x86_64-debug-fedora.config @@ -9093,3 +9093,5 @@ CONFIG_SND_SOC_SOF_IPC3=y CONFIG_SND_SOC_SOF_INTEL_IPC4=y CONFIG_SND_SOC_SOF_AMD_COMMON=m CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-debug-rhel.config b/SOURCES/kernel-x86_64-debug-rhel.config index 41c2975..210dddd 100644 --- a/SOURCES/kernel-x86_64-debug-rhel.config +++ b/SOURCES/kernel-x86_64-debug-rhel.config @@ -8087,3 +8087,5 @@ CONFIG_SND_SOC_SOF_AMD_ACP63=m # CONFIG_SND_AMD_ASOC_REMBRANDT is not set # CONFIG_SND_SOC_AMD_LEGACY_MACH is not set CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-fedora.config b/SOURCES/kernel-x86_64-fedora.config index 44b4660..713987a 100644 --- a/SOURCES/kernel-x86_64-fedora.config +++ b/SOURCES/kernel-x86_64-fedora.config @@ -9063,3 +9063,5 @@ CONFIG_SND_SOC_SOF_IPC3=y CONFIG_SND_SOC_SOF_INTEL_IPC4=y CONFIG_SND_SOC_SOF_AMD_COMMON=m CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-rhel.config b/SOURCES/kernel-x86_64-rhel.config index d9c818d..1a5ab05 100644 --- a/SOURCES/kernel-x86_64-rhel.config +++ b/SOURCES/kernel-x86_64-rhel.config @@ -8063,3 +8063,5 @@ CONFIG_SND_SOC_SOF_AMD_ACP63=m # CONFIG_SND_AMD_ASOC_REMBRANDT is not set # CONFIG_SND_SOC_AMD_LEGACY_MACH is not set CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-rt-debug-rhel.config b/SOURCES/kernel-x86_64-rt-debug-rhel.config index b606b47..1cb0a7f 100644 --- a/SOURCES/kernel-x86_64-rt-debug-rhel.config +++ b/SOURCES/kernel-x86_64-rt-debug-rhel.config @@ -8148,3 +8148,5 @@ CONFIG_SND_SOC_SOF_AMD_ACP63=m # CONFIG_SND_AMD_ASOC_REMBRANDT is not set # CONFIG_SND_SOC_AMD_LEGACY_MACH is not set CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel-x86_64-rt-rhel.config b/SOURCES/kernel-x86_64-rt-rhel.config index 6084234..b75bb3f 100644 --- a/SOURCES/kernel-x86_64-rt-rhel.config +++ b/SOURCES/kernel-x86_64-rt-rhel.config @@ -8124,3 +8124,5 @@ CONFIG_SND_SOC_SOF_AMD_ACP63=m # CONFIG_SND_AMD_ASOC_REMBRANDT is not set # CONFIG_SND_SOC_AMD_LEGACY_MACH is not set CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_HID_ASUS_ALLY=m +CONFIG_ASUS_ARMOURY=m diff --git a/SOURCES/kernel.changelog b/SOURCES/kernel.changelog index 0a0213f..f665727 100644 --- a/SOURCES/kernel.changelog +++ b/SOURCES/kernel.changelog @@ -1,3 +1,17 @@ +* Thu Aug 29 2024 Augusto Caringi [6.10.7-0] +- KVM: PPC: Book3S HV nestedv2: Keep nested guest HASHPKEYR in sync (Shivaprasad G Bhat) +- KVM: PPC: Book3S HV: Add one-reg interface for HASHPKEYR register (Shivaprasad G Bhat) +- KVM: PPC: Book3S HV nestedv2: Keep nested guest HASHKEYR in sync (Shivaprasad G Bhat) +- KVM: PPC: Book3S HV: Add one-reg interface for HASHKEYR register (Shivaprasad G Bhat) +- KVM: PPC: Book3S HV nestedv2: Keep nested guest DEXCR in sync (Shivaprasad G Bhat) +- KVM: PPC: Book3S HV: Add one-reg interface for DEXCR register (Shivaprasad G Bhat) +- Revert the F39 commits which should not have pushed (Justin M. Forbes) +- Turn off libbpf dynamic for perf on F39 (Justin M. Forbes) +- Revert "cpupower: Bump soname version" (Justin M. Forbes) +- Drop soname for libcpupower.so since we reverted the bump (Justin M. Forbes) +- Linux v6.10.7 +Resolves: + * Mon Aug 19 2024 Justin M. Forbes [6.10.6-0] - Add to BugsFixed (Justin M. Forbes) - selinux: revert our use of vma_is_initial_heap() (Paul Moore) diff --git a/SOURCES/linux-surface.patch b/SOURCES/linux-surface.patch index dd4d3b6..303c347 100644 --- a/SOURCES/linux-surface.patch +++ b/SOURCES/linux-surface.patch @@ -1,4 +1,4 @@ -From fa4500c4ae1546dba5d5e4fbada8e6d0406adab0 Mon Sep 17 00:00:00 2001 +From 252c5b2e65865a2a3aa6a5400f204c47d22490ee Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 19:48:58 +0200 Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag @@ -33,9 +33,9 @@ index b5c79f43359b..a1bbedd989e4 100644 .long 0 # SizeOfStackReserve .long 0 # SizeOfStackCommit -- -2.45.2 +2.46.0 -From b161e7d8c1f16ef72ed5195aa97e6357e06bdc4e Mon Sep 17 00:00:00 2001 +From 1146270e92aee0b612dfe695bcf8f7131a19bcf3 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -134,9 +134,9 @@ index 5e2ec60e2954..207868c699f2 100644 }; -- -2.45.2 +2.46.0 -From 2497b1ba9fa349ddf764c38c46160a785a5f3475 Mon Sep 17 00:00:00 2001 +From 800e9cfe84a3eadd4dc9ae700940068e77fa8a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -301,9 +301,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.2 +2.46.0 -From 52c3a74193a1e37e241dc8a8cef0a71e843a29b5 Mon Sep 17 00:00:00 2001 +From d51c5a356fee57c99a8d181825f8f941f34749d7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -456,9 +456,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.45.2 +2.46.0 -From 338d5143d47a9de3d5a25f1fa203f6b6a95864ef Mon Sep 17 00:00:00 2001 +From 317cde3654592dcb3e072d0d2fe7b4e5598cc078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -534,9 +534,9 @@ index 789c492df6fa..1e766b6c1f9a 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.45.2 +2.46.0 -From 5030f889081c8676ae652623ad86b797b05d7221 Mon Sep 17 00:00:00 2001 +From 268a79fb66862ef22294397a425fd074fc336c34 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -654,9 +654,9 @@ index bdf0552cd1c3..e062cc687689 100644 snprintf(filename, sizeof(filename), "%s/%s/%s", dir, ar->board_name, file); -- -2.45.2 +2.46.0 -From 318ef833ea6bf3a2ef7566bad79931b216bd7423 Mon Sep 17 00:00:00 2001 +From 9904c59dbdd422b811974893bab69fc5b4bc9a03 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -693,9 +693,9 @@ index 6589635f8ba3..a1df48a434e2 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.45.2 +2.46.0 -From ddcd34d797494f38ba7be0d9e46a919fda557576 Mon Sep 17 00:00:00 2001 +From b0d9ceae2f95a4e4093b07580bedc10821374555 Mon Sep 17 00:00:00 2001 From: Liban Hannan Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -800,9 +800,9 @@ index f55ec1fd7942..8d95579436a9 100644 { if (risky_device(dev)) -- -2.45.2 +2.46.0 -From 6ff2cce19a707fb565e9aebf9fb2b00fe845a46a Mon Sep 17 00:00:00 2001 +From ee1ebc3f9ec7a8418f418902817b5c5f4b51c21d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -3895,9 +3895,9 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.45.2 +2.46.0 -From 52e90ab224f06fd648ca85cd43a91670a9a4e683 Mon Sep 17 00:00:00 2001 +From 0d0e07366b425e953d6dab698d62dbe9a7546994 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -3936,9 +3936,9 @@ index e4a70886678c..961a33b87c24 100644 * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the -- -2.45.2 +2.46.0 -From a5da515376d209ea8610fed94888f48d9b64387f Mon Sep 17 00:00:00 2001 +From 19a947aa5cc417bd43656cf9d8bf010abdc6bc3f Mon Sep 17 00:00:00 2001 From: quo Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -6666,64 +6666,9 @@ index 000000000000..aec320d4e945 +int ithc_reset(struct ithc *ithc); + -- -2.45.2 +2.46.0 -From 5180e4810b868e0d3da85577b776a929cecf1d65 Mon Sep 17 00:00:00 2001 -From: Maximilian Luz -Date: Fri, 19 Apr 2024 20:41:47 +0200 -Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is - destroyed in probe - -There is a small window in ssam_serial_hub_probe() where the controller -is initialized but has not been started yet. Specifically, between -ssam_controller_init() and ssam_controller_start(). Any failure in this -window, for example caused by a failure of serdev_device_open(), -currently results in an incorrect warning being emitted. - -In particular, any failure in this window results in the controller -being destroyed via ssam_controller_destroy(). This function checks the -state of the controller and, in an attempt to validate that the -controller has been cleanly shut down before we try and deallocate any -resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. - -However, since we have only just initialized the controller and have not -yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this -is the only point at which the controller has this state, as it will -change after we start the controller with ssam_controller_start() and -never revert back. Further, at this point no communication has taken -place and the sender and receiver threads have not been started yet (and -we may not even have an open serdev device either). - -Therefore, it is perfectly safe to call ssam_controller_destroy() with a -state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the -warning currently being emitted is incorrect. Fix it by extending the -check. - -Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") -Signed-off-by: Maximilian Luz -Patchset: surface-sam ---- - drivers/platform/surface/aggregator/controller.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c -index 7fc602e01487..7e89f547999b 100644 ---- a/drivers/platform/surface/aggregator/controller.c -+++ b/drivers/platform/surface/aggregator/controller.c -@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) - if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) - return; - -- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); -+ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && -+ ctrl->state != SSAM_CONTROLLER_INITIALIZED); - - /* - * Note: New events could still have been received after the previous --- -2.45.2 - -From 144dbc865c07df0290009d509b31635aac53a907 Mon Sep 17 00:00:00 2001 +From 00b833401e8060eb50db269e0681383454a74848 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -6754,9 +6699,9 @@ index 1c4d74db08c9..f826489dc69d 100644 { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- -2.45.2 +2.46.0 -From 7b906ae84a56322a5098c77a774f5fb00b4318a5 Mon Sep 17 00:00:00 2001 +From 9e13165394bf1898d05c7d5a4a5adb1767d2307e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -6824,9 +6769,9 @@ index f826489dc69d..ef59a7b66667 100644 { }, }; -- -2.45.2 +2.46.0 -From d602c3714f0cc654b90de7800f844d6201eaa66b Mon Sep 17 00:00:00 2001 +From 83719d2cd70ad6ac1df993782e757ded15e881cc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 9 Jun 2024 20:05:57 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -6881,9 +6826,9 @@ index ef59a7b66667..70a2ea5a1957 100644 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, -- -2.45.2 +2.46.0 -From 4bde7be038c7dced1b596c7d41e6f0bb3043d301 Mon Sep 17 00:00:00 2001 +From c188646846cc6e9db1134eb62208d088ce615312 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -7109,9 +7054,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.45.2 +2.46.0 -From ae82a35c632785771ebe2ad7f48006a1eb8f6a91 Mon Sep 17 00:00:00 2001 +From 31d334453ebc65b7868bf33b1963553586e64fa3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -7304,9 +7249,9 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.45.2 +2.46.0 -From 6a80e0b93ce1d8cf9d1b7e383b4b951fb4908294 Mon Sep 17 00:00:00 2001 +From 36174000616d130e9b4655d69eb3bd5b07adbecb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:47:47 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -7333,9 +7278,9 @@ index 70a2ea5a1957..6b568804f70b 100644 &ssam_node_hid_main_touchpad, &ssam_node_hid_main_iid5, -- -2.45.2 +2.46.0 -From 3175ecd829a778ffef35956d8785877bb76fe4b0 Mon Sep 17 00:00:00 2001 +From e32f317be4ad620fb6683b62ad9e883f37e17f57 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 10 Jun 2024 21:48:02 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal @@ -7362,9 +7307,9 @@ index 6b568804f70b..9046df95c043 100644 &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -- -2.45.2 +2.46.0 -From aeef49471d7ec17f243c685b85c0c870c99e9e3d Mon Sep 17 00:00:00 2001 +From ebf64f6dcf1bdf0dbe80b5ec5e3d4b8a6cfab41e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 28 Jun 2024 22:31:37 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add Support for @@ -7416,9 +7361,9 @@ index 9046df95c043..058f4edd8b66 100644 { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, -- -2.45.2 +2.46.0 -From 56def3328ab5c84c33a87c062448f1f97e545282 Mon Sep 17 00:00:00 2001 +From 8dac7a369f2f1c461750a3c3f6d93caae9566ace Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -7528,9 +7473,9 @@ index 14ae0cfc325e..a3a9f81fb47f 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.45.2 +2.46.0 -From 99ca5a4092ea27b42c256940694e13a8f2abd457 Mon Sep 17 00:00:00 2001 +From fe964119c511036a560d1dfcbec1196ae4ed1621 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -7751,9 +7696,9 @@ index 000000000000..8b816ed8f35c +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.45.2 +2.46.0 -From 1afbbb29ce7bd15bbf4f812cbc034514bb667b43 Mon Sep 17 00:00:00 2001 +From d811fb8e32e1327baf131c85522aee281f4281af Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -7828,9 +7773,9 @@ index f6d060377d18..b8603f74eb28 100644 /* -- -2.45.2 +2.46.0 -From 888fc8298e984f1cb23ac66e91a02d2e7f174919 Mon Sep 17 00:00:00 2001 +From e21138766921f4a22e710b4858f75f98e308c61d Mon Sep 17 00:00:00 2001 From: Sachi King Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -7900,9 +7845,9 @@ index 2755601f979c..4240c98ca226 100644 -- -2.45.2 +2.46.0 -From 201768f64dd2128028bed46940ecd9ea85483973 Mon Sep 17 00:00:00 2001 +From a19b7328ccb6c090354593fa039e5283140a5e69 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 18 Feb 2023 01:02:49 +0100 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 @@ -7941,9 +7886,9 @@ index 13171454f959..a83beefd25f3 100644 { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, -- -2.45.2 +2.46.0 -From 9ae353f19e719e680d93710ec61aef6edefab6f1 Mon Sep 17 00:00:00 2001 +From 99fb371b3a11e3c3d67d29673508911b81a1408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when @@ -8174,9 +8119,9 @@ index 56fc78841f24..a266449065a0 100644 { .driver_data = MT_CLS_GOOGLE, HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, -- -2.45.2 +2.46.0 -From 922102cc310758a2655f9bb3eb9a413bc551b1a7 Mon Sep 17 00:00:00 2001 +From 7b797164a3f2ecf402b8f24d5123e74914b09064 Mon Sep 17 00:00:00 2001 From: PJungkamp Date: Fri, 25 Feb 2022 12:04:25 +0100 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet @@ -8473,9 +8418,9 @@ index a266449065a0..060c706e936a 100644 unregister_pm_notifier(&td->pm_notifier); del_timer_sync(&td->release_timer); -- -2.45.2 +2.46.0 -From dc75889e49675c868d33320a996c33d183fee94a Mon Sep 17 00:00:00 2001 +From e26e0570db9e2dbb37e075ef7a88270fe793fb94 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -8570,9 +8515,9 @@ index cafc5ab1cbcb..64bb5aca2c13 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.45.2 +2.46.0 -From 41732ed4458eb3b08b4a658f1cd617d83c90cec6 Mon Sep 17 00:00:00 2001 +From bed56a2a67db8c5934008ed83fa0bbd71360ab02 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -8621,9 +8566,9 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.45.2 +2.46.0 -From 2d145df171e42d90ac54b0bdc42e77337e99679a Mon Sep 17 00:00:00 2001 +From 0a70aafbfa7ad39054c0974e428935c9d9e48cf1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -8697,9 +8642,9 @@ index 503773707e01..a292a20c4315 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.45.2 +2.46.0 -From f0e749b5b8f19dca95eaf7b24c925f7684669993 Mon Sep 17 00:00:00 2001 +From bdae5b6a0e462398fa6035a2f0de8efae144abe4 Mon Sep 17 00:00:00 2001 From: zouxiaoh Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -8807,9 +8752,9 @@ index 8d95579436a9..cbfb59ed5985 100644 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts); -- -2.45.2 +2.46.0 -From 197059f84ca0575efb65a4667023e9e14c53fe87 Mon Sep 17 00:00:00 2001 +From aa044fab288ddf51ad963effe090d0b548d83243 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -8844,9 +8789,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.45.2 +2.46.0 -From cff4d571011727ee47c29f21c9b1d255ca4efe8e Mon Sep 17 00:00:00 2001 +From 12da0a015e6d71071561668950a4fb5e33220af8 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -8899,9 +8844,9 @@ index 07b302e09340..1d3097bc7e48 100644 agpio, func, polarity); if (ret) -- -2.45.2 +2.46.0 -From 31cab2b99a833eab39602f61e3f3f801884f8980 Mon Sep 17 00:00:00 2001 +From ddc65d1014592b1fe4d6e16c9badcc928e577b3b Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -8938,9 +8883,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.45.2 +2.46.0 -From b17d182f347660c7c2e873d0a2e21b57ce44858c Mon Sep 17 00:00:00 2001 +From ea560c5a7e55695438ac99fbd363352991fe62af Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -8989,9 +8934,9 @@ index 89c7192148df..44eca113e772 100644 if (ret < 0) goto out_cleanup; -- -2.45.2 +2.46.0 -From c51c33aa1cdbea15c1b493b300f66408d8306bd9 Mon Sep 17 00:00:00 2001 +From 0c59f9eee1c8dc8ea4d99f8b1a07b342ef5e425d Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -9030,9 +8975,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.45.2 +2.46.0 -From b37b24f5e18fd586452ec4a7cc978c3360074e42 Mon Sep 17 00:00:00 2001 +From 8f69fe36b3d6052c7f41182041fc59ea84515066 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -9071,9 +9016,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.45.2 +2.46.0 -From 8ef5b1010e49d11964f2dd7da3c3271f5f9bf503 Mon Sep 17 00:00:00 2001 +From 457ccb4dad651a58bc24e4c49fcc95a81e3762bb Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -9322,9 +9267,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.45.2 +2.46.0 -From ca688e057ec8149ccd01d2c7876b707aa33bdbc8 Mon Sep 17 00:00:00 2001 +From 281dcaef04abcc6a75b34c6f69f8f608b68912cf Mon Sep 17 00:00:00 2001 From: mojyack Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -9369,9 +9314,9 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.45.2 +2.46.0 -From d267b727836905eaefc1541eb743479338827db5 Mon Sep 17 00:00:00 2001 +From f1d09776b3c5026bfd4d035bbca5be3f8e41b247 Mon Sep 17 00:00:00 2001 From: mojyack Date: Tue, 26 Mar 2024 05:55:44 +0900 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 @@ -9401,9 +9346,9 @@ index c626ed845928..0094cfda57ea 100644 cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -- -2.45.2 +2.46.0 -From 68bfb06084548d1f7d23fc2c5e7c4b70262078b3 Mon Sep 17 00:00:00 2001 +From 29121bd1e5b235572d56645abdb8f54a31bf476e Mon Sep 17 00:00:00 2001 From: Sachi King Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -9468,9 +9413,9 @@ index 4bf82dbd2a6b..7a8cb090c656 100644 mp_config_acpi_legacy_irqs(); -- -2.45.2 +2.46.0 -From f72f4d6bc2d6e1f1ec68422cffaed5e77820c6c5 Mon Sep 17 00:00:00 2001 +From f8d58835a76ce8ea016c0fcd75ddb93a95ca14c6 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -9510,9 +9455,9 @@ index 7a8cb090c656..0faafc323e67 100644 }; -- -2.45.2 +2.46.0 -From ca8843e551ab3528c958bc8efaa51356dbdc23de Mon Sep 17 00:00:00 2001 +From 5c662b210790b2b297457de3e84274cc062b215e Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -9620,5 +9565,5 @@ index 1d670dbe4d1d..71c9e375ca1c 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.45.2 +2.46.0 diff --git a/SOURCES/patch-6.10-redhat.patch b/SOURCES/patch-6.10-redhat.patch index 01f9da9..3ef3fe6 100644 --- a/SOURCES/patch-6.10-redhat.patch +++ b/SOURCES/patch-6.10-redhat.patch @@ -1,6 +1,12 @@ + Documentation/virt/kvm/api.rst | 3 + Makefile | 12 ++ arch/arm/Kconfig | 4 +- arch/arm64/Kconfig | 2 +- + arch/powerpc/include/asm/kvm_host.h | 3 + + arch/powerpc/include/uapi/asm/kvm.h | 3 + + arch/powerpc/kvm/book3s_hv.c | 18 +++ + arch/powerpc/kvm/book3s_hv.h | 3 + + arch/powerpc/kvm/book3s_hv_nestedv2.c | 18 +++ arch/s390/include/asm/ipl.h | 1 + arch/s390/kernel/ipl.c | 5 + arch/s390/kernel/setup.c | 4 + @@ -23,7 +29,6 @@ drivers/input/rmi4/rmi_driver.c | 124 ++++++++++------- drivers/iommu/iommu.c | 22 +++ drivers/media/pci/intel/ipu-bridge.c | 40 ++++-- - .../broadcom/brcm80211/brcmfmac/cfg80211.c | 13 +- drivers/pci/quirks.c | 24 ++++ drivers/scsi/sd.c | 10 ++ drivers/usb/core/hub.c | 7 + @@ -40,11 +45,26 @@ security/lockdown/Kconfig | 13 ++ security/lockdown/lockdown.c | 1 + security/security.c | 12 ++ - security/selinux/hooks.c | 12 +- - 43 files changed, 800 insertions(+), 260 deletions(-) + 47 files changed, 827 insertions(+), 256 deletions(-) +diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst +index eec8df1dde06..88f49dd10cd0 100644 +--- a/Documentation/virt/kvm/api.rst ++++ b/Documentation/virt/kvm/api.rst +@@ -2445,8 +2445,11 @@ registers, find a list below: + PPC KVM_REG_PPC_PSSCR 64 + PPC KVM_REG_PPC_DEC_EXPIRY 64 + PPC KVM_REG_PPC_PTCR 64 ++ PPC KVM_REG_PPC_HASHKEYR 64 ++ PPC KVM_REG_PPC_HASHPKEYR 64 + PPC KVM_REG_PPC_DAWR1 64 + PPC KVM_REG_PPC_DAWRX1 64 ++ PPC KVM_REG_PPC_DEXCR 64 + PPC KVM_REG_PPC_TM_GPR0 64 + ... + PPC KVM_REG_PPC_TM_GPR31 64 diff --git a/Makefile b/Makefile -index 361a70264e1f..eaf69484d4ce 100644 +index ab77d171e268..c46aa8337181 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,18 @@ $(if $(filter __%, $(MAKECMDGOALS)), \ @@ -95,6 +115,120 @@ index 11bbdc15c6e5..9cecc1448e3c 100644 help For systems with 52-bit userspace VAs enabled, the kernel will attempt to maintain compatibility with older software by providing 48-bit VAs +diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h +index 8abac532146e..6a0c771d3ce8 100644 +--- a/arch/powerpc/include/asm/kvm_host.h ++++ b/arch/powerpc/include/asm/kvm_host.h +@@ -599,6 +599,9 @@ struct kvm_vcpu_arch { + ulong dawrx0; + ulong dawr1; + ulong dawrx1; ++ ulong dexcr; ++ ulong hashkeyr; ++ ulong hashpkeyr; + ulong ciabr; + ulong cfar; + ulong ppr; +diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h +index 1691297a766a..eaeda001784e 100644 +--- a/arch/powerpc/include/uapi/asm/kvm.h ++++ b/arch/powerpc/include/uapi/asm/kvm.h +@@ -645,6 +645,9 @@ struct kvm_ppc_cpu_char { + #define KVM_REG_PPC_SIER3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc3) + #define KVM_REG_PPC_DAWR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc4) + #define KVM_REG_PPC_DAWRX1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc5) ++#define KVM_REG_PPC_DEXCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc6) ++#define KVM_REG_PPC_HASHKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc7) ++#define KVM_REG_PPC_HASHPKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc8) + + /* Transactional Memory checkpointed state: + * This is all GPRs, all VSX regs and a subset of SPRs +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index d8352e4d9cdc..36068c3ed8a7 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -2349,6 +2349,15 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + case KVM_REG_PPC_DAWRX1: + *val = get_reg_val(id, kvmppc_get_dawrx1_hv(vcpu)); + break; ++ case KVM_REG_PPC_DEXCR: ++ *val = get_reg_val(id, kvmppc_get_dexcr_hv(vcpu)); ++ break; ++ case KVM_REG_PPC_HASHKEYR: ++ *val = get_reg_val(id, kvmppc_get_hashkeyr_hv(vcpu)); ++ break; ++ case KVM_REG_PPC_HASHPKEYR: ++ *val = get_reg_val(id, kvmppc_get_hashpkeyr_hv(vcpu)); ++ break; + case KVM_REG_PPC_CIABR: + *val = get_reg_val(id, kvmppc_get_ciabr_hv(vcpu)); + break; +@@ -2592,6 +2601,15 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + case KVM_REG_PPC_DAWRX1: + kvmppc_set_dawrx1_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); + break; ++ case KVM_REG_PPC_DEXCR: ++ kvmppc_set_dexcr_hv(vcpu, set_reg_val(id, *val)); ++ break; ++ case KVM_REG_PPC_HASHKEYR: ++ kvmppc_set_hashkeyr_hv(vcpu, set_reg_val(id, *val)); ++ break; ++ case KVM_REG_PPC_HASHPKEYR: ++ kvmppc_set_hashpkeyr_hv(vcpu, set_reg_val(id, *val)); ++ break; + case KVM_REG_PPC_CIABR: + kvmppc_set_ciabr_hv(vcpu, set_reg_val(id, *val)); + /* Don't allow setting breakpoints in hypervisor code */ +diff --git a/arch/powerpc/kvm/book3s_hv.h b/arch/powerpc/kvm/book3s_hv.h +index 47b2c815641e..a404c9b221c1 100644 +--- a/arch/powerpc/kvm/book3s_hv.h ++++ b/arch/powerpc/kvm/book3s_hv.h +@@ -116,6 +116,9 @@ KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr0, 64, KVMPPC_GSID_DAWR0) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr1, 64, KVMPPC_GSID_DAWR1) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx0, 64, KVMPPC_GSID_DAWRX0) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx1, 64, KVMPPC_GSID_DAWRX1) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dexcr, 64, KVMPPC_GSID_DEXCR) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashkeyr, 64, KVMPPC_GSID_HASHKEYR) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashpkeyr, 64, KVMPPC_GSID_HASHPKEYR) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ciabr, 64, KVMPPC_GSID_CIABR) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(wort, 64, KVMPPC_GSID_WORT) + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ppr, 64, KVMPPC_GSID_PPR) +diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c +index 342f58314770..eeecea8f202b 100644 +--- a/arch/powerpc/kvm/book3s_hv_nestedv2.c ++++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c +@@ -193,6 +193,15 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, + case KVMPPC_GSID_DAWRX1: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx1); + break; ++ case KVMPPC_GSID_DEXCR: ++ rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dexcr); ++ break; ++ case KVMPPC_GSID_HASHKEYR: ++ rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashkeyr); ++ break; ++ case KVMPPC_GSID_HASHPKEYR: ++ rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashpkeyr); ++ break; + case KVMPPC_GSID_CIABR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ciabr); + break; +@@ -445,6 +454,15 @@ static int gs_msg_ops_vcpu_refresh_info(struct kvmppc_gs_msg *gsm, + case KVMPPC_GSID_DAWRX1: + vcpu->arch.dawrx1 = kvmppc_gse_get_u32(gse); + break; ++ case KVMPPC_GSID_DEXCR: ++ vcpu->arch.dexcr = kvmppc_gse_get_u64(gse); ++ break; ++ case KVMPPC_GSID_HASHKEYR: ++ vcpu->arch.hashkeyr = kvmppc_gse_get_u64(gse); ++ break; ++ case KVMPPC_GSID_HASHPKEYR: ++ vcpu->arch.hashpkeyr = kvmppc_gse_get_u64(gse); ++ break; + case KVMPPC_GSID_CIABR: + vcpu->arch.ciabr = kvmppc_gse_get_u64(gse); + break; diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index b0d00032479d..afb9544fb007 100644 --- a/arch/s390/include/asm/ipl.h @@ -569,7 +703,7 @@ index 1687483ff319..390b67f19181 100644 return ctx.rc; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 503773707e01..2fead21fcb07 100644 +index cdc5a74092c7..45679565878f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1793,6 +1793,15 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) @@ -1523,30 +1657,6 @@ index 61750cc98d70..a0e9a71580b5 100644 }; static const struct ipu_property_names prop_names = { -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -index 5fe0e671ecb3..826b768196e2 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -4320,9 +4320,16 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, - /* Single PMK operation */ - pmk_op->count = cpu_to_le16(1); - length += sizeof(struct brcmf_pmksa_v3); -- memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN); -- memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); -- pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN; -+ if (pmksa->bssid) -+ memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN); -+ if (pmksa->pmkid) { -+ memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); -+ pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN; -+ } -+ if (pmksa->ssid && pmksa->ssid_len) { -+ memcpy(pmk_op->pmk[0].ssid.SSID, pmksa->ssid, pmksa->ssid_len); -+ pmk_op->pmk[0].ssid.SSID_len = pmksa->ssid_len; -+ } - pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0); - } - diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 568410e64ce6..6afbaee83950 100644 --- a/drivers/pci/quirks.c @@ -1957,26 +2067,3 @@ index 8cee5b6c6e6d..489e25946bf9 100644 #ifdef CONFIG_PERF_EVENTS /** * security_perf_event_open() - Check if a perf event open is allowed -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 55c78c318ccd..bfa61e005aac 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -3852,7 +3852,17 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, - if (default_noexec && - (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { - int rc = 0; -- if (vma_is_initial_heap(vma)) { -+ /* -+ * We don't use the vma_is_initial_heap() helper as it has -+ * a history of problems and is currently broken on systems -+ * where there is no heap, e.g. brk == start_brk. Before -+ * replacing the conditional below with vma_is_initial_heap(), -+ * or something similar, please ensure that the logic is the -+ * same as what we have below or you have tested every possible -+ * corner case you can think to test. -+ */ -+ if (vma->vm_start >= vma->vm_mm->start_brk && -+ vma->vm_end <= vma->vm_mm->brk) { - rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, - PROCESS__EXECHEAP, NULL); - } else if (!vma->vm_file && (vma_is_initial_stack(vma) || diff --git a/SOURCES/t2linux.patch b/SOURCES/t2linux.patch index 566de6c..46faa57 100644 --- a/SOURCES/t2linux.patch +++ b/SOURCES/t2linux.patch @@ -1477,7 +1477,7 @@ diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ce71b53ea6c5..fecec1d61393 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile -@@ -29,6 +29,8 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o +@@ -29,6 +29,8 @@ obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o @@ -1485,7 +1485,7 @@ index ce71b53ea6c5..fecec1d61393 100644 +obj-$(CONFIG_HID_APPLETB_KBD) += hid-appletb-kbd.o obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o obj-$(CONFIG_HID_ASUS) += hid-asus.o - obj-$(CONFIG_HID_AUREAL) += hid-aureal.o + obj-$(CONFIG_HID_ASUS_ALLY) += hid-asus-ally.o diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index bd022e004356..6dedb84d7cc3 100644 --- a/drivers/hid/hid-apple.c diff --git a/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch b/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch deleted file mode 100644 index 2a21e86..0000000 --- a/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch +++ /dev/null @@ -1,2320 +0,0 @@ -From 9fd3de7abd22d7e67a8757e3f67410302359fec7 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Fri, 1 Dec 2023 16:57:19 +1300 -Subject: [PATCH v14.7 4/4] HID: asus: add ROG Ally xpad settings - -- move ROG specific stuff to new .c -- add a header for common parts -- add xpad mode -- add deadzones -- add anti-deadzones -- add gamepad button remapping -- add gamepad mapping reset for xpad and wasd modes -- add turbo mode for individual buttons -- add joystick response curves -- add vibration intensity settings -- add calibration setting ---- - .../ABI/testing/sysfs-driver-hid-asus | 85 + - drivers/hid/Makefile | 2 + - drivers/hid/{hid-asus.c => hid-asus-core.c} | 71 +- - drivers/hid/hid-asus-rog.c | 1469 +++++++++++++++++ - drivers/hid/hid-asus-rog.h | 482 ++++++ - drivers/hid/hid-asus.h | 58 + - 6 files changed, 2126 insertions(+), 41 deletions(-) - create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-asus - rename drivers/hid/{hid-asus.c => hid-asus-core.c} (96%) - create mode 100644 drivers/hid/hid-asus-rog.c - create mode 100644 drivers/hid/hid-asus-rog.h - create mode 100644 drivers/hid/hid-asus.h - -diff --git a/Documentation/ABI/testing/sysfs-driver-hid-asus b/Documentation/ABI/testing/sysfs-driver-hid-asus -new file mode 100644 -index 000000000000..df5b0c5b0702 ---- /dev/null -+++ b/Documentation/ABI/testing/sysfs-driver-hid-asus -@@ -0,0 +1,85 @@ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/gamepad_mode -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Set the mode the ROG Ally xpad operates in: -+ - 1 = Game mode -+ - 2 = WASD mode -+ - 3 = Mouse mode -+ This setting applies instantly and applies settings that were previously changed -+ under that mode which are: -+ - deadzones -+ - anti-deadzones -+ - button mapping -+ - button turbo settings -+ - response curves -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/apply -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Apply the settings that have been stored in attributes so far. Because there are -+ many individual settings across a dozen packets this separation is required to -+ prevent spamming the MCU when userspace applications apply many changes at once. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/reset_btn_mapping -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Reset a gamepad mode to its default button mapping. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/deadzone -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Set the inner and outer deadzones of joysticks and triggers. These settings are not -+ written to the MCU until `apply` is set. -+ - range 0-64 (corresponds to 0-100%) -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/deadzone_index -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Descriptive labels for joystick deadzone array. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/anti-deadzone -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Set the joystick anti-deadzone feature: -+ - range 0-32 (corresponds to 0-50%) -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/calibration -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Calibration values for the joysticks and trigger analogues. There are no default -+ values as the calibration is determined in userspace. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/calibration_index -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Descriptive labels for joystick and triggers calibration array. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/rc_point -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Set the joystick response curve. There are 4 points available with 1 being the lowest -+ point and 4 being the highest point. -+ - range 0-64 (corresponds to 0-100%) -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis__/rc_point_index -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Descriptive labels for joystick response curve points. -+ -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/btn_