From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-dy1-f180.google.com (mail-dy1-f180.google.com [74.125.82.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D10D3E8C78 for ; Tue, 10 Mar 2026 07:29:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.180 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773127786; cv=none; b=WVHI+6FhkoG7w3EcHO6IdFYu34hTzpovpoh76TVoq7LfryX+lKVyoUUKQOZmMpFND7mrT3LvOCqMjPdQmgCBfChOyCY/Rm2omQp22xT6CVjOvQ9bFcdFaEt8XarmP7LFsjpkGk55/8fWxQFFhMd7zdx78E0RnTAmDHDFJUMfeuk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773127786; c=relaxed/simple; bh=gCXiCKhaJmhwkLrGzM6kUf/yLBe8ayeGTu/oRw+fnHw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jq3umv1aT7cFyHaUAgaUNNFcWKS7cG1/sFQnYZdUdW/KTNcH4qgvLuKcSdAX9foDW5R96dVujHbPYSen2yvEIpC3odoRAws1CZxq/LE0lfrcnq9KuW37OhEO9zS+aBj2ZBNwV81/yPWpfOqUaJrLRonHQowBL/iGG4ozO+AJc4c= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GTw3vaJz; arc=none smtp.client-ip=74.125.82.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GTw3vaJz" Received: by mail-dy1-f180.google.com with SMTP id 5a478bee46e88-2ba9c484e5eso12429212eec.1 for ; Tue, 10 Mar 2026 00:29:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773127783; x=1773732583; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=EbJj+BhWY40TJ6BSEM6IqA1O92CX4jlj8rIAmx9+drY=; b=GTw3vaJzVTHXb2yNbqZQ3C7/m+34hhzFE1XxGo/DTGuPCEOm/nkwSGBfzybIO4lx+L v0Zydnk0Im8AKZfda0+ZRRfH5EdVI6x//nJTr7e0dh8OTrR5Rbx/GsmOsyxGl71/lHa6 qqIYH/0JMxWaEp7w35I/gF68Ts9y0W96x9QzfgOpjIuaBfZsYm0K04N6T32pkkhBG687 jMo/liZv9n0QLyu9SZ6/7F9woNo3d0nXov/TtAQK5axXPjjq1mPopFCOlFSSDbTboRPB rII/NvtOh6AQXV5Hbqc6PCr80cQXdKeeAXFxZ4bzvz+mmzKGl74BnckJ8mYHnRtzOteo Zsxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773127783; x=1773732583; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=EbJj+BhWY40TJ6BSEM6IqA1O92CX4jlj8rIAmx9+drY=; b=POITfyQxkKRF9D66Z8kTSLQGnsRCU1Mci1izBxy7PVBwwQl0OrtSU/hqeQfNA6iqtI jMy5/U2guTDOOEL4mL5nm84QSjd4igEw88Hw88Q3x2gdTMDgNV9cQwZdUV5rQB5fd63w o/sZW5Tn6Aqfcu+IxwN1qsyKkKG+nJOdimJyW0yI7dHDawXEoazoIe0D65ihvxzYIoyj JTbT/b/Yi23pJrBldUOeYCexKhchoC+NL+IYxdLBFOUETi7tazNJLVH//WcF7VloLDcW 6mkVIuBVwJWeNlpNdLjMNi+yM7265AV9dufVnjKiSdLW4vrSc3QXcM91ujzuph6a0zS7 +ILg== X-Forwarded-Encrypted: i=1; AJvYcCVotzLj/lNx3wccOCLEvMDrlnJKgkhVnPe5HZwFxLt6vZVnhprF0M68y5ByGh0/DhKOYbTt89usMStpWxo=@vger.kernel.org X-Gm-Message-State: AOJu0Ywq17BmKVUa0VugHG+38/t6opjcg2qX67vId8fFPdhc1eZ7ezGK V1m7ycCaUxCqjpWDJ05QnZY8devlRwKw+LvD9aClAnDXXI3CvWaKGxVj X-Gm-Gg: ATEYQzw44vwbXI5AD8XUS76pr2LqPBj7x0AKNm7qY9Y/LDP6CABC37gWNawdIm2hulb ENnyXkBDzJZ96J9FgmbToNlT8AwkeGMn2YvbQZUnmdinFfZfEdlUK8zkkfOIA37qDw/sukRYgBb n0MGWQ6e1O55nLE1GYbZ8yGE2/dQTmcCqMatqdOySAJVzw334Z2gk37VYXMdFqLSEvm3xm92HjM q9X0I0ju1351jMt19rtJnm7M/fhk3zurnPBAjZSRwRbPjtgIUtPRWKLj4f/S99GRYSmAntUu1Yg JPNkXjKuHwnq7jRuGRgRsWNPtry9ooDaMCcY0DU7WQ7WRED5V71WFMK2aTcIYF5n9wkV1QHmXO6 u6y+cDdiTW3yTDOxw9Fwv8PN4szyu7zB2OJLRmnVkPapasnUv6CVyx3m3UVEp1z7EIc1nB7Nds1 czINCOhOK4B/mXvKv1Kik6QEqGBjAufD3mu7l+8E6bMV++yS53TETEgvVn7g5Criqy1LOLiDKcZ S9W X-Received: by 2002:a05:7300:cd90:b0:2ba:7863:f0a8 with SMTP id 5a478bee46e88-2be4e0d3a1cmr5339744eec.36.1773127783429; Tue, 10 Mar 2026 00:29:43 -0700 (PDT) Received: from lappy (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2be81209142sm721925eec.12.2026.03.10.00.29.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 00:29:43 -0700 (PDT) From: "Derek J. Clark" To: Jiri Kosina , Benjamin Tissoires Cc: Richard Hughes , Mario Limonciello , Zhixin Zhang , Mia Shao , Mark Pearson , "Pierre-Loup A . Griffais" , "Derek J . Clark" , linux-input@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v6 04/19] HID: hid-lenovo-go: Add Rumble and Haptic Settings Date: Tue, 10 Mar 2026 07:29:22 +0000 Message-ID: <20260310072937.3295875-5-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310072937.3295875-1-derekjohn.clark@gmail.com> References: <20260310072937.3295875-1-derekjohn.clark@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Adds attributes that control the handles rumble mode and intensity, as well as touchpad haptic feedback settings. Reviewed-by: Mark Pearson Signed-off-by: Derek J. Clark --- v6: - Make local attributes static. - Use NULL instead of 0 in mcu_propery_out when there is no data. v3: - Remove erroneous renaming of enabled -> enable for some left & right handle attributes. --- drivers/hid/hid-lenovo-go.c | 312 ++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c index d7d47db8362c..f2a54865cfbb 100644 --- a/drivers/hid/hid-lenovo-go.c +++ b/drivers/hid/hid-lenovo-go.c @@ -41,6 +41,8 @@ static struct hid_go_cfg { struct mutex cfg_mutex; /*ensure single synchronous output report*/ u8 fps_mode; u8 gp_left_auto_sleep_time; + u8 gp_left_notify_en; + u8 gp_left_rumble_mode; u32 gp_left_version_firmware; u8 gp_left_version_gen; u32 gp_left_version_hardware; @@ -48,11 +50,14 @@ static struct hid_go_cfg { u32 gp_left_version_protocol; u8 gp_mode; u8 gp_right_auto_sleep_time; + u8 gp_right_notify_en; + u8 gp_right_rumble_mode; u32 gp_right_version_firmware; u8 gp_right_version_gen; u32 gp_right_version_hardware; u32 gp_right_version_product; u32 gp_right_version_protocol; + u8 gp_rumble_intensity; u8 imu_left_bypass_en; u8 imu_left_sensor_en; u8 imu_right_bypass_en; @@ -64,6 +69,8 @@ static struct hid_go_cfg { u32 mcu_version_protocol; u8 rgb_en; u8 tp_en; + u8 tp_vibration_en; + u8 tp_vibration_intensity; u32 tx_dongle_version_firmware; u8 tx_dongle_version_gen; u32 tx_dongle_version_hardware; @@ -170,6 +177,49 @@ static const char *const gamepad_mode_text[] = { [DINPUT] = "dinput", }; +enum motor_cfg_index { + MOTOR_CFG_ALL = 0x01, + MOTOR_INTENSITY, + VIBRATION_NOTIFY_ENABLE, + RUMBLE_MODE, + TP_VIBRATION_ENABLE, + TP_VIBRATION_INTENSITY, +}; + +enum intensity_index { + INTENSITY_UNKNOWN, + INTENSITY_OFF, + INTENSITY_LOW, + INTENSITY_MEDIUM, + INTENSITY_HIGH, +}; + +static const char *const intensity_text[] = { + [INTENSITY_UNKNOWN] = "unknown", + [INTENSITY_OFF] = "off", + [INTENSITY_LOW] = "low", + [INTENSITY_MEDIUM] = "medium", + [INTENSITY_HIGH] = "high", +}; + +enum rumble_mode_index { + RUMBLE_MODE_UNKNOWN, + RUMBLE_MODE_FPS, + RUMBLE_MODE_RACE, + RUMBLE_MODE_AVERAGE, + RUMBLE_MODE_SPG, + RUMBLE_MODE_RPG, +}; + +static const char *const rumble_mode_text[] = { + [RUMBLE_MODE_UNKNOWN] = "unknown", + [RUMBLE_MODE_FPS] = "fps", + [RUMBLE_MODE_RACE] = "racing", + [RUMBLE_MODE_AVERAGE] = "standard", + [RUMBLE_MODE_SPG] = "spg", + [RUMBLE_MODE_RPG] = "rpg", +}; + static int hid_go_version_event(struct command_report *cmd_rep) { switch (cmd_rep->sub_cmd) { @@ -336,6 +386,47 @@ static int hid_go_feature_status_event(struct command_report *cmd_rep) } } +static int hid_go_motor_event(struct command_report *cmd_rep) +{ + switch (cmd_rep->sub_cmd) { + case MOTOR_CFG_ALL: + return -EINVAL; + case MOTOR_INTENSITY: + drvdata.gp_rumble_intensity = cmd_rep->data[0]; + return 0; + case VIBRATION_NOTIFY_ENABLE: + switch (cmd_rep->device_type) { + case LEFT_CONTROLLER: + drvdata.gp_left_notify_en = cmd_rep->data[0]; + return 0; + case RIGHT_CONTROLLER: + drvdata.gp_right_notify_en = cmd_rep->data[0]; + return 0; + default: + return -EINVAL; + }; + break; + case RUMBLE_MODE: + switch (cmd_rep->device_type) { + case LEFT_CONTROLLER: + drvdata.gp_left_rumble_mode = cmd_rep->data[0]; + return 0; + case RIGHT_CONTROLLER: + drvdata.gp_right_rumble_mode = cmd_rep->data[0]; + return 0; + default: + return -EINVAL; + }; + case TP_VIBRATION_ENABLE: + drvdata.tp_vibration_en = cmd_rep->data[0]; + return 0; + case TP_VIBRATION_INTENSITY: + drvdata.tp_vibration_intensity = cmd_rep->data[0]; + return 0; + } + return -EINVAL; +} + static int hid_go_set_event_return(struct command_report *cmd_rep) { if (cmd_rep->data[0] != 0) @@ -383,7 +474,11 @@ static int hid_go_raw_event(struct hid_device *hdev, struct hid_report *report, case GET_FEATURE_STATUS: ret = hid_go_feature_status_event(cmd_rep); break; + case GET_MOTOR_CFG: + ret = hid_go_motor_event(cmd_rep); + break; case SET_FEATURE_STATUS: + case SET_MOTOR_CFG: ret = hid_go_set_event_return(cmd_rep); break; default: @@ -759,6 +854,168 @@ static ssize_t feature_status_options(struct device *dev, return count; } +static ssize_t motor_config_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + enum motor_cfg_index index, + enum dev_type device_type) +{ + size_t size = 1; + u8 val = 0; + int ret; + + switch (index) { + case MOTOR_CFG_ALL: + return -EINVAL; + case MOTOR_INTENSITY: + ret = sysfs_match_string(intensity_text, buf); + val = ret; + break; + case VIBRATION_NOTIFY_ENABLE: + ret = sysfs_match_string(enabled_status_text, buf); + val = ret; + break; + case RUMBLE_MODE: + ret = sysfs_match_string(rumble_mode_text, buf); + val = ret; + break; + case TP_VIBRATION_ENABLE: + ret = sysfs_match_string(enabled_status_text, buf); + val = ret; + break; + case TP_VIBRATION_INTENSITY: + ret = sysfs_match_string(intensity_text, buf); + val = ret; + break; + }; + + if (ret < 0) + return ret; + + if (!val) + size = 0; + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, SET_MOTOR_CFG, + index, device_type, &val, size); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t motor_config_show(struct device *dev, + struct device_attribute *attr, char *buf, + enum motor_cfg_index index, + enum dev_type device_type) +{ + ssize_t count = 0; + int ret; + u8 i; + + ret = mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_MOTOR_CFG, + index, device_type, NULL, 0); + if (ret) + return ret; + + switch (index) { + case MOTOR_CFG_ALL: + return -EINVAL; + case MOTOR_INTENSITY: + i = drvdata.gp_rumble_intensity; + if (i >= ARRAY_SIZE(intensity_text)) + return -EINVAL; + + count = sysfs_emit(buf, "%s\n", intensity_text[i]); + break; + case VIBRATION_NOTIFY_ENABLE: + switch (device_type) { + case LEFT_CONTROLLER: + i = drvdata.gp_left_notify_en; + break; + case RIGHT_CONTROLLER: + i = drvdata.gp_right_notify_en; + break; + default: + return -EINVAL; + }; + if (i >= ARRAY_SIZE(enabled_status_text)) + return -EINVAL; + + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); + break; + case RUMBLE_MODE: + switch (device_type) { + case LEFT_CONTROLLER: + i = drvdata.gp_left_rumble_mode; + break; + case RIGHT_CONTROLLER: + i = drvdata.gp_right_rumble_mode; + break; + default: + return -EINVAL; + }; + if (i >= ARRAY_SIZE(rumble_mode_text)) + return -EINVAL; + + count = sysfs_emit(buf, "%s\n", rumble_mode_text[i]); + break; + case TP_VIBRATION_ENABLE: + i = drvdata.tp_vibration_en; + if (i >= ARRAY_SIZE(enabled_status_text)) + return -EINVAL; + + count = sysfs_emit(buf, "%s\n", enabled_status_text[i]); + break; + case TP_VIBRATION_INTENSITY: + i = drvdata.tp_vibration_intensity; + if (i >= ARRAY_SIZE(intensity_text)) + return -EINVAL; + + count = sysfs_emit(buf, "%s\n", intensity_text[i]); + break; + }; + + return count; +} + +static ssize_t motor_config_options(struct device *dev, + struct device_attribute *attr, char *buf, + enum motor_cfg_index index) +{ + ssize_t count = 0; + unsigned int i; + + switch (index) { + case MOTOR_CFG_ALL: + break; + case RUMBLE_MODE: + for (i = 1; i < ARRAY_SIZE(rumble_mode_text); i++) { + count += sysfs_emit_at(buf, count, "%s ", + rumble_mode_text[i]); + } + break; + case MOTOR_INTENSITY: + case TP_VIBRATION_INTENSITY: + for (i = 1; i < ARRAY_SIZE(intensity_text); i++) { + count += sysfs_emit_at(buf, count, "%s ", + intensity_text[i]); + } + break; + case VIBRATION_NOTIFY_ENABLE: + case TP_VIBRATION_ENABLE: + for (i = 1; i < ARRAY_SIZE(enabled_status_text); i++) { + count += sysfs_emit_at(buf, count, "%s ", + enabled_status_text[i]); + } + break; + }; + + if (count) + buf[count - 1] = '\n'; + + return count; +} + #define LEGO_DEVICE_ATTR_RW(_name, _attrname, _dtype, _rtype, _group) \ static ssize_t _name##_store(struct device *dev, \ struct device_attribute *attr, \ @@ -824,10 +1081,18 @@ static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mode_index"); static struct go_cfg_attr reset_mcu = { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_mcu, "reset_mcu", USB_MCU, feature_status); +static struct go_cfg_attr gamepad_rumble_intensity = { MOTOR_INTENSITY }; +LEGO_DEVICE_ATTR_RW(gamepad_rumble_intensity, "rumble_intensity", UNSPECIFIED, + index, motor_config); +static DEVICE_ATTR_RO_NAMED(gamepad_rumble_intensity_index, + "rumble_intensity_index"); + static struct attribute *mcu_attrs[] = { &dev_attr_fps_switch_status.attr, &dev_attr_gamepad_mode.attr, &dev_attr_gamepad_mode_index.attr, + &dev_attr_gamepad_rumble_intensity.attr, + &dev_attr_gamepad_rumble_intensity_index.attr, &dev_attr_reset_mcu.attr, &dev_attr_version_firmware_mcu.attr, &dev_attr_version_gen_mcu.attr, @@ -910,6 +1175,17 @@ static DEVICE_ATTR_RO_NAMED(imu_enabled_left_index, "imu_enabled_index"); static struct go_cfg_attr reset_left = { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_left, "reset", LEFT_CONTROLLER, feature_status); +static struct go_cfg_attr rumble_mode_left = { RUMBLE_MODE }; +LEGO_DEVICE_ATTR_RW(rumble_mode_left, "rumble_mode", LEFT_CONTROLLER, index, + motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_mode_left_index, "rumble_mode_index"); + +static struct go_cfg_attr rumble_notification_left = { VIBRATION_NOTIFY_ENABLE }; +LEGO_DEVICE_ATTR_RW(rumble_notification_left, "rumble_notification", + LEFT_CONTROLLER, index, motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_notification_left_index, + "rumble_notification_index"); + static struct attribute *left_gamepad_attrs[] = { &dev_attr_auto_sleep_time_left.attr, &dev_attr_auto_sleep_time_left_range.attr, @@ -918,6 +1194,10 @@ static struct attribute *left_gamepad_attrs[] = { &dev_attr_imu_enabled_left.attr, &dev_attr_imu_enabled_left_index.attr, &dev_attr_reset_left.attr, + &dev_attr_rumble_mode_left.attr, + &dev_attr_rumble_mode_left_index.attr, + &dev_attr_rumble_notification_left.attr, + &dev_attr_rumble_notification_left_index.attr, &dev_attr_version_hardware_left.attr, &dev_attr_version_firmware_left.attr, &dev_attr_version_gen_left.attr, @@ -966,6 +1246,17 @@ static DEVICE_ATTR_RO_NAMED(imu_enabled_right_index, "imu_enabled_index"); static struct go_cfg_attr reset_right = { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_right, "reset", LEFT_CONTROLLER, feature_status); +static struct go_cfg_attr rumble_mode_right = { RUMBLE_MODE }; +LEGO_DEVICE_ATTR_RW(rumble_mode_right, "rumble_mode", RIGHT_CONTROLLER, index, + motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_mode_right_index, "rumble_mode_index"); + +static struct go_cfg_attr rumble_notification_right = { VIBRATION_NOTIFY_ENABLE }; +LEGO_DEVICE_ATTR_RW(rumble_notification_right, "rumble_notification", + RIGHT_CONTROLLER, index, motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_notification_right_index, + "rumble_notification_index"); + static struct attribute *right_gamepad_attrs[] = { &dev_attr_auto_sleep_time_right.attr, &dev_attr_auto_sleep_time_right_range.attr, @@ -974,6 +1265,10 @@ static struct attribute *right_gamepad_attrs[] = { &dev_attr_imu_enabled_right.attr, &dev_attr_imu_enabled_right_index.attr, &dev_attr_reset_right.attr, + &dev_attr_rumble_mode_right.attr, + &dev_attr_rumble_mode_right_index.attr, + &dev_attr_rumble_notification_right.attr, + &dev_attr_rumble_notification_right_index.attr, &dev_attr_version_hardware_right.attr, &dev_attr_version_firmware_right.attr, &dev_attr_version_gen_right.attr, @@ -993,9 +1288,26 @@ LEGO_DEVICE_ATTR_RW(touchpad_enabled, "enabled", UNSPECIFIED, index, feature_status); static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index"); +static struct go_cfg_attr touchpad_vibration_enabled = { TP_VIBRATION_ENABLE }; +LEGO_DEVICE_ATTR_RW(touchpad_vibration_enabled, "vibration_enabled", UNSPECIFIED, + index, motor_config); +static DEVICE_ATTR_RO_NAMED(touchpad_vibration_enabled_index, + "vibration_enabled_index"); + +static struct go_cfg_attr touchpad_vibration_intensity = { TP_VIBRATION_INTENSITY }; +LEGO_DEVICE_ATTR_RW(touchpad_vibration_intensity, "vibration_intensity", + UNSPECIFIED, index, motor_config); +static DEVICE_ATTR_RO_NAMED(touchpad_vibration_intensity_index, + "vibration_intensity_index"); + static struct attribute *touchpad_attrs[] = { &dev_attr_touchpad_enabled.attr, &dev_attr_touchpad_enabled_index.attr, + &dev_attr_touchpad_vibration_enabled.attr, + &dev_attr_touchpad_vibration_enabled_index.attr, + &dev_attr_touchpad_vibration_intensity.attr, + &dev_attr_touchpad_vibration_intensity_index.attr, + NULL, }; static const struct attribute_group touchpad_attr_group = { -- 2.53.0