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 <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
This commit is contained in:
Derek J. Clark
2026-04-18 21:26:24 -07:00
committed by Jiri Kosina
parent e4c850a6e7
commit 99bde1dfe8

View File

@@ -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 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
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));