diff options
author | Jan200101 <sentrycraft123@gmail.com> | 2024-02-11 20:00:26 +0100 |
---|---|---|
committer | Jan200101 <sentrycraft123@gmail.com> | 2024-02-11 20:00:26 +0100 |
commit | d163bd3d8fbc0666ca31afdcf152a2450f352753 (patch) | |
tree | a0c5e11a9a02ad1a2855ed0338d3187979ba9c77 /SOURCES | |
parent | b8d31e3c4edc6bb6fe7ce82505962e61882ad3d0 (diff) | |
download | kernel-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.patch | 1471 | ||||
-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.patch | 2329 |
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 + |