mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
HID: hid-oxp: Add Second Generation Gamepad Mode Switch
Adds "gamepad_mode" attribute to second generation OneXPlayer configuration HID devices. This attribute initiates a mode shift in the device MCU that puts it into a state where all events are routed to an hidraw interface instead of the xpad evdev interface. This allows for debugging the hardware input mapping added in the next patch. 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:
parent
252c4bf1d9
commit
2f424f28fb
|
|
@ -33,20 +33,33 @@
|
|||
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_STATUS_EVENT = 0xb8,
|
||||
};
|
||||
|
||||
static struct oxp_hid_cfg {
|
||||
struct delayed_work oxp_rgb_queue;
|
||||
struct delayed_work oxp_mcu_init;
|
||||
struct led_classdev_mc *led_mc;
|
||||
struct hid_device *hdev;
|
||||
struct mutex cfg_mutex; /*ensure single synchronous output report*/
|
||||
u8 rgb_brightness;
|
||||
u8 gamepad_mode;
|
||||
u8 rgb_effect;
|
||||
u8 rgb_speed;
|
||||
u8 rgb_en;
|
||||
} drvdata;
|
||||
|
||||
enum oxp_gamepad_mode_index {
|
||||
OXP_GP_MODE_XINPUT = 0x00,
|
||||
OXP_GP_MODE_DEBUG = 0x03,
|
||||
};
|
||||
|
||||
static const char *const oxp_gamepad_mode_text[] = {
|
||||
[OXP_GP_MODE_XINPUT] = "xinput",
|
||||
[OXP_GP_MODE_DEBUG] = "debug",
|
||||
};
|
||||
|
||||
enum oxp_feature_en_index {
|
||||
OXP_FEAT_DISABLED,
|
||||
OXP_FEAT_ENABLED,
|
||||
|
|
@ -182,6 +195,30 @@ static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size);
|
||||
|
||||
static void oxp_mcu_init_fn(struct work_struct *work)
|
||||
{
|
||||
u8 gp_mode_data[3] = { OXP_GP_MODE_DEBUG, 0x01, 0x02 };
|
||||
int ret;
|
||||
|
||||
/* Cycle the gamepad mode */
|
||||
ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
|
||||
if (ret)
|
||||
dev_err(&drvdata.hdev->dev,
|
||||
"Error: Failed to set gamepad mode: %i\n", ret);
|
||||
|
||||
/* Remainder only applies for xinput mode */
|
||||
if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG)
|
||||
return;
|
||||
|
||||
gp_mode_data[0] = OXP_GP_MODE_XINPUT;
|
||||
ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
|
||||
if (ret)
|
||||
dev_err(&drvdata.hdev->dev,
|
||||
"Error: Failed to set gamepad mode: %i\n", ret);
|
||||
}
|
||||
|
||||
static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
|
||||
struct hid_report *report, u8 *data,
|
||||
int size)
|
||||
|
|
@ -192,6 +229,14 @@ static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
|
|||
if (data[0] != OXP_FID_GEN2_STATUS_EVENT)
|
||||
return 0;
|
||||
|
||||
/* Sent ~6s after resume event, indicating the MCU has fully reset.
|
||||
* Re-apply our settings after this has been received.
|
||||
*/
|
||||
if (data[3] == OXP_EFFECT_MONO_TRUE) {
|
||||
mod_delayed_work(system_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[3] != OXP_GET_PROPERTY)
|
||||
return 0;
|
||||
|
||||
|
|
@ -289,6 +334,77 @@ static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data,
|
|||
footer_size);
|
||||
}
|
||||
|
||||
static ssize_t gamepad_mode_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
u16 up = get_usage_page(drvdata.hdev);
|
||||
u8 data[3] = { 0x00, 0x01, 0x02 };
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
if (up != GEN2_USAGE_PAGE)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
|
||||
if (oxp_gamepad_mode_text[i] && sysfs_streq(buf, oxp_gamepad_mode_text[i])) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data[0] = ret;
|
||||
|
||||
ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, data, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drvdata.gamepad_mode = data[0];
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t gamepad_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%s\n", oxp_gamepad_mode_text[drvdata.gamepad_mode]);
|
||||
}
|
||||
static DEVICE_ATTR_RW(gamepad_mode);
|
||||
|
||||
static ssize_t gamepad_mode_index_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
|
||||
if (!oxp_gamepad_mode_text[i] ||
|
||||
oxp_gamepad_mode_text[i][0] == '\0')
|
||||
continue;
|
||||
|
||||
count += sysfs_emit_at(buf, count, "%s ", oxp_gamepad_mode_text[i]);
|
||||
}
|
||||
|
||||
if (count)
|
||||
buf[count - 1] = '\n';
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RO(gamepad_mode_index);
|
||||
|
||||
static struct attribute *oxp_cfg_attrs[] = {
|
||||
&dev_attr_gamepad_mode.attr,
|
||||
&dev_attr_gamepad_mode_index.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group oxp_cfg_attrs_group = {
|
||||
.attrs = oxp_cfg_attrs,
|
||||
};
|
||||
|
||||
static int oxp_rgb_status_store(u8 enabled, u8 speed, u8 brightness)
|
||||
{
|
||||
u16 up = get_usage_page(drvdata.hdev);
|
||||
|
|
@ -733,7 +849,21 @@ static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
|
|||
dev_warn(drvdata.led_mc->led_cdev.dev,
|
||||
"Failed to query RGB initial state: %i\n", ret);
|
||||
|
||||
/* Below features are only implemented in gen 2 */
|
||||
if (up != GEN2_USAGE_PAGE)
|
||||
return 0;
|
||||
|
||||
skip_rgb:
|
||||
drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
|
||||
|
||||
INIT_DELAYED_WORK(&drvdata.oxp_mcu_init, oxp_mcu_init_fn);
|
||||
mod_delayed_work(system_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
|
||||
|
||||
ret = devm_device_add_group(&hdev->dev, &oxp_cfg_attrs_group);
|
||||
if (ret)
|
||||
return dev_err_probe(&hdev->dev, ret,
|
||||
"Failed to attach configuration attributes\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -778,6 +908,7 @@ static int oxp_hid_probe(struct hid_device *hdev,
|
|||
static void oxp_hid_remove(struct hid_device *hdev)
|
||||
{
|
||||
cancel_delayed_work(&drvdata.oxp_rgb_queue);
|
||||
cancel_delayed_work(&drvdata.oxp_mcu_init);
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user