From 330c9aa3fde718e16ae71fd65889072dfe9d2acd Mon Sep 17 00:00:00 2001 From: ferreo Date: Sat, 8 Feb 2025 19:55:48 +0100 Subject: [PATCH] Update patches/asus2.patch --- patches/asus2.patch | 10389 ++++++++++++++++++++++++------------------ 1 file changed, 5837 insertions(+), 4552 deletions(-) diff --git a/patches/asus2.patch b/patches/asus2.patch index 0722891..13550ac 100644 --- a/patches/asus2.patch +++ b/patches/asus2.patch @@ -1,94 +1,45 @@ -From 701954edb42b4dcf79f52a74cfcda69ff54a5c20 Mon Sep 17 00:00:00 2001 +From 2da2427f9b97edebaf226c6a35e6eddfb0c8650f Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" -Date: Fri, 24 May 2024 10:54:36 +1200 -Subject: [PATCH 02/29] platform/x86: asus-wmi: don't fail if platform_profile - already registered +Date: Fri, 31 Jan 2025 09:14:52 +1300 +Subject: [PATCH 03/28] platform/x86: asus-wmi: Remove all ROG Ally CSEE hacks -On some newer laptops it appears that an AMD driver can register a -platform_profile handler. If this happens then the asus_wmi driver would -error with -EEXIST when trying to register its own handler leaving the -user with a possibly unusable system - this is especially true for -laptops with an MCU that emit a stream of HID packets, some of which can -be misinterpreted as shutdown signals. +Remove the hacks introduced by these commits: +- fc73fe3b8501 "platform/x86: asus-wmi: disable USB0 hub on ROG Ally before suspend" +- 6222853365c5 "platform/x86: asus-wmi: ROG Ally increase wait time, allow MCU powersave" +- 5e9a9192205f "platform/x86: asus-wmi: Add quirk for ROG Ally X" -We can safely continue loading the driver instead of bombing out. +The suspend issue the above was trying to fix has been corrected in MCU +firmware updates by ASUS, where the root cause of issues was a flag in +the MCU powersave path that was not being cleared on resume, leading to +every second resume leaving the MCU in a powered off state. + +The fixed MCU firmware has been available since 2024/10/09. +Minimum versions: +- ROG Ally 1: v319 +- ROG Ally X: v313 Signed-off-by: Luke D. Jones --- - drivers/platform/x86/asus-wmi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + drivers/platform/x86/asus-wmi.c | 40 --------------------------------- + 1 file changed, 40 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index 8bd187e8b47f..2a13466efaa9 100644 +index 8bd187e8b47f..01fc39d64f27 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c -@@ -4747,7 +4747,7 @@ static int asus_wmi_add(struct platform_device *pdev) - goto fail_fan_boost_mode; - - err = platform_profile_setup(asus); -- if (err) -+ if (err && err != -EEXIST) - goto fail_platform_profile_setup; - - err = asus_wmi_sysfs_init(asus->platform_device); --- -2.47.1 - - -From d33e3b4f8bd485888236355f7d0975d91a9110d0 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sun, 1 Sep 2024 14:30:37 +1200 -Subject: [PATCH 03/29] platform/x86: asus-wmi: Refactor Ally suspend/resume - -The CSEE method from ACPI is now called only on module load. This fixes -an issues with USB device loss on Ally 1 after reboot. - -Both Ally 1 and Ally X now rely only of the _DSM screen off/on calls -exposed in AMD s2idle to call the CSEE (which is done in the _DSM), plus -a small additional delay to allow the MCU time to do USB unplug/plug. - -Note: a new MCU FW is being released on 2024/10/16 which will completely -fix the issue this quirk series has been trying to fix, and it will be -able to be removed in full some time in the future. This quirk series -has also been tested with a test version of this FW fix with no ill -effects - users will notice only that powersave becomes reliable 100% of -the time. - -Signed-off-by: Luke D. Jones ---- - drivers/platform/x86/asus-wmi.c | 86 ++++++++++++++++++--------------- - 1 file changed, 48 insertions(+), 38 deletions(-) - -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index 2a13466efaa9..eed807dfcb6c 100644 ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -142,16 +142,20 @@ module_param(fnlock_default, bool, 0444); +@@ -142,11 +142,6 @@ module_param(fnlock_default, bool, 0444); #define ASUS_MINI_LED_2024_STRONG 0x01 #define ASUS_MINI_LED_2024_OFF 0x02 -/* Controls the power state of the USB0 hub on ROG Ally which input is on */ - #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" +-#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" -/* 300ms so far seems to produce a reliable result on AC and battery */ -#define ASUS_USB0_PWR_EC0_CSEE_WAIT 1500 -+/* -+ * The period required to wait after screen off/on/s2idle.check in MS. -+ * Time here greatly impacts the wake behaviour. Used in suspend/wake. -+ */ -+#define ASUS_USB0_PWR_EC0_CSEE_WAIT 600 -+#define ASUS_USB0_PWR_EC0_CSEE_OFF 0xB7 -+#define ASUS_USB0_PWR_EC0_CSEE_ON 0xB8 - +- 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[] = { -+static const struct dmi_system_id asus_rog_ally_device[] = { - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "RC71L"), -@@ -274,9 +278,6 @@ struct asus_wmi { +@@ -274,9 +269,6 @@ struct asus_wmi { u32 tablet_switch_dev_id; bool tablet_switch_inverted; @@ -98,34 +49,7 @@ index 2a13466efaa9..eed807dfcb6c 100644 enum fan_type fan_type; enum fan_type gpu_fan_type; enum fan_type mid_fan_type; -@@ -335,6 +336,8 @@ struct asus_wmi { - struct asus_wmi_driver *driver; - }; - -+static bool ally_mcu_usb_plug; -+ - /* WMI ************************************************************************/ - - static int asus_wmi_evaluate_method3(u32 method_id, -@@ -4707,6 +4710,17 @@ static int asus_wmi_add(struct platform_device *pdev) - if (err) - goto fail_platform; - -+ ally_mcu_usb_plug = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) -+ && dmi_check_system(asus_rog_ally_device); -+ if (ally_mcu_usb_plug) { -+ /* -+ * These steps ensure the device is in a valid good state, this is -+ * especially important for the Ally 1 after a reboot. -+ */ -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, ASUS_USB0_PWR_EC0_CSEE_ON); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+ - /* ensure defaults for tunables */ - asus->ppt_pl2_sppt = 5; - asus->ppt_pl1_spl = 5; -@@ -4719,8 +4733,6 @@ static int asus_wmi_add(struct platform_device *pdev) +@@ -4719,8 +4711,6 @@ 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); @@ -134,7 +58,7 @@ index 2a13466efaa9..eed807dfcb6c 100644 if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -@@ -4911,34 +4923,6 @@ static int asus_hotk_resume(struct device *device) +@@ -4911,34 +4901,6 @@ static int asus_hotk_resume(struct device *device) return 0; } @@ -169,67 +93,23 @@ index 2a13466efaa9..eed807dfcb6c 100644 static int asus_hotk_restore(struct device *device) { struct asus_wmi *asus = dev_get_drvdata(device); -@@ -4979,11 +4963,32 @@ static int asus_hotk_restore(struct device *device) - return 0; - } - -+static void asus_ally_s2idle_restore(void) -+{ -+ if (ally_mcu_usb_plug) { -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, ASUS_USB0_PWR_EC0_CSEE_ON); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+} -+ -+static int asus_hotk_prepare(struct device *device) -+{ -+ if (ally_mcu_usb_plug) { -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, ASUS_USB0_PWR_EC0_CSEE_OFF); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+ return 0; -+} -+ -+/* Use only for Ally devices due to the wake_on_ac */ -+static struct acpi_s2idle_dev_ops asus_ally_s2idle_dev_ops = { -+ .restore = asus_ally_s2idle_restore, -+}; -+ - static const struct dev_pm_ops asus_pm_ops = { +@@ -4983,8 +4945,6 @@ static const struct dev_pm_ops asus_pm_ops = { .thaw = asus_hotk_thaw, .restore = asus_hotk_restore, .resume = asus_hotk_resume, - .resume_early = asus_hotk_resume_early, - .prepare = asus_hotk_prepare, +- .prepare = asus_hotk_prepare, }; -@@ -5011,6 +5016,10 @@ static int asus_wmi_probe(struct platform_device *pdev) - return ret; - } - -+ ret = acpi_register_lps0_dev(&asus_ally_s2idle_dev_ops); -+ if (ret) -+ pr_warn("failed to register LPS0 sleep handler in asus-wmi\n"); -+ - return asus_wmi_add(pdev); - } - -@@ -5043,6 +5052,7 @@ EXPORT_SYMBOL_GPL(asus_wmi_register_driver); - - void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) - { -+ acpi_unregister_lps0_dev(&asus_ally_s2idle_dev_ops); - platform_device_unregister(driver->platform_device); - platform_driver_unregister(&driver->platform_driver); - used = false; + /* Registration ***************************************************************/ -- 2.47.1 -From 88042da6e79ac54e52c84f3b4e0239fdfa25335d Mon Sep 17 00:00:00 2001 +From 228ab740c4377f7b9e11ae88e4429c3c060fe18b Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 22 Sep 2024 21:40:46 +1200 -Subject: [PATCH 04/29] platform/x86: asus-wmi: export symbols used for +Subject: [PATCH 04/28] platform/x86: asus-wmi: export symbols used for read/write WMI Export some rather helpful read/write WMI symbols using a namespace. @@ -240,15 +120,26 @@ Also does a slight refactor of internals of these functions. Signed-off-by: Luke D. Jones Reviewed-by: Mario Limonciello --- + drivers/hid/hid-asus.c | 1 + drivers/platform/x86/asus-wmi.c | 44 ++++++++++++++++++++-- include/linux/platform_data/x86/asus-wmi.h | 10 +++++ - 2 files changed, 51 insertions(+), 3 deletions(-) + 3 files changed, 52 insertions(+), 3 deletions(-) +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 46e3e42f9eb5..2df6a1ca57ba 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1327,4 +1327,5 @@ static struct hid_driver asus_driver = { + }; + module_hid_driver(asus_driver); + ++MODULE_IMPORT_NS("ASUS_WMI"); + MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index eed807dfcb6c..93bbc2421366 100644 +index 01fc39d64f27..a0e0a7490688 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c -@@ -388,7 +388,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) +@@ -377,7 +377,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) { return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval); } @@ -257,7 +148,7 @@ index eed807dfcb6c..93bbc2421366 100644 static int asus_wmi_evaluate_method5(u32 method_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) -@@ -552,12 +552,50 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) +@@ -541,12 +541,50 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) return 0; } @@ -311,7 +202,7 @@ index eed807dfcb6c..93bbc2421366 100644 /* Helper for special devices with magic return codes */ static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 365e119bebaa..6ea4dedfb85e 100644 +index 783e2a336861..466781cbb4bb 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -158,8 +158,18 @@ @@ -337,40 +228,4404 @@ index 365e119bebaa..6ea4dedfb85e 100644 2.47.1 -From 88a3a655ded776243761ebf0912a9a83bfa7fe52 Mon Sep 17 00:00:00 2001 +From a52d59fec1f510c974eab71221fe7b0088d3ac59 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" -Date: Sat, 21 Sep 2024 16:04:58 +1200 -Subject: [PATCH 05/29] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI) - -A small change to asus_wmi_evaluate_method() was introduced during -asus-armoury driver development to put the exports behind a namespace. - -Import that namespace here. +Date: Tue, 28 Jan 2025 19:29:27 +1300 +Subject: [PATCH 05/28] hid-asus: check ROG Ally MCU version and warn Signed-off-by: Luke D. Jones -Acked-by: Jiri Kosina --- - drivers/hid/hid-asus.c | 1 + - 1 file changed, 1 insertion(+) + drivers/hid/hid-asus.c | 97 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index 506c6f377e7d..e6030e013939 100644 +index 2df6a1ca57ba..adccc2346ec3 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c -@@ -1301,4 +1301,5 @@ static struct hid_driver asus_driver = { - }; - module_hid_driver(asus_driver); +@@ -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 -+MODULE_IMPORT_NS("ASUS_WMI"); - MODULE_LICENSE("GPL"); ++#define ROG_ALLY_REPORT_SIZE 64 ++#define ROG_ALLY_X_MIN_MCU 313 ++#define ROG_ALLY_MIN_MCU 319 ++ + #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 | \ +@@ -534,9 +539,89 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) + return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT); + } + ++/* ++ * We don't care about any other part of the string except the version section. ++ * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 ++ */ ++static int mcu_parse_version_string(const u8 *response, size_t response_size) ++{ ++ int dot_count = 0; ++ size_t i; ++ ++ // Look for the second '.' to identify the start of the version ++ for (i = 0; i < response_size; i++) { ++ if (response[i] == '.') { ++ dot_count++; ++ if (dot_count == 2) { ++ int version = ++ simple_strtol((const char *)&response[i + 1], NULL, 10); ++ return (version >= 0) ? version : -EINVAL; ++ } ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int mcu_request_version(struct hid_device *hdev) ++{ ++ const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; ++ u8 *response; ++ int ret; ++ ++ response = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!response) ++ return -ENOMEM; ++ ++ ret = asus_kbd_set_report(hdev, request, sizeof(request)); ++ if (ret < 0) ++ goto out; ++ ++ ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response, ++ ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT, ++ HID_REQ_GET_REPORT); ++ if (ret < 0) ++ goto out; ++ ++ ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE); ++out: ++ if (ret < 0) ++ hid_err(hdev, "Failed to get MCU version: %d\n", ret); ++ kfree(response); ++ return ret; ++} ++ ++static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) ++{ ++ int min_version, version; ++ ++ min_version = ROG_ALLY_X_MIN_MCU; ++ version = mcu_request_version(hdev); ++ if (version) { ++ switch (idProduct) { ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: ++ min_version = ROG_ALLY_MIN_MCU; ++ break; ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: ++ min_version = ROG_ALLY_X_MIN_MCU; ++ break; ++ } ++ } ++ ++ hid_info(hdev, "Ally device MCU version: %d\n", version); ++ if (version < min_version) { ++ hid_warn(hdev, ++ "The MCU version must be %d or greater\n" ++ "Please update your MCU with official ASUS firmware release\n", ++ min_version); ++ } ++} ++ + static int asus_kbd_register_leds(struct hid_device *hdev) + { + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); ++ struct usb_interface *intf; ++ struct usb_device *udev; + unsigned char kbd_func; + int ret; + +@@ -560,6 +645,14 @@ static int asus_kbd_register_leds(struct hid_device *hdev) + if (ret < 0) + return ret; + } ++ ++ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { ++ intf = to_usb_interface(hdev->dev.parent); ++ udev = interface_to_usbdev(intf); ++ mcu_maybe_warn_version(hdev, ++ le16_to_cpu(udev->descriptor.idProduct)); ++ } ++ + } else { + /* Initialize keyboard */ + ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); +@@ -1280,10 +1373,10 @@ 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_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_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), + QUIRK_ROG_CLAYMORE_II_KEYBOARD }, -- 2.47.1 -From ffa88b3d61d2ecf4760cf613cf0c736090d8010c Mon Sep 17 00:00:00 2001 +From bdf1c20de6fb8fd2b61e64430db00732cb43d3f0 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Thu, 30 Jan 2025 20:55:02 +1300 +Subject: [PATCH 06/28] asus-wmi: disable mcu_powersave if MCU version too low + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus.c | 12 ++ + drivers/platform/x86/asus-wmi.c | 132 +------------------- + include/linux/platform_data/x86/asus-wmi.h | 138 +++++++++++++++++++++ + 3 files changed, 152 insertions(+), 130 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index adccc2346ec3..641bf1f8c747 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include /* For to_usb_interface for T100 touchpad intf check */ + #include +@@ -594,6 +595,8 @@ static int mcu_request_version(struct hid_device *hdev) + static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) + { + int min_version, version; ++ struct asus_wmi *asus; ++ struct device *dev; + + min_version = ROG_ALLY_X_MIN_MCU; + version = mcu_request_version(hdev); +@@ -614,6 +617,15 @@ static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) + "The MCU version must be %d or greater\n" + "Please update your MCU with official ASUS firmware release\n", + min_version); ++ /* Get the asus platform device */ ++ dev = bus_find_device_by_name(&platform_bus_type, NULL, "asus-nb-wmi"); ++ if (dev) { ++ asus = dev_get_drvdata(dev); ++ /* Do not show the powersave attribute if MCU version too low */ ++ if (asus) ++ asus->mcu_powersave_available = false; ++ put_device(dev); ++ } + } + } + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index a0e0a7490688..c02d9fa89799 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -198,135 +198,6 @@ struct agfn_fan_args { + u32 speed; /* read: RPM/100 - write: 0-255 */ + } __packed; + +-/* +- * / - debugfs root directory +- * dev_id - current dev_id +- * ctrl_param - current ctrl_param +- * method_id - current method_id +- * devs - call DEVS(dev_id, ctrl_param) and print result +- * dsts - call DSTS(dev_id) and print result +- * call - call method_id(dev_id, ctrl_param) and print result +- */ +-struct asus_wmi_debug { +- struct dentry *root; +- u32 method_id; +- u32 dev_id; +- u32 ctrl_param; +-}; +- +-struct asus_rfkill { +- struct asus_wmi *asus; +- struct rfkill *rfkill; +- u32 dev_id; +-}; +- +-enum fan_type { +- FAN_TYPE_NONE = 0, +- FAN_TYPE_AGFN, /* deprecated on newer platforms */ +- FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ +-}; +- +-struct fan_curve_data { +- bool enabled; +- u32 device_id; +- u8 temps[FAN_CURVE_POINTS]; +- u8 percents[FAN_CURVE_POINTS]; +-}; +- +-struct asus_wmi { +- int dsts_id; +- int spec; +- int sfun; +- +- struct input_dev *inputdev; +- struct backlight_device *backlight_device; +- struct backlight_device *screenpad_backlight_device; +- struct platform_device *platform_device; +- +- struct led_classdev wlan_led; +- int wlan_led_wk; +- struct led_classdev tpd_led; +- int tpd_led_wk; +- struct led_classdev kbd_led; +- int kbd_led_wk; +- struct led_classdev lightbar_led; +- int lightbar_led_wk; +- struct led_classdev micmute_led; +- struct led_classdev camera_led; +- struct workqueue_struct *led_workqueue; +- struct work_struct tpd_led_work; +- struct work_struct wlan_led_work; +- struct work_struct lightbar_led_work; +- +- struct asus_rfkill wlan; +- struct asus_rfkill bluetooth; +- struct asus_rfkill wimax; +- struct asus_rfkill wwan3g; +- struct asus_rfkill gps; +- struct asus_rfkill uwb; +- +- int tablet_switch_event_code; +- u32 tablet_switch_dev_id; +- bool tablet_switch_inverted; +- +- enum fan_type fan_type; +- enum fan_type gpu_fan_type; +- enum fan_type mid_fan_type; +- int fan_pwm_mode; +- int gpu_fan_pwm_mode; +- int mid_fan_pwm_mode; +- int agfn_pwm; +- +- bool fan_boost_mode_available; +- u8 fan_boost_mode_mask; +- u8 fan_boost_mode; +- +- bool egpu_enable_available; +- 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; +- +- u32 kbd_rgb_dev; +- bool kbd_rgb_state_available; +- +- u8 throttle_thermal_policy_mode; +- u32 throttle_thermal_policy_dev; +- +- bool cpu_fan_curve_available; +- bool gpu_fan_curve_available; +- bool mid_fan_curve_available; +- struct fan_curve_data custom_fan_curves[3]; +- +- struct platform_profile_handler platform_profile_handler; +- bool platform_profile_support; +- +- // The RSOC controls the maximum charging percentage. +- bool battery_rsoc_available; +- +- bool panel_overdrive_available; +- u32 mini_led_dev_id; +- +- struct hotplug_slot hotplug_slot; +- struct mutex hotplug_lock; +- struct mutex wmi_lock; +- struct workqueue_struct *hotplug_workqueue; +- struct work_struct hotplug_work; +- +- bool fnlock_locked; +- +- struct asus_wmi_debug debug; +- +- struct asus_wmi_driver *driver; +-}; +- + /* WMI ************************************************************************/ + + static int asus_wmi_evaluate_method3(u32 method_id, +@@ -4489,7 +4360,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + else if (attr == &dev_attr_nv_temp_target.attr) + devid = ASUS_WMI_DEVID_NV_THERM_TARGET; + else if (attr == &dev_attr_mcu_powersave.attr) +- devid = ASUS_WMI_DEVID_MCU_POWERSAVE; ++ ok = asus->mcu_powersave_available; + else if (attr == &dev_attr_boot_sound.attr) + devid = ASUS_WMI_DEVID_BOOT_SOUND; + else if (attr == &dev_attr_panel_od.attr) +@@ -4749,6 +4620,7 @@ 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->mcu_powersave_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); + + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) + asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 466781cbb4bb..4e6de0c97a78 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -5,6 +5,144 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++ ++/* ++ * / - debugfs root directory ++ * dev_id - current dev_id ++ * ctrl_param - current ctrl_param ++ * method_id - current method_id ++ * devs - call DEVS(dev_id, ctrl_param) and print result ++ * dsts - call DSTS(dev_id) and print result ++ * call - call method_id(dev_id, ctrl_param) and print result ++ */ ++struct asus_wmi_debug { ++ struct dentry *root; ++ u32 method_id; ++ u32 dev_id; ++ u32 ctrl_param; ++}; ++ ++struct asus_rfkill { ++ struct asus_wmi *asus; ++ struct rfkill *rfkill; ++ u32 dev_id; ++}; ++ ++enum fan_type { ++ FAN_TYPE_NONE = 0, ++ FAN_TYPE_AGFN, /* deprecated on newer platforms */ ++ FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ ++}; ++ ++#define FAN_CURVE_POINTS 8 ++ ++struct fan_curve_data { ++ bool enabled; ++ u32 device_id; ++ u8 temps[FAN_CURVE_POINTS]; ++ u8 percents[FAN_CURVE_POINTS]; ++}; ++ ++struct asus_wmi { ++ int dsts_id; ++ int spec; ++ int sfun; ++ ++ struct input_dev *inputdev; ++ struct backlight_device *backlight_device; ++ struct backlight_device *screenpad_backlight_device; ++ struct platform_device *platform_device; ++ ++ struct led_classdev wlan_led; ++ int wlan_led_wk; ++ struct led_classdev tpd_led; ++ int tpd_led_wk; ++ struct led_classdev kbd_led; ++ int kbd_led_wk; ++ struct led_classdev lightbar_led; ++ int lightbar_led_wk; ++ struct led_classdev micmute_led; ++ struct led_classdev camera_led; ++ struct workqueue_struct *led_workqueue; ++ struct work_struct tpd_led_work; ++ struct work_struct wlan_led_work; ++ struct work_struct lightbar_led_work; ++ ++ struct asus_rfkill wlan; ++ struct asus_rfkill bluetooth; ++ struct asus_rfkill wimax; ++ struct asus_rfkill wwan3g; ++ struct asus_rfkill gps; ++ struct asus_rfkill uwb; ++ ++ int tablet_switch_event_code; ++ u32 tablet_switch_dev_id; ++ bool tablet_switch_inverted; ++ ++ bool mcu_powersave_available; ++ ++ enum fan_type fan_type; ++ enum fan_type gpu_fan_type; ++ enum fan_type mid_fan_type; ++ int fan_pwm_mode; ++ int gpu_fan_pwm_mode; ++ int mid_fan_pwm_mode; ++ int agfn_pwm; ++ ++ bool fan_boost_mode_available; ++ u8 fan_boost_mode_mask; ++ u8 fan_boost_mode; ++ ++ bool egpu_enable_available; ++ 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; ++ ++ u32 kbd_rgb_dev; ++ bool kbd_rgb_state_available; ++ ++ u8 throttle_thermal_policy_mode; ++ u32 throttle_thermal_policy_dev; ++ ++ bool cpu_fan_curve_available; ++ bool gpu_fan_curve_available; ++ bool mid_fan_curve_available; ++ struct fan_curve_data custom_fan_curves[3]; ++ ++ // struct device *ppdev; ++ struct platform_profile_handler platform_profile_handler; ++ bool platform_profile_support; ++ ++ // The RSOC controls the maximum charging percentage. ++ bool battery_rsoc_available; ++ ++ bool panel_overdrive_available; ++ u32 mini_led_dev_id; ++ ++ struct hotplug_slot hotplug_slot; ++ struct mutex hotplug_lock; ++ struct mutex wmi_lock; ++ struct workqueue_struct *hotplug_workqueue; ++ struct work_struct hotplug_work; ++ ++ bool fnlock_locked; ++ ++ struct asus_wmi_debug debug; ++ ++ struct asus_wmi_driver *driver; ++}; + + /* WMI Methods */ + #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ +-- +2.47.1 + + +From 9480632d43f796b298bfb2fdbea5e4bb9ca2a340 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Mon, 26 Aug 2024 12:49:35 +1200 +Subject: [PATCH 07/28] hid-asus-ally: Add joystick LED ring support + +Adds basic support for the joystick RGB LED rings as a multicolour LED +device with 4 LEDs. + +Move the MCU check in to new driver as it must be done after init, and +hid-asus-ally takes over from hid-asus. + +Signed-off-by: Luke D. Jones +--- + drivers/hid/Kconfig | 9 + + drivers/hid/Makefile | 1 + + drivers/hid/hid-asus-ally.c | 627 ++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 38 +++ + drivers/hid/hid-asus.c | 116 +------ + 5 files changed, 689 insertions(+), 102 deletions(-) + create mode 100644 drivers/hid/hid-asus-ally.c + create mode 100644 drivers/hid/hid-asus-ally.h + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 4d2a89d65b65..89357822c27b 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -164,6 +164,15 @@ config HID_ASUS + - GL553V series + - GL753V series + ++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 24de45f3677d..f338c9eb4600 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..4ceb4aab8084 +--- /dev/null ++++ b/drivers/hid/hid-asus-ally.c +@@ -0,0 +1,627 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * HID driver for Asus ROG laptops and Ally ++ * ++ * Copyright (c) 2023 Luke Jones ++ */ ++ ++#include "linux/device.h" ++#include ++#include ++#include "linux/pm.h" ++#include "linux/slab.h" ++#include "linux/stddef.h" ++#include ++#include ++#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 ROG_ALLY_REPORT_SIZE 64 ++#define ROG_ALLY_X_MIN_MCU 313 ++#define ROG_ALLY_MIN_MCU 319 ++ ++#define ROG_ALLY_CFG_INTF_IN 0x83 ++#define ROG_ALLY_CFG_INTF_OUT 0x04 ++#define ROG_ALLY_X_INTF_IN 0x87 ++ ++#define FEATURE_KBD_LED_REPORT_ID1 0x5d ++#define FEATURE_KBD_LED_REPORT_ID2 0x5e ++ ++static const u8 EC_INIT_STRING[] = { 0x5A, 'A', 'S', 'U', 'S', ' ', 'T', 'e','c', 'h', '.', 'I', 'n', 'c', '.', '\0' }; ++static const u8 EC_MODE_LED_APPLY[] = { 0x5A, 0xB4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ++static const u8 EC_MODE_LED_SET[] = { 0x5A, 0xB5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ++static const u8 FORCE_FEEDBACK_OFF[] = { 0x0D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB }; ++ ++static const struct hid_device_id rog_ally_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X) }, ++ {} ++}; ++ ++struct ally_rgb_dev { ++ struct hid_device *hdev; ++ struct led_classdev_mc led_rgb_dev; ++ struct work_struct work; ++ bool output_worker_initialized; ++ spinlock_t lock; ++ ++ bool removed; ++ bool update_rgb; ++ uint8_t red[4]; ++ uint8_t green[4]; ++ uint8_t blue[4]; ++}; ++ ++struct ally_rgb_data { ++ uint8_t brightness; ++ uint8_t red[4]; ++ uint8_t green[4]; ++ uint8_t blue[4]; ++ bool initialized; ++}; ++ ++static struct ally_drvdata { ++ struct hid_device *hdev; ++ struct ally_rgb_dev *led_rgb_dev; ++ struct ally_rgb_data led_rgb_data; ++} drvdata; ++ ++/** ++ * asus_dev_set_report - send set report request to device. ++ * ++ * @hdev: hid device ++ * @buf: in/out data to transfer ++ * @len: length of buf ++ * ++ * Return: count of data transferred, negative if error ++ * ++ * Same behavior as hid_hw_raw_request. Note that the input buffer is duplicated. ++ */ ++static int asus_dev_set_report(struct hid_device *hdev, const u8 *buf, size_t len) ++{ ++ unsigned char *dmabuf; ++ int ret; ++ ++ dmabuf = kmemdup(buf, len, GFP_KERNEL); ++ if (!dmabuf) ++ return -ENOMEM; ++ ++ ret = hid_hw_raw_request(hdev, buf[0], dmabuf, len, HID_FEATURE_REPORT, ++ HID_REQ_SET_REPORT); ++ kfree(dmabuf); ++ ++ return ret; ++} ++ ++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); ++} ++ ++static u8 get_endpoint_address(struct hid_device *hdev) ++{ ++ struct usb_interface *intf; ++ struct usb_host_endpoint *ep; ++ ++ intf = to_usb_interface(hdev->dev.parent); ++ ++ if (intf) { ++ ep = intf->cur_altsetting->endpoint; ++ if (ep) { ++ return ep->desc.bEndpointAddress; ++ } ++ } ++ ++ return -ENODEV; ++} ++ ++/**************************************************************************************************/ ++/* ROG Ally LED control */ ++/**************************************************************************************************/ ++static void ally_rgb_schedule_work(struct ally_rgb_dev *led) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&led->lock, flags); ++ if (!led->removed) ++ schedule_work(&led->work); ++ spin_unlock_irqrestore(&led->lock, flags); ++} ++ ++/* ++ * The RGB still has the basic 0-3 level brightness. Since the multicolour ++ * brightness is being used in place, set this to max ++ */ ++static int ally_rgb_set_bright_base_max(struct hid_device *hdev) ++{ ++ u8 buf[] = { FEATURE_KBD_LED_REPORT_ID1, 0xba, 0xc5, 0xc4, 0x02 }; ++ ++ return asus_dev_set_report(hdev, buf, sizeof(buf)); ++} ++ ++static void ally_rgb_do_work(struct work_struct *work) ++{ ++ struct ally_rgb_dev *led = container_of(work, struct ally_rgb_dev, work); ++ int ret; ++ unsigned long flags; ++ ++ 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[5 + i * 3] = drvdata.led_rgb_dev->green[i]; ++ buf[6 + i * 3] = drvdata.led_rgb_dev->blue[i]; ++ buf[4 + i * 3] = drvdata.led_rgb_dev->red[i]; ++ } ++ 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); ++} ++ ++static void ally_rgb_set(struct led_classdev *cdev, enum led_brightness brightness) ++{ ++ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); ++ struct ally_rgb_dev *led = container_of(mc_cdev, struct ally_rgb_dev, led_rgb_dev); ++ int intensity, bright; ++ unsigned long flags; ++ ++ led_mc_calc_color_components(mc_cdev, brightness); ++ spin_lock_irqsave(&led->lock, flags); ++ led->update_rgb = true; ++ bright = mc_cdev->led_cdev.brightness; ++ for (int i = 0; i < 4; i++) { ++ intensity = mc_cdev->subled_info[i].intensity; ++ drvdata.led_rgb_dev->red[i] = (((intensity >> 16) & 0xFF) * bright) / 255; ++ drvdata.led_rgb_dev->green[i] = (((intensity >> 8) & 0xFF) * bright) / 255; ++ drvdata.led_rgb_dev->blue[i] = ((intensity & 0xFF) * bright) / 255; ++ } ++ spin_unlock_irqrestore(&led->lock, flags); ++ drvdata.led_rgb_data.initialized = true; ++ ++ ally_rgb_schedule_work(led); ++} ++ ++static int ally_rgb_set_static_from_multi(struct hid_device *hdev) ++{ ++ u8 buf[17] = {FEATURE_KBD_LED_REPORT_ID1, 0xb3}; ++ int ret; ++ ++ /* ++ * Set single zone single colour based on the first LED of EC software mode. ++ * buf[2] = zone, buf[3] = mode ++ */ ++ buf[4] = drvdata.led_rgb_data.red[0]; ++ buf[5] = drvdata.led_rgb_data.green[0]; ++ buf[6] = drvdata.led_rgb_data.blue[0]; ++ ++ ret = asus_dev_set_report(hdev, buf, sizeof(buf)); ++ if (ret < 0) ++ return ret; ++ ++ ret = asus_dev_set_report(hdev, EC_MODE_LED_APPLY, sizeof(EC_MODE_LED_APPLY)); ++ if (ret < 0) ++ return ret; ++ ++ return asus_dev_set_report(hdev, EC_MODE_LED_SET, sizeof(EC_MODE_LED_SET)); ++} ++ ++/* ++ * Store the RGB values for restoring on resume, and set the static mode to the first LED colour ++*/ ++static void ally_rgb_store_settings(void) ++{ ++ int arr_size = sizeof(drvdata.led_rgb_data.red); ++ ++ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; ++ ++ drvdata.led_rgb_data.brightness = led_rgb->led_rgb_dev.led_cdev.brightness; ++ ++ memcpy(drvdata.led_rgb_data.red, led_rgb->red, arr_size); ++ memcpy(drvdata.led_rgb_data.green, led_rgb->green, arr_size); ++ memcpy(drvdata.led_rgb_data.blue, led_rgb->blue, arr_size); ++ ++ ally_rgb_set_static_from_multi(led_rgb->hdev); ++} ++ ++static void ally_rgb_restore_settings(struct ally_rgb_dev *led_rgb, struct led_classdev *led_cdev, ++ struct mc_subled *mc_led_info) ++{ ++ int arr_size = sizeof(drvdata.led_rgb_data.red); ++ ++ memcpy(led_rgb->red, drvdata.led_rgb_data.red, arr_size); ++ memcpy(led_rgb->green, drvdata.led_rgb_data.green, arr_size); ++ memcpy(led_rgb->blue, drvdata.led_rgb_data.blue, arr_size); ++ for (int i = 0; i < 4; i++) { ++ mc_led_info[i].intensity = (drvdata.led_rgb_data.red[i] << 16) | ++ (drvdata.led_rgb_data.green[i] << 8) | ++ drvdata.led_rgb_data.blue[i]; ++ } ++ led_cdev->brightness = drvdata.led_rgb_data.brightness; ++} ++ ++/* Set LEDs. Call after any setup. */ ++static void ally_rgb_resume(void) ++{ ++ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; ++ struct led_classdev *led_cdev; ++ struct mc_subled *mc_led_info; ++ ++ if (!led_rgb) ++ return; ++ ++ led_cdev = &led_rgb->led_rgb_dev.led_cdev; ++ mc_led_info = led_rgb->led_rgb_dev.subled_info; ++ ++ if (drvdata.led_rgb_data.initialized) { ++ ally_rgb_restore_settings(led_rgb, led_cdev, mc_led_info); ++ led_rgb->update_rgb = true; ++ ally_rgb_schedule_work(led_rgb); ++ ally_rgb_set_bright_base_max(led_rgb->hdev); ++ } ++} ++ ++static int ally_rgb_register(struct hid_device *hdev, struct ally_rgb_dev *led_rgb) ++{ ++ struct mc_subled *mc_led_info; ++ struct led_classdev *led_cdev; ++ ++ mc_led_info = ++ devm_kmalloc_array(&hdev->dev, 12, sizeof(*mc_led_info), GFP_KERNEL | __GFP_ZERO); ++ if (!mc_led_info) ++ return -ENOMEM; ++ ++ mc_led_info[0].color_index = LED_COLOR_ID_RGB; ++ mc_led_info[1].color_index = LED_COLOR_ID_RGB; ++ mc_led_info[2].color_index = LED_COLOR_ID_RGB; ++ mc_led_info[3].color_index = LED_COLOR_ID_RGB; ++ ++ led_rgb->led_rgb_dev.subled_info = mc_led_info; ++ led_rgb->led_rgb_dev.num_colors = 4; ++ ++ led_cdev = &led_rgb->led_rgb_dev.led_cdev; ++ led_cdev->brightness = 128; ++ led_cdev->name = "ally:rgb:joystick_rings"; ++ led_cdev->max_brightness = 255; ++ led_cdev->brightness_set = ally_rgb_set; ++ ++ if (drvdata.led_rgb_data.initialized) { ++ ally_rgb_restore_settings(led_rgb, led_cdev, mc_led_info); ++ } ++ ++ return devm_led_classdev_multicolor_register(&hdev->dev, &led_rgb->led_rgb_dev); ++} ++ ++static struct ally_rgb_dev *ally_rgb_create(struct hid_device *hdev) ++{ ++ struct ally_rgb_dev *led_rgb; ++ int ret; ++ ++ led_rgb = devm_kzalloc(&hdev->dev, sizeof(struct ally_rgb_dev), GFP_KERNEL); ++ if (!led_rgb) ++ return ERR_PTR(-ENOMEM); ++ ++ ret = ally_rgb_register(hdev, led_rgb); ++ if (ret < 0) { ++ cancel_work_sync(&led_rgb->work); ++ devm_kfree(&hdev->dev, led_rgb); ++ return ERR_PTR(ret); ++ } ++ ++ led_rgb->hdev = hdev; ++ led_rgb->removed = false; ++ ++ INIT_WORK(&led_rgb->work, ally_rgb_do_work); ++ led_rgb->output_worker_initialized = true; ++ spin_lock_init(&led_rgb->lock); ++ ++ ally_rgb_set_bright_base_max(hdev); ++ ++ /* Not marked as initialized unless ally_rgb_set() is called */ ++ if (drvdata.led_rgb_data.initialized) { ++ msleep(1500); ++ led_rgb->update_rgb = true; ++ ally_rgb_schedule_work(led_rgb); ++ } ++ ++ return led_rgb; ++} ++ ++static void ally_rgb_remove(struct hid_device *hdev) ++{ ++ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; ++ unsigned long flags; ++ int ep; ++ ++ ep = get_endpoint_address(hdev); ++ if (ep != ROG_ALLY_CFG_INTF_IN) ++ return; ++ ++ if (!drvdata.led_rgb_dev || led_rgb->removed) ++ return; ++ ++ spin_lock_irqsave(&led_rgb->lock, flags); ++ led_rgb->removed = true; ++ led_rgb->output_worker_initialized = false; ++ spin_unlock_irqrestore(&led_rgb->lock, flags); ++ cancel_work_sync(&led_rgb->work); ++ devm_led_classdev_multicolor_unregister(&hdev->dev, &led_rgb->led_rgb_dev); ++ ++ hid_info(hdev, "Removed Ally RGB interface"); ++} ++ ++/**************************************************************************************************/ ++/* ROG Ally driver init */ ++/**************************************************************************************************/ ++ ++/* ++ * We don't care about any other part of the string except the version section. ++ * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 ++ */ ++static int mcu_parse_version_string(const u8 *response, size_t response_size) ++{ ++ int dot_count = 0; ++ size_t i; ++ ++ // Look for the second '.' to identify the start of the version ++ for (i = 0; i < response_size; i++) { ++ if (response[i] == '.') { ++ dot_count++; ++ if (dot_count == 2) { ++ int version = ++ simple_strtol((const char *)&response[i + 1], NULL, 10); ++ return (version >= 0) ? version : -EINVAL; ++ } ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int mcu_request_version(struct hid_device *hdev) ++{ ++ const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; ++ u8 *response; ++ int ret; ++ ++ response = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!response) ++ return -ENOMEM; ++ ++ ret = asus_dev_set_report(hdev, request, sizeof(request)); ++ if (ret < 0) ++ goto out; ++ ++ ret = asus_dev_get_report(hdev, response, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto out; ++ ++ ret = mcu_parse_version_string(response, FEATURE_ROG_ALLY_REPORT_SIZE); ++out: ++ if (ret < 0) ++ hid_err(hdev, "Failed to get MCU version: %d\n", ret); ++ kfree(response); ++ return ret; ++} ++ ++static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) ++{ ++ int min_version, version; ++ struct asus_wmi *asus; ++ struct device *dev; ++ ++ min_version = ROG_ALLY_X_MIN_MCU; ++ version = mcu_request_version(hdev); ++ if (version) { ++ switch (idProduct) { ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: ++ min_version = ROG_ALLY_MIN_MCU; ++ break; ++ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: ++ min_version = ROG_ALLY_X_MIN_MCU; ++ break; ++ } ++ } ++ ++ hid_info(hdev, "Ally device MCU version: %d\n", version); ++ if (version < min_version) { ++ hid_warn(hdev, ++ "The MCU version must be %d or greater\n" ++ "Please update your MCU with official ASUS firmware release\n", ++ min_version); ++ /* Get the asus platform device */ ++ dev = bus_find_device_by_name(&platform_bus_type, NULL, "asus-nb-wmi"); ++ if (dev) { ++ asus = dev_get_drvdata(dev); ++ /* Do not show the powersave attribute if MCU version too low */ ++ if (asus) ++ asus->mcu_powersave_available = false; ++ put_device(dev); ++ } ++ } ++} ++ ++static int ally_hid_init(struct hid_device *hdev) ++{ ++ int ret; ++ ++ ret = asus_dev_set_report(hdev, EC_INIT_STRING, sizeof(EC_INIT_STRING)); ++ if (ret < 0) { ++ hid_err(hdev, "Ally failed to send init command: %d\n", ret); ++ return ret; ++ } ++ ++ ret = asus_dev_set_report(hdev, FORCE_FEEDBACK_OFF, sizeof(FORCE_FEEDBACK_OFF)); ++ if (ret < 0) ++ hid_err(hdev, "Ally failed to send init command: %d\n", ret); ++ ++ return ret; ++} ++ ++static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_id) ++{ ++ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); ++ struct usb_device *udev = interface_to_usbdev(intf); ++ u16 idProduct = le16_to_cpu(udev->descriptor.idProduct); ++ int ret, ep; ++ ++ ep = get_endpoint_address(hdev); ++ if (ep < 0) ++ return ep; ++ ++ if (ep != ROG_ALLY_CFG_INTF_IN) ++ return -ENODEV; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "Parse failed\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); ++ if (ret) { ++ hid_err(hdev, "Failed to start HID device\n"); ++ return ret; ++ } ++ ++ ret = hid_hw_open(hdev); ++ if (ret) { ++ hid_err(hdev, "Failed to open HID device\n"); ++ goto err_stop; ++ } ++ ++ /* Initialize MCU even before alloc */ ++ ret = ally_hid_init(hdev); ++ if (ret < 0) ++ return ret; ++ ++ drvdata.hdev = hdev; ++ hid_set_drvdata(hdev, &drvdata); ++ ++ /* This should almost always exist */ ++ if (ep == ROG_ALLY_CFG_INTF_IN) { ++ mcu_maybe_warn_version(hdev, idProduct); ++ ++ drvdata.led_rgb_dev = ally_rgb_create(hdev); ++ if (IS_ERR(drvdata.led_rgb_dev)) ++ hid_err(hdev, "Failed to create Ally gamepad LEDs.\n"); ++ else ++ hid_info(hdev, "Created Ally RGB LED controls.\n"); ++ ++ if (IS_ERR(drvdata.led_rgb_dev)) ++ goto err_close; ++ } ++ ++ return 0; ++ ++err_close: ++ hid_hw_close(hdev); ++err_stop: ++ hid_hw_stop(hdev); ++ return ret; ++} ++ ++static void ally_hid_remove(struct hid_device *hdev) ++{ ++ if (drvdata.led_rgb_dev) ++ ally_rgb_remove(hdev); ++ ++ hid_hw_close(hdev); ++ hid_hw_stop(hdev); ++} ++ ++static int ally_hid_resume(struct hid_device *hdev) ++{ ++ ally_rgb_resume(); ++ ++ return 0; ++} ++ ++static int ally_hid_reset_resume(struct hid_device *hdev) ++{ ++ int ep = get_endpoint_address(hdev); ++ if (ep != ROG_ALLY_CFG_INTF_IN) ++ return 0; ++ ++ ally_hid_init(hdev); ++ ally_rgb_resume(); ++ ++ return 0; ++} ++ ++static int ally_pm_thaw(struct device *dev) ++{ ++ struct hid_device *hdev = to_hid_device(dev); ++ ++ return ally_hid_reset_resume(hdev); ++} ++ ++static int ally_pm_suspend(struct device *dev) ++{ ++ if (drvdata.led_rgb_dev) { ++ ally_rgb_store_settings(); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ally_pm_ops = { ++ .thaw = ally_pm_thaw, ++ .suspend = ally_pm_suspend, ++ .poweroff = ally_pm_suspend, ++}; ++ ++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_hid_probe, ++ .remove = ally_hid_remove, ++ /* HID is the better place for resume functions, not pm_ops */ ++ .resume = ally_hid_resume, ++ .reset_resume = ally_hid_reset_resume, ++ .driver = { ++ .pm = &ally_pm_ops, ++ } }; ++ ++static int __init rog_ally_init(void) ++{ ++ return hid_register_driver(&rog_ally_cfg); ++} ++ ++static void __exit rog_ally_exit(void) ++{ ++ hid_unregister_driver(&rog_ally_cfg); ++} ++ ++module_init(rog_ally_init); ++module_exit(rog_ally_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..eb8617c80c2a +--- /dev/null ++++ b/drivers/hid/hid-asus-ally.h +@@ -0,0 +1,38 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ * HID driver for Asus ROG laptops and Ally ++ * ++ * Copyright (c) 2023 Luke Jones ++ */ ++ ++#include ++#include ++ ++/* 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, ++}; +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 641bf1f8c747..bd28250777f1 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -53,9 +53,9 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); + #define FEATURE_KBD_LED_REPORT_ID1 0x5d + #define FEATURE_KBD_LED_REPORT_ID2 0x5e + +-#define ROG_ALLY_REPORT_SIZE 64 +-#define ROG_ALLY_X_MIN_MCU 313 +-#define ROG_ALLY_MIN_MCU 319 ++#define ROG_ALLY_CFG_INTF_IN 0x83 ++#define ROG_ALLY_CFG_INTF_OUT 0x04 ++#define ROG_ALLY_X_INTF_IN 0x87 + + #define SUPPORT_KBD_BACKLIGHT BIT(0) + +@@ -540,100 +540,9 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) + return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT); + } + +-/* +- * We don't care about any other part of the string except the version section. +- * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 +- */ +-static int mcu_parse_version_string(const u8 *response, size_t response_size) +-{ +- int dot_count = 0; +- size_t i; +- +- // Look for the second '.' to identify the start of the version +- for (i = 0; i < response_size; i++) { +- if (response[i] == '.') { +- dot_count++; +- if (dot_count == 2) { +- int version = +- simple_strtol((const char *)&response[i + 1], NULL, 10); +- return (version >= 0) ? version : -EINVAL; +- } +- } +- } +- +- return -EINVAL; +-} +- +-static int mcu_request_version(struct hid_device *hdev) +-{ +- const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; +- u8 *response; +- int ret; +- +- response = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL); +- if (!response) +- return -ENOMEM; +- +- ret = asus_kbd_set_report(hdev, request, sizeof(request)); +- if (ret < 0) +- goto out; +- +- ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response, +- ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT, +- HID_REQ_GET_REPORT); +- if (ret < 0) +- goto out; +- +- ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE); +-out: +- if (ret < 0) +- hid_err(hdev, "Failed to get MCU version: %d\n", ret); +- kfree(response); +- return ret; +-} +- +-static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) +-{ +- int min_version, version; +- struct asus_wmi *asus; +- struct device *dev; +- +- min_version = ROG_ALLY_X_MIN_MCU; +- version = mcu_request_version(hdev); +- if (version) { +- switch (idProduct) { +- case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: +- min_version = ROG_ALLY_MIN_MCU; +- break; +- case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: +- min_version = ROG_ALLY_X_MIN_MCU; +- break; +- } +- } +- +- hid_info(hdev, "Ally device MCU version: %d\n", version); +- if (version < min_version) { +- hid_warn(hdev, +- "The MCU version must be %d or greater\n" +- "Please update your MCU with official ASUS firmware release\n", +- min_version); +- /* Get the asus platform device */ +- dev = bus_find_device_by_name(&platform_bus_type, NULL, "asus-nb-wmi"); +- if (dev) { +- asus = dev_get_drvdata(dev); +- /* Do not show the powersave attribute if MCU version too low */ +- if (asus) +- asus->mcu_powersave_available = false; +- put_device(dev); +- } +- } +-} +- + static int asus_kbd_register_leds(struct hid_device *hdev) + { + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); +- struct usb_interface *intf; +- struct usb_device *udev; + unsigned char kbd_func; + int ret; + +@@ -657,14 +566,6 @@ static int asus_kbd_register_leds(struct hid_device *hdev) + if (ret < 0) + return ret; + } +- +- if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { +- intf = to_usb_interface(hdev->dev.parent); +- udev = interface_to_usbdev(intf); +- mcu_maybe_warn_version(hdev, +- le16_to_cpu(udev->descriptor.idProduct)); +- } +- + } else { + /* Initialize keyboard */ + ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); +@@ -1134,6 +1035,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 are used by hid-asus-ally */ ++ 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 == ROG_ALLY_X_INTF_IN || ++ ep->desc.bEndpointAddress == ROG_ALLY_CFG_INTF_IN || ++ ep->desc.bEndpointAddress == ROG_ALLY_CFG_INTF_OUT) ++ return -ENODEV; ++ } ++ + /* + * T90CHI's keyboard dock returns same ID values as T100CHI's dock. + * Thus, identify T90CHI dock with product name string. +-- +2.47.1 + + +From 7d7558f4323d8f9187fbb082f7bb3ad4286a78ec Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Wed, 2 Oct 2024 23:32:46 +1300 +Subject: [PATCH 08/28] hid-asus-ally: initial Ally-X gamepad + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 385 +++++++++++++++++++++++++++++++++++- + drivers/hid/hid-asus-ally.h | 5 + + 2 files changed, 389 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 4ceb4aab8084..3d950535c3e2 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -50,6 +50,51 @@ static const struct hid_device_id rog_ally_devices[] = { + {} + }; + ++/* 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 }, ++}; ++ ++/* 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; ++}; ++ + struct ally_rgb_dev { + struct hid_device *hdev; + struct led_classdev_mc led_rgb_dev; +@@ -74,6 +119,7 @@ struct ally_rgb_data { + + static struct ally_drvdata { + struct hid_device *hdev; ++ struct ally_x_device *ally_x; + struct ally_rgb_dev *led_rgb_dev; + struct ally_rgb_data led_rgb_data; + } drvdata; +@@ -128,6 +174,309 @@ static u8 get_endpoint_address(struct hid_device *hdev) + return -ENODEV; + } + ++/**************************************************************************************************/ ++/* 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); ++ } ++ ++ input_sync(ally_x->input); ++ ++ return 0; ++} ++ ++static struct input_dev *ally_x_alloc_input_dev(struct hid_device *hdev, ++ const char *name_suffix) ++{ ++ struct input_dev *input_dev; ++ ++ 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 int ally_x_play_effect(struct input_dev *idev, void *data, struct ff_effect *effect) ++{ ++ 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 void ally_x_work(struct work_struct *work) ++{ ++ 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 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); ++ ++ return input; ++} ++ ++static ssize_t ally_x_qam_mode_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ally_x_device *ally_x = drvdata.ally_x; ++ ++ return sysfs_emit(buf, "%d\n", ally_x->qam_btns_steam_mode); ++} ++ ++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; ++ ++ ret = kstrtobool(buf, &val); ++ if (ret < 0) ++ return ret; ++ ++ 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; ++ } ++ ++ /* 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 (sysfs_create_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr)) { ++ ret = -ENODEV; ++ goto unregister_input; ++ } ++ ++ 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); ++} ++ ++static void ally_x_remove(struct hid_device *hdev) ++{ ++ 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); ++} ++ + /**************************************************************************************************/ + /* ROG Ally LED control */ + /**************************************************************************************************/ +@@ -378,6 +727,24 @@ static void ally_rgb_remove(struct hid_device *hdev) + /* ROG Ally driver init */ + /**************************************************************************************************/ + ++static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, ++ int size) ++{ ++ 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) || ++ (data[0] == 0x5A)) { ++ ally_x_raw_event(ally_x, report, data, size); ++ } else { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + /* + * We don't care about any other part of the string except the version section. + * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 +@@ -493,7 +860,8 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ + if (ep < 0) + return ep; + +- if (ep != ROG_ALLY_CFG_INTF_IN) ++ if (ep != ROG_ALLY_CFG_INTF_IN && ++ ep != ROG_ALLY_X_INTF_IN) + return -ENODEV; + + ret = hid_parse(hdev); +@@ -536,6 +904,17 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ + goto err_close; + } + ++ /* May or may not exist */ ++ if (ep == ROG_ALLY_X_INTF_IN) { ++ 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"); ++ } ++ + return 0; + + err_close: +@@ -550,6 +929,9 @@ static void ally_hid_remove(struct hid_device *hdev) + if (drvdata.led_rgb_dev) + ally_rgb_remove(hdev); + ++ if (drvdata.ally_x) ++ ally_x_remove(hdev); ++ + hid_hw_close(hdev); + hid_hw_stop(hdev); + } +@@ -602,6 +984,7 @@ static struct hid_driver + .id_table = rog_ally_devices, + .probe = ally_hid_probe, + .remove = ally_hid_remove, ++ .raw_event = ally_raw_event, + /* HID is the better place for resume functions, not pm_ops */ + .resume = ally_hid_resume, + .reset_resume = ally_hid_reset_resume, +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index eb8617c80c2a..458d02996bca 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -36,3 +36,8 @@ enum xpad_cmd_len { + xpad_cmd_len_response_curve = 0x09, + xpad_cmd_len_adz = 0x02, + }; ++ ++/* 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) +-- +2.47.1 + + +From 146afa6c8d47142eff2e0de7dee7c4301f77aeae Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Wed, 2 Oct 2024 23:51:36 +1300 +Subject: [PATCH 09/28] hid-asus-ally: initial gamepad configuration + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 246 +++++++++++++++++++++++++++++++++++- + drivers/hid/hid-asus-ally.h | 38 +++--- + 2 files changed, 266 insertions(+), 18 deletions(-) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 3d950535c3e2..822139e2a5c0 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -10,7 +10,6 @@ + #include + #include "linux/pm.h" + #include "linux/slab.h" +-#include "linux/stddef.h" + #include + #include + #include +@@ -39,6 +38,9 @@ + #define FEATURE_KBD_LED_REPORT_ID1 0x5d + #define FEATURE_KBD_LED_REPORT_ID2 0x5e + ++#define BTN_DATA_LEN 11; ++#define BTN_CODE_BYTES_LEN 8 ++ + static const u8 EC_INIT_STRING[] = { 0x5A, 'A', 'S', 'U', 'S', ' ', 'T', 'e','c', 'h', '.', 'I', 'n', 'c', '.', '\0' }; + static const u8 EC_MODE_LED_APPLY[] = { 0x5A, 0xB4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const u8 EC_MODE_LED_SET[] = { 0x5A, 0xB5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +@@ -50,6 +52,58 @@ static const struct hid_device_id rog_ally_devices[] = { + {} + }; + ++struct btn_code_map { ++ u64 code; ++ const char *name; ++}; ++ ++/* byte_array must be >= 8 in length */ ++static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) ++{ ++ /* Convert the u64 to bytes[8] */ ++ for (int i = 0; i < 8; ++i) { ++ byte_array[i] = (keycode >> (56 - 8 * i)) & 0xFF; ++ } ++} ++ ++struct btn_data { ++ u64 button; ++ u64 macro; ++}; ++ ++struct btn_mapping { ++ struct btn_data btn_a; ++ struct btn_data btn_b; ++ struct btn_data btn_x; ++ struct btn_data btn_y; ++ struct btn_data btn_lb; ++ struct btn_data btn_rb; ++ struct btn_data btn_ls; ++ struct btn_data btn_rs; ++ struct btn_data btn_lt; ++ struct btn_data btn_rt; ++ struct btn_data dpad_up; ++ struct btn_data dpad_down; ++ struct btn_data dpad_left; ++ struct btn_data dpad_right; ++ struct btn_data btn_view; ++ struct btn_data btn_menu; ++ struct btn_data btn_m1; ++ struct btn_data btn_m2; ++}; ++ ++/* 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; ++ ++ enum xpad_mode mode; ++ /* ++ * index: [mode] ++ */ ++ struct btn_mapping *key_mapping[xpad_mode_mouse]; ++}; ++ + /* 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 }, +@@ -120,6 +174,7 @@ struct ally_rgb_data { + static struct ally_drvdata { + struct hid_device *hdev; + struct ally_x_device *ally_x; ++ struct ally_gamepad_cfg *gamepad_cfg; + struct ally_rgb_dev *led_rgb_dev; + struct ally_rgb_data led_rgb_data; + } drvdata; +@@ -174,6 +229,172 @@ static u8 get_endpoint_address(struct hid_device *hdev) + return -ENODEV; + } + ++/**************************************************************************************************/ ++/* ROG Ally gamepad configuration */ ++/**************************************************************************************************/ ++ ++/* This should be called before any attempts to set device functions */ ++static int ally_gamepad_check_ready(struct hid_device *hdev) ++{ ++ int ret, count; ++ u8 *hidbuf; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ 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_dbg(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_dbg(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 (count == READY_MAX_TRIES) ++ hid_warn(hdev, "ROG Ally never responded with a ready\n"); ++ ++ kfree(hidbuf); ++ return ret; ++} ++ ++/* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ ++static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, ++ enum btn_pair_index pair, ++ struct btn_data *btn1, struct btn_data *btn2, ++ u8 *out, int out_len) ++{ ++ int start = 5; ++ ++ 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; ++ ++ btn_code_to_byte_array(btn1->button, &out[start]); ++ start += BTN_DATA_LEN; ++ btn_code_to_byte_array(btn1->macro, &out[start]); ++ start += BTN_DATA_LEN; ++ btn_code_to_byte_array(btn2->button, &out[start]); ++ start += BTN_DATA_LEN; ++ btn_code_to_byte_array(btn2->macro, &out[start]); ++ //print_hex_dump(KERN_DEBUG, "byte_array: ", DUMP_PREFIX_OFFSET, 64, 1, out, 64, false); ++} ++ ++/* Apply the mapping pair to the device */ ++static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, ++ enum btn_pair_index btn_pair) ++{ ++ u8 mode = ally_cfg->mode - 1; ++ struct btn_data *btn1, *btn2; ++ u8 *hidbuf; ++ int ret; ++ ++ ret = ally_gamepad_check_ready(hdev); ++ if (ret < 0) ++ return ret; ++ ++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); ++ if (!hidbuf) ++ return -ENOMEM; ++ ++ switch (btn_pair) { ++ case btn_pair_m1_m2: ++ btn1 = &ally_cfg->key_mapping[mode]->btn_m1; ++ btn2 = &ally_cfg->key_mapping[mode]->btn_m2; ++ break; ++ default: ++ break; ++ } ++ ++ _btn_pair_to_hid_pkt(ally_cfg, btn_pair, btn1, btn2, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ++ kfree(hidbuf); ++ ++ return ret; ++} ++ ++static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) ++{ ++ struct ally_gamepad_cfg *ally_cfg; ++ struct input_dev *input_dev; ++ int err; ++ ++ ally_cfg = devm_kzalloc(&hdev->dev, sizeof(*ally_cfg), GFP_KERNEL); ++ if (!ally_cfg) ++ return ERR_PTR(-ENOMEM); ++ ally_cfg->hdev = hdev; ++ // Allocate memory for each mode's `btn_mapping` ++ ally_cfg->mode = xpad_mode_game; ++ for (int i = 0; i < xpad_mode_mouse; i++) { ++ ally_cfg->key_mapping[i] = devm_kzalloc(&hdev->dev, sizeof(struct btn_mapping), GFP_KERNEL); ++ if (!ally_cfg->key_mapping[i]) { ++ err = -ENOMEM; ++ goto free_key_mappings; ++ } ++ } ++ ++ input_dev = devm_input_allocate_device(&hdev->dev); ++ if (!input_dev) { ++ err = -ENOMEM; ++ goto free_ally_cfg; ++ } ++ ++ 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->input = input_dev; ++ ++ /* ignore all errors for this as they are related to USB HID I/O */ ++ ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m1.button = BTN_KB_M1; ++ ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m2.button = BTN_KB_M2; ++ _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); ++ ++ return ally_cfg; ++ ++free_input_dev: ++ devm_kfree(&hdev->dev, input_dev); ++ ++free_key_mappings: ++ for (int i = 0; i < xpad_mode_mouse; i++) { ++ if (ally_cfg->key_mapping[i]) ++ devm_kfree(&hdev->dev, ally_cfg->key_mapping[i]); ++ } ++ ++free_ally_cfg: ++ devm_kfree(&hdev->dev, ally_cfg); ++ return ERR_PTR(err); ++} ++ + /**************************************************************************************************/ + /* ROG Ally gamepad i/o and force-feedback */ + /**************************************************************************************************/ +@@ -730,6 +951,7 @@ static void ally_rgb_remove(struct hid_device *hdev) + 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) { +@@ -742,6 +964,14 @@ static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 + } + } + ++ 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; + } + +@@ -900,7 +1130,13 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ + else + hid_info(hdev, "Created Ally RGB LED controls.\n"); + +- if (IS_ERR(drvdata.led_rgb_dev)) ++ drvdata.gamepad_cfg = ally_gamepad_cfg_create(hdev); ++ 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_dev) && IS_ERR(drvdata.gamepad_cfg)) + goto err_close; + } + +@@ -913,6 +1149,12 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ + goto err_close; + } + hid_info(hdev, "Created Ally X controller.\n"); ++ ++ // 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; +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 458d02996bca..2b298ad4da0e 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -8,35 +8,41 @@ + #include + #include + ++/* ++ * 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, + }; + ++/* Values correspond to the actual HID byte value required */ ++enum btn_pair_index { ++ btn_pair_m1_m2 = 0x08, ++}; ++ ++#define BTN_KB_M2 0x02008E0000000000 ++#define BTN_KB_M1 0x02008F0000000000 ++ ++#define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ ++ struct device_attribute dev_attr_##_name = \ ++ __ATTR(_sysfs_name, 0200, NULL, _name##_store) ++ + /* 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 = \ +-- +2.47.1 + + +From 9bbfc9800a5489d1d6585d2174e2b34660026e1f Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sat, 5 Oct 2024 14:58:33 +1300 +Subject: [PATCH 10/28] hid-asus-ally: add button remap attributes + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 393 ++++++++++++++++++++++++++++++++++-- + drivers/hid/hid-asus-ally.h | 211 +++++++++++++++++++ + 2 files changed, 586 insertions(+), 18 deletions(-) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 822139e2a5c0..884cb688197e 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -57,6 +57,152 @@ struct btn_code_map { + const char *name; + }; + ++static const struct btn_code_map ally_btn_codes[] = { ++ { 0, "NONE" }, ++ /* Gamepad button codes */ ++ { BTN_PAD_A, "PAD_A" }, ++ { BTN_PAD_B, "PAD_B" }, ++ { BTN_PAD_X, "PAD_X" }, ++ { BTN_PAD_Y, "PAD_Y" }, ++ { BTN_PAD_LB, "PAD_LB" }, ++ { BTN_PAD_RB, "PAD_RB" }, ++ { BTN_PAD_LS, "PAD_LS" }, ++ { BTN_PAD_RS, "PAD_RS" }, ++ { BTN_PAD_DPAD_UP, "PAD_DPAD_UP" }, ++ { BTN_PAD_DPAD_DOWN, "PAD_DPAD_DOWN" }, ++ { BTN_PAD_DPAD_LEFT, "PAD_DPAD_LEFT" }, ++ { BTN_PAD_DPAD_RIGHT, "PAD_DPAD_RIGHT" }, ++ { BTN_PAD_VIEW, "PAD_VIEW" }, ++ { BTN_PAD_MENU, "PAD_MENU" }, ++ { BTN_PAD_XBOX, "PAD_XBOX" }, ++ ++ /* Triggers mapped to keyboard codes */ ++ { BTN_KB_M2, "KB_M2" }, ++ { BTN_KB_M1, "KB_M1" }, ++ { BTN_KB_ESC, "KB_ESC" }, ++ { BTN_KB_F1, "KB_F1" }, ++ { BTN_KB_F2, "KB_F2" }, ++ { BTN_KB_F3, "KB_F3" }, ++ { BTN_KB_F4, "KB_F4" }, ++ { BTN_KB_F5, "KB_F5" }, ++ { BTN_KB_F6, "KB_F6" }, ++ { BTN_KB_F7, "KB_F7" }, ++ { BTN_KB_F8, "KB_F8" }, ++ { BTN_KB_F9, "KB_F9" }, ++ { BTN_KB_F10, "KB_F10" }, ++ { BTN_KB_F11, "KB_F11" }, ++ { BTN_KB_F12, "KB_F12" }, ++ { BTN_KB_F14, "KB_F14" }, ++ { BTN_KB_F15, "KB_F15" }, ++ { BTN_KB_BACKTICK, "KB_BACKTICK" }, ++ { BTN_KB_1, "KB_1" }, ++ { BTN_KB_2, "KB_2" }, ++ { BTN_KB_3, "KB_3" }, ++ { BTN_KB_4, "KB_4" }, ++ { BTN_KB_5, "KB_5" }, ++ { BTN_KB_6, "KB_6" }, ++ { BTN_KB_7, "KB_7" }, ++ { BTN_KB_8, "KB_8" }, ++ { BTN_KB_9, "KB_9" }, ++ { BTN_KB_0, "KB_0" }, ++ { BTN_KB_HYPHEN, "KB_HYPHEN" }, ++ { BTN_KB_EQUALS, "KB_EQUALS" }, ++ { BTN_KB_BACKSPACE, "KB_BACKSPACE" }, ++ { BTN_KB_TAB, "KB_TAB" }, ++ { BTN_KB_Q, "KB_Q" }, ++ { BTN_KB_W, "KB_W" }, ++ { BTN_KB_E, "KB_E" }, ++ { BTN_KB_R, "KB_R" }, ++ { BTN_KB_T, "KB_T" }, ++ { BTN_KB_Y, "KB_Y" }, ++ { BTN_KB_U, "KB_U" }, ++ { BTN_KB_O, "KB_O" }, ++ { BTN_KB_P, "KB_P" }, ++ { BTN_KB_LBRACKET, "KB_LBRACKET" }, ++ { BTN_KB_RBRACKET, "KB_RBRACKET" }, ++ { BTN_KB_BACKSLASH, "KB_BACKSLASH" }, ++ { BTN_KB_CAPS, "KB_CAPS" }, ++ { BTN_KB_A, "KB_A" }, ++ { BTN_KB_S, "KB_S" }, ++ { BTN_KB_D, "KB_D" }, ++ { BTN_KB_F, "KB_F" }, ++ { BTN_KB_G, "KB_G" }, ++ { BTN_KB_H, "KB_H" }, ++ { BTN_KB_J, "KB_J" }, ++ { BTN_KB_K, "KB_K" }, ++ { BTN_KB_L, "KB_L" }, ++ { BTN_KB_SEMI, "KB_SEMI" }, ++ { BTN_KB_QUOTE, "KB_QUOTE" }, ++ { BTN_KB_RET, "KB_RET" }, ++ { BTN_KB_LSHIFT, "KB_LSHIFT" }, ++ { BTN_KB_Z, "KB_Z" }, ++ { BTN_KB_X, "KB_X" }, ++ { BTN_KB_C, "KB_C" }, ++ { BTN_KB_V, "KB_V" }, ++ { BTN_KB_B, "KB_B" }, ++ { BTN_KB_N, "KB_N" }, ++ { BTN_KB_M, "KB_M" }, ++ { BTN_KB_COMMA, "KB_COMMA" }, ++ { BTN_KB_PERIOD, "KB_PERIOD" }, ++ { BTN_KB_RSHIFT, "KB_RSHIFT" }, ++ { BTN_KB_LCTL, "KB_LCTL" }, ++ { BTN_KB_META, "KB_META" }, ++ { BTN_KB_LALT, "KB_LALT" }, ++ { BTN_KB_SPACE, "KB_SPACE" }, ++ { BTN_KB_RALT, "KB_RALT" }, ++ { BTN_KB_MENU, "KB_MENU" }, ++ { BTN_KB_RCTL, "KB_RCTL" }, ++ { BTN_KB_PRNTSCN, "KB_PRNTSCN" }, ++ { BTN_KB_SCRLCK, "KB_SCRLCK" }, ++ { BTN_KB_PAUSE, "KB_PAUSE" }, ++ { BTN_KB_INS, "KB_INS" }, ++ { BTN_KB_HOME, "KB_HOME" }, ++ { BTN_KB_PGUP, "KB_PGUP" }, ++ { BTN_KB_DEL, "KB_DEL" }, ++ { BTN_KB_END, "KB_END" }, ++ { BTN_KB_PGDWN, "KB_PGDWN" }, ++ { BTN_KB_UP_ARROW, "KB_UP_ARROW" }, ++ { BTN_KB_DOWN_ARROW, "KB_DOWN_ARROW" }, ++ { BTN_KB_LEFT_ARROW, "KB_LEFT_ARROW" }, ++ { BTN_KB_RIGHT_ARROW, "KB_RIGHT_ARROW" }, ++ ++ /* Numpad mappings */ ++ { BTN_NUMPAD_LOCK, "NUMPAD_LOCK" }, ++ { BTN_NUMPAD_FWDSLASH, "NUMPAD_FWDSLASH" }, ++ { BTN_NUMPAD_ASTERISK, "NUMPAD_ASTERISK" }, ++ { BTN_NUMPAD_HYPHEN, "NUMPAD_HYPHEN" }, ++ { BTN_NUMPAD_0, "NUMPAD_0" }, ++ { BTN_NUMPAD_1, "NUMPAD_1" }, ++ { BTN_NUMPAD_2, "NUMPAD_2" }, ++ { BTN_NUMPAD_3, "NUMPAD_3" }, ++ { BTN_NUMPAD_4, "NUMPAD_4" }, ++ { BTN_NUMPAD_5, "NUMPAD_5" }, ++ { BTN_NUMPAD_6, "NUMPAD_6" }, ++ { BTN_NUMPAD_7, "NUMPAD_7" }, ++ { BTN_NUMPAD_8, "NUMPAD_8" }, ++ { BTN_NUMPAD_9, "NUMPAD_9" }, ++ { BTN_NUMPAD_PLUS, "NUMPAD_PLUS" }, ++ { BTN_NUMPAD_ENTER, "NUMPAD_ENTER" }, ++ { BTN_NUMPAD_PERIOD, "NUMPAD_PERIOD" }, ++ ++ /* Mouse mappings */ ++ { BTN_MOUSE_LCLICK, "MOUSE_LCLICK" }, ++ { BTN_MOUSE_RCLICK, "MOUSE_RCLICK" }, ++ { BTN_MOUSE_MCLICK, "MOUSE_MCLICK" }, ++ { BTN_MOUSE_WHEEL_UP, "MOUSE_WHEEL_UP" }, ++ { BTN_MOUSE_WHEEL_DOWN, "MOUSE_WHEEL_DOWN" }, ++ ++ /* Media mappings */ ++ { BTN_MEDIA_SCREENSHOT, "MEDIA_SCREENSHOT" }, ++ { BTN_MEDIA_SHOW_KEYBOARD, "MEDIA_SHOW_KEYBOARD" }, ++ { BTN_MEDIA_SHOW_DESKTOP, "MEDIA_SHOW_DESKTOP" }, ++ { BTN_MEDIA_START_RECORDING, "MEDIA_START_RECORDING" }, ++ { BTN_MEDIA_MIC_OFF, "MEDIA_MIC_OFF" }, ++ { BTN_MEDIA_VOL_DOWN, "MEDIA_VOL_DOWN" }, ++ { BTN_MEDIA_VOL_UP, "MEDIA_VOL_UP" }, ++}; ++static const size_t keymap_len = ARRAY_SIZE(ally_btn_codes); ++ + /* byte_array must be >= 8 in length */ + static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) + { +@@ -66,6 +212,27 @@ static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) + } + } + ++static u64 name_to_btn(const char *name) ++{ ++ int len = strcspn(name, "\n"); ++ for (size_t i = 0; i < keymap_len; ++i) { ++ if (strncmp(ally_btn_codes[i].name, name, len) == 0) { ++ return ally_btn_codes[i].code; ++ } ++ } ++ return -EINVAL; ++} ++ ++static const char* btn_to_name(u64 key) ++{ ++ for (size_t i = 0; i < keymap_len; ++i) { ++ if (ally_btn_codes[i].code == key) { ++ return ally_btn_codes[i].name; ++ } ++ } ++ return NULL; ++} ++ + struct btn_data { + u64 button; + u64 macro; +@@ -101,7 +268,7 @@ struct ally_gamepad_cfg { + /* + * index: [mode] + */ +- struct btn_mapping *key_mapping[xpad_mode_mouse]; ++ struct btn_mapping key_mapping[xpad_mode_mouse]; + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -315,9 +482,41 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ + return -ENOMEM; + + switch (btn_pair) { ++ case btn_pair_dpad_u_d: ++ btn1 = &ally_cfg->key_mapping[mode].dpad_up; ++ btn2 = &ally_cfg->key_mapping[mode].dpad_down; ++ break; ++ case btn_pair_dpad_l_r: ++ btn1 = &ally_cfg->key_mapping[mode].dpad_left; ++ btn2 = &ally_cfg->key_mapping[mode].dpad_right; ++ break; ++ case btn_pair_ls_rs: ++ btn1 = &ally_cfg->key_mapping[mode].btn_ls; ++ btn2 = &ally_cfg->key_mapping[mode].btn_rs; ++ break; ++ case btn_pair_lb_rb: ++ btn1 = &ally_cfg->key_mapping[mode].btn_lb; ++ btn2 = &ally_cfg->key_mapping[mode].btn_rb; ++ break; ++ case btn_pair_lt_rt: ++ btn1 = &ally_cfg->key_mapping[mode].btn_lt; ++ btn2 = &ally_cfg->key_mapping[mode].btn_rt; ++ break; ++ case btn_pair_a_b: ++ btn1 = &ally_cfg->key_mapping[mode].btn_a; ++ btn2 = &ally_cfg->key_mapping[mode].btn_b; ++ break; ++ case btn_pair_x_y: ++ btn1 = &ally_cfg->key_mapping[mode].btn_x; ++ btn2 = &ally_cfg->key_mapping[mode].btn_y; ++ break; ++ case btn_pair_view_menu: ++ btn1 = &ally_cfg->key_mapping[mode].btn_view; ++ btn2 = &ally_cfg->key_mapping[mode].btn_menu; ++ break; + case btn_pair_m1_m2: +- btn1 = &ally_cfg->key_mapping[mode]->btn_m1; +- btn2 = &ally_cfg->key_mapping[mode]->btn_m2; ++ btn1 = &ally_cfg->key_mapping[mode].btn_m1; ++ btn2 = &ally_cfg->key_mapping[mode].btn_m2; + break; + default: + break; +@@ -331,6 +530,157 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ + return ret; + } + ++static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) ++{ ++ int ret; ++ ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_dpad_u_d); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_dpad_l_r); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_ls_rs); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lb_rb); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_a_b); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_x_y); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_view_menu); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lt_rt); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static ssize_t gamepad_apply_all_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_apply_all(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ALLY_DEVICE_ATTR_WO(gamepad_apply_all, apply_all); ++ ++/* button map attributes, regular and macro*/ ++ALLY_BTN_MAPPING(m1, btn_m1); ++ALLY_BTN_MAPPING(m2, btn_m2); ++ALLY_BTN_MAPPING(a, btn_a); ++ALLY_BTN_MAPPING(b, btn_b); ++ALLY_BTN_MAPPING(x, btn_x); ++ALLY_BTN_MAPPING(y, btn_y); ++ALLY_BTN_MAPPING(lb, btn_lb); ++ALLY_BTN_MAPPING(rb, btn_rb); ++ALLY_BTN_MAPPING(ls, btn_ls); ++ALLY_BTN_MAPPING(rs, btn_rs); ++ALLY_BTN_MAPPING(lt, btn_lt); ++ALLY_BTN_MAPPING(rt, btn_rt); ++ALLY_BTN_MAPPING(dpad_u, dpad_up); ++ALLY_BTN_MAPPING(dpad_d, dpad_down); ++ALLY_BTN_MAPPING(dpad_l, dpad_left); ++ALLY_BTN_MAPPING(dpad_r, dpad_right); ++ALLY_BTN_MAPPING(view, btn_view); ++ALLY_BTN_MAPPING(menu, btn_menu); ++ ++static void _gamepad_set_xpad_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ struct btn_mapping *map = &ally_cfg->key_mapping[ally_cfg->mode - 1]; ++ map->btn_m1.button = BTN_KB_M1; ++ map->btn_m2.button = BTN_KB_M2; ++ map->btn_a.button = BTN_PAD_A; ++ map->btn_b.button = BTN_PAD_B; ++ map->btn_x.button = BTN_PAD_X; ++ map->btn_y.button = BTN_PAD_Y; ++ map->btn_lb.button = BTN_PAD_LB; ++ map->btn_rb.button = BTN_PAD_RB; ++ map->btn_lt.button = BTN_PAD_LT; ++ map->btn_rt.button = BTN_PAD_RT; ++ map->btn_ls.button = BTN_PAD_LS; ++ map->btn_rs.button = BTN_PAD_RS; ++ map->dpad_up.button = BTN_PAD_DPAD_UP; ++ map->dpad_down.button = BTN_PAD_DPAD_DOWN; ++ map->dpad_left.button = BTN_PAD_DPAD_LEFT; ++ map->dpad_right.button = BTN_PAD_DPAD_RIGHT; ++ map->btn_view.button = BTN_PAD_VIEW; ++ map->btn_menu.button = BTN_PAD_MENU; ++} ++ ++static ssize_t btn_mapping_reset_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; ++ ++ switch (ally_cfg->mode) { ++ case xpad_mode_game: ++ _gamepad_set_xpad_default(ally_cfg); ++ break; ++ default: ++ _gamepad_set_xpad_default(ally_cfg); ++ break; ++ } ++ ++ return count; ++} ++ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping); ++ ++/* ROOT LEVEL ATTRS *******************************************************************************/ ++static struct attribute *gamepad_device_attrs[] = { ++ &dev_attr_btn_mapping_reset.attr, ++ &dev_attr_gamepad_apply_all.attr, ++ NULL ++}; ++ ++static const struct attribute_group ally_controller_attr_group = { ++ .attrs = gamepad_device_attrs, ++}; ++ ++static const struct attribute_group *gamepad_device_attr_groups[] = { ++ &ally_controller_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_lt_attr_group, ++ &btn_mapping_rt_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 struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + { + struct ally_gamepad_cfg *ally_cfg; +@@ -343,13 +693,6 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->hdev = hdev; + // Allocate memory for each mode's `btn_mapping` + ally_cfg->mode = xpad_mode_game; +- for (int i = 0; i < xpad_mode_mouse; i++) { +- ally_cfg->key_mapping[i] = devm_kzalloc(&hdev->dev, sizeof(struct btn_mapping), GFP_KERNEL); +- if (!ally_cfg->key_mapping[i]) { +- err = -ENOMEM; +- goto free_key_mappings; +- } +- } + + input_dev = devm_input_allocate_device(&hdev->dev); + if (!input_dev) { +@@ -375,26 +718,37 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->input = input_dev; + + /* ignore all errors for this as they are related to USB HID I/O */ +- ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m1.button = BTN_KB_M1; +- ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m2.button = BTN_KB_M2; ++ _gamepad_set_xpad_default(ally_cfg); ++ ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m1.button = BTN_KB_M1; ++ ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; + _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); + ++ drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup ++ 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_key_mappings: +- for (int i = 0; i < xpad_mode_mouse; i++) { +- if (ally_cfg->key_mapping[i]) +- devm_kfree(&hdev->dev, ally_cfg->key_mapping[i]); +- } +- + free_ally_cfg: + devm_kfree(&hdev->dev, ally_cfg); + return ERR_PTR(err); + } + ++static void ally_cfg_remove(struct hid_device *hdev) ++{ ++ // __gamepad_set_mode(hdev, drvdata.gamepad_cfg, xpad_mode_mouse); ++ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups); ++} ++ + /**************************************************************************************************/ + /* ROG Ally gamepad i/o and force-feedback */ + /**************************************************************************************************/ +@@ -1174,6 +1528,9 @@ static void ally_hid_remove(struct hid_device *hdev) + if (drvdata.ally_x) + ally_x_remove(hdev); + ++ if (drvdata.gamepad_cfg) ++ ally_cfg_remove(hdev); ++ + hid_hw_close(hdev); + hid_hw_stop(hdev); + } +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 2b298ad4da0e..f985cbd698c3 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -33,11 +33,155 @@ enum xpad_cmd_len { + + /* Values correspond to the actual HID byte value required */ + enum btn_pair_index { ++ 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, + }; + ++#define BTN_PAD_A 0x0101000000000000 ++#define BTN_PAD_B 0x0102000000000000 ++#define BTN_PAD_X 0x0103000000000000 ++#define BTN_PAD_Y 0x0104000000000000 ++#define BTN_PAD_LB 0x0105000000000000 ++#define BTN_PAD_RB 0x0106000000000000 ++#define BTN_PAD_LS 0x0107000000000000 ++#define BTN_PAD_RS 0x0108000000000000 ++#define BTN_PAD_DPAD_UP 0x0109000000000000 ++#define BTN_PAD_DPAD_DOWN 0x010A000000000000 ++#define BTN_PAD_DPAD_LEFT 0x010B000000000000 ++#define BTN_PAD_DPAD_RIGHT 0x010C000000000000 ++#define BTN_PAD_LT 0x010D000000000000 ++#define BTN_PAD_RT 0x010E000000000000 ++#define BTN_PAD_VIEW 0x0111000000000000 ++#define BTN_PAD_MENU 0x0112000000000000 ++#define BTN_PAD_XBOX 0x0113000000000000 ++ + #define BTN_KB_M2 0x02008E0000000000 + #define BTN_KB_M1 0x02008F0000000000 ++#define BTN_KB_ESC 0x0200760000000000 ++#define BTN_KB_F1 0x0200500000000000 ++#define BTN_KB_F2 0x0200600000000000 ++#define BTN_KB_F3 0x0200400000000000 ++#define BTN_KB_F4 0x02000C0000000000 ++#define BTN_KB_F5 0x0200030000000000 ++#define BTN_KB_F6 0x02000B0000000000 ++#define BTN_KB_F7 0x0200800000000000 ++#define BTN_KB_F8 0x02000A0000000000 ++#define BTN_KB_F9 0x0200010000000000 ++#define BTN_KB_F10 0x0200090000000000 ++#define BTN_KB_F11 0x0200780000000000 ++#define BTN_KB_F12 0x0200070000000000 ++#define BTN_KB_F14 0x0200180000000000 ++#define BTN_KB_F15 0x0200100000000000 ++#define BTN_KB_BACKTICK 0x02000E0000000000 ++#define BTN_KB_1 0x0200160000000000 ++#define BTN_KB_2 0x02001E0000000000 ++#define BTN_KB_3 0x0200260000000000 ++#define BTN_KB_4 0x0200250000000000 ++#define BTN_KB_5 0x02002E0000000000 ++#define BTN_KB_6 0x0200360000000000 ++#define BTN_KB_7 0x02003D0000000000 ++#define BTN_KB_8 0x02003E0000000000 ++#define BTN_KB_9 0x0200460000000000 ++#define BTN_KB_0 0x0200450000000000 ++#define BTN_KB_HYPHEN 0x02004E0000000000 ++#define BTN_KB_EQUALS 0x0200550000000000 ++#define BTN_KB_BACKSPACE 0x0200660000000000 ++#define BTN_KB_TAB 0x02000D0000000000 ++#define BTN_KB_Q 0x0200150000000000 ++#define BTN_KB_W 0x02001D0000000000 ++#define BTN_KB_E 0x0200240000000000 ++#define BTN_KB_R 0x02002D0000000000 ++#define BTN_KB_T 0x02002C0000000000 ++#define BTN_KB_Y 0x0200350000000000 ++#define BTN_KB_U 0x02003C0000000000 ++#define BTN_KB_O 0x0200440000000000 ++#define BTN_KB_P 0x02004D0000000000 ++#define BTN_KB_LBRACKET 0x0200540000000000 ++#define BTN_KB_RBRACKET 0x02005B0000000000 ++#define BTN_KB_BACKSLASH 0x02005D0000000000 ++#define BTN_KB_CAPS 0x0200580000000000 ++#define BTN_KB_A 0x02001C0000000000 ++#define BTN_KB_S 0x02001B0000000000 ++#define BTN_KB_D 0x0200230000000000 ++#define BTN_KB_F 0x02002B0000000000 ++#define BTN_KB_G 0x0200340000000000 ++#define BTN_KB_H 0x0200330000000000 ++#define BTN_KB_J 0x02003B0000000000 ++#define BTN_KB_K 0x0200420000000000 ++#define BTN_KB_L 0x02004B0000000000 ++#define BTN_KB_SEMI 0x02004C0000000000 ++#define BTN_KB_QUOTE 0x0200520000000000 ++#define BTN_KB_RET 0x02005A0000000000 ++#define BTN_KB_LSHIFT 0x0200880000000000 ++#define BTN_KB_Z 0x02001A0000000000 ++#define BTN_KB_X 0x0200220000000000 ++#define BTN_KB_C 0x0200210000000000 ++#define BTN_KB_V 0x02002A0000000000 ++#define BTN_KB_B 0x0200320000000000 ++#define BTN_KB_N 0x0200310000000000 ++#define BTN_KB_M 0x02003A0000000000 ++#define BTN_KB_COMMA 0x0200410000000000 ++#define BTN_KB_PERIOD 0x0200490000000000 ++#define BTN_KB_RSHIFT 0x0200890000000000 ++#define BTN_KB_LCTL 0x02008C0000000000 ++#define BTN_KB_META 0x0200820000000000 ++#define BTN_KB_LALT 0x02008A0000000000 ++#define BTN_KB_SPACE 0x0200290000000000 ++#define BTN_KB_RALT 0x02008B0000000000 ++#define BTN_KB_MENU 0x0200840000000000 ++#define BTN_KB_RCTL 0x02008D0000000000 ++#define BTN_KB_PRNTSCN 0x0200C30000000000 ++#define BTN_KB_SCRLCK 0x02007E0000000000 ++#define BTN_KB_PAUSE 0x0200910000000000 ++#define BTN_KB_INS 0x0200C20000000000 ++#define BTN_KB_HOME 0x0200940000000000 ++#define BTN_KB_PGUP 0x0200960000000000 ++#define BTN_KB_DEL 0x0200C00000000000 ++#define BTN_KB_END 0x0200950000000000 ++#define BTN_KB_PGDWN 0x0200970000000000 ++#define BTN_KB_UP_ARROW 0x0200980000000000 ++#define BTN_KB_DOWN_ARROW 0x0200990000000000 ++#define BTN_KB_LEFT_ARROW 0x0200910000000000 ++#define BTN_KB_RIGHT_ARROW 0x02009B0000000000 ++ ++#define BTN_NUMPAD_LOCK 0x0200770000000000 ++#define BTN_NUMPAD_FWDSLASH 0x0200900000000000 ++#define BTN_NUMPAD_ASTERISK 0x02007C0000000000 ++#define BTN_NUMPAD_HYPHEN 0x02007B0000000000 ++#define BTN_NUMPAD_0 0x0200700000000000 ++#define BTN_NUMPAD_1 0x0200690000000000 ++#define BTN_NUMPAD_2 0x0200720000000000 ++#define BTN_NUMPAD_3 0x02007A0000000000 ++#define BTN_NUMPAD_4 0x02006B0000000000 ++#define BTN_NUMPAD_5 0x0200730000000000 ++#define BTN_NUMPAD_6 0x0200740000000000 ++#define BTN_NUMPAD_7 0x02006C0000000000 ++#define BTN_NUMPAD_8 0x0200750000000000 ++#define BTN_NUMPAD_9 0x02007D0000000000 ++#define BTN_NUMPAD_PLUS 0x0200790000000000 ++#define BTN_NUMPAD_ENTER 0x0200810000000000 ++#define BTN_NUMPAD_PERIOD 0x0200710000000000 ++ ++#define BTN_MOUSE_LCLICK 0x0300000001000000 ++#define BTN_MOUSE_RCLICK 0x0300000002000000 ++#define BTN_MOUSE_MCLICK 0x0300000003000000 ++#define BTN_MOUSE_WHEEL_UP 0x0300000004000000 ++#define BTN_MOUSE_WHEEL_DOWN 0x0300000005000000 ++ ++#define BTN_MEDIA_SCREENSHOT 0x0500001600000000 ++#define BTN_MEDIA_SHOW_KEYBOARD 0x0500001900000000 ++#define BTN_MEDIA_SHOW_DESKTOP 0x0500001C00000000 ++#define BTN_MEDIA_START_RECORDING 0x0500001E00000000 ++#define BTN_MEDIA_MIC_OFF 0x0500000100000000 ++#define BTN_MEDIA_VOL_DOWN 0x0500000200000000 ++#define BTN_MEDIA_VOL_UP 0x0500000300000000 + + #define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ + struct device_attribute dev_attr_##_name = \ +@@ -47,3 +191,70 @@ enum btn_pair_index { + #define ALLY_DEVICE_ATTR_RW(_name, _sysfs_name) \ + struct device_attribute dev_attr_##_name = \ + __ATTR(_sysfs_name, 0644, _name##_show, _name##_store) ++ ++/* button specific macros */ ++#define ALLY_BTN_SHOW(_fname, _btn_name, _secondary) \ ++ static ssize_t _fname##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ struct btn_data *btn; \ ++ const char* name; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ ++ name = btn_to_name(_secondary ? btn->macro : btn->button); \ ++ return sysfs_emit(buf, "%s\n", name); \ ++ } ++ ++#define ALLY_BTN_STORE(_fname, _btn_name, _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; \ ++ struct btn_data *btn; \ ++ u64 code; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ ++ code = name_to_btn(buf); \ ++ if (_secondary) \ ++ btn->macro = code; \ ++ else \ ++ btn->button = code; \ ++ return count; \ ++ } ++ ++#define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ ++ static struct attribute *_fname##_attrs[] = { \ ++ &dev_attr_##_fname.attr, \ ++ &dev_attr_##_fname##_macro.attr, \ ++ }; \ ++ static const struct attribute_group _fname##_attr_group = { \ ++ .name = __stringify(_name), \ ++ .attrs = _fname##_attrs, \ ++ } ++ ++#define _ALLY_BTN_REMAP(_fname, _btn_name) \ ++ ALLY_BTN_SHOW(btn_mapping_##_fname##_remap, _btn_name, false); \ ++ ALLY_BTN_STORE(btn_mapping_##_fname##_remap, _btn_name, false); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_remap, remap); ++ ++#define _ALLY_BTN_MACRO(_fname, _btn_name) \ ++ ALLY_BTN_SHOW(btn_mapping_##_fname##_macro, _btn_name, true); \ ++ ALLY_BTN_STORE(btn_mapping_##_fname##_macro, _btn_name, true); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_macro, macro_remap); ++ ++#define ALLY_BTN_MAPPING(_fname, _btn_name) \ ++ _ALLY_BTN_REMAP(_fname, _btn_name) \ ++ _ALLY_BTN_MACRO(_fname, _btn_name) \ ++ static struct attribute *_fname##_attrs[] = { \ ++ &dev_attr_btn_mapping_##_fname##_remap.attr, \ ++ &dev_attr_btn_mapping_##_fname##_macro.attr, \ ++ NULL, \ ++ }; \ ++ static const struct attribute_group btn_mapping_##_fname##_attr_group = { \ ++ .name = __stringify(btn_##_fname), \ ++ .attrs = _fname##_attrs, \ ++ } +-- +2.47.1 + + +From 9bd5cccfdb79320029875979dede71904f068cc1 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Fri, 25 Oct 2024 08:56:54 +0200 +Subject: [PATCH 11/28] hid-asus-ally: add gamepad mode selection + +--- + drivers/hid/hid-asus-ally.c | 73 +++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 2 + + 2 files changed, 75 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 884cb688197e..08e953f6a3c5 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -647,9 +647,82 @@ static ssize_t btn_mapping_reset_store(struct device *dev, struct device_attribu + } + 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) ++{ ++ u8 *hidbuf; ++ int 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_mode; ++ hidbuf[3] = xpad_cmd_len_mode; ++ hidbuf[4] = val; ++ ++ ret = ally_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; ++ ++ ret = _gamepad_apply_all(hdev, ally_cfg); ++ if (ret < 0) ++ goto report_fail; ++ ++report_fail: ++ kfree(hidbuf); ++ return ret; ++} ++ ++static ssize_t gamepad_mode_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, "%d\n", ally_cfg->mode); ++} ++ ++static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hid_device *hdev = to_hid_device(dev); ++ 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 < xpad_mode_game || val > xpad_mode_mouse) ++ return -EINVAL; ++ ++ ally_cfg->mode = val; ++ ++ ret = _gamepad_set_mode(hdev, ally_cfg, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++DEVICE_ATTR_RW(gamepad_mode); ++ + /* ROOT LEVEL ATTRS *******************************************************************************/ + static struct attribute *gamepad_device_attrs[] = { + &dev_attr_btn_mapping_reset.attr, ++ &dev_attr_gamepad_mode.attr, + &dev_attr_gamepad_apply_all.attr, + NULL + }; +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index f985cbd698c3..f7e21be50d8e 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -20,6 +20,7 @@ enum xpad_mode { + + /* 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_leds = 0x08, + xpad_cmd_check_ready = 0x0A, +@@ -27,6 +28,7 @@ enum xpad_cmd { + + /* 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_leds = 0x0C, + }; +-- +2.47.1 + + +From 7864114a616a7e485fd12afe6a80ebbcfd756215 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sat, 5 Oct 2024 15:40:09 +1300 +Subject: [PATCH 12/28] hid-asus-ally: Turbo settings for buttons + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 72 +++++++++++++++++++++++++++++-------- + drivers/hid/hid-asus-ally.h | 50 ++++++++++++++++++++++++++ + 2 files changed, 108 insertions(+), 14 deletions(-) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 08e953f6a3c5..53c2b36c14fb 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -236,6 +236,7 @@ static const char* btn_to_name(u64 key) + struct btn_data { + u64 button; + u64 macro; ++ bool turbo; + }; + + struct btn_mapping { +@@ -530,6 +531,46 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ + return ret; + } + ++static int _gamepad_apply_turbo(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) ++{ ++ struct btn_mapping *map = &ally_cfg->key_mapping[ally_cfg->mode - 1]; ++ u8 *hidbuf; ++ int 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; ++ ++ hidbuf[4] = map->dpad_up.turbo; ++ hidbuf[6] = map->dpad_down.turbo; ++ hidbuf[8] = map->dpad_left.turbo; ++ hidbuf[10] = map->dpad_right.turbo; ++ ++ hidbuf[12] = map->btn_ls.turbo; ++ hidbuf[14] = map->btn_rs.turbo; ++ hidbuf[16] = map->btn_lb.turbo; ++ hidbuf[18] = map->btn_rb.turbo; ++ ++ hidbuf[20] = map->btn_a.turbo; ++ hidbuf[22] = map->btn_b.turbo; ++ hidbuf[24] = map->btn_x.turbo; ++ hidbuf[26] = map->btn_y.turbo; ++ ++ hidbuf[28] = map->btn_lt.turbo; ++ hidbuf[30] = map->btn_rt.turbo; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ++ kfree(hidbuf); ++ ++ return ret; ++} ++ + static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) + { + int ret; +@@ -559,6 +600,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c + if (ret < 0) + return ret; + ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lt_rt); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_turbo(hdev, ally_cfg); + if (ret < 0) + return ret; + +@@ -586,22 +630,22 @@ ALLY_DEVICE_ATTR_WO(gamepad_apply_all, apply_all); + /* button map attributes, regular and macro*/ + ALLY_BTN_MAPPING(m1, btn_m1); + ALLY_BTN_MAPPING(m2, btn_m2); +-ALLY_BTN_MAPPING(a, btn_a); +-ALLY_BTN_MAPPING(b, btn_b); +-ALLY_BTN_MAPPING(x, btn_x); +-ALLY_BTN_MAPPING(y, btn_y); +-ALLY_BTN_MAPPING(lb, btn_lb); +-ALLY_BTN_MAPPING(rb, btn_rb); +-ALLY_BTN_MAPPING(ls, btn_ls); +-ALLY_BTN_MAPPING(rs, btn_rs); +-ALLY_BTN_MAPPING(lt, btn_lt); +-ALLY_BTN_MAPPING(rt, btn_rt); +-ALLY_BTN_MAPPING(dpad_u, dpad_up); +-ALLY_BTN_MAPPING(dpad_d, dpad_down); +-ALLY_BTN_MAPPING(dpad_l, dpad_left); +-ALLY_BTN_MAPPING(dpad_r, dpad_right); + ALLY_BTN_MAPPING(view, btn_view); + ALLY_BTN_MAPPING(menu, btn_menu); ++ALLY_TURBO_BTN_MAPPING(a, btn_a); ++ALLY_TURBO_BTN_MAPPING(b, btn_b); ++ALLY_TURBO_BTN_MAPPING(x, btn_x); ++ALLY_TURBO_BTN_MAPPING(y, btn_y); ++ALLY_TURBO_BTN_MAPPING(lb, btn_lb); ++ALLY_TURBO_BTN_MAPPING(rb, btn_rb); ++ALLY_TURBO_BTN_MAPPING(ls, btn_ls); ++ALLY_TURBO_BTN_MAPPING(rs, btn_rs); ++ALLY_TURBO_BTN_MAPPING(lt, btn_lt); ++ALLY_TURBO_BTN_MAPPING(rt, btn_rt); ++ALLY_TURBO_BTN_MAPPING(dpad_u, dpad_up); ++ALLY_TURBO_BTN_MAPPING(dpad_d, dpad_down); ++ALLY_TURBO_BTN_MAPPING(dpad_l, dpad_left); ++ALLY_TURBO_BTN_MAPPING(dpad_r, dpad_right); + + static void _gamepad_set_xpad_default(struct ally_gamepad_cfg *ally_cfg) + { +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index f7e21be50d8e..63a3b5caa71c 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -24,6 +24,7 @@ enum xpad_cmd { + xpad_cmd_set_mapping = 0x02, + xpad_cmd_set_leds = 0x08, + xpad_cmd_check_ready = 0x0A, ++ xpad_cmd_set_turbo = 0x0F, + }; + + /* the xpad_cmd determines which feature is set or queried */ +@@ -31,6 +32,7 @@ enum xpad_cmd_len { + xpad_cmd_len_mode = 0x01, + xpad_cmd_len_mapping = 0x2c, + xpad_cmd_len_leds = 0x0C, ++ xpad_cmd_len_turbo = 0x20, + }; + + /* Values correspond to the actual HID byte value required */ +@@ -228,6 +230,37 @@ enum btn_pair_index { + return count; \ + } + ++#define ALLY_TURBO_SHOW(_fname, _btn_name) \ ++ static ssize_t _fname##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ struct btn_data *btn; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ ++ return sysfs_emit(buf, "%d\n", btn->turbo); \ ++ } ++ ++#define ALLY_TURBO_STORE(_fname, _btn_name) \ ++ 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; \ ++ struct btn_data *btn; \ ++ bool turbo; \ ++ int ret; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ ++ ret = kstrtobool(buf, &turbo); \ ++ if (ret) \ ++ return ret; \ ++ btn->turbo = turbo; \ ++ return count; \ ++ } ++ + #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ + static struct attribute *_fname##_attrs[] = { \ + &dev_attr_##_fname.attr, \ +@@ -260,3 +293,20 @@ enum btn_pair_index { + .name = __stringify(btn_##_fname), \ + .attrs = _fname##_attrs, \ + } ++ ++#define ALLY_TURBO_BTN_MAPPING(_fname, _btn_name) \ ++ _ALLY_BTN_REMAP(_fname, _btn_name) \ ++ _ALLY_BTN_MACRO(_fname, _btn_name) \ ++ ALLY_TURBO_SHOW(btn_mapping_##_fname##_turbo, _btn_name); \ ++ ALLY_TURBO_STORE(btn_mapping_##_fname##_turbo, _btn_name); \ ++ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_turbo, turbo); \ ++ static struct attribute *_fname##_turbo_attrs[] = { \ ++ &dev_attr_btn_mapping_##_fname##_remap.attr, \ ++ &dev_attr_btn_mapping_##_fname##_macro.attr, \ ++ &dev_attr_btn_mapping_##_fname##_turbo.attr, \ ++ NULL, \ ++ }; \ ++ static const struct attribute_group btn_mapping_##_fname##_attr_group = { \ ++ .name = __stringify(btn_##_fname), \ ++ .attrs = _fname##_turbo_attrs, \ ++ } +-- +2.47.1 + + +From f19752b0af90acea553188b1baa9f18dabc684c2 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sat, 5 Oct 2024 20:46:00 +1300 +Subject: [PATCH 13/28] hid-asus-ally: add vibration intensity settings + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 93 +++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 6 +++ + 2 files changed, 99 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 53c2b36c14fb..8b40b806631c 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -270,6 +270,11 @@ struct ally_gamepad_cfg { + * index: [mode] + */ + struct btn_mapping key_mapping[xpad_mode_mouse]; ++ /* ++ * index: left, right ++ * max: 64 ++ */ ++ u8 vibration_intensity[2]; + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -441,6 +446,89 @@ static int ally_gamepad_check_ready(struct hid_device *hdev) + return ret; + } + ++/* 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"); ++} ++ ++ALLY_DEVICE_ATTR_RO(gamepad_vibration_intensity_index, vibration_intensity_index); ++ ++static ssize_t _gamepad_apply_intensity(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) ++{ ++ u8 *hidbuf; ++ int 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_vibe_intensity; ++ hidbuf[3] = xpad_cmd_len_vibe_intensity; ++ hidbuf[4] = ally_cfg->vibration_intensity[0]; ++ hidbuf[5] = ally_cfg->vibration_intensity[1]; ++ ++ ret = ally_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; ++} ++ ++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; ++ ++ if (!drvdata.gamepad_cfg) ++ return -ENODEV; ++ ++ return sysfs_emit( ++ buf, "%d %d\n", ++ ally_cfg->vibration_intensity[0], ++ ally_cfg->vibration_intensity[1]); ++} ++ ++static ssize_t gamepad_vibration_intensity_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, ++ size_t count) ++{ ++ 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[0] = left; ++ ally_cfg->vibration_intensity[1] = right; ++ ++ ret = _gamepad_apply_intensity(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); ++ + /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ + static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, + enum btn_pair_index pair, +@@ -768,6 +856,8 @@ static struct attribute *gamepad_device_attrs[] = { + &dev_attr_btn_mapping_reset.attr, + &dev_attr_gamepad_mode.attr, + &dev_attr_gamepad_apply_all.attr, ++ &dev_attr_gamepad_vibration_intensity.attr, ++ &dev_attr_gamepad_vibration_intensity_index.attr, + NULL + }; + +@@ -840,6 +930,9 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; + _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); + ++ ally_cfg->vibration_intensity[0] = 0x64; ++ ally_cfg->vibration_intensity[1] = 0x64; ++ + drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup + if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { + err = -ENODEV; +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 63a3b5caa71c..6ac79ad3c5f2 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -22,6 +22,7 @@ enum xpad_mode { + enum xpad_cmd { + xpad_cmd_set_mode = 0x01, + xpad_cmd_set_mapping = 0x02, ++ xpad_cmd_set_vibe_intensity = 0x06, + xpad_cmd_set_leds = 0x08, + xpad_cmd_check_ready = 0x0A, + xpad_cmd_set_turbo = 0x0F, +@@ -31,6 +32,7 @@ enum xpad_cmd { + enum xpad_cmd_len { + xpad_cmd_len_mode = 0x01, + xpad_cmd_len_mapping = 0x2c, ++ xpad_cmd_len_vibe_intensity = 0x02, + xpad_cmd_len_leds = 0x0C, + xpad_cmd_len_turbo = 0x20, + }; +@@ -196,6 +198,10 @@ enum btn_pair_index { + 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) ++ + /* button specific macros */ + #define ALLY_BTN_SHOW(_fname, _btn_name, _secondary) \ + static ssize_t _fname##_show(struct device *dev, \ +-- +2.47.1 + + +From e59c4657466b382c250568f87ec742bfefaa25bf Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sat, 5 Oct 2024 21:32:41 +1300 +Subject: [PATCH 14/28] hid-asus-ally: add JS deadzones + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 84 +++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 39 +++++++++++++++++ + 2 files changed, 123 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 8b40b806631c..64f4b466f0bb 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -260,6 +260,11 @@ struct btn_mapping { + struct btn_data btn_m2; + }; + ++struct deadzone { ++ u8 inner; ++ u8 outer; ++}; ++ + /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ + struct ally_gamepad_cfg { + struct hid_device *hdev; +@@ -275,6 +280,10 @@ struct ally_gamepad_cfg { + * max: 64 + */ + u8 vibration_intensity[2]; ++ ++ /* deadzones */ ++ struct deadzone ls_dz; // left stick ++ struct deadzone rs_dz; // right stick + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -529,6 +538,75 @@ static ssize_t gamepad_vibration_intensity_store(struct device *dev, + + ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); + ++/* ANALOGUE DEADZONES *****************************************************************************/ ++static ssize_t _gamepad_apply_deadzones(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) ++{ ++ u8 *hidbuf; ++ int ret; ++ ++ ret = ally_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->ls_dz.inner; ++ hidbuf[5] = ally_cfg->ls_dz.outer; ++ hidbuf[6] = ally_cfg->rs_dz.inner; ++ hidbuf[7] = ally_cfg->rs_dz.outer; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ ++ kfree(hidbuf); ++ return ret; ++} ++ ++static void _gamepad_set_deadzones_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ ally_cfg->ls_dz.inner = 0x00; ++ ally_cfg->ls_dz.outer = 0x64; ++ ally_cfg->rs_dz.inner = 0x00; ++ ally_cfg->rs_dz.outer = 0x64; ++} ++ ++static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "inner outer\n"); ++} ++ ++ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index); ++ ++ALLY_DEADZONES(axis_xy_left, ls_dz); ++ALLY_DEADZONES(axis_xy_right, rs_dz); ++ ++static struct attribute *axis_xy_left_attrs[] = { ++ &dev_attr_axis_xy_left_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ NULL ++}; ++static const struct attribute_group axis_xy_left_attr_group = { ++ .name = "axis_xy_left", ++ .attrs = axis_xy_left_attrs, ++}; ++ ++static struct attribute *axis_xy_right_attrs[] = { ++ &dev_attr_axis_xy_right_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ NULL ++}; ++static const struct attribute_group axis_xy_right_attr_group = { ++ .name = "axis_xy_right", ++ .attrs = axis_xy_right_attrs, ++}; ++ + /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ + static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, + enum btn_pair_index pair, +@@ -691,6 +769,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c + if (ret < 0) + return ret; + ret = _gamepad_apply_turbo(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_deadzones(hdev, ally_cfg); + if (ret < 0) + return ret; + +@@ -867,6 +948,8 @@ static const struct attribute_group ally_controller_attr_group = { + + static const struct attribute_group *gamepad_device_attr_groups[] = { + &ally_controller_attr_group, ++ &axis_xy_left_attr_group, ++ &axis_xy_right_attr_group, + &btn_mapping_m1_attr_group, + &btn_mapping_m2_attr_group, + &btn_mapping_a_attr_group, +@@ -932,6 +1015,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + + ally_cfg->vibration_intensity[0] = 0x64; + ally_cfg->vibration_intensity[1] = 0x64; ++ _gamepad_set_deadzones_default(ally_cfg); + + drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup + if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 6ac79ad3c5f2..3dc14a5226f3 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -22,6 +22,7 @@ enum xpad_mode { + enum xpad_cmd { + xpad_cmd_set_mode = 0x01, + xpad_cmd_set_mapping = 0x02, ++ xpad_cmd_set_js_dz = 0x04, /* deadzones */ + xpad_cmd_set_vibe_intensity = 0x06, + xpad_cmd_set_leds = 0x08, + xpad_cmd_check_ready = 0x0A, +@@ -32,6 +33,7 @@ enum xpad_cmd { + 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_turbo = 0x20, +@@ -267,6 +269,43 @@ enum btn_pair_index { + return count; \ + } + ++#define ALLY_DEADZONE_SHOW(_fname, _axis_name) \ ++ static ssize_t _fname##_show(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++ { \ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ ++ struct deadzone *dz; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ dz = &ally_cfg->_axis_name; \ ++ return sysfs_emit(buf, "%d %d\n", dz->inner, dz->outer); \ ++ } ++ ++#define ALLY_DEADZONE_STORE(_fname, _axis_name) \ ++ 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; \ ++ struct hid_device *hdev = to_hid_device(dev); \ ++ u32 inner, outer; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ if (sscanf(buf, "%d %d", &inner, &outer) != 2) \ ++ return -EINVAL; \ ++ if (inner > 64 || outer > 64 || inner > outer) \ ++ return -EINVAL; \ ++ ally_cfg->_axis_name.inner = inner; \ ++ ally_cfg->_axis_name.outer = outer; \ ++ _gamepad_apply_deadzones(hdev, ally_cfg); \ ++ return count; \ ++ } ++ ++#define ALLY_DEADZONES(_fname, _mname) \ ++ ALLY_DEADZONE_SHOW(_fname##_deadzone, _mname); \ ++ ALLY_DEADZONE_STORE(_fname##_deadzone, _mname); \ ++ ALLY_DEVICE_ATTR_RW(_fname##_deadzone, deadzone) ++ + #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ + static struct attribute *_fname##_attrs[] = { \ + &dev_attr_##_fname.attr, \ +-- +2.47.1 + + +From 2a5cd6d77dcc471ac4792100ef677c2beba316f0 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sat, 5 Oct 2024 21:37:27 +1300 +Subject: [PATCH 15/28] hid-asus-ally: add trigger deadzones + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 43 +++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 1 + + 2 files changed, 44 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 64f4b466f0bb..4a3e7cea1c5e 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -284,6 +284,8 @@ struct ally_gamepad_cfg { + /* deadzones */ + struct deadzone ls_dz; // left stick + struct deadzone rs_dz; // right stick ++ struct deadzone lt_dz; // left trigger ++ struct deadzone rt_dz; // right trigger + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -563,7 +565,20 @@ static ssize_t _gamepad_apply_deadzones(struct hid_device *hdev, + hidbuf[7] = ally_cfg->rs_dz.outer; + + 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->lt_dz.inner; ++ hidbuf[5] = ally_cfg->lt_dz.outer; ++ hidbuf[6] = ally_cfg->rt_dz.inner; ++ hidbuf[7] = ally_cfg->rt_dz.outer; ++ ++ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ goto end; + ++end: + kfree(hidbuf); + return ret; + } +@@ -574,6 +589,10 @@ static void _gamepad_set_deadzones_default(struct ally_gamepad_cfg *ally_cfg) + ally_cfg->ls_dz.outer = 0x64; + ally_cfg->rs_dz.inner = 0x00; + ally_cfg->rs_dz.outer = 0x64; ++ ally_cfg->lt_dz.inner = 0x00; ++ ally_cfg->lt_dz.outer = 0x64; ++ ally_cfg->rt_dz.inner = 0x00; ++ ally_cfg->rt_dz.outer = 0x64; + } + + static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr, +@@ -586,6 +605,8 @@ ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index); + + ALLY_DEADZONES(axis_xy_left, ls_dz); + ALLY_DEADZONES(axis_xy_right, rs_dz); ++ALLY_DEADZONES(axis_z_left, lt_dz); ++ALLY_DEADZONES(axis_z_right, rt_dz); + + static struct attribute *axis_xy_left_attrs[] = { + &dev_attr_axis_xy_left_deadzone.attr, +@@ -607,6 +628,26 @@ static const struct attribute_group axis_xy_right_attr_group = { + .attrs = axis_xy_right_attrs, + }; + ++static struct attribute *axis_z_left_attrs[] = { ++ &dev_attr_axis_z_left_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ NULL, ++}; ++static const struct attribute_group axis_z_left_attr_group = { ++ .name = "axis_z_left", ++ .attrs = axis_z_left_attrs, ++}; ++ ++static struct attribute *axis_z_right_attrs[] = { ++ &dev_attr_axis_z_right_deadzone.attr, ++ &dev_attr_axis_xyz_deadzone_index.attr, ++ NULL, ++}; ++static const struct attribute_group axis_z_right_attr_group = { ++ .name = "axis_z_right", ++ .attrs = axis_z_right_attrs, ++}; ++ + /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ + static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, + enum btn_pair_index pair, +@@ -950,6 +991,8 @@ static const struct attribute_group *gamepad_device_attr_groups[] = { + &ally_controller_attr_group, + &axis_xy_left_attr_group, + &axis_xy_right_attr_group, ++ &axis_z_left_attr_group, ++ &axis_z_right_attr_group, + &btn_mapping_m1_attr_group, + &btn_mapping_m2_attr_group, + &btn_mapping_a_attr_group, +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 3dc14a5226f3..32ed5caa3759 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -23,6 +23,7 @@ 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, +-- +2.47.1 + + +From 8a42534a96ece50ab358fd5a15375aad1a89b39f Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sun, 6 Oct 2024 19:49:24 +1300 +Subject: [PATCH 16/28] hid-asus-ally: add anti-deadzones + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 110 ++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 2 + + 2 files changed, 112 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index 4a3e7cea1c5e..ff1c2cf61e66 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -286,6 +286,9 @@ struct ally_gamepad_cfg { + struct deadzone rs_dz; // right stick + struct deadzone lt_dz; // left trigger + struct deadzone rt_dz; // right trigger ++ /* anti-deadzones */ ++ u8 ls_adz; // left stick ++ u8 rs_adz; // right stick + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -608,7 +611,109 @@ ALLY_DEADZONES(axis_xy_right, rs_dz); + ALLY_DEADZONES(axis_z_left, lt_dz); + ALLY_DEADZONES(axis_z_right, rt_dz); + ++/* ANTI-DEADZONES *********************************************************************************/ ++static ssize_t _gamepad_apply_js_ADZ(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) ++{ ++ u8 *hidbuf; ++ int 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->ls_adz; ++ hidbuf[5] = ally_cfg->rs_adz; ++ ++ ret = ally_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; ++} ++ ++static void _gamepad_set_anti_deadzones_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ ally_cfg->ls_adz = 0x00; ++ ally_cfg->rs_adz = 0x00; ++} ++ ++static ssize_t _gamepad_js_ADZ_store(struct device *dev, const char *buf, u8 *adz) ++{ ++ int ret, val; ++ ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ ++ if (val < 0 || val > 32) ++ return -EINVAL; ++ ++ *adz = val; ++ ++ return ret; ++} ++ ++static ssize_t axis_xy_left_anti_deadzone_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ ++ return sysfs_emit(buf, "%d\n", ally_cfg->ls_adz); ++} ++ ++static ssize_t axis_xy_left_anti_deadzone_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int ret; ++ ++ ret = _gamepad_js_ADZ_store(dev, buf, &ally_cfg->ls_adz); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ALLY_DEVICE_ATTR_RW(axis_xy_left_anti_deadzone, anti_deadzone); ++ ++static ssize_t axis_xy_right_anti_deadzone_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ ++ return sysfs_emit(buf, "%d\n", ally_cfg->rs_adz); ++} ++ ++static ssize_t axis_xy_right_anti_deadzone_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; ++ int ret; ++ ++ ret = _gamepad_js_ADZ_store(dev, buf, &ally_cfg->rs_adz); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ALLY_DEVICE_ATTR_RW(axis_xy_right_anti_deadzone, anti_deadzone); ++ + static struct attribute *axis_xy_left_attrs[] = { ++ &dev_attr_axis_xy_left_anti_deadzone.attr, + &dev_attr_axis_xy_left_deadzone.attr, + &dev_attr_axis_xyz_deadzone_index.attr, + NULL +@@ -619,6 +724,7 @@ static const struct attribute_group axis_xy_left_attr_group = { + }; + + static struct attribute *axis_xy_right_attrs[] = { ++ &dev_attr_axis_xy_right_anti_deadzone.attr, + &dev_attr_axis_xy_right_deadzone.attr, + &dev_attr_axis_xyz_deadzone_index.attr, + NULL +@@ -813,6 +919,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c + if (ret < 0) + return ret; + ret = _gamepad_apply_deadzones(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ret = _gamepad_apply_js_ADZ(hdev, ally_cfg); + if (ret < 0) + return ret; + +@@ -1059,6 +1168,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->vibration_intensity[0] = 0x64; + ally_cfg->vibration_intensity[1] = 0x64; + _gamepad_set_deadzones_default(ally_cfg); ++ _gamepad_set_anti_deadzones_default(ally_cfg); + + drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup + if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 32ed5caa3759..69f59592dd50 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -28,6 +28,7 @@ enum xpad_cmd { + xpad_cmd_set_leds = 0x08, + xpad_cmd_check_ready = 0x0A, + xpad_cmd_set_turbo = 0x0F, ++ xpad_cmd_set_adz = 0x18, + }; + + /* the xpad_cmd determines which feature is set or queried */ +@@ -38,6 +39,7 @@ enum xpad_cmd_len { + xpad_cmd_len_vibe_intensity = 0x02, + xpad_cmd_len_leds = 0x0C, + xpad_cmd_len_turbo = 0x20, ++ xpad_cmd_len_adz = 0x02, + }; + + /* Values correspond to the actual HID byte value required */ +-- +2.47.1 + + +From 29991f2b1cd7ff8af75db182707856f682f30a7e Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Sun, 6 Oct 2024 21:22:40 +1300 +Subject: [PATCH 17/28] hid-asus-ally: add JS response curves + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 103 ++++++++++++++++++++++++++++++++++++ + drivers/hid/hid-asus-ally.h | 38 +++++++++++++ + 2 files changed, 141 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index ff1c2cf61e66..aad965e069ee 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -5,10 +5,12 @@ + * Copyright (c) 2023 Luke Jones + */ + ++#include "linux/compiler_attributes.h" + #include "linux/device.h" + #include + #include + #include "linux/pm.h" ++#include "linux/printk.h" + #include "linux/slab.h" + #include + #include +@@ -265,6 +267,17 @@ struct deadzone { + u8 outer; + }; + ++struct response_curve { ++ uint8_t move_pct_1; ++ uint8_t response_pct_1; ++ uint8_t move_pct_2; ++ uint8_t response_pct_2; ++ uint8_t move_pct_3; ++ uint8_t response_pct_3; ++ uint8_t move_pct_4; ++ uint8_t response_pct_4; ++} __packed; ++ + /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ + struct ally_gamepad_cfg { + struct hid_device *hdev; +@@ -289,6 +302,9 @@ struct ally_gamepad_cfg { + /* anti-deadzones */ + u8 ls_adz; // left stick + u8 rs_adz; // right stick ++ /* joystick response curves */ ++ struct response_curve ls_rc; ++ struct response_curve rs_rc; + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -712,10 +728,85 @@ static ssize_t axis_xy_right_anti_deadzone_store(struct device *dev, + } + ALLY_DEVICE_ATTR_RW(axis_xy_right_anti_deadzone, anti_deadzone); + ++/* JS RESPONSE CURVES *****************************************************************************/ ++static void _gamepad_set_js_response_curves_default(struct ally_gamepad_cfg *ally_cfg) ++{ ++ struct response_curve *js1_rc = &ally_cfg->ls_rc; ++ struct response_curve *js2_rc = &ally_cfg->rs_rc; ++ js1_rc->move_pct_1 = js2_rc->move_pct_1 = 0x16; // 25% ++ js1_rc->move_pct_2 = js2_rc->move_pct_2 = 0x32; // 50% ++ js1_rc->move_pct_3 = js2_rc->move_pct_3 = 0x48; // 75% ++ js1_rc->move_pct_4 = js2_rc->move_pct_4 = 0x64; // 100% ++ js1_rc->response_pct_1 = js2_rc->response_pct_1 = 0x16; ++ js1_rc->response_pct_2 = js2_rc->response_pct_2 = 0x32; ++ js1_rc->response_pct_3 = js2_rc->response_pct_3 = 0x48; ++ js1_rc->response_pct_4 = js2_rc->response_pct_4 = 0x64; ++} ++ ++static ssize_t _gamepad_apply_response_curves(struct hid_device *hdev, ++ struct ally_gamepad_cfg *ally_cfg) ++{ ++ u8 *hidbuf; ++ int 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; ++ memcpy(&hidbuf[2], &ally_cfg->ls_rc, sizeof(ally_cfg->ls_rc)); ++ ++ ret = ally_gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; ++ ++ hidbuf[4] = 0x02; ++ memcpy(&hidbuf[5], &ally_cfg->rs_rc, sizeof(ally_cfg->rs_rc)); ++ ++ ret = ally_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; ++} ++ ++ALLY_JS_RC_POINT(axis_xy_left, move, 1); ++ALLY_JS_RC_POINT(axis_xy_left, move, 2); ++ALLY_JS_RC_POINT(axis_xy_left, move, 3); ++ALLY_JS_RC_POINT(axis_xy_left, move, 4); ++ALLY_JS_RC_POINT(axis_xy_left, response, 1); ++ALLY_JS_RC_POINT(axis_xy_left, response, 2); ++ALLY_JS_RC_POINT(axis_xy_left, response, 3); ++ALLY_JS_RC_POINT(axis_xy_left, response, 4); ++ ++ALLY_JS_RC_POINT(axis_xy_right, move, 1); ++ALLY_JS_RC_POINT(axis_xy_right, move, 2); ++ALLY_JS_RC_POINT(axis_xy_right, move, 3); ++ALLY_JS_RC_POINT(axis_xy_right, move, 4); ++ALLY_JS_RC_POINT(axis_xy_right, response, 1); ++ALLY_JS_RC_POINT(axis_xy_right, response, 2); ++ALLY_JS_RC_POINT(axis_xy_right, response, 3); ++ALLY_JS_RC_POINT(axis_xy_right, response, 4); ++ + static struct attribute *axis_xy_left_attrs[] = { + &dev_attr_axis_xy_left_anti_deadzone.attr, + &dev_attr_axis_xy_left_deadzone.attr, + &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_axis_xy_left_move_1.attr, ++ &dev_attr_axis_xy_left_move_2.attr, ++ &dev_attr_axis_xy_left_move_3.attr, ++ &dev_attr_axis_xy_left_move_4.attr, ++ &dev_attr_axis_xy_left_response_1.attr, ++ &dev_attr_axis_xy_left_response_2.attr, ++ &dev_attr_axis_xy_left_response_3.attr, ++ &dev_attr_axis_xy_left_response_4.attr, + NULL + }; + static const struct attribute_group axis_xy_left_attr_group = { +@@ -727,6 +818,14 @@ static struct attribute *axis_xy_right_attrs[] = { + &dev_attr_axis_xy_right_anti_deadzone.attr, + &dev_attr_axis_xy_right_deadzone.attr, + &dev_attr_axis_xyz_deadzone_index.attr, ++ &dev_attr_axis_xy_right_move_1.attr, ++ &dev_attr_axis_xy_right_move_2.attr, ++ &dev_attr_axis_xy_right_move_3.attr, ++ &dev_attr_axis_xy_right_move_4.attr, ++ &dev_attr_axis_xy_right_response_1.attr, ++ &dev_attr_axis_xy_right_response_2.attr, ++ &dev_attr_axis_xy_right_response_3.attr, ++ &dev_attr_axis_xy_right_response_4.attr, + NULL + }; + static const struct attribute_group axis_xy_right_attr_group = { +@@ -922,6 +1021,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c + if (ret < 0) + return ret; + ret = _gamepad_apply_js_ADZ(hdev, ally_cfg); ++ if (ret < 0) ++ return ret; ++ ret =_gamepad_apply_response_curves(hdev, ally_cfg); + if (ret < 0) + return ret; + +@@ -1169,6 +1271,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->vibration_intensity[1] = 0x64; + _gamepad_set_deadzones_default(ally_cfg); + _gamepad_set_anti_deadzones_default(ally_cfg); ++ _gamepad_set_js_response_curves_default(ally_cfg); + + drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup + if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { +diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h +index 69f59592dd50..c83817589082 100644 +--- a/drivers/hid/hid-asus-ally.h ++++ b/drivers/hid/hid-asus-ally.h +@@ -28,6 +28,7 @@ enum xpad_cmd { + xpad_cmd_set_leds = 0x08, + xpad_cmd_check_ready = 0x0A, + xpad_cmd_set_turbo = 0x0F, ++ xpad_cmd_set_response_curve = 0x13, + xpad_cmd_set_adz = 0x18, + }; + +@@ -39,6 +40,7 @@ enum xpad_cmd_len { + xpad_cmd_len_vibe_intensity = 0x02, + xpad_cmd_len_leds = 0x0C, + xpad_cmd_len_turbo = 0x20, ++ xpad_cmd_len_response_curve = 0x09, + xpad_cmd_len_adz = 0x02, + }; + +@@ -309,6 +311,42 @@ enum btn_pair_index { + ALLY_DEADZONE_STORE(_fname##_deadzone, _mname); \ + ALLY_DEVICE_ATTR_RW(_fname##_deadzone, deadzone) + ++/* response curve macros */ ++#define ALLY_RESP_CURVE_SHOW(_fname, _mname) \ ++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, "%d\n", ally_cfg->ls_rc._mname); \ ++ } ++ ++#define ALLY_RESP_CURVE_STORE(_fname, _mname) \ ++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; \ ++ int ret, val; \ ++ if (!drvdata.gamepad_cfg) \ ++ return -ENODEV; \ ++ ret = kstrtoint(buf, 0, &val); \ ++ if (ret) \ ++ return ret; \ ++ if (val < 0 || val > 100) \ ++ return -EINVAL; \ ++ ally_cfg->ls_rc._mname = val; \ ++ return count; \ ++ } ++ ++/* _point_n must start at 1 */ ++#define ALLY_JS_RC_POINT(_fname, _mname, _num) \ ++ ALLY_RESP_CURVE_SHOW(_fname##_##_mname##_##_num, _mname##_pct_##_num); \ ++ ALLY_RESP_CURVE_STORE(_fname##_##_mname##_##_num, _mname##_pct_##_num); \ ++ ALLY_DEVICE_ATTR_RW(_fname##_##_mname##_##_num, curve_##_mname##_pct_##_num) ++ + #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ + static struct attribute *_fname##_attrs[] = { \ + &dev_attr_##_fname.attr, \ +-- +2.47.1 + + +From a46fa579d620183c76a594bf70df3864ee7c3f21 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Thu, 10 Oct 2024 11:15:36 +1300 +Subject: [PATCH 18/28] hid-asus-ally: add calibrations (wip) + +Signed-off-by: Luke D. Jones +--- + drivers/hid/hid-asus-ally.c | 95 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 95 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index aad965e069ee..a1015713c245 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -278,6 +278,28 @@ struct response_curve { + uint8_t response_pct_4; + } __packed; + ++struct js_axis_calibrations { ++ uint16_t left_y_stable; ++ uint16_t left_y_min; ++ uint16_t left_y_max; ++ uint16_t left_x_stable; ++ uint16_t left_x_min; ++ uint16_t left_x_max; ++ uint16_t right_y_stable; ++ uint16_t right_y_min; ++ uint16_t right_y_max; ++ uint16_t right_x_stable; ++ uint16_t right_x_min; ++ uint16_t right_x_max; ++} __packed; ++ ++struct tr_axis_calibrations { ++ uint16_t left_stable; ++ uint16_t left_max; ++ uint16_t right_stable; ++ uint16_t right_max; ++} __packed; ++ + /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ + struct ally_gamepad_cfg { + struct hid_device *hdev; +@@ -305,6 +327,9 @@ struct ally_gamepad_cfg { + /* joystick response curves */ + struct response_curve ls_rc; + struct response_curve rs_rc; ++ ++ struct js_axis_calibrations js_cal; ++ struct tr_axis_calibrations tr_cal; + }; + + /* The hatswitch outputs integers, we use them to index this X|Y pair */ +@@ -382,6 +407,18 @@ static struct ally_drvdata { + struct ally_rgb_data led_rgb_data; + } drvdata; + ++static void reverse_bytes_in_pairs(u8 *buf, size_t size) { ++ uint16_t *word_ptr; ++ size_t i; ++ ++ for (i = 0; i < size; i += 2) { ++ if (i + 1 < size) { ++ word_ptr = (uint16_t *)&buf[i]; ++ *word_ptr = cpu_to_be16(*word_ptr); ++ } ++ } ++} ++ + /** + * asus_dev_set_report - send set report request to device. + * +@@ -795,6 +832,63 @@ ALLY_JS_RC_POINT(axis_xy_right, response, 2); + ALLY_JS_RC_POINT(axis_xy_right, response, 3); + ALLY_JS_RC_POINT(axis_xy_right, response, 4); + ++/* 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 */ ++ reverse_bytes_in_pairs(&hidbuf[6], sizeof(struct js_axis_calibrations)); ++ ally_cfg->js_cal = *(struct js_axis_calibrations *)&hidbuf[6]; ++ print_hex_dump(KERN_INFO, "HID Buffer JS: ", DUMP_PREFIX_OFFSET, 16, 1, hidbuf, 32, true); ++ struct js_axis_calibrations *cal = &drvdata.gamepad_cfg->js_cal; ++ pr_err("LS_CAL: X: %d, Min: %d, Max: %d", cal->left_x_stable, cal->left_x_min, cal->left_x_max); ++ pr_err("LS_CAL: Y: %d, Min: %d, Max: %d", cal->left_y_stable, cal->left_y_min, cal->left_y_max); ++ pr_err("RS_CAL: X: %d, Min: %d, Max: %d", cal->right_x_stable, cal->right_x_min, cal->right_x_max); ++ pr_err("RS_CAL: Y: %d, Min: %d, Max: %d", cal->right_y_stable, cal->right_y_min, cal->right_y_max); ++ } else { ++ /* Trigger calibration */ ++ reverse_bytes_in_pairs(&hidbuf[6], sizeof(struct tr_axis_calibrations)); ++ ally_cfg->tr_cal = *(struct tr_axis_calibrations *)&hidbuf[6]; ++ print_hex_dump(KERN_INFO, "HID Buffer TR: ", DUMP_PREFIX_OFFSET, 16, 1, hidbuf, 32, true); ++ } ++ } ++ ++cleanup: ++ kfree(hidbuf); ++ return ret; ++} ++ + static struct attribute *axis_xy_left_attrs[] = { + &dev_attr_axis_xy_left_anti_deadzone.attr, + &dev_attr_axis_xy_left_deadzone.attr, +@@ -1266,6 +1360,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) + ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m1.button = BTN_KB_M1; + ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; + _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); ++ gamepad_get_calibration(hdev); + + ally_cfg->vibration_intensity[0] = 0x64; + ally_cfg->vibration_intensity[1] = 0x64; +-- +2.47.1 + + +From ce9ddc7e913a1d52fa4fb4b6e1330e2746b0a8e9 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Wed, 6 Nov 2024 00:27:03 +0300 +Subject: [PATCH 19/28] debug by default + +--- + drivers/hid/hid-asus-ally.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c +index a1015713c245..c10121ebcbb8 100644 +--- a/drivers/hid/hid-asus-ally.c ++++ b/drivers/hid/hid-asus-ally.c +@@ -21,6 +21,8 @@ + #include "hid-ids.h" + #include "hid-asus-ally.h" + ++#define DEBUG ++ + #define READY_MAX_TRIES 3 + #define FEATURE_REPORT_ID 0x0d + #define FEATURE_ROG_ALLY_REPORT_ID 0x5a +-- +2.47.1 + + +From c80e393a6ffe8c8085107bbe9b2fcb0a9eff199a Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 22 Sep 2024 21:39:43 +1200 -Subject: [PATCH 06/29] platform/x86: asus-armoury: move existing tunings to +Subject: [PATCH 20/28] platform/x86: asus-armoury: move existing tunings to asus-armoury module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -405,11 +4660,11 @@ Signed-off-by: Luke D. Jones --- drivers/platform/x86/Kconfig | 12 + drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/asus-armoury.c | 573 +++++++++++++++++++++ + drivers/platform/x86/asus-armoury.c | 553 +++++++++++++++++++++ drivers/platform/x86/asus-armoury.h | 147 ++++++ drivers/platform/x86/asus-wmi.c | 4 - include/linux/platform_data/x86/asus-wmi.h | 3 + - 6 files changed, 736 insertions(+), 4 deletions(-) + 6 files changed, 716 insertions(+), 4 deletions(-) create mode 100644 drivers/platform/x86/asus-armoury.c create mode 100644 drivers/platform/x86/asus-armoury.h @@ -450,10 +4705,10 @@ index e1b142947067..fe3e7e7dede8 100644 obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c new file mode 100644 -index 000000000000..e6b64418f77b +index 000000000000..d2e8c21d62dc --- /dev/null +++ b/drivers/platform/x86/asus-armoury.c -@@ -0,0 +1,573 @@ +@@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes @@ -496,20 +4751,6 @@ index 000000000000..e6b64418f77b +#define ASUS_MINI_LED_2024_STRONG 0x01 +#define ASUS_MINI_LED_2024_OFF 0x02 + -+/* Default limits for tunables available on ASUS ROG laptops */ -+#define NVIDIA_BOOST_MIN 5 -+#define NVIDIA_BOOST_MAX 25 -+#define NVIDIA_TEMP_MIN 75 -+#define NVIDIA_TEMP_MAX 87 -+#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 -+ -+static const struct class *fw_attr_class; -+ +struct asus_armoury_priv { + struct device *fw_attr_dev; + struct kset *fw_attr_kset; @@ -894,11 +5135,7 @@ index 000000000000..e6b64418f77b +{ + int err, i; + -+ err = fw_attributes_class_get(&fw_attr_class); -+ if (err) -+ return err; -+ -+ asus_armoury.fw_attr_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0), ++ asus_armoury.fw_attr_dev = device_create(&firmware_attributes_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); @@ -976,9 +5213,8 @@ index 000000000000..e6b64418f77b +err_destroy_kset: + kset_unregister(asus_armoury.fw_attr_kset); +err_destroy_classdev: -+ device_destroy(fw_attr_class, MKDEV(0, 0)); +fail_class_get: -+ fw_attributes_class_put(); ++ device_destroy(&firmware_attributes_class, MKDEV(0, 0)); + return err; +} + @@ -1013,8 +5249,7 @@ index 000000000000..e6b64418f77b + + 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(); ++ device_destroy(&firmware_attributes_class, MKDEV(0, 0)); + + mutex_unlock(&asus_armoury.mutex); +} @@ -1029,7 +5264,7 @@ index 000000000000..e6b64418f77b +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..b00d829c9da0 +index 000000000000..440f41c5df3b --- /dev/null +++ b/drivers/platform/x86/asus-armoury.h @@ -0,0 +1,147 @@ @@ -1179,9 +5414,9 @@ index 000000000000..b00d829c9da0 + .name = _fsname, .attrs = _attrname##_attrs \ + } + -+#endif /* _ASUS_BIOSCFG_H_ */ ++#endif /* _ASUS_ARMOURY_H_ */ diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index 93bbc2421366..ff8f0f47696c 100644 +index c02d9fa89799..b91cb5538b2d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -55,8 +55,6 @@ module_param(fnlock_default, bool, 0444); @@ -1203,12 +5438,12 @@ index 93bbc2421366..ff8f0f47696c 100644 #define FAN_CURVE_POINTS 8 diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 6ea4dedfb85e..21313e1eb6c9 100644 +index 4e6de0c97a78..ff0e762b83a4 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -6,6 +6,9 @@ - #include - #include +@@ -144,6 +144,9 @@ struct asus_wmi { + struct asus_wmi_driver *driver; + }; +#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" +#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI" @@ -1220,10 +5455,10 @@ index 6ea4dedfb85e..21313e1eb6c9 100644 2.47.1 -From a987017d8c7e5445f521ea683f1686bf80ce5f26 Mon Sep 17 00:00:00 2001 +From 291c0678506e20bdeef67949b18a24c820c13697 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 19 Sep 2024 17:23:35 +1200 -Subject: [PATCH 07/29] platform/x86: asus-armoury: add panel_hd_mode attribute +Subject: [PATCH 21/28] platform/x86: asus-armoury: add panel_hd_mode attribute Add panel_hd_mode to toggle the panel mode between single and high definition modes. @@ -1236,10 +5471,10 @@ Reviewed-by: Mario Limonciello 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index e6b64418f77b..b8b9440e0c31 100644 +index d2e8c21d62dc..716bf96b6b58 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c -@@ -107,7 +107,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); +@@ -93,7 +93,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); static bool asus_bios_requires_reboot(struct kobj_attribute *attr) { @@ -1249,7 +5484,7 @@ index e6b64418f77b..b8b9440e0c31 100644 } static int armoury_wmi_set_devstate(struct kobj_attribute *attr, u32 value, u32 wmi_dev) -@@ -419,6 +420,8 @@ ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, +@@ -405,6 +406,8 @@ 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"); @@ -1258,7 +5493,7 @@ index e6b64418f77b..b8b9440e0c31 100644 ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, "Show the eGPU connection status"); -@@ -432,6 +435,7 @@ static const struct asus_attr_group armoury_attr_groups[] = { +@@ -418,6 +421,7 @@ static const struct asus_attr_group armoury_attr_groups[] = { { &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 }, @@ -1267,10 +5502,10 @@ index e6b64418f77b..b8b9440e0c31 100644 static int asus_fw_attr_add(void) diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 21313e1eb6c9..a6064995c2cc 100644 +index ff0e762b83a4..28d9ec1326ab 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -76,6 +76,7 @@ +@@ -214,6 +214,7 @@ struct asus_wmi { #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019 /* Misc */ @@ -1282,420 +5517,10 @@ index 21313e1eb6c9..a6064995c2cc 100644 2.47.1 -From abd20481883aba301d432eb3f9431c61aefec535 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Thu, 19 Sep 2024 17:19:37 +1200 -Subject: [PATCH 08/29] platform/x86: asus-armoury: add the ppt_* and nv_* - tuning knobs - -Adds the ppt_* and nv_* tuning knobs that are available via WMI methods -and adds proper min/max levels plus defaults. - -Signed-off-by: Luke D. Jones -Reviewed-by: Mario Limonciello ---- - drivers/platform/x86/asus-armoury.c | 134 ++++++++++++++++++++++++++++ - drivers/platform/x86/asus-armoury.h | 65 ++++++++++++++ - 2 files changed, 199 insertions(+) - -diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index b8b9440e0c31..9e9c57cc742f 100644 ---- a/drivers/platform/x86/asus-armoury.c -+++ b/drivers/platform/x86/asus-armoury.c -@@ -52,12 +52,40 @@ - #define PPT_PLATFORM_MAX 100 - #define PPT_PLATFORM_DEFAULT 80 - -+/* 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_pl3_fppt; // cpu -+ u32 ppt_apu_sppt; // plat -+ u32 ppt_platform_sppt; // plat -+ -+ 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; -+}; -+ - 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; - -@@ -411,6 +439,25 @@ 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)"); - - /* 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_pl3_fppt, "ppt_pl3_fppt", ASUS_WMI_DEVID_PPT_FPPT, cpu_default, cpu_min, -+ cpu_max, 1, "Set the CPU slow 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(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_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", - "Show the current mode of charging"); - -@@ -431,6 +478,14 @@ static const struct asus_attr_group armoury_attr_groups[] = { - { &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_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT }, -+ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, -+ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, -+ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, -+ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, -+ - { &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 }, -@@ -532,6 +587,79 @@ static int asus_fw_attr_add(void) - - /* Init / exit ****************************************************************/ - -+/* Set up the min/max and defaults for ROG tunables */ -+static void init_rog_tunables(struct rog_tunables *rog) -+{ -+ u32 platform_default = PPT_PLATFORM_DEFAULT; -+ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT; -+ u32 platform_max = PPT_PLATFORM_MAX; -+ u32 max_boost = NVIDIA_BOOST_MAX; -+ u32 cpu_max = PPT_CPU_LIMIT_MAX; -+ const char *product; -+ -+ /* -+ * ASUS product_name contains everything required, e.g, -+ * "ROG Flow X16 GV601VV_GV601VV_00185149B". -+ * The bulk of these defaults are gained from users reporting what -+ * ASUS Armoury Crate in Windows provides them. -+ * This should be turned in to a table eventually. -+ */ -+ 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") || strstr(product, "RC72")) { -+ 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; -+ } else { -+ pr_notice("Using default CPU limits. Please report if these are not correct.\n"); -+ } -+ -+ 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_pl3_fppt = cpu_default; -+ rog->ppt_apu_sppt = cpu_default; -+ rog->ppt_platform_sppt = platform_default; -+ -+ rog->nv_boost_default = NVIDIA_BOOST_MAX; -+ rog->nv_boost_min = 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_min = NVIDIA_TEMP_MIN; -+ rog->nv_temp_max = NVIDIA_TEMP_MAX; -+ rog->nv_temp_target = NVIDIA_TEMP_MIN; -+} -+ - static int __init asus_fw_init(void) - { - char *wmi_uid; -@@ -548,6 +676,12 @@ static int __init asus_fw_init(void) - if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) - return -ENODEV; - -+ asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL); -+ if (!asus_armoury.rog_tunables) -+ return -ENOMEM; -+ -+ init_rog_tunables(asus_armoury.rog_tunables); -+ - err = asus_fw_attr_add(); - if (err) - return err; -diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h -index b00d829c9da0..91ec6f4cb149 100644 ---- a/drivers/platform/x86/asus-armoury.h -+++ b/drivers/platform/x86/asus-armoury.h -@@ -17,6 +17,12 @@ static ssize_t attr_uint_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) - { -@@ -144,4 +150,63 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, - .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_uint_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_ */ --- -2.47.1 - - -From 961fd02b999977441e0f621b335a42048665949f Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sun, 2 Jun 2024 14:32:15 +1200 -Subject: [PATCH 09/29] platform/x86: asus-armoury: add dgpu tgp control - -Implement the dgpu TGP control under the asus-armoury module using the -fw_attributes class. - -Reviewed-by: Mario Limonciello -Signed-off-by: Luke D. Jones ---- - drivers/platform/x86/asus-armoury.c | 21 +++++++++++++++++++++ - drivers/platform/x86/asus-armoury.h | 18 ++++++++++++++++++ - include/linux/platform_data/x86/asus-wmi.h | 3 +++ - 3 files changed, 42 insertions(+) - -diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index 9e9c57cc742f..5d7e4643813e 100644 ---- a/drivers/platform/x86/asus-armoury.c -+++ b/drivers/platform/x86/asus-armoury.c -@@ -45,6 +45,9 @@ - #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 - #define PPT_CPU_LIMIT_MIN 5 - #define PPT_CPU_LIMIT_MAX 150 - #define PPT_CPU_LIMIT_DEFAULT 80 -@@ -77,6 +80,11 @@ struct rog_tunables { - 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; - }; - - static const struct class *fw_attr_class; -@@ -457,6 +465,12 @@ ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_D - 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_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_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP, -+ "Read the base TGP value"); - - ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", - "Show the current mode of charging"); -@@ -485,6 +499,8 @@ static const struct asus_attr_group armoury_attr_groups[] = { - { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, - { &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 }, - - { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, - { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, -@@ -658,6 +674,11 @@ static void init_rog_tunables(struct rog_tunables *rog) - rog->nv_temp_min = 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) -diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h -index 91ec6f4cb149..9639e7ca772f 100644 ---- a/drivers/platform/x86/asus-armoury.h -+++ b/drivers/platform/x86/asus-armoury.h -@@ -90,6 +90,20 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, - static struct kobj_attribute attr_##_attrname##_##_prop = \ - __ASUS_ATTR_RO(_attrname, _prop) - -+/* Requires current_value_show */ -+#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); \ -@@ -107,6 +121,10 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, - .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) -diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index a6064995c2cc..8c755799eb60 100644 ---- a/include/linux/platform_data/x86/asus-wmi.h -+++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -137,6 +137,9 @@ - /* dgpu on/off */ - #define ASUS_WMI_DEVID_DGPU 0x00090020 - -+#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 -+#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 -+ - /* gpu mux switch, 0 = dGPU, 1 = Optimus */ - #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 - #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026 --- -2.47.1 - - -From 6e39a84d8a15975a08a4d91cc0561079c7b86c3d Mon Sep 17 00:00:00 2001 +From 6db68b4041e9a6b74d071f9f5088148916964fcc Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 2 Jun 2024 14:44:31 +1200 -Subject: [PATCH 10/29] platform/x86: asus-armoury: add apu-mem control support +Subject: [PATCH 22/28] platform/x86: asus-armoury: add apu-mem control support Implement the APU memory size control under the asus-armoury module using the fw_attributes class. @@ -1707,14 +5532,14 @@ Signed-off-by: Luke D. Jones Reviewed-by: Mario Limonciello --- drivers/platform/x86/asus-armoury.c | 114 +++++++++++++++++++++ - include/linux/platform_data/x86/asus-wmi.h | 1 + - 2 files changed, 115 insertions(+) + include/linux/platform_data/x86/asus-wmi.h | 2 + + 2 files changed, 116 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index 5d7e4643813e..386f4236f5f8 100644 +index 716bf96b6b58..298f7b203d7c 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c -@@ -446,6 +446,119 @@ static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj +@@ -396,6 +396,119 @@ static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj 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)"); @@ -1832,36 +5657,37 @@ index 5d7e4643813e..386f4236f5f8 100644 +ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); + /* 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"); -@@ -501,6 +614,7 @@ static const struct asus_attr_group armoury_attr_groups[] = { - { &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 }, + ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", + "Show the current mode of charging"); +@@ -416,6 +529,7 @@ 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 }, + { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 8c755799eb60..88bf250dc8ca 100644 +index 28d9ec1326ab..ba397d7d0825 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -139,6 +139,7 @@ +@@ -275,6 +275,8 @@ struct asus_wmi { + /* dgpu on/off */ + #define ASUS_WMI_DEVID_DGPU 0x00090020 - #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 - #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 +#define ASUS_WMI_DEVID_APU_MEM 0x000600C1 - ++ /* gpu mux switch, 0 = dGPU, 1 = Optimus */ #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 + #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026 -- 2.47.1 -From fd1f1c947e97fe066986d82aea4986990764ccc8 Mon Sep 17 00:00:00 2001 +From c9c56bcc8fca365ed6a80f1012dbd29d8c3070f6 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 18 Sep 2024 21:19:12 +1200 -Subject: [PATCH 11/29] platform/x86: asus-armoury: add core count control +Subject: [PATCH 23/28] platform/x86: asus-armoury: add core count control Implement Intel core enablement under the asus-armoury module using the fw_attributes class. @@ -1872,16 +5698,16 @@ depending on their requirements. After change a reboot is required. Signed-off-by: Luke D. Jones Reviewed-by: Mario Limonciello --- - drivers/platform/x86/asus-armoury.c | 226 +++++++++++++++++++++ - drivers/platform/x86/asus-armoury.h | 28 +++ - include/linux/platform_data/x86/asus-wmi.h | 4 + - 3 files changed, 258 insertions(+) + drivers/platform/x86/asus-armoury.c | 236 +++++++++++++++++++++ + drivers/platform/x86/asus-armoury.h | 34 +++ + include/linux/platform_data/x86/asus-wmi.h | 5 + + 3 files changed, 275 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index 386f4236f5f8..f09811d76b45 100644 +index 298f7b203d7c..49e1788d8bba 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c -@@ -40,6 +40,24 @@ +@@ -40,10 +40,39 @@ #define ASUS_MINI_LED_2024_STRONG 0x01 #define ASUS_MINI_LED_2024_OFF 0x02 @@ -1903,24 +5729,25 @@ index 386f4236f5f8..f09811d76b45 100644 +#define CPU_PERF_CORE_COUNT_MIN 4 +#define CPU_POWR_CORE_COUNT_MIN 0 + - /* Default limits for tunables available on ASUS ROG laptops */ - #define NVIDIA_BOOST_MIN 5 - #define NVIDIA_BOOST_MAX 25 -@@ -85,6 +103,13 @@ struct rog_tunables { - u32 dgpu_tgp_min; - u32 dgpu_tgp_max; - u32 dgpu_tgp; -+ ++/* Tunables provided by ASUS for gaming laptops */ ++struct cpu_cores { + u32 cur_perf_cores; + u32 min_perf_cores; + u32 max_perf_cores; + u32 cur_power_cores; + u32 min_power_cores; + u32 max_power_cores; - }; ++}; ++ + struct asus_armoury_priv { + struct device *fw_attr_dev; + struct kset *fw_attr_kset; - static const struct class *fw_attr_class; -@@ -144,6 +169,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); ++ struct cpu_cores *cpu_cores; + u32 mini_led_dev_id; + u32 gpu_mux_dev_id; + +@@ -94,6 +123,8 @@ 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") || @@ -1929,7 +5756,7 @@ index 386f4236f5f8..f09811d76b45 100644 !strcmp(attr->attr.name, "panel_hd_mode"); } -@@ -559,6 +586,195 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at +@@ -509,6 +540,195 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at } ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); @@ -1943,8 +5770,8 @@ index 386f4236f5f8..f09811d76b45 100644 + return err; + + cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores); -+ asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores); ++ asus_armoury.cpu_cores->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores); ++ asus_armoury.cpu_cores->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores); + + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores); + if (err) { @@ -1952,11 +5779,11 @@ index 386f4236f5f8..f09811d76b45 100644 + return err; + } + -+ asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores); -+ asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores); ++ asus_armoury.cpu_cores->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores); ++ asus_armoury.cpu_cores->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores); + -+ asus_armoury.rog_tunables->min_perf_cores = CPU_PERF_CORE_COUNT_MIN; -+ asus_armoury.rog_tunables->min_power_cores = CPU_POWR_CORE_COUNT_MIN; ++ asus_armoury.cpu_cores->min_perf_cores = CPU_PERF_CORE_COUNT_MIN; ++ asus_armoury.cpu_cores->min_power_cores = CPU_POWR_CORE_COUNT_MIN; + + return 0; +} @@ -1971,25 +5798,25 @@ index 386f4236f5f8..f09811d76b45 100644 + case CPU_CORE_MAX: + if (core_type == CPU_CORE_PERF) + return sysfs_emit(buf, "%d\n", -+ asus_armoury.rog_tunables->max_perf_cores); ++ asus_armoury.cpu_cores->max_perf_cores); + else + return sysfs_emit(buf, "%d\n", -+ asus_armoury.rog_tunables->max_power_cores); ++ asus_armoury.cpu_cores->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); ++ asus_armoury.cpu_cores->min_perf_cores); + else + return sysfs_emit(buf, "%d\n", -+ asus_armoury.rog_tunables->min_power_cores); ++ asus_armoury.cpu_cores->min_power_cores); + default: + break; + } + + if (core_type == CPU_CORE_PERF) -+ cores = asus_armoury.rog_tunables->cur_perf_cores; ++ cores = asus_armoury.cpu_cores->cur_perf_cores; + else -+ cores = asus_armoury.rog_tunables->cur_power_cores; ++ cores = asus_armoury.cpu_cores->cur_power_cores; + + return sysfs_emit(buf, "%d\n", cores); +} @@ -2006,14 +5833,14 @@ index 386f4236f5f8..f09811d76b45 100644 + + if (core_type == CPU_CORE_PERF) { + perf_cores = new_cores; -+ power_cores = out_val = asus_armoury.rog_tunables->cur_power_cores; -+ min = asus_armoury.rog_tunables->min_perf_cores; -+ max = asus_armoury.rog_tunables->max_perf_cores; ++ power_cores = out_val = asus_armoury.cpu_cores->cur_power_cores; ++ min = asus_armoury.cpu_cores->min_perf_cores; ++ max = asus_armoury.cpu_cores->max_perf_cores; + } else { -+ perf_cores = asus_armoury.rog_tunables->cur_perf_cores; ++ perf_cores = asus_armoury.cpu_cores->cur_perf_cores; + power_cores = out_val = new_cores; -+ min = asus_armoury.rog_tunables->min_power_cores; -+ max = asus_armoury.rog_tunables->max_power_cores; ++ min = asus_armoury.cpu_cores->min_power_cores; ++ max = asus_armoury.cpu_cores->max_power_cores; + } + + if (new_cores < min || new_cores > max) @@ -2123,37 +5950,56 @@ index 386f4236f5f8..f09811d76b45 100644 + "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"); -@@ -615,6 +831,8 @@ static const struct asus_attr_group armoury_attr_groups[] = { - { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, - { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, + ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", + "Show the current mode of charging"); +@@ -530,6 +750,8 @@ static const struct asus_attr_group armoury_attr_groups[] = { + { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, + { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, { &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 }, -@@ -816,6 +1034,14 @@ static int __init asus_fw_init(void) - return -ENOMEM; +@@ -643,6 +865,20 @@ static int __init asus_fw_init(void) + if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) + return -ENODEV; - init_rog_tunables(asus_armoury.rog_tunables); ++ + if (asus_wmi_is_present(ASUS_WMI_DEVID_CORES_MAX)) { ++ asus_armoury.cpu_cores = kzalloc(sizeof(struct cpu_cores), GFP_KERNEL); ++ if (!asus_armoury.cpu_cores) ++ return -ENOMEM; ++ + err = init_max_cpu_cores(); + if (err) { -+ kfree(asus_armoury.rog_tunables); ++ kfree(asus_armoury.cpu_cores); + pr_err("Could not initialise CPU core control %d\n", err); + return err; + } + } - ++ err = asus_fw_attr_add(); if (err) + return err; diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h -index 9639e7ca772f..2620708d3994 100644 +index 440f41c5df3b..5d6bef6d2b12 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h -@@ -168,6 +168,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, +@@ -23,6 +23,12 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, + return sysfs_emit(buf, "enumeration\n"); + } + ++static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "integer\n"); ++} ++ + #define __ASUS_ATTR_RO(_func, _name) \ + { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ +@@ -144,4 +150,32 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, .name = _fsname, .attrs = _attrname##_attrs \ } @@ -2185,14 +6031,12 @@ index 9639e7ca772f..2620708d3994 100644 + .name = _fsname, .attrs = _attrname##_attrs \ + } + - /* - * ROG PPT attributes need a little different in setup as they - * require rog_tunables members. + #endif /* _ASUS_ARMOURY_H_ */ diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 88bf250dc8ca..cc21e4272460 100644 +index ba397d7d0825..5af4430c863f 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -137,6 +137,10 @@ +@@ -275,6 +275,11 @@ struct asus_wmi { /* dgpu on/off */ #define ASUS_WMI_DEVID_DGPU 0x00090020 @@ -2200,17 +6044,18 @@ index 88bf250dc8ca..cc21e4272460 100644 +#define ASUS_WMI_DEVID_CORES 0x001200D2 + /* Maximum Intel E-core and P-core availability */ +#define ASUS_WMI_DEVID_CORES_MAX 0x001200D3 - #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 - #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 ++ #define ASUS_WMI_DEVID_APU_MEM 0x000600C1 + + /* gpu mux switch, 0 = dGPU, 1 = Optimus */ -- 2.47.1 -From 95ee3427398d33b92d44e36c7986e4155fa93095 Mon Sep 17 00:00:00 2001 +From 4be3d720922e9488adf138754fb9c9ba47247448 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Mon, 3 Jun 2024 12:04:41 +1200 -Subject: [PATCH 12/29] platform/x86: asus-wmi: deprecate bios features +Subject: [PATCH 24/28] platform/x86: asus-wmi: deprecate bios features With the existence of the asus-armoury module the attributes no-longer need to live under the /sys/devices/platform/asus-nb-wmi/ path. @@ -2223,8 +6068,9 @@ Reviewed-by: Mario Limonciello --- .../ABI/testing/sysfs-platform-asus-wmi | 17 +++ drivers/platform/x86/Kconfig | 9 ++ - drivers/platform/x86/asus-wmi.c | 134 ++++++++++++++---- - 3 files changed, 130 insertions(+), 30 deletions(-) + drivers/platform/x86/asus-wmi.c | 123 ++++++++++++++---- + include/linux/platform_data/x86/asus-wmi.h | 17 ++- + 4 files changed, 134 insertions(+), 32 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi index 28144371a0f1..765d50b0d9df 100644 @@ -2387,47 +6233,12 @@ index 294364cc7478..b160173a530e 100644 tristate "Asus Notebook WMI Driver" depends on ASUS_WMI diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index ff8f0f47696c..6bd89cd0acdf 100644 +index b91cb5538b2d..7e9878851f40 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c -@@ -286,11 +286,12 @@ struct asus_wmi { - u8 fan_boost_mode_mask; - u8 fan_boost_mode; - -+ -+ /* Tunables provided by ASUS for gaming laptops */ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) - bool egpu_enable_available; - 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; -@@ -298,6 +299,9 @@ struct asus_wmi { - u32 ppt_fppt; - u32 nv_dynamic_boost; - u32 nv_temp_target; -+ bool panel_overdrive_available; -+ u32 mini_led_dev_id; -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ - - u32 kbd_rgb_dev; - bool kbd_rgb_state_available; -@@ -316,9 +320,6 @@ struct asus_wmi { - // The RSOC controls the maximum charging percentage. - bool battery_rsoc_available; - -- bool panel_overdrive_available; -- u32 mini_led_dev_id; -- - struct hotplug_slot hotplug_slot; - struct mutex hotplug_lock; - struct mutex wmi_lock; -@@ -334,6 +335,15 @@ struct asus_wmi { - - static bool ally_mcu_usb_plug; +@@ -194,6 +194,15 @@ struct agfn_fan_args { + u32 speed; /* read: RPM/100 - write: 0-255 */ + } __packed; +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) +static void asus_wmi_show_deprecated(void) @@ -2441,7 +6252,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 /* WMI ************************************************************************/ static int asus_wmi_evaluate_method3(u32 method_id, -@@ -724,6 +734,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) +@@ -584,6 +593,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) } /* Charging mode, 1=Barrel, 2=USB ******************************************/ @@ -2449,7 +6260,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t charge_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -734,12 +745,16 @@ static ssize_t charge_mode_show(struct device *dev, +@@ -594,12 +604,16 @@ static ssize_t charge_mode_show(struct device *dev, if (result < 0) return result; @@ -2466,7 +6277,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t dgpu_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -750,6 +765,8 @@ static ssize_t dgpu_disable_show(struct device *dev, +@@ -610,6 +624,8 @@ static ssize_t dgpu_disable_show(struct device *dev, if (result < 0) return result; @@ -2475,7 +6286,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -803,8 +820,10 @@ static ssize_t dgpu_disable_store(struct device *dev, +@@ -663,8 +679,10 @@ static ssize_t dgpu_disable_store(struct device *dev, return count; } static DEVICE_ATTR_RW(dgpu_disable); @@ -2486,7 +6297,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t egpu_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -815,6 +834,8 @@ static ssize_t egpu_enable_show(struct device *dev, +@@ -675,6 +693,8 @@ static ssize_t egpu_enable_show(struct device *dev, if (result < 0) return result; @@ -2495,7 +6306,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -871,8 +892,10 @@ static ssize_t egpu_enable_store(struct device *dev, +@@ -731,8 +751,10 @@ static ssize_t egpu_enable_store(struct device *dev, return count; } static DEVICE_ATTR_RW(egpu_enable); @@ -2506,7 +6317,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t egpu_connected_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -883,12 +906,16 @@ static ssize_t egpu_connected_show(struct device *dev, +@@ -743,12 +765,16 @@ static ssize_t egpu_connected_show(struct device *dev, if (result < 0) return result; @@ -2523,7 +6334,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t gpu_mux_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -899,6 +926,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev, +@@ -759,6 +785,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev, if (result < 0) return result; @@ -2532,7 +6343,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -957,6 +986,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev, +@@ -817,6 +845,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev, return count; } static DEVICE_ATTR_RW(gpu_mux_mode); @@ -2540,7 +6351,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 /* TUF Laptop Keyboard RGB Modes **********************************************/ static ssize_t kbd_rgb_mode_store(struct device *dev, -@@ -1080,6 +1110,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = { +@@ -940,6 +969,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = { }; /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ @@ -2548,7 +6359,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t ppt_pl2_sppt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -@@ -1118,6 +1149,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev, +@@ -978,6 +1008,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2557,7 +6368,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); } static DEVICE_ATTR_RW(ppt_pl2_sppt); -@@ -1160,6 +1193,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev, +@@ -1020,6 +1052,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2566,7 +6377,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); } static DEVICE_ATTR_RW(ppt_pl1_spl); -@@ -1203,6 +1238,8 @@ static ssize_t ppt_fppt_show(struct device *dev, +@@ -1063,6 +1097,8 @@ static ssize_t ppt_fppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2575,7 +6386,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->ppt_fppt); } static DEVICE_ATTR_RW(ppt_fppt); -@@ -1246,6 +1283,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev, +@@ -1106,6 +1142,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2584,7 +6395,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); } static DEVICE_ATTR_RW(ppt_apu_sppt); -@@ -1289,6 +1328,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev, +@@ -1149,6 +1187,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2593,7 +6404,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); } static DEVICE_ATTR_RW(ppt_platform_sppt); -@@ -1332,6 +1373,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev, +@@ -1192,6 +1232,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2602,7 +6413,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); } static DEVICE_ATTR_RW(nv_dynamic_boost); -@@ -1375,11 +1418,15 @@ static ssize_t nv_temp_target_show(struct device *dev, +@@ -1235,11 +1277,15 @@ static ssize_t nv_temp_target_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); @@ -2618,7 +6429,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t mcu_powersave_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -1390,6 +1437,8 @@ static ssize_t mcu_powersave_show(struct device *dev, +@@ -1250,6 +1296,8 @@ static ssize_t mcu_powersave_show(struct device *dev, if (result < 0) return result; @@ -2627,7 +6438,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -1425,6 +1474,7 @@ static ssize_t mcu_powersave_store(struct device *dev, +@@ -1285,6 +1333,7 @@ static ssize_t mcu_powersave_store(struct device *dev, return count; } static DEVICE_ATTR_RW(mcu_powersave); @@ -2635,7 +6446,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 /* Battery ********************************************************************/ -@@ -2298,6 +2348,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) +@@ -2158,6 +2207,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) } /* Panel Overdrive ************************************************************/ @@ -2643,7 +6454,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t panel_od_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -2308,6 +2359,8 @@ static ssize_t panel_od_show(struct device *dev, +@@ -2168,6 +2218,8 @@ static ssize_t panel_od_show(struct device *dev, if (result < 0) return result; @@ -2652,7 +6463,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -2344,9 +2397,10 @@ static ssize_t panel_od_store(struct device *dev, +@@ -2204,9 +2256,10 @@ static ssize_t panel_od_store(struct device *dev, return count; } static DEVICE_ATTR_RW(panel_od); @@ -2664,7 +6475,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t boot_sound_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -2357,6 +2411,8 @@ static ssize_t boot_sound_show(struct device *dev, +@@ -2217,6 +2270,8 @@ static ssize_t boot_sound_show(struct device *dev, if (result < 0) return result; @@ -2673,7 +6484,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", result); } -@@ -2392,8 +2448,10 @@ static ssize_t boot_sound_store(struct device *dev, +@@ -2252,8 +2307,10 @@ static ssize_t boot_sound_store(struct device *dev, return count; } static DEVICE_ATTR_RW(boot_sound); @@ -2684,7 +6495,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t mini_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -2424,6 +2482,8 @@ static ssize_t mini_led_mode_show(struct device *dev, +@@ -2284,6 +2341,8 @@ static ssize_t mini_led_mode_show(struct device *dev, } } @@ -2693,7 +6504,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 return sysfs_emit(buf, "%d\n", value); } -@@ -2494,10 +2554,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev, +@@ -2354,10 +2413,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev, return sysfs_emit(buf, "0 1 2\n"); } @@ -2707,7 +6518,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 /* Quirks *********************************************************************/ -@@ -3785,6 +3848,7 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus) +@@ -3645,6 +3707,7 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus) return throttle_thermal_policy_write(asus); } @@ -2715,7 +6526,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 static ssize_t throttle_thermal_policy_show(struct device *dev, struct device_attribute *attr, char *buf) { -@@ -3828,6 +3892,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, +@@ -3688,6 +3751,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent */ static DEVICE_ATTR_RW(throttle_thermal_policy); @@ -2723,7 +6534,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 /* Platform profile ***********************************************************/ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, -@@ -4425,27 +4490,29 @@ static struct attribute *platform_attributes[] = { +@@ -4285,27 +4349,29 @@ static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_touchpad.attr, @@ -2771,7 +6582,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 NULL }; -@@ -4467,7 +4534,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, +@@ -4327,7 +4393,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, devid = ASUS_WMI_DEVID_LID_RESUME; else if (attr == &dev_attr_als_enable.attr) devid = ASUS_WMI_DEVID_ALS_ENABLE; @@ -2784,7 +6595,7 @@ index ff8f0f47696c..6bd89cd0acdf 100644 devid = ASUS_WMI_DEVID_CHARGE_MODE; else if (attr == &dev_attr_egpu_enable.attr) ok = asus->egpu_enable_available; -@@ -4505,6 +4576,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, +@@ -4365,6 +4435,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, ok = asus->mini_led_dev_id != 0; else if (attr == &dev_attr_available_mini_led_mode.attr) ok = asus->mini_led_dev_id != 0; @@ -2792,15 +6603,15 @@ index ff8f0f47696c..6bd89cd0acdf 100644 if (devid != -1) { ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); -@@ -4756,6 +4828,7 @@ static int asus_wmi_add(struct platform_device *pdev) - } +@@ -4605,6 +4676,7 @@ static int asus_wmi_add(struct platform_device *pdev) + goto fail_platform; /* ensure defaults for tunables */ +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) asus->ppt_pl2_sppt = 5; asus->ppt_pl1_spl = 5; asus->ppt_apu_sppt = 5; -@@ -4777,17 +4850,18 @@ static int asus_wmi_add(struct platform_device *pdev) +@@ -4627,17 +4699,18 @@ static int asus_wmi_add(struct platform_device *pdev) asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX; else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO)) asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO; @@ -2824,3832 +6635,1306 @@ index ff8f0f47696c..6bd89cd0acdf 100644 err = fan_boost_mode_check_present(asus); if (err) goto fail_fan_boost_mode; +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 5af4430c863f..3ba0f8fef150 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -10,6 +10,8 @@ + #include + #include + ++#define FAN_CURVE_POINTS 8 ++ + /* + * / - debugfs root directory + * dev_id - current dev_id +@@ -32,14 +34,14 @@ struct asus_rfkill { + u32 dev_id; + }; + ++#define FAN_CURVE_POINTS 8 ++ + enum fan_type { + FAN_TYPE_NONE = 0, + FAN_TYPE_AGFN, /* deprecated on newer platforms */ + FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ + }; + +-#define FAN_CURVE_POINTS 8 +- + struct fan_curve_data { + bool enabled; + u32 device_id; +@@ -97,11 +99,12 @@ struct asus_wmi { + u8 fan_boost_mode_mask; + u8 fan_boost_mode; + ++ ++ /* Tunables provided by ASUS for gaming laptops */ ++#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) + bool egpu_enable_available; + 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; +@@ -109,6 +112,9 @@ struct asus_wmi { + u32 ppt_fppt; + u32 nv_dynamic_boost; + u32 nv_temp_target; ++ bool panel_overdrive_available; ++ u32 mini_led_dev_id; ++#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ + + u32 kbd_rgb_dev; + bool kbd_rgb_state_available; +@@ -128,9 +134,6 @@ struct asus_wmi { + // The RSOC controls the maximum charging percentage. + bool battery_rsoc_available; + +- bool panel_overdrive_available; +- u32 mini_led_dev_id; +- + struct hotplug_slot hotplug_slot; + struct mutex hotplug_lock; + struct mutex wmi_lock; -- 2.47.1 -From ab778daeb11f674e02e49ddb867610da892449e0 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Mon, 26 Aug 2024 12:49:35 +1200 -Subject: [PATCH 13/29] hid-asus-ally: Add joystick LED ring support +From a874558b5b9953e216c0f17582cd6c91f4214840 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello +Date: Tue, 21 Jan 2025 16:03:52 -0600 +Subject: [PATCH 25/28] drm/amd/display: Avoid divide by zero by initializing + dummy pitch to 1 -Adds basic support for the joystick RGB LED rings as a multicolour LED -device with 4 LEDs. +If the dummy values in `populate_dummy_dml_surface_cfg()` aren't updated +then they can lead to a divide by zero in downstream callers like +CalculateVMAndRowBytes() + +Signed-off-by: Mario Limonciello +--- + drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +index bde4250853b1..f07afe451006 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c ++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +@@ -852,7 +852,7 @@ static void populate_dummy_dml_surface_cfg(struct dml_surface_cfg_st *out, unsig + out->SurfaceWidthC[location] = in->timing.h_addressable; + out->SurfaceHeightC[location] = in->timing.v_addressable; + out->PitchY[location] = ((out->SurfaceWidthY[location] + 127) / 128) * 128; +- out->PitchC[location] = 0; ++ out->PitchC[location] = 1; + out->DCCEnable[location] = false; + out->DCCMetaPitchY[location] = 0; + out->DCCMetaPitchC[location] = 0; +-- +2.47.1 + + +From 4f6e377bcec0ed811d32a96098b7adf69f72fa51 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" +Date: Thu, 19 Sep 2024 17:19:37 +1200 +Subject: [PATCH 26/28] platform/x86: asus-armoury: add the ppt_* and nv_* + tuning knobs + +Adds the ppt_* and nv_* tuning knobs that are available via WMI methods +and adds proper min/max levels plus defaults. Signed-off-by: Luke D. Jones --- - drivers/hid/Kconfig | 9 + - drivers/hid/Makefile | 1 + - drivers/hid/hid-asus-ally.c | 625 ++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 38 +++ - drivers/hid/hid-asus.c | 20 +- - 5 files changed, 691 insertions(+), 2 deletions(-) - create mode 100644 drivers/hid/hid-asus-ally.c - create mode 100644 drivers/hid/hid-asus-ally.h + drivers/platform/x86/asus-armoury.c | 182 ++++- + drivers/platform/x86/asus-armoury.h | 778 ++++++++++++++++++++- + include/linux/platform_data/x86/asus-wmi.h | 3 + + 3 files changed, 950 insertions(+), 13 deletions(-) -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4d2a89d65b65..89357822c27b 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -164,6 +164,15 @@ config HID_ASUS - - GL553V series - - GL753V series +diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c +index 49e1788d8bba..5768997ea2d3 100644 +--- a/drivers/platform/x86/asus-armoury.c ++++ b/drivers/platform/x86/asus-armoury.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include -+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. +@@ -68,11 +69,25 @@ struct cpu_cores { + u32 max_power_cores; + }; + ++struct rog_tunables { ++ const struct power_data *tuning_limits; ++ u32 ppt_pl1_spl; // cpu ++ u32 ppt_pl2_sppt; // cpu ++ u32 ppt_pl3_fppt; // cpu ++ u32 ppt_apu_sppt; // plat ++ u32 ppt_platform_sppt; // plat + - config HID_AUREAL - tristate "Aureal" - help -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 24de45f3677d..f338c9eb4600 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..bfadf5cd700d ---- /dev/null -+++ b/drivers/hid/hid-asus-ally.c -@@ -0,0 +1,625 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later ++ u32 nv_dynamic_boost; ++ u32 nv_temp_target; ++ u32 nv_tgp; ++}; ++ + struct asus_armoury_priv { + struct device *fw_attr_dev; + struct kset *fw_attr_kset; + + struct cpu_cores *cpu_cores; ++ struct rog_tunables *rog_tunables; + u32 mini_led_dev_id; + u32 gpu_mux_dev_id; + +@@ -730,6 +745,26 @@ 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, ++ "Set the CPU slow package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, ++ "Set the CPU fast package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, "ppt_pl3_fppt", ASUS_WMI_DEVID_PPT_FPPT, ++ "Set the CPU fastest package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT, ++ "Set the APU package limit"); ++ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT, ++ "Set the platform package limit"); ++ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST, ++ "Set the Nvidia dynamic boost limit"); ++ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET, ++ "Set the Nvidia max thermal limit"); ++ATTR_GROUP_ROG_TUNABLE(nv_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, ++ "Set the additional TGP on top of the base TGP"); ++ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, "nv_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP, ++ "Read the base TGP value"); ++ ++ + ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", + "Show the current mode of charging"); + +@@ -753,6 +788,16 @@ static const struct asus_attr_group armoury_attr_groups[] = { + { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX }, + { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX }, + ++ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, ++ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, ++ { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT }, ++ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, ++ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, ++ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, ++ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, ++ { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, ++ { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, ++ + { &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 }, +@@ -762,6 +807,9 @@ static const struct asus_attr_group armoury_attr_groups[] = { + + static int asus_fw_attr_add(void) + { ++ const struct power_limits *limits; ++ bool should_create; ++ const char *name; + int err, i; + + asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), +@@ -815,17 +863,55 @@ static int asus_fw_attr_add(void) + } + + for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { ++ name = armoury_attr_groups[i].attr_group->name; ++ should_create = true; ++ + 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_err("Failed to create sysfs-group for %s\n", +- armoury_attr_groups[i].attr_group->name); +- goto err_remove_groups; ++ /* ++ * Check ROG tunables against initialized limits, don't create attributes for any ++ * that might have a supported WMI method but no associated data. ++ */ ++ if (!strcmp(name, "ppt_pl1_spl") || !strcmp(name, "ppt_pl2_sppt") || ++ !strcmp(name, "ppt_pl3_fppt") || !strcmp(name, "ppt_apu_sppt") || ++ !strcmp(name, "ppt_platform_sppt") || !strcmp(name, "nv_dynamic_boost") || ++ !strcmp(name, "nv_temp_target") || !strcmp(name, "nv_base_tgp") || ++ !strcmp(name, "dgpu_tgp")) ++ { ++ should_create = false; ++ if (asus_armoury.rog_tunables && asus_armoury.rog_tunables->tuning_limits && ++ asus_armoury.rog_tunables->tuning_limits->ac_data) { ++ /* Must have AC table, and a max value for each attribute */ ++ limits = asus_armoury.rog_tunables->tuning_limits->ac_data; ++ should_create = limits && ( ++ (!strcmp(name, "ppt_pl1_spl") && limits->ppt_pl1_spl_max) || ++ (!strcmp(name, "ppt_pl2_sppt") && limits->ppt_pl2_sppt_max) || ++ (!strcmp(name, "ppt_pl3_fppt") && limits->ppt_pl3_fppt_max) || ++ (!strcmp(name, "ppt_apu_sppt") && limits->ppt_apu_sppt_max) || ++ (!strcmp(name, "ppt_platform_sppt") && limits->ppt_platform_sppt_max) || ++ (!strcmp(name, "nv_dynamic_boost") && limits->nv_dynamic_boost_max) || ++ (!strcmp(name, "nv_temp_target") && limits->nv_temp_target_max) || ++ (!strcmp(name, "nv_base_tgp") && limits->nv_tgp_max) || ++ (!strcmp(name, "dgpu_tgp") && limits->nv_tgp_max)); ++ ++ /* Log error so users can report upstream */ ++ if (!should_create) ++ pr_err("Missing max value on %s for tunable: %s\n", ++ dmi_get_system_info(DMI_BOARD_NAME), name); ++ } + } +- } ++ ++ if (should_create) { ++ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, ++ armoury_attr_groups[i].attr_group); ++ if (err) { ++ pr_err("Failed to create sysfs-group for %s\n", ++ armoury_attr_groups[i].attr_group->name); ++ goto err_remove_groups; ++ } ++ } ++} + + return 0; + +@@ -849,6 +935,78 @@ static int asus_fw_attr_add(void) + + /* Init / exit ****************************************************************/ + ++/* Set up the min/max and defaults for ROG tunables */ ++static bool init_rog_tunables(struct rog_tunables *rog) ++{ ++ const struct dmi_system_id *dmi_id; ++ const struct power_data *power_data; ++ const struct power_limits *limits; ++ ++ /* Match the system against the power_limits table */ ++ dmi_id = dmi_first_match(power_limits); ++ if (!dmi_id) { ++ pr_warn("No matching power limits found for this system\n"); ++ // rog->tuning_limits = &default_power_data; ++ rog->tuning_limits = NULL; ++ return false; ++ } ++ ++ /* Get the power data for this system */ ++ power_data = dmi_id->driver_data; ++ if (!power_data) { ++ pr_info("No power data available for this system\n"); ++ return false; ++ } ++ ++ /* Store the power limits for later use */ ++ rog->tuning_limits = power_data; ++ ++ if (power_supply_is_system_supplied()) { ++ limits = power_data->ac_data; ++ if (!limits) { ++ pr_warn("No AC power limits available\n"); ++ return false; ++ } ++ } else { ++ limits = power_data->dc_data; ++ if (!limits && !power_data->ac_data) { ++ pr_err("No power limits available\n"); ++ return false; ++ } ++ } ++ ++ /* Set initial values */ ++ rog->ppt_pl1_spl = limits->ppt_pl1_spl_def ? ++ limits->ppt_pl1_spl_def : ++ limits->ppt_pl1_spl_max; ++ ++ rog->ppt_pl2_sppt = limits->ppt_pl2_sppt_def ? ++ limits->ppt_pl2_sppt_def : ++ limits->ppt_pl2_sppt_max; ++ ++ rog->ppt_pl3_fppt = limits->ppt_pl3_fppt_def ? ++ limits->ppt_pl3_fppt_def : ++ limits->ppt_pl3_fppt_max; ++ ++ rog->ppt_apu_sppt = limits->ppt_apu_sppt_def ? ++ limits->ppt_apu_sppt_def : ++ limits->ppt_apu_sppt_max; ++ ++ rog->ppt_platform_sppt = limits->ppt_platform_sppt_def ? ++ limits->ppt_platform_sppt_def : ++ limits->ppt_platform_sppt_max; ++ ++ rog->nv_dynamic_boost = limits->nv_dynamic_boost_max; ++ rog->nv_temp_target = limits->nv_temp_target_max; ++ rog->nv_tgp = limits->nv_tgp_max; ++ ++ pr_debug("Power limits initialized for %s (%s power)\n", ++ dmi_id->matches[0].substr, ++ power_supply_is_system_supplied() ? "AC" : "DC"); ++ ++ return true; ++} ++ + static int __init asus_fw_init(void) + { + char *wmi_uid; +@@ -879,6 +1037,16 @@ static int __init asus_fw_init(void) + } + } + ++ asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL); ++ if (!asus_armoury.rog_tunables) ++ return -ENOMEM; ++ /* Init logs warn/error and the driver should still be usable if init fails */ ++ if (!init_rog_tunables(asus_armoury.rog_tunables)) { ++ kfree(asus_armoury.rog_tunables); ++ pr_err("Could not initialise PPT tunable control %d\n", err); ++ } ++ ++ /* Must always be last step to ensure data is available */ + err = asus_fw_attr_add(); + if (err) + return err; +diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h +index 5d6bef6d2b12..9adc07ba6d6b 100644 +--- a/drivers/platform/x86/asus-armoury.h ++++ b/drivers/platform/x86/asus-armoury.h +@@ -8,6 +8,7 @@ + #ifndef _ASUS_ARMOURY_H_ + #define _ASUS_ARMOURY_H_ + ++#include + #include + #include + +@@ -17,18 +18,18 @@ static ssize_t attr_uint_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 enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, +- char *buf) +-{ +- return sysfs_emit(buf, "enumeration\n"); +-} +- + 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 }, \ +@@ -90,6 +91,20 @@ static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, + static struct kobj_attribute attr_##_attrname##_##_prop = \ + __ASUS_ATTR_RO(_attrname, _prop) + ++/* Requires current_value_show */ ++#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); \ +@@ -107,6 +122,10 @@ static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, + .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) +@@ -178,4 +197,751 @@ static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, + .name = _fsname, .attrs = _attrname##_attrs \ + } + +/* -+ * HID driver for Asus ROG laptops and Ally -+ * -+ * Copyright (c) 2023 Luke Jones ++ * ROG PPT attributes need a little different in setup as they ++ * require rog_tunables members. + */ + -+#include "linux/device.h" -+#include "linux/err.h" -+#include "linux/kstrtox.h" -+#include "linux/pm.h" -+#include "linux/slab.h" -+#include "linux/stddef.h" -+#include -+#include -+#include -+#include -+#include ++ #define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ ++ static ssize_t _attrname##_##_prop##_show( \ ++ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ ++ { \ ++ const struct power_limits *limits; \ ++ limits = power_supply_is_system_supplied() ? \ ++ asus_armoury.rog_tunables->tuning_limits->ac_data : \ ++ asus_armoury.rog_tunables->tuning_limits->dc_data; \ ++ if (!limits) \ ++ return -ENODEV; \ ++ return sysfs_emit(buf, "%d\n", limits->_val); \ ++ } \ ++ static struct kobj_attribute attr_##_attrname##_##_prop = \ ++ __ASUS_ATTR_RO(_attrname, _prop) + -+#include "hid-ids.h" -+#include "hid-asus-ally.h" ++#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \ ++ static ssize_t _attrname##_default_value_show( \ ++ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ ++ { \ ++ const struct power_limits *limits; \ ++ limits = power_supply_is_system_supplied() ? \ ++ asus_armoury.rog_tunables->tuning_limits->ac_data : \ ++ asus_armoury.rog_tunables->tuning_limits->dc_data; \ ++ if (!limits) \ ++ return -ENODEV; \ ++ return sysfs_emit(buf, "%d\n", \ ++ limits->_attrname##_def ? \ ++ limits->_attrname##_def : \ ++ limits->_attrname##_max); \ ++ } \ ++ static struct kobj_attribute attr_##_attrname##_default_value = \ ++ __ASUS_ATTR_RO(_attrname, default_value) + -+#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 __ROG_TUNABLE_RW(_attr, _wmi) \ ++ static ssize_t _attr##_current_value_store( \ ++ struct kobject *kobj, struct kobj_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ const struct power_limits *limits; \ ++ limits = power_supply_is_system_supplied() ? \ ++ asus_armoury.rog_tunables->tuning_limits->ac_data : \ ++ asus_armoury.rog_tunables->tuning_limits->dc_data; \ ++ if (!limits) \ ++ return -ENODEV; \ ++ return attr_uint_store(kobj, attr, buf, count, \ ++ limits->_attr##_min, \ ++ limits->_attr##_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 ALLY_CFG_INTF_IN_ADDRESS 0x83 -+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 -+#define ALLY_X_INTERFACE_ADDRESS 0x87 ++#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \ ++ __ROG_TUNABLE_RW(_attrname, _wmi); \ ++ __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \ ++ __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \ ++ __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \ ++ __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ ++ __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 \ ++ } + -+#define FEATURE_KBD_LED_REPORT_ID1 0x5d -+#define FEATURE_KBD_LED_REPORT_ID2 0x5e + -+#define ALLY_MIN_BIOS 319 -+#define ALLY_X_MIN_BIOS 313 ++/* Default is always the maximum value unless *_def is specified */ ++struct power_limits { ++ u32 ppt_pl1_spl_min; ++ u32 ppt_pl1_spl_def; ++ u32 ppt_pl1_spl_max; ++ u32 ppt_pl2_sppt_min; ++ u32 ppt_pl2_sppt_def; ++ u32 ppt_pl2_sppt_max; ++ u32 ppt_pl3_fppt_min; ++ u32 ppt_pl3_fppt_def; ++ u32 ppt_pl3_fppt_max; ++ u32 ppt_apu_sppt_min; ++ u32 ppt_apu_sppt_def; ++ u32 ppt_apu_sppt_max; ++ u32 ppt_platform_sppt_min; ++ u32 ppt_platform_sppt_def; ++ u32 ppt_platform_sppt_max; ++ /* Nvidia GPU specific, default is always max */ ++ u32 nv_dynamic_boost_def; // unused. exists for macro ++ u32 nv_dynamic_boost_min; ++ u32 nv_dynamic_boost_max; ++ u32 nv_temp_target_def; // unused. exists for macro ++ u32 nv_temp_target_min; ++ u32 nv_temp_target_max; ++ u32 nv_tgp_def; // unused. exists for macro ++ u32 nv_tgp_min; ++ u32 nv_tgp_max; ++}; + -+static const u8 EC_INIT_STRING[] = { 0x5A, 'A', 'S', 'U', 'S', ' ', 'T', 'e','c', 'h', '.', 'I', 'n', 'c', '.', '\0' }; -+static const u8 EC_MODE_LED_APPLY[] = { 0x5A, 0xB4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -+static const u8 EC_MODE_LED_SET[] = { 0x5A, 0xB5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -+static const u8 FORCE_FEEDBACK_OFF[] = { 0x0D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB }; ++struct power_data { ++ const struct power_limits *ac_data; ++ const struct power_limits *dc_data; ++}; + -+static const struct hid_device_id rog_ally_devices[] = { -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X) }, ++/* ++ * For each avilable attribute there must be a min and a max. ++ * _def is not required and will be assumed to be default == max if missing. ++ */ ++static const struct dmi_system_id power_limits[] = { ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA507R"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80 ++ }, ++ .dc_data = NULL ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA507X"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_tgp_min = 55, ++ .nv_tgp_max = 85, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_def = 45, ++ .ppt_pl1_spl_max = 65, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_def = 54, ++ .ppt_pl2_sppt_max = 65, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 65, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA507Z"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 65, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 105, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 15, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_tgp_min = 55, ++ .nv_tgp_max = 85, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 45, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_max = 60, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA607P"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 30, ++ .ppt_pl1_spl_def = 100, ++ .ppt_pl1_spl_max = 135, ++ .ppt_pl2_sppt_min = 30, ++ .ppt_pl2_sppt_def = 115, ++ .ppt_pl2_sppt_max = 135, ++ .ppt_pl3_fppt_min = 30, ++ .ppt_pl3_fppt_max = 135, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_tgp_min = 55, ++ .nv_tgp_max = 115, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_def = 45, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_def = 60, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 25, ++ .ppt_pl3_fppt_max = 80, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 15, ++ .ppt_apu_sppt_max = 80, ++ .ppt_platform_sppt_min = 30, ++ .ppt_platform_sppt_max = 120 ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 25, ++ .ppt_apu_sppt_max = 35, ++ .ppt_platform_sppt_min = 45, ++ .ppt_platform_sppt_max = 100 ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA617NT"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 15, ++ .ppt_apu_sppt_max = 80, ++ .ppt_platform_sppt_min = 30, ++ .ppt_platform_sppt_max = 115 ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 15, ++ .ppt_apu_sppt_max = 45, ++ .ppt_platform_sppt_min = 30, ++ .ppt_platform_sppt_max = 50 ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FA617XS"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 15, ++ .ppt_apu_sppt_max = 80, ++ .ppt_platform_sppt_min = 30, ++ .ppt_platform_sppt_max = 120, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 25, ++ .ppt_apu_sppt_max = 35, ++ .ppt_platform_sppt_min = 45, ++ .ppt_platform_sppt_max = 100, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "FX507Z"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 90, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 135, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 15, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 45, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_max = 60, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GA401Q"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_max = 80, ++ }, ++ .dc_data = NULL ++ }, ++ }, ++ { ++ .matches = { ++ // This model is full AMD. No Nvidia dGPU. ++ DMI_MATCH(DMI_BOARD_NAME, "GA402R"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 15, ++ .ppt_apu_sppt_max = 80, ++ .ppt_platform_sppt_min = 30, ++ .ppt_platform_sppt_max = 115, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_apu_sppt_min = 25, ++ .ppt_apu_sppt_def = 30, ++ .ppt_apu_sppt_max = 45, ++ .ppt_platform_sppt_min = 40, ++ .ppt_platform_sppt_max = 60, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GA402X"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_def = 35, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_def = 65, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 35, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 35, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 65, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GA403U"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80 ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 35, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 35, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 65 ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GA503R"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_def = 35, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_def = 65, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_def = 25, ++ .ppt_pl1_spl_max = 65, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_def = 54, ++ .ppt_pl2_sppt_max = 60, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 65 ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GA605W"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_tgp_min = 55, ++ .nv_tgp_max = 85, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 35, ++ .ppt_pl2_sppt_min = 31, ++ .ppt_pl2_sppt_max = 44, ++ .ppt_pl3_fppt_min = 45, ++ .ppt_pl3_fppt_max = 65, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GU604V"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 65, ++ .ppt_pl1_spl_max = 120, ++ .ppt_pl2_sppt_min = 65, ++ .ppt_pl2_sppt_max = 150, ++ /* Only allowed in AC mode */ ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 40, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_def = 40, ++ .ppt_pl2_sppt_max = 60, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GU605M"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 90, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 135, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 35, ++ .ppt_pl2_sppt_min = 38, ++ .ppt_pl2_sppt_max = 53, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GV601V"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_def = 100, ++ .ppt_pl1_spl_max = 110, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 135, ++ /* Only allowed in AC mode */ ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 40, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_def = 40, ++ .ppt_pl2_sppt_max = 60, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "G513Q"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ /* Yes this laptop is very limited */ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_max = 80, ++ }, ++ .dc_data = NULL ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "G614J"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 140, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 175, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 55, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 70, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "G634J"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 140, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 175, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 55, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 70, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "G814J"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 140, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 140, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 55, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 70, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "G834J"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 28, ++ .ppt_pl1_spl_max = 140, ++ .ppt_pl2_sppt_min = 28, ++ .ppt_pl2_sppt_max = 175, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 25, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 55, ++ .ppt_pl2_sppt_min = 25, ++ .ppt_pl2_sppt_max = 70, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "H7606W"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 15, ++ .ppt_pl1_spl_max = 80, ++ .ppt_pl2_sppt_min = 35, ++ .ppt_pl2_sppt_max = 80, ++ .ppt_pl3_fppt_min = 35, ++ .ppt_pl3_fppt_max = 80, ++ .nv_dynamic_boost_min = 5, ++ .nv_dynamic_boost_max = 20, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ .nv_tgp_min = 55, ++ .nv_tgp_max = 85, ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 25, ++ .ppt_pl1_spl_max = 35, ++ .ppt_pl2_sppt_min = 31, ++ .ppt_pl2_sppt_max = 44, ++ .ppt_pl3_fppt_min = 45, ++ .ppt_pl3_fppt_max = 65, ++ .nv_temp_target_min = 75, ++ .nv_temp_target_max = 87, ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "RC71"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 7, ++ .ppt_pl1_spl_max = 30, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_max = 43, ++ .ppt_pl3_fppt_min = 15, ++ .ppt_pl3_fppt_max = 53 ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 7, ++ .ppt_pl1_spl_def = 15, ++ .ppt_pl1_spl_max = 25, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_def = 20, ++ .ppt_pl2_sppt_max = 30, ++ .ppt_pl3_fppt_min = 15, ++ .ppt_pl3_fppt_def = 25, ++ .ppt_pl3_fppt_max = 35 ++ } ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "RC72"), ++ }, ++ .driver_data = &(struct power_data){ ++ .ac_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 7, ++ .ppt_pl1_spl_max = 30, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_max = 43, ++ .ppt_pl3_fppt_min = 15, ++ .ppt_pl3_fppt_max = 53 ++ }, ++ .dc_data = &(struct power_limits){ ++ .ppt_pl1_spl_min = 7, ++ .ppt_pl1_spl_def = 17, ++ .ppt_pl1_spl_max = 25, ++ .ppt_pl2_sppt_min = 15, ++ .ppt_pl2_sppt_def = 24, ++ .ppt_pl2_sppt_max = 30, ++ .ppt_pl3_fppt_min = 15, ++ .ppt_pl3_fppt_def = 30, ++ .ppt_pl3_fppt_max = 35 ++ } ++ }, ++ }, + {} +}; + -+struct ally_rgb_dev { -+ struct hid_device *hdev; -+ struct led_classdev_mc led_rgb_dev; -+ struct work_struct work; -+ bool output_worker_initialized; -+ spinlock_t lock; -+ -+ bool removed; -+ bool update_rgb; -+ uint8_t red[4]; -+ uint8_t green[4]; -+ uint8_t blue[4]; -+}; -+ -+struct ally_rgb_data { -+ uint8_t brightness; -+ uint8_t red[4]; -+ uint8_t green[4]; -+ uint8_t blue[4]; -+ bool initialized; -+}; -+ -+static struct ally_drvdata { -+ struct hid_device *hdev; -+ struct ally_rgb_dev *led_rgb_dev; -+ struct ally_rgb_data led_rgb_data; -+} drvdata; -+ -+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); -+} -+ -+/** -+ * asus_dev_set_report - send set report request to device. -+ * -+ * @hdev: hid device -+ * @buf: in/out data to transfer -+ * @len: length of buf -+ * -+ * Return: count of data transferred, negative if error -+ * -+ * Same behavior as hid_hw_raw_request. Note that the input buffer is duplicated. -+ */ -+static int asus_dev_set_report(struct hid_device *hdev, const u8 *buf, size_t len) -+{ -+ unsigned char *dmabuf; -+ int ret; -+ -+ dmabuf = kmemdup(buf, len, GFP_KERNEL); -+ if (!dmabuf) -+ return -ENOMEM; -+ -+ ret = hid_hw_raw_request(hdev, buf[0], dmabuf, len, HID_FEATURE_REPORT, -+ HID_REQ_SET_REPORT); -+ kfree(dmabuf); -+ -+ return ret; -+} -+ -+static u8 get_endpoint_address(struct hid_device *hdev) -+{ -+ struct usb_interface *intf; -+ struct usb_host_endpoint *ep; -+ -+ intf = to_usb_interface(hdev->dev.parent); -+ -+ if (intf) { -+ ep = intf->cur_altsetting->endpoint; -+ if (ep) { -+ return ep->desc.bEndpointAddress; -+ } -+ } -+ -+ return -ENODEV; -+} -+ -+/**************************************************************************************************/ -+/* ROG Ally LED control */ -+/**************************************************************************************************/ -+static void ally_rgb_schedule_work(struct ally_rgb_dev *led) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ if (!led->removed) -+ schedule_work(&led->work); -+ spin_unlock_irqrestore(&led->lock, flags); -+} -+ -+/* -+ * The RGB still has the basic 0-3 level brightness. Since the multicolour -+ * brightness is being used in place, set this to max -+ */ -+static int ally_rgb_set_bright_base_max(struct hid_device *hdev) -+{ -+ u8 buf[] = { FEATURE_KBD_LED_REPORT_ID1, 0xba, 0xc5, 0xc4, 0x02 }; -+ -+ return asus_dev_set_report(hdev, buf, sizeof(buf)); -+} -+ -+static void ally_rgb_do_work(struct work_struct *work) -+{ -+ struct ally_rgb_dev *led = container_of(work, struct ally_rgb_dev, work); -+ int ret; -+ unsigned long flags; -+ -+ 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[5 + i * 3] = drvdata.led_rgb_dev->green[i]; -+ buf[6 + i * 3] = drvdata.led_rgb_dev->blue[i]; -+ buf[4 + i * 3] = drvdata.led_rgb_dev->red[i]; -+ } -+ 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); -+} -+ -+static void ally_rgb_set(struct led_classdev *cdev, enum led_brightness brightness) -+{ -+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); -+ struct ally_rgb_dev *led = container_of(mc_cdev, struct ally_rgb_dev, led_rgb_dev); -+ int intensity, bright; -+ unsigned long flags; -+ -+ led_mc_calc_color_components(mc_cdev, brightness); -+ spin_lock_irqsave(&led->lock, flags); -+ led->update_rgb = true; -+ bright = mc_cdev->led_cdev.brightness; -+ for (int i = 0; i < 4; i++) { -+ intensity = mc_cdev->subled_info[i].intensity; -+ drvdata.led_rgb_dev->red[i] = (((intensity >> 16) & 0xFF) * bright) / 255; -+ drvdata.led_rgb_dev->green[i] = (((intensity >> 8) & 0xFF) * bright) / 255; -+ drvdata.led_rgb_dev->blue[i] = ((intensity & 0xFF) * bright) / 255; -+ } -+ spin_unlock_irqrestore(&led->lock, flags); -+ drvdata.led_rgb_data.initialized = true; -+ -+ ally_rgb_schedule_work(led); -+} -+ -+static int ally_rgb_set_static_from_multi(struct hid_device *hdev) -+{ -+ u8 buf[17] = {FEATURE_KBD_LED_REPORT_ID1, 0xb3}; -+ int ret; -+ -+ /* -+ * Set single zone single colour based on the first LED of EC software mode. -+ * buf[2] = zone, buf[3] = mode -+ */ -+ buf[4] = drvdata.led_rgb_data.red[0]; -+ buf[5] = drvdata.led_rgb_data.green[0]; -+ buf[6] = drvdata.led_rgb_data.blue[0]; -+ -+ ret = asus_dev_set_report(hdev, buf, sizeof(buf)); -+ if (ret < 0) -+ return ret; -+ -+ ret = asus_dev_set_report(hdev, EC_MODE_LED_APPLY, sizeof(EC_MODE_LED_APPLY)); -+ if (ret < 0) -+ return ret; -+ -+ return asus_dev_set_report(hdev, EC_MODE_LED_SET, sizeof(EC_MODE_LED_SET)); -+} -+ -+/* -+ * Store the RGB values for restoring on resume, and set the static mode to the first LED colour -+*/ -+static void ally_rgb_store_settings(void) -+{ -+ int arr_size = sizeof(drvdata.led_rgb_data.red); -+ -+ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; -+ -+ drvdata.led_rgb_data.brightness = led_rgb->led_rgb_dev.led_cdev.brightness; -+ -+ memcpy(drvdata.led_rgb_data.red, led_rgb->red, arr_size); -+ memcpy(drvdata.led_rgb_data.green, led_rgb->green, arr_size); -+ memcpy(drvdata.led_rgb_data.blue, led_rgb->blue, arr_size); -+ -+ ally_rgb_set_static_from_multi(led_rgb->hdev); -+} -+ -+static void ally_rgb_restore_settings(struct ally_rgb_dev *led_rgb, struct led_classdev *led_cdev, -+ struct mc_subled *mc_led_info) -+{ -+ int arr_size = sizeof(drvdata.led_rgb_data.red); -+ -+ memcpy(led_rgb->red, drvdata.led_rgb_data.red, arr_size); -+ memcpy(led_rgb->green, drvdata.led_rgb_data.green, arr_size); -+ memcpy(led_rgb->blue, drvdata.led_rgb_data.blue, arr_size); -+ for (int i = 0; i < 4; i++) { -+ mc_led_info[i].intensity = (drvdata.led_rgb_data.red[i] << 16) | -+ (drvdata.led_rgb_data.green[i] << 8) | -+ drvdata.led_rgb_data.blue[i]; -+ } -+ led_cdev->brightness = drvdata.led_rgb_data.brightness; -+} -+ -+/* Set LEDs. Call after any setup. */ -+static void ally_rgb_resume(void) -+{ -+ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; -+ struct led_classdev *led_cdev; -+ struct mc_subled *mc_led_info; -+ -+ if (!led_rgb) -+ return; -+ -+ led_cdev = &led_rgb->led_rgb_dev.led_cdev; -+ mc_led_info = led_rgb->led_rgb_dev.subled_info; -+ -+ if (drvdata.led_rgb_data.initialized) { -+ ally_rgb_restore_settings(led_rgb, led_cdev, mc_led_info); -+ led_rgb->update_rgb = true; -+ ally_rgb_schedule_work(led_rgb); -+ ally_rgb_set_bright_base_max(led_rgb->hdev); -+ } -+} -+ -+static int ally_rgb_register(struct hid_device *hdev, struct ally_rgb_dev *led_rgb) -+{ -+ struct mc_subled *mc_led_info; -+ struct led_classdev *led_cdev; -+ -+ mc_led_info = -+ devm_kmalloc_array(&hdev->dev, 12, sizeof(*mc_led_info), GFP_KERNEL | __GFP_ZERO); -+ if (!mc_led_info) -+ return -ENOMEM; -+ -+ mc_led_info[0].color_index = LED_COLOR_ID_RGB; -+ mc_led_info[1].color_index = LED_COLOR_ID_RGB; -+ mc_led_info[2].color_index = LED_COLOR_ID_RGB; -+ mc_led_info[3].color_index = LED_COLOR_ID_RGB; -+ -+ led_rgb->led_rgb_dev.subled_info = mc_led_info; -+ led_rgb->led_rgb_dev.num_colors = 4; -+ -+ led_cdev = &led_rgb->led_rgb_dev.led_cdev; -+ led_cdev->brightness = 128; -+ led_cdev->name = "ally:rgb:joystick_rings"; -+ led_cdev->max_brightness = 255; -+ led_cdev->brightness_set = ally_rgb_set; -+ -+ if (drvdata.led_rgb_data.initialized) { -+ ally_rgb_restore_settings(led_rgb, led_cdev, mc_led_info); -+ } -+ -+ return devm_led_classdev_multicolor_register(&hdev->dev, &led_rgb->led_rgb_dev); -+} -+ -+static struct ally_rgb_dev *ally_rgb_create(struct hid_device *hdev) -+{ -+ struct ally_rgb_dev *led_rgb; -+ int ret; -+ -+ led_rgb = devm_kzalloc(&hdev->dev, sizeof(struct ally_rgb_dev), GFP_KERNEL); -+ if (!led_rgb) -+ return ERR_PTR(-ENOMEM); -+ -+ ret = ally_rgb_register(hdev, led_rgb); -+ if (ret < 0) { -+ cancel_work_sync(&led_rgb->work); -+ devm_kfree(&hdev->dev, led_rgb); -+ return ERR_PTR(ret); -+ } -+ -+ led_rgb->hdev = hdev; -+ led_rgb->removed = false; -+ -+ INIT_WORK(&led_rgb->work, ally_rgb_do_work); -+ led_rgb->output_worker_initialized = true; -+ spin_lock_init(&led_rgb->lock); -+ -+ ally_rgb_set_bright_base_max(hdev); -+ -+ /* Not marked as initialized unless ally_rgb_set() is called */ -+ if (drvdata.led_rgb_data.initialized) { -+ msleep(1500); -+ led_rgb->update_rgb = true; -+ ally_rgb_schedule_work(led_rgb); -+ } -+ -+ return led_rgb; -+} -+ -+static void ally_rgb_remove(struct hid_device *hdev) -+{ -+ struct ally_rgb_dev *led_rgb = drvdata.led_rgb_dev; -+ unsigned long flags; -+ int ep; -+ -+ ep = get_endpoint_address(hdev); -+ if (ep != ALLY_CFG_INTF_IN_ADDRESS) -+ return; -+ -+ if (!drvdata.led_rgb_dev || led_rgb->removed) -+ return; -+ -+ spin_lock_irqsave(&led_rgb->lock, flags); -+ led_rgb->removed = true; -+ led_rgb->output_worker_initialized = false; -+ spin_unlock_irqrestore(&led_rgb->lock, flags); -+ cancel_work_sync(&led_rgb->work); -+ devm_led_classdev_multicolor_unregister(&hdev->dev, &led_rgb->led_rgb_dev); -+ -+ hid_info(hdev, "Removed Ally RGB interface"); -+} -+ -+/**************************************************************************************************/ -+/* ROG Ally driver init */ -+/**************************************************************************************************/ -+ -+/* -+ * Very simple parse. We don't care about any other part of the string except the version section. -+ * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 -+ */ -+static int mcu_parse_version_string(const u8 *response, size_t response_size) -+{ -+ int dot_count = 0; -+ size_t i; -+ -+ // Look for the second '.' to identify the start of the version -+ for (i = 0; i < response_size; i++) { -+ if (response[i] == '.') { -+ dot_count++; -+ if (dot_count == 2) { -+ int version = -+ simple_strtol((const char *)&response[i + 1], NULL, 10); -+ return (version >= 0) ? version : -EINVAL; -+ } -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int mcu_request_version(struct hid_device *hdev) -+{ -+ const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; -+ size_t response_size = FEATURE_ROG_ALLY_REPORT_SIZE; -+ u8 *response; -+ int ret; -+ -+ response = kzalloc(response_size, GFP_KERNEL); -+ if (!response) { -+ kfree(request); -+ return -ENOMEM; -+ } -+ -+ ret = asus_dev_set_report(hdev, request, sizeof(request)); -+ if (ret < 0) -+ goto error; -+ -+ ret = asus_dev_get_report(hdev, response, response_size); -+ if (ret < 0) -+ goto error; -+ -+ ret = mcu_parse_version_string(response, response_size); -+ if (ret < 0) -+ goto error; -+ -+ goto cleanup; -+ -+error: -+ hid_err(hdev, "Failed to get MCU version: %d\n", ret); -+cleanup: -+ kfree(response); -+ -+ return ret; -+} -+ -+static void mcu_maybe_warn_version(struct hid_device *hdev, int idProduct) -+{ -+ int min_version, version; -+ -+ min_version = 0; -+ version = mcu_request_version(hdev); -+ if (version) { -+ switch (idProduct) { -+ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: -+ min_version = ALLY_MIN_BIOS; -+ break; -+ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: -+ min_version = ALLY_X_MIN_BIOS; -+ break; -+ } -+ } -+ -+ hid_info(hdev, "Ally device MCU version: %d\n", version); -+ if (version <= min_version) { -+ hid_warn(hdev, -+ "The MCU version must be %d or greater\n" -+ "Please update your MCU with official ASUS firmware release " -+ "which has bug fixes to make the Linux experience better\n", -+ min_version); -+ } -+} -+ -+static int ally_hid_init(struct hid_device *hdev) -+{ -+ int ret; -+ -+ ret = asus_dev_set_report(hdev, EC_INIT_STRING, sizeof(EC_INIT_STRING)); -+ if (ret < 0) { -+ hid_err(hdev, "Ally failed to send init command: %d\n", ret); -+ return ret; -+ } -+ -+ ret = asus_dev_set_report(hdev, FORCE_FEEDBACK_OFF, sizeof(FORCE_FEEDBACK_OFF)); -+ if (ret < 0) -+ hid_err(hdev, "Ally failed to send init command: %d\n", ret); -+ -+ return ret; -+} -+ -+static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_id) -+{ -+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); -+ struct usb_device *udev = interface_to_usbdev(intf); -+ u16 idProduct = le16_to_cpu(udev->descriptor.idProduct); -+ int ret, ep; -+ -+ ep = get_endpoint_address(hdev); -+ if (ep < 0) -+ return ep; -+ -+ if (ep != ALLY_CFG_INTF_IN_ADDRESS) -+ return -ENODEV; -+ -+ ret = hid_parse(hdev); -+ if (ret) { -+ hid_err(hdev, "Parse failed\n"); -+ return ret; -+ } -+ -+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); -+ if (ret) { -+ hid_err(hdev, "Failed to start HID device\n"); -+ return ret; -+ } -+ -+ ret = hid_hw_open(hdev); -+ if (ret) { -+ hid_err(hdev, "Failed to open HID device\n"); -+ goto err_stop; -+ } -+ -+ /* Initialize MCU even before alloc */ -+ ret = ally_hid_init(hdev); -+ if (ret < 0) -+ return ret; -+ -+ drvdata.hdev = hdev; -+ hid_set_drvdata(hdev, &drvdata); -+ -+ /* This should almost always exist */ -+ if (ep == ALLY_CFG_INTF_IN_ADDRESS) { -+ mcu_maybe_warn_version(hdev, idProduct); -+ -+ drvdata.led_rgb_dev = ally_rgb_create(hdev); -+ if (IS_ERR(drvdata.led_rgb_dev)) -+ hid_err(hdev, "Failed to create Ally gamepad LEDs.\n"); -+ else -+ hid_info(hdev, "Created Ally RGB LED controls.\n"); -+ -+ if (IS_ERR(drvdata.led_rgb_dev)) -+ goto err_close; -+ } -+ -+ return 0; -+ -+err_close: -+ hid_hw_close(hdev); -+err_stop: -+ hid_hw_stop(hdev); -+ return ret; -+} -+ -+static void ally_hid_remove(struct hid_device *hdev) -+{ -+ if (drvdata.led_rgb_dev) -+ ally_rgb_remove(hdev); -+ -+ hid_hw_close(hdev); -+ hid_hw_stop(hdev); -+} -+ -+static int ally_hid_resume(struct hid_device *hdev) -+{ -+ ally_rgb_resume(); -+ -+ return 0; -+} -+ -+static int ally_hid_reset_resume(struct hid_device *hdev) -+{ -+ int ep = get_endpoint_address(hdev); -+ if (ep != ALLY_CFG_INTF_IN_ADDRESS) -+ return 0; -+ -+ ally_hid_init(hdev); -+ ally_rgb_resume(); -+ -+ return 0; -+} -+ -+static int ally_pm_thaw(struct device *dev) -+{ -+ struct hid_device *hdev = to_hid_device(dev); -+ -+ return ally_hid_reset_resume(hdev); -+} -+ -+static int ally_pm_suspend(struct device *dev) -+{ -+ if (drvdata.led_rgb_dev) { -+ ally_rgb_store_settings(); -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops ally_pm_ops = { -+ .thaw = ally_pm_thaw, -+ .suspend = ally_pm_suspend, -+ .poweroff = ally_pm_suspend, -+}; -+ -+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_hid_probe, -+ .remove = ally_hid_remove, -+ /* HID is the better place for resume functions, not pm_ops */ -+ .resume = ally_hid_resume, -+ .reset_resume = ally_hid_reset_resume, -+ .driver = { -+ .pm = &ally_pm_ops, -+ } }; -+ -+static int __init rog_ally_init(void) -+{ -+ return hid_register_driver(&rog_ally_cfg); -+} -+ -+static void __exit rog_ally_exit(void) -+{ -+ hid_unregister_driver(&rog_ally_cfg); -+} -+ -+module_init(rog_ally_init); -+module_exit(rog_ally_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..eb8617c80c2a ---- /dev/null -+++ b/drivers/hid/hid-asus-ally.h -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later -+ * -+ * HID driver for Asus ROG laptops and Ally -+ * -+ * Copyright (c) 2023 Luke Jones -+ */ -+ -+#include -+#include -+ -+/* 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, -+}; -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index e6030e013939..ef18f721e2ff 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 + #endif /* _ASUS_ARMOURY_H_ */ +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 3ba0f8fef150..34eddaee5983 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -285,6 +285,9 @@ struct asus_wmi { -+#define ALLY_CFG_INTF_IN_ADDRESS 0x83 -+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 -+#define ALLY_X_INTERFACE_ADDRESS 0x87 + #define ASUS_WMI_DEVID_APU_MEM 0x000600C1 + ++#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 ++#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 + - #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 | \ -@@ -1003,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. -@@ -1254,10 +1270,10 @@ 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_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_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), - QUIRK_ROG_CLAYMORE_II_KEYBOARD }, + /* gpu mux switch, 0 = dGPU, 1 = Optimus */ + #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 + #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026 -- 2.47.1 -From c1fa1ae4de0cc611b264f3452fd24fe3cca0a2b8 Mon Sep 17 00:00:00 2001 +From 51da1eea5ae6e86da671d31aa94693af04e1d1e2 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" -Date: Wed, 2 Oct 2024 23:32:46 +1300 -Subject: [PATCH 14/29] hid-asus-ally: initial Ally-X gamepad +Date: Tue, 28 Jan 2025 14:44:43 +1300 +Subject: [PATCH 27/28] asus-wmi: change quiet to low-power Signed-off-by: Luke D. Jones --- - drivers/hid/hid-asus-ally.c | 399 +++++++++++++++++++++++++++++++++++- - drivers/hid/hid-asus-ally.h | 5 + - 2 files changed, 403 insertions(+), 1 deletion(-) + drivers/platform/x86/asus-wmi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index bfadf5cd700d..33d9ac0c6bd5 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -49,6 +49,51 @@ static const struct hid_device_id rog_ally_devices[] = { - {} - }; - -+/* 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 }, -+}; -+ -+/* 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; -+}; -+ - struct ally_rgb_dev { - struct hid_device *hdev; - struct led_classdev_mc led_rgb_dev; -@@ -73,6 +118,7 @@ struct ally_rgb_data { - - static struct ally_drvdata { - struct hid_device *hdev; -+ struct ally_x_device *ally_x; - struct ally_rgb_dev *led_rgb_dev; - struct ally_rgb_data led_rgb_data; - } drvdata; -@@ -127,6 +173,309 @@ static u8 get_endpoint_address(struct hid_device *hdev) - return -ENODEV; - } - -+/**************************************************************************************************/ -+/* 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); -+ } -+ -+ input_sync(ally_x->input); -+ -+ return 0; -+} -+ -+static struct input_dev *ally_x_alloc_input_dev(struct hid_device *hdev, -+ const char *name_suffix) -+{ -+ struct input_dev *input_dev; -+ -+ 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 int ally_x_play_effect(struct input_dev *idev, void *data, struct ff_effect *effect) -+{ -+ 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 void ally_x_work(struct work_struct *work) -+{ -+ 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 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); -+ -+ return input; -+} -+ -+static ssize_t ally_x_qam_mode_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct ally_x_device *ally_x = drvdata.ally_x; -+ -+ return sysfs_emit(buf, "%d\n", ally_x->qam_btns_steam_mode); -+} -+ -+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; -+ -+ ret = kstrtobool(buf, &val); -+ if (ret < 0) -+ return ret; -+ -+ 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; -+ } -+ -+ /* 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 (sysfs_create_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr)) { -+ ret = -ENODEV; -+ goto unregister_input; -+ } -+ -+ 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); -+} -+ -+static void ally_x_remove(struct hid_device *hdev) -+{ -+ 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); -+} -+ - /**************************************************************************************************/ - /* ROG Ally LED control */ - /**************************************************************************************************/ -@@ -377,6 +726,32 @@ static void ally_rgb_remove(struct hid_device *hdev) - /* 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) || -+ (data[0] == 0x5A)) { -+ ally_x_raw_event(ally_x, report, data, size); -+ } else { -+ return -1; -+ } -+ } -+ // 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; -+} -+ - /* - * Very simple parse. We don't care about any other part of the string except the version section. - * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 -@@ -491,7 +866,8 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ - if (ep < 0) - return ep; - -- if (ep != ALLY_CFG_INTF_IN_ADDRESS) -+ if (ep != ALLY_CFG_INTF_IN_ADDRESS || -+ ep != ALLY_X_INTERFACE_ADDRESS) - return -ENODEV; - - ret = hid_parse(hdev); -@@ -534,6 +910,23 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ - goto err_close; - } - -+ /* May or may not exist */ -+ if (ep == 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"); -+ -+ // 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: -@@ -548,6 +941,9 @@ static void ally_hid_remove(struct hid_device *hdev) - if (drvdata.led_rgb_dev) - ally_rgb_remove(hdev); - -+ if (drvdata.ally_x) -+ ally_x_remove(hdev); -+ - hid_hw_close(hdev); - hid_hw_stop(hdev); - } -@@ -600,6 +996,7 @@ static struct hid_driver - .id_table = rog_ally_devices, - .probe = ally_hid_probe, - .remove = ally_hid_remove, -+ .raw_event = ally_raw_event, - /* HID is the better place for resume functions, not pm_ops */ - .resume = ally_hid_resume, - .reset_resume = ally_hid_reset_resume, -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index eb8617c80c2a..458d02996bca 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -36,3 +36,8 @@ enum xpad_cmd_len { - xpad_cmd_len_response_curve = 0x09, - xpad_cmd_len_adz = 0x02, - }; -+ -+/* 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) --- -2.47.1 - - -From 9ba17e350f65373bd366c8465bb8f26d98d4a405 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Wed, 2 Oct 2024 23:51:36 +1300 -Subject: [PATCH 15/29] hid-asus-ally: initial gamepad configuration - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 259 +++++++++++++++++++++++++++++++++--- - drivers/hid/hid-asus-ally.h | 38 +++--- - 2 files changed, 264 insertions(+), 33 deletions(-) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 33d9ac0c6bd5..eed1bc84026d 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -6,11 +6,8 @@ - */ - - #include "linux/device.h" --#include "linux/err.h" --#include "linux/kstrtox.h" - #include "linux/pm.h" - #include "linux/slab.h" --#include "linux/stddef.h" - #include - #include - #include -@@ -38,6 +35,9 @@ - #define ALLY_MIN_BIOS 319 - #define ALLY_X_MIN_BIOS 313 - -+#define BTN_DATA_LEN 11; -+#define BTN_CODE_BYTES_LEN 8 -+ - static const u8 EC_INIT_STRING[] = { 0x5A, 'A', 'S', 'U', 'S', ' ', 'T', 'e','c', 'h', '.', 'I', 'n', 'c', '.', '\0' }; - static const u8 EC_MODE_LED_APPLY[] = { 0x5A, 0xB4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - static const u8 EC_MODE_LED_SET[] = { 0x5A, 0xB5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -@@ -49,6 +49,58 @@ static const struct hid_device_id rog_ally_devices[] = { - {} - }; - -+struct btn_code_map { -+ u64 code; -+ const char *name; -+}; -+ -+/* byte_array must be >= 8 in length */ -+static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) -+{ -+ /* Convert the u64 to bytes[8] */ -+ for (int i = 0; i < 8; ++i) { -+ byte_array[i] = (keycode >> (56 - 8 * i)) & 0xFF; -+ } -+} -+ -+struct btn_data { -+ u64 button; -+ u64 macro; -+}; -+ -+struct btn_mapping { -+ struct btn_data btn_a; -+ struct btn_data btn_b; -+ struct btn_data btn_x; -+ struct btn_data btn_y; -+ struct btn_data btn_lb; -+ struct btn_data btn_rb; -+ struct btn_data btn_ls; -+ struct btn_data btn_rs; -+ struct btn_data btn_lt; -+ struct btn_data btn_rt; -+ struct btn_data dpad_up; -+ struct btn_data dpad_down; -+ struct btn_data dpad_left; -+ struct btn_data dpad_right; -+ struct btn_data btn_view; -+ struct btn_data btn_menu; -+ struct btn_data btn_m1; -+ struct btn_data btn_m2; -+}; -+ -+/* 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; -+ -+ enum xpad_mode mode; -+ /* -+ * index: [mode] -+ */ -+ struct btn_mapping *key_mapping[xpad_mode_mouse]; -+}; -+ - /* 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 }, -@@ -119,6 +171,7 @@ struct ally_rgb_data { - static struct ally_drvdata { - struct hid_device *hdev; - struct ally_x_device *ally_x; -+ struct ally_gamepad_cfg *gamepad_cfg; - struct ally_rgb_dev *led_rgb_dev; - struct ally_rgb_data led_rgb_data; - } drvdata; -@@ -173,6 +226,172 @@ static u8 get_endpoint_address(struct hid_device *hdev) - return -ENODEV; - } - -+/**************************************************************************************************/ -+/* ROG Ally gamepad configuration */ -+/**************************************************************************************************/ -+ -+/* This should be called before any attempts to set device functions */ -+static int ally_gamepad_check_ready(struct hid_device *hdev) -+{ -+ int ret, count; -+ u8 *hidbuf; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ 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_dbg(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_dbg(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 (count == READY_MAX_TRIES) -+ hid_warn(hdev, "ROG Ally never responded with a ready\n"); -+ -+ kfree(hidbuf); -+ return ret; -+} -+ -+/* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ -+static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, -+ enum btn_pair_index pair, -+ struct btn_data *btn1, struct btn_data *btn2, -+ u8 *out, int out_len) -+{ -+ int start = 5; -+ -+ 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; -+ -+ btn_code_to_byte_array(btn1->button, &out[start]); -+ start += BTN_DATA_LEN; -+ btn_code_to_byte_array(btn1->macro, &out[start]); -+ start += BTN_DATA_LEN; -+ btn_code_to_byte_array(btn2->button, &out[start]); -+ start += BTN_DATA_LEN; -+ btn_code_to_byte_array(btn2->macro, &out[start]); -+ //print_hex_dump(KERN_DEBUG, "byte_array: ", DUMP_PREFIX_OFFSET, 64, 1, out, 64, false); -+} -+ -+/* Apply the mapping pair to the device */ -+static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, -+ enum btn_pair_index btn_pair) -+{ -+ u8 mode = ally_cfg->mode - 1; -+ struct btn_data *btn1, *btn2; -+ u8 *hidbuf; -+ int ret; -+ -+ ret = ally_gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ switch (btn_pair) { -+ case btn_pair_m1_m2: -+ btn1 = &ally_cfg->key_mapping[mode]->btn_m1; -+ btn2 = &ally_cfg->key_mapping[mode]->btn_m2; -+ break; -+ default: -+ break; -+ } -+ -+ _btn_pair_to_hid_pkt(ally_cfg, btn_pair, btn1, btn2, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ -+ kfree(hidbuf); -+ -+ return ret; -+} -+ -+static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) -+{ -+ struct ally_gamepad_cfg *ally_cfg; -+ struct input_dev *input_dev; -+ int err; -+ -+ ally_cfg = devm_kzalloc(&hdev->dev, sizeof(*ally_cfg), GFP_KERNEL); -+ if (!ally_cfg) -+ return ERR_PTR(-ENOMEM); -+ ally_cfg->hdev = hdev; -+ // Allocate memory for each mode's `btn_mapping` -+ ally_cfg->mode = xpad_mode_game; -+ for (int i = 0; i < xpad_mode_mouse; i++) { -+ ally_cfg->key_mapping[i] = devm_kzalloc(&hdev->dev, sizeof(struct btn_mapping), GFP_KERNEL); -+ if (!ally_cfg->key_mapping[i]) { -+ err = -ENOMEM; -+ goto free_key_mappings; -+ } -+ } -+ -+ input_dev = devm_input_allocate_device(&hdev->dev); -+ if (!input_dev) { -+ err = -ENOMEM; -+ goto free_ally_cfg; -+ } -+ -+ 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->input = input_dev; -+ -+ /* ignore all errors for this as they are related to USB HID I/O */ -+ ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m1.button = BTN_KB_M1; -+ ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m2.button = BTN_KB_M2; -+ _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); -+ -+ return ally_cfg; -+ -+free_input_dev: -+ devm_kfree(&hdev->dev, input_dev); -+ -+free_key_mappings: -+ for (int i = 0; i < xpad_mode_mouse; i++) { -+ if (ally_cfg->key_mapping[i]) -+ devm_kfree(&hdev->dev, ally_cfg->key_mapping[i]); -+ } -+ -+free_ally_cfg: -+ devm_kfree(&hdev->dev, ally_cfg); -+ return ERR_PTR(err); -+} -+ - /**************************************************************************************************/ - /* ROG Ally gamepad i/o and force-feedback */ - /**************************************************************************************************/ -@@ -729,7 +948,7 @@ static void ally_rgb_remove(struct hid_device *hdev) - 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_gamepad_cfg *cfg = drvdata.gamepad_cfg; - struct ally_x_device *ally_x = drvdata.ally_x; - - if (ally_x) { -@@ -741,13 +960,13 @@ static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 - return -1; - } - } -- // 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); -- // } -+ 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; - } -@@ -866,7 +1085,7 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ - if (ep < 0) - return ep; - -- if (ep != ALLY_CFG_INTF_IN_ADDRESS || -+ if (ep != ALLY_CFG_INTF_IN_ADDRESS && - ep != ALLY_X_INTERFACE_ADDRESS) - return -ENODEV; - -@@ -906,7 +1125,13 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ - else - hid_info(hdev, "Created Ally RGB LED controls.\n"); - -- if (IS_ERR(drvdata.led_rgb_dev)) -+ drvdata.gamepad_cfg = ally_gamepad_cfg_create(hdev); -+ 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_dev) && IS_ERR(drvdata.gamepad_cfg)) - goto err_close; - } - -@@ -921,10 +1146,10 @@ static int ally_hid_probe(struct hid_device *hdev, const struct hid_device_id *_ - hid_info(hdev, "Created Ally X controller.\n"); - - // 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"); -- // } -+ 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; -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 458d02996bca..2b298ad4da0e 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -8,35 +8,41 @@ - #include - #include - -+/* -+ * 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, - }; - -+/* Values correspond to the actual HID byte value required */ -+enum btn_pair_index { -+ btn_pair_m1_m2 = 0x08, -+}; -+ -+#define BTN_KB_M2 0x02008E0000000000 -+#define BTN_KB_M1 0x02008F0000000000 -+ -+#define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ -+ struct device_attribute dev_attr_##_name = \ -+ __ATTR(_sysfs_name, 0200, NULL, _name##_store) -+ - /* 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 = \ --- -2.47.1 - - -From 84b34f27d809c52e7d220f30d4cc20fe0b64a332 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sat, 5 Oct 2024 14:58:33 +1300 -Subject: [PATCH 16/29] hid-asus-ally: add button remap attributes - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 393 ++++++++++++++++++++++++++++++++++-- - drivers/hid/hid-asus-ally.h | 211 +++++++++++++++++++ - 2 files changed, 586 insertions(+), 18 deletions(-) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index eed1bc84026d..56cc7abc397f 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -54,6 +54,152 @@ struct btn_code_map { - const char *name; - }; - -+static const struct btn_code_map ally_btn_codes[] = { -+ { 0, "NONE" }, -+ /* Gamepad button codes */ -+ { BTN_PAD_A, "PAD_A" }, -+ { BTN_PAD_B, "PAD_B" }, -+ { BTN_PAD_X, "PAD_X" }, -+ { BTN_PAD_Y, "PAD_Y" }, -+ { BTN_PAD_LB, "PAD_LB" }, -+ { BTN_PAD_RB, "PAD_RB" }, -+ { BTN_PAD_LS, "PAD_LS" }, -+ { BTN_PAD_RS, "PAD_RS" }, -+ { BTN_PAD_DPAD_UP, "PAD_DPAD_UP" }, -+ { BTN_PAD_DPAD_DOWN, "PAD_DPAD_DOWN" }, -+ { BTN_PAD_DPAD_LEFT, "PAD_DPAD_LEFT" }, -+ { BTN_PAD_DPAD_RIGHT, "PAD_DPAD_RIGHT" }, -+ { BTN_PAD_VIEW, "PAD_VIEW" }, -+ { BTN_PAD_MENU, "PAD_MENU" }, -+ { BTN_PAD_XBOX, "PAD_XBOX" }, -+ -+ /* Triggers mapped to keyboard codes */ -+ { BTN_KB_M2, "KB_M2" }, -+ { BTN_KB_M1, "KB_M1" }, -+ { BTN_KB_ESC, "KB_ESC" }, -+ { BTN_KB_F1, "KB_F1" }, -+ { BTN_KB_F2, "KB_F2" }, -+ { BTN_KB_F3, "KB_F3" }, -+ { BTN_KB_F4, "KB_F4" }, -+ { BTN_KB_F5, "KB_F5" }, -+ { BTN_KB_F6, "KB_F6" }, -+ { BTN_KB_F7, "KB_F7" }, -+ { BTN_KB_F8, "KB_F8" }, -+ { BTN_KB_F9, "KB_F9" }, -+ { BTN_KB_F10, "KB_F10" }, -+ { BTN_KB_F11, "KB_F11" }, -+ { BTN_KB_F12, "KB_F12" }, -+ { BTN_KB_F14, "KB_F14" }, -+ { BTN_KB_F15, "KB_F15" }, -+ { BTN_KB_BACKTICK, "KB_BACKTICK" }, -+ { BTN_KB_1, "KB_1" }, -+ { BTN_KB_2, "KB_2" }, -+ { BTN_KB_3, "KB_3" }, -+ { BTN_KB_4, "KB_4" }, -+ { BTN_KB_5, "KB_5" }, -+ { BTN_KB_6, "KB_6" }, -+ { BTN_KB_7, "KB_7" }, -+ { BTN_KB_8, "KB_8" }, -+ { BTN_KB_9, "KB_9" }, -+ { BTN_KB_0, "KB_0" }, -+ { BTN_KB_HYPHEN, "KB_HYPHEN" }, -+ { BTN_KB_EQUALS, "KB_EQUALS" }, -+ { BTN_KB_BACKSPACE, "KB_BACKSPACE" }, -+ { BTN_KB_TAB, "KB_TAB" }, -+ { BTN_KB_Q, "KB_Q" }, -+ { BTN_KB_W, "KB_W" }, -+ { BTN_KB_E, "KB_E" }, -+ { BTN_KB_R, "KB_R" }, -+ { BTN_KB_T, "KB_T" }, -+ { BTN_KB_Y, "KB_Y" }, -+ { BTN_KB_U, "KB_U" }, -+ { BTN_KB_O, "KB_O" }, -+ { BTN_KB_P, "KB_P" }, -+ { BTN_KB_LBRACKET, "KB_LBRACKET" }, -+ { BTN_KB_RBRACKET, "KB_RBRACKET" }, -+ { BTN_KB_BACKSLASH, "KB_BACKSLASH" }, -+ { BTN_KB_CAPS, "KB_CAPS" }, -+ { BTN_KB_A, "KB_A" }, -+ { BTN_KB_S, "KB_S" }, -+ { BTN_KB_D, "KB_D" }, -+ { BTN_KB_F, "KB_F" }, -+ { BTN_KB_G, "KB_G" }, -+ { BTN_KB_H, "KB_H" }, -+ { BTN_KB_J, "KB_J" }, -+ { BTN_KB_K, "KB_K" }, -+ { BTN_KB_L, "KB_L" }, -+ { BTN_KB_SEMI, "KB_SEMI" }, -+ { BTN_KB_QUOTE, "KB_QUOTE" }, -+ { BTN_KB_RET, "KB_RET" }, -+ { BTN_KB_LSHIFT, "KB_LSHIFT" }, -+ { BTN_KB_Z, "KB_Z" }, -+ { BTN_KB_X, "KB_X" }, -+ { BTN_KB_C, "KB_C" }, -+ { BTN_KB_V, "KB_V" }, -+ { BTN_KB_B, "KB_B" }, -+ { BTN_KB_N, "KB_N" }, -+ { BTN_KB_M, "KB_M" }, -+ { BTN_KB_COMMA, "KB_COMMA" }, -+ { BTN_KB_PERIOD, "KB_PERIOD" }, -+ { BTN_KB_RSHIFT, "KB_RSHIFT" }, -+ { BTN_KB_LCTL, "KB_LCTL" }, -+ { BTN_KB_META, "KB_META" }, -+ { BTN_KB_LALT, "KB_LALT" }, -+ { BTN_KB_SPACE, "KB_SPACE" }, -+ { BTN_KB_RALT, "KB_RALT" }, -+ { BTN_KB_MENU, "KB_MENU" }, -+ { BTN_KB_RCTL, "KB_RCTL" }, -+ { BTN_KB_PRNTSCN, "KB_PRNTSCN" }, -+ { BTN_KB_SCRLCK, "KB_SCRLCK" }, -+ { BTN_KB_PAUSE, "KB_PAUSE" }, -+ { BTN_KB_INS, "KB_INS" }, -+ { BTN_KB_HOME, "KB_HOME" }, -+ { BTN_KB_PGUP, "KB_PGUP" }, -+ { BTN_KB_DEL, "KB_DEL" }, -+ { BTN_KB_END, "KB_END" }, -+ { BTN_KB_PGDWN, "KB_PGDWN" }, -+ { BTN_KB_UP_ARROW, "KB_UP_ARROW" }, -+ { BTN_KB_DOWN_ARROW, "KB_DOWN_ARROW" }, -+ { BTN_KB_LEFT_ARROW, "KB_LEFT_ARROW" }, -+ { BTN_KB_RIGHT_ARROW, "KB_RIGHT_ARROW" }, -+ -+ /* Numpad mappings */ -+ { BTN_NUMPAD_LOCK, "NUMPAD_LOCK" }, -+ { BTN_NUMPAD_FWDSLASH, "NUMPAD_FWDSLASH" }, -+ { BTN_NUMPAD_ASTERISK, "NUMPAD_ASTERISK" }, -+ { BTN_NUMPAD_HYPHEN, "NUMPAD_HYPHEN" }, -+ { BTN_NUMPAD_0, "NUMPAD_0" }, -+ { BTN_NUMPAD_1, "NUMPAD_1" }, -+ { BTN_NUMPAD_2, "NUMPAD_2" }, -+ { BTN_NUMPAD_3, "NUMPAD_3" }, -+ { BTN_NUMPAD_4, "NUMPAD_4" }, -+ { BTN_NUMPAD_5, "NUMPAD_5" }, -+ { BTN_NUMPAD_6, "NUMPAD_6" }, -+ { BTN_NUMPAD_7, "NUMPAD_7" }, -+ { BTN_NUMPAD_8, "NUMPAD_8" }, -+ { BTN_NUMPAD_9, "NUMPAD_9" }, -+ { BTN_NUMPAD_PLUS, "NUMPAD_PLUS" }, -+ { BTN_NUMPAD_ENTER, "NUMPAD_ENTER" }, -+ { BTN_NUMPAD_PERIOD, "NUMPAD_PERIOD" }, -+ -+ /* Mouse mappings */ -+ { BTN_MOUSE_LCLICK, "MOUSE_LCLICK" }, -+ { BTN_MOUSE_RCLICK, "MOUSE_RCLICK" }, -+ { BTN_MOUSE_MCLICK, "MOUSE_MCLICK" }, -+ { BTN_MOUSE_WHEEL_UP, "MOUSE_WHEEL_UP" }, -+ { BTN_MOUSE_WHEEL_DOWN, "MOUSE_WHEEL_DOWN" }, -+ -+ /* Media mappings */ -+ { BTN_MEDIA_SCREENSHOT, "MEDIA_SCREENSHOT" }, -+ { BTN_MEDIA_SHOW_KEYBOARD, "MEDIA_SHOW_KEYBOARD" }, -+ { BTN_MEDIA_SHOW_DESKTOP, "MEDIA_SHOW_DESKTOP" }, -+ { BTN_MEDIA_START_RECORDING, "MEDIA_START_RECORDING" }, -+ { BTN_MEDIA_MIC_OFF, "MEDIA_MIC_OFF" }, -+ { BTN_MEDIA_VOL_DOWN, "MEDIA_VOL_DOWN" }, -+ { BTN_MEDIA_VOL_UP, "MEDIA_VOL_UP" }, -+}; -+static const size_t keymap_len = ARRAY_SIZE(ally_btn_codes); -+ - /* byte_array must be >= 8 in length */ - static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) - { -@@ -63,6 +209,27 @@ static void btn_code_to_byte_array(u64 keycode, u8 *byte_array) - } - } - -+static u64 name_to_btn(const char *name) -+{ -+ int len = strcspn(name, "\n"); -+ for (size_t i = 0; i < keymap_len; ++i) { -+ if (strncmp(ally_btn_codes[i].name, name, len) == 0) { -+ return ally_btn_codes[i].code; -+ } -+ } -+ return -EINVAL; -+} -+ -+static const char* btn_to_name(u64 key) -+{ -+ for (size_t i = 0; i < keymap_len; ++i) { -+ if (ally_btn_codes[i].code == key) { -+ return ally_btn_codes[i].name; -+ } -+ } -+ return NULL; -+} -+ - struct btn_data { - u64 button; - u64 macro; -@@ -98,7 +265,7 @@ struct ally_gamepad_cfg { - /* - * index: [mode] - */ -- struct btn_mapping *key_mapping[xpad_mode_mouse]; -+ struct btn_mapping key_mapping[xpad_mode_mouse]; - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -312,9 +479,41 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ - return -ENOMEM; - - switch (btn_pair) { -+ case btn_pair_dpad_u_d: -+ btn1 = &ally_cfg->key_mapping[mode].dpad_up; -+ btn2 = &ally_cfg->key_mapping[mode].dpad_down; -+ break; -+ case btn_pair_dpad_l_r: -+ btn1 = &ally_cfg->key_mapping[mode].dpad_left; -+ btn2 = &ally_cfg->key_mapping[mode].dpad_right; -+ break; -+ case btn_pair_ls_rs: -+ btn1 = &ally_cfg->key_mapping[mode].btn_ls; -+ btn2 = &ally_cfg->key_mapping[mode].btn_rs; -+ break; -+ case btn_pair_lb_rb: -+ btn1 = &ally_cfg->key_mapping[mode].btn_lb; -+ btn2 = &ally_cfg->key_mapping[mode].btn_rb; -+ break; -+ case btn_pair_lt_rt: -+ btn1 = &ally_cfg->key_mapping[mode].btn_lt; -+ btn2 = &ally_cfg->key_mapping[mode].btn_rt; -+ break; -+ case btn_pair_a_b: -+ btn1 = &ally_cfg->key_mapping[mode].btn_a; -+ btn2 = &ally_cfg->key_mapping[mode].btn_b; -+ break; -+ case btn_pair_x_y: -+ btn1 = &ally_cfg->key_mapping[mode].btn_x; -+ btn2 = &ally_cfg->key_mapping[mode].btn_y; -+ break; -+ case btn_pair_view_menu: -+ btn1 = &ally_cfg->key_mapping[mode].btn_view; -+ btn2 = &ally_cfg->key_mapping[mode].btn_menu; -+ break; - case btn_pair_m1_m2: -- btn1 = &ally_cfg->key_mapping[mode]->btn_m1; -- btn2 = &ally_cfg->key_mapping[mode]->btn_m2; -+ btn1 = &ally_cfg->key_mapping[mode].btn_m1; -+ btn2 = &ally_cfg->key_mapping[mode].btn_m2; +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 7e9878851f40..9a71a49d2c6a 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -3771,7 +3771,7 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + case ASUS_THROTTLE_THERMAL_POLICY_SILENT: +- *profile = PLATFORM_PROFILE_QUIET; ++ *profile = PLATFORM_PROFILE_LOW_POWER; break; default: + return -EINVAL; +@@ -3795,7 +3795,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, + case PLATFORM_PROFILE_BALANCED: + tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; break; -@@ -328,6 +527,157 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ - return ret; - } - -+static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) -+{ -+ int ret; -+ -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_dpad_u_d); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_dpad_l_r); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_ls_rs); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lb_rb); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_a_b); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_x_y); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_view_menu); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lt_rt); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static ssize_t gamepad_apply_all_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_apply_all(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ALLY_DEVICE_ATTR_WO(gamepad_apply_all, apply_all); -+ -+/* button map attributes, regular and macro*/ -+ALLY_BTN_MAPPING(m1, btn_m1); -+ALLY_BTN_MAPPING(m2, btn_m2); -+ALLY_BTN_MAPPING(a, btn_a); -+ALLY_BTN_MAPPING(b, btn_b); -+ALLY_BTN_MAPPING(x, btn_x); -+ALLY_BTN_MAPPING(y, btn_y); -+ALLY_BTN_MAPPING(lb, btn_lb); -+ALLY_BTN_MAPPING(rb, btn_rb); -+ALLY_BTN_MAPPING(ls, btn_ls); -+ALLY_BTN_MAPPING(rs, btn_rs); -+ALLY_BTN_MAPPING(lt, btn_lt); -+ALLY_BTN_MAPPING(rt, btn_rt); -+ALLY_BTN_MAPPING(dpad_u, dpad_up); -+ALLY_BTN_MAPPING(dpad_d, dpad_down); -+ALLY_BTN_MAPPING(dpad_l, dpad_left); -+ALLY_BTN_MAPPING(dpad_r, dpad_right); -+ALLY_BTN_MAPPING(view, btn_view); -+ALLY_BTN_MAPPING(menu, btn_menu); -+ -+static void _gamepad_set_xpad_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ struct btn_mapping *map = &ally_cfg->key_mapping[ally_cfg->mode - 1]; -+ map->btn_m1.button = BTN_KB_M1; -+ map->btn_m2.button = BTN_KB_M2; -+ map->btn_a.button = BTN_PAD_A; -+ map->btn_b.button = BTN_PAD_B; -+ map->btn_x.button = BTN_PAD_X; -+ map->btn_y.button = BTN_PAD_Y; -+ map->btn_lb.button = BTN_PAD_LB; -+ map->btn_rb.button = BTN_PAD_RB; -+ map->btn_lt.button = BTN_PAD_LT; -+ map->btn_rt.button = BTN_PAD_RT; -+ map->btn_ls.button = BTN_PAD_LS; -+ map->btn_rs.button = BTN_PAD_RS; -+ map->dpad_up.button = BTN_PAD_DPAD_UP; -+ map->dpad_down.button = BTN_PAD_DPAD_DOWN; -+ map->dpad_left.button = BTN_PAD_DPAD_LEFT; -+ map->dpad_right.button = BTN_PAD_DPAD_RIGHT; -+ map->btn_view.button = BTN_PAD_VIEW; -+ map->btn_menu.button = BTN_PAD_MENU; -+} -+ -+static ssize_t btn_mapping_reset_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; -+ -+ switch (ally_cfg->mode) { -+ case xpad_mode_game: -+ _gamepad_set_xpad_default(ally_cfg); -+ break; -+ default: -+ _gamepad_set_xpad_default(ally_cfg); -+ break; -+ } -+ -+ return count; -+} -+ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping); -+ -+/* ROOT LEVEL ATTRS *******************************************************************************/ -+static struct attribute *gamepad_device_attrs[] = { -+ &dev_attr_btn_mapping_reset.attr, -+ &dev_attr_gamepad_apply_all.attr, -+ NULL -+}; -+ -+static const struct attribute_group ally_controller_attr_group = { -+ .attrs = gamepad_device_attrs, -+}; -+ -+static const struct attribute_group *gamepad_device_attr_groups[] = { -+ &ally_controller_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_lt_attr_group, -+ &btn_mapping_rt_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 struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - { - struct ally_gamepad_cfg *ally_cfg; -@@ -340,13 +690,6 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->hdev = hdev; - // Allocate memory for each mode's `btn_mapping` - ally_cfg->mode = xpad_mode_game; -- for (int i = 0; i < xpad_mode_mouse; i++) { -- ally_cfg->key_mapping[i] = devm_kzalloc(&hdev->dev, sizeof(struct btn_mapping), GFP_KERNEL); -- if (!ally_cfg->key_mapping[i]) { -- err = -ENOMEM; -- goto free_key_mappings; -- } -- } - - input_dev = devm_input_allocate_device(&hdev->dev); - if (!input_dev) { -@@ -372,26 +715,37 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->input = input_dev; - - /* ignore all errors for this as they are related to USB HID I/O */ -- ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m1.button = BTN_KB_M1; -- ally_cfg->key_mapping[ally_cfg->mode - 1]->btn_m2.button = BTN_KB_M2; -+ _gamepad_set_xpad_default(ally_cfg); -+ ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m1.button = BTN_KB_M1; -+ ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; - _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); - -+ drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup -+ 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_key_mappings: -- for (int i = 0; i < xpad_mode_mouse; i++) { -- if (ally_cfg->key_mapping[i]) -- devm_kfree(&hdev->dev, ally_cfg->key_mapping[i]); -- } -- - free_ally_cfg: - devm_kfree(&hdev->dev, ally_cfg); - return ERR_PTR(err); - } - -+static void ally_cfg_remove(struct hid_device *hdev) -+{ -+ // __gamepad_set_mode(hdev, drvdata.gamepad_cfg, xpad_mode_mouse); -+ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups); -+} -+ - /**************************************************************************************************/ - /* ROG Ally gamepad i/o and force-feedback */ - /**************************************************************************************************/ -@@ -1169,6 +1523,9 @@ static void ally_hid_remove(struct hid_device *hdev) - if (drvdata.ally_x) - ally_x_remove(hdev); - -+ if (drvdata.gamepad_cfg) -+ ally_cfg_remove(hdev); -+ - hid_hw_close(hdev); - hid_hw_stop(hdev); - } -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 2b298ad4da0e..f985cbd698c3 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -33,11 +33,155 @@ enum xpad_cmd_len { - - /* Values correspond to the actual HID byte value required */ - enum btn_pair_index { -+ 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, - }; - -+#define BTN_PAD_A 0x0101000000000000 -+#define BTN_PAD_B 0x0102000000000000 -+#define BTN_PAD_X 0x0103000000000000 -+#define BTN_PAD_Y 0x0104000000000000 -+#define BTN_PAD_LB 0x0105000000000000 -+#define BTN_PAD_RB 0x0106000000000000 -+#define BTN_PAD_LS 0x0107000000000000 -+#define BTN_PAD_RS 0x0108000000000000 -+#define BTN_PAD_DPAD_UP 0x0109000000000000 -+#define BTN_PAD_DPAD_DOWN 0x010A000000000000 -+#define BTN_PAD_DPAD_LEFT 0x010B000000000000 -+#define BTN_PAD_DPAD_RIGHT 0x010C000000000000 -+#define BTN_PAD_LT 0x010D000000000000 -+#define BTN_PAD_RT 0x010E000000000000 -+#define BTN_PAD_VIEW 0x0111000000000000 -+#define BTN_PAD_MENU 0x0112000000000000 -+#define BTN_PAD_XBOX 0x0113000000000000 -+ - #define BTN_KB_M2 0x02008E0000000000 - #define BTN_KB_M1 0x02008F0000000000 -+#define BTN_KB_ESC 0x0200760000000000 -+#define BTN_KB_F1 0x0200500000000000 -+#define BTN_KB_F2 0x0200600000000000 -+#define BTN_KB_F3 0x0200400000000000 -+#define BTN_KB_F4 0x02000C0000000000 -+#define BTN_KB_F5 0x0200030000000000 -+#define BTN_KB_F6 0x02000B0000000000 -+#define BTN_KB_F7 0x0200800000000000 -+#define BTN_KB_F8 0x02000A0000000000 -+#define BTN_KB_F9 0x0200010000000000 -+#define BTN_KB_F10 0x0200090000000000 -+#define BTN_KB_F11 0x0200780000000000 -+#define BTN_KB_F12 0x0200070000000000 -+#define BTN_KB_F14 0x0200180000000000 -+#define BTN_KB_F15 0x0200100000000000 -+#define BTN_KB_BACKTICK 0x02000E0000000000 -+#define BTN_KB_1 0x0200160000000000 -+#define BTN_KB_2 0x02001E0000000000 -+#define BTN_KB_3 0x0200260000000000 -+#define BTN_KB_4 0x0200250000000000 -+#define BTN_KB_5 0x02002E0000000000 -+#define BTN_KB_6 0x0200360000000000 -+#define BTN_KB_7 0x02003D0000000000 -+#define BTN_KB_8 0x02003E0000000000 -+#define BTN_KB_9 0x0200460000000000 -+#define BTN_KB_0 0x0200450000000000 -+#define BTN_KB_HYPHEN 0x02004E0000000000 -+#define BTN_KB_EQUALS 0x0200550000000000 -+#define BTN_KB_BACKSPACE 0x0200660000000000 -+#define BTN_KB_TAB 0x02000D0000000000 -+#define BTN_KB_Q 0x0200150000000000 -+#define BTN_KB_W 0x02001D0000000000 -+#define BTN_KB_E 0x0200240000000000 -+#define BTN_KB_R 0x02002D0000000000 -+#define BTN_KB_T 0x02002C0000000000 -+#define BTN_KB_Y 0x0200350000000000 -+#define BTN_KB_U 0x02003C0000000000 -+#define BTN_KB_O 0x0200440000000000 -+#define BTN_KB_P 0x02004D0000000000 -+#define BTN_KB_LBRACKET 0x0200540000000000 -+#define BTN_KB_RBRACKET 0x02005B0000000000 -+#define BTN_KB_BACKSLASH 0x02005D0000000000 -+#define BTN_KB_CAPS 0x0200580000000000 -+#define BTN_KB_A 0x02001C0000000000 -+#define BTN_KB_S 0x02001B0000000000 -+#define BTN_KB_D 0x0200230000000000 -+#define BTN_KB_F 0x02002B0000000000 -+#define BTN_KB_G 0x0200340000000000 -+#define BTN_KB_H 0x0200330000000000 -+#define BTN_KB_J 0x02003B0000000000 -+#define BTN_KB_K 0x0200420000000000 -+#define BTN_KB_L 0x02004B0000000000 -+#define BTN_KB_SEMI 0x02004C0000000000 -+#define BTN_KB_QUOTE 0x0200520000000000 -+#define BTN_KB_RET 0x02005A0000000000 -+#define BTN_KB_LSHIFT 0x0200880000000000 -+#define BTN_KB_Z 0x02001A0000000000 -+#define BTN_KB_X 0x0200220000000000 -+#define BTN_KB_C 0x0200210000000000 -+#define BTN_KB_V 0x02002A0000000000 -+#define BTN_KB_B 0x0200320000000000 -+#define BTN_KB_N 0x0200310000000000 -+#define BTN_KB_M 0x02003A0000000000 -+#define BTN_KB_COMMA 0x0200410000000000 -+#define BTN_KB_PERIOD 0x0200490000000000 -+#define BTN_KB_RSHIFT 0x0200890000000000 -+#define BTN_KB_LCTL 0x02008C0000000000 -+#define BTN_KB_META 0x0200820000000000 -+#define BTN_KB_LALT 0x02008A0000000000 -+#define BTN_KB_SPACE 0x0200290000000000 -+#define BTN_KB_RALT 0x02008B0000000000 -+#define BTN_KB_MENU 0x0200840000000000 -+#define BTN_KB_RCTL 0x02008D0000000000 -+#define BTN_KB_PRNTSCN 0x0200C30000000000 -+#define BTN_KB_SCRLCK 0x02007E0000000000 -+#define BTN_KB_PAUSE 0x0200910000000000 -+#define BTN_KB_INS 0x0200C20000000000 -+#define BTN_KB_HOME 0x0200940000000000 -+#define BTN_KB_PGUP 0x0200960000000000 -+#define BTN_KB_DEL 0x0200C00000000000 -+#define BTN_KB_END 0x0200950000000000 -+#define BTN_KB_PGDWN 0x0200970000000000 -+#define BTN_KB_UP_ARROW 0x0200980000000000 -+#define BTN_KB_DOWN_ARROW 0x0200990000000000 -+#define BTN_KB_LEFT_ARROW 0x0200910000000000 -+#define BTN_KB_RIGHT_ARROW 0x02009B0000000000 -+ -+#define BTN_NUMPAD_LOCK 0x0200770000000000 -+#define BTN_NUMPAD_FWDSLASH 0x0200900000000000 -+#define BTN_NUMPAD_ASTERISK 0x02007C0000000000 -+#define BTN_NUMPAD_HYPHEN 0x02007B0000000000 -+#define BTN_NUMPAD_0 0x0200700000000000 -+#define BTN_NUMPAD_1 0x0200690000000000 -+#define BTN_NUMPAD_2 0x0200720000000000 -+#define BTN_NUMPAD_3 0x02007A0000000000 -+#define BTN_NUMPAD_4 0x02006B0000000000 -+#define BTN_NUMPAD_5 0x0200730000000000 -+#define BTN_NUMPAD_6 0x0200740000000000 -+#define BTN_NUMPAD_7 0x02006C0000000000 -+#define BTN_NUMPAD_8 0x0200750000000000 -+#define BTN_NUMPAD_9 0x02007D0000000000 -+#define BTN_NUMPAD_PLUS 0x0200790000000000 -+#define BTN_NUMPAD_ENTER 0x0200810000000000 -+#define BTN_NUMPAD_PERIOD 0x0200710000000000 -+ -+#define BTN_MOUSE_LCLICK 0x0300000001000000 -+#define BTN_MOUSE_RCLICK 0x0300000002000000 -+#define BTN_MOUSE_MCLICK 0x0300000003000000 -+#define BTN_MOUSE_WHEEL_UP 0x0300000004000000 -+#define BTN_MOUSE_WHEEL_DOWN 0x0300000005000000 -+ -+#define BTN_MEDIA_SCREENSHOT 0x0500001600000000 -+#define BTN_MEDIA_SHOW_KEYBOARD 0x0500001900000000 -+#define BTN_MEDIA_SHOW_DESKTOP 0x0500001C00000000 -+#define BTN_MEDIA_START_RECORDING 0x0500001E00000000 -+#define BTN_MEDIA_MIC_OFF 0x0500000100000000 -+#define BTN_MEDIA_VOL_DOWN 0x0500000200000000 -+#define BTN_MEDIA_VOL_UP 0x0500000300000000 - - #define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ - struct device_attribute dev_attr_##_name = \ -@@ -47,3 +191,70 @@ enum btn_pair_index { - #define ALLY_DEVICE_ATTR_RW(_name, _sysfs_name) \ - struct device_attribute dev_attr_##_name = \ - __ATTR(_sysfs_name, 0644, _name##_show, _name##_store) -+ -+/* button specific macros */ -+#define ALLY_BTN_SHOW(_fname, _btn_name, _secondary) \ -+ static ssize_t _fname##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ struct btn_data *btn; \ -+ const char* name; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ -+ name = btn_to_name(_secondary ? btn->macro : btn->button); \ -+ return sysfs_emit(buf, "%s\n", name); \ -+ } -+ -+#define ALLY_BTN_STORE(_fname, _btn_name, _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; \ -+ struct btn_data *btn; \ -+ u64 code; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ -+ code = name_to_btn(buf); \ -+ if (_secondary) \ -+ btn->macro = code; \ -+ else \ -+ btn->button = code; \ -+ return count; \ -+ } -+ -+#define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ -+ static struct attribute *_fname##_attrs[] = { \ -+ &dev_attr_##_fname.attr, \ -+ &dev_attr_##_fname##_macro.attr, \ -+ }; \ -+ static const struct attribute_group _fname##_attr_group = { \ -+ .name = __stringify(_name), \ -+ .attrs = _fname##_attrs, \ -+ } -+ -+#define _ALLY_BTN_REMAP(_fname, _btn_name) \ -+ ALLY_BTN_SHOW(btn_mapping_##_fname##_remap, _btn_name, false); \ -+ ALLY_BTN_STORE(btn_mapping_##_fname##_remap, _btn_name, false); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_remap, remap); -+ -+#define _ALLY_BTN_MACRO(_fname, _btn_name) \ -+ ALLY_BTN_SHOW(btn_mapping_##_fname##_macro, _btn_name, true); \ -+ ALLY_BTN_STORE(btn_mapping_##_fname##_macro, _btn_name, true); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_macro, macro_remap); -+ -+#define ALLY_BTN_MAPPING(_fname, _btn_name) \ -+ _ALLY_BTN_REMAP(_fname, _btn_name) \ -+ _ALLY_BTN_MACRO(_fname, _btn_name) \ -+ static struct attribute *_fname##_attrs[] = { \ -+ &dev_attr_btn_mapping_##_fname##_remap.attr, \ -+ &dev_attr_btn_mapping_##_fname##_macro.attr, \ -+ NULL, \ -+ }; \ -+ static const struct attribute_group btn_mapping_##_fname##_attr_group = { \ -+ .name = __stringify(btn_##_fname), \ -+ .attrs = _fname##_attrs, \ -+ } +- case PLATFORM_PROFILE_QUIET: ++ case PLATFORM_PROFILE_LOW_POWER: + tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT; + break; + default: -- 2.47.1 -From 2f3abc431a0d61a3b391f050929a8bd2ff22fbf3 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Fri, 25 Oct 2024 08:56:54 +0200 -Subject: [PATCH 17/29] hid-asus-ally: add gamepad mode selection +From e1cf942d39b9999fc1694a232c9d28dcaf51b5b0 Mon Sep 17 00:00:00 2001 +From: Luke Jones +Date: Wed, 5 Feb 2025 12:37:47 +1300 +Subject: [PATCH 28/28] backport: fix fw_attr use +Signed-off-by: Luke Jones --- - drivers/hid/hid-asus-ally.c | 73 +++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 2 + - 2 files changed, 75 insertions(+) + drivers/platform/x86/asus-armoury.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 56cc7abc397f..7cecdc10ba2c 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -644,9 +644,82 @@ static ssize_t btn_mapping_reset_store(struct device *dev, struct device_attribu - } - 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) -+{ -+ u8 *hidbuf; -+ int 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_mode; -+ hidbuf[3] = xpad_cmd_len_mode; -+ hidbuf[4] = val; -+ -+ ret = ally_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; -+ -+ ret = _gamepad_apply_all(hdev, ally_cfg); -+ if (ret < 0) -+ goto report_fail; -+ -+report_fail: -+ kfree(hidbuf); -+ return ret; -+} -+ -+static ssize_t gamepad_mode_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, "%d\n", ally_cfg->mode); -+} -+ -+static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct hid_device *hdev = to_hid_device(dev); -+ 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 < xpad_mode_game || val > xpad_mode_mouse) -+ return -EINVAL; -+ -+ ally_cfg->mode = val; -+ -+ ret = _gamepad_set_mode(hdev, ally_cfg, val); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ -+DEVICE_ATTR_RW(gamepad_mode); -+ - /* ROOT LEVEL ATTRS *******************************************************************************/ - static struct attribute *gamepad_device_attrs[] = { - &dev_attr_btn_mapping_reset.attr, -+ &dev_attr_gamepad_mode.attr, - &dev_attr_gamepad_apply_all.attr, - NULL - }; -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index f985cbd698c3..f7e21be50d8e 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -20,6 +20,7 @@ enum xpad_mode { - - /* 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_leds = 0x08, - xpad_cmd_check_ready = 0x0A, -@@ -27,6 +28,7 @@ enum xpad_cmd { - - /* 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_leds = 0x0C, - }; --- -2.47.1 - - -From 061aa0f79b14ea7ac01a0703132f2717506297d8 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sat, 5 Oct 2024 15:40:09 +1300 -Subject: [PATCH 18/29] hid-asus-ally: Turbo settings for buttons - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 72 +++++++++++++++++++++++++++++-------- - drivers/hid/hid-asus-ally.h | 50 ++++++++++++++++++++++++++ - 2 files changed, 108 insertions(+), 14 deletions(-) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 7cecdc10ba2c..b0fcad91f2b7 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -233,6 +233,7 @@ static const char* btn_to_name(u64 key) - struct btn_data { - u64 button; - u64 macro; -+ bool turbo; - }; - - struct btn_mapping { -@@ -527,6 +528,46 @@ static int _gamepad_apply_btn_pair(struct hid_device *hdev, struct ally_gamepad_ - return ret; - } - -+static int _gamepad_apply_turbo(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) -+{ -+ struct btn_mapping *map = &ally_cfg->key_mapping[ally_cfg->mode - 1]; -+ u8 *hidbuf; -+ int 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; -+ -+ hidbuf[4] = map->dpad_up.turbo; -+ hidbuf[6] = map->dpad_down.turbo; -+ hidbuf[8] = map->dpad_left.turbo; -+ hidbuf[10] = map->dpad_right.turbo; -+ -+ hidbuf[12] = map->btn_ls.turbo; -+ hidbuf[14] = map->btn_rs.turbo; -+ hidbuf[16] = map->btn_lb.turbo; -+ hidbuf[18] = map->btn_rb.turbo; -+ -+ hidbuf[20] = map->btn_a.turbo; -+ hidbuf[22] = map->btn_b.turbo; -+ hidbuf[24] = map->btn_x.turbo; -+ hidbuf[26] = map->btn_y.turbo; -+ -+ hidbuf[28] = map->btn_lt.turbo; -+ hidbuf[30] = map->btn_rt.turbo; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ -+ kfree(hidbuf); -+ -+ return ret; -+} -+ - static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg) - { - int ret; -@@ -556,6 +597,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c - if (ret < 0) - return ret; - ret = _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_lt_rt); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_turbo(hdev, ally_cfg); - if (ret < 0) - return ret; - -@@ -583,22 +627,22 @@ ALLY_DEVICE_ATTR_WO(gamepad_apply_all, apply_all); - /* button map attributes, regular and macro*/ - ALLY_BTN_MAPPING(m1, btn_m1); - ALLY_BTN_MAPPING(m2, btn_m2); --ALLY_BTN_MAPPING(a, btn_a); --ALLY_BTN_MAPPING(b, btn_b); --ALLY_BTN_MAPPING(x, btn_x); --ALLY_BTN_MAPPING(y, btn_y); --ALLY_BTN_MAPPING(lb, btn_lb); --ALLY_BTN_MAPPING(rb, btn_rb); --ALLY_BTN_MAPPING(ls, btn_ls); --ALLY_BTN_MAPPING(rs, btn_rs); --ALLY_BTN_MAPPING(lt, btn_lt); --ALLY_BTN_MAPPING(rt, btn_rt); --ALLY_BTN_MAPPING(dpad_u, dpad_up); --ALLY_BTN_MAPPING(dpad_d, dpad_down); --ALLY_BTN_MAPPING(dpad_l, dpad_left); --ALLY_BTN_MAPPING(dpad_r, dpad_right); - ALLY_BTN_MAPPING(view, btn_view); - ALLY_BTN_MAPPING(menu, btn_menu); -+ALLY_TURBO_BTN_MAPPING(a, btn_a); -+ALLY_TURBO_BTN_MAPPING(b, btn_b); -+ALLY_TURBO_BTN_MAPPING(x, btn_x); -+ALLY_TURBO_BTN_MAPPING(y, btn_y); -+ALLY_TURBO_BTN_MAPPING(lb, btn_lb); -+ALLY_TURBO_BTN_MAPPING(rb, btn_rb); -+ALLY_TURBO_BTN_MAPPING(ls, btn_ls); -+ALLY_TURBO_BTN_MAPPING(rs, btn_rs); -+ALLY_TURBO_BTN_MAPPING(lt, btn_lt); -+ALLY_TURBO_BTN_MAPPING(rt, btn_rt); -+ALLY_TURBO_BTN_MAPPING(dpad_u, dpad_up); -+ALLY_TURBO_BTN_MAPPING(dpad_d, dpad_down); -+ALLY_TURBO_BTN_MAPPING(dpad_l, dpad_left); -+ALLY_TURBO_BTN_MAPPING(dpad_r, dpad_right); - - static void _gamepad_set_xpad_default(struct ally_gamepad_cfg *ally_cfg) - { -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index f7e21be50d8e..63a3b5caa71c 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -24,6 +24,7 @@ enum xpad_cmd { - xpad_cmd_set_mapping = 0x02, - xpad_cmd_set_leds = 0x08, - xpad_cmd_check_ready = 0x0A, -+ xpad_cmd_set_turbo = 0x0F, - }; - - /* the xpad_cmd determines which feature is set or queried */ -@@ -31,6 +32,7 @@ enum xpad_cmd_len { - xpad_cmd_len_mode = 0x01, - xpad_cmd_len_mapping = 0x2c, - xpad_cmd_len_leds = 0x0C, -+ xpad_cmd_len_turbo = 0x20, - }; - - /* Values correspond to the actual HID byte value required */ -@@ -228,6 +230,37 @@ enum btn_pair_index { - return count; \ - } - -+#define ALLY_TURBO_SHOW(_fname, _btn_name) \ -+ static ssize_t _fname##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ struct btn_data *btn; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ -+ return sysfs_emit(buf, "%d\n", btn->turbo); \ -+ } -+ -+#define ALLY_TURBO_STORE(_fname, _btn_name) \ -+ 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; \ -+ struct btn_data *btn; \ -+ bool turbo; \ -+ int ret; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ btn = &ally_cfg->key_mapping[ally_cfg->mode - 1]._btn_name; \ -+ ret = kstrtobool(buf, &turbo); \ -+ if (ret) \ -+ return ret; \ -+ btn->turbo = turbo; \ -+ return count; \ -+ } -+ - #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ - static struct attribute *_fname##_attrs[] = { \ - &dev_attr_##_fname.attr, \ -@@ -260,3 +293,20 @@ enum btn_pair_index { - .name = __stringify(btn_##_fname), \ - .attrs = _fname##_attrs, \ - } -+ -+#define ALLY_TURBO_BTN_MAPPING(_fname, _btn_name) \ -+ _ALLY_BTN_REMAP(_fname, _btn_name) \ -+ _ALLY_BTN_MACRO(_fname, _btn_name) \ -+ ALLY_TURBO_SHOW(btn_mapping_##_fname##_turbo, _btn_name); \ -+ ALLY_TURBO_STORE(btn_mapping_##_fname##_turbo, _btn_name); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_turbo, turbo); \ -+ static struct attribute *_fname##_turbo_attrs[] = { \ -+ &dev_attr_btn_mapping_##_fname##_remap.attr, \ -+ &dev_attr_btn_mapping_##_fname##_macro.attr, \ -+ &dev_attr_btn_mapping_##_fname##_turbo.attr, \ -+ NULL, \ -+ }; \ -+ static const struct attribute_group btn_mapping_##_fname##_attr_group = { \ -+ .name = __stringify(btn_##_fname), \ -+ .attrs = _fname##_turbo_attrs, \ -+ } --- -2.47.1 - - -From 34494abc5037b770f9f7c4cf2d3c7ff3d972b5a2 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sat, 5 Oct 2024 20:46:00 +1300 -Subject: [PATCH 19/29] hid-asus-ally: add vibration intensity settings - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 93 +++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 6 +++ - 2 files changed, 99 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index b0fcad91f2b7..724bf3e8639a 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -267,6 +267,11 @@ struct ally_gamepad_cfg { - * index: [mode] - */ - struct btn_mapping key_mapping[xpad_mode_mouse]; -+ /* -+ * index: left, right -+ * max: 64 -+ */ -+ u8 vibration_intensity[2]; - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -438,6 +443,89 @@ static int ally_gamepad_check_ready(struct hid_device *hdev) - return ret; - } - -+/* 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"); -+} -+ -+ALLY_DEVICE_ATTR_RO(gamepad_vibration_intensity_index, vibration_intensity_index); -+ -+static ssize_t _gamepad_apply_intensity(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int 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_vibe_intensity; -+ hidbuf[3] = xpad_cmd_len_vibe_intensity; -+ hidbuf[4] = ally_cfg->vibration_intensity[0]; -+ hidbuf[5] = ally_cfg->vibration_intensity[1]; -+ -+ ret = ally_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; -+} -+ -+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; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ return sysfs_emit( -+ buf, "%d %d\n", -+ ally_cfg->vibration_intensity[0], -+ ally_cfg->vibration_intensity[1]); -+} -+ -+static ssize_t gamepad_vibration_intensity_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ 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[0] = left; -+ ally_cfg->vibration_intensity[1] = right; -+ -+ ret = _gamepad_apply_intensity(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ -+ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); -+ - /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ - static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, - enum btn_pair_index pair, -@@ -765,6 +853,8 @@ static struct attribute *gamepad_device_attrs[] = { - &dev_attr_btn_mapping_reset.attr, - &dev_attr_gamepad_mode.attr, - &dev_attr_gamepad_apply_all.attr, -+ &dev_attr_gamepad_vibration_intensity.attr, -+ &dev_attr_gamepad_vibration_intensity_index.attr, - NULL - }; - -@@ -837,6 +927,9 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; - _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); - -+ ally_cfg->vibration_intensity[0] = 0x64; -+ ally_cfg->vibration_intensity[1] = 0x64; -+ - drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup - if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { - err = -ENODEV; -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 63a3b5caa71c..6ac79ad3c5f2 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -22,6 +22,7 @@ enum xpad_mode { - enum xpad_cmd { - xpad_cmd_set_mode = 0x01, - xpad_cmd_set_mapping = 0x02, -+ xpad_cmd_set_vibe_intensity = 0x06, - xpad_cmd_set_leds = 0x08, - xpad_cmd_check_ready = 0x0A, - xpad_cmd_set_turbo = 0x0F, -@@ -31,6 +32,7 @@ enum xpad_cmd { - enum xpad_cmd_len { - xpad_cmd_len_mode = 0x01, - xpad_cmd_len_mapping = 0x2c, -+ xpad_cmd_len_vibe_intensity = 0x02, - xpad_cmd_len_leds = 0x0C, - xpad_cmd_len_turbo = 0x20, - }; -@@ -196,6 +198,10 @@ enum btn_pair_index { - 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) -+ - /* button specific macros */ - #define ALLY_BTN_SHOW(_fname, _btn_name, _secondary) \ - static ssize_t _fname##_show(struct device *dev, \ --- -2.47.1 - - -From f925a380b924029b0009db07a05a1ded5d21afdf Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sat, 5 Oct 2024 21:32:41 +1300 -Subject: [PATCH 20/29] hid-asus-ally: add JS deadzones - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 84 +++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 39 +++++++++++++++++ - 2 files changed, 123 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 724bf3e8639a..a813b2972a66 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -257,6 +257,11 @@ struct btn_mapping { - struct btn_data btn_m2; - }; - -+struct deadzone { -+ u8 inner; -+ u8 outer; -+}; -+ - /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ - struct ally_gamepad_cfg { - struct hid_device *hdev; -@@ -272,6 +277,10 @@ struct ally_gamepad_cfg { - * max: 64 - */ - u8 vibration_intensity[2]; -+ -+ /* deadzones */ -+ struct deadzone ls_dz; // left stick -+ struct deadzone rs_dz; // right stick - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -526,6 +535,75 @@ static ssize_t gamepad_vibration_intensity_store(struct device *dev, - - ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); - -+/* ANALOGUE DEADZONES *****************************************************************************/ -+static ssize_t _gamepad_apply_deadzones(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = ally_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->ls_dz.inner; -+ hidbuf[5] = ally_cfg->ls_dz.outer; -+ hidbuf[6] = ally_cfg->rs_dz.inner; -+ hidbuf[7] = ally_cfg->rs_dz.outer; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ -+ kfree(hidbuf); -+ return ret; -+} -+ -+static void _gamepad_set_deadzones_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ ally_cfg->ls_dz.inner = 0x00; -+ ally_cfg->ls_dz.outer = 0x64; -+ ally_cfg->rs_dz.inner = 0x00; -+ ally_cfg->rs_dz.outer = 0x64; -+} -+ -+static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "inner outer\n"); -+} -+ -+ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index); -+ -+ALLY_DEADZONES(axis_xy_left, ls_dz); -+ALLY_DEADZONES(axis_xy_right, rs_dz); -+ -+static struct attribute *axis_xy_left_attrs[] = { -+ &dev_attr_axis_xy_left_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ NULL -+}; -+static const struct attribute_group axis_xy_left_attr_group = { -+ .name = "axis_xy_left", -+ .attrs = axis_xy_left_attrs, -+}; -+ -+static struct attribute *axis_xy_right_attrs[] = { -+ &dev_attr_axis_xy_right_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ NULL -+}; -+static const struct attribute_group axis_xy_right_attr_group = { -+ .name = "axis_xy_right", -+ .attrs = axis_xy_right_attrs, -+}; -+ - /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ - static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, - enum btn_pair_index pair, -@@ -688,6 +766,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c - if (ret < 0) - return ret; - ret = _gamepad_apply_turbo(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_deadzones(hdev, ally_cfg); - if (ret < 0) - return ret; - -@@ -864,6 +945,8 @@ static const struct attribute_group ally_controller_attr_group = { - - static const struct attribute_group *gamepad_device_attr_groups[] = { - &ally_controller_attr_group, -+ &axis_xy_left_attr_group, -+ &axis_xy_right_attr_group, - &btn_mapping_m1_attr_group, - &btn_mapping_m2_attr_group, - &btn_mapping_a_attr_group, -@@ -929,6 +1012,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - - ally_cfg->vibration_intensity[0] = 0x64; - ally_cfg->vibration_intensity[1] = 0x64; -+ _gamepad_set_deadzones_default(ally_cfg); - - drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup - if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 6ac79ad3c5f2..3dc14a5226f3 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -22,6 +22,7 @@ enum xpad_mode { - enum xpad_cmd { - xpad_cmd_set_mode = 0x01, - xpad_cmd_set_mapping = 0x02, -+ xpad_cmd_set_js_dz = 0x04, /* deadzones */ - xpad_cmd_set_vibe_intensity = 0x06, - xpad_cmd_set_leds = 0x08, - xpad_cmd_check_ready = 0x0A, -@@ -32,6 +33,7 @@ enum xpad_cmd { - 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_turbo = 0x20, -@@ -267,6 +269,43 @@ enum btn_pair_index { - return count; \ - } - -+#define ALLY_DEADZONE_SHOW(_fname, _axis_name) \ -+ static ssize_t _fname##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ struct deadzone *dz; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ dz = &ally_cfg->_axis_name; \ -+ return sysfs_emit(buf, "%d %d\n", dz->inner, dz->outer); \ -+ } -+ -+#define ALLY_DEADZONE_STORE(_fname, _axis_name) \ -+ 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; \ -+ struct hid_device *hdev = to_hid_device(dev); \ -+ u32 inner, outer; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ if (sscanf(buf, "%d %d", &inner, &outer) != 2) \ -+ return -EINVAL; \ -+ if (inner > 64 || outer > 64 || inner > outer) \ -+ return -EINVAL; \ -+ ally_cfg->_axis_name.inner = inner; \ -+ ally_cfg->_axis_name.outer = outer; \ -+ _gamepad_apply_deadzones(hdev, ally_cfg); \ -+ return count; \ -+ } -+ -+#define ALLY_DEADZONES(_fname, _mname) \ -+ ALLY_DEADZONE_SHOW(_fname##_deadzone, _mname); \ -+ ALLY_DEADZONE_STORE(_fname##_deadzone, _mname); \ -+ ALLY_DEVICE_ATTR_RW(_fname##_deadzone, deadzone) -+ - #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ - static struct attribute *_fname##_attrs[] = { \ - &dev_attr_##_fname.attr, \ --- -2.47.1 - - -From 9cf3fa400f89e0f0845907544cde3c4abe11b0d3 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sat, 5 Oct 2024 21:37:27 +1300 -Subject: [PATCH 21/29] hid-asus-ally: add trigger deadzones - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 43 +++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 1 + - 2 files changed, 44 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index a813b2972a66..fc5620e63b06 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -281,6 +281,8 @@ struct ally_gamepad_cfg { - /* deadzones */ - struct deadzone ls_dz; // left stick - struct deadzone rs_dz; // right stick -+ struct deadzone lt_dz; // left trigger -+ struct deadzone rt_dz; // right trigger - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -560,7 +562,20 @@ static ssize_t _gamepad_apply_deadzones(struct hid_device *hdev, - hidbuf[7] = ally_cfg->rs_dz.outer; - - 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->lt_dz.inner; -+ hidbuf[5] = ally_cfg->lt_dz.outer; -+ hidbuf[6] = ally_cfg->rt_dz.inner; -+ hidbuf[7] = ally_cfg->rt_dz.outer; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto end; - -+end: - kfree(hidbuf); - return ret; - } -@@ -571,6 +586,10 @@ static void _gamepad_set_deadzones_default(struct ally_gamepad_cfg *ally_cfg) - ally_cfg->ls_dz.outer = 0x64; - ally_cfg->rs_dz.inner = 0x00; - ally_cfg->rs_dz.outer = 0x64; -+ ally_cfg->lt_dz.inner = 0x00; -+ ally_cfg->lt_dz.outer = 0x64; -+ ally_cfg->rt_dz.inner = 0x00; -+ ally_cfg->rt_dz.outer = 0x64; - } - - static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr, -@@ -583,6 +602,8 @@ ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index); - - ALLY_DEADZONES(axis_xy_left, ls_dz); - ALLY_DEADZONES(axis_xy_right, rs_dz); -+ALLY_DEADZONES(axis_z_left, lt_dz); -+ALLY_DEADZONES(axis_z_right, rt_dz); - - static struct attribute *axis_xy_left_attrs[] = { - &dev_attr_axis_xy_left_deadzone.attr, -@@ -604,6 +625,26 @@ static const struct attribute_group axis_xy_right_attr_group = { - .attrs = axis_xy_right_attrs, - }; - -+static struct attribute *axis_z_left_attrs[] = { -+ &dev_attr_axis_z_left_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ NULL, -+}; -+static const struct attribute_group axis_z_left_attr_group = { -+ .name = "axis_z_left", -+ .attrs = axis_z_left_attrs, -+}; -+ -+static struct attribute *axis_z_right_attrs[] = { -+ &dev_attr_axis_z_right_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ NULL, -+}; -+static const struct attribute_group axis_z_right_attr_group = { -+ .name = "axis_z_right", -+ .attrs = axis_z_right_attrs, -+}; -+ - /* A HID packet conatins mappings for two buttons: btn1, btn1_macro, btn2, btn2_macro */ - static void _btn_pair_to_hid_pkt(struct ally_gamepad_cfg *ally_cfg, - enum btn_pair_index pair, -@@ -947,6 +988,8 @@ static const struct attribute_group *gamepad_device_attr_groups[] = { - &ally_controller_attr_group, - &axis_xy_left_attr_group, - &axis_xy_right_attr_group, -+ &axis_z_left_attr_group, -+ &axis_z_right_attr_group, - &btn_mapping_m1_attr_group, - &btn_mapping_m2_attr_group, - &btn_mapping_a_attr_group, -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 3dc14a5226f3..32ed5caa3759 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -23,6 +23,7 @@ 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, --- -2.47.1 - - -From 33d060c292e0be3c1f73c983494c33e252ae6496 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sun, 6 Oct 2024 19:49:24 +1300 -Subject: [PATCH 22/29] hid-asus-ally: add anti-deadzones - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 110 ++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 2 + - 2 files changed, 112 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index fc5620e63b06..9d8bd0afaa68 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -283,6 +283,9 @@ struct ally_gamepad_cfg { - struct deadzone rs_dz; // right stick - struct deadzone lt_dz; // left trigger - struct deadzone rt_dz; // right trigger -+ /* anti-deadzones */ -+ u8 ls_adz; // left stick -+ u8 rs_adz; // right stick - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -605,7 +608,109 @@ ALLY_DEADZONES(axis_xy_right, rs_dz); - ALLY_DEADZONES(axis_z_left, lt_dz); - ALLY_DEADZONES(axis_z_right, rt_dz); - -+/* ANTI-DEADZONES *********************************************************************************/ -+static ssize_t _gamepad_apply_js_ADZ(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int 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->ls_adz; -+ hidbuf[5] = ally_cfg->rs_adz; -+ -+ ret = ally_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; -+} -+ -+static void _gamepad_set_anti_deadzones_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ ally_cfg->ls_adz = 0x00; -+ ally_cfg->rs_adz = 0x00; -+} -+ -+static ssize_t _gamepad_js_ADZ_store(struct device *dev, const char *buf, u8 *adz) -+{ -+ int ret, val; -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ -+ if (val < 0 || val > 32) -+ return -EINVAL; -+ -+ *adz = val; -+ -+ return ret; -+} -+ -+static ssize_t axis_xy_left_anti_deadzone_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ -+ return sysfs_emit(buf, "%d\n", ally_cfg->ls_adz); -+} -+ -+static ssize_t axis_xy_left_anti_deadzone_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ int ret; -+ -+ ret = _gamepad_js_ADZ_store(dev, buf, &ally_cfg->ls_adz); -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ALLY_DEVICE_ATTR_RW(axis_xy_left_anti_deadzone, anti_deadzone); -+ -+static ssize_t axis_xy_right_anti_deadzone_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ -+ return sysfs_emit(buf, "%d\n", ally_cfg->rs_adz); -+} -+ -+static ssize_t axis_xy_right_anti_deadzone_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ int ret; -+ -+ ret = _gamepad_js_ADZ_store(dev, buf, &ally_cfg->rs_adz); -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ALLY_DEVICE_ATTR_RW(axis_xy_right_anti_deadzone, anti_deadzone); -+ - static struct attribute *axis_xy_left_attrs[] = { -+ &dev_attr_axis_xy_left_anti_deadzone.attr, - &dev_attr_axis_xy_left_deadzone.attr, - &dev_attr_axis_xyz_deadzone_index.attr, - NULL -@@ -616,6 +721,7 @@ static const struct attribute_group axis_xy_left_attr_group = { - }; - - static struct attribute *axis_xy_right_attrs[] = { -+ &dev_attr_axis_xy_right_anti_deadzone.attr, - &dev_attr_axis_xy_right_deadzone.attr, - &dev_attr_axis_xyz_deadzone_index.attr, - NULL -@@ -810,6 +916,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c - if (ret < 0) - return ret; - ret = _gamepad_apply_deadzones(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ ret = _gamepad_apply_js_ADZ(hdev, ally_cfg); - if (ret < 0) - return ret; - -@@ -1056,6 +1165,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->vibration_intensity[0] = 0x64; - ally_cfg->vibration_intensity[1] = 0x64; - _gamepad_set_deadzones_default(ally_cfg); -+ _gamepad_set_anti_deadzones_default(ally_cfg); - - drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup - if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 32ed5caa3759..69f59592dd50 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -28,6 +28,7 @@ enum xpad_cmd { - xpad_cmd_set_leds = 0x08, - xpad_cmd_check_ready = 0x0A, - xpad_cmd_set_turbo = 0x0F, -+ xpad_cmd_set_adz = 0x18, - }; - - /* the xpad_cmd determines which feature is set or queried */ -@@ -38,6 +39,7 @@ enum xpad_cmd_len { - xpad_cmd_len_vibe_intensity = 0x02, - xpad_cmd_len_leds = 0x0C, - xpad_cmd_len_turbo = 0x20, -+ xpad_cmd_len_adz = 0x02, - }; - - /* Values correspond to the actual HID byte value required */ --- -2.47.1 - - -From 67683991b856661858d72befcf50e1af469d34f3 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Sun, 6 Oct 2024 21:22:40 +1300 -Subject: [PATCH 23/29] hid-asus-ally: add JS response curves - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 103 ++++++++++++++++++++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 38 +++++++++++++ - 2 files changed, 141 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 9d8bd0afaa68..9f9a7516b774 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -5,8 +5,10 @@ - * Copyright (c) 2023 Luke Jones - */ - -+#include "linux/compiler_attributes.h" - #include "linux/device.h" - #include "linux/pm.h" -+#include "linux/printk.h" - #include "linux/slab.h" - #include - #include -@@ -262,6 +264,17 @@ struct deadzone { - u8 outer; - }; - -+struct response_curve { -+ uint8_t move_pct_1; -+ uint8_t response_pct_1; -+ uint8_t move_pct_2; -+ uint8_t response_pct_2; -+ uint8_t move_pct_3; -+ uint8_t response_pct_3; -+ uint8_t move_pct_4; -+ uint8_t response_pct_4; -+} __packed; -+ - /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ - struct ally_gamepad_cfg { - struct hid_device *hdev; -@@ -286,6 +299,9 @@ struct ally_gamepad_cfg { - /* anti-deadzones */ - u8 ls_adz; // left stick - u8 rs_adz; // right stick -+ /* joystick response curves */ -+ struct response_curve ls_rc; -+ struct response_curve rs_rc; - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -709,10 +725,85 @@ static ssize_t axis_xy_right_anti_deadzone_store(struct device *dev, - } - ALLY_DEVICE_ATTR_RW(axis_xy_right_anti_deadzone, anti_deadzone); - -+/* JS RESPONSE CURVES *****************************************************************************/ -+static void _gamepad_set_js_response_curves_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ struct response_curve *js1_rc = &ally_cfg->ls_rc; -+ struct response_curve *js2_rc = &ally_cfg->rs_rc; -+ js1_rc->move_pct_1 = js2_rc->move_pct_1 = 0x16; // 25% -+ js1_rc->move_pct_2 = js2_rc->move_pct_2 = 0x32; // 50% -+ js1_rc->move_pct_3 = js2_rc->move_pct_3 = 0x48; // 75% -+ js1_rc->move_pct_4 = js2_rc->move_pct_4 = 0x64; // 100% -+ js1_rc->response_pct_1 = js2_rc->response_pct_1 = 0x16; -+ js1_rc->response_pct_2 = js2_rc->response_pct_2 = 0x32; -+ js1_rc->response_pct_3 = js2_rc->response_pct_3 = 0x48; -+ js1_rc->response_pct_4 = js2_rc->response_pct_4 = 0x64; -+} -+ -+static ssize_t _gamepad_apply_response_curves(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int 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; -+ memcpy(&hidbuf[2], &ally_cfg->ls_rc, sizeof(ally_cfg->ls_rc)); -+ -+ ret = ally_gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ hidbuf[4] = 0x02; -+ memcpy(&hidbuf[5], &ally_cfg->rs_rc, sizeof(ally_cfg->rs_rc)); -+ -+ ret = ally_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; -+} -+ -+ALLY_JS_RC_POINT(axis_xy_left, move, 1); -+ALLY_JS_RC_POINT(axis_xy_left, move, 2); -+ALLY_JS_RC_POINT(axis_xy_left, move, 3); -+ALLY_JS_RC_POINT(axis_xy_left, move, 4); -+ALLY_JS_RC_POINT(axis_xy_left, response, 1); -+ALLY_JS_RC_POINT(axis_xy_left, response, 2); -+ALLY_JS_RC_POINT(axis_xy_left, response, 3); -+ALLY_JS_RC_POINT(axis_xy_left, response, 4); -+ -+ALLY_JS_RC_POINT(axis_xy_right, move, 1); -+ALLY_JS_RC_POINT(axis_xy_right, move, 2); -+ALLY_JS_RC_POINT(axis_xy_right, move, 3); -+ALLY_JS_RC_POINT(axis_xy_right, move, 4); -+ALLY_JS_RC_POINT(axis_xy_right, response, 1); -+ALLY_JS_RC_POINT(axis_xy_right, response, 2); -+ALLY_JS_RC_POINT(axis_xy_right, response, 3); -+ALLY_JS_RC_POINT(axis_xy_right, response, 4); -+ - static struct attribute *axis_xy_left_attrs[] = { - &dev_attr_axis_xy_left_anti_deadzone.attr, - &dev_attr_axis_xy_left_deadzone.attr, - &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_axis_xy_left_move_1.attr, -+ &dev_attr_axis_xy_left_move_2.attr, -+ &dev_attr_axis_xy_left_move_3.attr, -+ &dev_attr_axis_xy_left_move_4.attr, -+ &dev_attr_axis_xy_left_response_1.attr, -+ &dev_attr_axis_xy_left_response_2.attr, -+ &dev_attr_axis_xy_left_response_3.attr, -+ &dev_attr_axis_xy_left_response_4.attr, - NULL - }; - static const struct attribute_group axis_xy_left_attr_group = { -@@ -724,6 +815,14 @@ static struct attribute *axis_xy_right_attrs[] = { - &dev_attr_axis_xy_right_anti_deadzone.attr, - &dev_attr_axis_xy_right_deadzone.attr, - &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_axis_xy_right_move_1.attr, -+ &dev_attr_axis_xy_right_move_2.attr, -+ &dev_attr_axis_xy_right_move_3.attr, -+ &dev_attr_axis_xy_right_move_4.attr, -+ &dev_attr_axis_xy_right_response_1.attr, -+ &dev_attr_axis_xy_right_response_2.attr, -+ &dev_attr_axis_xy_right_response_3.attr, -+ &dev_attr_axis_xy_right_response_4.attr, - NULL - }; - static const struct attribute_group axis_xy_right_attr_group = { -@@ -919,6 +1018,9 @@ static ssize_t _gamepad_apply_all(struct hid_device *hdev, struct ally_gamepad_c - if (ret < 0) - return ret; - ret = _gamepad_apply_js_ADZ(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ ret =_gamepad_apply_response_curves(hdev, ally_cfg); - if (ret < 0) - return ret; - -@@ -1166,6 +1268,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->vibration_intensity[1] = 0x64; - _gamepad_set_deadzones_default(ally_cfg); - _gamepad_set_anti_deadzones_default(ally_cfg); -+ _gamepad_set_js_response_curves_default(ally_cfg); - - drvdata.gamepad_cfg = ally_cfg; // Must asign before attr group setup - if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -index 69f59592dd50..c83817589082 100644 ---- a/drivers/hid/hid-asus-ally.h -+++ b/drivers/hid/hid-asus-ally.h -@@ -28,6 +28,7 @@ enum xpad_cmd { - xpad_cmd_set_leds = 0x08, - xpad_cmd_check_ready = 0x0A, - xpad_cmd_set_turbo = 0x0F, -+ xpad_cmd_set_response_curve = 0x13, - xpad_cmd_set_adz = 0x18, - }; - -@@ -39,6 +40,7 @@ enum xpad_cmd_len { - xpad_cmd_len_vibe_intensity = 0x02, - xpad_cmd_len_leds = 0x0C, - xpad_cmd_len_turbo = 0x20, -+ xpad_cmd_len_response_curve = 0x09, - xpad_cmd_len_adz = 0x02, - }; - -@@ -309,6 +311,42 @@ enum btn_pair_index { - ALLY_DEADZONE_STORE(_fname##_deadzone, _mname); \ - ALLY_DEVICE_ATTR_RW(_fname##_deadzone, deadzone) - -+/* response curve macros */ -+#define ALLY_RESP_CURVE_SHOW(_fname, _mname) \ -+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, "%d\n", ally_cfg->ls_rc._mname); \ -+ } -+ -+#define ALLY_RESP_CURVE_STORE(_fname, _mname) \ -+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; \ -+ int ret, val; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ ret = kstrtoint(buf, 0, &val); \ -+ if (ret) \ -+ return ret; \ -+ if (val < 0 || val > 100) \ -+ return -EINVAL; \ -+ ally_cfg->ls_rc._mname = val; \ -+ return count; \ -+ } -+ -+/* _point_n must start at 1 */ -+#define ALLY_JS_RC_POINT(_fname, _mname, _num) \ -+ ALLY_RESP_CURVE_SHOW(_fname##_##_mname##_##_num, _mname##_pct_##_num); \ -+ ALLY_RESP_CURVE_STORE(_fname##_##_mname##_##_num, _mname##_pct_##_num); \ -+ ALLY_DEVICE_ATTR_RW(_fname##_##_mname##_##_num, curve_##_mname##_pct_##_num) -+ - #define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ - static struct attribute *_fname##_attrs[] = { \ - &dev_attr_##_fname.attr, \ --- -2.47.1 - - -From b492b11b9d1a233423d8b38b0f49712d7f8ca00a Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Thu, 10 Oct 2024 11:15:36 +1300 -Subject: [PATCH 24/29] hid-asus-ally: add calibrations (wip) - -Signed-off-by: Luke D. Jones ---- - drivers/hid/hid-asus-ally.c | 95 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 95 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 9f9a7516b774..5a8458e232d3 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -275,6 +275,28 @@ struct response_curve { - uint8_t response_pct_4; - } __packed; - -+struct js_axis_calibrations { -+ uint16_t left_y_stable; -+ uint16_t left_y_min; -+ uint16_t left_y_max; -+ uint16_t left_x_stable; -+ uint16_t left_x_min; -+ uint16_t left_x_max; -+ uint16_t right_y_stable; -+ uint16_t right_y_min; -+ uint16_t right_y_max; -+ uint16_t right_x_stable; -+ uint16_t right_x_min; -+ uint16_t right_x_max; -+} __packed; -+ -+struct tr_axis_calibrations { -+ uint16_t left_stable; -+ uint16_t left_max; -+ uint16_t right_stable; -+ uint16_t right_max; -+} __packed; -+ - /* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */ - struct ally_gamepad_cfg { - struct hid_device *hdev; -@@ -302,6 +324,9 @@ struct ally_gamepad_cfg { - /* joystick response curves */ - struct response_curve ls_rc; - struct response_curve rs_rc; -+ -+ struct js_axis_calibrations js_cal; -+ struct tr_axis_calibrations tr_cal; - }; - - /* The hatswitch outputs integers, we use them to index this X|Y pair */ -@@ -379,6 +404,18 @@ static struct ally_drvdata { - struct ally_rgb_data led_rgb_data; - } drvdata; - -+static void reverse_bytes_in_pairs(u8 *buf, size_t size) { -+ uint16_t *word_ptr; -+ size_t i; -+ -+ for (i = 0; i < size; i += 2) { -+ if (i + 1 < size) { -+ word_ptr = (uint16_t *)&buf[i]; -+ *word_ptr = cpu_to_be16(*word_ptr); -+ } -+ } -+} -+ - 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, -@@ -792,6 +829,63 @@ ALLY_JS_RC_POINT(axis_xy_right, response, 2); - ALLY_JS_RC_POINT(axis_xy_right, response, 3); - ALLY_JS_RC_POINT(axis_xy_right, response, 4); - -+/* 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 */ -+ reverse_bytes_in_pairs(&hidbuf[6], sizeof(struct js_axis_calibrations)); -+ ally_cfg->js_cal = *(struct js_axis_calibrations *)&hidbuf[6]; -+ print_hex_dump(KERN_INFO, "HID Buffer JS: ", DUMP_PREFIX_OFFSET, 16, 1, hidbuf, 32, true); -+ struct js_axis_calibrations *cal = &drvdata.gamepad_cfg->js_cal; -+ pr_err("LS_CAL: X: %d, Min: %d, Max: %d", cal->left_x_stable, cal->left_x_min, cal->left_x_max); -+ pr_err("LS_CAL: Y: %d, Min: %d, Max: %d", cal->left_y_stable, cal->left_y_min, cal->left_y_max); -+ pr_err("RS_CAL: X: %d, Min: %d, Max: %d", cal->right_x_stable, cal->right_x_min, cal->right_x_max); -+ pr_err("RS_CAL: Y: %d, Min: %d, Max: %d", cal->right_y_stable, cal->right_y_min, cal->right_y_max); -+ } else { -+ /* Trigger calibration */ -+ reverse_bytes_in_pairs(&hidbuf[6], sizeof(struct tr_axis_calibrations)); -+ ally_cfg->tr_cal = *(struct tr_axis_calibrations *)&hidbuf[6]; -+ print_hex_dump(KERN_INFO, "HID Buffer TR: ", DUMP_PREFIX_OFFSET, 16, 1, hidbuf, 32, true); -+ } -+ } -+ -+cleanup: -+ kfree(hidbuf); -+ return ret; -+} -+ - static struct attribute *axis_xy_left_attrs[] = { - &dev_attr_axis_xy_left_anti_deadzone.attr, - &dev_attr_axis_xy_left_deadzone.attr, -@@ -1263,6 +1357,7 @@ static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) - ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m1.button = BTN_KB_M1; - ally_cfg->key_mapping[ally_cfg->mode - 1].btn_m2.button = BTN_KB_M2; - _gamepad_apply_btn_pair(hdev, ally_cfg, btn_pair_m1_m2); -+ gamepad_get_calibration(hdev); - - ally_cfg->vibration_intensity[0] = 0x64; - ally_cfg->vibration_intensity[1] = 0x64; --- -2.47.1 - - -From be811003d716d94cc0465313677ed275d18911d7 Mon Sep 17 00:00:00 2001 -From: "Luke D. Jones" -Date: Wed, 6 Nov 2024 00:27:03 +0300 -Subject: [PATCH 25/29] debug by default - ---- - drivers/hid/hid-asus-ally.c | 2 ++ - drivers/platform/x86/asus-armoury.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -index 5a8458e232d3..d59316001f50 100644 ---- a/drivers/hid/hid-asus-ally.c -+++ b/drivers/hid/hid-asus-ally.c -@@ -19,6 +19,8 @@ - #include "hid-ids.h" - #include "hid-asus-ally.h" - -+#define DEBUG -+ - #define READY_MAX_TRIES 3 - #define FEATURE_REPORT_ID 0x0d - #define FEATURE_ROG_ALLY_REPORT_ID 0x5a diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -index f09811d76b45..4dac91d02278 100644 +index 5768997ea2d3..47f3bf381825 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c -@@ -27,6 +27,8 @@ - #include "asus-armoury.h" - #include "firmware_attributes_class.h" +@@ -82,6 +82,8 @@ struct rog_tunables { + u32 nv_tgp; + }; -+#define DEBUG ++static const struct class *fw_attr_class; + - #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" + struct asus_armoury_priv { + struct device *fw_attr_dev; + struct kset *fw_attr_kset; +@@ -812,7 +814,11 @@ static int asus_fw_attr_add(void) + const char *name; + int err, i; - #define ASUS_MINI_LED_MODE_MASK 0x03 +- asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), ++ err = fw_attributes_class_get(&fw_attr_class); ++ if (err) ++ return err; ++ ++ 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); +@@ -928,8 +934,9 @@ static int asus_fw_attr_add(void) + err_destroy_kset: + kset_unregister(asus_armoury.fw_attr_kset); + err_destroy_classdev: ++ device_destroy(fw_attr_class, MKDEV(0, 0)); + fail_class_get: +- device_destroy(&firmware_attributes_class, MKDEV(0, 0)); ++ fw_attributes_class_put(); + return err; + } + +@@ -1060,7 +1067,8 @@ static void __exit asus_fw_exit(void) + + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); + kset_unregister(asus_armoury.fw_attr_kset); +- device_destroy(&firmware_attributes_class, MKDEV(0, 0)); ++ device_destroy(fw_attr_class, MKDEV(0, 0)); ++ fw_attributes_class_put(); + + mutex_unlock(&asus_armoury.mutex); + } -- 2.47.1