Commit d0c22de9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull input fixes from Dmitry Torokhov:

 - even more Xbox controllers added to xpad driver: Turtle Beach Recon
   Wired Controller, Turtle Beach Stealth Ultra, and PowerA Wired
   Controller

 - a fix to Synaptics RMI driver to not crash if controller reports
   unsupported version of F34 (firmware flash) function

* tag 'input-for-v6.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: synaptics-rmi - fix crash with unsupported versions of F34
  Input: xpad - add more controllers
parents 95a9580d ca39500f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -290,6 +290,8 @@ static const struct xpad_device {
	{ 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
	{ 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
	{ 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE },
	{ 0x10f5, 0x7008, "Turtle Beach Recon Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
	{ 0x10f5, 0x7073, "Turtle Beach Stealth Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
	{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
	{ 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 },
	{ 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 },
@@ -354,6 +356,7 @@ static const struct xpad_device {
	{ 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 },
	{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
	{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
	{ 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
	{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
	{ 0x20d6, 0x400b, "PowerA FUSION Pro 4 Wired Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
	{ 0x20d6, 0x890b, "PowerA MOGA XP-Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+76 −59
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 * Copyright (C) 2016 Zodiac Inflight Innovations
 */

#include "linux/device.h"
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/firmware.h>
@@ -289,27 +290,21 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
	return rmi_f34_flash_firmware(f34, syn_fw);
}

static int rmi_f34_status(struct rmi_function *fn)
{
	struct f34_data *f34 = dev_get_drvdata(&fn->dev);

	/*
	 * The status is the percentage complete, or once complete,
	 * zero for success or a negative return code.
	 */
	return f34->update_status;
}

static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
					     struct device_attribute *dattr,
					     char *buf)
{
	struct rmi_driver_data *data = dev_get_drvdata(dev);
	struct rmi_function *fn = data->f34_container;
	struct rmi_function *fn;
	struct f34_data *f34;

	if (fn) {
	fn = data->f34_container;
	if (!fn)
		return -ENODEV;

	f34 = dev_get_drvdata(&fn->dev);
	if (!f34)
		return -ENODEV;

	if (f34->bl_version == 5)
		return sysfs_emit(buf, "%c%c\n",
@@ -321,9 +316,6 @@ static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
				  f34->bootloader_id[0]);
}

	return 0;
}

static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL);

static ssize_t rmi_driver_configuration_id_show(struct device *dev,
@@ -334,13 +326,16 @@ static ssize_t rmi_driver_configuration_id_show(struct device *dev,
	struct rmi_function *fn = data->f34_container;
	struct f34_data *f34;

	if (fn) {
	fn = data->f34_container;
	if (!fn)
		return -ENODEV;

	f34 = dev_get_drvdata(&fn->dev);
	if (!f34)
		return -ENODEV;

		return sysfs_emit(buf, "%s\n", f34->configuration_id);
	}

	return 0;
	return sysfs_emit(buf, "%s\n", f34->configuration_id);
}

static DEVICE_ATTR(configuration_id, 0444,
@@ -356,10 +351,14 @@ static int rmi_firmware_update(struct rmi_driver_data *data,

	if (!data->f34_container) {
		dev_warn(dev, "%s: No F34 present!\n", __func__);
		return -EINVAL;
		return -ENODEV;
	}

	f34 = dev_get_drvdata(&data->f34_container->dev);
	if (!f34) {
		dev_warn(dev, "%s: No valid F34 present!\n", __func__);
		return -ENODEV;
	}

	if (f34->bl_version >= 7) {
		if (data->pdt_props & HAS_BSR) {
@@ -485,10 +484,18 @@ static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
						char *buf)
{
	struct rmi_driver_data *data = dev_get_drvdata(dev);
	int update_status = 0;
	struct f34_data *f34;
	int update_status = -ENODEV;

	if (data->f34_container)
		update_status = rmi_f34_status(data->f34_container);
	/*
	 * The status is the percentage complete, or once complete,
	 * zero for success or a negative return code.
	 */
	if (data->f34_container) {
		f34 = dev_get_drvdata(&data->f34_container->dev);
		if (f34)
			update_status = f34->update_status;
	}

	return sysfs_emit(buf, "%d\n", update_status);
}
@@ -508,33 +515,21 @@ static const struct attribute_group rmi_firmware_attr_group = {
	.attrs = rmi_firmware_attrs,
};

static int rmi_f34_probe(struct rmi_function *fn)
static int rmi_f34v5_probe(struct f34_data *f34)
{
	struct f34_data *f34;
	unsigned char f34_queries[9];
	struct rmi_function *fn = f34->fn;
	u8 f34_queries[9];
	bool has_config_id;
	u8 version = fn->fd.function_version;
	int ret;

	f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
	if (!f34)
		return -ENOMEM;

	f34->fn = fn;
	dev_set_drvdata(&fn->dev, f34);

	/* v5 code only supported version 0, try V7 probe */
	if (version > 0)
		return rmi_f34v7_probe(f34);
	int error;

	f34->bl_version = 5;

	ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
	error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
			       f34_queries, sizeof(f34_queries));
	if (ret) {
	if (error) {
		dev_err(&fn->dev, "%s: Failed to query properties\n",
			__func__);
		return ret;
		return error;
	}

	snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
@@ -560,11 +555,11 @@ static int rmi_f34_probe(struct rmi_function *fn)
		f34->v5.config_blocks);

	if (has_config_id) {
		ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
		error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
				       f34_queries, sizeof(f34_queries));
		if (ret) {
		if (error) {
			dev_err(&fn->dev, "Failed to read F34 config ID\n");
			return ret;
			return error;
		}

		snprintf(f34->configuration_id, sizeof(f34->configuration_id),
@@ -579,6 +574,28 @@ static int rmi_f34_probe(struct rmi_function *fn)
	return 0;
}

static int rmi_f34_probe(struct rmi_function *fn)
{
	struct f34_data *f34;
	u8 version = fn->fd.function_version;
	int error;

	f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
	if (!f34)
		return -ENOMEM;

	f34->fn = fn;

	/* v5 code only supported version 0 */
	error = version == 0 ? rmi_f34v5_probe(f34) : rmi_f34v7_probe(f34);
	if (error)
		return error;

	dev_set_drvdata(&fn->dev, f34);

	return 0;
}

int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
{
	return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);