From: Derek J. Clark Date: Sun, 19 Apr 2026 04:26:24 +0000 (-0700) Subject: HID: hid-oxp: Add Vibration Intensity Attribute X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=99bde1dfe878e990655142a2eddd187e84735198;p=thirdparty%2Flinux.git HID: hid-oxp: Add Vibration Intensity Attribute Adds attribute for setting the rumble intensity level. This setting must be re-applied after the gamepad mode is set as doing so resets this to the default value. Reviewed-by: Zhouwang Huang Tested-by: Zhouwang Huang Signed-off-by: Derek J. Clark Signed-off-by: Jiri Kosina --- diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c index 52002d4cbd0b2..20a54f337220d 100644 --- a/drivers/hid/hid-oxp.c +++ b/drivers/hid/hid-oxp.c @@ -34,6 +34,7 @@ enum oxp_function_index { OXP_FID_GEN1_RGB_SET = 0x07, OXP_FID_GEN1_RGB_REPLY = 0x0f, OXP_FID_GEN2_TOGGLE_MODE = 0xb2, + OXP_FID_GEN2_RUMBLE_SET = 0xb3, OXP_FID_GEN2_KEY_STATE = 0xb4, OXP_FID_GEN2_STATUS_EVENT = 0xb8, }; @@ -181,6 +182,7 @@ static struct oxp_hid_cfg { struct mutex cfg_mutex; /*ensure single synchronous output report*/ u8 rgb_brightness; u8 gamepad_mode; + u8 rumble_intensity; u8 rgb_effect; u8 rgb_speed; u8 rgb_en; @@ -266,6 +268,11 @@ static const char *const oxp_rgb_effect_text[] = { [OXP_EFFECT_MONO_LIST] = "monocolor", }; +enum oxp_rumble_side_index { + OXP_RUMBLE_LEFT = 0x00, + OXP_RUMBLE_RIGHT, +}; + struct oxp_gen_1_rgb_report { u8 report_id; u8 message_id; @@ -341,6 +348,7 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev, static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size); static int oxp_set_buttons(void); +static int oxp_rumble_intensity_set(u8 intensity); static void oxp_mcu_init_fn(struct work_struct *work) { @@ -368,6 +376,12 @@ static void oxp_mcu_init_fn(struct work_struct *work) if (ret) dev_err(&drvdata.hdev->dev, "Error: Failed to set gamepad mode: %i\n", ret); + + /* Set vibration level */ + ret = oxp_rumble_intensity_set(drvdata.rumble_intensity); + if (ret) + dev_err(&drvdata.hdev->dev, + "Error: Failed to set rumble intensity: %i\n", ret); } static int oxp_hid_raw_event_gen_2(struct hid_device *hdev, @@ -514,6 +528,14 @@ static ssize_t gamepad_mode_store(struct device *dev, drvdata.gamepad_mode = data[0]; + if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG) + return count; + + /* Re-apply rumble settings as switching gamepad mode will override */ + ret = oxp_rumble_intensity_set(drvdata.rumble_intensity); + if (ret) + return ret; + return count; } @@ -857,6 +879,59 @@ static ssize_t button_mapping_options_show(struct device *dev, } static DEVICE_ATTR_RO(button_mapping_options); +static int oxp_rumble_intensity_set(u8 intensity) +{ + u8 header[15] = { 0x02, 0x38, 0x02, 0xe3, 0x39, 0xe3, 0x39, 0xe3, + 0x39, 0x01, intensity, 0x05, 0xe3, 0x39, 0xe3 }; + u8 footer[9] = { 0x39, 0xe3, 0x39, 0xe3, 0xe3, 0x02, 0x04, 0x39, 0x39 }; + size_t footer_size = ARRAY_SIZE(footer); + size_t header_size = ARRAY_SIZE(header); + u8 data[59] = { 0x0 }; + size_t data_size = ARRAY_SIZE(data); + + memcpy(data, header, header_size); + memcpy(data + data_size - footer_size, footer, footer_size); + + return oxp_gen_2_property_out(OXP_FID_GEN2_RUMBLE_SET, data, data_size); +} + +static ssize_t rumble_intensity_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int ret; + u8 val; + + ret = kstrtou8(buf, 10, &val); + if (ret) + return ret; + + if (val < 0 || val > 5) + return -EINVAL; + + ret = oxp_rumble_intensity_set(val); + if (ret) + return ret; + + drvdata.rumble_intensity = val; + + return count; +} + +static ssize_t rumble_intensity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%i\n", drvdata.rumble_intensity); +} +static DEVICE_ATTR_RW(rumble_intensity); + +static ssize_t rumble_intensity_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "0-5\n"); +} +static DEVICE_ATTR_RO(rumble_intensity_range); + #define OXP_DEVICE_ATTR_RW(_name, _group) \ static ssize_t _name##_store(struct device *dev, \ struct device_attribute *attr, \ @@ -948,6 +1023,8 @@ static struct attribute *oxp_cfg_attrs[] = { &dev_attr_gamepad_mode.attr, &dev_attr_gamepad_mode_index.attr, &dev_attr_reset_buttons.attr, + &dev_attr_rumble_intensity.attr, + &dev_attr_rumble_intensity_range.attr, NULL, }; @@ -1422,6 +1499,7 @@ skip_rgb: INIT_DELAYED_WORK(&drvdata.oxp_btn_queue, oxp_btn_queue_fn); drvdata.gamepad_mode = OXP_GP_MODE_XINPUT; + drvdata.rumble_intensity = 5; INIT_DELAYED_WORK(&drvdata.oxp_mcu_init, oxp_mcu_init_fn); mod_delayed_work(system_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));