hid-asus: check ROG Ally MCU version and warn
[ Upstream commit 00e005c952f74f50a3f86af96f56877be4685e14 ] ASUS have fixed suspend issues arising from a flag not being cleared in the MCU FW in both the ROG Ally 1 and the ROG Ally X. Implement a check and a warning to encourage users to update the FW to a minimum supported version. Signed-off-by: Luke D. Jones <luke@ljones.dev> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> Link: https://lore.kernel.org/r/20250323023421.78012-2-luke@ljones.dev Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6f84ec0a5a
commit
ff38cf0bd8
@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define FEATURE_KBD_LED_REPORT_ID1 0x5d
|
||||
#define FEATURE_KBD_LED_REPORT_ID2 0x5e
|
||||
|
||||
#define ROG_ALLY_REPORT_SIZE 64
|
||||
#define ROG_ALLY_X_MIN_MCU 313
|
||||
#define ROG_ALLY_MIN_MCU 319
|
||||
|
||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
||||
|
||||
#define MAX_TOUCH_MAJOR 8
|
||||
@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define QUIRK_MEDION_E1239T BIT(10)
|
||||
#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
|
||||
#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
|
||||
#define QUIRK_ROG_ALLY_XPAD BIT(13)
|
||||
|
||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
||||
QUIRK_NO_INIT_REPORTS | \
|
||||
@@ -534,9 +539,99 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
|
||||
return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't care about any other part of the string except the version section.
|
||||
* Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01
|
||||
* The bytes "5a 05 03 31 00 1a 13" and possibly more come before the version
|
||||
* string, and there may be additional bytes after the version string such as
|
||||
* "75 00 74 00 65 00" or a postfix such as "_T01"
|
||||
*/
|
||||
static int mcu_parse_version_string(const u8 *response, size_t response_size)
|
||||
{
|
||||
const u8 *end = response + response_size;
|
||||
const u8 *p = response;
|
||||
int dots, err, version;
|
||||
char buf[4];
|
||||
|
||||
dots = 0;
|
||||
while (p < end && dots < 2) {
|
||||
if (*p++ == '.')
|
||||
dots++;
|
||||
}
|
||||
|
||||
if (dots != 2 || p >= end || (p + 3) >= end)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buf, p, 3);
|
||||
buf[3] = '\0';
|
||||
|
||||
err = kstrtoint(buf, 10, &version);
|
||||
if (err || version < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
static int mcu_request_version(struct hid_device *hdev)
|
||||
{
|
||||
u8 *response __free(kfree) = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
|
||||
const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 };
|
||||
int ret;
|
||||
|
||||
if (!response)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = asus_kbd_set_report(hdev, request, sizeof(request));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response,
|
||||
ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to parse MCU version: %d\n", ret);
|
||||
print_hex_dump(KERN_ERR, "MCU: ", DUMP_PREFIX_NONE,
|
||||
16, 1, response, ROG_ALLY_REPORT_SIZE, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void validate_mcu_fw_version(struct hid_device *hdev, int idProduct)
|
||||
{
|
||||
int min_version, version;
|
||||
|
||||
version = mcu_request_version(hdev);
|
||||
if (version < 0)
|
||||
return;
|
||||
|
||||
switch (idProduct) {
|
||||
case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY:
|
||||
min_version = ROG_ALLY_MIN_MCU;
|
||||
break;
|
||||
case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X:
|
||||
min_version = ROG_ALLY_X_MIN_MCU;
|
||||
break;
|
||||
default:
|
||||
min_version = 0;
|
||||
}
|
||||
|
||||
if (version < min_version) {
|
||||
hid_warn(hdev,
|
||||
"The MCU firmware version must be %d or greater to avoid issues with suspend.\n",
|
||||
min_version);
|
||||
}
|
||||
}
|
||||
|
||||
static int asus_kbd_register_leds(struct hid_device *hdev)
|
||||
{
|
||||
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||
struct usb_interface *intf;
|
||||
struct usb_device *udev;
|
||||
unsigned char kbd_func;
|
||||
int ret;
|
||||
|
||||
@@ -560,6 +655,14 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) {
|
||||
intf = to_usb_interface(hdev->dev.parent);
|
||||
udev = interface_to_usbdev(intf);
|
||||
validate_mcu_fw_version(hdev,
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Initialize keyboard */
|
||||
ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID);
|
||||
@@ -1280,10 +1383,10 @@ static const struct hid_device_id asus_devices[] = {
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD},
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
|
||||
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
|
||||
|
||||
Reference in New Issue
Block a user