aboutsummaryrefslogtreecommitdiff
path: root/SOURCES
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2024-02-11 20:00:26 +0100
committerJan200101 <sentrycraft123@gmail.com>2024-02-11 20:00:26 +0100
commitd163bd3d8fbc0666ca31afdcf152a2450f352753 (patch)
treea0c5e11a9a02ad1a2855ed0338d3187979ba9c77 /SOURCES
parentb8d31e3c4edc6bb6fe7ce82505962e61882ad3d0 (diff)
downloadkernel-fsync-d163bd3d8fbc0666ca31afdcf152a2450f352753.tar.gz
kernel-fsync-d163bd3d8fbc0666ca31afdcf152a2450f352753.zip
kernel 6.7.4 rog ally patches update
Diffstat (limited to 'SOURCES')
-rw-r--r--SOURCES/v10-0004-HID-asus-add-ROG-Ally-xpad-settings.patch1471
-rw-r--r--SOURCES/v14.8-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch (renamed from SOURCES/v10-0001-HID-asus-fix-more-n-key-report-descriptors-if-n-.patch)8
-rw-r--r--SOURCES/v14.8-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch (renamed from SOURCES/v10-0002-HID-asus-make-asus_kbd_init-generic-remove-rog_n.patch)6
-rw-r--r--SOURCES/v14.8-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch (renamed from SOURCES/v10-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch)8
-rw-r--r--SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch2329
5 files changed, 2340 insertions, 1482 deletions
diff --git a/SOURCES/v10-0004-HID-asus-add-ROG-Ally-xpad-settings.patch b/SOURCES/v10-0004-HID-asus-add-ROG-Ally-xpad-settings.patch
deleted file mode 100644
index 5c4f5c5..0000000
--- a/SOURCES/v10-0004-HID-asus-add-ROG-Ally-xpad-settings.patch
+++ /dev/null
@@ -1,1471 +0,0 @@
-From 89b9e9a58ddfe3c6d400d08c607b50b3e2c60cbf Mon Sep 17 00:00:00 2001
-From: "Luke D. Jones" <luke@ljones.dev>
-Date: Fri, 1 Dec 2023 16:57:19 +1300
-Subject: [PATCH v10 4/4] HID: asus: add ROG Ally xpad settings
-
-- move ROG specific stuff to new .c
-- add a header for common parts
-- add xpad mode
-- add deadzones
-- add gamepad button remapping
-- add gamepad mapping reset for xpad and wasd modes
-
-Signed-off-by: Luke D. Jones <luke@ljones.dev>
----
- drivers/hid/Makefile | 2 +
- drivers/hid/{hid-asus.c => hid-asus-core.c} | 71 +-
- drivers/hid/hid-asus-rog.c | 1206 +++++++++++++++++++
- drivers/hid/hid-asus.h | 51 +
- 4 files changed, 1289 insertions(+), 41 deletions(-)
- rename drivers/hid/{hid-asus.c => hid-asus-core.c} (96%)
- create mode 100644 drivers/hid/hid-asus-rog.c
- create mode 100644 drivers/hid/hid-asus.h
-
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 8a06d0f840bc..7c2436ed05d6 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -23,6 +23,8 @@ hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o
- hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
- hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
-
-+hid-asus-y := hid-asus-core.o hid-asus-rog.o
-+
- obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
- obj-$(CONFIG_HID_ACCUTOUCH) += hid-accutouch.o
- obj-$(CONFIG_HID_ALPS) += hid-alps.o
-diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus-core.c
-similarity index 96%
-rename from drivers/hid/hid-asus.c
-rename to drivers/hid/hid-asus-core.c
-index 3a1a6024d299..026705c43ee1 100644
---- a/drivers/hid/hid-asus.c
-+++ b/drivers/hid/hid-asus-core.c
-@@ -20,9 +20,8 @@
- * Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
- */
-
--/*
-- */
--
-+#include <asm-generic/errno-base.h>
-+#include <asm-generic/errno.h>
- #include <linux/dmi.h>
- #include <linux/hid.h>
- #include <linux/module.h>
-@@ -32,6 +31,7 @@
- #include <linux/power_supply.h>
- #include <linux/leds.h>
-
-+#include "hid-asus.h"
- #include "hid-ids.h"
-
- MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
-@@ -47,10 +47,6 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
- #define T100CHI_MOUSE_REPORT_ID 0x06
- #define FEATURE_REPORT_ID 0x0d
- #define INPUT_REPORT_ID 0x5d
--#define FEATURE_KBD_REPORT_ID 0x5a
--#define FEATURE_KBD_REPORT_SIZE 16
--#define FEATURE_KBD_LED_REPORT_ID1 0x5d
--#define FEATURE_KBD_LED_REPORT_ID2 0x5e
-
- #define SUPPORT_KBD_BACKLIGHT BIT(0)
-
-@@ -71,20 +67,6 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
- #define BATTERY_STAT_CHARGING (1)
- #define BATTERY_STAT_FULL (2)
-
--#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
--#define QUIRK_NO_INIT_REPORTS BIT(1)
--#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
--#define QUIRK_IS_MULTITOUCH BIT(3)
--#define QUIRK_NO_CONSUMER_USAGES BIT(4)
--#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
--#define QUIRK_T100_KEYBOARD BIT(6)
--#define QUIRK_T100CHI BIT(7)
--#define QUIRK_G752_KEYBOARD BIT(8)
--#define QUIRK_T90CHI BIT(9)
--#define QUIRK_MEDION_E1239T BIT(10)
--#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
--#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
--
- #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
- QUIRK_NO_INIT_REPORTS | \
- QUIRK_NO_CONSUMER_USAGES)
-@@ -113,22 +95,6 @@ struct asus_touchpad_info {
- int report_size;
- };
-
--struct asus_drvdata {
-- unsigned long quirks;
-- struct hid_device *hdev;
-- struct input_dev *input;
-- struct input_dev *tp_kbd_input;
-- struct asus_kbd_leds *kbd_backlight;
-- const struct asus_touchpad_info *tp;
-- bool enable_backlight;
-- struct power_supply *battery;
-- struct power_supply_desc battery_desc;
-- int battery_capacity;
-- int battery_stat;
-- bool battery_in_query;
-- unsigned long battery_next_query;
--};
--
- static int asus_report_battery(struct asus_drvdata *, u8 *, int);
-
- static const struct asus_touchpad_info asus_i2c_tp = {
-@@ -329,6 +295,16 @@ static int asus_raw_event(struct hid_device *hdev,
- if (drvdata->battery && data[0] == BATTERY_REPORT_ID)
- return asus_report_battery(drvdata, data, size);
-
-+ // TODO: remove after debugging
-+ // if (data[0] == 0x5a || data[0] == 0x5d || data[0] == 0x5e){
-+ // for (int i = 0; i < size; i++) {
-+ // if (i == 0)
-+ // printk(KERN_INFO "GOT: %02x,", data[i]);
-+ // else
-+ // printk(KERN_CONT "%02x,", data[i]);
-+ // }
-+ // }
-+
- if (drvdata->tp && data[0] == INPUT_REPORT_ID)
- return asus_report_input(drvdata, data, size);
-
-@@ -365,7 +341,7 @@ static int asus_raw_event(struct hid_device *hdev,
- return 0;
- }
-
--static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
-+int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
- {
- unsigned char *dmabuf;
- int ret;
-@@ -386,6 +362,13 @@ static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t bu
- return ret;
- }
-
-+int asus_kbd_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size)
-+{
-+ return hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, out_buf,
-+ out_buf_size, HID_FEATURE_REPORT,
-+ HID_REQ_GET_REPORT);
-+}
-+
- static int asus_kbd_init(struct hid_device *hdev, u8 report_id)
- {
- const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
-@@ -846,8 +829,8 @@ static int asus_input_mapping(struct hid_device *hdev,
- case 0xb2: asus_map_key_clear(KEY_PROG2); break; /* Fn+Left previous aura */
- case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */
- case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */
-- case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */
-- case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally left back */
-+ case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle, Ally M1 */
-+ case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally M2 */
- case 0xa6: asus_map_key_clear(KEY_F16); break; /* ROG Ally QAM button */
- case 0xa7: asus_map_key_clear(KEY_F17); break; /* ROG Ally ROG long-press */
- case 0xa8: asus_map_key_clear(KEY_F18); break; /* ROG Ally ROG long-press-release */
-@@ -1063,6 +1046,10 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
- }
- }
-
-+ /* all ROG devices have this HID interface but we will focus on Ally for now */
-+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && hid_is_usb(hdev))
-+ rog_ally.probe(hdev, &rog_ally);
-+
- ret = hid_parse(hdev);
- if (ret) {
- hid_err(hdev, "Asus hid parse failed: %d\n", ret);
-@@ -1112,6 +1099,8 @@ static void asus_remove(struct hid_device *hdev)
- cancel_work_sync(&drvdata->kbd_backlight->work);
- }
-
-+ rog_ally.remove(hdev, &rog_ally);
-+
- hid_hw_stop(hdev);
- }
-
-@@ -1245,7 +1234,7 @@ static const struct hid_device_id asus_devices[] = {
- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
- USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
-- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
-+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
- USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
- QUIRK_ROG_CLAYMORE_II_KEYBOARD },
-diff --git a/drivers/hid/hid-asus-rog.c b/drivers/hid/hid-asus-rog.c
-new file mode 100644
-index 000000000000..897c13769bae
---- /dev/null
-+++ b/drivers/hid/hid-asus-rog.c
-@@ -0,0 +1,1206 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * HID driver for Asus ROG laptops and Ally
-+ *
-+ * Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com>
-+ */
-+
-+#include <linux/hid.h>
-+#include <linux/types.h>
-+#include <linux/usb.h>
-+
-+#include "hid-asus.h"
-+
-+/* 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)
-+
-+#define BTN_CODE_LEN 11
-+#define MAPPING_BLOCK_LEN 44
-+
-+enum ally_xpad_mode {
-+ ally_xpad_mode_game = 0x01,
-+ ally_xpad_mode_wasd = 0x02,
-+ ally_xpad_mode_mouse = 0x03,
-+};
-+
-+enum ally_xpad_cmd {
-+ ally_xpad_cmd_set_mode = 0x01,
-+ ally_xpad_cmd_set_js_dz = 0x04, /* deadzones */
-+ ally_xpad_cmd_set_tr_dz = 0x05, /* deadzones */
-+ ally_xpad_cmd_check_ready = 0x0A,
-+};
-+
-+enum ally_xpad_axis {
-+ ally_xpad_axis_xy_left = 0x01,
-+ ally_xpad_axis_xy_right = 0x02,
-+ ally_xpad_axis_z_left = 0x03,
-+ ally_xpad_axis_z_right = 0x04,
-+};
-+
-+enum ally_out_dev {
-+ ally_out_dev_blank = 0x00,
-+ ally_out_dev_xpad = 0x01,
-+ ally_out_dev_keyboard = 0x02,
-+ ally_out_dev_mouse = 0x03,
-+ ally_out_dev_macro = 0x04,
-+ ally_out_dev_media = 0x05,
-+};
-+
-+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,
-+};
-+
-+/* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */
-+struct asus_rog_ally {
-+ enum ally_xpad_mode mode;
-+ /*ally_xpad_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[2][4];
-+ /*
-+ * index: left, right
-+ * max: 64
-+ */
-+ u8 vibration_intensity[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[2][8];
-+ /*
-+ * left = byte 0, right = byte 1
-+ */
-+ bool supports_anti_deadzones;
-+ u8 anti_deadzones[2];
-+
-+ /*
-+ * index: [mode][phys pair][b1, b1 secondary, b2, b2 secondary, blocks of 11]
-+ */
-+ u8 key_mapping[ally_xpad_mode_mouse][btn_pair_lt_rt][MAPPING_BLOCK_LEN];
-+};
-+
-+#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_`"
-+#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_-"
-+#define KB_EQUALS "kb_="
-+#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"
-+//#defi KB_I neuf, "i")) out[2] = 0x1c;
-+#define KB_O "kb_o"
-+#define KB_P "kb_p"
-+#define KB_LBRACKET "kb_["
-+#define KB_RBRACKET "kb_]"
-+#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_;"
-+#define KB_QUOTE "kb_'"
-+#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_COMA "kb_,"
-+#define KB_PERIOD "kb_."
-+// #defKB_uf, "/")) out[2] = 0x52; missing
-+#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_LCK "numpad_lck"
-+#define NUMPAD_FWDSLASH "numpad_/"
-+#define NUMPAD_STAR "numpad_*"
-+#define NUMPAD_HYPHEN "numpad_-"
-+#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_+"
-+#define NUMPAD_ENTER "numpad_enter"
-+#define NUMPAD_PERIOD "numpad_."
-+
-+#define RAT_LCLICK "rat_lclick"
-+#define RAT_RCLICK "rat_rclick"
-+#define RAT_MCLICK "rat_mclick"
-+#define RAT_WHEEL_UP "rat_wheel_up"
-+#define RAT_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"
-+
-+static struct asus_rog_ally *__rog_ally_data(struct device *raw_dev)
-+{
-+ struct hid_device *hdev = to_hid_device(raw_dev);
-+ return ((struct asus_drvdata *)hid_get_drvdata(hdev))->rog_ally_data;
-+}
-+
-+/* writes the bytes for a requested key/function in to the out buffer */
-+const static int __string_to_key_code(const char *buf, u8 *out, int out_len)
-+{
-+ 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
-+
-+ // Allow clearing
-+ if (!strcmp(buf, " ") || !strcmp(buf, "\n"))
-+ goto success;
-+
-+ // set group xpad
-+ out[0] = 0x01;
-+ if (!strcmp(buf, PAD_A)) out[1] = 0x01;
-+ else if (!strcmp(buf, PAD_B)) out[1] = 0x02;
-+ else if (!strcmp(buf, PAD_X)) out[1] = 0x03;
-+ else if (!strcmp(buf, PAD_Y)) out[1] = 0x04;
-+ else if (!strcmp(buf, PAD_LB)) out[1] = 0x05;
-+ else if (!strcmp(buf, PAD_RB)) out[1] = 0x06;
-+ else if (!strcmp(buf, PAD_LS)) out[1] = 0x07;
-+ else if (!strcmp(buf, PAD_RS)) out[1] = 0x08;
-+ else if (!strcmp(buf, PAD_DPAD_UP)) out[1] = 0x09;
-+ else if (!strcmp(buf, PAD_DPAD_DOWN)) out[1] = 0x0a;
-+ else if (!strcmp(buf, PAD_DPAD_LEFT)) out[1] = 0x0b;
-+ else if (!strcmp(buf, PAD_DPAD_RIGHT)) out[1] = 0x0c;
-+ else if (!strcmp(buf, PAD_VIEW)) out[1] = 0x11;
-+ else if (!strcmp(buf, PAD_MENU)) out[1] = 0x12;
-+ else if (!strcmp(buf, PAD_XBOX)) out[1] = 0x13;
-+ if (out[1])
-+ goto success;
-+
-+ // set group keyboard
-+ out[0] = 0x02;
-+ if (!strcmp(buf, KB_M1)) out[2] = 0x8f;
-+ else if (!strcmp(buf, KB_M2)) out[2] = 0x8e;
-+ else if (!strcmp(buf, KB_ESC)) out[2] = 0x76;
-+ else if (!strcmp(buf, KB_F1)) out[2] = 0x50;
-+ else if (!strcmp(buf, KB_F2)) out[2] = 0x60;
-+ else if (!strcmp(buf, KB_F3)) out[2] = 0x40;
-+ else if (!strcmp(buf, KB_F4)) out[2] = 0x0c;
-+ else if (!strcmp(buf, KB_F5)) out[2] = 0x03;
-+ else if (!strcmp(buf, KB_F6)) out[2] = 0x0b;
-+ else if (!strcmp(buf, KB_F7)) out[2] = 0x80;
-+ else if (!strcmp(buf, KB_F8)) out[2] = 0x0a;
-+ else if (!strcmp(buf, KB_F9)) out[2] = 0x01;
-+ else if (!strcmp(buf, KB_F10)) out[2] = 0x09;
-+ else if (!strcmp(buf, KB_F11)) out[2] = 0x78;
-+ else if (!strcmp(buf, KB_F12)) out[2] = 0x07;
-+ else if (!strcmp(buf, KB_F14)) out[2] = 0x10;
-+ else if (!strcmp(buf, KB_F15)) out[2] = 0x18;
-+
-+ else if (!strcmp(buf, KB_BACKTICK)) out[2] = 0x0e;
-+ else if (!strcmp(buf, KB_1)) out[2] = 0x16;
-+ else if (!strcmp(buf, KB_2)) out[2] = 0x1e;
-+ else if (!strcmp(buf, KB_3)) out[2] = 0x26;
-+ else if (!strcmp(buf, KB_4)) out[2] = 0x25;
-+ else if (!strcmp(buf, KB_5)) out[2] = 0x2e;
-+ else if (!strcmp(buf, KB_6)) out[2] = 0x36;
-+ else if (!strcmp(buf, KB_7)) out[2] = 0x3d;
-+ else if (!strcmp(buf, KB_8)) out[2] = 0x3e;
-+ else if (!strcmp(buf, KB_9)) out[2] = 0x46;
-+ else if (!strcmp(buf, KB_0)) out[2] = 0x45;
-+ else if (!strcmp(buf, KB_HYPHEN)) out[2] = 0x4e;
-+ else if (!strcmp(buf, KB_EQUALS)) out[2] = 0x55;
-+ else if (!strcmp(buf, KB_BACKSPACE)) out[2] = 0x66;
-+
-+ else if (!strcmp(buf, KB_TAB)) out[2] = 0x0d;
-+ else if (!strcmp(buf, KB_Q)) out[2] = 0x15;
-+ else if (!strcmp(buf, KB_W)) out[2] = 0x1d;
-+ else if (!strcmp(buf, KB_E)) out[2] = 0x24;
-+ else if (!strcmp(buf, KB_R)) out[2] = 0x2d;
-+ else if (!strcmp(buf, KB_T)) out[2] = 0x2d;
-+ else if (!strcmp(buf, KB_Y)) out[2] = 0x35;
-+ else if (!strcmp(buf, KB_U)) out[2] = 0x3c;
-+ // else if (!strcmp(buf, "i\n")) out[2] = 0x1c;
-+ else if (!strcmp(buf, KB_O)) out[2] = 0x44;
-+ else if (!strcmp(buf, KB_P)) out[2] = 0x4d;
-+ else if (!strcmp(buf, KB_LBRACKET)) out[2] = 0x54;
-+ else if (!strcmp(buf, KB_RBRACKET)) out[2] = 0x5b;
-+ else if (!strcmp(buf, KB_BACKSLASH)) out[2] = 0x5d;
-+
-+ else if (!strcmp(buf, KB_CAPS)) out[2] = 0x58;
-+ else if (!strcmp(buf, KB_A)) out[2] = 0x1c;
-+ else if (!strcmp(buf, KB_S)) out[2] = 0x1b;
-+ else if (!strcmp(buf, KB_D)) out[2] = 0x23;
-+ else if (!strcmp(buf, KB_F)) out[2] = 0x2b;
-+ else if (!strcmp(buf, KB_G)) out[2] = 0x34;
-+ else if (!strcmp(buf, KB_H)) out[2] = 0x33;
-+ else if (!strcmp(buf, KB_J)) out[2] = 0x3b;
-+ else if (!strcmp(buf, KB_K)) out[2] = 0x42;
-+ else if (!strcmp(buf, KB_L)) out[2] = 0x4b;
-+ else if (!strcmp(buf, KB_SEMI)) out[2] = 0x4c;
-+ else if (!strcmp(buf, KB_QUOTE)) out[2] = 0x52;
-+ else if (!strcmp(buf, KB_RET)) out[2] = 0x5a;
-+
-+ else if (!strcmp(buf, KB_LSHIFT)) out[2] = 0x88;
-+ else if (!strcmp(buf, KB_Z)) out[2] = 0x1a;
-+ else if (!strcmp(buf, KB_X)) out[2] = 0x22;
-+ else if (!strcmp(buf, KB_C)) out[2] = 0x21;
-+ else if (!strcmp(buf, KB_V)) out[2] = 0x2a;
-+ else if (!strcmp(buf, KB_B)) out[2] = 0x32;
-+ else if (!strcmp(buf, KB_N)) out[2] = 0x31;
-+ else if (!strcmp(buf, KB_M)) out[2] = 0x3a;
-+ else if (!strcmp(buf, KB_COMA)) out[2] = 0x41;
-+ else if (!strcmp(buf, KB_PERIOD)) out[2] = 0x49;
-+ // else if (!strcmp(buf, "/\n")) out[2] = 0x52; missing
-+ else if (!strcmp(buf, KB_RSHIFT)) out[2] = 0x89;
-+
-+ else if (!strcmp(buf, KB_LCTL)) out[2] = 0x8c;
-+ else if (!strcmp(buf, KB_META)) out[2] = 0x82;
-+ else if (!strcmp(buf, KB_LALT)) out[2] = 0xba;
-+ else if (!strcmp(buf, KB_SPACE)) out[2] = 0x29;
-+ else if (!strcmp(buf, KB_RALT)) out[2] = 0x8b;
-+ else if (!strcmp(buf, KB_MENU)) out[2] = 0x84;
-+ else if (!strcmp(buf, KB_RCTL)) out[2] = 0x8d;
-+
-+ else if (!strcmp(buf, KB_PRNTSCN)) out[2] = 0xc3;
-+ else if (!strcmp(buf, KB_SCRLCK)) out[2] = 0x7e;
-+ else if (!strcmp(buf, KB_PAUSE)) out[2] = 0x91;
-+ else if (!strcmp(buf, KB_INS)) out[2] = 0xc2;
-+ else if (!strcmp(buf, KB_HOME)) out[2] = 0x94;
-+ else if (!strcmp(buf, KB_PGUP)) out[2] = 0x96;
-+ else if (!strcmp(buf, KB_DEL)) out[2] = 0xc0;
-+ else if (!strcmp(buf, KB_END)) out[2] = 0x95;
-+ else if (!strcmp(buf, KB_PGDWN)) out[2] = 0x97;
-+
-+ else if (!strcmp(buf, KB_UP_ARROW)) out[2] = 0x99;
-+ else if (!strcmp(buf, KB_DOWN_ARROW)) out[2] = 0x98;
-+ else if (!strcmp(buf, KB_LEFT_ARROW)) out[2] = 0x91;
-+ else if (!strcmp(buf, KB_RIGHT_ARROW)) out[2] = 0x9b;
-+
-+ else if (!strcmp(buf, NUMPAD_LCK)) out[2] = 0x77;
-+ else if (!strcmp(buf, NUMPAD_FWDSLASH)) out[2] = 0x90;
-+ else if (!strcmp(buf, NUMPAD_STAR)) out[2] = 0x7c;
-+ else if (!strcmp(buf, NUMPAD_HYPHEN)) out[2] = 0x7b;
-+ else if (!strcmp(buf, NUMPAD_0)) out[2] = 0x70;
-+ else if (!strcmp(buf, NUMPAD_1)) out[2] = 0x69;
-+ else if (!strcmp(buf, NUMPAD_2)) out[2] = 0x72;
-+ else if (!strcmp(buf, NUMPAD_3)) out[2] = 0x7a;
-+ else if (!strcmp(buf, NUMPAD_4)) out[2] = 0x6b;
-+ else if (!strcmp(buf, NUMPAD_5)) out[2] = 0x73;
-+ else if (!strcmp(buf, NUMPAD_6)) out[2] = 0x74;
-+ else if (!strcmp(buf, NUMPAD_7)) out[2] = 0x6c;
-+ else if (!strcmp(buf, NUMPAD_8)) out[2] = 0x75;
-+ else if (!strcmp(buf, NUMPAD_9)) out[2] = 0x7d;
-+ else if (!strcmp(buf, NUMPAD_PLUS)) out[2] = 0x79;
-+ else if (!strcmp(buf, NUMPAD_ENTER)) out[2] = 0x81;
-+ else if (!strcmp(buf, NUMPAD_PERIOD)) out[2] = 0x71;
-+ if (out[2])
-+ goto success;
-+
-+ out[0] = 0x03;
-+ if (!strcmp(buf, RAT_LCLICK)) out[4] = 0x01;
-+ else if (!strcmp(buf, RAT_RCLICK)) out[4] = 0x02;
-+ else if (!strcmp(buf, RAT_MCLICK)) out[4] = 0x03;
-+ else if (!strcmp(buf, RAT_WHEEL_UP)) out[4] = 0x04;
-+ else if (!strcmp(buf, RAT_WHEEL_DOWN)) out[4] = 0x05;
-+ if (out[4] != 0)
-+ goto success;
-+
-+ out[0] = 0x05;
-+ if (!strcmp(buf, MEDIA_SCREENSHOT)) out[3] = 0x16;
-+ else if (!strcmp(buf, MEDIA_SHOW_KEYBOARD)) out[3] = 0x19;
-+ else if (!strcmp(buf, MEDIA_SHOW_DESKTOP)) out[3] = 0x1c;
-+ else if (!strcmp(buf, MEDIA_START_RECORDING)) out[3] = 0x1e;
-+ else if (!strcmp(buf, MEDIA_MIC_OFF)) out[3] = 0x01;
-+ else if (!strcmp(buf, MEDIA_VOL_DOWN)) out[3] = 0x02;
-+ else if (!strcmp(buf, MEDIA_VOL_UP)) out[3] = 0x03;
-+ if (out[3])
-+ goto success;
-+
-+ // restore bytes if invalid input
-+ memcpy(out, save_buf, out_len);
-+ kfree(save_buf);
-+ return -EINVAL;
-+
-+success:
-+ kfree(save_buf);
-+ return 0;
-+}
-+
-+const static char* __btn_map_to_string(struct device *raw_dev, enum btn_pair pair, enum btn_pair_side side, bool secondary)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ u8 *btn_block;
-+ int offs;
-+
-+ // TODO: this little block is common
-+ offs = side ? MAPPING_BLOCK_LEN / 2 : 0;
-+ offs = secondary ? offs + BTN_CODE_LEN : offs;
-+ btn_block = rog_ally->key_mapping[rog_ally->mode - 1][pair - 1] + offs;
-+
-+ if (btn_block[0] == 0x01) {
-+ if (btn_block[1] == 0x01) return PAD_A;
-+ if (btn_block[1] == 0x02) return PAD_B;
-+ if (btn_block[1] == 0x03) return PAD_X;
-+ if (btn_block[1] == 0x04) return PAD_Y;
-+ if (btn_block[1] == 0x05) return PAD_LB;
-+ if (btn_block[1] == 0x06) return PAD_RB;
-+ if (btn_block[1] == 0x07) return PAD_LS;
-+ if (btn_block[1] == 0x08) return PAD_RS;
-+ if (btn_block[1] == 0x09) return PAD_DPAD_UP;
-+ if (btn_block[1] == 0x0a) return PAD_DPAD_DOWN;
-+ if (btn_block[1] == 0x0b) return PAD_DPAD_LEFT;
-+ if (btn_block[1] == 0x0c) return PAD_DPAD_RIGHT;
-+ if (btn_block[1] == 0x11) return PAD_VIEW;
-+ if (btn_block[1] == 0x12) return PAD_MENU;
-+ if (btn_block[1] == 0x13) return PAD_XBOX;
-+ }
-+
-+ if (btn_block[0] == 0x02) {
-+ if (btn_block[2] == 0x8f) return KB_M1;
-+ if (btn_block[2] == 0x8e) return KB_M2;
-+
-+ if (btn_block[2] == 0x76) return KB_ESC;
-+ if (btn_block[2] == 0x50) return KB_F1;
-+ if (btn_block[2] == 0x60) return KB_F2;
-+ if (btn_block[2] == 0x40) return KB_F3;
-+ if (btn_block[2] == 0x0c) return KB_F4;
-+ if (btn_block[2] == 0x03) return KB_F5;
-+ if (btn_block[2] == 0x0b) return KB_F6;
-+ if (btn_block[2] == 0x80) return KB_F7;
-+ if (btn_block[2] == 0x0a) return KB_F8;
-+ if (btn_block[2] == 0x01) return KB_F9;
-+ if (btn_block[2] == 0x09) return KB_F10;
-+ if (btn_block[2] == 0x78) return KB_F11;
-+ if (btn_block[2] == 0x07) return KB_F12;
-+ if (btn_block[2] == 0x10) return KB_F14;
-+ if (btn_block[2] == 0x18) return KB_F15;
-+
-+ if (btn_block[2] == 0x0e) return KB_BACKTICK;
-+ if (btn_block[2] == 0x16) return KB_1;
-+ if (btn_block[2] == 0x1e) return KB_2;
-+ if (btn_block[2] == 0x26) return KB_3;
-+ if (btn_block[2] == 0x25) return KB_4;
-+ if (btn_block[2] == 0x2e) return KB_5;
-+ if (btn_block[2] == 0x36) return KB_6;
-+ if (btn_block[2] == 0x3d) return KB_7;
-+ if (btn_block[2] == 0x3e) return KB_8;
-+ if (btn_block[2] == 0x46) return KB_9;
-+ if (btn_block[2] == 0x45) return KB_0;
-+ if (btn_block[2] == 0x4e) return KB_HYPHEN;
-+ if (btn_block[2] == 0x55) return KB_EQUALS;
-+ if (btn_block[2] == 0x66) return KB_BACKSPACE;
-+
-+ if (btn_block[2] == 0x0d) return KB_TAB;
-+ if (btn_block[2] == 0x15) return KB_Q;
-+ if (btn_block[2] == 0x1d) return KB_W;
-+ if (btn_block[2] == 0x24) return KB_E;
-+ if (btn_block[2] == 0x2d) return KB_R;
-+ if (btn_block[2] == 0x2d) return KB_T;
-+ if (btn_block[2] == 0x35) return KB_Y;
-+ if (btn_block[2] == 0x3c) return KB_U;
-+ // TODO: I
-+ if (btn_block[2] == 0x44) return KB_O;
-+ if (btn_block[2] == 0x4d) return KB_P;
-+ if (btn_block[2] == 0x54) return KB_LBRACKET;
-+ if (btn_block[2] == 0x5b) return KB_RBRACKET;
-+ if (btn_block[2] == 0x5d) return KB_BACKSLASH;
-+
-+ if (btn_block[2] == 0x58) return KB_CAPS;
-+ if (btn_block[2] == 0x1c) return KB_A;
-+ if (btn_block[2] == 0x1b) return KB_S;
-+ if (btn_block[2] == 0x23) return KB_D;
-+ if (btn_block[2] == 0x2b) return KB_F;
-+ if (btn_block[2] == 0x34) return KB_G;
-+ if (btn_block[2] == 0x33) return KB_H;
-+ if (btn_block[2] == 0x3b) return KB_J;
-+ if (btn_block[2] == 0x42) return KB_K;
-+ if (btn_block[2] == 0x4b) return KB_L;
-+ if (btn_block[2] == 0x4c) return KB_SEMI;
-+ if (btn_block[2] == 0x52) return KB_QUOTE;
-+ if (btn_block[2] == 0x5a) return KB_RET;
-+
-+ if (btn_block[2] == 0x88) return KB_LSHIFT;
-+ if (btn_block[2] == 0x1a) return KB_Z;
-+ if (btn_block[2] == 0x22) return KB_X;
-+ if (btn_block[2] == 0x21) return KB_C;
-+ if (btn_block[2] == 0x2a) return KB_V;
-+ if (btn_block[2] == 0x32) return KB_B;
-+ if (btn_block[2] == 0x31) return KB_N;
-+ if (btn_block[2] == 0x3a) return KB_M;
-+ if (btn_block[2] == 0x41) return KB_COMA;
-+ if (btn_block[2] == 0x49) return KB_PERIOD;
-+ if (btn_block[2] == 0x89) return KB_RSHIFT;
-+
-+ if (btn_block[2] == 0x8c) return KB_LCTL;
-+ if (btn_block[2] == 0x82) return KB_META;
-+ if (btn_block[2] == 0xba) return KB_LALT;
-+ if (btn_block[2] == 0x29) return KB_SPACE;
-+ if (btn_block[2] == 0x8b) return KB_RALT;
-+ if (btn_block[2] == 0x84) return KB_MENU;
-+ if (btn_block[2] == 0x8d) return KB_RCTL;
-+
-+ if (btn_block[2] == 0xc3) return KB_PRNTSCN;
-+ if (btn_block[2] == 0x7e) return KB_SCRLCK;
-+ if (btn_block[2] == 0x91) return KB_PAUSE;
-+ if (btn_block[2] == 0xc2) return KB_INS;
-+ if (btn_block[2] == 0x94) return KB_HOME;
-+ if (btn_block[2] == 0x96) return KB_PGUP;
-+ if (btn_block[2] == 0xc0) return KB_DEL;
-+ if (btn_block[2] == 0x95) return KB_END;
-+ if (btn_block[2] == 0x97) return KB_PGDWN;
-+
-+ if (btn_block[2] == 0x99) return KB_UP_ARROW;
-+ if (btn_block[2] == 0x98) return KB_DOWN_ARROW;
-+ if (btn_block[2] == 0x91) return KB_LEFT_ARROW;
-+ if (btn_block[2] == 0x9b) return KB_RIGHT_ARROW;
-+
-+ if (btn_block[2] == 0x77) return NUMPAD_LCK;
-+ if (btn_block[2] == 0x90) return NUMPAD_FWDSLASH;
-+ if (btn_block[2] == 0x7c) return NUMPAD_STAR;
-+ if (btn_block[2] == 0x7b) return NUMPAD_HYPHEN;
-+ if (btn_block[2] == 0x70) return NUMPAD_0;
-+ if (btn_block[2] == 0x69) return NUMPAD_1;
-+ if (btn_block[2] == 0x72) return NUMPAD_2;
-+ if (btn_block[2] == 0x7a) return NUMPAD_3;
-+ if (btn_block[2] == 0x6b) return NUMPAD_4;
-+ if (btn_block[2] == 0x73) return NUMPAD_5;
-+ if (btn_block[2] == 0x74) return NUMPAD_6;
-+ if (btn_block[2] == 0x6c) return NUMPAD_7;
-+ if (btn_block[2] == 0x75) return NUMPAD_8;
-+ if (btn_block[2] == 0x7d) return NUMPAD_9;
-+ if (btn_block[2] == 0x79) return NUMPAD_PLUS;
-+ if (btn_block[2] == 0x81) return NUMPAD_ENTER;
-+ if (btn_block[2] == 0x71) return NUMPAD_PERIOD;
-+ }
-+
-+ if (btn_block[0] == 0x03) {
-+ if (btn_block[4] == 0x01) return RAT_LCLICK;
-+ if (btn_block[4] == 0x02) return RAT_RCLICK;
-+ if (btn_block[4] == 0x03) return RAT_MCLICK;
-+ if (btn_block[4] == 0x04) return RAT_WHEEL_UP;
-+ if (btn_block[4] == 0x05) return RAT_WHEEL_DOWN;
-+ }
-+
-+ if (btn_block[0] == 0x05) {
-+ if (btn_block[3] == 0x16) return MEDIA_SCREENSHOT;
-+ if (btn_block[3] == 0x19) return MEDIA_SHOW_KEYBOARD;
-+ if (btn_block[3] == 0x1c) return MEDIA_SHOW_DESKTOP;
-+ if (btn_block[3] == 0x1e) return MEDIA_START_RECORDING;
-+ if (btn_block[3] == 0x01) return MEDIA_MIC_OFF;
-+ if (btn_block[3] == 0x02) return MEDIA_VOL_DOWN;
-+ if (btn_block[3] == 0x03) return MEDIA_VOL_UP;
-+ }
-+
-+ 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)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_KBD_REPORT_ID;
-+ hidbuf[1] = 0xD1;
-+ hidbuf[2] = ally_xpad_cmd_check_ready;
-+ hidbuf[3] = 01;
-+ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0;
-+ ret = asus_kbd_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = hidbuf[2] == ally_xpad_cmd_check_ready;
-+ if (!ret) {
-+ hid_warn(hdev, "ROG Ally not ready\n");
-+ ret = -ENOMSG;
-+ }
-+
-+ kfree(hidbuf);
-+ return ret;
-+
-+report_fail:
-+ hid_dbg(hdev, "ROG Ally check failed get report: %d\n", ret);
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+/********** BUTTON REMAPPING *********************************************************************/
-+static void __btn_pair_to_pkt(struct device *raw_dev, enum btn_pair pair, u8 *out, int out_len)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+
-+ out[0] = FEATURE_KBD_REPORT_ID;
-+ out[1] = 0xD1;
-+ out[2] = 0x02;
-+ out[3] = pair;
-+ out[4] = 0x2c; //length
-+ memcpy(&out[5], &rog_ally->key_mapping[rog_ally->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 device *raw_dev, const char *buf, enum btn_pair pair, int side,
-+ bool secondary)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ u8 *key_code;
-+ int offs;
-+
-+ offs = side ? MAPPING_BLOCK_LEN / 2 : 0;
-+ offs = secondary ? offs + BTN_CODE_LEN : offs;
-+ key_code = rog_ally->key_mapping[rog_ally->mode - 1][pair - 1] + offs;
-+
-+ return __string_to_key_code(buf, key_code, BTN_CODE_LEN);
-+}
-+
-+/* Apply the mapping pair to the device */
-+static int __gamepad_set_mapping(struct device *raw_dev, enum btn_pair pair)
-+{
-+ struct hid_device *hdev = to_hid_device(raw_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;
-+
-+ __btn_pair_to_pkt(raw_dev, pair, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ kfree(hidbuf);
-+
-+ return ret;
-+}
-+
-+static int __gamepad_set_mapping_all(struct device *raw_dev)
-+{
-+ struct hid_device *hdev = to_hid_device(raw_dev);
-+ int ret;
-+
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_dpad_u_d);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_dpad_l_r);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_ls_rs);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_lb_rb);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_a_b);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_x_y);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_view_menu);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_m1_m2);
-+ if (ret < 0)
-+ return ret;
-+ return __gamepad_set_mapping(&hdev->dev, btn_pair_lt_rt);
-+}
-+
-+static ssize_t btn_mapping_apply_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_set_mapping_all(raw_dev);
-+ if (ret < 0)
-+ return ret;
-+ return count;
-+}
-+ALLY_DEVICE_ATTR_WO(btn_mapping_apply, apply);
-+
-+/* button map attributes, regular and macro*/
-+#define ALLY_BTN_SHOW(_fname, _pair, _side, _secondary) \
-+static ssize_t _fname##_show(struct device *raw_dev, struct device_attribute *attr, char *buf) { \
-+ return sysfs_emit(buf, "%s\n", __btn_map_to_string(raw_dev, _pair, _side, _secondary)); \
-+}
-+
-+#define ALLY_BTN_STORE(_fname, _pair, _side, _secondary) \
-+static ssize_t _fname##_store(struct device *raw_dev, struct device_attribute *attr, \
-+ const char *buf, size_t count) { \
-+ int ret = __gamepad_mapping_store(raw_dev, buf, _pair, _side, _secondary); \
-+ if (ret < 0) return ret; \
-+ return count; \
-+}
-+
-+#define ALLY_BTN_MAPPING(_fname, _sysname, _pair, _side) \
-+ ALLY_BTN_SHOW(_fname, _pair, _side, false); \
-+ ALLY_BTN_STORE(_fname, _pair, _side, false); \
-+ ALLY_BTN_SHOW(_fname##_macro, _pair, _side, true); \
-+ ALLY_BTN_STORE(_fname##_macro, _pair, _side, true); \
-+ ALLY_DEVICE_ATTR_RW(_fname, _sysname); \
-+ ALLY_DEVICE_ATTR_RW(_fname##_macro, _sysname##_macro);
-+
-+ALLY_BTN_MAPPING(btn_mapping_m2, M2, btn_pair_m1_m2, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_m1, M1, btn_pair_m1_m2, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_a, A, btn_pair_a_b, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_b, B, btn_pair_a_b, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_x, X, btn_pair_x_y, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_y, Y, btn_pair_x_y, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_lb, LB, btn_pair_lb_rb, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_rb, RB, btn_pair_lb_rb, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_ls, LS, btn_pair_ls_rs, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_rs, RS, btn_pair_ls_rs, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_lt, LT, btn_pair_lt_rt, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_rt, RT, btn_pair_lt_rt, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_dpad_u, dpad_U, btn_pair_dpad_u_d, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_dpad_d, dpad_D, btn_pair_dpad_u_d, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_dpad_l, dpad_L, btn_pair_dpad_l_r, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_dpad_r, dpad_R, btn_pair_dpad_l_r, btn_pair_side_right);
-+ALLY_BTN_MAPPING(btn_mapping_view, view, btn_pair_view_menu, btn_pair_side_left);
-+ALLY_BTN_MAPPING(btn_mapping_menu, menu, btn_pair_view_menu, btn_pair_side_right);
-+
-+static void __gamepad_mapping_xpad_default(struct asus_rog_ally *rog_ally)
-+{
-+ u8 map1[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};
-+ u8 map2[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};
-+ u8 map3[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};
-+ u8 map4[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};
-+ u8 map5[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};
-+ u8 map6[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};
-+ u8 map7[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};
-+ u8 map8[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};
-+ u8 map9[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};
-+ memcpy(&rog_ally->key_mapping[0][0], &map1, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][1], &map2, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][2], &map3, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][3], &map4, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][4], &map5, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][5], &map6, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][6], &map7, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][7], &map8, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[0][8], &map9, MAPPING_BLOCK_LEN);
-+}
-+
-+static void __gamepad_mapping_wasd_default(struct asus_rog_ally *rog_ally)
-+{
-+ u8 map1[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};
-+ u8 map2[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};
-+ u8 map3[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};
-+ u8 map4[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};
-+ u8 map5[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};
-+ u8 map6[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};
-+ u8 map7[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};
-+ u8 map8[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};
-+ u8 map9[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};
-+ memcpy(&rog_ally->key_mapping[1][0], &map1, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][1], &map2, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][2], &map3, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][3], &map4, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][4], &map5, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][5], &map6, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][6], &map7, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][7], &map8, MAPPING_BLOCK_LEN);
-+ memcpy(&rog_ally->key_mapping[1][8], &map9, MAPPING_BLOCK_LEN);
-+}
-+
-+static ssize_t btn_mapping_reset_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ switch (rog_ally->mode)
-+ {
-+ case ally_xpad_mode_game:
-+ __gamepad_mapping_xpad_default(rog_ally);
-+ break;
-+ case ally_xpad_mode_wasd:
-+ __gamepad_mapping_wasd_default(rog_ally);
-+ break;
-+ default:
-+ __gamepad_mapping_xpad_default(rog_ally);
-+ break;
-+ }
-+
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset);
-+
-+static struct attribute *gamepad_button_mapping_attrs[] = { &dev_attr_btn_mapping_apply.attr,
-+ &dev_attr_btn_mapping_reset.attr,
-+ &dev_attr_btn_mapping_m2.attr,
-+ &dev_attr_btn_mapping_m2_macro.attr,
-+ &dev_attr_btn_mapping_m1.attr,
-+ &dev_attr_btn_mapping_m1_macro.attr,
-+ &dev_attr_btn_mapping_a.attr,
-+ &dev_attr_btn_mapping_a_macro.attr,
-+ &dev_attr_btn_mapping_b.attr,
-+ &dev_attr_btn_mapping_b_macro.attr,
-+ &dev_attr_btn_mapping_x.attr,
-+ &dev_attr_btn_mapping_x_macro.attr,
-+ &dev_attr_btn_mapping_y.attr,
-+ &dev_attr_btn_mapping_y_macro.attr,
-+ &dev_attr_btn_mapping_lb.attr,
-+ &dev_attr_btn_mapping_lb_macro.attr,
-+ &dev_attr_btn_mapping_rb.attr,
-+ &dev_attr_btn_mapping_rb_macro.attr,
-+ &dev_attr_btn_mapping_ls.attr,
-+ &dev_attr_btn_mapping_ls_macro.attr,
-+ &dev_attr_btn_mapping_rs.attr,
-+ &dev_attr_btn_mapping_rs_macro.attr,
-+ &dev_attr_btn_mapping_lt.attr,
-+ &dev_attr_btn_mapping_lt_macro.attr,
-+ &dev_attr_btn_mapping_rt.attr,
-+ &dev_attr_btn_mapping_rt_macro.attr,
-+ &dev_attr_btn_mapping_dpad_u.attr,
-+ &dev_attr_btn_mapping_dpad_u_macro.attr,
-+ &dev_attr_btn_mapping_dpad_d.attr,
-+ &dev_attr_btn_mapping_dpad_d_macro.attr,
-+ &dev_attr_btn_mapping_dpad_l.attr,
-+ &dev_attr_btn_mapping_dpad_l_macro.attr,
-+ &dev_attr_btn_mapping_dpad_r.attr,
-+ &dev_attr_btn_mapping_dpad_r_macro.attr,
-+ &dev_attr_btn_mapping_view.attr,
-+ &dev_attr_btn_mapping_view_macro.attr,
-+ &dev_attr_btn_mapping_menu.attr,
-+ &dev_attr_btn_mapping_menu_macro.attr,
-+ NULL };
-+
-+static const struct attribute_group ally_controller_button_mapping_attr_group = {
-+ .name = "button_mapping",
-+ .attrs = gamepad_button_mapping_attrs,
-+};
-+
-+/********** GAMEPAD MODE *************************************************************************/
-+// TODO: general purpose request function which checks the device is ready before setting
-+/* The gamepad mode also needs to be set on boot/mod-load and shutdown */
-+static ssize_t __gamepad_set_mode(struct device *raw_dev, int val)
-+{
-+ struct hid_device *hdev = to_hid_device(raw_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;
-+
-+ hidbuf[0] = FEATURE_KBD_REPORT_ID;
-+ hidbuf[1] = 0xD1;
-+ hidbuf[2] = ally_xpad_cmd_set_mode;
-+ hidbuf[3] = 0x01;
-+ hidbuf[4] = val;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = asus_kbd_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_mode_show(struct device *raw_dev, struct device_attribute *attr, char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ return sysfs_emit(buf, "%d\n", rog_ally->mode);
-+}
-+
-+static ssize_t gamepad_mode_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ int ret, val;
-+
-+ ret = kstrtoint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ if (val < ally_xpad_mode_game || val > ally_xpad_mode_mouse)
-+ return -EINVAL;
-+
-+ rog_ally->mode = val;
-+
-+ ret = __gamepad_set_mode(raw_dev, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ return count;
-+}
-+
-+DEVICE_ATTR_RW(gamepad_mode);
-+
-+static struct attribute *gamepad_device_attrs[] = { &dev_attr_gamepad_mode.attr, NULL };
-+
-+static const struct attribute_group ally_controller_attr_group = {
-+ .attrs = gamepad_device_attrs,
-+};
-+
-+/********** ANALOGUE DEADZONES ********************************************************************/
-+static ssize_t __gamepad_set_deadzones(struct device *raw_dev, enum ally_xpad_axis axis,
-+ const char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ struct hid_device *hdev = to_hid_device(raw_dev);
-+ int ret, cmd, side, is_tr;
-+ u32 inner, outer;
-+ u8 *hidbuf;
-+
-+ if (sscanf(buf, "%d %d", &inner, &outer) != 2)
-+ return -EINVAL;
-+
-+ if (inner > 64 || outer > 64 || inner > outer)
-+ return -EINVAL;
-+
-+ is_tr = axis > ally_xpad_axis_xy_right;
-+ side = axis == ally_xpad_axis_xy_right || axis == ally_xpad_axis_z_right ? 2 : 0;
-+ cmd = is_tr ? ally_xpad_cmd_set_js_dz : ally_xpad_cmd_set_tr_dz;
-+
-+ rog_ally->deadzones[is_tr][side] = inner;
-+ rog_ally->deadzones[is_tr][side + 1] = outer;
-+
-+ 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_KBD_REPORT_ID;
-+ hidbuf[1] = 0xD1;
-+ hidbuf[2] = cmd;
-+ hidbuf[3] = 0x04; // length
-+ hidbuf[4] = rog_ally->deadzones[is_tr][0];
-+ hidbuf[5] = rog_ally->deadzones[is_tr][1];
-+ hidbuf[6] = rog_ally->deadzones[is_tr][2];
-+ hidbuf[7] = rog_ally->deadzones[is_tr][3];
-+
-+ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t axis_xyz_deadzone_index_show(struct device *raw_dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "inner outer\n");
-+}
-+
-+static ssize_t axis_xy_left_deadzone_show(struct device *raw_dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ return sysfs_emit(buf, "%d %d\n", rog_ally->deadzones[0][0], rog_ally->deadzones[0][1]);
-+}
-+
-+static ssize_t axis_xy_left_deadzone_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_set_deadzones(raw_dev, ally_xpad_axis_xy_left, buf);
-+ if (ret < 0)
-+ return ret;
-+ return count;
-+}
-+
-+static ssize_t axis_xy_right_deadzone_show(struct device *raw_dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ return sysfs_emit(buf, "%d %d\n", rog_ally->deadzones[0][2], rog_ally->deadzones[0][3]);
-+}
-+
-+static ssize_t axis_xy_right_deadzone_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_set_deadzones(raw_dev, ally_xpad_axis_xy_right, buf);
-+ if (ret < 0)
-+ return ret;
-+ return count;
-+}
-+
-+static ssize_t axis_z_left_deadzone_show(struct device *raw_dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ return sysfs_emit(buf, "%d %d\n", rog_ally->deadzones[1][0], rog_ally->deadzones[1][1]);
-+}
-+
-+static ssize_t axis_z_left_deadzone_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_set_deadzones(raw_dev, ally_xpad_axis_z_left, buf);
-+ if (ret < 0)
-+ return ret;
-+ return count;
-+}
-+
-+static ssize_t axis_z_right_deadzone_show(struct device *raw_dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
-+ return sysfs_emit(buf, "%d %d\n", rog_ally->deadzones[1][2], rog_ally->deadzones[1][3]);
-+}
-+
-+static ssize_t axis_z_right_deadzone_store(struct device *raw_dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_set_deadzones(raw_dev, ally_xpad_axis_z_right, buf);
-+ if (ret < 0)
-+ return ret;
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index);
-+ALLY_DEVICE_ATTR_RW(axis_xy_left_deadzone, deadzone);
-+ALLY_DEVICE_ATTR_RW(axis_xy_right_deadzone, deadzone);
-+ALLY_DEVICE_ATTR_RW(axis_z_left_deadzone, deadzone);
-+ALLY_DEVICE_ATTR_RW(axis_z_right_deadzone, deadzone);
-+
-+static struct attribute *gamepad_axis_xy_left_attrs[] = { &dev_attr_axis_xy_left_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_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_axis_xy_right_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_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_axis_z_left_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_index.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_axis_z_right_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_index.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,
-+ &ally_controller_button_mapping_attr_group,
-+ NULL
-+};
-+
-+static int asus_rog_ally_probe(struct hid_device *hdev, const struct rog_ops *ops)
-+{
-+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
-+ int ret;
-+
-+ /* all ROG devices have this HID interface but we will focus on Ally for now */
-+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && hid_is_usb(hdev)) {
-+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-+
-+ if (intf->altsetting->desc.bInterfaceNumber == 0) {
-+ hid_info(hdev, "Setting up ROG USB interface\n");
-+ /* initialise and set up USB, common to ROG */
-+ // TODO:
-+
-+ /* initialise the Ally data */
-+ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) {
-+ hid_info(hdev, "Setting up ROG Ally interface\n");
-+
-+ drvdata->rog_ally_data = devm_kzalloc(
-+ &hdev->dev, sizeof(*drvdata->rog_ally_data), GFP_KERNEL);
-+ if (!drvdata->rog_ally_data) {
-+ hid_err(hdev, "Can't alloc Asus ROG USB interface\n");
-+ ret = -ENOMEM;
-+ goto err_stop_hw;
-+ }
-+ drvdata->rog_ally_data->mode = ally_xpad_mode_game;
-+ drvdata->rog_ally_data->deadzones[0][1] = 64;
-+ drvdata->rog_ally_data->deadzones[0][3] = 64;
-+ drvdata->rog_ally_data->deadzones[1][1] = 64;
-+ drvdata->rog_ally_data->deadzones[1][3] = 64;
-+
-+ ret = __gamepad_set_mode(&hdev->dev, ally_xpad_mode_game);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_mapping_xpad_default(drvdata->rog_ally_data);
-+ // these calls will never error so ignore the return
-+ __gamepad_mapping_store(&hdev->dev, "kb_f14", btn_pair_m1_m2,
-+ btn_pair_side_left, false); // M2
-+ __gamepad_mapping_store(&hdev->dev, "kb_f15", btn_pair_m1_m2,
-+ btn_pair_side_right, false); // M1
-+ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_m1_m2);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups))
-+ goto err_stop_hw;
-+ }
-+ }
-+
-+ return 0;
-+err_stop_hw:
-+ hid_hw_stop(hdev);
-+ return ret;
-+}
-+
-+void asus_rog_ally_remove(struct hid_device *hdev, const struct rog_ops *ops)
-+{
-+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
-+ if (drvdata->rog_ally_data) {
-+ __gamepad_set_mode(&hdev->dev, ally_xpad_mode_mouse);
-+ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups);
-+ }
-+}
-+
-+const struct rog_ops rog_ally = {
-+ .probe = asus_rog_ally_probe,
-+ .remove = asus_rog_ally_remove,
-+};
-diff --git a/drivers/hid/hid-asus.h b/drivers/hid/hid-asus.h
-new file mode 100644
-index 000000000000..e7d7041b56fb
---- /dev/null
-+++ b/drivers/hid/hid-asus.h
-@@ -0,0 +1,51 @@
-+#include <linux/hid.h>
-+#include <linux/types.h>
-+
-+#define FEATURE_KBD_REPORT_ID 0x5a
-+#define FEATURE_KBD_REPORT_SIZE 16
-+#define FEATURE_KBD_LED_REPORT_ID1 0x5d
-+#define FEATURE_KBD_LED_REPORT_ID2 0x5e
-+#define FEATURE_ROG_ALLY_REPORT_SIZE 64
-+
-+#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
-+#define QUIRK_NO_INIT_REPORTS BIT(1)
-+#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
-+#define QUIRK_IS_MULTITOUCH BIT(3)
-+#define QUIRK_NO_CONSUMER_USAGES BIT(4)
-+#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
-+#define QUIRK_T100_KEYBOARD BIT(6)
-+#define QUIRK_T100CHI BIT(7)
-+#define QUIRK_G752_KEYBOARD BIT(8)
-+#define QUIRK_T90CHI BIT(9)
-+#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)
-+
-+struct asus_drvdata {
-+ unsigned long quirks;
-+ struct hid_device *hdev;
-+ struct input_dev *input;
-+ struct input_dev *tp_kbd_input;
-+ struct asus_kbd_leds *kbd_backlight;
-+ const struct asus_touchpad_info *tp;
-+ bool enable_backlight;
-+ struct power_supply *battery;
-+ struct power_supply_desc battery_desc;
-+ int battery_capacity;
-+ int battery_stat;
-+ bool battery_in_query;
-+ unsigned long battery_next_query;
-+ struct asus_rog_ally *rog_ally_data;
-+};
-+
-+extern int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size);
-+
-+extern int asus_kbd_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size);
-+
-+struct rog_ops {
-+ int (*probe) (struct hid_device *hdev, const struct rog_ops *ops);
-+ void (*remove) (struct hid_device *hdev, const struct rog_ops *ops);
-+};
-+
-+extern const struct rog_ops rog_ally;
-\ No newline at end of file
---
-2.41.0
-
diff --git a/SOURCES/v10-0001-HID-asus-fix-more-n-key-report-descriptors-if-n-.patch b/SOURCES/v14.8-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch
index 61107eb..3aa05b5 100644
--- a/SOURCES/v10-0001-HID-asus-fix-more-n-key-report-descriptors-if-n-.patch
+++ b/SOURCES/v14.8-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch
@@ -1,8 +1,8 @@
-From f311b6a3ff32c8221a0003c4a154aecbf04fb12c Mon Sep 17 00:00:00 2001
+From 5efbf21a6dc030b27e32cd632cfde1c3c7801075 Mon Sep 17 00:00:00 2001
From: "Luke D. Jones" <luke@ljones.dev>
Date: Sat, 2 Dec 2023 17:27:23 +1300
-Subject: [PATCH v10 1/4] HID: asus: fix more n-key report descriptors if n-key
- quirked
+Subject: [PATCH v14.7 1/4] HID: asus: fix more n-key report descriptors if
+ n-key quirked
Adjusts the report descriptor for N-Key devices to
make the output count 0x01 which completely avoids
@@ -85,5 +85,5 @@ index 78cdfb8b9a7a..855972a4470f 100644
}
--
-2.41.0
+2.43.0
diff --git a/SOURCES/v10-0002-HID-asus-make-asus_kbd_init-generic-remove-rog_n.patch b/SOURCES/v14.8-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch
index 670480b..f0f4967 100644
--- a/SOURCES/v10-0002-HID-asus-make-asus_kbd_init-generic-remove-rog_n.patch
+++ b/SOURCES/v14.8-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch
@@ -1,7 +1,7 @@
-From 119615a0034ee5f8d7a949c1c9d992b1be125fcb Mon Sep 17 00:00:00 2001
+From d6b33439281d1b8cf93b0c5c5ecabcd9c6e7baad Mon Sep 17 00:00:00 2001
From: "Luke D. Jones" <luke@ljones.dev>
Date: Sat, 2 Dec 2023 17:47:59 +1300
-Subject: [PATCH v10 2/4] HID: asus: make asus_kbd_init() generic, remove
+Subject: [PATCH v14.7 2/4] HID: asus: make asus_kbd_init() generic, remove
rog_nkey_led_init()
Some of the n-key stuff is old and outdated, so
@@ -126,5 +126,5 @@ index 855972a4470f..cdd998a761fe 100644
return ret;
--
-2.41.0
+2.43.0
diff --git a/SOURCES/v10-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch b/SOURCES/v14.8-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch
index 8cca8ca..a2a2785 100644
--- a/SOURCES/v10-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch
+++ b/SOURCES/v14.8-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch
@@ -1,7 +1,7 @@
-From 2b1a33a519668105eb7261c2d8964da576be6146 Mon Sep 17 00:00:00 2001
+From 646c1ffacd59555825734bbcd2fa6e38100570c5 Mon Sep 17 00:00:00 2001
From: "Luke D. Jones" <luke@ljones.dev>
Date: Wed, 29 Nov 2023 22:18:11 +1300
-Subject: [PATCH v10 3/4] HID: asus: add ROG Ally N-Key ID and keycodes
+Subject: [PATCH v14.7 3/4] HID: asus: add ROG Ally N-Key ID and keycodes
---
drivers/hid/hid-asus.c | 7 +++++++
@@ -34,7 +34,7 @@ index cdd998a761fe..3a1a6024d299 100644
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
-index c6e4e0d1f214..6debff9ad678 100644
+index 72046039d1be..ec9a41050446 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -208,6 +208,7 @@
@@ -46,5 +46,5 @@ index c6e4e0d1f214..6debff9ad678 100644
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
--
-2.41.0
+2.43.0
diff --git a/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch b/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch
new file mode 100644
index 0000000..0d4d43d
--- /dev/null
+++ b/SOURCES/v14.8-0004-HID-asus-add-ROG-Ally-xpad-settings.patch
@@ -0,0 +1,2329 @@
+From 9fd3de7abd22d7e67a8757e3f67410302359fec7 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 1 Dec 2023 16:57:19 +1300
+Subject: [PATCH v14.7 4/4] HID: asus: add ROG Ally xpad settings
+
+- move ROG specific stuff to new .c
+- add a header for common parts
+- add xpad mode
+- add deadzones
+- add anti-deadzones
+- add gamepad button remapping
+- add gamepad mapping reset for xpad and wasd modes
+- add turbo mode for individual buttons
+- add joystick response curves
+- add vibration intensity settings
+- add calibration setting
+---
+ .../ABI/testing/sysfs-driver-hid-asus | 85 +
+ drivers/hid/Makefile | 2 +
+ drivers/hid/{hid-asus.c => hid-asus-core.c} | 71 +-
+ drivers/hid/hid-asus-rog.c | 1469 +++++++++++++++++
+ drivers/hid/hid-asus-rog.h | 482 ++++++
+ drivers/hid/hid-asus.h | 58 +
+ 6 files changed, 2126 insertions(+), 41 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-asus
+ rename drivers/hid/{hid-asus.c => hid-asus-core.c} (96%)
+ create mode 100644 drivers/hid/hid-asus-rog.c
+ create mode 100644 drivers/hid/hid-asus-rog.h
+ create mode 100644 drivers/hid/hid-asus.h
+
+diff --git a/Documentation/ABI/testing/sysfs-driver-hid-asus b/Documentation/ABI/testing/sysfs-driver-hid-asus
+new file mode 100644
+index 000000000000..df5b0c5b0702
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-driver-hid-asus
+@@ -0,0 +1,85 @@
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/gamepad_mode
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the mode the ROG Ally xpad operates in:
++ - 1 = Game mode
++ - 2 = WASD mode
++ - 3 = Mouse mode
++ This setting applies instantly and applies settings that were previously changed
++ under that mode which are:
++ - deadzones
++ - anti-deadzones
++ - button mapping
++ - button turbo settings
++ - response curves
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/apply
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Apply the settings that have been stored in attributes so far. Because there are
++ many individual settings across a dozen packets this separation is required to
++ prevent spamming the MCU when userspace applications apply many changes at once.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/reset_btn_mapping
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Reset a gamepad mode to its default button mapping.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y/z>_<left/right>/deadzone
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the inner and outer deadzones of joysticks and triggers. These settings are not
++ written to the MCU until `apply` is set.
++ - range 0-64 (corresponds to 0-100%)
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y/z>_<left/right>/deadzone_index
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Descriptive labels for joystick deadzone array.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/anti-deadzone
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the joystick anti-deadzone feature:
++ - range 0-32 (corresponds to 0-50%)
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y/z>_<left/right>/calibration
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Calibration values for the joysticks and trigger analogues. There are no default
++ values as the calibration is determined in userspace.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y/z>_<left/right>/calibration_index
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Descriptive labels for joystick and triggers calibration array.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/rc_point<n>
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the joystick response curve. There are 4 points available with 1 being the lowest
++ point and 4 being the highest point.
++ - range 0-64 (corresponds to 0-100%)
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/rc_point_index
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Descriptive labels for joystick response curve points.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/btn_<label>/turbo
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the turbo mode of the button:
++ - 0 = no turbo, a separate press and release is registered on press and release
++ - 1-16 = interval between presses if button held down in steps of 1000ms/16
++ These settings are not written to the MCU until `apply` is set.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/vibration_intensity
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Set the vibration intensity for left and right haptics. Applies instantly.
++
++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/vibration_intensity_index
++Date: December 2023
++Contact: linux-input@vger.kernel.org
++Description: Descriptive labels for index points of vibration_intensity.
+\ No newline at end of file
+diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
+index 8a06d0f840bc..7c2436ed05d6 100644
+--- a/drivers/hid/Makefile
++++ b/drivers/hid/Makefile
+@@ -23,6 +23,8 @@ hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o
+ hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
+ hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
+
++hid-asus-y := hid-asus-core.o hid-asus-rog.o
++
+ obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
+ obj-$(CONFIG_HID_ACCUTOUCH) += hid-accutouch.o
+ obj-$(CONFIG_HID_ALPS) += hid-alps.o
+diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus-core.c
+similarity index 96%
+rename from drivers/hid/hid-asus.c
+rename to drivers/hid/hid-asus-core.c
+index 3a1a6024d299..026705c43ee1 100644
+--- a/drivers/hid/hid-asus.c
++++ b/drivers/hid/hid-asus-core.c
+@@ -20,9 +20,8 @@
+ * Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
+ */
+
+-/*
+- */
+-
++#include <asm-generic/errno-base.h>
++#include <asm-generic/errno.h>
+ #include <linux/dmi.h>
+ #include <linux/hid.h>
+ #include <linux/module.h>
+@@ -32,6 +31,7 @@
+ #include <linux/power_supply.h>
+ #include <linux/leds.h>
+
++#include "hid-asus.h"
+ #include "hid-ids.h"
+
+ MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
+@@ -47,10 +47,6 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
+ #define T100CHI_MOUSE_REPORT_ID 0x06
+ #define FEATURE_REPORT_ID 0x0d
+ #define INPUT_REPORT_ID 0x5d
+-#define FEATURE_KBD_REPORT_ID 0x5a
+-#define FEATURE_KBD_REPORT_SIZE 16
+-#define FEATURE_KBD_LED_REPORT_ID1 0x5d
+-#define FEATURE_KBD_LED_REPORT_ID2 0x5e
+
+ #define SUPPORT_KBD_BACKLIGHT BIT(0)
+
+@@ -71,20 +67,6 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
+ #define BATTERY_STAT_CHARGING (1)
+ #define BATTERY_STAT_FULL (2)
+
+-#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
+-#define QUIRK_NO_INIT_REPORTS BIT(1)
+-#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
+-#define QUIRK_IS_MULTITOUCH BIT(3)
+-#define QUIRK_NO_CONSUMER_USAGES BIT(4)
+-#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
+-#define QUIRK_T100_KEYBOARD BIT(6)
+-#define QUIRK_T100CHI BIT(7)
+-#define QUIRK_G752_KEYBOARD BIT(8)
+-#define QUIRK_T90CHI BIT(9)
+-#define QUIRK_MEDION_E1239T BIT(10)
+-#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
+-#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
+-
+ #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
+ QUIRK_NO_INIT_REPORTS | \
+ QUIRK_NO_CONSUMER_USAGES)
+@@ -113,22 +95,6 @@ struct asus_touchpad_info {
+ int report_size;
+ };
+
+-struct asus_drvdata {
+- unsigned long quirks;
+- struct hid_device *hdev;
+- struct input_dev *input;
+- struct input_dev *tp_kbd_input;
+- struct asus_kbd_leds *kbd_backlight;
+- const struct asus_touchpad_info *tp;
+- bool enable_backlight;
+- struct power_supply *battery;
+- struct power_supply_desc battery_desc;
+- int battery_capacity;
+- int battery_stat;
+- bool battery_in_query;
+- unsigned long battery_next_query;
+-};
+-
+ static int asus_report_battery(struct asus_drvdata *, u8 *, int);
+
+ static const struct asus_touchpad_info asus_i2c_tp = {
+@@ -329,6 +295,16 @@ static int asus_raw_event(struct hid_device *hdev,
+ if (drvdata->battery && data[0] == BATTERY_REPORT_ID)
+ return asus_report_battery(drvdata, data, size);
+
++ // TODO: remove after debugging
++ // if (data[0] == 0x5a || data[0] == 0x5d || data[0] == 0x5e){
++ // for (int i = 0; i < size; i++) {
++ // if (i == 0)
++ // printk(KERN_INFO "GOT: %02x,", data[i]);
++ // else
++ // printk(KERN_CONT "%02x,", data[i]);
++ // }
++ // }
++
+ if (drvdata->tp && data[0] == INPUT_REPORT_ID)
+ return asus_report_input(drvdata, data, size);
+
+@@ -365,7 +341,7 @@ static int asus_raw_event(struct hid_device *hdev,
+ return 0;
+ }
+
+-static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
++int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
+ {
+ unsigned char *dmabuf;
+ int ret;
+@@ -386,6 +362,13 @@ static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t bu
+ return ret;
+ }
+
++int asus_kbd_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size)
++{
++ return hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, out_buf,
++ out_buf_size, HID_FEATURE_REPORT,
++ HID_REQ_GET_REPORT);
++}
++
+ static int asus_kbd_init(struct hid_device *hdev, u8 report_id)
+ {
+ const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
+@@ -846,8 +829,8 @@ static int asus_input_mapping(struct hid_device *hdev,
+ case 0xb2: asus_map_key_clear(KEY_PROG2); break; /* Fn+Left previous aura */
+ case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */
+ case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */
+- case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */
+- case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally left back */
++ case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle, Ally M1 */
++ case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally M2 */
+ case 0xa6: asus_map_key_clear(KEY_F16); break; /* ROG Ally QAM button */
+ case 0xa7: asus_map_key_clear(KEY_F17); break; /* ROG Ally ROG long-press */
+ case 0xa8: asus_map_key_clear(KEY_F18); break; /* ROG Ally ROG long-press-release */
+@@ -1063,6 +1046,10 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ }
+ }
+
++ /* all ROG devices have this HID interface but we will focus on Ally for now */
++ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && hid_is_usb(hdev))
++ rog_ally.probe(hdev, &rog_ally);
++
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "Asus hid parse failed: %d\n", ret);
+@@ -1112,6 +1099,8 @@ static void asus_remove(struct hid_device *hdev)
+ cancel_work_sync(&drvdata->kbd_backlight->work);
+ }
+
++ rog_ally.remove(hdev, &rog_ally);
++
+ hid_hw_stop(hdev);
+ }
+
+@@ -1245,7 +1234,7 @@ static const struct hid_device_id asus_devices[] = {
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
+- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
++ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
+ QUIRK_ROG_CLAYMORE_II_KEYBOARD },
+diff --git a/drivers/hid/hid-asus-rog.c b/drivers/hid/hid-asus-rog.c
+new file mode 100644
+index 000000000000..94b7c986576c
+--- /dev/null
++++ b/drivers/hid/hid-asus-rog.c
+@@ -0,0 +1,1469 @@
++// 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>
++#include <linux/usb.h>
++
++#include "hid-asus.h"
++#include "hid-asus-rog.h"
++
++/* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */
++struct asus_rog_ally {
++ 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];
++ /*
++ *
++ */
++ u8 turbo_btns[xpad_mode_mouse][TURBO_BLOCK_LEN];
++ /*
++ */
++ u32 js_calibrations[2][6];
++ u32 tr_calibrations[2][2];
++};
++
++static struct asus_rog_ally *__rog_ally_data(struct device *raw_dev)
++{
++ struct hid_device *hdev = to_hid_device(raw_dev);
++ return ((struct asus_drvdata *)hid_get_drvdata(hdev))->rog_ally_data;
++}
++
++#define STR_TO_CODE_IF(_idx, _code, _label) \
++ if (!strcmp(buf, _label)) \
++ out[_idx] = _code;
++
++#define STR_TO_CODE_ELIF(_idx, _code, _label) else if (!strcmp(buf, _label)) out[_idx] = _code;
++
++/* writes the bytes for a requested key/function in to the out buffer */
++const static int __string_to_key_code(const char *buf, u8 *out, int out_len)
++{
++ 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
++
++ // Allow clearing
++ if (!strcmp(buf, " ") || !strcmp(buf, "\n"))
++ goto success;
++
++ // set group xpad
++ out[0] = 0x01;
++ STR_TO_CODE_IF(1, 0x01, PAD_A)
++ STR_TO_CODE_ELIF(1, 0x02, PAD_B)
++ STR_TO_CODE_ELIF(1, 0x03, PAD_X)
++ STR_TO_CODE_ELIF(1, 0x04, PAD_Y)
++ STR_TO_CODE_ELIF(1, 0x05, PAD_LB)
++ STR_TO_CODE_ELIF(1, 0x06, PAD_RB)
++ STR_TO_CODE_ELIF(1, 0x07, PAD_LS)
++ STR_TO_CODE_ELIF(1, 0x08, PAD_RS)
++ STR_TO_CODE_ELIF(1, 0x09, PAD_DPAD_UP)
++ STR_TO_CODE_ELIF(1, 0x0a, PAD_DPAD_DOWN)
++ STR_TO_CODE_ELIF(1, 0x0b, PAD_DPAD_LEFT)
++ STR_TO_CODE_ELIF(1, 0x0c, PAD_DPAD_RIGHT)
++ STR_TO_CODE_ELIF(1, 0x11, PAD_VIEW)
++ STR_TO_CODE_ELIF(1, 0x12, PAD_MENU)
++ STR_TO_CODE_ELIF(1, 0x13, PAD_XBOX)
++ if (out[1])
++ goto success;
++
++ // set group keyboard
++ out[0] = 0x02;
++ STR_TO_CODE_IF(2, 0x8f, KB_M1)
++ STR_TO_CODE_ELIF(2, 0x8e, KB_M2)
++
++ STR_TO_CODE_ELIF(2, 0x76, KB_ESC)
++ STR_TO_CODE_ELIF(2, 0x50, KB_F1)
++ STR_TO_CODE_ELIF(2, 0x60, KB_F2)
++ STR_TO_CODE_ELIF(2, 0x40, KB_F3)
++ STR_TO_CODE_ELIF(2, 0x0c, KB_F4)
++ STR_TO_CODE_ELIF(2, 0x03, KB_F5)
++ STR_TO_CODE_ELIF(2, 0x0b, KB_F6)
++ STR_TO_CODE_ELIF(2, 0x80, KB_F7)
++ STR_TO_CODE_ELIF(2, 0x0a, KB_F8)
++ STR_TO_CODE_ELIF(2, 0x01, KB_F9)
++ STR_TO_CODE_ELIF(2, 0x09, KB_F10)
++ STR_TO_CODE_ELIF(2, 0x78, KB_F11)
++ STR_TO_CODE_ELIF(2, 0x07, KB_F12)
++ STR_TO_CODE_ELIF(2, 0x10, KB_F14)
++ STR_TO_CODE_ELIF(2, 0x18, KB_F15)
++
++ STR_TO_CODE_ELIF(2, 0x0e, KB_BACKTICK)
++ STR_TO_CODE_ELIF(2, 0x16, KB_1)
++ STR_TO_CODE_ELIF(2, 0x1e, KB_2)
++ STR_TO_CODE_ELIF(2, 0x26, KB_3)
++ STR_TO_CODE_ELIF(2, 0x25, KB_4)
++ STR_TO_CODE_ELIF(2, 0x2e, KB_5)
++ STR_TO_CODE_ELIF(2, 0x36, KB_6)
++ STR_TO_CODE_ELIF(2, 0x3d, KB_7)
++ STR_TO_CODE_ELIF(2, 0x3e, KB_8)
++ STR_TO_CODE_ELIF(2, 0x46, KB_9)
++ STR_TO_CODE_ELIF(2, 0x45, KB_0)
++ STR_TO_CODE_ELIF(2, 0x4e, KB_HYPHEN)
++ STR_TO_CODE_ELIF(2, 0x55, KB_EQUALS)
++ STR_TO_CODE_ELIF(2, 0x66, KB_BACKSPACE)
++
++ STR_TO_CODE_ELIF(2, 0x0d, KB_TAB)
++ STR_TO_CODE_ELIF(2, 0x15, KB_Q)
++ STR_TO_CODE_ELIF(2, 0x1d, KB_W)
++ STR_TO_CODE_ELIF(2, 0x24, KB_E)
++ STR_TO_CODE_ELIF(2, 0x2d, KB_R)
++ STR_TO_CODE_ELIF(2, 0x2d, KB_T)
++ STR_TO_CODE_ELIF(2, 0x35, KB_Y)
++ STR_TO_CODE_ELIF(2, 0x3c, KB_U)
++ STR_TO_CODE_ELIF(2, 0x43, KB_I)
++ STR_TO_CODE_ELIF(2, 0x44, KB_O)
++ STR_TO_CODE_ELIF(2, 0x4d, KB_P)
++ STR_TO_CODE_ELIF(2, 0x54, KB_LBRACKET)
++ STR_TO_CODE_ELIF(2, 0x5b, KB_RBRACKET)
++ STR_TO_CODE_ELIF(2, 0x5d, KB_BACKSLASH)
++
++ STR_TO_CODE_ELIF(2, 0x58, KB_CAPS)
++ STR_TO_CODE_ELIF(2, 0x1c, KB_A)
++ STR_TO_CODE_ELIF(2, 0x1b, KB_S)
++ STR_TO_CODE_ELIF(2, 0x23, KB_D)
++ STR_TO_CODE_ELIF(2, 0x2b, KB_F)
++ STR_TO_CODE_ELIF(2, 0x34, KB_G)
++ STR_TO_CODE_ELIF(2, 0x33, KB_H)
++ STR_TO_CODE_ELIF(2, 0x3b, KB_J)
++ STR_TO_CODE_ELIF(2, 0x42, KB_K)
++ STR_TO_CODE_ELIF(2, 0x4b, KB_L)
++ STR_TO_CODE_ELIF(2, 0x4c, KB_SEMI)
++ STR_TO_CODE_ELIF(2, 0x52, KB_QUOTE)
++ STR_TO_CODE_ELIF(2, 0x5a, KB_RET)
++
++ STR_TO_CODE_ELIF(2, 0x88, KB_LSHIFT)
++ STR_TO_CODE_ELIF(2, 0x1a, KB_Z)
++ STR_TO_CODE_ELIF(2, 0x22, KB_X)
++ STR_TO_CODE_ELIF(2, 0x21, KB_C)
++ STR_TO_CODE_ELIF(2, 0x2a, KB_V)
++ STR_TO_CODE_ELIF(2, 0x32, KB_B)
++ STR_TO_CODE_ELIF(2, 0x31, KB_N)
++ STR_TO_CODE_ELIF(2, 0x3a, KB_M)
++ STR_TO_CODE_ELIF(2, 0x41, KB_COMMA)
++ STR_TO_CODE_ELIF(2, 0x49, KB_PERIOD)
++ STR_TO_CODE_ELIF(2, 0x4a, KB_FWDSLASH)
++ STR_TO_CODE_ELIF(2, 0x89, KB_RSHIFT)
++
++ STR_TO_CODE_ELIF(2, 0x8c, KB_LCTL)
++ STR_TO_CODE_ELIF(2, 0x82, KB_META)
++ STR_TO_CODE_ELIF(2, 0xba, KB_LALT)
++ STR_TO_CODE_ELIF(2, 0x29, KB_SPACE)
++ STR_TO_CODE_ELIF(2, 0x8b, KB_RALT)
++ STR_TO_CODE_ELIF(2, 0x84, KB_MENU)
++ STR_TO_CODE_ELIF(2, 0x8d, KB_RCTL)
++
++ STR_TO_CODE_ELIF(2, 0xc3, KB_PRNTSCN)
++ STR_TO_CODE_ELIF(2, 0x7e, KB_SCRLCK)
++ STR_TO_CODE_ELIF(2, 0x91, KB_PAUSE)
++ STR_TO_CODE_ELIF(2, 0xc2, KB_INS)
++ STR_TO_CODE_ELIF(2, 0x94, KB_HOME)
++ STR_TO_CODE_ELIF(2, 0x96, KB_PGUP)
++ STR_TO_CODE_ELIF(2, 0xc0, KB_DEL)
++ STR_TO_CODE_ELIF(2, 0x95, KB_END)
++ STR_TO_CODE_ELIF(2, 0x97, KB_PGDWN)
++
++ STR_TO_CODE_ELIF(2, 0x99, KB_UP_ARROW)
++ STR_TO_CODE_ELIF(2, 0x98, KB_DOWN_ARROW)
++ STR_TO_CODE_ELIF(2, 0x91, KB_LEFT_ARROW)
++ STR_TO_CODE_ELIF(2, 0x9b, KB_RIGHT_ARROW)
++
++ STR_TO_CODE_ELIF(2, 0x77, NUMPAD_LOCK)
++ STR_TO_CODE_ELIF(2, 0x90, NUMPAD_FWDSLASH)
++ STR_TO_CODE_ELIF(2, 0x7c, NUMPAD_ASTERISK)
++ STR_TO_CODE_ELIF(2, 0x7b, NUMPAD_HYPHEN)
++ STR_TO_CODE_ELIF(2, 0x70, NUMPAD_0)
++ STR_TO_CODE_ELIF(2, 0x69, NUMPAD_1)
++ STR_TO_CODE_ELIF(2, 0x72, NUMPAD_2)
++ STR_TO_CODE_ELIF(2, 0x7a, NUMPAD_3)
++ STR_TO_CODE_ELIF(2, 0x6b, NUMPAD_4)
++ STR_TO_CODE_ELIF(2, 0x73, NUMPAD_5)
++ STR_TO_CODE_ELIF(2, 0x74, NUMPAD_6)
++ STR_TO_CODE_ELIF(2, 0x6c, NUMPAD_7)
++ STR_TO_CODE_ELIF(2, 0x75, NUMPAD_8)
++ STR_TO_CODE_ELIF(2, 0x7d, NUMPAD_9)
++ STR_TO_CODE_ELIF(2, 0x79, NUMPAD_PLUS)
++ STR_TO_CODE_ELIF(2, 0x81, NUMPAD_ENTER)
++ STR_TO_CODE_ELIF(2, 0x71, NUMPAD_PERIOD)
++ if (out[2])
++ goto success;
++
++ out[0] = 0x03;
++ STR_TO_CODE_IF(4, 0x01, RAT_LCLICK)
++ STR_TO_CODE_ELIF(4, 0x02, RAT_RCLICK)
++ STR_TO_CODE_ELIF(4, 0x03, RAT_MCLICK)
++ STR_TO_CODE_ELIF(4, 0x04, RAT_WHEEL_UP)
++ STR_TO_CODE_ELIF(4, 0x05, RAT_WHEEL_DOWN)
++ if (out[4] != 0)
++ goto success;
++
++ out[0] = 0x05;
++ STR_TO_CODE_IF(3, 0x16, MEDIA_SCREENSHOT)
++ STR_TO_CODE_ELIF(3, 0x19, MEDIA_SHOW_KEYBOARD)
++ STR_TO_CODE_ELIF(3, 0x1c, MEDIA_SHOW_DESKTOP)
++ STR_TO_CODE_ELIF(3, 0x1e, MEDIA_START_RECORDING)
++ STR_TO_CODE_ELIF(3, 0x01, MEDIA_MIC_OFF)
++ STR_TO_CODE_ELIF(3, 0x02, MEDIA_VOL_DOWN)
++ STR_TO_CODE_ELIF(3, 0x03, MEDIA_VOL_UP)
++ if (out[3])
++ goto success;
++
++ // restore bytes if invalid input
++ memcpy(out, save_buf, out_len);
++ kfree(save_buf);
++ return -EINVAL;
++
++success:
++ kfree(save_buf);
++ return 0;
++}
++
++#define CODE_TO_STR_IF(_idx, _code, _label) \
++ if (btn_block[_idx] == _code) \
++ return _label;
++
++const static char *__btn_map_to_string(struct device *raw_dev, enum btn_pair pair,
++ enum btn_pair_side side, bool secondary)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ u8 *btn_block;
++ int offs;
++
++ // TODO: this little block is common
++ offs = side ? MAPPING_BLOCK_LEN / 2 : 0;
++ offs = secondary ? offs + BTN_CODE_LEN : offs;
++ btn_block = rog_ally->key_mapping[rog_ally->mode - 1][pair - 1] + offs;
++
++ if (btn_block[0] == 0x01) {
++ CODE_TO_STR_IF(1, 0x01, PAD_A)
++ CODE_TO_STR_IF(1, 0x02, PAD_B)
++ CODE_TO_STR_IF(1, 0x03, PAD_X)
++ CODE_TO_STR_IF(1, 0x04, PAD_Y)
++ CODE_TO_STR_IF(1, 0x05, PAD_LB)
++ CODE_TO_STR_IF(1, 0x06, PAD_RB)
++ CODE_TO_STR_IF(1, 0x07, PAD_LS)
++ CODE_TO_STR_IF(1, 0x08, PAD_RS)
++ CODE_TO_STR_IF(1, 0x09, PAD_DPAD_UP)
++ CODE_TO_STR_IF(1, 0x0a, PAD_DPAD_DOWN)
++ CODE_TO_STR_IF(1, 0x0b, PAD_DPAD_LEFT)
++ CODE_TO_STR_IF(1, 0x0c, PAD_DPAD_RIGHT)
++ CODE_TO_STR_IF(1, 0x11, PAD_VIEW)
++ CODE_TO_STR_IF(1, 0x12, PAD_MENU)
++ CODE_TO_STR_IF(1, 0x13, PAD_XBOX)
++ }
++
++ if (btn_block[0] == 0x02) {
++ CODE_TO_STR_IF(2, 0x8f, KB_M1)
++ CODE_TO_STR_IF(2, 0x8e, KB_M2)
++ CODE_TO_STR_IF(2, 0x76, KB_ESC)
++ CODE_TO_STR_IF(2, 0x50, KB_F1)
++ CODE_TO_STR_IF(2, 0x60, KB_F2)
++ CODE_TO_STR_IF(2, 0x40, KB_F3)
++ CODE_TO_STR_IF(2, 0x0c, KB_F4)
++ CODE_TO_STR_IF(2, 0x03, KB_F5)
++ CODE_TO_STR_IF(2, 0x0b, KB_F6)
++ CODE_TO_STR_IF(2, 0x80, KB_F7)
++ CODE_TO_STR_IF(2, 0x0a, KB_F8)
++ CODE_TO_STR_IF(2, 0x01, KB_F9)
++ CODE_TO_STR_IF(2, 0x09, KB_F10)
++ CODE_TO_STR_IF(2, 0x78, KB_F11)
++ CODE_TO_STR_IF(2, 0x07, KB_F12)
++ CODE_TO_STR_IF(2, 0x10, KB_F14)
++ CODE_TO_STR_IF(2, 0x18, KB_F15)
++
++ CODE_TO_STR_IF(2, 0x0e, KB_BACKTICK)
++ CODE_TO_STR_IF(2, 0x16, KB_1)
++ CODE_TO_STR_IF(2, 0x1e, KB_2)
++ CODE_TO_STR_IF(2, 0x26, KB_3)
++ CODE_TO_STR_IF(2, 0x25, KB_4)
++ CODE_TO_STR_IF(2, 0x2e, KB_5)
++ CODE_TO_STR_IF(2, 0x36, KB_6)
++ CODE_TO_STR_IF(2, 0x3d, KB_7)
++ CODE_TO_STR_IF(2, 0x3e, KB_8)
++ CODE_TO_STR_IF(2, 0x46, KB_9)
++ CODE_TO_STR_IF(2, 0x45, KB_0)
++ CODE_TO_STR_IF(2, 0x4e, KB_HYPHEN)
++ CODE_TO_STR_IF(2, 0x55, KB_EQUALS)
++ CODE_TO_STR_IF(2, 0x66, KB_BACKSPACE)
++
++ CODE_TO_STR_IF(2, 0x0d, KB_TAB)
++ CODE_TO_STR_IF(2, 0x15, KB_Q)
++ CODE_TO_STR_IF(2, 0x1d, KB_W)
++ CODE_TO_STR_IF(2, 0x24, KB_E)
++ CODE_TO_STR_IF(2, 0x2d, KB_R)
++ CODE_TO_STR_IF(2, 0x2d, KB_T)
++ CODE_TO_STR_IF(2, 0x35, KB_Y)
++ CODE_TO_STR_IF(2, 0x3c, KB_U)
++ CODE_TO_STR_IF(2, 0x43, KB_I)
++ CODE_TO_STR_IF(2, 0x44, KB_O)
++ CODE_TO_STR_IF(2, 0x4d, KB_P)
++ CODE_TO_STR_IF(2, 0x54, KB_LBRACKET)
++ CODE_TO_STR_IF(2, 0x5b, KB_RBRACKET)
++ CODE_TO_STR_IF(2, 0x5d, KB_BACKSLASH)
++
++ CODE_TO_STR_IF(2, 0x58, KB_CAPS)
++ CODE_TO_STR_IF(2, 0x1c, KB_A)
++ CODE_TO_STR_IF(2, 0x1b, KB_S)
++ CODE_TO_STR_IF(2, 0x23, KB_D)
++ CODE_TO_STR_IF(2, 0x2b, KB_F)
++ CODE_TO_STR_IF(2, 0x34, KB_G)
++ CODE_TO_STR_IF(2, 0x33, KB_H)
++ CODE_TO_STR_IF(2, 0x3b, KB_J)
++ CODE_TO_STR_IF(2, 0x42, KB_K)
++ CODE_TO_STR_IF(2, 0x4b, KB_L)
++ CODE_TO_STR_IF(2, 0x4c, KB_SEMI)
++ CODE_TO_STR_IF(2, 0x52, KB_QUOTE)
++ CODE_TO_STR_IF(2, 0x5a, KB_RET)
++
++ CODE_TO_STR_IF(2, 0x88, KB_LSHIFT)
++ CODE_TO_STR_IF(2, 0x1a, KB_Z)
++ CODE_TO_STR_IF(2, 0x22, KB_X)
++ CODE_TO_STR_IF(2, 0x21, KB_C)
++ CODE_TO_STR_IF(2, 0x2a, KB_V)
++ CODE_TO_STR_IF(2, 0x32, KB_B)
++ CODE_TO_STR_IF(2, 0x31, KB_N)
++ CODE_TO_STR_IF(2, 0x3a, KB_M)
++ CODE_TO_STR_IF(2, 0x41, KB_COMMA)
++ CODE_TO_STR_IF(2, 0x49, KB_PERIOD)
++ CODE_TO_STR_IF(2, 0x4a, KB_FWDSLASH)
++ CODE_TO_STR_IF(2, 0x89, KB_RSHIFT)
++
++ CODE_TO_STR_IF(2, 0x8c, KB_LCTL)
++ CODE_TO_STR_IF(2, 0x82, KB_META)
++ CODE_TO_STR_IF(2, 0xba, KB_LALT)
++ CODE_TO_STR_IF(2, 0x29, KB_SPACE)
++ CODE_TO_STR_IF(2, 0x8b, KB_RALT)
++ CODE_TO_STR_IF(2, 0x84, KB_MENU)
++ CODE_TO_STR_IF(2, 0x8d, KB_RCTL)
++
++ CODE_TO_STR_IF(2, 0xc3, KB_PRNTSCN)
++ CODE_TO_STR_IF(2, 0x7e, KB_SCRLCK)
++ CODE_TO_STR_IF(2, 0x91, KB_PAUSE)
++ CODE_TO_STR_IF(2, 0xc2, KB_INS)
++ CODE_TO_STR_IF(2, 0x94, KB_HOME)
++ CODE_TO_STR_IF(2, 0x96, KB_PGUP)
++ CODE_TO_STR_IF(2, 0xc0, KB_DEL)
++ CODE_TO_STR_IF(2, 0x95, KB_END)
++ CODE_TO_STR_IF(2, 0x97, KB_PGDWN)
++
++ CODE_TO_STR_IF(2, 0x99, KB_UP_ARROW)
++ CODE_TO_STR_IF(2, 0x98, KB_DOWN_ARROW)
++ CODE_TO_STR_IF(2, 0x91, KB_LEFT_ARROW)
++ CODE_TO_STR_IF(2, 0x9b, KB_RIGHT_ARROW)
++
++ CODE_TO_STR_IF(2, 0x77, NUMPAD_LOCK)
++ CODE_TO_STR_IF(2, 0x90, NUMPAD_FWDSLASH)
++ CODE_TO_STR_IF(2, 0x7c, NUMPAD_ASTERISK)
++ CODE_TO_STR_IF(2, 0x7b, NUMPAD_HYPHEN)
++ CODE_TO_STR_IF(2, 0x70, NUMPAD_0)
++ CODE_TO_STR_IF(2, 0x69, NUMPAD_1)
++ CODE_TO_STR_IF(2, 0x72, NUMPAD_2)
++ CODE_TO_STR_IF(2, 0x7a, NUMPAD_3)
++ CODE_TO_STR_IF(2, 0x6b, NUMPAD_4)
++ CODE_TO_STR_IF(2, 0x73, NUMPAD_5)
++ CODE_TO_STR_IF(2, 0x74, NUMPAD_6)
++ CODE_TO_STR_IF(2, 0x6c, NUMPAD_7)
++ CODE_TO_STR_IF(2, 0x75, NUMPAD_8)
++ CODE_TO_STR_IF(2, 0x7d, NUMPAD_9)
++ CODE_TO_STR_IF(2, 0x79, NUMPAD_PLUS)
++ CODE_TO_STR_IF(2, 0x81, NUMPAD_ENTER)
++ CODE_TO_STR_IF(2, 0x71, NUMPAD_PERIOD)
++ }
++
++ if (btn_block[0] == 0x03) {
++ CODE_TO_STR_IF(4, 0x01, RAT_LCLICK)
++ CODE_TO_STR_IF(4, 0x02, RAT_RCLICK)
++ CODE_TO_STR_IF(4, 0x03, RAT_MCLICK)
++ CODE_TO_STR_IF(4, 0x04, RAT_WHEEL_UP)
++ CODE_TO_STR_IF(4, 0x05, RAT_WHEEL_DOWN)
++ }
++
++ if (btn_block[0] == 0x05) {
++ CODE_TO_STR_IF(3, 0x16, MEDIA_SCREENSHOT)
++ CODE_TO_STR_IF(3, 0x19, MEDIA_SHOW_KEYBOARD)
++ CODE_TO_STR_IF(3, 0x1c, MEDIA_SHOW_DESKTOP)
++ CODE_TO_STR_IF(3, 0x1e, MEDIA_START_RECORDING)
++ CODE_TO_STR_IF(3, 0x01, MEDIA_MIC_OFF)
++ CODE_TO_STR_IF(3, 0x02, MEDIA_VOL_DOWN)
++ CODE_TO_STR_IF(3, 0x03, MEDIA_VOL_UP)
++ }
++
++ 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)
++{
++ u8 *hidbuf;
++ int ret, count;
++
++ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
++ if (!hidbuf)
++ return -ENOMEM;
++
++ for (count = 0; count < 3; count++) {
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_check_ready;
++ hidbuf[3] = 01;
++ ret = asus_kbd_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_kbd_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)
++ hid_warn(hdev, "ROG Ally not ready, retry %d\n", count);
++ else
++ break;
++ msleep(2); // don't spam the entire loop in less than USB response time
++ }
++
++ if (count == 3)
++ hid_err(hdev, "ROG Ally never responded with a ready\n");
++
++ kfree(hidbuf);
++ return ret;
++}
++
++/********** BUTTON REMAPPING *********************************************************************/
++static void __btn_pair_to_pkt(struct device *raw_dev, enum btn_pair pair, u8 *out, int out_len)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++
++ out[0] = FEATURE_KBD_REPORT_ID;
++ out[1] = 0xD1;
++ out[2] = xpad_cmd_set_mapping;
++ out[3] = pair;
++ out[4] = 0x2c; //length
++ memcpy(&out[5], &rog_ally->key_mapping[rog_ally->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 device *raw_dev, const char *buf, enum btn_pair pair,
++ int side, bool secondary)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ u8 *key_code;
++ int offs;
++
++ offs = side ? MAPPING_BLOCK_LEN / 2 : 0;
++ offs = secondary ? offs + BTN_CODE_LEN : offs;
++ key_code = rog_ally->key_mapping[rog_ally->mode - 1][pair - 1] + offs;
++
++ return __string_to_key_code(buf, key_code, BTN_CODE_LEN);
++}
++
++/* Apply the mapping pair to the device */
++static int __gamepad_set_mapping(struct device *raw_dev, enum btn_pair pair)
++{
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ __btn_pair_to_pkt(raw_dev, pair, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++ kfree(hidbuf);
++
++ return ret;
++}
++
++static ssize_t btn_mapping_apply_store(struct device *raw_dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret = __gamepad_write_all_to_mcu(raw_dev);
++ if (ret < 0)
++ return ret;
++ return count;
++}
++ALLY_DEVICE_ATTR_WO(btn_mapping_apply, apply);
++
++/********** BUTTON TURBO *************************************************************************/
++static int __gamepad_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 *raw_dev, enum btn_pair pair, int side)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ return rog_ally->turbo_btns[rog_ally->mode - 1][__gamepad_turbo_index(pair, side)];
++};
++
++static int __gamepad_turbo_store(struct device *raw_dev, const char *buf, enum btn_pair pair,
++ int side)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ int ret, val;
++
++ ret = kstrtoint(buf, 0, &val);
++ if (ret)
++ return ret;
++ if (val < 0 || val > 16)
++ return -EINVAL;
++
++ rog_ally->turbo_btns[rog_ally->mode - 1][__gamepad_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 asus_rog_ally *rog_ally)
++{
++ memcpy(&rog_ally->key_mapping[0][0], &XPAD_DEF1, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][1], &XPAD_DEF2, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][2], &XPAD_DEF3, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][3], &XPAD_DEF4, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][4], &XPAD_DEF5, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][5], &XPAD_DEF6, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][6], &XPAD_DEF7, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][7], &XPAD_DEF8, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[0][8], &XPAD_DEF9, MAPPING_BLOCK_LEN);
++}
++
++static void __gamepad_mapping_wasd_default(struct asus_rog_ally *rog_ally)
++{
++ memcpy(&rog_ally->key_mapping[1][0], &WASD_DEF1, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][1], &WASD_DEF2, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][2], &WASD_DEF3, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][3], &WASD_DEF4, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][4], &WASD_DEF5, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][5], &WASD_DEF6, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][6], &WASD_DEF7, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][7], &WASD_DEF8, MAPPING_BLOCK_LEN);
++ memcpy(&rog_ally->key_mapping[1][8], &WASD_DEF9, MAPPING_BLOCK_LEN);
++}
++
++static ssize_t btn_mapping_reset_store(struct device *raw_dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ switch (rog_ally->mode) {
++ case xpad_mode_game:
++ __gamepad_mapping_xpad_default(rog_ally);
++ break;
++ case xpad_mode_wasd:
++ __gamepad_mapping_wasd_default(rog_ally);
++ break;
++ default:
++ __gamepad_mapping_xpad_default(rog_ally);
++ break;
++ }
++
++ return count;
++}
++
++ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping);
++
++/********** GAMEPAD MODE *************************************************************************/
++static ssize_t __gamepad_set_mode(struct device *raw_dev, int val)
++{
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_mode;
++ hidbuf[3] = 0x01;
++ hidbuf[4] = val;
++
++ ret = __gamepad_check_ready(hdev);
++ if (ret < 0)
++ goto report_fail;
++
++ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++ if (ret < 0)
++ goto report_fail;
++
++ ret = __gamepad_write_all_to_mcu(raw_dev);
++ if (ret < 0)
++ goto report_fail;
++
++report_fail:
++ kfree(hidbuf);
++ return ret;
++}
++
++static ssize_t gamepad_mode_show(struct device *raw_dev, struct device_attribute *attr, char *buf)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ return sysfs_emit(buf, "%d\n", rog_ally->mode);
++}
++
++static ssize_t gamepad_mode_store(struct device *raw_dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ int ret, val;
++
++ ret = kstrtoint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ if (val < xpad_mode_game || val > xpad_mode_mouse)
++ return -EINVAL;
++
++ rog_ally->mode = val;
++
++ ret = __gamepad_set_mode(raw_dev, 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 *raw_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 device *raw_dev)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_vibe_intensity;
++ hidbuf[3] = 0x02; // length
++ hidbuf[4] = rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left];
++ hidbuf[5] = rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right];
++
++ ret = __gamepad_check_ready(hdev);
++ if (ret < 0)
++ goto report_fail;
++
++ ret = asus_kbd_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 *raw_dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ return sysfs_emit(buf, "%d %d\n",
++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left],
++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right]);
++}
++
++static ssize_t gamepad_vibration_intensity_store(struct device *raw_dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ u32 left, right;
++ int ret;
++
++ if (sscanf(buf, "%d %d", &left, &right) != 2)
++ return -EINVAL;
++
++ if (left > 64 || right > 64)
++ return -EINVAL;
++
++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left] = left;
++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right] = right;
++
++ ret = __gamepad_write_vibe_intensity_to_mcu(raw_dev);
++ 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 device *raw_dev)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_js_dz;
++ hidbuf[3] = 0x04; // length
++ hidbuf[4] = rog_ally->deadzones[rog_ally->mode - 1][0][0];
++ hidbuf[5] = rog_ally->deadzones[rog_ally->mode - 1][0][1];
++ hidbuf[6] = rog_ally->deadzones[rog_ally->mode - 1][0][2];
++ hidbuf[7] = rog_ally->deadzones[rog_ally->mode - 1][0][3];
++
++ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++ if (ret < 0)
++ goto end;
++
++ hidbuf[2] = xpad_cmd_set_tr_dz;
++ hidbuf[4] = rog_ally->deadzones[rog_ally->mode - 1][1][0];
++ hidbuf[5] = rog_ally->deadzones[rog_ally->mode - 1][1][1];
++ hidbuf[6] = rog_ally->deadzones[rog_ally->mode - 1][1][2];
++ hidbuf[7] = rog_ally->deadzones[rog_ally->mode - 1][1][3];
++
++ ret = asus_kbd_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 device *raw_dev, enum xpad_axis axis,
++ const char *buf)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ 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;
++
++ rog_ally->deadzones[rog_ally->mode - 1][is_tr][side] = inner;
++ rog_ally->deadzones[rog_ally->mode - 1][is_tr][side + 1] = outer;
++
++ return 0;
++}
++
++static ssize_t axis_xyz_deadzone_index_show(struct device *raw_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 device *raw_dev)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_adz;
++ hidbuf[3] = 0x02; // length
++ hidbuf[4] = rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_left];
++ hidbuf[5] = rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_right];
++
++ ret = __gamepad_check_ready(hdev);
++ if (ret < 0)
++ goto report_fail;
++
++ ret = asus_kbd_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 *raw_dev, const char *buf,
++ enum btn_pair_side side)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ int ret, val;
++
++ ret = kstrtoint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ if (val < 0 || val > 32)
++ return -EINVAL;
++
++ rog_ally->anti_deadzones[rog_ally->mode - 1][side] = val;
++
++ return ret;
++}
++
++static ssize_t xpad_axis_xy_left_ADZ_show(struct device *raw_dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ return sysfs_emit(buf, "%d\n",
++ rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_left]);
++}
++
++static ssize_t xpad_axis_xy_left_ADZ_store(struct device *raw_dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret = __gamepad_js_ADZ_store(raw_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 *raw_dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ return sysfs_emit(buf, "%d\n",
++ rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_right]);
++}
++
++static ssize_t xpad_axis_xy_right_ADZ_store(struct device *raw_dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret = __gamepad_js_ADZ_store(raw_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 *raw_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 device *raw_dev)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_response_curve;
++ hidbuf[3] = 0x09; // length
++ hidbuf[4] = 0x01;
++ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode - 1][btn_pair_side_left], 8);
++
++ ret = __gamepad_check_ready(hdev);
++ if (ret < 0)
++ goto report_fail;
++
++ hidbuf[4] = 0x02;
++ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode - 1][btn_pair_side_right], 8);
++
++ ret = __gamepad_check_ready(hdev);
++ if (ret < 0)
++ goto report_fail;
++
++ ret = asus_kbd_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 *raw_dev, const char *buf,
++ enum btn_pair_side side, int point)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ int idx = (point - 1) * 2;
++ u32 move, response;
++
++ if (sscanf(buf, "%d %d", &move, &response) != 2)
++ return -EINVAL;
++
++ if (move > 64 || response > 64)
++ return -EINVAL;
++
++ rog_ally->response_curve[rog_ally->mode - 1][side][idx] = move;
++ rog_ally->response_curve[rog_ally->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 ssize_t __gamepad_write_cal_to_mcu(struct device *raw_dev, enum xpad_axis axis)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_dev);
++ u8 *hidbuf;
++ u8 *c, side, pkt_len, data_len;
++ int ret, cal, checksum = 0;
++
++ 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;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_calibration;
++ hidbuf[3] = pkt_len;
++ hidbuf[4] = 0x01; // second command (set)
++ hidbuf[5] = axis;
++ c = &hidbuf[6]; // pointer
++
++ for (size_t i = 0; i < data_len; i++) {
++ cal = rog_ally->js_calibrations[side][i];
++ *c = (u8)((cal & 0xff00) >> 8);
++ checksum += *c;
++ c += 1;
++ *c = (u8)(cal & 0xff);
++ checksum += *c;
++ c += 1;
++ }
++
++ hidbuf[6 + data_len * 2] = checksum;
++
++ // TODO: debug if
++ printk("CAL: ");
++ for (size_t i = 0; i < 19; i++) {
++ printk(KERN_CONT "%02x,", hidbuf[i]);
++ }
++
++ ret = asus_kbd_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_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_calibration;
++ hidbuf[3] = 0x01; // pkt len
++ hidbuf[4] = 0x03; // second command (set)
++
++ ret = asus_kbd_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 *raw_dev, const char *buf, enum xpad_axis axis)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ u32 x_stable, x_min, x_max, y_stable, y_min, y_max, side;
++
++ 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;
++ //TODO: validate input
++
++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
++ /* stored in reverse order for easy copy to packet */
++ rog_ally->js_calibrations[side][0] = y_stable;
++ rog_ally->js_calibrations[side][1] = y_min;
++ rog_ally->js_calibrations[side][2] = y_max;
++ rog_ally->js_calibrations[side][3] = x_stable;
++ rog_ally->js_calibrations[side][4] = x_min;
++ rog_ally->js_calibrations[side][5] = x_max;
++
++ return __gamepad_write_cal_to_mcu(raw_dev, axis);
++ } else {
++ if (sscanf(buf, "%d %d", &x_stable, &x_max) != 2)
++ return -EINVAL;
++ //TODO: validate input
++
++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
++ /* stored in reverse order for easy copy to packet */
++ rog_ally->tr_calibrations[side][0] = x_stable;
++ rog_ally->tr_calibrations[side][1] = x_max;
++
++ return __gamepad_write_cal_to_mcu(raw_dev, axis);
++ }
++}
++
++static ssize_t __gamepad_cal_show(struct device *raw_dev, char *buf, enum xpad_axis axis)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ int side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
++
++ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) {
++ return sysfs_emit(buf, "%d %d %d %d %d %d\n", rog_ally->js_calibrations[side][3],
++ rog_ally->js_calibrations[side][4],
++ rog_ally->js_calibrations[side][5],
++ rog_ally->js_calibrations[side][0],
++ rog_ally->js_calibrations[side][1],
++ rog_ally->js_calibrations[side][2]);
++ } else {
++ return sysfs_emit(buf, "%d %d\n", rog_ally->tr_calibrations[side][0],
++ rog_ally->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 *raw_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 *raw_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 *raw_dev, const char *buf, enum xpad_axis axis)
++{
++ struct hid_device *hdev = to_hid_device(raw_dev);
++ u8 *hidbuf;
++ u8 side;
++ 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;
++
++ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
++
++ hidbuf[0] = FEATURE_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_calibration;
++ hidbuf[3] = 0x02; // pkt len
++ hidbuf[4] = 0x02; // second command (reset)
++ hidbuf[5] = axis;
++
++ ret = asus_kbd_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_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_calibration;
++ hidbuf[3] = 0x01; // pkt len
++ hidbuf[4] = 0x03; // second command (set)
++
++ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++ if (ret < 0)
++ goto report_fail;
++
++report_fail:
++ 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 device *raw_dev)
++{
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev);
++ struct hid_device *hdev = to_hid_device(raw_dev);
++ u8 *hidbuf;
++ int ret = 0;
++
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_dpad_u_d);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_dpad_l_r);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_ls_rs);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_lb_rb);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_a_b);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_x_y);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_view_menu);
++ if (ret < 0)
++ return ret;
++ ret = __gamepad_set_mapping(&hdev->dev, btn_pair_m1_m2);
++ if (ret < 0)
++ return ret;
++ __gamepad_set_mapping(&hdev->dev, btn_pair_lt_rt);
++ if (ret < 0)
++ return ret;
++ __gamepad_set_deadzones(raw_dev);
++ if (ret < 0)
++ return ret;
++ __gamepad_write_js_ADZ_to_mcu(raw_dev);
++ if (ret < 0)
++ return ret;
++ __gamepad_write_vibe_intensity_to_mcu(raw_dev);
++ if (ret < 0)
++ return ret;
++ __gamepad_write_response_curves_to_mcu(raw_dev);
++ 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_KBD_REPORT_ID;
++ hidbuf[1] = 0xD1;
++ hidbuf[2] = xpad_cmd_set_turbo;
++ hidbuf[3] = 0x20; // length
++ memcpy(&hidbuf[4], rog_ally->turbo_btns[rog_ally->mode - 1], TURBO_BLOCK_LEN);
++ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
++
++ kfree(hidbuf);
++ return ret;
++}
++
++static int asus_rog_ally_probe(struct hid_device *hdev, const struct rog_ops *ops)
++{
++ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
++ int ret = 0;
++
++ /* all ROG devices have this HID interface but we will focus on Ally for now */
++ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && hid_is_usb(hdev)) {
++ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
++
++ if (intf->altsetting->desc.bInterfaceNumber == 0) {
++ hid_info(hdev, "Setting up ROG USB interface\n");
++ /* initialise and set up USB, common to ROG */
++ // TODO:
++
++ /* initialise the Ally data */
++ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) {
++ hid_info(hdev, "Setting up ROG Ally interface\n");
++
++ drvdata->rog_ally_data = devm_kzalloc(
++ &hdev->dev, sizeof(*drvdata->rog_ally_data), GFP_KERNEL);
++ if (!drvdata->rog_ally_data) {
++ hid_err(hdev, "Can't alloc Asus ROG USB interface\n");
++ ret = -ENOMEM;
++ goto err_stop_hw;
++ }
++ // TODO: move these to functions
++ drvdata->rog_ally_data->mode = xpad_mode_game;
++ for (int i = 0; i < xpad_mode_mouse; i++) {
++ drvdata->rog_ally_data->deadzones[i][0][1] = 64;
++ drvdata->rog_ally_data->deadzones[i][0][3] = 64;
++ drvdata->rog_ally_data->deadzones[i][1][1] = 64;
++ drvdata->rog_ally_data->deadzones[i][1][3] = 64;
++
++ drvdata->rog_ally_data->response_curve[i][0][0] = 0x14;
++ drvdata->rog_ally_data->response_curve[i][0][1] = 0x14;
++ drvdata->rog_ally_data->response_curve[i][0][2] = 0x28;
++ drvdata->rog_ally_data->response_curve[i][0][3] = 0x28;
++ drvdata->rog_ally_data->response_curve[i][0][4] = 0x3c;
++ drvdata->rog_ally_data->response_curve[i][0][5] = 0x3c;
++ drvdata->rog_ally_data->response_curve[i][0][6] = 0x50;
++ drvdata->rog_ally_data->response_curve[i][0][7] = 0x50;
++
++ drvdata->rog_ally_data->response_curve[i][1][0] = 0x14;
++ drvdata->rog_ally_data->response_curve[i][1][1] = 0x14;
++ drvdata->rog_ally_data->response_curve[i][1][2] = 0x28;
++ drvdata->rog_ally_data->response_curve[i][1][3] = 0x28;
++ drvdata->rog_ally_data->response_curve[i][1][4] = 0x3c;
++ drvdata->rog_ally_data->response_curve[i][1][5] = 0x3c;
++ drvdata->rog_ally_data->response_curve[i][1][6] = 0x50;
++ drvdata->rog_ally_data->response_curve[i][1][7] = 0x50;
++
++ drvdata->rog_ally_data->vibration_intensity[i][0] = 64;
++ drvdata->rog_ally_data->vibration_intensity[i][1] = 64;
++ }
++
++ /* ignore all errors for this as they are related to USB HID I/O */
++ __gamepad_mapping_xpad_default(drvdata->rog_ally_data);
++ __gamepad_mapping_wasd_default(drvdata->rog_ally_data);
++ // these calls will never error so ignore the return
++ __gamepad_mapping_store(&hdev->dev, "kb_f14", btn_pair_m1_m2,
++ btn_pair_side_left, false); // M2
++ __gamepad_mapping_store(&hdev->dev, "kb_f15", btn_pair_m1_m2,
++ btn_pair_side_right, false); // M1
++ __gamepad_set_mapping(&hdev->dev, btn_pair_m1_m2);
++ __gamepad_set_mode(&hdev->dev, xpad_mode_game);
++ }
++
++ if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups))
++ goto err_stop_hw;
++ }
++ }
++
++ return 0;
++err_stop_hw:
++ hid_hw_stop(hdev);
++ return ret;
++}
++
++void asus_rog_ally_remove(struct hid_device *hdev, const struct rog_ops *ops)
++{
++ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
++ if (drvdata->rog_ally_data) {
++ __gamepad_set_mode(&hdev->dev, xpad_mode_mouse);
++ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups);
++ }
++}
++
++const struct rog_ops rog_ally = {
++ .probe = asus_rog_ally_probe,
++ .remove = asus_rog_ally_remove,
++};
+diff --git a/drivers/hid/hid-asus-rog.h b/drivers/hid/hid-asus-rog.h
+new file mode 100644
+index 000000000000..efad0b041d5d
+--- /dev/null
++++ b/drivers/hid/hid-asus-rog.h
+@@ -0,0 +1,482 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * HID driver for Asus ROG laptops and Ally
++ *
++ * Copyright (c) 2023 Luke Jones <luke@ljones.dev>
++ */
++
++/* data that is private to the hid-asus-rog module */
++
++#include <linux/hid.h>
++#include <linux/types.h>
++
++#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 RAT_LCLICK "rat_lclick"
++#define RAT_RCLICK "rat_rclick"
++#define RAT_MCLICK "rat_mclick"
++#define RAT_WHEEL_UP "rat_wheel_up"
++#define RAT_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 *raw_dev, struct device_attribute *attr, \
++ char *buf) \
++ { \
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); \
++ int idx = (_point_n - 1) * 2; \
++ return sysfs_emit( \
++ buf, "%d %d\n", \
++ rog_ally->response_curve[rog_ally->mode][btn_pair_side_left][idx], \
++ rog_ally->response_curve[rog_ally->mode][btn_pair_side_right][idx + 1]); \
++ }
++
++#define ALLY_RESP_CURVE_STORE(_name, _side, _point_n) \
++ static ssize_t _name##_store(struct device *raw_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ int ret = __gamepad_store_response_curve(raw_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 *raw_dev, \
++ struct device_attribute *attr, char *buf) \
++ { \
++ struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); \
++ int side, is_tr; \
++ \
++ 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", \
++ rog_ally->deadzones[rog_ally->mode][is_tr][side], \
++ rog_ally->deadzones[rog_ally->mode][is_tr][side + 1]); \
++ }
++
++#define ALLY_AXIS_DEADZONE_STORE(_axis) \
++ static ssize_t _axis##_deadzone_store(struct device *raw_dev, \
++ struct device_attribute *attr, const char *buf, \
++ size_t count) \
++ { \
++ int ret = __gamepad_store_deadzones(raw_dev, _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 *raw_dev, struct device_attribute *attr, \
++ char *buf) \
++ { \
++ return sysfs_emit(buf, "%s\n", \
++ __btn_map_to_string(raw_dev, _pair, _side, _secondary)); \
++ }
++
++#define ALLY_BTN_STORE(_fname, _pair, _side, _secondary) \
++ static ssize_t _fname##_store(struct device *raw_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ int ret = __gamepad_mapping_store(raw_dev, 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 *raw_dev, struct device_attribute *attr, \
++ char *buf) \
++ { \
++ return sysfs_emit(buf, "%d\n", __gamepad_turbo_show(raw_dev, _pair, _side)); \
++ }
++
++#define ALLY_BTN_TURBO_STORE(_fname, _pair, _side) \
++ static ssize_t _fname##_turbo_store(struct device *raw_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ int ret = __gamepad_turbo_store(raw_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 *raw_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ int ret = __gamepad_cal_store(raw_dev, buf, _axis); \
++ if (ret < 0) \
++ return ret; \
++ return count; \
++ };
++
++#define ALLY_CAL_SHOW(_fname, _axis) \
++ static ssize_t _fname##_show(struct device *raw_dev, struct device_attribute *attr, \
++ char *buf) \
++ { \
++ return __gamepad_cal_show(raw_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 *raw_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ int ret = __gamepad_cal_reset(raw_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);
++
++/* 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_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_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,
++};
++
++static int __gamepad_write_all_to_mcu(struct device *raw_dev);
+\ No newline at end of file
+diff --git a/drivers/hid/hid-asus.h b/drivers/hid/hid-asus.h
+new file mode 100644
+index 000000000000..18317cad7110
+--- /dev/null
++++ b/drivers/hid/hid-asus.h
+@@ -0,0 +1,58 @@
++// 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 FEATURE_KBD_REPORT_ID 0x5a
++#define FEATURE_KBD_REPORT_SIZE 16
++#define FEATURE_KBD_LED_REPORT_ID1 0x5d
++#define FEATURE_KBD_LED_REPORT_ID2 0x5e
++#define FEATURE_ROG_ALLY_REPORT_SIZE 64
++
++#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
++#define QUIRK_NO_INIT_REPORTS BIT(1)
++#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
++#define QUIRK_IS_MULTITOUCH BIT(3)
++#define QUIRK_NO_CONSUMER_USAGES BIT(4)
++#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
++#define QUIRK_T100_KEYBOARD BIT(6)
++#define QUIRK_T100CHI BIT(7)
++#define QUIRK_G752_KEYBOARD BIT(8)
++#define QUIRK_T90CHI BIT(9)
++#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)
++
++struct asus_drvdata {
++ unsigned long quirks;
++ struct hid_device *hdev;
++ struct input_dev *input;
++ struct input_dev *tp_kbd_input;
++ struct asus_kbd_leds *kbd_backlight;
++ const struct asus_touchpad_info *tp;
++ bool enable_backlight;
++ struct power_supply *battery;
++ struct power_supply_desc battery_desc;
++ int battery_capacity;
++ int battery_stat;
++ bool battery_in_query;
++ unsigned long battery_next_query;
++ struct asus_rog_ally *rog_ally_data;
++};
++
++extern int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size);
++
++extern int asus_kbd_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size);
++
++struct rog_ops {
++ int (*probe) (struct hid_device *hdev, const struct rog_ops *ops);
++ void (*remove) (struct hid_device *hdev, const struct rog_ops *ops);
++};
++
++extern const struct rog_ops rog_ally;
+\ No newline at end of file
+--
+2.43.0
+