diff options
Diffstat (limited to 'SOURCES/asus-linux.patch')
-rw-r--r-- | SOURCES/asus-linux.patch | 5069 |
1 files changed, 0 insertions, 5069 deletions
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch deleted file mode 100644 index e22d980..0000000 --- a/SOURCES/asus-linux.patch +++ /dev/null @@ -1,5069 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jan200101 <sentrycraft123@gmail.com> -Date: Sun, 8 Sep 2024 01:49:57 +0200 -Subject: [PATCH] asus-linux 6.10.6 - -Signed-off-by: Jan200101 <sentrycraft123@gmail.com> ---- - drivers/hid/Kconfig | 9 + - drivers/hid/Makefile | 1 + - drivers/hid/hid-asus-ally.c | 2284 +++++++++++++++++++ - drivers/hid/hid-asus-ally.h | 544 +++++ - drivers/hid/hid-asus.c | 29 + - drivers/hid/hid-ids.h | 3 + - drivers/platform/x86/Kconfig | 14 + - drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/amd/pmf/pmf-quirks.c | 9 +- - drivers/platform/x86/asus-armoury.c | 1049 +++++++++ - drivers/platform/x86/asus-armoury.h | 259 +++ - drivers/platform/x86/asus-wmi.c | 254 ++- - drivers/platform/x86/intel/int3472/Makefile | 9 +- - drivers/platform/x86/intel/int3472/common.c | 7 + - include/linux/platform_data/x86/asus-wmi.h | 56 + - sound/pci/hda/patch_realtek.c | 8 + - 16 files changed, 4466 insertions(+), 70 deletions(-) - create mode 100644 drivers/hid/hid-asus-ally.c - create mode 100644 drivers/hid/hid-asus-ally.h - create mode 100644 drivers/platform/x86/asus-armoury.c - create mode 100644 drivers/platform/x86/asus-armoury.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 08446c89eff6..ea0dbe9111c4 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -164,6 +164,15 @@ config HID_ASUS - - GL553V series - - GL753V series - -+config HID_ASUS_ALLY -+ tristate "Asus Ally gamepad configuration support" -+ depends on USB_HID -+ depends on LEDS_CLASS -+ depends on LEDS_CLASS_MULTICOLOR -+ select POWER_SUPPLY -+ help -+ Support for configuring the Asus ROG Ally gamepad using attributes. -+ - config HID_AUREAL - tristate "Aureal" - help -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index ce71b53ea6c5..98b346d8f783 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o - obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o - obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o - obj-$(CONFIG_HID_ASUS) += hid-asus.o -+obj-$(CONFIG_HID_ASUS_ALLY) += hid-asus-ally.o - obj-$(CONFIG_HID_AUREAL) += hid-aureal.o - obj-$(CONFIG_HID_BELKIN) += hid-belkin.o - obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o -diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c -new file mode 100644 -index 000000000000..fd3d23b2c284 ---- /dev/null -+++ b/drivers/hid/hid-asus-ally.c -@@ -0,0 +1,2284 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * HID driver for Asus ROG laptops and Ally -+ * -+ * Copyright (c) 2023 Luke Jones <luke@ljones.dev> -+ */ -+ -+#include "linux/delay.h" -+#include "linux/device.h" -+#include "linux/err.h" -+#include "linux/input-event-codes.h" -+#include "linux/kstrtox.h" -+#include "linux/printk.h" -+#include "linux/slab.h" -+#include "linux/stddef.h" -+#include "linux/sysfs.h" -+#include <linux/hid.h> -+#include <linux/types.h> -+#include <linux/usb.h> -+#include <linux/leds.h> -+#include <linux/led-class-multicolor.h> -+ -+#include "hid-ids.h" -+#include "hid-asus-ally.h" -+ -+#define READY_MAX_TRIES 3 -+#define FEATURE_REPORT_ID 0x0d -+#define FEATURE_ROG_ALLY_REPORT_ID 0x5a -+#define FEATURE_ROG_ALLY_CODE_PAGE 0xD1 -+#define FEATURE_ROG_ALLY_REPORT_SIZE 64 -+#define ALLY_X_INPUT_REPORT_USB 0x0B -+#define ALLY_X_INPUT_REPORT_USB_SIZE 16 -+ -+#define ALLY_CFG_INTF_IN_ADDRESS 0x83 -+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 -+#define ALLY_X_INTERFACE_ADDRESS 0x87 -+ -+#define FEATURE_KBD_LED_REPORT_ID1 0x5d -+#define FEATURE_KBD_LED_REPORT_ID2 0x5e -+ -+enum ROG_ALLY_TYPE { -+ ROG_ALLY_TYPE, -+ ROG_ALLY_TYPE_X, -+}; -+ -+static const struct hid_device_id rog_ally_devices[] = { -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), -+ .driver_data = ROG_ALLY_TYPE }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), -+ .driver_data = ROG_ALLY_TYPE_X }, -+ {} -+}; -+ -+struct KeyCode { -+ const char *label; -+ u8 code; -+}; -+ -+static const struct KeyCode gamepad_codes[] = { -+ { "PAD_A", 0x01 }, { "PAD_B", 0x02 }, { "PAD_X", 0x03 }, -+ { "PAD_Y", 0x04 }, { "PAD_LB", 0x05 }, { "PAD_RB", 0x06 }, -+ { "PAD_LS", 0x07 }, { "PAD_RS", 0x08 }, { "PAD_DPAD_UP", 0x09 }, -+ { "PAD_DPAD_DOWN", 0x0a }, { "PAD_DPAD_LEFT", 0x0b }, { "PAD_DPAD_RIGHT", 0x0c }, -+ { "PAD_VIEW", 0x11 }, { "PAD_MENU", 0x12 }, { "PAD_XBOX", 0x13 } -+}; -+ -+static const struct KeyCode keyboard_codes[] = { { "KB_M1", 0x8f }, -+ { "KB_M2", 0x8e }, -+ { "KB_ESC", 0x76 }, -+ { "KB_F1", 0x50 }, -+ { "KB_F2", 0x60 }, -+ { "KB_F3", 0x40 }, -+ { "KB_F4", 0x0c }, -+ { "KB_F5", 0x03 }, -+ { "KB_F6", 0x0b }, -+ { "KB_F7", 0x80 }, -+ { "KB_F8", 0x0a }, -+ { "KB_F9", 0x01 }, -+ { "KB_F10", 0x09 }, -+ { "KB_F11", 0x78 }, -+ { "KB_F12", 0x07 }, -+ { "KB_F14", 0x10 }, -+ { "KB_F15", 0x18 }, -+ { "KB_BACKTICK", 0x0e }, -+ { "KB_1", 0x16 }, -+ { "KB_2", 0x1e }, -+ { "KB_3", 0x26 }, -+ { "KB_4", 0x25 }, -+ { "KB_5", 0x2e }, -+ { "KB_6", 0x36 }, -+ { "KB_7", 0x3d }, -+ { "KB_8", 0x3e }, -+ { "KB_9", 0x46 }, -+ { "KB_0", 0x45 }, -+ { "KB_HYPHEN", 0x4e }, -+ { "KB_EQUALS", 0x55 }, -+ { "KB_BACKSPACE", 0x66 }, -+ { "KB_TAB", 0x0d }, -+ { "KB_Q", 0x15 }, -+ { "KB_W", 0x1d }, -+ { "KB_E", 0x24 }, -+ { "KB_R", 0x2d }, -+ { "KB_T", 0x2d }, -+ { "KB_Y", 0x35 }, -+ { "KB_U", 0x3c }, -+ { "KB_I", 0x43 }, -+ { "KB_O", 0x44 }, -+ { "KB_P", 0x4d }, -+ { "KB_LBRACKET", 0x54 }, -+ { "KB_RBRACKET", 0x5b }, -+ { "KB_BACKSLASH", 0x5d }, -+ { "KB_CAPS", 0x58 }, -+ { "KB_A", 0x1c }, -+ { "KB_S", 0x1b }, -+ { "KB_D", 0x23 }, -+ { "KB_F", 0x2b }, -+ { "KB_G", 0x34 }, -+ { "KB_H", 0x33 }, -+ { "KB_J", 0x3b }, -+ { "KB_K", 0x42 }, -+ { "KB_L", 0x4b }, -+ { "KB_SEMI", 0x4c }, -+ { "KB_QUOTE", 0x52 }, -+ { "KB_RET", 0x5a }, -+ { "KB_LSHIFT", 0x88 }, -+ { "KB_Z", 0x1a }, -+ { "KB_X", 0x22 }, -+ { "KB_C", 0x21 }, -+ { "KB_V", 0x2a }, -+ { "KB_B", 0x32 }, -+ { "KB_N", 0x31 }, -+ { "KB_M", 0x3a }, -+ { "KB_COMMA", 0x41 }, -+ { "KB_PERIOD", 0x49 }, -+ { "KB_FWDSLASH", 0x4a }, -+ { "KB_RSHIFT", 0x89 }, -+ { "KB_LCTL", 0x8c }, -+ { "KB_META", 0x82 }, -+ { "KB_LALT", 0xba }, -+ { "KB_SPACE", 0x29 }, -+ { "KB_RALT", 0x8b }, -+ { "KB_MENU", 0x84 }, -+ { "KB_RCTL", 0x8d }, -+ { "KB_PRNTSCN", 0xc3 }, -+ { "KB_SCRLCK", 0x7e }, -+ { "KB_PAUSE", 0x91 }, -+ { "KB_INS", 0xc2 }, -+ { "KB_HOME", 0x94 }, -+ { "KB_PGUP", 0x96 }, -+ { "KB_DEL", 0xc0 }, -+ { "KB_END", 0x95 }, -+ { "KB_PGDWN", 0x97 }, -+ { "KB_UP_ARROW", 0x99 }, -+ { "KB_DOWN_ARROW", 0x98 }, -+ { "KB_LEFT_ARROW", 0x91 }, -+ { "KB_RIGHT_ARROW", 0x9b }, -+ { "NUMPAD_LOCK", 0x77 }, -+ { "NUMPAD_FWDSLASH", 0x90 }, -+ { "NUMPAD_ASTERISK", 0x7c }, -+ { "NUMPAD_HYPHEN", 0x7b }, -+ { "NUMPAD_0", 0x70 }, -+ { "NUMPAD_1", 0x69 }, -+ { "NUMPAD_2", 0x72 }, -+ { "NUMPAD_3", 0x7a }, -+ { "NUMPAD_4", 0x6b }, -+ { "NUMPAD_5", 0x73 }, -+ { "NUMPAD_6", 0x74 }, -+ { "NUMPAD_7", 0x6c }, -+ { "NUMPAD_8", 0x75 }, -+ { "NUMPAD_9", 0x7d }, -+ { "NUMPAD_PLUS", 0x79 }, -+ { "NUMPAD_ENTER", 0x81 }, -+ { "NUMPAD_PERIOD", 0x71 } }; -+ -+static const struct KeyCode mouse_codes[] = { { "MOUSE_LCLICK", 0x01 }, -+ { "MOUSE_RCLICK", 0x02 }, -+ { "MOUSE_MCLICK", 0x03 }, -+ { "MOUSE_WHEEL_UP", 0x04 }, -+ { "MOUSE_WHEEL_DOWN", 0x05 } }; -+ -+static const struct KeyCode media_codes[] = { -+ { "MEDIA_SCREENSHOT", 0x16 }, { "MEDIA_SHOW_KEYBOARD", 0x19 }, -+ { "MEDIA_SHOW_DESKTOP", 0x1c }, { "MEDIA_START_RECORDING", 0x1e }, -+ { "MEDIA_MIC_OFF", 0x01 }, { "MEDIA_VOL_DOWN", 0x02 }, -+ { "MEDIA_VOL_UP", 0x03 } -+}; -+ -+/* 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_leds { -+ struct hid_device *hdev; -+ /* Need two dev here to enable the 3 step brightness */ -+ struct led_classdev led_bright_dev; -+ struct led_classdev_mc led_rgb_dev; -+ struct work_struct work; -+ spinlock_t lock; -+ -+ bool removed; -+ -+ /* Update the main brightness 0-2 using a single raw write */ -+ bool update_bright; -+ unsigned int brightness; -+ -+ /* Update the RGB only to keep write efficient */ -+ bool update_rgb; -+ uint8_t gamepad_red; -+ uint8_t gamepad_green; -+ uint8_t gamepad_blue; -+}; -+ -+/* 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: [joysticks/triggers][left(2 bytes), right(2 bytes)] -+ * joysticks: 2 bytes: inner, outer -+ * triggers: 2 bytes: lower, upper -+ * min/max: 0-64 -+ */ -+ u8 deadzones[xpad_mode_mouse][2][4]; -+ /* -+ * index: left, right -+ * max: 64 -+ */ -+ u8 vibration_intensity[xpad_mode_mouse][2]; -+ /* -+ * index: [joysticks][2 byte stepping per point] -+ * - 4 points of 2 bytes each -+ * - byte 0 of pair = stick move % -+ * - byte 1 of pair = stick response % -+ * - min/max: 1-63 -+ */ -+ bool supports_response_curves; -+ u8 response_curve[xpad_mode_mouse][2][8]; -+ /* -+ * left = byte 0, right = byte 1 -+ */ -+ bool supports_anti_deadzones; -+ u8 anti_deadzones[xpad_mode_mouse][2]; -+ /* -+ * index: [mode][phys pair][b1, b1 secondary, b2, b2 secondary, blocks of 11] -+ */ -+ u8 key_mapping[xpad_mode_mouse][btn_pair_lt_rt][MAPPING_BLOCK_LEN]; -+ /* -+ * index: [mode][button index] -+ */ -+ u8 turbo_btns[xpad_mode_mouse][TURBO_BLOCK_LEN]; -+ /* -+ * index: [joystick side][Y-stable, Y-min, Y-max, X-stable, X-min, X-max] -+ */ -+ u32 js_calibrations[2][6]; -+ /* -+ * index: [trigger side][stable, max] -+ */ -+ u32 tr_calibrations[2][2]; -+}; -+ -+static struct ally_drvdata { -+ struct hid_device *hdev; -+ struct ally_x_device *ally_x; -+ struct ally_gamepad_cfg *gamepad_cfg; -+ struct ally_rgb_leds *led_rgb; -+} drvdata; -+ -+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 int asus_dev_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size) -+{ -+ unsigned char *dmabuf; -+ int ret; -+ -+ dmabuf = kmemdup(buf, buf_size, GFP_KERNEL); -+ if (!dmabuf) -+ return -ENOMEM; -+ -+ ret = hid_hw_raw_request(hdev, buf[0], dmabuf, buf_size, HID_FEATURE_REPORT, -+ HID_REQ_SET_REPORT); -+ kfree(dmabuf); -+ -+ return ret; -+} -+ -+/**************************************************************************************************/ -+/* 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 configuration */ -+/**************************************************************************************************/ -+static int __gamepad_write_all_to_mcu(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg); -+ -+static int process_key_code(const struct KeyCode *codes, int code_count, const char *buf_copy, -+ u8 *out, int out_idx) -+{ -+ for (int i = 0; i < code_count; i++) { -+ if (strcmp(buf_copy, codes[i].label) == 0) { -+ out[out_idx] = codes[i].code; -+ return 0; // Found -+ } -+ } -+ return -EINVAL; // Not found -+} -+ -+static int __string_to_key_code(const char *buf, u8 *out, int out_len) -+{ -+ char buf_copy[32]; -+ u8 *save_buf; -+ -+ if (out_len != BTN_CODE_LEN) -+ return -EINVAL; -+ -+ save_buf = kzalloc(out_len, GFP_KERNEL); -+ if (!save_buf) -+ return -ENOMEM; -+ memcpy(save_buf, out, out_len); -+ memset(out, 0, out_len); /* always clear before adjusting */ -+ -+ strscpy(buf_copy, buf); -+ buf_copy[strcspn(buf_copy, "\n")] = 0; -+ -+ /* Gamepad group */ -+ out[0] = 0x01; -+ if (process_key_code(gamepad_codes, ARRAY_SIZE(gamepad_codes), buf_copy, out, 1) == 0) -+ goto success; -+ -+ /* Keyboard group */ -+ out[0] = 0x02; -+ if (process_key_code(keyboard_codes, ARRAY_SIZE(keyboard_codes), buf_copy, out, 2) == 0) -+ goto success; -+ -+ /* Mouse group */ -+ out[0] = 0x03; -+ if (process_key_code(mouse_codes, ARRAY_SIZE(mouse_codes), buf_copy, out, 4) == 0) -+ goto success; -+ -+ /* Media group */ -+ out[0] = 0x05; -+ if (process_key_code(media_codes, ARRAY_SIZE(media_codes), buf_copy, out, 3) == 0) -+ goto success; -+ -+ /* Restore bytes if invalid input */ -+ memcpy(out, save_buf, out_len); -+ kfree(save_buf); -+ return -EINVAL; -+ -+success: -+ kfree(save_buf); -+ return 0; -+} -+ -+static const char *key_code_to_string(const struct KeyCode *codes, int code_count, u8 code) -+{ -+ for (int i = 0; i < code_count; i++) { -+ if (codes[i].code == code) -+ return codes[i].label; -+ } -+ return ""; -+} -+ -+static u8 *__get_btn_block(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, -+ enum btn_pair_side side, bool secondary) -+{ -+ int offs; -+ -+ offs = side ? MAPPING_BLOCK_LEN / 2 : 0; -+ offs = secondary ? offs + BTN_CODE_LEN : offs; -+ return ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1] + offs; -+} -+ -+static const char *__btn_map_to_string(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, -+ enum btn_pair_side side, bool secondary) -+{ -+ u8 *out_arg = __get_btn_block(ally_cfg, pair, side, secondary); -+ -+ switch (out_arg[0]) { -+ case 0x01: // Gamepad buttons -+ return key_code_to_string(gamepad_codes, ARRAY_SIZE(gamepad_codes), out_arg[1]); -+ case 0x02: // Keyboard keys -+ return key_code_to_string(keyboard_codes, ARRAY_SIZE(keyboard_codes), -+ out_arg[2]); -+ case 0x03: // Mouse buttons -+ return key_code_to_string(mouse_codes, ARRAY_SIZE(mouse_codes), out_arg[4]); -+ case 0x05: // Media controls -+ return key_code_to_string(media_codes, ARRAY_SIZE(media_codes), out_arg[3]); -+ default: -+ return ""; -+ } -+} -+ -+/* ASUS ROG Ally device specific attributes */ -+ -+/* This should be called before any attempts to set device functions */ -+static int __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_warn(hdev, "ROG Ally check failed set report: %d\n", ret); -+ -+ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0; -+ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret); -+ -+ ret = hidbuf[2] == xpad_cmd_check_ready; -+ if (ret) -+ break; -+ usleep_range( -+ 1000, -+ 2000); /* don't spam the entire loop in less than USB response time */ -+ } -+ -+ if (count == READY_MAX_TRIES) -+ hid_warn(hdev, "ROG Ally never responded with a ready\n"); -+ -+ kfree(hidbuf); -+ return ret; -+} -+ -+/* BUTTON REMAPPING *******************************************************************************/ -+static void __btn_pair_to_pkt(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, u8 *out, -+ int out_len) -+{ -+ out[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ out[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ out[2] = xpad_cmd_set_mapping; -+ out[3] = pair; -+ out[4] = xpad_cmd_len_mapping; -+ memcpy(&out[5], &ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1], -+ MAPPING_BLOCK_LEN); -+} -+ -+/* Store the button setting in driver data. Does not apply to device until __gamepad_set_mapping */ -+static int __gamepad_mapping_store(struct ally_gamepad_cfg *ally_cfg, const char *buf, -+ enum btn_pair pair, int side, bool secondary) -+{ -+ u8 *out_arg; -+ -+ out_arg = __get_btn_block(ally_cfg, pair, side, secondary); -+ -+ return __string_to_key_code(buf, out_arg, BTN_CODE_LEN); -+} -+ -+/* Apply the mapping pair to the device */ -+static int __gamepad_set_mapping(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, -+ enum btn_pair pair) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ __btn_pair_to_pkt(ally_cfg, pair, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ -+ kfree(hidbuf); -+ -+ return ret; -+} -+ -+static ssize_t btn_mapping_apply_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ struct hid_device *hdev = to_hid_device(dev); -+ int ret; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ ret = __gamepad_write_all_to_mcu(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ALLY_DEVICE_ATTR_WO(btn_mapping_apply, apply_all); -+ -+/* BUTTON TURBO ***********************************************************************************/ -+static int __btn_turbo_index(enum btn_pair pair, int side) -+{ -+ return (pair - 1) * (2 * TURBO_BLOCK_STEP) + (side * TURBO_BLOCK_STEP); -+}; -+ -+static int __gamepad_turbo_show(struct device *dev, enum btn_pair pair, int side) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ return ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)]; -+}; -+ -+static int __gamepad_turbo_store(struct device *dev, const char *buf, enum btn_pair pair, -+ int side) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ int ret, val; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ if (val < 0 || val > 16) -+ return -EINVAL; -+ -+ ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)] = val; -+ -+ return 0; -+}; -+ -+/* button map attributes, regular and macro*/ -+ALLY_BTN_MAPPING(m2, btn_pair_m1_m2, btn_pair_side_left); -+ALLY_BTN_MAPPING(m1, btn_pair_m1_m2, btn_pair_side_right); -+ALLY_BTN_MAPPING(a, btn_pair_a_b, btn_pair_side_left); -+ALLY_BTN_MAPPING(b, btn_pair_a_b, btn_pair_side_right); -+ALLY_BTN_MAPPING(x, btn_pair_x_y, btn_pair_side_left); -+ALLY_BTN_MAPPING(y, btn_pair_x_y, btn_pair_side_right); -+ALLY_BTN_MAPPING(lb, btn_pair_lb_rb, btn_pair_side_left); -+ALLY_BTN_MAPPING(rb, btn_pair_lb_rb, btn_pair_side_right); -+ALLY_BTN_MAPPING(ls, btn_pair_ls_rs, btn_pair_side_left); -+ALLY_BTN_MAPPING(rs, btn_pair_ls_rs, btn_pair_side_right); -+ALLY_BTN_MAPPING(lt, btn_pair_lt_rt, btn_pair_side_left); -+ALLY_BTN_MAPPING(rt, btn_pair_lt_rt, btn_pair_side_right); -+ALLY_BTN_MAPPING(dpad_u, btn_pair_dpad_u_d, btn_pair_side_left); -+ALLY_BTN_MAPPING(dpad_d, btn_pair_dpad_u_d, btn_pair_side_right); -+ALLY_BTN_MAPPING(dpad_l, btn_pair_dpad_l_r, btn_pair_side_left); -+ALLY_BTN_MAPPING(dpad_r, btn_pair_dpad_l_r, btn_pair_side_right); -+ALLY_BTN_MAPPING(view, btn_pair_view_menu, btn_pair_side_left); -+ALLY_BTN_MAPPING(menu, btn_pair_view_menu, btn_pair_side_right); -+ -+static void __gamepad_mapping_xpad_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ memcpy(&ally_cfg->key_mapping[0][0], &XPAD_DEF1, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][1], &XPAD_DEF2, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][2], &XPAD_DEF3, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][3], &XPAD_DEF4, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][4], &XPAD_DEF5, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][5], &XPAD_DEF6, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][6], &XPAD_DEF7, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][7], &XPAD_DEF8, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[0][8], &XPAD_DEF9, MAPPING_BLOCK_LEN); -+} -+ -+static void __gamepad_mapping_wasd_default(struct ally_gamepad_cfg *ally_cfg) -+{ -+ memcpy(&ally_cfg->key_mapping[1][0], &WASD_DEF1, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][1], &WASD_DEF2, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][2], &WASD_DEF3, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][3], &WASD_DEF4, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][4], &WASD_DEF5, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][5], &WASD_DEF6, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][6], &WASD_DEF7, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][7], &WASD_DEF8, MAPPING_BLOCK_LEN); -+ memcpy(&ally_cfg->key_mapping[1][8], &WASD_DEF9, MAPPING_BLOCK_LEN); -+} -+ -+static ssize_t 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_mapping_xpad_default(ally_cfg); -+ break; -+ case xpad_mode_wasd: -+ __gamepad_mapping_wasd_default(ally_cfg); -+ break; -+ default: -+ __gamepad_mapping_xpad_default(ally_cfg); -+ break; -+ } -+ -+ return count; -+} -+ -+ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping); -+ -+/* GAMEPAD MODE ***********************************************************************************/ -+static ssize_t __gamepad_set_mode(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg, -+ int val) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_mode; -+ hidbuf[3] = xpad_cmd_len_mode; -+ hidbuf[4] = val; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = __gamepad_write_all_to_mcu(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); -+ -+/* 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_write_vibe_intensity_to_mcu(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_vibe_intensity; -+ hidbuf[3] = xpad_cmd_len_vibe_intensity; -+ hidbuf[4] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left]; -+ hidbuf[5] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right]; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+report_fail: -+ kfree(hidbuf); -+ return ret; -+} -+ -+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[ally_cfg->mode - 1][btn_pair_side_left], -+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right]); -+} -+ -+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[ally_cfg->mode - 1][btn_pair_side_left] = left; -+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right] = right; -+ -+ ret = __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ -+ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity); -+ -+/* ROOT LEVEL ATTRS *******************************************************************************/ -+static struct attribute *gamepad_device_attrs[] = { -+ &dev_attr_gamepad_mode.attr, -+ &dev_attr_btn_mapping_reset.attr, -+ &dev_attr_btn_mapping_apply.attr, -+ &dev_attr_gamepad_vibration_intensity.attr, -+ &dev_attr_gamepad_vibration_intensity_index.attr, -+ NULL -+}; -+ -+static const struct attribute_group ally_controller_attr_group = { -+ .attrs = gamepad_device_attrs, -+}; -+ -+/* ANALOGUE DEADZONES *****************************************************************************/ -+static ssize_t __gamepad_set_deadzones(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_js_dz; -+ hidbuf[3] = xpad_cmd_len_deadzone; -+ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][0][0]; -+ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][0][1]; -+ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][0][2]; -+ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][0][3]; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto end; -+ -+ hidbuf[2] = xpad_cmd_set_tr_dz; -+ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][1][0]; -+ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][1][1]; -+ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][1][2]; -+ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][1][3]; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto end; -+ -+end: -+ kfree(hidbuf); -+ return ret; -+} -+ -+static ssize_t __gamepad_store_deadzones(struct ally_gamepad_cfg *ally_cfg, enum xpad_axis axis, -+ const char *buf) -+{ -+ int cmd, side, is_tr; -+ u32 inner, outer; -+ -+ if (sscanf(buf, "%d %d", &inner, &outer) != 2) -+ return -EINVAL; -+ -+ if (inner > 64 || outer > 64 || inner > outer) -+ return -EINVAL; -+ -+ is_tr = axis > xpad_axis_xy_right; -+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 2 : 0; -+ cmd = is_tr ? xpad_cmd_set_js_dz : xpad_cmd_set_tr_dz; -+ -+ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side] = inner; -+ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side + 1] = outer; -+ -+ return 0; -+} -+ -+static ssize_t 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_AXIS_DEADZONE(xpad_axis_xy_left, deadzone); -+ALLY_AXIS_DEADZONE(xpad_axis_xy_right, deadzone); -+ALLY_AXIS_DEADZONE(xpad_axis_z_left, deadzone); -+ALLY_AXIS_DEADZONE(xpad_axis_z_right, deadzone); -+ -+/* ANTI-DEADZONES *********************************************************************************/ -+static ssize_t __gamepad_write_js_ADZ_to_mcu(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_adz; -+ hidbuf[3] = xpad_cmd_len_adz; -+ hidbuf[4] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left]; -+ hidbuf[5] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right]; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+report_fail: -+ kfree(hidbuf); -+ return ret; -+} -+ -+static ssize_t __gamepad_js_ADZ_store(struct device *dev, const char *buf, -+ enum btn_pair_side side) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ int ret, val; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ -+ if (val < 0 || val > 32) -+ return -EINVAL; -+ -+ ally_cfg->anti_deadzones[ally_cfg->mode - 1][side] = val; -+ -+ return ret; -+} -+ -+static ssize_t xpad_axis_xy_left_ADZ_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->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left]); -+} -+ -+static ssize_t xpad_axis_xy_left_ADZ_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_left); -+ -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ -+ALLY_DEVICE_ATTR_RW(xpad_axis_xy_left_ADZ, anti_deadzone); -+ -+static ssize_t xpad_axis_xy_right_ADZ_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ return sysfs_emit(buf, "%d\n", -+ ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right]); -+} -+ -+static ssize_t xpad_axis_xy_right_ADZ_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_right); -+ -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ -+ALLY_DEVICE_ATTR_RW(xpad_axis_xy_right_ADZ, anti_deadzone); -+ -+/* JS RESPONSE CURVES *****************************************************************************/ -+static ssize_t rc_point_index_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ return sysfs_emit(buf, "move response\n"); -+} -+ -+ALLY_DEVICE_ATTR_RO(rc_point_index, rc_point_index); -+ -+static ssize_t __gamepad_write_response_curves_to_mcu(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __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_response_curve; -+ hidbuf[3] = xpad_cmd_len_response_curve; -+ hidbuf[4] = 0x01; -+ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_left], -+ 8); -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ hidbuf[4] = 0x02; -+ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_right], -+ 8); -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+report_fail: -+ kfree(hidbuf); -+ return ret; -+} -+ -+static ssize_t __gamepad_store_response_curve(struct device *dev, const char *buf, -+ enum btn_pair_side side, int point) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ u32 move, response; -+ int idx; -+ -+ idx = (point - 1) * 2; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ if (sscanf(buf, "%d %d", &move, &response) != 2) -+ return -EINVAL; -+ -+ if (move > 64 || response > 64) -+ return -EINVAL; -+ -+ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx] = move; -+ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx + 1] = response; -+ -+ return 0; -+} -+ -+ALLY_JS_RC_POINT(left, 1, rc_point_); -+ALLY_JS_RC_POINT(left, 2, rc_point_); -+ALLY_JS_RC_POINT(left, 3, rc_point_); -+ALLY_JS_RC_POINT(left, 4, rc_point_); -+ -+ALLY_JS_RC_POINT(right, 1, rc_point_); -+ALLY_JS_RC_POINT(right, 2, rc_point_); -+ALLY_JS_RC_POINT(right, 3, rc_point_); -+ALLY_JS_RC_POINT(right, 4, rc_point_); -+ -+/* CALIBRATIONS ***********************************************************************************/ -+static int __gamepad_get_calibration(struct hid_device *hdev) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ u8 *hidbuf; -+ int ret, i; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ for (i = 0; i < 2; i++) { -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = 0xD0; -+ hidbuf[2] = 0x03; -+ hidbuf[3] = i + 1; // 0x01 JS, 0x02 TR -+ hidbuf[4] = 0x20; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) { -+ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret); -+ goto cleanup; -+ } -+ -+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); -+ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0 || hidbuf[5] != 1) { -+ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret); -+ goto cleanup; -+ } -+ -+ if (i == 0) { -+ /* Joystick calibration */ -+ /* [left][index] is Y: stable, min, max. X: stable, min, max */ -+ ally_cfg->js_calibrations[0][3] = (hidbuf[6] << 8) | hidbuf[7]; -+ ally_cfg->js_calibrations[0][4] = (hidbuf[8] << 8) | hidbuf[9]; -+ ally_cfg->js_calibrations[0][5] = (hidbuf[10] << 8) | hidbuf[11]; -+ ally_cfg->js_calibrations[0][0] = (hidbuf[12] << 8) | hidbuf[13]; -+ ally_cfg->js_calibrations[0][1] = (hidbuf[14] << 8) | hidbuf[15]; -+ ally_cfg->js_calibrations[0][2] = (hidbuf[16] << 8) | hidbuf[17]; -+ /* [right][index] is Y: stable, min, max. X: stable, min, max */ -+ ally_cfg->js_calibrations[1][0] = (hidbuf[24] << 8) | hidbuf[25]; -+ ally_cfg->js_calibrations[1][1] = (hidbuf[26] << 8) | hidbuf[27]; -+ ally_cfg->js_calibrations[1][2] = (hidbuf[28] << 8) | hidbuf[29]; -+ ally_cfg->js_calibrations[1][3] = (hidbuf[18] << 8) | hidbuf[19]; -+ ally_cfg->js_calibrations[1][4] = (hidbuf[20] << 8) | hidbuf[21]; -+ ally_cfg->js_calibrations[1][5] = (hidbuf[22] << 8) | hidbuf[23]; -+ } else { -+ /* Trigger calibration */ -+ /* [left/right][stable/max] */ -+ ally_cfg->tr_calibrations[0][0] = (hidbuf[6] << 8) | hidbuf[7]; -+ ally_cfg->tr_calibrations[0][1] = (hidbuf[8] << 8) | hidbuf[9]; -+ ally_cfg->tr_calibrations[1][0] = (hidbuf[10] << 8) | hidbuf[11]; -+ ally_cfg->tr_calibrations[1][1] = (hidbuf[12] << 8) | hidbuf[13]; -+ } -+ } -+ -+cleanup: -+ kfree(hidbuf); -+ return ret; -+} -+ -+static ssize_t __gamepad_write_cal_to_mcu(struct device *dev, enum xpad_axis axis) -+{ -+ struct hid_device *hdev = to_hid_device(dev); -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ u8 *c, side, pkt_len, data_len; -+ int ret, cal, checksum = 0; -+ u8 *hidbuf; -+ int *head; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; -+ pkt_len = axis > xpad_axis_xy_right ? 0x06 : 0x0E; -+ data_len = axis > xpad_axis_xy_right ? 2 : 6; -+ head = axis > xpad_axis_xy_right ? ally_cfg->tr_calibrations[side] : -+ ally_cfg->js_calibrations[side]; -+ -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_calibration; -+ hidbuf[3] = pkt_len; -+ hidbuf[4] = 0x01; /* second command (write calibration) */ -+ hidbuf[5] = axis; -+ c = &hidbuf[6]; /* pointer to data start */ -+ -+ for (size_t i = 0; i < data_len; i++) { -+ cal = head[i]; -+ *c = (u8)((cal & 0xff00) >> 8); -+ checksum += *c; -+ c += 1; -+ *c = (u8)(cal & 0xff); -+ checksum += *c; -+ c += 1; -+ } -+ -+ hidbuf[6 + data_len * 2] = checksum; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_calibration; -+ hidbuf[3] = xpad_cmd_len_calibration3; -+ hidbuf[4] = 0x03; /* second command (apply the calibration that was written) */ -+ -+ 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_cal_store(struct device *dev, const char *buf, enum xpad_axis axis) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ u32 x_stable, x_min, x_max, y_stable, y_min, y_max, side; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) { -+ if (sscanf(buf, "%d %d %d %d %d %d", &x_stable, &x_min, &x_max, &y_stable, -+ &y_min, &y_max) != 6) -+ return -EINVAL; -+ -+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; -+ /* stored in reverse order for easy copy to packet */ -+ ally_cfg->js_calibrations[side][0] = y_stable; -+ ally_cfg->js_calibrations[side][1] = y_min; -+ ally_cfg->js_calibrations[side][2] = y_max; -+ ally_cfg->js_calibrations[side][3] = x_stable; -+ ally_cfg->js_calibrations[side][4] = x_min; -+ ally_cfg->js_calibrations[side][5] = x_max; -+ -+ return __gamepad_write_cal_to_mcu(dev, axis); -+ } -+ if (sscanf(buf, "%d %d", &x_stable, &x_max) != 2) -+ return -EINVAL; -+ -+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; -+ /* stored in reverse order for easy copy to packet */ -+ ally_cfg->tr_calibrations[side][0] = x_stable; -+ ally_cfg->tr_calibrations[side][1] = x_max; -+ -+ return __gamepad_write_cal_to_mcu(dev, axis); -+} -+ -+static ssize_t __gamepad_cal_show(struct device *dev, char *buf, enum xpad_axis axis) -+{ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; -+ int side = (axis == xpad_axis_xy_right || axis == xpad_axis_z_right) ? 1 : 0; -+ -+ if (!drvdata.gamepad_cfg) -+ return -ENODEV; -+ -+ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) { -+ return sysfs_emit( -+ buf, "%d %d %d %d %d %d\n", ally_cfg->js_calibrations[side][3], -+ ally_cfg->js_calibrations[side][4], ally_cfg->js_calibrations[side][5], -+ ally_cfg->js_calibrations[side][0], ally_cfg->js_calibrations[side][1], -+ ally_cfg->js_calibrations[side][2]); -+ } -+ -+ return sysfs_emit(buf, "%d %d\n", ally_cfg->tr_calibrations[side][0], -+ ally_cfg->tr_calibrations[side][1]); -+} -+ -+ALLY_CAL_ATTR(xpad_axis_xy_left_cal, xpad_axis_xy_left, calibration); -+ALLY_CAL_ATTR(xpad_axis_xy_right_cal, xpad_axis_xy_right, calibration); -+ALLY_CAL_ATTR(xpad_axis_z_left_cal, xpad_axis_z_left, calibration); -+ALLY_CAL_ATTR(xpad_axis_z_right_cal, xpad_axis_z_right, calibration); -+ -+static ssize_t xpad_axis_xy_cal_index_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "x_stable x_min x_max y_stable y_min y_max\n"); -+} -+ -+ALLY_DEVICE_ATTR_RO(xpad_axis_xy_cal_index, calibration_index); -+ -+static ssize_t xpad_axis_z_cal_index_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "z_stable z_max\n"); -+} -+ -+ALLY_DEVICE_ATTR_RO(xpad_axis_z_cal_index, calibration_index); -+ -+static ssize_t __gamepad_cal_reset(struct device *dev, const char *buf, enum xpad_axis axis) -+{ -+ struct hid_device *hdev = to_hid_device(dev); -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ -+ /* Write the reset value, then apply it */ -+ for (u8 cmd = 0x02; cmd <= 0x03; cmd++) { -+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE); -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_calibration; -+ hidbuf[3] = (cmd == 0x02) ? xpad_cmd_len_calibration2 : -+ xpad_cmd_len_calibration3; -+ hidbuf[4] = cmd; -+ hidbuf[5] = axis; -+ -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ break; -+ } -+ -+ __gamepad_get_calibration(hdev); -+ -+ kfree(hidbuf); -+ return ret; -+} -+ -+ALLY_CAL_RESET_ATTR(xpad_axis_xy_left_cal_reset, xpad_axis_xy_left, calibration_reset); -+ALLY_CAL_RESET_ATTR(xpad_axis_xy_right_cal_reset, xpad_axis_xy_right, calibration_reset); -+ALLY_CAL_RESET_ATTR(xpad_axis_z_left_cal_reset, xpad_axis_z_left, calibration_reset); -+ALLY_CAL_RESET_ATTR(xpad_axis_z_right_cal_reset, xpad_axis_z_right, calibration_reset); -+ -+static struct attribute *gamepad_axis_xy_left_attrs[] = { -+ &dev_attr_xpad_axis_xy_left_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_xpad_axis_xy_left_ADZ.attr, -+ &dev_attr_xpad_axis_xy_left_cal_reset.attr, -+ &dev_attr_xpad_axis_xy_left_cal.attr, -+ &dev_attr_xpad_axis_xy_cal_index.attr, -+ &dev_attr_rc_point_left_1.attr, -+ &dev_attr_rc_point_left_2.attr, -+ &dev_attr_rc_point_left_3.attr, -+ &dev_attr_rc_point_left_4.attr, -+ &dev_attr_rc_point_index.attr, -+ NULL -+}; -+static const struct attribute_group ally_controller_axis_xy_left_attr_group = { -+ .name = "axis_xy_left", -+ .attrs = gamepad_axis_xy_left_attrs, -+}; -+ -+static struct attribute *gamepad_axis_xy_right_attrs[] = { -+ &dev_attr_xpad_axis_xy_right_deadzone.attr, -+ &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_xpad_axis_xy_right_ADZ.attr, -+ &dev_attr_xpad_axis_xy_right_cal_reset.attr, -+ &dev_attr_xpad_axis_xy_right_cal.attr, -+ &dev_attr_xpad_axis_xy_cal_index.attr, -+ &dev_attr_rc_point_right_1.attr, -+ &dev_attr_rc_point_right_2.attr, -+ &dev_attr_rc_point_right_3.attr, -+ &dev_attr_rc_point_right_4.attr, -+ &dev_attr_rc_point_index.attr, -+ NULL -+}; -+static const struct attribute_group ally_controller_axis_xy_right_attr_group = { -+ .name = "axis_xy_right", -+ .attrs = gamepad_axis_xy_right_attrs, -+}; -+ -+static struct attribute *gamepad_axis_z_left_attrs[] = { -+ &dev_attr_xpad_axis_z_left_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_xpad_axis_z_left_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr, -+ &dev_attr_xpad_axis_z_left_cal_reset.attr, NULL -+}; -+static const struct attribute_group ally_controller_axis_z_left_attr_group = { -+ .name = "axis_z_left", -+ .attrs = gamepad_axis_z_left_attrs, -+}; -+ -+static struct attribute *gamepad_axis_z_right_attrs[] = { -+ &dev_attr_xpad_axis_z_right_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr, -+ &dev_attr_xpad_axis_z_right_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr, -+ &dev_attr_xpad_axis_z_right_cal_reset.attr, NULL -+}; -+static const struct attribute_group ally_controller_axis_z_right_attr_group = { -+ .name = "axis_z_right", -+ .attrs = gamepad_axis_z_right_attrs, -+}; -+ -+static const struct attribute_group *gamepad_device_attr_groups[] = { -+ &ally_controller_attr_group, -+ &ally_controller_axis_xy_left_attr_group, -+ &ally_controller_axis_xy_right_attr_group, -+ &ally_controller_axis_z_left_attr_group, -+ &ally_controller_axis_z_right_attr_group, -+ &btn_mapping_m1_attr_group, -+ &btn_mapping_m2_attr_group, -+ &btn_mapping_a_attr_group, -+ &btn_mapping_b_attr_group, -+ &btn_mapping_x_attr_group, -+ &btn_mapping_y_attr_group, -+ &btn_mapping_lb_attr_group, -+ &btn_mapping_rb_attr_group, -+ &btn_mapping_ls_attr_group, -+ &btn_mapping_rs_attr_group, -+ &btn_mapping_dpad_u_attr_group, -+ &btn_mapping_dpad_d_attr_group, -+ &btn_mapping_dpad_l_attr_group, -+ &btn_mapping_dpad_r_attr_group, -+ &btn_mapping_view_attr_group, -+ &btn_mapping_menu_attr_group, -+ NULL -+}; -+ -+static int __gamepad_write_all_to_mcu(struct hid_device *hdev, -+ struct ally_gamepad_cfg *ally_cfg) -+{ -+ u8 *hidbuf; -+ int ret; -+ -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_u_d); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_l_r); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_ls_rs); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lb_rb); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_a_b); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_x_y); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_view_menu); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2); -+ if (ret < 0) -+ return ret; -+ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lt_rt); -+ if (ret < 0) -+ return ret; -+ __gamepad_set_deadzones(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ __gamepad_write_js_ADZ_to_mcu(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ __gamepad_write_response_curves_to_mcu(hdev, ally_cfg); -+ if (ret < 0) -+ return ret; -+ ret = __gamepad_check_ready(hdev); -+ if (ret < 0) -+ return ret; -+ -+ /* set turbo */ -+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); -+ if (!hidbuf) -+ return -ENOMEM; -+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID; -+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE; -+ hidbuf[2] = xpad_cmd_set_turbo; -+ hidbuf[3] = xpad_cmd_len_turbo; -+ memcpy(&hidbuf[4], ally_cfg->turbo_btns[ally_cfg->mode - 1], TURBO_BLOCK_LEN); -+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ -+ kfree(hidbuf); -+ return ret; -+} -+ -+static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev) -+{ -+ struct ally_gamepad_cfg *ally_cfg; -+ struct input_dev *input_dev; -+ int i, err; -+ -+ ally_cfg = devm_kzalloc(&hdev->dev, sizeof(*ally_cfg), GFP_KERNEL); -+ if (!ally_cfg) -+ return ERR_PTR(-ENOMEM); -+ ally_cfg->hdev = hdev; -+ -+ input_dev = devm_input_allocate_device(&hdev->dev); -+ if (!input_dev) { -+ err = -ENOMEM; -+ goto free_ally_cfg; -+ } -+ ally_cfg->input = input_dev; -+ -+ input_dev->id.bustype = hdev->bus; -+ input_dev->id.vendor = hdev->vendor; -+ input_dev->id.product = hdev->product; -+ input_dev->id.version = hdev->version; -+ input_dev->uniq = hdev->uniq; -+ input_dev->name = "ASUS ROG Ally Config"; -+ input_set_capability(input_dev, EV_KEY, KEY_PROG1); -+ input_set_capability(input_dev, EV_KEY, KEY_F16); -+ input_set_capability(input_dev, EV_KEY, KEY_F17); -+ input_set_capability(input_dev, EV_KEY, KEY_F18); -+ -+ input_set_drvdata(input_dev, hdev); -+ -+ err = input_register_device(input_dev); -+ if (err) -+ goto free_input_dev; -+ -+ ally_cfg->mode = xpad_mode_game; -+ for (i = 0; i < xpad_mode_mouse; i++) { -+ ally_cfg->deadzones[i][0][1] = 64; -+ ally_cfg->deadzones[i][0][3] = 64; -+ ally_cfg->deadzones[i][1][1] = 64; -+ ally_cfg->deadzones[i][1][3] = 64; -+ ally_cfg->response_curve[i][0][0] = 0x14; -+ ally_cfg->response_curve[i][0][1] = 0x14; -+ ally_cfg->response_curve[i][0][2] = 0x28; -+ ally_cfg->response_curve[i][0][3] = 0x28; -+ ally_cfg->response_curve[i][0][4] = 0x3c; -+ ally_cfg->response_curve[i][0][5] = 0x3c; -+ ally_cfg->response_curve[i][0][6] = 0x63; -+ ally_cfg->response_curve[i][0][7] = 0x63; -+ ally_cfg->response_curve[i][1][0] = 0x14; -+ ally_cfg->response_curve[i][1][1] = 0x14; -+ ally_cfg->response_curve[i][1][2] = 0x28; -+ ally_cfg->response_curve[i][1][3] = 0x28; -+ ally_cfg->response_curve[i][1][4] = 0x3c; -+ ally_cfg->response_curve[i][1][5] = 0x3c; -+ ally_cfg->response_curve[i][1][6] = 0x63; -+ ally_cfg->response_curve[i][1][7] = 0x63; -+ ally_cfg->vibration_intensity[i][0] = 64; -+ ally_cfg->vibration_intensity[i][1] = 64; -+ } -+ drvdata.gamepad_cfg = ally_cfg; -+ -+ /* ignore all errors for this as they are related to USB HID I/O */ -+ __gamepad_mapping_xpad_default(ally_cfg); -+ __gamepad_mapping_wasd_default(ally_cfg); -+ /* these calls will never error so ignore the return */ -+ __gamepad_mapping_store(ally_cfg, KB_M2, btn_pair_m1_m2, btn_pair_side_left, false); -+ __gamepad_mapping_store(ally_cfg, KB_M1, btn_pair_m1_m2, btn_pair_side_right, false); -+ __gamepad_set_mode(hdev, ally_cfg, xpad_mode_game); -+ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2); -+ /* ensure we have data for users to start from */ -+ __gamepad_get_calibration(hdev); -+ -+ if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) { -+ err = -ENODEV; -+ goto unregister_input_dev; -+ } -+ -+ return ally_cfg; -+ -+unregister_input_dev: -+ input_unregister_device(input_dev); -+ ally_cfg->input = NULL; // Prevent double free when kfree(ally_cfg) happens -+ -+free_input_dev: -+ devm_kfree(&hdev->dev, input_dev); -+ -+free_ally_cfg: -+ devm_kfree(&hdev->dev, ally_cfg); -+ return ERR_PTR(err); -+} -+ -+static 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 LED control */ -+/**************************************************************************************************/ -+static void ally_schedule_work(struct ally_rgb_leds *led) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ if (!led->removed) -+ schedule_work(&led->work); -+ spin_unlock_irqrestore(&led->lock, flags); -+ pr_warn("5"); -+} -+ -+static void ally_led_do_brightness(struct work_struct *work) -+{ -+ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work); -+ u8 buf1[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xb4, 0x00, 0x00, 0x00 }; -+ u8 buf[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 }; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ if (!led->update_bright) { -+ spin_unlock_irqrestore(&led->lock, flags); -+ return; -+ } -+ led->update_bright = false; -+ buf[4] = led->brightness; -+ spin_unlock_irqrestore(&led->lock, flags); -+ -+ if (asus_dev_set_report(led->hdev, buf, sizeof(buf)) < 0) -+ hid_err(led->hdev, "Ally failed to set backlight\n"); -+ if (asus_dev_set_report(led->hdev, buf1, sizeof(buf1)) < 0) -+ hid_err(led->hdev, "Ally failed to set backlight\n"); -+} -+ -+static void ally_led_do_rgb(struct work_struct *work) -+{ -+ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work); -+ unsigned long flags; -+ int ret; -+ -+ u8 buf[16] = { [0] = FEATURE_ROG_ALLY_REPORT_ID, -+ [1] = FEATURE_ROG_ALLY_CODE_PAGE, -+ [2] = xpad_cmd_set_leds, -+ [3] = xpad_cmd_len_leds }; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ if (!led->update_rgb) { -+ spin_unlock_irqrestore(&led->lock, flags); -+ return; -+ } -+ for (int i = 0; i < 4; i++) { -+ buf[4 + i * 3] = led->gamepad_red; -+ buf[5 + i * 3] = led->gamepad_green; -+ buf[6 + i * 3] = led->gamepad_blue; -+ } -+ led->update_rgb = false; -+ spin_unlock_irqrestore(&led->lock, flags); -+ -+ ret = asus_dev_set_report(led->hdev, buf, sizeof(buf)); -+ if (ret < 0) -+ hid_err(led->hdev, "Ally failed to set gamepad backlight: %d\n", ret); -+} -+ -+static void ally_led_work(struct work_struct *work) -+{ -+ ally_led_do_brightness(work); -+ ally_led_do_rgb(work); -+} -+ -+static void ally_backlight_set(struct led_classdev *led_cdev, enum led_brightness brightness) -+{ -+ struct ally_rgb_leds *led = -+ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ led->update_bright = true; -+ led->brightness = brightness; -+ spin_unlock_irqrestore(&led->lock, flags); -+ -+ ally_schedule_work(led); -+} -+ -+static enum led_brightness ally_backlight_get(struct led_classdev *led_cdev) -+{ -+ struct ally_rgb_leds *led = -+ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev); -+ enum led_brightness brightness; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led->lock, flags); -+ brightness = led->brightness; -+ spin_unlock_irqrestore(&led->lock, flags); -+ -+ return brightness; -+} -+ -+static void ally_set_rgb_brightness(struct led_classdev *cdev, enum led_brightness brightness) -+{ -+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); -+ struct ally_rgb_leds *led = container_of(mc_cdev, struct ally_rgb_leds, led_rgb_dev); -+ unsigned long flags; -+ -+ led_mc_calc_color_components(mc_cdev, brightness); -+ spin_lock_irqsave(&led->lock, flags); -+ led->update_rgb = true; -+ led->gamepad_red = mc_cdev->subled_info[0].brightness; -+ led->gamepad_green = mc_cdev->subled_info[1].brightness; -+ led->gamepad_blue = mc_cdev->subled_info[2].brightness; -+ spin_unlock_irqrestore(&led->lock, flags); -+ -+ ally_schedule_work(led); -+} -+ -+static int ally_gamepad_register_brightness(struct hid_device *hdev, -+ struct ally_rgb_leds *led_rgb) -+{ -+ struct led_classdev *led_cdev; -+ -+ led_cdev = &led_rgb->led_bright_dev; -+ led_cdev->name = "ally:kbd_backlight"; /* Let a desktop control it also */ -+ led_cdev->max_brightness = 3; -+ led_cdev->brightness_set = ally_backlight_set; -+ led_cdev->brightness_get = ally_backlight_get; -+ -+ return devm_led_classdev_register(&hdev->dev, &led_rgb->led_bright_dev); -+} -+ -+static int ally_gamepad_register_rgb_leds(struct hid_device *hdev, -+ struct ally_rgb_leds *led_rgb) -+{ -+ struct mc_subled *mc_led_info; -+ struct led_classdev *led_cdev; -+ -+ mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info), -+ GFP_KERNEL | __GFP_ZERO); -+ if (!mc_led_info) -+ return -ENOMEM; -+ -+ mc_led_info[0].color_index = LED_COLOR_ID_RED; -+ mc_led_info[1].color_index = LED_COLOR_ID_GREEN; -+ mc_led_info[2].color_index = LED_COLOR_ID_BLUE; -+ -+ led_rgb->led_rgb_dev.subled_info = mc_led_info; -+ led_rgb->led_rgb_dev.num_colors = 3; -+ -+ led_cdev = &led_rgb->led_rgb_dev.led_cdev; -+ led_cdev->name = "ally:rgb:gamepad"; -+ led_cdev->brightness = 128; -+ led_cdev->max_brightness = 255; -+ led_cdev->brightness_set = ally_set_rgb_brightness; -+ -+ return devm_led_classdev_multicolor_register(&hdev->dev, &led_rgb->led_rgb_dev); -+} -+ -+static struct ally_rgb_leds *ally_gamepad_rgb_create(struct hid_device *hdev) -+{ -+ struct ally_rgb_leds *led_rgb; -+ int ret; -+ -+ led_rgb = devm_kzalloc(&hdev->dev, sizeof(struct ally_rgb_leds), GFP_KERNEL); -+ if (!led_rgb) -+ return ERR_PTR(-ENOMEM); -+ -+ ret = ally_gamepad_register_rgb_leds(hdev, led_rgb); -+ if (ret < 0) { -+ cancel_work_sync(&led_rgb->work); -+ devm_kfree(&hdev->dev, led_rgb); -+ return ERR_PTR(ret); -+ } -+ -+ ret = ally_gamepad_register_brightness(hdev, led_rgb); -+ if (ret < 0) { -+ cancel_work_sync(&led_rgb->work); -+ devm_kfree(&hdev->dev, led_rgb); -+ return ERR_PTR(ret); -+ } -+ -+ led_rgb->hdev = hdev; -+ led_rgb->brightness = 3; -+ led_rgb->removed = false; -+ -+ INIT_WORK(&led_rgb->work, ally_led_work); -+ spin_lock_init(&led_rgb->lock); -+ -+ return led_rgb; -+} -+ -+static void ally_rgb_remove(struct hid_device *hdev) -+{ -+ struct ally_rgb_leds *led_rgb = drvdata.led_rgb; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&led_rgb->lock, flags); -+ led_rgb->removed = true; -+ spin_unlock_irqrestore(&led_rgb->lock, flags); -+ cancel_work_sync(&led_rgb->work); -+} -+ -+/**************************************************************************************************/ -+/* ROG Ally driver init */ -+/**************************************************************************************************/ -+static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, -+ int size) -+{ -+ struct ally_gamepad_cfg *cfg = drvdata.gamepad_cfg; -+ struct ally_x_device *ally_x = drvdata.ally_x; -+ -+ if (ally_x) { -+ if ((hdev->bus == BUS_USB && report->id == ALLY_X_INPUT_REPORT_USB && -+ size == ALLY_X_INPUT_REPORT_USB_SIZE) || -+ (cfg && data[0] == 0x5A)) { -+ ally_x_raw_event(ally_x, report, data, size); -+ } else { -+ return -1; -+ } -+ } -+ 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; -+} -+ -+static int ally_gamepad_init(struct hid_device *hdev, u8 report_id) -+{ -+ const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, 0x65, -+ 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; -+ int ret; -+ -+ ret = asus_dev_set_report(hdev, buf, sizeof(buf)); -+ if (ret < 0) -+ hid_err(hdev, "Ally failed to send init command: %d\n", ret); -+ -+ return ret; -+} -+ -+static int ally_probe(struct hid_device *hdev, const struct hid_device_id *id) -+{ -+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); -+ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint; -+ int ret; -+ -+ if (ep->desc.bEndpointAddress != ALLY_CFG_INTF_IN_ADDRESS && -+ ep->desc.bEndpointAddress != ALLY_X_INTERFACE_ADDRESS) -+ return -ENODEV; -+ -+ ret = hid_parse(hdev); -+ if (ret) { -+ hid_err(hdev, "Parse failed\n"); -+ return ret; -+ } -+ -+ 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_gamepad_init(hdev, FEATURE_REPORT_ID); -+ if (ret < 0) -+ return ret; -+ -+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1); -+ if (ret < 0) -+ return ret; -+ -+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2); -+ if (ret < 0) -+ return ret; -+ -+ drvdata.hdev = hdev; -+ hid_set_drvdata(hdev, &drvdata); -+ -+ /* This should almost always exist */ -+ if (ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS) { -+ drvdata.led_rgb = ally_gamepad_rgb_create(hdev); -+ if (IS_ERR(drvdata.led_rgb)) -+ hid_err(hdev, "Failed to create Ally gamepad LEDs.\n"); -+ else -+ hid_info(hdev, "Created Ally RGB LED controls.\n"); -+ -+ ally_gamepad_cfg_create(hdev); // assigns self -+ if (IS_ERR(drvdata.gamepad_cfg)) -+ hid_err(hdev, "Failed to create Ally gamepad attributes.\n"); -+ else -+ hid_info(hdev, "Created Ally gamepad attributes.\n"); -+ -+ if (IS_ERR(drvdata.led_rgb) && IS_ERR(drvdata.gamepad_cfg)) -+ goto err_close; -+ } -+ -+ /* May or may not exist */ -+ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS) { -+ drvdata.ally_x = ally_x_create(hdev); -+ if (IS_ERR(drvdata.ally_x)) { -+ hid_err(hdev, "Failed to create Ally X gamepad.\n"); -+ drvdata.ally_x = NULL; -+ goto err_close; -+ } -+ hid_info(hdev, "Created Ally X controller.\n"); -+ -+ // Not required since we send this inputs ep through the gamepad input dev -+ if (drvdata.gamepad_cfg && drvdata.gamepad_cfg->input) { -+ input_unregister_device(drvdata.gamepad_cfg->input); -+ hid_info(hdev, "Ally X removed unrequired input dev.\n"); -+ } -+ } -+ -+ return 0; -+ -+err_close: -+ hid_hw_close(hdev); -+err_stop: -+ hid_hw_stop(hdev); -+ return ret; -+} -+ -+static void ally_remove(struct hid_device *hdev) -+{ -+ if (drvdata.ally_x) -+ ally_x_remove(hdev); -+ if (drvdata.led_rgb) -+ ally_rgb_remove(hdev); -+ if (drvdata.gamepad_cfg) -+ ally_cfg_remove(hdev); -+ hid_hw_close(hdev); -+ hid_hw_stop(hdev); -+} -+ -+static int ally_resume(struct hid_device *hdev) -+{ -+ int ret; -+ -+ ret = ally_gamepad_init(hdev, FEATURE_REPORT_ID); -+ if (ret < 0) -+ return ret; -+ -+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1); -+ if (ret < 0) -+ return ret; -+ -+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2); -+ if (ret < 0) -+ return ret; -+ -+ if (drvdata.ally_x && drvdata.ally_x->output_worker_initialized) -+ schedule_work(&drvdata.ally_x->output_worker); -+ -+ return ret; -+} -+ -+MODULE_DEVICE_TABLE(hid, rog_ally_devices); -+ -+static struct hid_driver rog_ally_cfg = { -+ .name = "asus_rog_ally", -+ .id_table = rog_ally_devices, -+ .probe = ally_probe, -+ .remove = ally_remove, -+ .raw_event = ally_raw_event, -+ .resume = ally_resume, -+}; -+ -+static int __init rog_ally_cfg_init(void) -+{ -+ return hid_register_driver(&rog_ally_cfg); -+} -+ -+static void __exit rog_ally_cfg_exit(void) -+{ -+ hid_unregister_driver(&rog_ally_cfg); -+} -+ -+module_init(rog_ally_cfg_init); -+module_exit(rog_ally_cfg_exit); -+ -+MODULE_AUTHOR("Luke D. Jones"); -+MODULE_DESCRIPTION("HID Driver for ASUS ROG Ally gamepad configuration."); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h -new file mode 100644 -index 000000000000..252d9f126e32 ---- /dev/null -+++ b/drivers/hid/hid-asus-ally.h -@@ -0,0 +1,544 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later -+ * -+ * HID driver for Asus ROG laptops and Ally -+ * -+ * Copyright (c) 2023 Luke Jones <luke@ljones.dev> -+ */ -+ -+#include <linux/hid.h> -+#include <linux/types.h> -+ -+#define ALLY_X_INTERFACE_ADDRESS 0x87 -+ -+#define BTN_CODE_LEN 11 -+#define MAPPING_BLOCK_LEN 44 -+ -+#define TURBO_BLOCK_LEN 32 -+#define TURBO_BLOCK_STEP 2 -+ -+#define PAD_A "pad_a" -+#define PAD_B "pad_b" -+#define PAD_X "pad_x" -+#define PAD_Y "pad_y" -+#define PAD_LB "pad_lb" -+#define PAD_RB "pad_rb" -+#define PAD_LS "pad_ls" -+#define PAD_RS "pad_rs" -+#define PAD_DPAD_UP "pad_dpad_up" -+#define PAD_DPAD_DOWN "pad_dpad_down" -+#define PAD_DPAD_LEFT "pad_dpad_left" -+#define PAD_DPAD_RIGHT "pad_dpad_right" -+#define PAD_VIEW "pad_view" -+#define PAD_MENU "pad_menu" -+#define PAD_XBOX "pad_xbox" -+ -+#define KB_M1 "kb_m1" -+#define KB_M2 "kb_m2" -+#define KB_ESC "kb_esc" -+#define KB_F1 "kb_f1" -+#define KB_F2 "kb_f2" -+#define KB_F3 "kb_f3" -+#define KB_F4 "kb_f4" -+#define KB_F5 "kb_f5" -+#define KB_F6 "kb_f6" -+#define KB_F7 "kb_f7" -+#define KB_F8 "kb_f8" -+#define KB_F9 "kb_f9" -+#define KB_F10 "kb_f10" -+#define KB_F11 "kb_f11" -+#define KB_F12 "kb_f12" -+#define KB_F14 "kb_f14" -+#define KB_F15 "kb_f15" -+ -+#define KB_BACKTICK "kb_backtick" -+#define KB_1 "kb_1" -+#define KB_2 "kb_2" -+#define KB_3 "kb_3" -+#define KB_4 "kb_4" -+#define KB_5 "kb_5" -+#define KB_6 "kb_6" -+#define KB_7 "kb_7" -+#define KB_8 "kb_8" -+#define KB_9 "kb_9" -+#define KB_0 "kb_0" -+#define KB_HYPHEN "kb_hyphen" -+#define KB_EQUALS "kb_equals" -+#define KB_BACKSPACE "kb_backspace" -+ -+#define KB_TAB "kb_tab" -+#define KB_Q "kb_q" -+#define KB_W "kb_w" -+#define KB_E "kb_e" -+#define KB_R "kb_r" -+#define KB_T "kb_t" -+#define KB_Y "kb_y" -+#define KB_U "kb_u" -+#define KB_I "kb_i" -+#define KB_O "kb_o" -+#define KB_P "kb_p" -+#define KB_LBRACKET "kb_lbracket" -+#define KB_RBRACKET "kb_rbracket" -+#define KB_BACKSLASH "kb_bkslash" -+ -+#define KB_CAPS "kb_caps" -+#define KB_A "kb_a" -+#define KB_S "kb_s" -+#define KB_D "kb_d" -+#define KB_F "kb_f" -+#define KB_G "kb_g" -+#define KB_H "kb_h" -+#define KB_J "kb_j" -+#define KB_K "kb_k" -+#define KB_L "kb_l" -+#define KB_SEMI "kb_semicolon" -+#define KB_QUOTE "kb_quote" -+#define KB_RET "kb_enter" -+ -+#define KB_LSHIFT "kb_lshift" -+#define KB_Z "kb_z" -+#define KB_X "kb_x" -+#define KB_C "kb_c" -+#define KB_V "kb_v" -+#define KB_B "kb_b" -+#define KB_N "kb_n" -+#define KB_M "kb_m" -+#define KB_COMMA "kb_comma" -+#define KB_PERIOD "kb_period" -+#define KB_FWDSLASH "kb_fwdslash" -+#define KB_RSHIFT "kb_rshift" -+ -+#define KB_LCTL "kb_lctl" -+#define KB_META "kb_meta" -+#define KB_LALT "kb_lalt" -+#define KB_SPACE "kb_space" -+#define KB_RALT "kb_ralt" -+#define KB_MENU "kb_menu" -+#define KB_RCTL "kb_rctl" -+ -+#define KB_PRNTSCN "kb_prntscn" -+#define KB_SCRLCK "kb_scrlck" -+#define KB_PAUSE "kb_pause" -+#define KB_INS "kb_ins" -+#define KB_HOME "kb_home" -+#define KB_PGUP "kb_pgup" -+#define KB_DEL "kb_del" -+#define KB_END "kb_end" -+#define KB_PGDWN "kb_pgdwn" -+ -+#define KB_UP_ARROW "kb_up_arrow" -+#define KB_DOWN_ARROW "kb_down_arrow" -+#define KB_LEFT_ARROW "kb_left_arrow" -+#define KB_RIGHT_ARROW "kb_right_arrow" -+ -+#define NUMPAD_LOCK "numpad_lock" -+#define NUMPAD_FWDSLASH "numpad_fwdslash" -+#define NUMPAD_ASTERISK "numpad_asterisk" -+#define NUMPAD_HYPHEN "numpad_hyphen" -+#define NUMPAD_0 "numpad_0" -+#define NUMPAD_1 "numpad_1" -+#define NUMPAD_2 "numpad_2" -+#define NUMPAD_3 "numpad_3" -+#define NUMPAD_4 "numpad_4" -+#define NUMPAD_5 "numpad_5" -+#define NUMPAD_6 "numpad_6" -+#define NUMPAD_7 "numpad_7" -+#define NUMPAD_8 "numpad_8" -+#define NUMPAD_9 "numpad_9" -+#define NUMPAD_PLUS "numpad_plus" -+#define NUMPAD_ENTER "numpad_enter" -+#define NUMPAD_PERIOD "numpad_." -+ -+#define MOUSE_LCLICK "rat_lclick" -+#define MOUSE_RCLICK "rat_rclick" -+#define MOUSE_MCLICK "rat_mclick" -+#define MOUSE_WHEEL_UP "rat_wheel_up" -+#define MOUSE_WHEEL_DOWN "rat_wheel_down" -+ -+#define MEDIA_SCREENSHOT "media_screenshot" -+#define MEDIA_SHOW_KEYBOARD "media_show_keyboard" -+#define MEDIA_SHOW_DESKTOP "media_show_desktop" -+#define MEDIA_START_RECORDING "media_start_recording" -+#define MEDIA_MIC_OFF "media_mic_off" -+#define MEDIA_VOL_DOWN "media_vol_down" -+#define MEDIA_VOL_UP "media_vol_up" -+ -+/* required so we can have nested attributes with same name but different functions */ -+#define ALLY_DEVICE_ATTR_RW(_name, _sysfs_name) \ -+ struct device_attribute dev_attr_##_name = \ -+ __ATTR(_sysfs_name, 0644, _name##_show, _name##_store) -+ -+#define ALLY_DEVICE_ATTR_RO(_name, _sysfs_name) \ -+ struct device_attribute dev_attr_##_name = \ -+ __ATTR(_sysfs_name, 0444, _name##_show, NULL) -+ -+#define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \ -+ struct device_attribute dev_attr_##_name = \ -+ __ATTR(_sysfs_name, 0200, NULL, _name##_store) -+ -+/* response curve macros */ -+#define ALLY_RESP_CURVE_SHOW(_name, _point_n) \ -+ static ssize_t _name##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ int idx = (_point_n - 1) * 2; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ return sysfs_emit( \ -+ buf, "%d %d\n", \ -+ ally_cfg->response_curve[ally_cfg->mode] \ -+ [btn_pair_side_left][idx], \ -+ ally_cfg->response_curve[ally_cfg->mode] \ -+ [btn_pair_side_right] \ -+ [idx + 1]); \ -+ } -+ -+#define ALLY_RESP_CURVE_STORE(_name, _side, _point_n) \ -+ static ssize_t _name##_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ int ret = __gamepad_store_response_curve( \ -+ dev, buf, btn_pair_side_##_side, _point_n); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+/* _point_n must start at 1 */ -+#define ALLY_JS_RC_POINT(_side, _point_n, _sysfs_label) \ -+ ALLY_RESP_CURVE_SHOW(rc_point_##_side##_##_point_n, _point_n); \ -+ ALLY_RESP_CURVE_STORE(rc_point_##_side##_##_point_n, _side, _point_n); \ -+ ALLY_DEVICE_ATTR_RW(rc_point_##_side##_##_point_n, \ -+ _sysfs_label##_point_n) -+ -+/* deadzone macros */ -+#define ALLY_AXIS_DEADZONE_SHOW(_axis) \ -+ static ssize_t _axis##_deadzone_show( \ -+ struct device *dev, struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ int side, is_tr; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ is_tr = _axis > xpad_axis_xy_right; \ -+ side = _axis == xpad_axis_xy_right || \ -+ _axis == xpad_axis_z_right ? \ -+ 2 : \ -+ 0; \ -+ return sysfs_emit( \ -+ buf, "%d %d\n", \ -+ ally_cfg->deadzones[ally_cfg->mode][is_tr][side], \ -+ ally_cfg->deadzones[ally_cfg->mode][is_tr][side + 1]); \ -+ } -+ -+#define ALLY_AXIS_DEADZONE_STORE(_axis) \ -+ static ssize_t _axis##_deadzone_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ int ret = __gamepad_store_deadzones(ally_cfg, _axis, buf); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+#define ALLY_AXIS_DEADZONE(_axis, _sysfs_label) \ -+ ALLY_AXIS_DEADZONE_SHOW(_axis); \ -+ ALLY_AXIS_DEADZONE_STORE(_axis); \ -+ ALLY_DEVICE_ATTR_RW(_axis##_deadzone, _sysfs_label) -+ -+/* button specific macros */ -+#define ALLY_BTN_SHOW(_fname, _pair, _side, _secondary) \ -+ static ssize_t _fname##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ return sysfs_emit(buf, "%s\n", \ -+ __btn_map_to_string(ally_cfg, _pair, _side, \ -+ _secondary)); \ -+ } -+ -+#define ALLY_BTN_STORE(_fname, _pair, _side, _secondary) \ -+ static ssize_t _fname##_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \ -+ if (!drvdata.gamepad_cfg) \ -+ return -ENODEV; \ -+ int ret = __gamepad_mapping_store(ally_cfg, buf, _pair, _side, \ -+ _secondary); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+#define ALLY_BTN_TURBO_SHOW(_fname, _pair, _side) \ -+ static ssize_t _fname##_turbo_show( \ -+ struct device *dev, struct device_attribute *attr, char *buf) \ -+ { \ -+ return sysfs_emit(buf, "%d\n", \ -+ __gamepad_turbo_show(dev, _pair, _side)); \ -+ } -+ -+#define ALLY_BTN_TURBO_STORE(_fname, _pair, _side) \ -+ static ssize_t _fname##_turbo_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ int ret = __gamepad_turbo_store(dev, buf, _pair, _side); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+#define ALLY_BTN_ATTRS_GROUP(_name, _fname) \ -+ static struct attribute *_fname##_attrs[] = { \ -+ &dev_attr_##_fname.attr, &dev_attr_##_fname##_macro.attr, \ -+ &dev_attr_##_fname##_turbo.attr, NULL \ -+ }; \ -+ static const struct attribute_group _fname##_attr_group = { \ -+ .name = __stringify(_name), \ -+ .attrs = _fname##_attrs, \ -+ } -+ -+#define ALLY_BTN_MAPPING(_fname, _pair, _side) \ -+ ALLY_BTN_SHOW(btn_mapping_##_fname, _pair, _side, false); \ -+ ALLY_BTN_STORE(btn_mapping_##_fname, _pair, _side, false); \ -+ ALLY_BTN_SHOW(btn_mapping_##_fname##_macro, _pair, _side, true); \ -+ ALLY_BTN_STORE(btn_mapping_##_fname##_macro, _pair, _side, true); \ -+ ALLY_BTN_TURBO_SHOW(btn_mapping_##_fname, _pair, _side); \ -+ ALLY_BTN_TURBO_STORE(btn_mapping_##_fname, _pair, _side); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname, remap); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_macro, macro_remap); \ -+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_turbo, turbo); \ -+ ALLY_BTN_ATTRS_GROUP(btn_##_fname, btn_mapping_##_fname) -+ -+/* calibration macros */ -+#define ALLY_CAL_STORE(_fname, _axis) \ -+ static ssize_t _fname##_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ int ret = __gamepad_cal_store(dev, buf, _axis); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+#define ALLY_CAL_SHOW(_fname, _axis) \ -+ static ssize_t _fname##_show(struct device *dev, \ -+ struct device_attribute *attr, char *buf) \ -+ { \ -+ return __gamepad_cal_show(dev, buf, _axis); \ -+ } -+ -+#define ALLY_CAL_ATTR(_fname, _axis, _sysfs_label) \ -+ ALLY_CAL_STORE(_fname, _axis); \ -+ ALLY_CAL_SHOW(_fname, _axis); \ -+ ALLY_DEVICE_ATTR_RW(_fname, _sysfs_label) -+ -+#define ALLY_CAL_RESET_STORE(_fname, _axis) \ -+ static ssize_t _fname##_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ int ret = __gamepad_cal_reset(dev, buf, _axis); \ -+ if (ret < 0) \ -+ return ret; \ -+ return count; \ -+ } -+ -+#define ALLY_CAL_RESET_ATTR(_fname, _axis, _sysfs_label) \ -+ ALLY_CAL_RESET_STORE(_fname, _axis); \ -+ ALLY_DEVICE_ATTR_WO(_fname, _sysfs_label) -+ -+/* -+ * The following blocks of packets exist to make setting a default boot config -+ * easier. They were directly captured from setting the gamepad up. -+ */ -+ -+/* Default blocks for the xpad mode */ -+static const u8 XPAD_DEF1[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF2[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00, -+ 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF3[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF4[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF5[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF6[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00, -+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF7[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF8[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 XPAD_DEF9[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+ -+/* default blocks for the wasd mode */ -+static const u8 WASD_DEF1[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00 -+}; -+static const u8 WASD_DEF2[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF3[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF4[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF5[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF6[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF7[MAPPING_BLOCK_LEN] = { -+ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF8[MAPPING_BLOCK_LEN] = { -+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+static const u8 WASD_DEF9[MAPPING_BLOCK_LEN] = { -+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x0d, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+ -+/* -+ * the xpad_mode is used inside the mode setting packet and is used -+ * for indexing (xpad_mode - 1) -+ */ -+enum xpad_mode { -+ xpad_mode_game = 0x01, -+ xpad_mode_wasd = 0x02, -+ xpad_mode_mouse = 0x03, -+}; -+ -+/* the xpad_cmd determines which feature is set or queried */ -+enum xpad_cmd { -+ xpad_cmd_set_mode = 0x01, -+ xpad_cmd_set_mapping = 0x02, -+ xpad_cmd_set_js_dz = 0x04, /* deadzones */ -+ xpad_cmd_set_tr_dz = 0x05, /* deadzones */ -+ xpad_cmd_set_vibe_intensity = 0x06, -+ xpad_cmd_set_leds = 0x08, -+ xpad_cmd_check_ready = 0x0A, -+ xpad_cmd_set_calibration = 0x0D, -+ xpad_cmd_set_turbo = 0x0F, -+ xpad_cmd_set_response_curve = 0x13, -+ xpad_cmd_set_adz = 0x18, -+}; -+ -+/* the xpad_cmd determines which feature is set or queried */ -+enum xpad_cmd_len { -+ xpad_cmd_len_mode = 0x01, -+ xpad_cmd_len_mapping = 0x2c, -+ xpad_cmd_len_deadzone = 0x04, -+ xpad_cmd_len_vibe_intensity = 0x02, -+ xpad_cmd_len_leds = 0x0C, -+ xpad_cmd_len_calibration2 = 0x01, -+ xpad_cmd_len_calibration3 = 0x01, -+ xpad_cmd_len_turbo = 0x20, -+ xpad_cmd_len_response_curve = 0x09, -+ xpad_cmd_len_adz = 0x02, -+}; -+ -+/* -+ * the xpad_mode is used in various set and query HID packets and is -+ * used for indexing (xpad_axis - 1) -+ */ -+enum xpad_axis { -+ xpad_axis_xy_left = 0x01, -+ xpad_axis_xy_right = 0x02, -+ xpad_axis_z_left = 0x03, -+ xpad_axis_z_right = 0x04, -+}; -+ -+enum btn_pair { -+ btn_pair_dpad_u_d = 0x01, -+ btn_pair_dpad_l_r = 0x02, -+ btn_pair_ls_rs = 0x03, -+ btn_pair_lb_rb = 0x04, -+ btn_pair_a_b = 0x05, -+ btn_pair_x_y = 0x06, -+ btn_pair_view_menu = 0x07, -+ btn_pair_m1_m2 = 0x08, -+ btn_pair_lt_rt = 0x09, -+}; -+ -+enum btn_pair_side { -+ btn_pair_side_left = 0x00, -+ btn_pair_side_right = 0x01, -+}; -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index 37e6d25593c2..9f83a770de8d 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); - #define FEATURE_KBD_LED_REPORT_ID1 0x5d - #define FEATURE_KBD_LED_REPORT_ID2 0x5e - -+#define ALLY_CFG_INTF_IN_ADDRESS 0x83 -+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04 -+#define ALLY_X_INTERFACE_ADDRESS 0x87 -+ - #define SUPPORT_KBD_BACKLIGHT BIT(0) - - #define MAX_TOUCH_MAJOR 8 -@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); - #define QUIRK_MEDION_E1239T BIT(10) - #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) - #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) -+#define QUIRK_ROG_ALLY_XPAD BIT(13) - - #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ - QUIRK_NO_INIT_REPORTS | \ -@@ -492,12 +497,19 @@ static void asus_kbd_backlight_work(struct work_struct *work) - */ - static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev) - { -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); - u32 value; - int ret; - - if (!IS_ENABLED(CONFIG_ASUS_WMI)) - return false; - -+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && -+ dmi_check_system(asus_use_hid_led_dmi_ids)) { -+ hid_info(hdev, "using HID for asus::kbd_backlight\n"); -+ return false; -+ } -+ - ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, - ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value); - hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value); -@@ -996,6 +1008,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) - - drvdata->quirks = id->driver_data; - -+ /* Ignore these endpoints as they will be used by other drivers */ -+ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { -+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent); -+ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint; -+ -+ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS || -+ ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS || -+ ep->desc.bEndpointAddress == ALLY_CFG_INTF_OUT_ADDRESS) -+ return -ENODEV; -+ } -+ - /* - * T90CHI's keyboard dock returns same ID values as T100CHI's dock. - * Thus, identify T90CHI dock with product name string. -@@ -1247,6 +1270,12 @@ static const struct hid_device_id asus_devices[] = { - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), -+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD}, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, -+ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), -+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, -+ USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD), - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 72d56ee7ce1b..57f1f1bc5eb6 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -209,7 +209,10 @@ - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 - #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 -+#define USB_DEVICE_ID_ASUSTEK_ROG_RAIKIRI_PAD 0x1abb - #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe -+#define USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD 0x1a83 -+#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c - #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b - #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 - -diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index ddfccc226751..d13c4085c228 100644 ---- a/drivers/platform/x86/Kconfig -+++ b/drivers/platform/x86/Kconfig -@@ -265,6 +265,19 @@ config ASUS_WIRELESS - If you choose to compile this driver as a module the module will be - called asus-wireless. - -+config ASUS_ARMOURY -+ tristate "ASUS Armoury (firmware) Driver" -+ depends on ACPI_WMI -+ depends on ASUS_WMI -+ select FW_ATTR_CLASS -+ help -+ Say Y here if you have a WMI aware Asus laptop and would like to use the -+ firmware_attributes API to control various settings typically exposed in -+ the ASUS Armoury Crate application available on Windows. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called asus-armoury. -+ - config ASUS_WMI - tristate "ASUS WMI Driver" - depends on ACPI_WMI -@@ -276,6 +289,7 @@ config ASUS_WMI - depends on HOTPLUG_PCI - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on SERIO_I8042 || SERIO_I8042 = n -+ select ASUS_ARMOURY - select INPUT_SPARSEKMAP - select LEDS_CLASS - select NEW_LEDS -diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index e1b142947067..fe3e7e7dede8 100644 ---- a/drivers/platform/x86/Makefile -+++ b/drivers/platform/x86/Makefile -@@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o - # ASUS - obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o - obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o -+obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o - obj-$(CONFIG_ASUS_WMI) += asus-wmi.o - obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o - obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o -diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c -index 0b2eb0ae85fe..460444cda1b2 100644 ---- a/drivers/platform/x86/amd/pmf/pmf-quirks.c -+++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c -@@ -29,6 +29,14 @@ static const struct dmi_system_id fwbug_list[] = { - }, - .driver_data = &quirk_no_sps_bug, - }, -+ { -+ .ident = "ROG Ally X", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "RC72LA"), -+ }, -+ .driver_data = &quirk_no_sps_bug, -+ }, - {} - }; - -@@ -48,4 +56,3 @@ void amd_pmf_quirks_init(struct amd_pmf_dev *dev) - dmi_id->ident); - } - } -- -diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c -new file mode 100644 -index 000000000000..aa784b6b9483 ---- /dev/null -+++ b/drivers/platform/x86/asus-armoury.c -@@ -0,0 +1,1049 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes -+ * class to expose the various WMI functions that many gaming and some -+ * non-gaming ASUS laptops have available. -+ * These typically don't fit anywhere else in the sysfs such as under LED class, -+ * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool. -+ * -+ * Copyright(C) 2010 Intel Corporation. -+ * Copyright(C) 2024-2024 Luke Jones <luke@ljones.dev> -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include <linux/platform_data/x86/asus-wmi.h> -+#include <linux/errno.h> -+#include <linux/fs.h> -+#include <linux/types.h> -+#include <linux/dmi.h> -+#include <linux/device.h> -+#include <linux/kmod.h> -+#include <linux/kobject.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/kernel.h> -+#include "asus-armoury.h" -+#include "firmware_attributes_class.h" -+ -+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" -+ -+#define ASUS_MINI_LED_MODE_MASK 0x03 -+/* Standard modes for devices with only on/off */ -+#define ASUS_MINI_LED_OFF 0x00 -+#define ASUS_MINI_LED_ON 0x01 -+/* New mode on some devices, define here to clarify remapping later */ -+#define ASUS_MINI_LED_STRONG_MODE 0x02 -+/* New modes for devices with 3 mini-led mode types */ -+#define ASUS_MINI_LED_2024_WEAK 0x00 -+#define ASUS_MINI_LED_2024_STRONG 0x01 -+#define ASUS_MINI_LED_2024_OFF 0x02 -+ -+enum cpu_core_type { -+ CPU_CORE_PERF = 0, -+ CPU_CORE_POWER, -+}; -+ -+enum cpu_core_value { -+ CPU_CORE_DEFAULT = 0, -+ CPU_CORE_MIN, -+ CPU_CORE_MAX, -+ CPU_CORE_CURRENT, -+}; -+ -+/* Default limits for tunables available on ASUS ROG laptops */ -+#define PPT_CPU_LIMIT_MIN 5 -+#define PPT_CPU_LIMIT_MAX 150 -+#define PPT_CPU_LIMIT_DEFAULT 80 -+#define PPT_PLATFORM_MIN 5 -+#define PPT_PLATFORM_MAX 100 -+#define PPT_PLATFORM_DEFAULT 80 -+#define NVIDIA_BOOST_MIN 5 -+#define NVIDIA_BOOST_MAX 25 -+#define NVIDIA_TEMP_MIN 75 -+#define NVIDIA_TEMP_MAX 87 -+#define NVIDIA_POWER_MIN 0 -+#define NVIDIA_POWER_MAX 70 -+#define NVIDIA_POWER_DEFAULT 70 -+ -+/* Tunables provided by ASUS for gaming laptops */ -+struct rog_tunables { -+ u32 cpu_default; -+ u32 cpu_min; -+ u32 cpu_max; -+ -+ u32 platform_default; -+ u32 platform_min; -+ u32 platform_max; -+ -+ u32 ppt_pl1_spl; // cpu -+ u32 ppt_pl2_sppt; // cpu -+ u32 ppt_apu_sppt; // plat -+ u32 ppt_platform_sppt; // plat -+ u32 ppt_fppt; // cpu -+ -+ u32 nv_boost_default; -+ u32 nv_boost_min; -+ u32 nv_boost_max; -+ u32 nv_dynamic_boost; -+ -+ u32 nv_temp_default; -+ u32 nv_temp_min; -+ u32 nv_temp_max; -+ u32 nv_temp_target; -+ -+ u32 dgpu_tgp_default; -+ u32 dgpu_tgp_min; -+ u32 dgpu_tgp_max; -+ u32 dgpu_tgp; -+ -+ u32 min_perf_cores; -+ u32 max_perf_cores; -+ u32 max_power_cores; -+}; -+ -+static const struct class *fw_attr_class; -+ -+struct asus_armoury_priv { -+ struct device *fw_attr_dev; -+ struct kset *fw_attr_kset; -+ -+ struct rog_tunables *rog_tunables; -+ u32 mini_led_dev_id; -+ u32 gpu_mux_dev_id; -+ -+ struct mutex mutex; -+}; -+ -+static struct asus_armoury_priv asus_armoury = { -+ .mutex = __MUTEX_INITIALIZER(asus_armoury.mutex) -+}; -+ -+struct fw_attrs_group { -+ u32 pending_reboot; -+}; -+ -+static struct fw_attrs_group fw_attrs = { -+ .pending_reboot = 0, -+}; -+ -+struct asus_attr_group { -+ const struct attribute_group *attr_group; -+ u32 wmi_devid; -+}; -+ -+/** -+ * asus_wmi_is_present() - determine if a WMI interface is available. -+ * @dev_id: The WMI function ID to use. -+ * -+ * Returns: Boolean state. Note that an error will also return false. -+ */ -+static bool asus_wmi_is_present(u32 dev_id) -+{ -+ u32 retval; -+ int status; -+ -+ status = asus_wmi_get_devstate_dsts(dev_id, &retval); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); -+ -+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); -+} -+ -+static void asus_set_reboot_and_signal_event(void) -+{ -+ fw_attrs.pending_reboot = 1; -+ kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); -+} -+ -+static ssize_t pending_reboot_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "%u\n", fw_attrs.pending_reboot); -+} -+ -+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); -+ -+static bool asus_bios_requires_reboot(struct kobj_attribute *attr) -+{ -+ return !strcmp(attr->attr.name, "gpu_mux_mode") || -+ !strcmp(attr->attr.name, "cores_performance") || -+ !strcmp(attr->attr.name, "cores_efficiency") || -+ !strcmp(attr->attr.name, "panel_hd_mode"); -+} -+ -+/** -+ * attr_int_store() - Generic store function for use with most WMI functions. -+ * @kobj: Pointer to the driver object. -+ * @kobj_attribute: Pointer the the attribute calling this function. -+ * @buf: The buffer to read from, this is parsed to `int` type. -+ * @count: -+ * @min: Minimum accepted value. Below this returns -EINVAL. -+ * @max: Maximum accepted value. Above this returns -EINVAL. -+ * @store_value: Pointer to where the parsed value should be stored. -+ * @wmi_dev: The WMI function ID to use. -+ * -+ * The WMI functions available on most ASUS laptops return a 1 as "success", and -+ * a 0 as failed. However some functions can return n > 1 for additional errors. -+ * attr_int_store() currently treats all values which are not 1 as errors, ignoring -+ * the possible differences in WMI error returns. -+ * -+ * Returns: Either count, or an error. -+ */ -+static ssize_t attr_int_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count, -+ u32 min, u32 max, u32 *store_value, u32 wmi_dev) -+{ -+ u32 result, value; -+ int err; -+ -+ err = kstrtouint(buf, 10, &value); -+ if (err) -+ return err; -+ -+ if (value < min || value > max) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(wmi_dev, value, &result); -+ if (err) { -+ pr_err("Failed to set %s: %d\n", attr->attr.name, err); -+ return err; -+ } -+ -+ if (result != 1) { -+ pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result); -+ return -EIO; -+ } -+ -+ if (store_value != NULL) -+ *store_value = value; -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ if (asus_bios_requires_reboot(attr)) -+ asus_set_reboot_and_signal_event(); -+ -+ return count; -+} -+ -+/* Mini-LED mode **************************************************************/ -+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ u32 value; -+ int err; -+ -+ err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value); -+ if (err) -+ return err; -+ -+ value = value & ASUS_MINI_LED_MODE_MASK; -+ -+ /* -+ * Remap the mode values to match previous generation mini-led. The last gen -+ * WMI 0 == off, while on this version WMI 2 ==off (flipped). -+ */ -+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (value) { -+ case ASUS_MINI_LED_2024_WEAK: -+ value = ASUS_MINI_LED_ON; -+ break; -+ case ASUS_MINI_LED_2024_STRONG: -+ value = ASUS_MINI_LED_STRONG_MODE; -+ break; -+ case ASUS_MINI_LED_2024_OFF: -+ value = ASUS_MINI_LED_OFF; -+ break; -+ } -+ } -+ -+ return sysfs_emit(buf, "%u\n", value); -+} -+ -+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 mode; -+ -+ err = kstrtou32(buf, 10, &mode); -+ if (err) -+ return err; -+ -+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && -+ mode > ASUS_MINI_LED_ON) -+ return -EINVAL; -+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && -+ mode > ASUS_MINI_LED_STRONG_MODE) -+ return -EINVAL; -+ -+ /* -+ * Remap the mode values so expected behaviour is the same as the last -+ * generation of mini-LED with 0 == off, 1 == on. -+ */ -+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (mode) { -+ case ASUS_MINI_LED_OFF: -+ mode = ASUS_MINI_LED_2024_OFF; -+ break; -+ case ASUS_MINI_LED_ON: -+ mode = ASUS_MINI_LED_2024_WEAK; -+ break; -+ case ASUS_MINI_LED_STRONG_MODE: -+ mode = ASUS_MINI_LED_2024_STRONG; -+ break; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result); -+ if (err) { -+ pr_warn("Failed to set mini-LED: %d\n", err); -+ return err; -+ } -+ -+ if (result != 1) { -+ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+ -+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ switch (asus_armoury.mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ return sysfs_emit(buf, "0;1\n"); -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ return sysfs_emit(buf, "0;1;2\n"); -+ } -+ -+ return sysfs_emit(buf, "0\n"); -+} -+ -+ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); -+ -+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 optimus; -+ -+ err = kstrtou32(buf, 10, &optimus); -+ if (err) -+ return err; -+ -+ if (optimus > 1) -+ return -EINVAL; -+ -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) { -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result); -+ if (err) -+ return err; -+ if (result && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); -+ return err; -+ } -+ } -+ -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) { -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result); -+ if (err) -+ return err; -+ if (result && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result); -+ if (err) { -+ pr_err("Failed to set GPU MUX mode: %d\nn", err); -+ return err; -+ } -+ /* !1 is considered a fail by ASUS */ -+ if (result != 1) { -+ pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id); -+ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); -+ -+/* -+ * A user may be required to store the value twice, typcial store first, then -+ * rescan PCI bus to activate power, then store a second time to save correctly. -+ * The reason for this is that an extra code path in the ACPI is enabled when -+ * the device and bus are powered. -+ */ -+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 disable; -+ -+ err = kstrtou32(buf, 10, &disable); -+ if (err) -+ return err; -+ -+ if (disable > 1) -+ return -EINVAL; -+ -+ if (asus_armoury.gpu_mux_dev_id) { -+ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result); -+ if (err) -+ return err; -+ if (!result && disable) { -+ err = -ENODEV; -+ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); -+ if (err) { -+ pr_warn("Failed to set dgpu disable: %d\n", err); -+ return err; -+ } -+ -+ if (result != 1) { -+ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU); -+ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU"); -+ -+/* The ACPI call to enable the eGPU also disables the internal dGPU */ -+static ssize_t egpu_enable_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 enable; -+ -+ err = kstrtou32(buf, 10, &enable); -+ if (err) -+ return err; -+ -+ if (enable > 1) -+ return -EINVAL; -+ -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result); -+ if (err) { -+ pr_warn("Failed to get egpu connection status: %d\n", err); -+ return err; -+ } -+ -+ if (asus_armoury.gpu_mux_dev_id) { -+ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result); -+ if (err) { -+ pr_warn("Failed to get gpu mux status: %d\n", result); -+ return result; -+ } -+ if (!result && enable) { -+ err = -ENODEV; -+ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); -+ if (err) { -+ pr_warn("Failed to set egpu state: %d\n", err); -+ return err; -+ } -+ -+ if (result != 1) { -+ pr_warn("Failed to set egpu state (retval): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU); -+ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); -+ -+/* Device memory available to APU */ -+ -+static ssize_t apu_mem_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ int err; -+ u32 mem; -+ -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem); -+ if (err) -+ return err; -+ -+ switch (mem) { -+ case 256: -+ mem = 0; -+ break; -+ case 258: -+ mem = 1; -+ break; -+ case 259: -+ mem = 2; -+ break; -+ case 260: -+ mem = 3; -+ break; -+ case 261: -+ mem = 4; -+ break; -+ case 262: -+ /* This is out of order and looks wrong but is correct */ -+ mem = 8; -+ break; -+ case 263: -+ mem = 5; -+ break; -+ case 264: -+ mem = 6; -+ break; -+ case 265: -+ mem = 7; -+ break; -+ default: -+ mem = 4; -+ break; -+ } -+ -+ return sysfs_emit(buf, "%d\n", mem); -+} -+ -+static ssize_t apu_mem_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 requested, mem; -+ -+ result = kstrtou32(buf, 10, &requested); -+ if (result) -+ return result; -+ -+ switch (requested) { -+ case 0: -+ mem = 0; -+ break; -+ case 1: -+ mem = 258; -+ break; -+ case 2: -+ mem = 259; -+ break; -+ case 3: -+ mem = 260; -+ break; -+ case 4: -+ mem = 261; -+ break; -+ case 5: -+ mem = 263; -+ break; -+ case 6: -+ mem = 264; -+ break; -+ case 7: -+ mem = 265; -+ break; -+ case 8: -+ /* This is outof order and looks wrong but is correct */ -+ mem = 262; -+ break; -+ default: -+ return -EIO; -+ } -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result); -+ if (err) { -+ pr_warn("Failed to set apu_mem: %d\n", err); -+ return err; -+ } -+ -+ pr_info("APU memory changed to %dGB, reboot required\n", requested); -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ asus_set_reboot_and_signal_event(); -+ -+ return count; -+} -+ -+static ssize_t apu_mem_possible_values_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n"); -+} -+ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory for the APU to use"); -+ -+static int init_max_cpu_cores(void) -+{ -+ u32 cores; -+ int err; -+ -+ asus_armoury.rog_tunables->min_perf_cores = 4; -+ asus_armoury.rog_tunables->max_perf_cores = 4; -+ asus_armoury.rog_tunables->max_power_cores = 8; -+ -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores); -+ if (err) -+ return err; -+ -+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ asus_armoury.rog_tunables->max_power_cores = (cores & 0xff00) >> 8; -+ asus_armoury.rog_tunables->max_perf_cores = cores & 0xff; -+ -+ return 0; -+} -+ -+static ssize_t cores_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf, -+ enum cpu_core_type core_type, -+ enum cpu_core_value core_value) -+{ -+ u32 cores; -+ int err; -+ -+ switch (core_value) { -+ case CPU_CORE_DEFAULT: -+ case CPU_CORE_MAX: -+ if (core_type == CPU_CORE_PERF) -+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_perf_cores); -+ else -+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_power_cores); -+ case CPU_CORE_MIN: -+ if (core_type == CPU_CORE_PERF) -+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->min_perf_cores); -+ else -+ return sysfs_emit(buf, "%d\n", 0); -+ default: -+ break; -+ } -+ -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores); -+ if (err) -+ return err; -+ -+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ if (core_type == CPU_CORE_PERF) -+ cores &= 0xff; -+ else -+ cores = (cores & 0xff00) >> 8; -+ return sysfs_emit(buf, "%d\n", cores); -+} -+ -+static ssize_t cores_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, -+ enum cpu_core_type core_type) -+{ -+ int result, err; -+ u32 cores, currentv, min, max; -+ -+ result = kstrtou32(buf, 10, &cores); -+ if (result) -+ return result; -+ -+ if (core_type == CPU_CORE_PERF) { -+ min = asus_armoury.rog_tunables->min_perf_cores; -+ max = asus_armoury.rog_tunables->max_perf_cores; -+ } else { -+ min = 0; -+ max = asus_armoury.rog_tunables->max_power_cores; -+ } -+ if (cores < min || cores > max) -+ return -EINVAL; -+ -+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, ¤tv); -+ if (err) -+ return err; -+ -+ if (core_type == CPU_CORE_PERF) -+ cores |= (currentv & 0xff00); -+ else -+ cores |= currentv & 0xff; -+ -+ if (cores == currentv) -+ return 0; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, cores, &result); -+ if (err) { -+ pr_warn("Failed to set CPU core count: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set CPU core count (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ pr_info("CPU core count changed, reboot required\n"); -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ asus_set_reboot_and_signal_event(); -+ -+ return 0; -+} -+ -+static ssize_t cores_performance_min_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN); -+} -+ -+static ssize_t cores_performance_max_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX); -+} -+ -+static ssize_t cores_performance_default_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT); -+} -+ -+static ssize_t cores_performance_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT); -+} -+ -+static ssize_t cores_performance_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int err; -+ -+ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF); -+ if (err) -+ return err; -+ -+ return count; -+} -+ATTR_GROUP_CORES_RW(cores_performance, "cores_performance", -+ "Set the max available performance cores"); -+ -+static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN); -+} -+ -+static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX); -+} -+ -+static ssize_t cores_efficiency_default_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT); -+} -+ -+static ssize_t cores_efficiency_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT); -+} -+ -+static ssize_t cores_efficiency_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int err; -+ -+ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER); -+ if (err) -+ return err; -+ -+ return count; -+} -+ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency", -+ "Set the max available efficiency cores"); -+ -+/* Simple attribute creation */ -+ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, -+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, -+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU fast package limit"); -+ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT, -+ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT, -+ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit"); -+ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, -+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit"); -+ -+ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST, -+ nv_boost_default, nv_boost_min, nv_boost_max, 1, "Set the Nvidia dynamic boost limit"); -+ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET, -+ nv_temp_default, nv_boost_min, nv_temp_max, 1, "Set the Nvidia max thermal limit"); -+ATTR_GROUP_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP, -+ "Read the base TGP value"); -+ATTR_GROUP_ROG_TUNABLE(dgpu_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, -+ dgpu_tgp_default, dgpu_tgp_min, dgpu_tgp_max, 1, -+ "Set the additional TGP on top of the base TGP"); -+ -+ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, -+ "0;1;2", "Show the current mode of charging"); -+ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, -+ "Set the boot POST sound"); -+ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, -+ "Set MCU powersaving mode"); -+ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, -+ "Set the panel refresh overdrive"); -+ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, -+ "Set the panel HD mode to UHD<0> or FHD<1>"); -+ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, -+ "Show the eGPU connection status"); -+ -+/* If an attribute does not require any special case handling add it here */ -+static const struct asus_attr_group armoury_attr_groups[] = { -+ { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, -+ { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, -+ { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, -+ -+ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, -+ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, -+ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, -+ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, -+ { &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT }, -+ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, -+ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, -+ { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, -+ { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, -+ { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, -+ { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX }, -+ { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX }, -+ -+ { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, -+ { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, -+ { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, -+ { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, -+ { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, -+}; -+ -+static int asus_fw_attr_add(void) -+{ -+ int err; -+ -+ err = fw_attributes_class_get(&fw_attr_class); -+ if (err) -+ goto fail_class_created; -+ -+ asus_armoury.fw_attr_dev = device_create(fw_attr_class, NULL, -+ MKDEV(0, 0), NULL, "%s", DRIVER_NAME); -+ -+ if (IS_ERR(asus_armoury.fw_attr_dev)) { -+ err = PTR_ERR(asus_armoury.fw_attr_dev); -+ goto fail_class_created; -+ } -+ -+ asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, -+ &asus_armoury.fw_attr_dev->kobj); -+ if (!asus_armoury.fw_attr_dev) { -+ err = -ENOMEM; -+ pr_debug("Failed to create and add attributes\n"); -+ goto err_destroy_classdev; -+ } -+ -+ err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -+ if (err) { -+ pr_warn("Failed to create sysfs level attributes\n"); -+ goto fail_class_created; -+ } -+ -+ err = 0; -+ asus_armoury.mini_led_dev_id = 0; -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) { -+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ &mini_led_mode_attr_group); -+ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) { -+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ &mini_led_mode_attr_group); -+ } -+ if (err) -+ pr_warn("Failed to create sysfs-group for mini_led\n"); -+ -+ err = 0; -+ asus_armoury.gpu_mux_dev_id = 0; -+ if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) { -+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) { -+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+ } -+ if (err) -+ pr_warn("Failed to create sysfs-group for gpu_mux\n"); -+ -+ for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { -+ if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid)) -+ continue; -+ -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ armoury_attr_groups[i].attr_group); -+ if (err) -+ pr_warn("Failed to create sysfs-group for %s\n", -+ armoury_attr_groups[i].attr_group->name); -+ else -+ pr_debug("Created sysfs-group for %s\n", -+ armoury_attr_groups[i].attr_group->name); -+ } -+ -+ return 0; -+ -+err_destroy_classdev: -+ device_destroy(fw_attr_class, MKDEV(0, 0)); -+ -+fail_class_created: -+ fw_attributes_class_put(); -+ return err; -+} -+ -+/* Init / exit ****************************************************************/ -+ -+/* Set up the min/max and defaults for ROG tunables */ -+static void init_rog_tunables(struct rog_tunables *rog) -+{ -+ const char *product; -+ u32 max_boost = NVIDIA_BOOST_MAX; -+ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT; -+ u32 cpu_max = PPT_CPU_LIMIT_MAX; -+ u32 platform_default = PPT_PLATFORM_DEFAULT; -+ u32 platform_max = PPT_PLATFORM_MAX; -+ -+ /* -+ * ASUS product_name contains everything required, e.g, -+ * "ROG Flow X16 GV601VV_GV601VV_00185149B" -+ */ -+ product = dmi_get_system_info(DMI_PRODUCT_NAME); -+ -+ if (strstr(product, "GA402R")) { -+ cpu_default = 125; -+ } else if (strstr(product, "13QY")) { -+ cpu_max = 250; -+ } else if (strstr(product, "X13")) { -+ cpu_max = 75; -+ cpu_default = 50; -+ } else if (strstr(product, "RC71")) { -+ cpu_max = 50; -+ cpu_default = 30; -+ } else if (strstr(product, "G814") -+ || strstr(product, "G614") -+ || strstr(product, "G834") -+ || strstr(product, "G634")) { -+ cpu_max = 175; -+ } else if (strstr(product, "GA402X") -+ || strstr(product, "GA403") -+ || strstr(product, "FA507N") -+ || strstr(product, "FA507X") -+ || strstr(product, "FA707N") -+ || strstr(product, "FA707X")) { -+ cpu_max = 90; -+ } -+ -+ if (strstr(product, "GZ301ZE")) -+ max_boost = 5; -+ else if (strstr(product, "FX507ZC4")) -+ max_boost = 15; -+ else if (strstr(product, "GU605")) -+ max_boost = 20; -+ -+ /* ensure defaults for tunables */ -+ rog->cpu_default = cpu_default; -+ rog->cpu_min = PPT_CPU_LIMIT_MIN; -+ rog->cpu_max = cpu_max; -+ -+ rog->platform_default = platform_default; -+ rog->platform_max = PPT_PLATFORM_MIN; -+ rog->platform_max = platform_max; -+ -+ rog->ppt_pl1_spl = cpu_default; -+ rog->ppt_pl2_sppt = cpu_default; -+ rog->ppt_apu_sppt = cpu_default; -+ -+ rog->ppt_platform_sppt = platform_default; -+ rog->ppt_fppt = platform_default; -+ -+ rog->nv_boost_default = NVIDIA_BOOST_MAX; -+ rog->nv_boost_max = NVIDIA_BOOST_MIN; -+ rog->nv_boost_max = max_boost; -+ rog->nv_dynamic_boost = NVIDIA_BOOST_MIN; -+ -+ rog->nv_temp_default = NVIDIA_TEMP_MAX; -+ rog->nv_temp_max = NVIDIA_TEMP_MIN; -+ rog->nv_temp_max = NVIDIA_TEMP_MAX; -+ rog->nv_temp_target = NVIDIA_TEMP_MIN; -+ -+ rog->dgpu_tgp_default = NVIDIA_POWER_DEFAULT; -+ rog->dgpu_tgp_min = NVIDIA_POWER_MIN; -+ rog->dgpu_tgp_max = NVIDIA_POWER_MAX; -+ rog->dgpu_tgp = NVIDIA_POWER_MAX; -+ -+} -+ -+static int __init asus_fw_init(void) -+{ -+ int err; -+ -+ fw_attrs.pending_reboot = 0; -+ -+ mutex_lock(&asus_armoury.mutex); -+ -+ asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL); -+ if (!asus_armoury.rog_tunables) { -+ mutex_unlock(&asus_armoury.mutex); -+ return -ENOMEM; -+ } -+ init_rog_tunables(asus_armoury.rog_tunables); -+ init_max_cpu_cores(); -+ -+ err = asus_fw_attr_add(); -+ mutex_unlock(&asus_armoury.mutex); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void __exit asus_fw_exit(void) -+{ -+ mutex_lock(&asus_armoury.mutex); -+ -+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -+ kset_unregister(asus_armoury.fw_attr_kset); -+ device_destroy(fw_attr_class, MKDEV(0, 0)); -+ fw_attributes_class_put(); -+ -+ mutex_unlock(&asus_armoury.mutex); -+} -+ -+module_init(asus_fw_init); -+module_exit(asus_fw_exit); -+ -+MODULE_AUTHOR("Luke Jones <luke@ljones.dev>"); -+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); -diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h -new file mode 100644 -index 000000000000..25b2c055930e ---- /dev/null -+++ b/drivers/platform/x86/asus-armoury.h -@@ -0,0 +1,259 @@ -+/* SPDX-License-Identifier: GPL-2.0 -+ * -+ * Definitions for kernel modules using asus-armoury driver -+ * -+ * Copyright (c) 2024 Luke Jones <luke@ljones.dev> -+ */ -+ -+#ifndef _ASUS_BIOSCFG_H_ -+#define _ASUS_BIOSCFG_H_ -+ -+#include "firmware_attributes_class.h" -+#include <linux/types.h> -+ -+#define DRIVER_NAME "asus-armoury" -+ -+static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count, -+ u32 min, u32 max, u32 *store_value, u32 wmi_dev); -+ -+ -+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "integer\n"); -+} -+ -+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "enumeration\n"); -+} -+ -+#define __ASUS_ATTR_RO(_func, _name) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _func##_##_name##_show, \ -+} -+ -+#define __ASUS_ATTR_RO_AS(_name, _show) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _show, \ -+} -+ -+#define __ASUS_ATTR_RW(_func, _name) __ATTR(_name, 0644, \ -+ _func##_##_name##_show, _func##_##_name##_store) -+ -+#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ -+static ssize_t _attr##_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ return attr_int_store(kobj, attr, buf, count, _min, _max, NULL, _wmi); \ -+} -+ -+#define WMI_SHOW_INT(_attr, _fmt, _wmi) \ -+static ssize_t _attr##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ u32 result; \ -+ int err; \ -+ err = asus_wmi_get_devstate_dsts(_wmi, &result); \ -+ if (err) \ -+ return err; \ -+ return sysfs_emit(buf, _fmt, \ -+ result & ~ASUS_WMI_DSTS_PRESENCE_BIT); \ -+} -+ -+/* Create functions and attributes for use in other macros or on their own */ -+ -+#define __ATTR_CURRENT_INT_RO(_attr, _wmi) \ -+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RO(_attr, current_value) -+ -+#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi) \ -+__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \ -+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RW(_attr, current_value) -+ -+/* Shows a formatted static variable */ -+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ -+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, _fmt, _val); \ -+} \ -+static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop) -+ -+/* Requires current_value show&|store */ -+#define __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+} -+ -+/* Boolean style enumeration, base macro. Requires adding show/store */ -+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+} -+ -+#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ -+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+ __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) -+ -+#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ -+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) -+ -+#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ -+ __ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi); \ -+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) -+ -+/* -+ * Requires <name>_current_value_show(), <name>_current_value_show() -+ */ -+#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname) \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) -+ -+#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, \ -+ _possible, _dispname) \ -+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \ -+ __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) -+ -+/* -+ * Requires <name>_current_value_show(), <name>_current_value_show() -+ * and <name>_possible_values_show() -+ */ -+#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname) \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+static struct kobj_attribute attr_##_attrname##_possible_values = \ -+ __ASUS_ATTR_RO(_attrname, possible_values); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+} -+ -+/* CPU core attributes need a little different in setup */ -+#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname) \ -+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+static struct kobj_attribute attr_##_attrname##_default_value = \ -+ __ASUS_ATTR_RO(_attrname, default_value); \ -+static struct kobj_attribute attr_##_attrname##_min_value = \ -+ __ASUS_ATTR_RO(_attrname, min_value); \ -+static struct kobj_attribute attr_##_attrname##_max_value = \ -+ __ASUS_ATTR_RO(_attrname, max_value); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+} -+ -+/* -+ * ROG PPT attributes need a little different in setup as they -+ * require rog_tunables members. -+ */ -+ -+#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi) \ -+static ssize_t _attr##_current_value_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ return attr_int_store(kobj, attr, buf, count, \ -+ asus_armoury.rog_tunables->_min, \ -+ asus_armoury.rog_tunables->_max, \ -+ &asus_armoury.rog_tunables->_attr, _wmi); \ -+} \ -+static ssize_t _attr##_current_value_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, "%u\n", asus_armoury.rog_tunables->_attr);\ -+} \ -+static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RW(_attr, current_value) -+ -+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ -+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->_val);\ -+} \ -+static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop) -+ -+#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, \ -+ _min, _max, _incstep, _dispname) \ -+__ROG_TUNABLE_SHOW(default_value, _attrname, _default); \ -+__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi); \ -+__ROG_TUNABLE_SHOW(min_value, _attrname, _min); \ -+__ROG_TUNABLE_SHOW(max_value, _attrname, _max); \ -+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep); \ -+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+}; \ -+static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, \ -+ .attrs = _attrname##_attrs \ -+} -+ -+#endif /* _ASUS_BIOSCFG_H_ */ -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index bc9c5db38324..9faebd12bd49 100644 ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -97,6 +97,12 @@ module_param(fnlock_default, bool, 0444); - #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 - #define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 - -+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 -+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 -+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 -+ -+#define PLATFORM_PROFILE_MAX 2 -+ - #define USB_INTEL_XUSB2PR 0xD0 - #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 - -@@ -146,6 +152,20 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; - - static int throttle_thermal_policy_write(struct asus_wmi *); - -+static const struct dmi_system_id asus_ally_mcu_quirk[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC72L"), -+ }, -+ }, -+ { }, -+}; -+ - static bool ashs_present(void) - { - int i = 0; -@@ -285,8 +305,8 @@ struct asus_wmi { - u32 kbd_rgb_dev; - bool kbd_rgb_state_available; - -- bool throttle_thermal_policy_available; - u8 throttle_thermal_policy_mode; -+ u32 throttle_thermal_policy_dev; - - bool cpu_fan_curve_available; - bool gpu_fan_curve_available; -@@ -334,20 +354,29 @@ static int asus_wmi_evaluate_method3(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; -+ } - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - -+ pr_debug("Result: 0x%08x\n", tmp); - if (retval) - *retval = tmp; - - kfree(obj); - -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); - return -ENODEV; -+ } - - return 0; - } -@@ -377,20 +406,29 @@ static int asus_wmi_evaluate_method5(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2, arg3, arg4); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; -+ } - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - -+ pr_debug("Result: %x\n", tmp); - if (retval) - *retval = tmp; - - kfree(obj); - -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); - return -ENODEV; -+ } - - return 0; - } -@@ -416,8 +454,13 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, - &input, &output); - -- if (ACPI_FAILURE(status)) -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); - return -EIO; -+ } - - obj = (union acpi_object *)output.pointer; - -@@ -453,8 +496,11 @@ static int asus_wmi_evaluate_method_buf(u32 method_id, - - kfree(obj); - -- if (err) -+ if (err) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, err); - return err; -+ } - - return 0; - } -@@ -503,12 +549,56 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) - return 0; - } - --static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, -- u32 *retval) -+/** -+ * asus_wmi_get_devstate_dsts() - Get the WMI function state. -+ * @dev_id: The WMI function to call. -+ * @retval: A pointer to where to store the value returned from WMI. -+ * -+ * The returned WMI function state can also be used to determine if the WMI -+ * function is supported by checking if the asus_wmi_get_devstate_dsts() -+ * returns an error. -+ * -+ * On success the return value is 0, and the retval is a valid value returned -+ * by the successful WMI function call. An error value is returned only if the -+ * WMI function failed, or if it returns "unsupported" which is typically a 0 -+ * (no return, and no 'supported' bit set), or a 0xFFFFFFFE (~1) which if not -+ * caught here can result in unexpected behaviour later. -+ */ -+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) -+{ -+ int err; -+ -+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); -+ if (err) -+ return err; -+ /* Be explicit about retval */ -+ if (*retval == 0xFFFFFFFE || *retval == 0) -+ return -ENODEV; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(asus_wmi_get_devstate_dsts); -+ -+/** -+ * asus_wmi_set_devstate() - Set the WMI function state. -+ * @dev_id: The WMI function to call. -+ * @ctrl_param: The argument to be used for this WMI function. -+ * @retval: A pointer to where to store the value returned from WMI. -+ * -+ * The returned WMI function state if not checked here for error as -+ * asus_wmi_set_devstate() is not called unless first paired with a call to -+ * asus_wmi_get_devstate_dsts() to check that the WMI function is supported. -+ * -+ * On success the return value is 0, and the retval is a valid value returned -+ * by the successful WMI function call. An error value is returned only if the -+ * WMI function failed. -+ */ -+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) - { - return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, - ctrl_param, retval); - } -+EXPORT_SYMBOL_GPL(asus_wmi_set_devstate); - - /* Helper for special devices with magic return codes */ - static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, -@@ -542,6 +632,7 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) - { - u32 retval; - int status = asus_wmi_get_devstate(asus, dev_id, &retval); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); - - return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); - } -@@ -1685,7 +1776,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus) - goto error; - } - -- if (!kbd_led_read(asus, &led_val, NULL)) { -+ if (!kbd_led_read(asus, &led_val, NULL) && !dmi_check_system(asus_use_hid_led_dmi_ids)) { -+ pr_info("using asus-wmi for asus::kbd_backlight\n"); - asus->kbd_led_wk = led_val; - asus->kbd_led.name = "asus::kbd_backlight"; - asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; -@@ -3127,7 +3219,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) - int err, fan_idx; - u8 mode = 0; - -- if (asus->throttle_thermal_policy_available) -+ if (asus->throttle_thermal_policy_dev) - mode = asus->throttle_thermal_policy_mode; - /* DEVID_<C/G>PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ - if (mode == 2) -@@ -3334,7 +3426,7 @@ static ssize_t fan_curve_enable_store(struct device *dev, - * For machines with throttle this is the only way to reset fans - * to default mode of operation (does not erase curve data). - */ -- if (asus->throttle_thermal_policy_available) { -+ if (asus->throttle_thermal_policy_dev) { - err = throttle_thermal_policy_write(asus); - if (err) - return err; -@@ -3551,8 +3643,8 @@ static const struct attribute_group asus_fan_curve_attr_group = { - __ATTRIBUTE_GROUPS(asus_fan_curve_attr); - - /* -- * Must be initialised after throttle_thermal_policy_check_present() as -- * we check the status of throttle_thermal_policy_available during init. -+ * Must be initialised after throttle_thermal_policy_dev is set as -+ * we check the status of throttle_thermal_policy_dev during init. - */ - static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) - { -@@ -3562,18 +3654,27 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) - - err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, - ASUS_WMI_DEVID_CPU_FAN_CURVE); -- if (err) -+ if (err) { -+ pr_err("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_CPU_FAN_CURVE, err); - return err; -+ } - - err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available, - ASUS_WMI_DEVID_GPU_FAN_CURVE); -- if (err) -+ if (err) { -+ pr_err("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_GPU_FAN_CURVE, err); - return err; -+ } - - err = fan_curve_check_present(asus, &asus->mid_fan_curve_available, - ASUS_WMI_DEVID_MID_FAN_CURVE); -- if (err) -+ if (err) { -+ pr_err("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_MID_FAN_CURVE, err); - return err; -+ } - - if (!asus->cpu_fan_curve_available - && !asus->gpu_fan_curve_available -@@ -3593,38 +3694,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) - } - - /* Throttle thermal policy ****************************************************/ -- --static int throttle_thermal_policy_check_present(struct asus_wmi *asus) --{ -- u32 result; -- int err; -- -- asus->throttle_thermal_policy_available = false; -- -- err = asus_wmi_get_devstate(asus, -- ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, -- &result); -- if (err) { -- if (err == -ENODEV) -- return 0; -- return err; -- } -- -- if (result & ASUS_WMI_DSTS_PRESENCE_BIT) -- asus->throttle_thermal_policy_available = true; -- -- return 0; --} -- - static int throttle_thermal_policy_write(struct asus_wmi *asus) - { -- int err; -- u8 value; -+ u8 value = asus->throttle_thermal_policy_mode; - u32 retval; -+ int err; - -- value = asus->throttle_thermal_policy_mode; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, -+ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, - value, &retval); - - sysfs_notify(&asus->platform_device->dev.kobj, NULL, -@@ -3654,7 +3730,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) - - static int throttle_thermal_policy_set_default(struct asus_wmi *asus) - { -- if (!asus->throttle_thermal_policy_available) -+ if (!asus->throttle_thermal_policy_dev) - return 0; - - asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -@@ -3666,7 +3742,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus) - u8 new_mode = asus->throttle_thermal_policy_mode + 1; - int err; - -- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) -+ if (new_mode > PLATFORM_PROFILE_MAX) - new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; - - asus->throttle_thermal_policy_mode = new_mode; -@@ -3705,7 +3781,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, - if (result < 0) - return result; - -- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) -+ if (new_mode > PLATFORM_PROFILE_MAX) - return -EINVAL; - - asus->throttle_thermal_policy_mode = new_mode; -@@ -3722,10 +3798,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, - return count; - } - --// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent -+/* -+ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent -+ */ - static DEVICE_ATTR_RW(throttle_thermal_policy); - - /* Platform profile ***********************************************************/ -+static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode) -+{ -+ bool vivo; -+ -+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ -+ if (vivo) { -+ switch (mode) { -+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; -+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; -+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; -+ } -+ } -+ -+ return mode; -+} -+ -+static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode) -+{ -+ bool vivo; -+ -+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ -+ if (vivo) { -+ switch (mode) { -+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO: -+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO: -+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; -+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO: -+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT; -+ } -+ } -+ -+ return mode; -+} -+ - static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, - enum platform_profile_option *profile) - { -@@ -3733,10 +3851,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, - int tp; - - asus = container_of(pprof, struct asus_wmi, platform_profile_handler); -- - tp = asus->throttle_thermal_policy_mode; - -- switch (tp) { -+ switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) { - case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: - *profile = PLATFORM_PROFILE_BALANCED; - break; -@@ -3775,7 +3892,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, - return -EOPNOTSUPP; - } - -- asus->throttle_thermal_policy_mode = tp; -+ asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp); - return throttle_thermal_policy_write(asus); - } - -@@ -3788,7 +3905,7 @@ static int platform_profile_setup(struct asus_wmi *asus) - * Not an error if a component platform_profile relies on is unavailable - * so early return, skipping the setup of platform_profile. - */ -- if (!asus->throttle_thermal_policy_available) -+ if (!asus->throttle_thermal_policy_dev) - return 0; - - dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); -@@ -3803,8 +3920,13 @@ static int platform_profile_setup(struct asus_wmi *asus) - asus->platform_profile_handler.choices); - - err = platform_profile_register(&asus->platform_profile_handler); -- if (err) -+ if (err == -EEXIST) { -+ pr_warn("%s, a platform_profile handler is already registered\n", __func__); -+ return 0; -+ } else if (err) { -+ pr_err("%s, failed at platform_profile_register: %d\n", __func__, err); - return err; -+ } - - asus->platform_profile_support = true; - return 0; -@@ -4203,7 +4325,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) - if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { - if (asus->fan_boost_mode_available) - fan_boost_mode_switch_next(asus); -- if (asus->throttle_thermal_policy_available) -+ if (asus->throttle_thermal_policy_dev) - throttle_thermal_policy_switch_next(asus); - return; - -@@ -4375,7 +4497,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, - else if (attr == &dev_attr_fan_boost_mode.attr) - ok = asus->fan_boost_mode_available; - else if (attr == &dev_attr_throttle_thermal_policy.attr) -- ok = asus->throttle_thermal_policy_available; -+ ok = asus->throttle_thermal_policy_dev != 0; - else if (attr == &dev_attr_ppt_pl2_sppt.attr) - devid = ASUS_WMI_DEVID_PPT_PL2_SPPT; - else if (attr == &dev_attr_ppt_pl1_spl.attr) -@@ -4401,8 +4523,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, - else if (attr == &dev_attr_available_mini_led_mode.attr) - ok = asus->mini_led_dev_id != 0; - -- if (devid != -1) -+ if (devid != -1) { - ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); -+ pr_debug("%s called 0x%08x, ok: %x\n", __func__, devid, ok); -+ } - - return ok ? attr->mode : 0; - } -@@ -4650,7 +4774,7 @@ static int asus_wmi_add(struct platform_device *pdev) - asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); - asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); - asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) -- && dmi_match(DMI_BOARD_NAME, "RC71L"); -+ && dmi_check_system(asus_ally_mcu_quirk); - - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) - asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -@@ -4667,18 +4791,17 @@ static int asus_wmi_add(struct platform_device *pdev) - else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) - asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; - -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) -+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO)) -+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ - err = fan_boost_mode_check_present(asus); - if (err) - goto fail_fan_boost_mode; - -- err = throttle_thermal_policy_check_present(asus); -- if (err) -- goto fail_throttle_thermal_policy; -- else -- throttle_thermal_policy_set_default(asus); -- - err = platform_profile_setup(asus); -- if (err) -+ if (err && err != -EEXIST) - goto fail_platform_profile_setup; - - err = asus_wmi_sysfs_init(asus->platform_device); -@@ -4771,7 +4894,6 @@ static int asus_wmi_add(struct platform_device *pdev) - fail_input: - asus_wmi_sysfs_exit(asus->platform_device); - fail_sysfs: --fail_throttle_thermal_policy: - fail_custom_fan_curve: - fail_platform_profile_setup: - if (asus->platform_profile_support) -diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile -index 9f16cb514397..a8aba07bf1dc 100644 ---- a/drivers/platform/x86/intel/int3472/Makefile -+++ b/drivers/platform/x86/intel/int3472/Makefile -@@ -1,4 +1,7 @@ - obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \ -- intel_skl_int3472_tps68470.o --intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o --intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o -+ intel_skl_int3472_tps68470.o \ -+ intel_skl_int3472_common.o -+intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o -+intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o -+ -+intel_skl_int3472_common-y += common.o -diff --git a/drivers/platform/x86/intel/int3472/common.c b/drivers/platform/x86/intel/int3472/common.c -index 9db2bb0bbba4..b3a2578e06c1 100644 ---- a/drivers/platform/x86/intel/int3472/common.c -+++ b/drivers/platform/x86/intel/int3472/common.c -@@ -29,6 +29,7 @@ union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *i - - return obj; - } -+EXPORT_SYMBOL_GPL(skl_int3472_get_acpi_buffer); - - int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) - { -@@ -52,6 +53,7 @@ int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) - kfree(obj); - return ret; - } -+EXPORT_SYMBOL_GPL(skl_int3472_fill_cldb); - - /* sensor_adev_ret may be NULL, name_ret must not be NULL */ - int skl_int3472_get_sensor_adev_and_name(struct device *dev, -@@ -80,3 +82,8 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev, - - return ret; - } -+EXPORT_SYMBOL_GPL(skl_int3472_get_sensor_adev_and_name); -+ -+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver library"); -+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>"); -+MODULE_LICENSE("GPL"); -diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h -index 3eb5cd6773ad..a23cc8624218 100644 ---- a/include/linux/platform_data/x86/asus-wmi.h -+++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -4,6 +4,7 @@ - - #include <linux/errno.h> - #include <linux/types.h> -+#include <linux/dmi.h> - - /* WMI Methods */ - #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ -@@ -64,8 +65,10 @@ - #define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032 - #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018 - #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075 -+#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019 - - /* Misc */ -+#define ASUS_WMI_DEVID_PANEL_HD 0x0005001C - #define ASUS_WMI_DEVID_PANEL_OD 0x00050019 - #define ASUS_WMI_DEVID_CAMERA 0x00060013 - #define ASUS_WMI_DEVID_LID_FLIP 0x00060062 -@@ -126,6 +129,14 @@ - /* dgpu on/off */ - #define ASUS_WMI_DEVID_DGPU 0x00090020 - -+/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */ -+#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 */ - #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 - #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026 -@@ -151,8 +162,18 @@ - #define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F - - #if IS_REACHABLE(CONFIG_ASUS_WMI) -+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval); -+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval); - int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); - #else -+static int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) -+{ -+ return -ENODEV; -+} -+static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) -+{ -+ return -ENODEV; -+} - static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, - u32 *retval) - { -@@ -160,4 +181,39 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, - } - #endif - -+/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */ -+static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403U"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605M"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"), -+ }, -+ }, -+ { }, -+}; -+ - #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index 3840565ef8b0..5641b40b9cdc 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -7409,6 +7409,7 @@ enum { - ALC285_FIXUP_THINKPAD_X1_GEN7, - ALC285_FIXUP_THINKPAD_HEADSET_JACK, - ALC294_FIXUP_ASUS_ALLY, -+ ALC294_FIXUP_ASUS_ALLY_X, - ALC294_FIXUP_ASUS_ALLY_PINS, - ALC294_FIXUP_ASUS_ALLY_VERBS, - ALC294_FIXUP_ASUS_ALLY_SPEAKER, -@@ -8875,6 +8876,12 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS - }, -+ [ALC294_FIXUP_ASUS_ALLY_X] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = tas2781_fixup_i2c, -+ .chained = true, -+ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS -+ }, - [ALC294_FIXUP_ASUS_ALLY_PINS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { -@@ -10307,6 +10314,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), - SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY), -+ SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X), - SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), - SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), |