From nobody Sun Feb 8 23:25:47 2026 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 3CA73273803 for ; Mon, 29 Dec 2025 03:18:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766978285; cv=none; b=EZJCOcrKXT+R2h414j4oSWGRvzJd3jwrmLpX+tRuhVXOC5bAOK3wEtJTRRgmOO4Qy90TOstL7oPrc30xwfQ5+V/hVXulYRZ9AnZXOJOIUbaxQBy+TfEqAlR5sjBPk5BP/zAtAJw17mOwMWpiteNEUlJ/IhadCSMAJ4l2lG17xVs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766978285; c=relaxed/simple; bh=LXmgTZe1DTlhBfOcVlbAaBHy8ZKaDHEjHmzF1BOSMdg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dLjM/fL/AvCKj0IeubmCaHAvRjqya17tzZ710JxUbBxxDmUU0urngBIXUuLN115kjlOplt8/OVrFOPy+6wccjrCOPfpPJ3fSPiD+FmZmtwkiYmUxPeGRg7f1qPqpSHbnxcRatqBzX10c47W0vT0U4NMxBdeFkbrredjjOefe1TY= 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=g5HSFf45; arc=none smtp.client-ip=209.85.210.174 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="g5HSFf45" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-7bab7c997eeso10167557b3a.0 for ; Sun, 28 Dec 2025 19:18:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1766978281; x=1767583081; 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=3JwaiSohIuuXkqze/ZakjDyPJj0LsG+i+X6xuEUq81s=; b=g5HSFf45gOY/i4N5x3QWdj5pLjSOXEvAX4f+SxdxgN2mpK0AQ9x9MYZkKczsHjXhiL QXR+d/RSnHeTwTYXEVWoBqIIG0cUJtcxvA8lDP7M5UliGxN18h9VMLZkxzeibjyZ5JUT bf2e4eAbazzNDZW+550pbK0qeqYvdHRUqZ/b9OKbSkqXx+QRu4ksEdFTHwI6la/kRSm1 BZfOFeACmtP1aWpk0/X3nDGWNVUQa8Gdl0A1TW2yO2VrwyIzc6Zbk564PfQ284sC27Dz MjiS96mnKxeZEnW7MMng5k5SWDbsieyf4H2U/B4OsTe+GkI3chA+rW0Hvb+cfSSvUYnN aPFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766978281; x=1767583081; 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=3JwaiSohIuuXkqze/ZakjDyPJj0LsG+i+X6xuEUq81s=; b=rJJQtUD1VF1XCuHajsAXpvSN3xYdv3/YT8/OIMZfEyeNJMNk0nXw+/idBlJxSSHFuE ICk0qspG6FccRomPUuFQLY4mBKZNC2dHTxkMfQONILBsLJV7boif4xOqMI6YvLcrzVtI cHsk9F9vNrtG96bKNCLnT9f7fYPnI69wsUzyxnp/ATYhapVwYqZ5oITSY435RpAHcYiA RcgYNP+ZbnmeBDWBCPWaPFz9ijiZJuxKCpL5ccRWEdx4VHr02riEWkXXeWhep5SlIHcQ qlzBo1ZGaTd5X9Zo6/tsUM9u26OyfXUhtRUn0YxtNsCjg+nu+naGP2v9ty4oS2rQMLO0 2xpw== X-Forwarded-Encrypted: i=1; AJvYcCUQ+AT1RgL6ZeO/VFaDc/yri+H5B20Qus5y0tiSFQbpnKse7OYRivlGknrdjRGh/9EGR+azV3dUmDzLKLU=@vger.kernel.org X-Gm-Message-State: AOJu0YysY2g204wqCz2Z0FKivvrtFw2cyhaDBBwXu021FH7QkdaH6xht tDTLXe3HeZbFxhcpi++2o+WGZlnldB7dsENNgduW5uKKyY+prse2ibqS X-Gm-Gg: AY/fxX4dwG7CbNeD3sSys4fAwtuPtL56DkNVagGvsKbY/M2NtDRsQ7TfaFcDNeu9i8E /3McPDVY5UvmPpLHHMcQBbzIbjL5bc+Fb9bcxLQ7pGdAj1C66yizFtX4jBvznZ+WmLDyGZ94VMo yaP3NTBUe6/HX/ro6FauCuYZh6Y3xITydKT0HzKQ6y2YnVPHRFrS0CIBqfkQmzvGboiIPF20W8S IBLcADlkdISkrezhali5wiVD3kYhtlQG26EYIRJE5NaSYghiGsHHQ6QXKevzelCOnY+gCAVCukD +Y+fsBtYHxG6epOBtbtxTI88BbbPnubgzk7A2v/7rUS5xyKwPWg4mBx9KB6DphxHNbwmNk1/OZ+ LvB0PTVAleO91XzgjVshUDjX1cpOAZpxcJxPW9brwKn/UmTL76dJDrVaXHWFebAG2axc+ipBASU 9KuPSmTWQRaNAvi4cRxItWVQN4oLa2iOziJ4J/bIE9ux+XezQOSb5HrZ7RvknOHgk= X-Google-Smtp-Source: AGHT+IE0oxTw33lXF0gPNZqSMH5W8WMr0A1jHiugdw67TZB5txq6InB6ctwd1MVVDSWaebt5Yahqaw== X-Received: by 2002:a05:7022:6199:b0:11f:1e59:4c2d with SMTP id a92af1059eb24-121721acb6dmr26336978c88.7.1766978281186; Sun, 28 Dec 2025 19:18:01 -0800 (PST) Received: from lappy (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-121724dd7f5sm112992785c88.5.2025.12.28.19.18.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Dec 2025 19:18:00 -0800 (PST) From: "Derek J. Clark" To: Jiri Kosina , Benjamin Tissoires Cc: 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 v2 04/16] HID: hid-lenovo-go: Add Rumble and Haptic Settings Date: Mon, 29 Dec 2025 03:17:41 +0000 Message-ID: <20251229031753.581664-5-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20251229031753.581664-1-derekjohn.clark@gmail.com> References: <20251229031753.581664-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: quoted-printable Content-Type: text/plain; charset="utf-8" Adds attributes that control the handles rumble mode and intensity, as well as touchpad haptic feedback settings. Signed-off-by: Derek J. Clark --- drivers/hid/hid-lenovo-go.c | 340 ++++++++++++++++++++++++++++++++++-- 1 file changed, 326 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-lenovo-go.c b/drivers/hid/hid-lenovo-go.c index 681791f119d1..7d8bd1dba7ce 100644 --- a/drivers/hid/hid-lenovo-go.c +++ b/drivers/hid/hid-lenovo-go.c @@ -38,6 +38,8 @@ 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; @@ -45,11 +47,14 @@ 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; @@ -61,6 +66,8 @@ 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; @@ -167,6 +174,49 @@ static const char *const gamepad_mode_text[] =3D { [DINPUT] =3D "dinput", }; =20 +enum motor_cfg_index { + MOTOR_CFG_ALL =3D 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[] =3D { + [INTENSITY_UNKNOWN] =3D "unknown", + [INTENSITY_OFF] =3D "off", + [INTENSITY_LOW] =3D "low", + [INTENSITY_MEDIUM] =3D "medium", + [INTENSITY_HIGH] =3D "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[] =3D { + [RUMBLE_MODE_UNKNOWN] =3D "unknown", + [RUMBLE_MODE_FPS] =3D "fps", + [RUMBLE_MODE_RACE] =3D "racing", + [RUMBLE_MODE_AVERAGE] =3D "standard", + [RUMBLE_MODE_SPG] =3D "spg", + [RUMBLE_MODE_RPG] =3D "rpg", +}; + static int hid_go_version_event(struct command_report *cmd_rep) { switch (cmd_rep->sub_cmd) { @@ -333,6 +383,47 @@ static int hid_go_feature_status_event(struct command_= report *cmd_rep) } } =20 +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 =3D cmd_rep->data[0]; + return 0; + case VIBRATION_NOTIFY_ENABLE: + switch (cmd_rep->device_type) { + case LEFT_CONTROLLER: + drvdata.gp_left_notify_en =3D cmd_rep->data[0]; + return 0; + case RIGHT_CONTROLLER: + drvdata.gp_right_notify_en =3D 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 =3D cmd_rep->data[0]; + return 0; + case RIGHT_CONTROLLER: + drvdata.gp_right_rumble_mode =3D cmd_rep->data[0]; + return 0; + default: + return -EINVAL; + }; + case TP_VIBRATION_ENABLE: + drvdata.tp_vibration_en =3D cmd_rep->data[0]; + return 0; + case TP_VIBRATION_INTENSITY: + drvdata.tp_vibration_intensity =3D 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] !=3D 0) @@ -380,7 +471,11 @@ static int hid_go_raw_event(struct hid_device *hdev, s= truct hid_report *report, case GET_FEATURE_STATUS: ret =3D hid_go_feature_status_event(cmd_rep); break; + case GET_MOTOR_CFG: + ret =3D hid_go_motor_event(cmd_rep); + break; case SET_FEATURE_STATUS: + case SET_MOTOR_CFG: ret =3D hid_go_set_event_return(cmd_rep); break; default: @@ -757,6 +852,168 @@ static ssize_t feature_status_options(struct device *= dev, return count; } =20 +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 =3D 1; + u8 val =3D 0; + int ret; + + switch (index) { + case MOTOR_CFG_ALL: + return -EINVAL; + case MOTOR_INTENSITY: + ret =3D sysfs_match_string(intensity_text, buf); + val =3D ret; + break; + case VIBRATION_NOTIFY_ENABLE: + ret =3D sysfs_match_string(enabled_status_text, buf); + val =3D ret; + break; + case RUMBLE_MODE: + ret =3D sysfs_match_string(rumble_mode_text, buf); + val =3D ret; + break; + case TP_VIBRATION_ENABLE: + ret =3D sysfs_match_string(enabled_status_text, buf); + val =3D ret; + break; + case TP_VIBRATION_INTENSITY: + ret =3D sysfs_match_string(intensity_text, buf); + val =3D ret; + break; + }; + + if (ret < 0) + return ret; + + if (!val) + size =3D 0; + + ret =3D 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 =3D 0; + int ret; + u8 i; + + ret =3D mcu_property_out(drvdata.hdev, MCU_CONFIG_DATA, GET_MOTOR_CFG, + index, device_type, 0, 0); + if (ret) + return ret; + + switch (index) { + case MOTOR_CFG_ALL: + return -EINVAL; + case MOTOR_INTENSITY: + i =3D drvdata.gp_rumble_intensity; + if (i >=3D ARRAY_SIZE(intensity_text)) + return -EINVAL; + + count =3D sysfs_emit(buf, "%s\n", intensity_text[i]); + break; + case VIBRATION_NOTIFY_ENABLE: + switch (device_type) { + case LEFT_CONTROLLER: + i =3D drvdata.gp_left_notify_en; + break; + case RIGHT_CONTROLLER: + i =3D drvdata.gp_right_notify_en; + break; + default: + return -EINVAL; + }; + if (i >=3D ARRAY_SIZE(enabled_status_text)) + return -EINVAL; + + count =3D sysfs_emit(buf, "%s\n", enabled_status_text[i]); + break; + case RUMBLE_MODE: + switch (device_type) { + case LEFT_CONTROLLER: + i =3D drvdata.gp_left_rumble_mode; + break; + case RIGHT_CONTROLLER: + i =3D drvdata.gp_right_rumble_mode; + break; + default: + return -EINVAL; + }; + if (i >=3D ARRAY_SIZE(rumble_mode_text)) + return -EINVAL; + + count =3D sysfs_emit(buf, "%s\n", rumble_mode_text[i]); + break; + case TP_VIBRATION_ENABLE: + i =3D drvdata.tp_vibration_en; + if (i >=3D ARRAY_SIZE(enabled_status_text)) + return -EINVAL; + + count =3D sysfs_emit(buf, "%s\n", enabled_status_text[i]); + break; + case TP_VIBRATION_INTENSITY: + i =3D drvdata.tp_vibration_intensity; + if (i >=3D ARRAY_SIZE(intensity_text)) + return -EINVAL; + + count =3D 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 =3D 0; + unsigned int i; + + switch (index) { + case MOTOR_CFG_ALL: + break; + case RUMBLE_MODE: + for (i =3D 1; i < ARRAY_SIZE(rumble_mode_text); i++) { + count +=3D sysfs_emit_at(buf, count, "%s ", + rumble_mode_text[i]); + } + break; + case MOTOR_INTENSITY: + case TP_VIBRATION_INTENSITY: + for (i =3D 1; i < ARRAY_SIZE(intensity_text); i++) { + count +=3D sysfs_emit_at(buf, count, "%s ", + intensity_text[i]); + } + break; + case VIBRATION_NOTIFY_ENABLE: + case TP_VIBRATION_ENABLE: + for (i =3D 1; i < ARRAY_SIZE(enabled_status_text); i++) { + count +=3D sysfs_emit_at(buf, count, "%s ", + enabled_status_text[i]); + } + break; + }; + + if (count) + buf[count - 1] =3D '\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, \ @@ -822,10 +1079,18 @@ static DEVICE_ATTR_RO_NAMED(gamepad_mode_index, "mod= e_index"); struct go_cfg_attr reset_mcu =3D { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_mcu, "reset_mcu", USB_MCU, feature_status); =20 +struct go_cfg_attr gamepad_rumble_intensity =3D { MOTOR_INTENSITY }; +LEGO_DEVICE_ATTR_RW(gamepad_rumble_intensity, "rumble_intensity", UNSPECIF= IED, + index, motor_config); +static DEVICE_ATTR_RO_NAMED(gamepad_rumble_intensity_index, + "rumble_intensity_index"); + static struct attribute *mcu_attrs[] =3D { &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, @@ -896,26 +1161,41 @@ static DEVICE_ATTR_RO_NAMED(auto_sleep_time_left_ran= ge, "auto_sleep_time_range"); =20 struct go_cfg_attr imu_bypass_left =3D { FEATURE_IMU_BYPASS }; -LEGO_DEVICE_ATTR_RW(imu_bypass_left, "imu_bypass_enabled", LEFT_CONTROLLER, +LEGO_DEVICE_ATTR_RW(imu_bypass_left, "imu_bypass_enable", LEFT_CONTROLLER, index, feature_status); -static DEVICE_ATTR_RO_NAMED(imu_bypass_left_index, "imu_bypass_enabled_ind= ex"); +static DEVICE_ATTR_RO_NAMED(imu_bypass_left_index, "imu_bypass_enable_inde= x"); =20 -struct go_cfg_attr imu_enabled_left =3D { FEATURE_IMU_ENABLE }; -LEGO_DEVICE_ATTR_RW(imu_enabled_left, "imu_enabled", LEFT_CONTROLLER, inde= x, +struct go_cfg_attr imu_enable_left =3D { FEATURE_IMU_ENABLE }; +LEGO_DEVICE_ATTR_RW(imu_enable_left, "imu_enable", LEFT_CONTROLLER, index, feature_status); -static DEVICE_ATTR_RO_NAMED(imu_enabled_left_index, "imu_enabled_index"); +static DEVICE_ATTR_RO_NAMED(imu_enable_left_index, "imu_enable_index"); =20 struct go_cfg_attr reset_left =3D { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_left, "reset", LEFT_CONTROLLER, feature_status); =20 +struct go_cfg_attr rumble_mode_left =3D { RUMBLE_MODE }; +LEGO_DEVICE_ATTR_RW(rumble_mode_left, "rumble_mode", LEFT_CONTROLLER, inde= x, + motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_mode_left_index, "rumble_mode_index"); + +struct go_cfg_attr rumble_notification_left =3D { 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[] =3D { &dev_attr_auto_sleep_time_left.attr, &dev_attr_auto_sleep_time_left_range.attr, &dev_attr_imu_bypass_left.attr, &dev_attr_imu_bypass_left_index.attr, - &dev_attr_imu_enabled_left.attr, - &dev_attr_imu_enabled_left_index.attr, + &dev_attr_imu_enable_left.attr, + &dev_attr_imu_enable_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, @@ -952,26 +1232,41 @@ static DEVICE_ATTR_RO_NAMED(auto_sleep_time_right_ra= nge, "auto_sleep_time_range"); =20 struct go_cfg_attr imu_bypass_right =3D { FEATURE_IMU_BYPASS }; -LEGO_DEVICE_ATTR_RW(imu_bypass_right, "imu_bypass_enabled", RIGHT_CONTROLL= ER, +LEGO_DEVICE_ATTR_RW(imu_bypass_right, "imu_bypass_enable", RIGHT_CONTROLLE= R, index, feature_status); -static DEVICE_ATTR_RO_NAMED(imu_bypass_right_index, "imu_bypass_enabled_in= dex"); +static DEVICE_ATTR_RO_NAMED(imu_bypass_right_index, "imu_bypass_enable_ind= ex"); =20 -struct go_cfg_attr imu_enabled_right =3D { FEATURE_IMU_BYPASS }; -LEGO_DEVICE_ATTR_RW(imu_enabled_right, "imu_enabled", RIGHT_CONTROLLER, in= dex, +struct go_cfg_attr imu_enable_right =3D { FEATURE_IMU_BYPASS }; +LEGO_DEVICE_ATTR_RW(imu_enable_right, "imu_enable", RIGHT_CONTROLLER, inde= x, feature_status); -static DEVICE_ATTR_RO_NAMED(imu_enabled_right_index, "imu_enabled_index"); +static DEVICE_ATTR_RO_NAMED(imu_enable_right_index, "imu_enable_index"); =20 struct go_cfg_attr reset_right =3D { FEATURE_RESET_GAMEPAD }; LEGO_DEVICE_ATTR_WO(reset_right, "reset", LEFT_CONTROLLER, feature_status); =20 +struct go_cfg_attr rumble_mode_right =3D { RUMBLE_MODE }; +LEGO_DEVICE_ATTR_RW(rumble_mode_right, "rumble_mode", RIGHT_CONTROLLER, in= dex, + motor_config); +static DEVICE_ATTR_RO_NAMED(rumble_mode_right_index, "rumble_mode_index"); + +struct go_cfg_attr rumble_notification_right =3D { 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[] =3D { &dev_attr_auto_sleep_time_right.attr, &dev_attr_auto_sleep_time_right_range.attr, &dev_attr_imu_bypass_right.attr, &dev_attr_imu_bypass_right_index.attr, - &dev_attr_imu_enabled_right.attr, - &dev_attr_imu_enabled_right_index.attr, + &dev_attr_imu_enable_right.attr, + &dev_attr_imu_enable_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, @@ -991,9 +1286,26 @@ LEGO_DEVICE_ATTR_RW(touchpad_enabled, "enabled", UNSP= ECIFIED, index, feature_status); static DEVICE_ATTR_RO_NAMED(touchpad_enabled_index, "enabled_index"); =20 +struct go_cfg_attr touchpad_vibration_enabled =3D { TP_VIBRATION_ENABLE }; +LEGO_DEVICE_ATTR_RW(touchpad_vibration_enabled, "vibration_enabled", UNSPE= CIFIED, + index, motor_config); +static DEVICE_ATTR_RO_NAMED(touchpad_vibration_enabled_index, + "vibration_enabled_index"); + +struct go_cfg_attr touchpad_vibration_intensity =3D { TP_VIBRATION_INTENSI= TY }; +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[] =3D { &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, }; =20 static const struct attribute_group touchpad_attr_group =3D { --=20 2.51.2