Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v2 2/3] mfd: tps6594: add power button functionality
From: Michael Walle @ 2025-08-26 13:46 UTC (permalink / raw)
  To: Dmitry Torokhov, Lee Jones
  Cc: jcormier, Job Sava, linux-kernel, linux-input, Michael Walle
In-Reply-To: <20250826134631.1499936-1-mwalle@kernel.org>

The PMIC has a multi-function pin PB/EN/VSENSE. If it is configured as
push-button (PB), add the corresponding device for it.

Co-developed-by: Job Sava <jsava@criticallink.com>
Signed-off-by: Job Sava <jsava@criticallink.com>
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
v2:
 - new patch, these bits were previously part of another patch
 - don't use "ti,power-button" to decide whether to add the power-button
   device, but read the configuration register of the pin, whose default
   value is stored in the OTP memory of the chip
---
 drivers/mfd/tps6594-core.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c
index c16c37e36617..9195c9059489 100644
--- a/drivers/mfd/tps6594-core.c
+++ b/drivers/mfd/tps6594-core.c
@@ -20,6 +20,8 @@
 #include <linux/mfd/tps6594.h>
 
 #define TPS6594_CRC_SYNC_TIMEOUT_MS 150
+#define TPS65224_EN_SEL_PB 1
+#define TPS65224_GPIO3_SEL_PB 3
 
 /* Completion to synchronize CRC feature enabling on all PMICs */
 static DECLARE_COMPLETION(tps6594_crc_comp);
@@ -128,6 +130,12 @@ static const struct resource tps6594_rtc_resources[] = {
 	DEFINE_RES_IRQ_NAMED(TPS6594_IRQ_POWER_UP, TPS6594_IRQ_NAME_POWERUP),
 };
 
+static const struct resource tps6594_pwrbutton_resources[] = {
+	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL),
+	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE),
+	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_SHORT, TPS65224_IRQ_NAME_PB_SHORT),
+};
+
 static const struct mfd_cell tps6594_common_cells[] = {
 	MFD_CELL_RES("tps6594-regulator", tps6594_regulator_resources),
 	MFD_CELL_RES("tps6594-pinctrl", tps6594_pinctrl_resources),
@@ -318,8 +326,6 @@ static const struct resource tps65224_pfsm_resources[] = {
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_UNLOCK, TPS65224_IRQ_NAME_REG_UNLOCK),
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TWARN, TPS65224_IRQ_NAME_TWARN),
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_LONG, TPS65224_IRQ_NAME_PB_LONG),
-	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL),
-	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE),
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_ORD, TPS65224_IRQ_NAME_TSD_ORD),
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_FAIL, TPS65224_IRQ_NAME_BIST_FAIL),
 	DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_CRC_ERR, TPS65224_IRQ_NAME_REG_CRC_ERR),
@@ -347,6 +353,12 @@ static const struct mfd_cell tps65224_common_cells[] = {
 	MFD_CELL_RES("tps6594-regulator", tps65224_regulator_resources),
 };
 
+static const struct mfd_cell tps6594_pwrbutton_cell = {
+	.name = "tps6594-pwrbutton",
+	.resources = tps6594_pwrbutton_resources,
+	.num_resources = ARRAY_SIZE(tps6594_pwrbutton_resources),
+};
+
 static const struct regmap_irq tps65224_irqs[] = {
 	/* INT_BUCK register */
 	REGMAP_IRQ_REG(TPS65224_IRQ_BUCK1_UVOV, 0, TPS65224_BIT_BUCK1_UVOV_INT),
@@ -681,6 +693,7 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc)
 	struct device *dev = tps->dev;
 	int ret;
 	struct regmap_irq_chip *irq_chip;
+	unsigned int pwr_on, gpio3_cfg;
 	const struct mfd_cell *cells;
 	int n_cells;
 
@@ -727,6 +740,27 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc)
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to add common child devices\n");
 
+	/* If either the PB/EN/VSENSE or GPIO3 is configured as PB, register a driver for it */
+	if (tps->chip_id == TPS65224 || tps->chip_id == TPS652G1) {
+		ret = regmap_read(tps->regmap, TPS6594_REG_NPWRON_CONF, &pwr_on);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to read PB/EN/VSENSE config\n");
+
+		ret = regmap_read(tps->regmap, TPS6594_REG_GPIOX_CONF(2), &gpio3_cfg);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to read GPIO3 config\n");
+
+		if (FIELD_GET(TPS65224_MASK_EN_PB_VSENSE_CONFIG, pwr_on) == TPS65224_EN_SEL_PB ||
+		    FIELD_GET(TPS65224_MASK_GPIO_SEL, gpio3_cfg) == TPS65224_GPIO3_SEL_PB) {
+			ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+						   &tps6594_pwrbutton_cell, 1, NULL, 0,
+						   regmap_irq_get_domain(tps->irq_data));
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "Failed to add power button device.\n");
+		}
+	}
+
 	/* No RTC for LP8764, TPS65224 and TPS652G1 */
 	if (tps->chip_id != LP8764 && tps->chip_id != TPS65224 && tps->chip_id != TPS652G1) {
 		ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_rtc_cells,
-- 
2.39.5


^ permalink raw reply related

* [PATCH v2 1/3] input: tps6594-pwrbutton: Add power button functionality
From: Michael Walle @ 2025-08-26 13:46 UTC (permalink / raw)
  To: Dmitry Torokhov, Lee Jones
  Cc: jcormier, Job Sava, linux-kernel, linux-input, Michael Walle
In-Reply-To: <20250826134631.1499936-1-mwalle@kernel.org>

From: Job Sava <jsava@criticallink.com>

TPS6594 defines two interrupts for the power button one for push and
one for release.

This driver is very simple in that it maps the push interrupt to a key
input and the release interrupt to a key release.

Signed-off-by: Job Sava <jsava@criticallink.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
v2:
 - moved the mfd part into a seperate patch
---
 drivers/input/misc/Kconfig             |  10 ++
 drivers/input/misc/Makefile            |   1 +
 drivers/input/misc/tps6594-pwrbutton.c | 126 +++++++++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 drivers/input/misc/tps6594-pwrbutton.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0fb21c99a5e3..cce51358242f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -506,6 +506,16 @@ config INPUT_TPS65219_PWRBUTTON
 	  To compile this driver as a module, choose M here. The module will
 	  be called tps65219-pwrbutton.
 
+config INPUT_TPS6594_PWRBUTTON
+	tristate "TPS6594 Power button driver"
+	depends on MFD_TPS6594
+	help
+	  Say Y here if you want to enable power button reporting for
+	  TPS6594 Power Management IC devices.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called tps6594-pwrbutton.
+
 config INPUT_AXP20X_PEK
 	tristate "X-Powers AXP20X power button driver"
 	depends on MFD_AXP20X
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d468c8140b93..bb12f883851c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
 obj-$(CONFIG_INPUT_STPMIC1_ONKEY)  	+= stpmic1_onkey.o
 obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON)	+= tps65218-pwrbutton.o
 obj-$(CONFIG_INPUT_TPS65219_PWRBUTTON)	+= tps65219-pwrbutton.o
+obj-$(CONFIG_INPUT_TPS6594_PWRBUTTON)	+= tps6594-pwrbutton.o
 obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
 obj-$(CONFIG_INPUT_TWL4030_VIBRA)	+= twl4030-vibra.o
 obj-$(CONFIG_INPUT_TWL6040_VIBRA)	+= twl6040-vibra.o
diff --git a/drivers/input/misc/tps6594-pwrbutton.c b/drivers/input/misc/tps6594-pwrbutton.c
new file mode 100644
index 000000000000..cd039b3866dc
--- /dev/null
+++ b/drivers/input/misc/tps6594-pwrbutton.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * power button driver for TI TPS6594 PMICs
+ *
+ * Copyright (C) 2025 Critical Link LLC - https://www.criticallink.com/
+ */
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps6594.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct tps6594_pwrbutton {
+	struct device *dev;
+	struct input_dev *idev;
+	char phys[32];
+};
+
+static irqreturn_t tps6594_pb_push_irq(int irq, void *_pwr)
+{
+	struct tps6594_pwrbutton *pwr = _pwr;
+
+	input_report_key(pwr->idev, KEY_POWER, 1);
+	pm_wakeup_event(pwr->dev, 0);
+	input_sync(pwr->idev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tps6594_pb_release_irq(int irq, void *_pwr)
+{
+	struct tps6594_pwrbutton *pwr = _pwr;
+
+	input_report_key(pwr->idev, KEY_POWER, 0);
+	input_sync(pwr->idev);
+
+	return IRQ_HANDLED;
+}
+
+static int tps6594_pb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tps6594_pwrbutton *pwr;
+	struct input_dev *idev;
+	int error;
+	int push_irq;
+	int release_irq;
+
+	pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
+	if (!pwr)
+		return -ENOMEM;
+
+	idev = devm_input_allocate_device(dev);
+	if (!idev)
+		return -ENOMEM;
+
+	idev->name = pdev->name;
+	snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
+		 pdev->name);
+	idev->phys = pwr->phys;
+	idev->id.bustype = BUS_I2C;
+
+	input_set_capability(idev, EV_KEY, KEY_POWER);
+
+	pwr->dev = dev;
+	pwr->idev = idev;
+	device_init_wakeup(dev, true);
+
+	push_irq = platform_get_irq(pdev, 0);
+	if (push_irq < 0)
+		return -EINVAL;
+
+	release_irq = platform_get_irq(pdev, 1);
+	if (release_irq < 0)
+		return -EINVAL;
+
+	error = devm_request_threaded_irq(dev, push_irq, NULL,
+					  tps6594_pb_push_irq,
+					  IRQF_ONESHOT,
+					  pdev->resource[0].name, pwr);
+	if (error) {
+		dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq,
+			error);
+		return error;
+	}
+
+	error = devm_request_threaded_irq(dev, release_irq, NULL,
+					  tps6594_pb_release_irq,
+					  IRQF_ONESHOT,
+					  pdev->resource[1].name, pwr);
+	if (error) {
+		dev_err(dev, "failed to request release IRQ #%d: %d\n",
+			release_irq, error);
+		return error;
+	}
+
+	error = input_register_device(idev);
+	if (error) {
+		dev_err(dev, "Can't register power button: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id tps6594_pwrbtn_id_table[] = {
+	{ "tps6594-pwrbutton", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps6594_pwrbtn_id_table);
+
+static struct platform_driver tps6594_pb_driver = {
+	.probe = tps6594_pb_probe,
+	.driver = {
+		.name = "tps6594_pwrbutton",
+	},
+	.id_table = tps6594_pwrbtn_id_table,
+};
+module_platform_driver(tps6594_pb_driver);
+
+MODULE_DESCRIPTION("TPS6594 Power Button");
+MODULE_LICENSE("GPL");
-- 
2.39.5


^ permalink raw reply related

* [PATCH v2 0/3] mfd: tps6594: add power button and power-off
From: Michael Walle @ 2025-08-26 13:46 UTC (permalink / raw)
  To: Dmitry Torokhov, Lee Jones
  Cc: jcormier, Job Sava, linux-kernel, linux-input, Michael Walle

I took over the series from [1] since the original developer was an
intern and is no longer with their former company.

Changelog is in the individual patches. But the most prominent
change is that the pin mux config is now read from the chip itself
instead of having a DT property.

[1] https://lore.kernel.org/all/20250520-linux-stable-tps6594-pwrbutton-v1-0-0cc5c6e0415c@criticallink.com/

Job Sava (1):
  input: tps6594-pwrbutton: Add power button functionality

Michael Walle (2):
  mfd: tps6594: add power button functionality
  mfd: tps6594: Add board power-off support

 drivers/input/misc/Kconfig             |  10 ++
 drivers/input/misc/Makefile            |   1 +
 drivers/input/misc/tps6594-pwrbutton.c | 126 +++++++++++++++++++++++++
 drivers/mfd/tps6594-core.c             |  58 +++++++++++-
 4 files changed, 193 insertions(+), 2 deletions(-)
 create mode 100644 drivers/input/misc/tps6594-pwrbutton.c

-- 
2.39.5


^ permalink raw reply

* Re: [PATCH 1/2] hid: intel-thc-hid: intel-quicki2c: Add WCL Device IDs
From: srinivas pandruvada @ 2025-08-26 13:35 UTC (permalink / raw)
  To: Xinpeng Sun, jikos, bentiss; +Cc: linux-input, linux-kernel
In-Reply-To: <20250826072701.991046-1-xinpeng.sun@intel.com>

On Tue, 2025-08-26 at 15:27 +0800, Xinpeng Sun wrote:

Not even a single line of description?

Thanks,
Srinivas

> Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com>
> ---
>  drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c | 2 ++
>  drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h | 2 ++
>  2 files changed, 4 insertions(+)
> 
> diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
> b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
> index f122fde879b9..17b1f2df8f8a 100644
> --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
> +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
> @@ -1019,6 +1019,8 @@ static const struct pci_device_id
> quicki2c_pci_tbl[] = {
>  	{ PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2,
> &ptl_ddata) },
>  	{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1,
> &ptl_ddata) },
>  	{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2,
> &ptl_ddata) },
> +	{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT1,
> &ptl_ddata) },
> +	{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT2,
> &ptl_ddata) },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
> diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> index b78c8864d39e..240492a38c24 100644
> --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
> @@ -13,6 +13,8 @@
>  #define
> PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT2	0xE34A
>  #define
> PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT1	0xE448
>  #define
> PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT2	0xE44A
> +#define
> PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT1 	0x4D48
> +#define
> PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT2 	0x4D4A
>  
>  /* Packet size value, the unit is 16 bytes */
>  #define MAX_PACKET_SIZE_VALUE_LNL			256


^ permalink raw reply

* [PATCH v2 3/3] HID: tighten ioctl command parsing
From: bentiss @ 2025-08-26 12:39 UTC (permalink / raw)
  To: Jiri Kosina, Shuah Khan, Arnd Bergmann
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires,
	Arnd Bergmann
In-Reply-To: <20250826-b4-hidraw-ioctls-v2-0-c7726b236719@kernel.org>

From: Arnd Bergmann <arnd@arndb.de>

The handling for variable-length ioctl commands in hidraw_ioctl() is
rather complex and the check for the data direction is incomplete.

Simplify this code by factoring out the various ioctls grouped by dir
and size, and using a switch() statement with the size masked out, to
ensure the rest of the command is correctly matched.

Fixes: 9188e79ec3fd ("HID: add phys and name ioctls to hidraw")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
 drivers/hid/hidraw.c        | 224 ++++++++++++++++++++++++--------------------
 include/uapi/linux/hidraw.h |   2 +
 2 files changed, 124 insertions(+), 102 deletions(-)

diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c887f48756f4be2a4bac03128f2885bde96c1e39..bbd6f23bce78951c7d667ff5c1c923cee3509e3f 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -394,27 +394,15 @@ static int hidraw_revoke(struct hidraw_list *list)
 	return 0;
 }
 
-static long hidraw_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
+static long hidraw_fixed_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd,
+				    void __user *arg)
 {
-	struct inode *inode = file_inode(file);
-	unsigned int minor = iminor(inode);
-	long ret = 0;
-	struct hidraw *dev;
-	struct hidraw_list *list = file->private_data;
-	void __user *user_arg = (void __user*) arg;
-
-	down_read(&minors_rwsem);
-	dev = hidraw_table[minor];
-	if (!dev || !dev->exist || hidraw_is_revoked(list)) {
-		ret = -ENODEV;
-		goto out;
-	}
+	struct hid_device *hid = dev->hid;
 
 	switch (cmd) {
 		case HIDIOCGRDESCSIZE:
-			if (put_user(dev->hid->rsize, (int __user *)arg))
-				ret = -EFAULT;
+			if (put_user(hid->rsize, (int __user *)arg))
+				return -EFAULT;
 			break;
 
 		case HIDIOCGRDESC:
@@ -422,113 +410,145 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
 				__u32 len;
 
 				if (get_user(len, (int __user *)arg))
-					ret = -EFAULT;
-				else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
-					ret = -EINVAL;
-				else if (copy_to_user(user_arg + offsetof(
-					struct hidraw_report_descriptor,
-					value[0]),
-					dev->hid->rdesc,
-					min(dev->hid->rsize, len)))
-					ret = -EFAULT;
+					return -EFAULT;
+
+				if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
+					return -EINVAL;
+
+				if (copy_to_user(arg + offsetof(
+				    struct hidraw_report_descriptor,
+				    value[0]),
+				    hid->rdesc,
+				    min(hid->rsize, len)))
+					return -EFAULT;
+
 				break;
 			}
 		case HIDIOCGRAWINFO:
 			{
 				struct hidraw_devinfo dinfo;
 
-				dinfo.bustype = dev->hid->bus;
-				dinfo.vendor = dev->hid->vendor;
-				dinfo.product = dev->hid->product;
-				if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
-					ret = -EFAULT;
+				dinfo.bustype = hid->bus;
+				dinfo.vendor = hid->vendor;
+				dinfo.product = hid->product;
+				if (copy_to_user(arg, &dinfo, sizeof(dinfo)))
+					return -EFAULT;
 				break;
 			}
 		case HIDIOCREVOKE:
 			{
-				if (user_arg)
-					ret = -EINVAL;
-				else
-					ret = hidraw_revoke(list);
-				break;
+				struct hidraw_list *list = file->private_data;
+
+				if (arg)
+					return -EINVAL;
+
+				return hidraw_revoke(list);
 			}
 		default:
-			{
-				struct hid_device *hid = dev->hid;
-				if (_IOC_TYPE(cmd) != 'H') {
-					ret = -EINVAL;
-					break;
-				}
+			/*
+			 * None of the above ioctls can return -EAGAIN, so
+			 * use it as a marker that we need to check variable
+			 * length ioctls.
+			 */
+			return -EAGAIN;
+	}
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
-					break;
-				}
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
-					break;
-				}
+	return 0;
+}
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT);
-					break;
-				}
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT);
-					break;
-				}
+static long hidraw_rw_variable_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd,
+					  void __user *user_arg)
+{
+	int len = _IOC_SIZE(cmd);
+
+	switch (cmd & ~IOCSIZE_MASK) {
+	case HIDIOCSFEATURE(0):
+		return hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
+	case HIDIOCGFEATURE(0):
+		return hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
+	case HIDIOCSINPUT(0):
+		return hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT);
+	case HIDIOCGINPUT(0):
+		return hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT);
+	case HIDIOCSOUTPUT(0):
+		return hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT);
+	case HIDIOCGOUTPUT(0):
+		return hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT);
+	}
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT);
-					break;
-				}
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) {
-					int len = _IOC_SIZE(cmd);
-					ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT);
-					break;
-				}
+	return -EINVAL;
+}
 
-				/* Begin Read-only ioctls. */
-				if (_IOC_DIR(cmd) != _IOC_READ) {
-					ret = -EINVAL;
-					break;
-				}
+static long hidraw_ro_variable_size_ioctl(struct file *file, struct hidraw *dev, unsigned int cmd,
+					  void __user *user_arg)
+{
+	struct hid_device *hid = dev->hid;
+	int len = _IOC_SIZE(cmd);
+	int field_len;
+
+	switch (cmd & ~IOCSIZE_MASK) {
+	case HIDIOCGRAWNAME(0):
+		field_len = strlen(hid->name) + 1;
+		if (len > field_len)
+			len = field_len;
+		return copy_to_user(user_arg, hid->name, len) ?  -EFAULT : len;
+	case HIDIOCGRAWPHYS(0):
+		field_len = strlen(hid->phys) + 1;
+		if (len > field_len)
+			len = field_len;
+		return copy_to_user(user_arg, hid->phys, len) ?  -EFAULT : len;
+	case HIDIOCGRAWUNIQ(0):
+		field_len = strlen(hid->uniq) + 1;
+		if (len > field_len)
+			len = field_len;
+		return copy_to_user(user_arg, hid->uniq, len) ?  -EFAULT : len;
+	}
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
-					int len = strlen(hid->name) + 1;
-					if (len > _IOC_SIZE(cmd))
-						len = _IOC_SIZE(cmd);
-					ret = copy_to_user(user_arg, hid->name, len) ?
-						-EFAULT : len;
-					break;
-				}
+	return -EINVAL;
+}
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
-					int len = strlen(hid->phys) + 1;
-					if (len > _IOC_SIZE(cmd))
-						len = _IOC_SIZE(cmd);
-					ret = copy_to_user(user_arg, hid->phys, len) ?
-						-EFAULT : len;
-					break;
-				}
+static long hidraw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct inode *inode = file_inode(file);
+	unsigned int minor = iminor(inode);
+	struct hidraw *dev;
+	struct hidraw_list *list = file->private_data;
+	void __user *user_arg = (void __user *)arg;
+	int ret;
 
-				if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWUNIQ(0))) {
-					int len = strlen(hid->uniq) + 1;
-					if (len > _IOC_SIZE(cmd))
-						len = _IOC_SIZE(cmd);
-					ret = copy_to_user(user_arg, hid->uniq, len) ?
-						-EFAULT : len;
-					break;
-				}
-			}
+	down_read(&minors_rwsem);
+	dev = hidraw_table[minor];
+	if (!dev || !dev->exist || hidraw_is_revoked(list)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (_IOC_TYPE(cmd) != 'H') {
+		ret = -EINVAL;
+		goto out;
+	}
 
+	if (_IOC_NR(cmd) > HIDIOCTL_LAST || _IOC_NR(cmd) == 0) {
 		ret = -ENOTTY;
+		goto out;
 	}
+
+	ret = hidraw_fixed_size_ioctl(file, dev, cmd, user_arg);
+	if (ret != -EAGAIN)
+		goto out;
+
+	switch (_IOC_DIR(cmd)) {
+	case (_IOC_READ | _IOC_WRITE):
+		ret = hidraw_rw_variable_size_ioctl(file, dev, cmd, user_arg);
+		break;
+	case _IOC_READ:
+		ret = hidraw_ro_variable_size_ioctl(file, dev, cmd, user_arg);
+		break;
+	default:
+		/* Any other IOC_DIR is wrong */
+		ret = -EINVAL;
+	}
+
 out:
 	up_read(&minors_rwsem);
 	return ret;
diff --git a/include/uapi/linux/hidraw.h b/include/uapi/linux/hidraw.h
index d5ee269864e07fcaba481fa285bacbd98739e44f..ebd701b3c18d9d7465880199091933f13f2e1128 100644
--- a/include/uapi/linux/hidraw.h
+++ b/include/uapi/linux/hidraw.h
@@ -48,6 +48,8 @@ struct hidraw_devinfo {
 #define HIDIOCGOUTPUT(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0C, len)
 #define HIDIOCREVOKE	      _IOW('H', 0x0D, int) /* Revoke device access */
 
+#define HIDIOCTL_LAST		_IOC_NR(HIDIOCREVOKE)
+
 #define HIDRAW_FIRST_MINOR 0
 #define HIDRAW_MAX_DEVICES 64
 /* number of reports to buffer */

-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 2/3] selftests/hid: hidraw: forge wrong ioctls and tests them
From: Benjamin Tissoires @ 2025-08-26 12:39 UTC (permalink / raw)
  To: Jiri Kosina, Shuah Khan, Arnd Bergmann
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires
In-Reply-To: <20250826-b4-hidraw-ioctls-v2-0-c7726b236719@kernel.org>

We also need coverage for when the malicious user is not using the
proper ioctls definitions and tries to work around the driver.

Suggested-by: Arnd Bergmann <arnd@kernel.org>
Co-developed-by: claude-4-sonnet
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
 tools/testing/selftests/hid/hidraw.c | 127 +++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/tools/testing/selftests/hid/hidraw.c b/tools/testing/selftests/hid/hidraw.c
index 6d61d03e2ef05e1900fe5a3938d93421717b2621..d625772f8b7cf71fd94956d3a49d54ff44e2b34d 100644
--- a/tools/testing/selftests/hid/hidraw.c
+++ b/tools/testing/selftests/hid/hidraw.c
@@ -332,6 +332,133 @@ TEST_F(hidraw, ioctl_gfeature_invalid)
 	ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
 }
 
+/*
+ * Test ioctl with incorrect nr bits
+ */
+TEST_F(hidraw, ioctl_invalid_nr)
+{
+	char buf[256] = {0};
+	int err;
+	unsigned int bad_cmd;
+
+	/*
+	 * craft an ioctl command with wrong _IOC_NR bits
+	 */
+	bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */
+
+	/* test the ioctl */
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0) should have failed");
+	ASSERT_EQ(errno, ENOTTY)
+		TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0), got errno %d", errno);
+
+	/*
+	 * craft an ioctl command with wrong _IOC_NR bits
+	 */
+	bad_cmd = _IOC(_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */
+
+	/* test the ioctl */
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0) should have failed");
+	ASSERT_EQ(errno, ENOTTY)
+		TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0), got errno %d", errno);
+
+	/* also test with bigger number */
+	bad_cmd = _IOC(_IOC_READ, 'H', 0x42, sizeof(buf)); /* 0x42 is not valid as well */
+
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0x42) should have failed");
+	ASSERT_EQ(errno, ENOTTY)
+		TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0x42), got errno %d", errno);
+
+	/* also test with bigger number: 0x42 is not valid as well */
+	bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x42, sizeof(buf));
+
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0x42) should have failed");
+	ASSERT_EQ(errno, ENOTTY)
+		TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0x42), got errno %d", errno);
+}
+
+/*
+ * Test ioctl with incorrect type bits
+ */
+TEST_F(hidraw, ioctl_invalid_type)
+{
+	char buf[256] = {0};
+	int err;
+	unsigned int bad_cmd;
+
+	/*
+	 * craft an ioctl command with wrong _IOC_TYPE bits
+	 */
+	bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'I', 0x01, sizeof(buf)); /* 'I' should be 'H' */
+
+	/* test the ioctl */
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("ioctl with wrong _IOC_TYPE (I) should have failed");
+	ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_NR, got errno %d", errno);
+}
+
+/*
+ * Test HIDIOCGFEATURE ioctl with incorrect _IOC_DIR bits
+ */
+TEST_F(hidraw, ioctl_gfeature_invalid_dir)
+{
+	__u8 buf[10] = {0};
+	int err;
+	unsigned int bad_cmd;
+
+	/* set report ID 1 in first byte */
+	buf[0] = 1;
+
+	/*
+	 * craft an ioctl command with wrong _IOC_DIR bits
+	 * HIDIOCGFEATURE should have _IOC_WRITE|_IOC_READ, let's use only _IOC_WRITE
+	 */
+	bad_cmd = _IOC(_IOC_WRITE, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */
+
+	/* try to get feature report with wrong direction bits */
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed");
+	ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
+
+	/* also test with only _IOC_READ */
+	bad_cmd = _IOC(_IOC_READ, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */
+
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed");
+	ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
+}
+
+/*
+ * Test read-only ioctl with incorrect _IOC_DIR bits
+ */
+TEST_F(hidraw, ioctl_readonly_invalid_dir)
+{
+	char buf[256] = {0};
+	int err;
+	unsigned int bad_cmd;
+
+	/*
+	 * craft an ioctl command with wrong _IOC_DIR bits
+	 * HIDIOCGRAWNAME should have _IOC_READ, let's use _IOC_WRITE
+	 */
+	bad_cmd = _IOC(_IOC_WRITE, 'H', 0x04, sizeof(buf)); /* should be _IOC_READ */
+
+	/* try to get device name with wrong direction bits */
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed");
+	ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
+
+	/* also test with _IOC_WRITE|_IOC_READ */
+	bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x04, sizeof(buf)); /* should be only _IOC_READ */
+
+	err = ioctl(self->hidraw_fd, bad_cmd, buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed");
+	ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
+}
+
 /*
  * Test HIDIOCSFEATURE ioctl to set feature report
  */

-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 1/3] selftests/hid: hidraw: add more coverage for hidraw ioctls
From: Benjamin Tissoires @ 2025-08-26 12:39 UTC (permalink / raw)
  To: Jiri Kosina, Shuah Khan, Arnd Bergmann
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires
In-Reply-To: <20250826-b4-hidraw-ioctls-v2-0-c7726b236719@kernel.org>

Try to ensure all ioctls are having at least one test.

Co-developed-by: claude-4-sonnet
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
 tools/testing/selftests/hid/hid_common.h |   6 +
 tools/testing/selftests/hid/hidraw.c     | 346 +++++++++++++++++++++++++++++++
 2 files changed, 352 insertions(+)

diff --git a/tools/testing/selftests/hid/hid_common.h b/tools/testing/selftests/hid/hid_common.h
index f77f69c6657d0f0f66beb3b50bf4b126f6f63348..8085519c47cb505b901ac80f2087dc9a1aa2b9c0 100644
--- a/tools/testing/selftests/hid/hid_common.h
+++ b/tools/testing/selftests/hid/hid_common.h
@@ -230,6 +230,12 @@ static int uhid_event(struct __test_metadata *_metadata, int fd)
 		break;
 	case UHID_SET_REPORT:
 		UHID_LOG("UHID_SET_REPORT from uhid-dev");
+
+		answer.type = UHID_SET_REPORT_REPLY;
+		answer.u.set_report_reply.id = ev.u.set_report.id;
+		answer.u.set_report_reply.err = 0; /* success */
+
+		uhid_write(_metadata, fd, &answer);
 		break;
 	default:
 		TH_LOG("Invalid event from uhid-dev: %u", ev.type);
diff --git a/tools/testing/selftests/hid/hidraw.c b/tools/testing/selftests/hid/hidraw.c
index 821db37ba4bbef82e5cf4b44b6675666f87a12ad..6d61d03e2ef05e1900fe5a3938d93421717b2621 100644
--- a/tools/testing/selftests/hid/hidraw.c
+++ b/tools/testing/selftests/hid/hidraw.c
@@ -2,6 +2,9 @@
 /* Copyright (c) 2022-2024 Red Hat */
 
 #include "hid_common.h"
+#include <linux/input.h>
+#include <string.h>
+#include <sys/ioctl.h>
 
 /* for older kernels */
 #ifndef HIDIOCREVOKE
@@ -215,6 +218,349 @@ TEST_F(hidraw, write_event_revoked)
 	pthread_mutex_unlock(&uhid_output_mtx);
 }
 
+/*
+ * Test HIDIOCGRDESCSIZE ioctl to get report descriptor size
+ */
+TEST_F(hidraw, ioctl_rdescsize)
+{
+	int desc_size = 0;
+	int err;
+
+	/* call HIDIOCGRDESCSIZE ioctl */
+	err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
+	ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESCSIZE ioctl failed");
+
+	/* verify the size matches our test report descriptor */
+	ASSERT_EQ(desc_size, sizeof(rdesc))
+		TH_LOG("expected size %zu, got %d", sizeof(rdesc), desc_size);
+}
+
+/*
+ * Test HIDIOCGRDESC ioctl to get report descriptor data
+ */
+TEST_F(hidraw, ioctl_rdesc)
+{
+	struct hidraw_report_descriptor desc;
+	int err;
+
+	/* get the full report descriptor */
+	desc.size = sizeof(rdesc);
+	err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc);
+	ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed");
+
+	/* verify the descriptor data matches our test descriptor */
+	ASSERT_EQ(memcmp(desc.value, rdesc, sizeof(rdesc)), 0)
+		TH_LOG("report descriptor data mismatch");
+}
+
+/*
+ * Test HIDIOCGRDESC ioctl with smaller buffer size
+ */
+TEST_F(hidraw, ioctl_rdesc_small_buffer)
+{
+	struct hidraw_report_descriptor desc;
+	int err;
+	size_t small_size = sizeof(rdesc) / 2; /* request half the descriptor size */
+
+	/* get partial report descriptor */
+	desc.size = small_size;
+	err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc);
+	ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed with small buffer");
+
+	/* verify we got the first part of the descriptor */
+	ASSERT_EQ(memcmp(desc.value, rdesc, small_size), 0)
+		TH_LOG("partial report descriptor data mismatch");
+}
+
+/*
+ * Test HIDIOCGRAWINFO ioctl to get device information
+ */
+TEST_F(hidraw, ioctl_rawinfo)
+{
+	struct hidraw_devinfo devinfo;
+	int err;
+
+	/* get device info */
+	err = ioctl(self->hidraw_fd, HIDIOCGRAWINFO, &devinfo);
+	ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRAWINFO ioctl failed");
+
+	/* verify device info matches our test setup */
+	ASSERT_EQ(devinfo.bustype, BUS_USB)
+		TH_LOG("expected bustype 0x03, got 0x%x", devinfo.bustype);
+	ASSERT_EQ(devinfo.vendor, 0x0001)
+		TH_LOG("expected vendor 0x0001, got 0x%x", devinfo.vendor);
+	ASSERT_EQ(devinfo.product, 0x0a37)
+		TH_LOG("expected product 0x0a37, got 0x%x", devinfo.product);
+}
+
+/*
+ * Test HIDIOCGFEATURE ioctl to get feature report
+ */
+TEST_F(hidraw, ioctl_gfeature)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set report ID 1 in first byte */
+	buf[0] = 1;
+
+	/* get feature report */
+	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+	ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGFEATURE ioctl failed, got %d", err);
+
+	/* verify we got the expected feature data */
+	ASSERT_EQ(buf[0], feature_data[0])
+		TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
+	ASSERT_EQ(buf[1], feature_data[1])
+		TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
+}
+
+/*
+ * Test HIDIOCGFEATURE ioctl with invalid report ID
+ */
+TEST_F(hidraw, ioctl_gfeature_invalid)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set invalid report ID (not 1) */
+	buf[0] = 2;
+
+	/* try to get feature report */
+	err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE should have failed with invalid report ID");
+	ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
+}
+
+/*
+ * Test HIDIOCSFEATURE ioctl to set feature report
+ */
+TEST_F(hidraw, ioctl_sfeature)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* prepare feature report data */
+	buf[0] = 1; /* report ID */
+	buf[1] = 0x42;
+	buf[2] = 0x24;
+
+	/* set feature report */
+	err = ioctl(self->hidraw_fd, HIDIOCSFEATURE(3), buf);
+	ASSERT_EQ(err, 3) TH_LOG("HIDIOCSFEATURE ioctl failed, got %d", err);
+
+	/*
+	 * Note: The uhid mock doesn't validate the set report data,
+	 * so we just verify the ioctl succeeds
+	 */
+}
+
+/*
+ * Test HIDIOCGINPUT ioctl to get input report
+ */
+TEST_F(hidraw, ioctl_ginput)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set report ID 1 in first byte */
+	buf[0] = 1;
+
+	/* get input report */
+	err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf);
+	ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGINPUT ioctl failed, got %d", err);
+
+	/* verify we got the expected input data */
+	ASSERT_EQ(buf[0], feature_data[0])
+		TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
+	ASSERT_EQ(buf[1], feature_data[1])
+		TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
+}
+
+/*
+ * Test HIDIOCGINPUT ioctl with invalid report ID
+ */
+TEST_F(hidraw, ioctl_ginput_invalid)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set invalid report ID (not 1) */
+	buf[0] = 2;
+
+	/* try to get input report */
+	err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGINPUT should have failed with invalid report ID");
+	ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
+}
+
+/*
+ * Test HIDIOCSINPUT ioctl to set input report
+ */
+TEST_F(hidraw, ioctl_sinput)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* prepare input report data */
+	buf[0] = 1; /* report ID */
+	buf[1] = 0x55;
+	buf[2] = 0xAA;
+
+	/* set input report */
+	err = ioctl(self->hidraw_fd, HIDIOCSINPUT(3), buf);
+	ASSERT_EQ(err, 3) TH_LOG("HIDIOCSINPUT ioctl failed, got %d", err);
+
+	/*
+	 * Note: The uhid mock doesn't validate the set report data,
+	 * so we just verify the ioctl succeeds
+	 */
+}
+
+/*
+ * Test HIDIOCGOUTPUT ioctl to get output report
+ */
+TEST_F(hidraw, ioctl_goutput)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set report ID 1 in first byte */
+	buf[0] = 1;
+
+	/* get output report */
+	err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf);
+	ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGOUTPUT ioctl failed, got %d", err);
+
+	/* verify we got the expected output data */
+	ASSERT_EQ(buf[0], feature_data[0])
+		TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
+	ASSERT_EQ(buf[1], feature_data[1])
+		TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
+}
+
+/*
+ * Test HIDIOCGOUTPUT ioctl with invalid report ID
+ */
+TEST_F(hidraw, ioctl_goutput_invalid)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* set invalid report ID (not 1) */
+	buf[0] = 2;
+
+	/* try to get output report */
+	err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf);
+	ASSERT_LT(err, 0) TH_LOG("HIDIOCGOUTPUT should have failed with invalid report ID");
+	ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
+}
+
+/*
+ * Test HIDIOCSOUTPUT ioctl to set output report
+ */
+TEST_F(hidraw, ioctl_soutput)
+{
+	__u8 buf[10] = {0};
+	int err;
+
+	/* prepare output report data */
+	buf[0] = 1; /* report ID */
+	buf[1] = 0x33;
+	buf[2] = 0xCC;
+
+	/* set output report */
+	err = ioctl(self->hidraw_fd, HIDIOCSOUTPUT(3), buf);
+	ASSERT_EQ(err, 3) TH_LOG("HIDIOCSOUTPUT ioctl failed, got %d", err);
+
+	/*
+	 * Note: The uhid mock doesn't validate the set report data,
+	 * so we just verify the ioctl succeeds
+	 */
+}
+
+/*
+ * Test HIDIOCGRAWNAME ioctl to get device name string
+ */
+TEST_F(hidraw, ioctl_rawname)
+{
+	char name[256] = {0};
+	char expected_name[64];
+	int err;
+
+	/* get device name */
+	err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(name)), name);
+	ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWNAME ioctl failed, got %d", err);
+
+	/* construct expected name based on device id */
+	snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id);
+
+	/* verify the name matches expected pattern */
+	ASSERT_EQ(strcmp(name, expected_name), 0)
+		TH_LOG("expected name '%s', got '%s'", expected_name, name);
+}
+
+/*
+ * Test HIDIOCGRAWPHYS ioctl to get device physical address string
+ */
+TEST_F(hidraw, ioctl_rawphys)
+{
+	char phys[256] = {0};
+	char expected_phys[64];
+	int err;
+
+	/* get device physical address */
+	err = ioctl(self->hidraw_fd, HIDIOCGRAWPHYS(sizeof(phys)), phys);
+	ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWPHYS ioctl failed, got %d", err);
+
+	/* construct expected phys based on device id */
+	snprintf(expected_phys, sizeof(expected_phys), "%d", self->hid.dev_id);
+
+	/* verify the phys matches expected value */
+	ASSERT_EQ(strcmp(phys, expected_phys), 0)
+		TH_LOG("expected phys '%s', got '%s'", expected_phys, phys);
+}
+
+/*
+ * Test HIDIOCGRAWUNIQ ioctl to get device unique identifier string
+ */
+TEST_F(hidraw, ioctl_rawuniq)
+{
+	char uniq[256] = {0};
+	int err;
+
+	/* get device unique identifier */
+	err = ioctl(self->hidraw_fd, HIDIOCGRAWUNIQ(sizeof(uniq)), uniq);
+	ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWUNIQ ioctl failed, got %d", err);
+
+	/* uniq is typically empty in our test setup */
+	ASSERT_EQ(strlen(uniq), 0) TH_LOG("expected empty uniq, got '%s'", uniq);
+}
+
+/*
+ * Test device string ioctls with small buffer sizes
+ */
+TEST_F(hidraw, ioctl_strings_small_buffer)
+{
+	char small_buf[8] = {0};
+	char expected_name[64];
+	int err;
+
+	/* test HIDIOCGRAWNAME with small buffer */
+	err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(small_buf)), small_buf);
+	ASSERT_EQ(err, sizeof(small_buf))
+		TH_LOG("HIDIOCGRAWNAME with small buffer failed, got %d", err);
+
+	/* construct expected truncated name */
+	snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id);
+
+	/* verify we got truncated name (first 8 chars, no null terminator guaranteed) */
+	ASSERT_EQ(strncmp(small_buf, expected_name, sizeof(small_buf)), 0)
+		TH_LOG("expected truncated name to match first %zu chars", sizeof(small_buf));
+
+	/* Note: hidraw driver doesn't guarantee null termination when buffer is too small */
+}
+
 int main(int argc, char **argv)
 {
 	return test_harness_run(argc, argv);

-- 
2.51.0


^ permalink raw reply related

* [PATCH v2 0/3] HID: hidraw: rework ioctls
From: Benjamin Tissoires @ 2025-08-26 12:39 UTC (permalink / raw)
  To: Jiri Kosina, Shuah Khan, Arnd Bergmann
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires,
	Arnd Bergmann

Arnd sent the v1 of the series in July, and it was bogus. So with a
little help from claude-sonnet I built up the missing ioctls tests and
tried to figure out a way to apply Arnd's logic without breaking the
existing ioctls.

The end result is in patch 3/3, which makes use of subfunctions to keep
the main ioctl code path clean.

Arnd, I kept your From: and SoB fields, please shout if you are unhappy.

Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
changes in v2:
- add new hidraw ioctls tests
- refactor Arnd's patch to keep the existing error path logic
- link to v1: https://lore.kernel.org/linux-input/20250711072847.2836962-1-arnd@kernel.org/

---

Jiri, checkpatch.pl complains about my co-develop tag. Did we get some
consensus for AI-assisted tag?

---
Arnd Bergmann (1):
      HID: tighten ioctl command parsing

Benjamin Tissoires (2):
      selftests/hid: hidraw: add more coverage for hidraw ioctls
      selftests/hid: hidraw: forge wrong ioctls and tests them

 drivers/hid/hidraw.c                     | 224 ++++++++-------
 include/uapi/linux/hidraw.h              |   2 +
 tools/testing/selftests/hid/hid_common.h |   6 +
 tools/testing/selftests/hid/hidraw.c     | 473 +++++++++++++++++++++++++++++++
 4 files changed, 603 insertions(+), 102 deletions(-)
---
base-commit: b80a75cf6999fb79971b41eaec7af2bb4b514714
change-id: 20250825-b4-hidraw-ioctls-66f34297032a

Best regards,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply

* Re: [PATCH v1] HID: mf: add support for Legion Go dual dinput modes
From: Jiri Kosina @ 2025-08-26 10:49 UTC (permalink / raw)
  To: Antheas Kapenekakis; +Cc: linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <CAGwozwH8Px=6X1AnH+3pohqdr9Y5thi6MfzJgOGtPC2c23ksjQ@mail.gmail.com>

On Tue, 26 Aug 2025, Antheas Kapenekakis wrote:

> Can you replace mf with quirks when merging if it is more appropriate?

Done. Now in hid.git#for-6.17/upstream-fixes. Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH v1] HID: mf: add support for Legion Go dual dinput modes
From: Antheas Kapenekakis @ 2025-08-26 10:46 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <404sp531-6o34-rs48-po90-5276or97q405@xreary.bet>

On Tue, 26 Aug 2025 at 12:41, Jiri Kosina <jikos@kernel.org> wrote:
>
> On Sun, 3 Aug 2025, Antheas Kapenekakis wrote:
>
> > The Legion Go features detachable controllers which support a dual
> > dinput mode. In this mode, the controllers appear under a single HID
> > device with two applications.
> >
> > Currently, both controllers appear under the same event device, causing
> > their controls to be mixed up. This patch separates the two so that
> > they can be used independently.
> >
> > In addition, the latest firmware update for the Legion Go swaps the IDs
> > to the ones used by the Legion Go 2, so add those IDs as well.
> >
> > Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
>
> Hi,
>
> thanks, the patch looks good, but what is the 'mf: ' prefix about in the
> subject/shortlog?

Hm, I referenced a previous commit while writing the header and it
might not be relevant. Can you replace mf with quirks when merging if
it is more appropriate?

Thank you,
Antheas

> --
> Jiri Kosina
> SUSE Labs
>
>


^ permalink raw reply

* Re: [PATCH v1] HID: mf: add support for Legion Go dual dinput modes
From: Jiri Kosina @ 2025-08-26 10:41 UTC (permalink / raw)
  To: Antheas Kapenekakis; +Cc: linux-input, linux-kernel, Benjamin Tissoires
In-Reply-To: <20250803160253.12956-1-lkml@antheas.dev>

On Sun, 3 Aug 2025, Antheas Kapenekakis wrote:

> The Legion Go features detachable controllers which support a dual
> dinput mode. In this mode, the controllers appear under a single HID
> device with two applications.
> 
> Currently, both controllers appear under the same event device, causing
> their controls to be mixed up. This patch separates the two so that
> they can be used independently.
> 
> In addition, the latest firmware update for the Legion Go swaps the IDs
> to the ones used by the Legion Go 2, so add those IDs as well.
> 
> Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>

Hi,

thanks, the patch looks good, but what is the 'mf: ' prefix about in the 
subject/shortlog?

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH] HID: elecom: add support for ELECOM M-DT2DRBK
From: Jiri Kosina @ 2025-08-26 10:40 UTC (permalink / raw)
  To: Martin Hilgendorf; +Cc: Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <20250802134542.21692-1-martin.hilgendorf@posteo.de>

On Sat, 2 Aug 2025, Martin Hilgendorf wrote:

> The DT2DRBK trackball has 8 buttons, but the report descriptor only
> specifies 5. This patch adds the device ID and performs a similar fixup as
> for other ELECOM devices to enable the remaining 3 buttons.
> 
> Signed-off-by: Martin Hilgendorf <martin.hilgendorf@posteo.de>

Applied to hid.git#for-6.17/upstream-fixes, thanks.

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH] HID: tighten ioctl command parsing
From: Benjamin Tissoires @ 2025-08-26 10:13 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Arnd Bergmann, Jiri Kosina, Peter Hutterer, linux-input,
	linux-kernel
In-Reply-To: <e0557372-b029-4831-8d32-c1eb512ac736@app.fastmail.com>

On Aug 22 2025, Arnd Bergmann wrote:
> On Thu, Aug 21, 2025, at 08:56, Benjamin Tissoires wrote:
> > On Jul 11 2025, Arnd Bergmann wrote:
> >>
> >> +			break;
> >> +	}
> >>  
> >> +	hid = dev->hid;
> >> +	switch (cmd & ~IOCSIZE_MASK) {
> >
> > Jiri pinged me about this one, and I gave it a go with the existing
> > tests I have in selftests... and turns out that this changes the logic
> > of the ioctl processing.
> >
> > The removed block was in the default section of the switch/case
> > statement. Now it's added *after*, meaning that any ioctl that was
> > normally processed before are now caught in the default of the switch
> > statement below and return -ENOTTY.
> >
> > Running tools/testing/selftests/hid/hid_bpf showed that.
> 
> Ah, of course, thanks for checking and describing the issue.
> 
> Did you already come up with a fixed patch? I'm currently
> travelling and won't be able to send a v2 quickly, so if you
> have a version that works for you, let's use that instead.
> 

I spent yesterday trying to find a way to make the old behavior looks
the same than the new, and got a rather big rewrite of your patch. I'll
send this out as a v2, keeping your From and SoB, but please shout if
you are unhappy with those 2 tags.

Cheers,
Benjamin

^ permalink raw reply

* [PATCH 2/2] hid: intel-thc-hid: intel-quickspi: Add WCL Device IDs
From: Xinpeng Sun @ 2025-08-26  7:27 UTC (permalink / raw)
  To: jikos, bentiss
  Cc: srinivas.pandruvada, linux-input, linux-kernel, Xinpeng Sun
In-Reply-To: <20250826072701.991046-1-xinpeng.sun@intel.com>

Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com>
---
 drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c | 2 ++
 drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
index 5e5f179dd113..84314989dc53 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -976,6 +976,8 @@ static const struct pci_device_id quickspi_pci_tbl[] = {
 	{PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_SPI_PORT2, &ptl), },
 	{PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT1, &ptl), },
 	{PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT2, &ptl), },
+	{PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_SPI_PORT1, &ptl), },
+	{PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_SPI_PORT2, &ptl), },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, quickspi_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
index 6fdf674b21c5..f3532d866749 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
@@ -19,6 +19,8 @@
 #define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT2	0xE34B
 #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT1	0xE449
 #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT2	0xE44B
+#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_SPI_PORT1 	0x4D49
+#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_SPI_PORT2 	0x4D4B
 
 /* HIDSPI special ACPI parameters DSM methods */
 #define ACPI_QUICKSPI_REVISION_NUM			2
-- 
2.40.1


^ permalink raw reply related

* [PATCH 1/2] hid: intel-thc-hid: intel-quicki2c: Add WCL Device IDs
From: Xinpeng Sun @ 2025-08-26  7:27 UTC (permalink / raw)
  To: jikos, bentiss
  Cc: srinivas.pandruvada, linux-input, linux-kernel, Xinpeng Sun

Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com>
---
 drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c | 2 ++
 drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index f122fde879b9..17b1f2df8f8a 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
@@ -1019,6 +1019,8 @@ static const struct pci_device_id quicki2c_pci_tbl[] = {
 	{ PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
 	{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
 	{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
+	{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
+	{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
index b78c8864d39e..240492a38c24 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
@@ -13,6 +13,8 @@
 #define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT2	0xE34A
 #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT1	0xE448
 #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT2	0xE44A
+#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT1 	0x4D48
+#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT2 	0x4D4A
 
 /* Packet size value, the unit is 16 bytes */
 #define MAX_PACKET_SIZE_VALUE_LNL			256
-- 
2.40.1


^ permalink raw reply related

* Re: [PATCH 0/2] HID: bpf: allow bpf to rebind a driver to hid-mutltiouch
From: Peter Hutterer @ 2025-08-26  2:54 UTC (permalink / raw)
  To: Benjamin Tissoires; +Cc: Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <20250821-bpf-rescan-v1-0-08f9e2bc01bb@kernel.org>

On Thu, Aug 21, 2025 at 04:38:12PM +0200, Benjamin Tissoires wrote:
> This happened while Peter was trying to fix a Viewsonic device: the HID
> device sending multiotuch data through a proprietary collection was
> handled by hid-generic, and we don't have any way of attaching it to
> hid-multitouch because the pre-scanning wasn't able to see the Contact
> ID HID usage.
> 
> After a little of back and forth, it turns out that the best solution is
> to re-scan the device when a report descriptor is changed from the BPF
> point of view.
> 
> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

Thanks, this series looks good to me.

Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

Cheers,
  Peter

> ---
> Benjamin Tissoires (2):
>       HID: core: factor out hid_set_group()
>       HID: bpf: rescan the device for the group after a load/unload
> 
>  drivers/hid/hid-core.c | 44 ++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 36 insertions(+), 8 deletions(-)
> ---
> base-commit: f55f91622e6f10884d30049f6748588b3718eecd
> change-id: 20250821-bpf-rescan-d4764865c67f
> 
> Best regards,
> -- 
> Benjamin Tissoires <bentiss@kernel.org>
> 

^ permalink raw reply

* Re: [PATCH] dt-bindings: input: touchscreen: imagis: add missing minItems
From: Duje Mihanović @ 2025-08-25 18:57 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Karel Balej, David Wronek, phone-devel,
	~postmarketos/upstreaming, linux-input, devicetree, linux-kernel
In-Reply-To: <20250825-capillary-viral-b7448ca6a57e@spud>

On Monday, 25 August 2025 18:42:38 Central European Summer Time Conor Dooley wrote:
> On Sun, Aug 24, 2025 at 06:12:05PM +0200, Duje Mihanović wrote:
> > The binding currently expects exactly 5 keycodes, which matches the
> > chip's theoretical maximum but probably not the number of touch keys on
> > any phone using the IST3032C. Add a minItems value of 2 to prevent
> > dt-validate complaints.
> 
> Does this mean that there are devicetrees in the wild that use < 5
> keycodes?

Indeed.

> > 
> > +  - |
> > +    #include <dt-bindings/input/linux-event-codes.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    i2c {
> > +      #address-cells = <1>;
> > +      #size-cells = <0>;
> > +      touchscreen@50 {
> > +        compatible = "imagis,ist3032c";
> > +        reg = <0x50>;
> > +        interrupt-parent = <&gpio>;
> > +        interrupts = <72 IRQ_TYPE_EDGE_FALLING>;
> > +        vdd-supply = <&ldo2>;
> > +        touchscreen-size-x = <480>;
> > +        touchscreen-size-y = <800>;
> > +        linux,keycodes = <KEY_APPSELECT>, <KEY_BACK>;
> 
> Does this really need a dedicated example? Why can't the property go
> into the existing one?

Only the IST3032C is currently known to support these keys and this is enforced
by the binding, so it wouldn't really make sense to add it to the 3038C
example.

Regards,
--
Duje




^ permalink raw reply

* Re: [PATCH] dt-bindings: input: touchscreen: imagis: add missing minItems
From: Conor Dooley @ 2025-08-25 16:42 UTC (permalink / raw)
  To: Duje Mihanović
  Cc: Markuss Broks, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Karel Balej, David Wronek, phone-devel,
	~postmarketos/upstreaming, linux-input, devicetree, linux-kernel
In-Reply-To: <20250824-imagis-minitems-v1-1-cea9db55e87f@dujemihanovic.xyz>

[-- Attachment #1: Type: text/plain, Size: 2271 bytes --]

On Sun, Aug 24, 2025 at 06:12:05PM +0200, Duje Mihanović wrote:
> The binding currently expects exactly 5 keycodes, which matches the
> chip's theoretical maximum but probably not the number of touch keys on
> any phone using the IST3032C. Add a minItems value of 2 to prevent
> dt-validate complaints.

Does this mean that there are devicetrees in the wild that use < 5
keycodes?

> 
> Also add another example to make sure the linux,keycodes property is
> checked.
> 
> Signed-off-by: Duje Mihanović <duje@dujemihanovic.xyz>
> ---
>  .../bindings/input/touchscreen/imagis,ist3038c.yaml    | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
> index bd8ede3a4ad8939cef97e9b177548a8fc8386df7..0ef79343bf9a223501aff8b6a525b873e777ea20 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml
> @@ -35,6 +35,7 @@ properties:
>  
>    linux,keycodes:
>      description: Keycodes for the touch keys
> +    minItems: 2
>      maxItems: 5
>  
>    touchscreen-size-x: true
> @@ -87,5 +88,22 @@ examples:
>          touchscreen-inverted-y;
>        };
>      };
> +  - |
> +    #include <dt-bindings/input/linux-event-codes.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    i2c {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +      touchscreen@50 {
> +        compatible = "imagis,ist3032c";
> +        reg = <0x50>;
> +        interrupt-parent = <&gpio>;
> +        interrupts = <72 IRQ_TYPE_EDGE_FALLING>;
> +        vdd-supply = <&ldo2>;
> +        touchscreen-size-x = <480>;
> +        touchscreen-size-y = <800>;
> +        linux,keycodes = <KEY_APPSELECT>, <KEY_BACK>;

Does this really need a dedicated example? Why can't the property go
into the existing one?

> +      };
> +    };
>  
>  ...
> 
> ---
> base-commit: c17b750b3ad9f45f2b6f7e6f7f4679844244f0b9
> change-id: 20250824-imagis-minitems-4a71387ce61b
> 
> Best regards,
> -- 
> Duje Mihanović <duje@dujemihanovic.xyz>
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH RFC 1/3] dt-bindings: input: elan: Introduce Elan eKTP1059 Touchpad
From: Conor Dooley @ 2025-08-25 16:40 UTC (permalink / raw)
  To: Andreas Kemnade
  Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Henrik Rydberg, Tony Lindgren, hns, linux-input, devicetree,
	linux-kernel, linux-omap
In-Reply-To: <20250825-ektp-submit-v1-1-1dd476c1277b@kemnade.info>

[-- Attachment #1: Type: text/plain, Size: 1853 bytes --]

On Mon, Aug 25, 2025 at 12:07:28AM +0200, Andreas Kemnade wrote:
> The Elan eKTP1059 Touchpad is seen in the Epson Moverio BT-200
> attached via SPI. Add a binding for this chip. Little is known.
> 
> Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
> ---
>  .../devicetree/bindings/input/elan,ektp1059.yaml   | 45 ++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/elan,ektp1059.yaml b/Documentation/devicetree/bindings/input/elan,ektp1059.yaml
> new file mode 100644
> index 000000000000..a10256a271e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/elan,ektp1059.yaml
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/input/elan,ektp1059.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Elantech SPI Touchpad
> +
> +maintainers:
> +  - Andreas Kemnade <andreas@kemnade.info>
> +
> +allOf:
> +  - $ref: touchscreen/touchscreen.yaml#
> +
> +properties:
> +  compatible:
> +    const: elan,ektp1059
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +
> +additionalProperties: false

Shouldn't this be unevalutedProperties: false, since you want to make
use of what's in touchscreen.yaml?

> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    spi {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        touchpad@0 {
> +            compatible = "elan,ektp1059";
> +            reg = <0x0>;
> +            interrupt-parent = <&gpio4>;
> +            interrupts = <0x0 IRQ_TYPE_LEVEL_LOW>;
> +        };
> +    };
> 
> -- 
> 2.39.5
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v3 2/2] HID: Make elan touch controllers power on after panel is enabled
From: Doug Anderson @ 2025-08-25 16:29 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Pin-yen Lin, Neil Armstrong, Jessica Zhang, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Benjamin Tissoires, linux-kernel, linux-input, Chen-Yu Tsai,
	dri-devel
In-Reply-To: <pr01os80-s752-1rqp-782q-65nr8222npq7@xreary.bet>

Hi,

On Tue, Aug 19, 2025 at 1:55 AM Jiri Kosina <jikos@kernel.org> wrote:
>
> On Mon, 18 Aug 2025, Doug Anderson wrote:
>
> > > Introduce a new HID quirk to indicate that this device has to be enabled
> > > after the panel's backlight is enabled, and update the driver data for
> > > the elan devices to enable this quirk. This cannot be a I2C HID quirk
> > > because the kernel needs to acknowledge this before powering up the
> > > device and read the VID/PID. When this quirk is enabled, register
> > > .panel_enabled()/.panel_disabling() instead for the panel follower.
> > >
> > > Also rename the *panel_prepare* functions into *panel_follower* because
> > > they could be called in other situations now.
> > >
> > > Fixes: bd3cba00dcc63 ("HID: i2c-hid: elan: Add support for Elan eKTH6915 i2c-hid touchscreens")
> > > Fixes: d06651bebf99e ("HID: i2c-hid: elan: Add elan-ekth6a12nay timing")
> > >
> > > Reviewed-by: Douglas Anderson <dianders@chromium.org>
> > > Signed-off-by: Pin-yen Lin <treapking@chromium.org>

Note: cuddled the "Fixes" tags and the "Reviewed-by" tag next to each
other while applying.


> > > ---
> > >
> > > Changes in v3:
> > > - Collect review tag
> > > - Add fixes tags
> > >
> > > Changes in v2:
> > > - Rename *panel_prepare* functions to *panel_follower*
> > > - Replace after_panel_enabled flag with enabled/disabling callbacks
> > >
> > >  drivers/hid/i2c-hid/i2c-hid-core.c    | 46 ++++++++++++++++-----------
> > >  drivers/hid/i2c-hid/i2c-hid-of-elan.c | 11 ++++++-
> > >  include/linux/hid.h                   |  2 ++
> > >  3 files changed, 40 insertions(+), 19 deletions(-)
> >
> > Re-iterating my response from v2 [1] so it's still seen even if people
> > only look at the latest version. :-) If HID folks don't mind us
> > landing this through drm-misc, feel free to Ack this patch.
>
> Acked-by: Jiri Kosina <jkosina@suse.com>

Pushed to drm-misc-next with Jiri's Ack:

[2/2] HID: i2c-hid: Make elan touch controllers power on after panel is enabled
      commit: cbdd16b818eef876dd2de9d503fe7397a0666cbe

NOTE that I added "i2c-hid" into the subject prefix to make things
more consistent.

-Doug

^ permalink raw reply

* Re: [PATCH v3 1/2] drm/panel: Allow powering on panel follower after panel is enabled
From: Doug Anderson @ 2025-08-25 16:28 UTC (permalink / raw)
  To: Pin-yen Lin
  Cc: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jiri Kosina,
	Benjamin Tissoires, linux-kernel, linux-input, Chen-Yu Tsai,
	dri-devel
In-Reply-To: <CAD=FV=XZK3HO8iC3VyMH+fP_XG2ogSNvUWuUcPFUxn1jU6-JZA@mail.gmail.com>

Hi,

On Mon, Aug 18, 2025 at 1:11 PM Doug Anderson <dianders@chromium.org> wrote:
>
> Hi,
>
> On Mon, Aug 18, 2025 at 4:50 AM Pin-yen Lin <treapking@chromium.org> wrote:
> >
> > Some touch controllers have to be powered on after the panel's backlight
> > is enabled. To support these controllers, introduce .panel_enabled() and
> > .panel_disabling() to panel_follower_funcs and use them to power on the
> > device after the panel and its backlight are enabled.
> >
> > Signed-off-by: Pin-yen Lin <treapking@chromium.org>
> >
> > ---
> >
> > Changes in v3:
> > - Update kernel-docs of drm_panel_add_follower() and drm_panel_remove_follower()
> > - Fix the order of calling .panel_disabling() and .panel_unpreparing()
> > - Add a blank line before the goto label
> >
> > Changes in v2:
> > - Replace after_panel_enabled flag with enabled/disabling callbacks
> >
> >  drivers/gpu/drm/drm_panel.c | 73 +++++++++++++++++++++++++++++++------
> >  include/drm/drm_panel.h     | 14 +++++++
> >  2 files changed, 76 insertions(+), 11 deletions(-)
>
> Looks good to me now.
>
> Reviewed-by: Douglas Anderson <dianders@chromium.org>
>
> If there are no objections, I'll plan to apply patch #1 next week to
> give people a little time to speak up. As per discussion in v2 [1],
> unless we hear back an "Ack" from HID maintainers then patch #2 will
> just need to wait a while before it can land in the HID tree.
>
> Question for Jessica / Neil: what do you think about landing
> ${SUBJECT} patch in drm-misc-fixes instead of drm-misc-next? This is a
> dependency for the next patch which is marked as a "Fix". It'll mean
> that the patch can make it into mainline faster so the HID patch could
> land faster. The patch is also pretty low risk...
>
> [1] https://lore.kernel.org/r/CAD=FV=UV8_XGmxC=7Z18PEnj6wKz+yZQuV_4h+LJh_MNCqszvg@mail.gmail.com/

I didn't hear anything and it didn't seem urgent enough to put in
Fixes. Pushed to drm-misc-next.

[1/2] drm/panel: Allow powering on panel follower after panel is enabled
      commit: 2eb22214c132374e11e681c44d7879c91f67f614

^ permalink raw reply

* RE: [BUG] Kernel panic in amd_sfh on Lenovo Legion Go
From: Natikar, Basavaraj @ 2025-08-25 14:10 UTC (permalink / raw)
  To: Matthew Schwartz, S-k, Shyam-sundar
  Cc: Limonciello, Mario, linux-input@vger.kernel.org
In-Reply-To: <a21abca5-4268-449d-95f1-bdd7a25894a5@linux.dev>

[AMD Official Use Only - AMD Internal Distribution Only]

Thank you, Matthew, for bringing this issue to our attention.
We will look into it and keep you updated.

Thanks,
--
Basavaraj

-----Original Message-----
From: Matthew Schwartz <matthew.schwartz@linux.dev>
Sent: Friday, August 22, 2025 12:29 AM
To: Natikar, Basavaraj <Basavaraj.Natikar@amd.com>; S-k, Shyam-sundar <Shyam-sundar.S-k@amd.com>
Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; linux-input@vger.kernel.org
Subject: [BUG] Kernel panic in amd_sfh on Lenovo Legion Go

Hello,

While using my Lenovo Legion Go handheld device on SteamOS, I have had many instances of warnings and occasional kernel panics in amd_sfh_work on their 6.15.8 kernel. Using kdumpst, I was able to get some logs for the most recent kernel panic:

<4>[  662.713733] ------------[ cut here ]------------ <4>[  662.713738] list_del corruption. prev->next should be ffff8ccc66a51e88, but was ffff8ccc5fc5d0e8. (prev=ffff8ccc41425280) <4>[  662.713754] WARNING: CPU: 11 PID: 164 at lib/list_debug.c:62 __list_del_entry_valid_or_report+0xfa/0x10a
<4>[  662.714204] CPU: 11 UID: 0 PID: 164 Comm: kworker/11:1 Tainted: G        W           6.15.8-valve1-2-neptune-615-g49248f4e2ad1 #1 PREEMPT(full)  64605a591817db76b46b95d73e86c4364b25c841
<4>[  662.714214] Tainted: [W]=WARN
<4>[  662.714218] Hardware name: LENOVO 83E1/LNVNB161216, BIOS N3CN37WW 12/06/2024 <4>[  662.714223] Workqueue: events amd_sfh_work [amd_sfh] <4>[  662.714236] RIP: 0010:__list_del_entry_valid_or_report+0xfa/0x10a
<4>[  662.714245] Code: e8 cb 4a 0f 00 0f 0b e9 77 ff ff ff 4c 89 e7 e8 dc 0c 3b 00 49 8b 14 24 4c 89 e1 48 89 de 48 c7 c7 28 c7 13 b0 e8 a6 4a 0f 00 <0f> 0b e9 52 ff ff ff 5b 5d 41 5c e9 91 c6 eb ff 48 89 df e8 1e fe <4>[  662.714250] RSP: 0018:ffffd12c806e3df8 EFLAGS: 00010246 <4>[  662.714257] RAX: 0000000000000000 RBX: ffff8ccc66a51e88 RCX: 0000000000000027 <4>[  662.714262] RDX: ffff8ccf0fedbd08 RSI: 0000000000000001 RDI: ffff8ccf0fedbd00 <4>[  662.714266] RBP: ffff8ccc41425280 R08: 0000000000000000 R09: 00000000fffdffff <4>[  662.714270] R10: ffffffffb16d0120 R11: ffffd12c806e3c88 R12: ffff8ccc41425280 <4>[  662.714274] R13: ffff8ccc66a51e88 R14: 0000000000000000 R15: ffff8ccc66a51e80 <4>[  662.714278] FS:  0000000000000000(0000) GS:ffff8ccf5e88a000(0000) knlGS:0000000000000000 <4>[  662.714283] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4>[  662.714287] CR2: 00000000c4f52010 CR3: 0000000164de1000 CR4: 0000000000f50ef0 <4>[  662.714292] PKRU: 55555554 <4>[  662.714296] Call Trace:
<4>[  662.714301]  <TASK>
<4>[  662.714310]  amd_sfh_work.cold+0x1c/0x21 [amd_sfh 590e26be9da743ed9c42d4473ff11e552461cd54]
<4>[  662.714323]  ? srso_alias_return_thunk+0x5/0xfbef5
<4>[  662.714333]  process_one_work+0x190/0x350 <4>[  662.714344]  worker_thread+0x2d7/0x410 <4>[  662.714353]  ? __pfx_worker_thread+0x10/0x10 <4>[  662.714360]  kthread+0xf9/0x240 <4>[  662.714370]  ? __pfx_kthread+0x10/0x10 <4>[  662.714378]  ret_from_fork+0x31/0x50 <4>[  662.714388]  ? __pfx_kthread+0x10/0x10 <4>[  662.714396]  ret_from_fork_asm+0x1a/0x30 <4>[  662.714411]  </TASK> <4>[  662.714415] ---[ end trace 0000000000000000 ]--- <4>[  662.714577] Oops: general protection fault, probably for non-canonical address 0x32e31c55d8aa0687: 0000 [#1] SMP NOPTI
<4>[  662.714590] CPU: 4 UID: 0 PID: 162 Comm: kworker/4:1 Tainted: G        W           6.15.8-valve1-2-neptune-615-g49248f4e2ad1 #1 PREEMPT(full)  64605a591817db76b46b95d73e86c4364b25c841
<4>[  662.714601] Tainted: [W]=WARN
<4>[  662.714605] Hardware name: LENOVO 83E1/LNVNB161216, BIOS N3CN37WW 12/06/2024 <4>[  662.714609] Workqueue: events amd_sfh_work [amd_sfh] <4>[  662.714622] RIP: 0010:amd_sfh_work+0x31/0x150 [amd_sfh] <4>[  662.714631] Code: 00 00 41 57 41 56 41 55 41 54 55 53 48 89 fb 48 83 ec 08 4c 8b af c0 00 00 00 4c 8b 67 f8 49 8b 45 08 49 8b 4d 00 4d 8d 7d f8 <4c> 3b 28 0f 85 2b 3b 00 00 4c 3b 69 08 0f 85 21 3b 00 00 48 89 41 <4>[  662.714636] RSP: 0018:ffffd12c8068fe18 EFLAGS: 00010296 <4>[  662.714643] RAX: 32e31c55d8aa0687 RBX: ffff8ccc414251c8 RCX: dead000000000100 <4>[  662.714648] RDX: 0000000000000001 RSI: ffff8ccc42240ec6 RDI: ffff8ccc414251c8 <4>[  662.714652] RBP: ffff8ccc400b7800 R08: 8080808080808080 R09: 0000000000000000 <4>[  662.714656] R10: ffff8ccc400508c0 R11: fefefefefefefeff R12: ffff8ccc43ac4e58 <4>[  662.714659] R13: ffff8ccc66a51e88 R14: 0000000000000000 R15: ffff8ccc66a51e80 <4>[  662.714664] FS:  0000000000000000(0000) GS:ffff8ccf5e6ca000(0000) knlGS:0000000000000000 <4>[  662.714669] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4>[  662.714673] CR2: 00007f7ccc5f9000 CR3: 0000000164de1000 CR4: 0000000000f50ef0 <4>[  662.714678] PKRU: 55555554 <4>[  662.714681] Call Trace:
<4>[  662.714687]  <TASK>
<4>[  662.714690]  ? srso_alias_return_thunk+0x5/0xfbef5
<4>[  662.714704]  process_one_work+0x190/0x350 <4>[  662.714715]  worker_thread+0x2d7/0x410 <4>[  662.714728]  ? __pfx_worker_thread+0x10/0x10 <4>[  662.714736]  kthread+0xf9/0x240 <4>[  662.714746]  ? __pfx_kthread+0x10/0x10 <4>[  662.714755]  ret_from_fork+0x31/0x50 <4>[  662.714763]  ? __pfx_kthread+0x10/0x10 <4>[  662.714772]  ret_from_fork_asm+0x1a/0x30 <4>[  662.714787]  </TASK> <4>[  662.715218] ---[ end trace 0000000000000000 ]---

Full dmesg from pstore:

dmesg-pstore.202508210732-0: https://gist.github.com/matte-schwartz/f7d5fbc9eb6b47051fb5c3ea4d6ae32f
dmesg-pstore-202508210732-1: https://gist.github.com/matte-schwartz/a473354010a23ecb0b119024c960166d

Similar warnings in amd-sfh appeared intermittently earlier in my journal until eventually one triggered the kernel panic above.

The warnings appeared while I was leaving the device idle on Steam's GamepadUI home page while using gamescope. Because this bug is intermittent, I don't have a more reliable way to reproduce the issue other than leaving the device idle for extended periods of time.

Thanks,
Matthew

^ permalink raw reply

* Re: [PATCH v1 0/2] Input: wdt87xx_i2c - a couple of cleanups
From: Andy Shevchenko @ 2025-08-25 13:55 UTC (permalink / raw)
  To: linux-input, linux-kernel; +Cc: Dmitry Torokhov
In-Reply-To: <20250321183957.455518-1-andriy.shevchenko@linux.intel.com>

On Fri, Mar 21, 2025 at 08:39:16PM +0200, Andy Shevchenko wrote:
> A couple of cleanups related to ACPI ID table and probe function.

Any news here?

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH RFC 3/3] ARM: dts: ti/omap: epson-bt2ws: add touchpad
From: Andreas Kemnade @ 2025-08-24 22:07 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Henrik Rydberg, Tony Lindgren, hns
  Cc: linux-input, devicetree, linux-kernel, linux-omap,
	Andreas Kemnade
In-Reply-To: <20250825-ektp-submit-v1-0-1dd476c1277b@kemnade.info>

Add the EKTP1059 based touchpad connected via SPI.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
 arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts | 32 +++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts
index c90f43cc2fae..746ac4761b0d 100644
--- a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts
+++ b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts
@@ -429,6 +429,23 @@ MATRIX_KEY(1, 1, KEY_VOLUMEDOWN)
 	linux,input-no-autorepeat;
 };
 
+&mcspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcspi1_pins>;
+
+	touchpad@0 {
+		compatible = "elan,ektp1059";
+		reg = <0>;      /* cs0 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&elan_pins>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+		spi-max-frequency = <200000>;
+		spi-cpol;
+		spi-cpha;
+	};
+};
+
 &mcbsp2 {
 	#sound-dai-cells = <0>;
 	pinctrl-names = "default";
@@ -506,6 +523,12 @@ OMAP4_IOPAD(0x1d4, PIN_OUTPUT | MUX_MODE3) /* gpio191 */
 		>;
 	};
 
+	elan_pins: pinmux-elan-pins {
+		pinctrl-single,pins = <
+			OMAP4_IOPAD(0x78, PIN_INPUT | MUX_MODE3) /* gpio52 */
+		>;
+	};
+
 	gpio_keys_pins: pinmux-gpio-key-pins {
 		pinctrl-single,pins = <
 			OMAP4_IOPAD(0x56, PIN_INPUT_PULLUP | MUX_MODE3) /* gpio35 */
@@ -579,6 +602,15 @@ OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE3) /* gpio27 */
 		>;
 	};
 
+	mcspi1_pins: pinmux-mcspi1-pins {
+		pinctrl-single,pins = <
+			OMAP4_IOPAD(0x132, PIN_INPUT_PULLUP | MUX_MODE0)
+			OMAP4_IOPAD(0x134, PIN_INPUT_PULLUP | MUX_MODE0)
+			OMAP4_IOPAD(0x136, PIN_OUTPUT | MUX_MODE0)
+			OMAP4_IOPAD(0x138, PIN_OUTPUT | MUX_MODE0)
+		>;
+	};
+
 	mcbsp2_pins: pinmux-mcbsp2-pins {
 		pinctrl-single,pins = <
 			OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0)       /* abe_mcbsp2_clkx */

-- 
2.39.5


^ permalink raw reply related

* [PATCH RFC 0/3] Input: add EKTP1059 Touchpad
From: Andreas Kemnade @ 2025-08-24 22:07 UTC (permalink / raw)
  To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Henrik Rydberg, Tony Lindgren, hns
  Cc: linux-input, devicetree, linux-kernel, linux-omap,
	Andreas Kemnade

Add a driver and bindings for the Touchpad found in the Epson Moverio
BT-200. The only information source is the driver in the vendor kernel.
Besides of cleanup it differs from it by not doing much postprocessing.

The touchpad has no buttons and can react to three simultanous touches
but positions can be used only for two touches.

This is an early RFC, maybe somebody recognizes something from other
ELAN chips.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
Andreas Kemnade (3):
      dt-bindings: input: elan: Introduce Elan eKTP1059 Touchpad
      Input: Add driver for Elan eKTP1059 Touchpad
      ARM: dts: ti/omap: epson-bt2ws: add touchpad

 .../devicetree/bindings/input/elan,ektp1059.yaml   |  45 ++++
 arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts  |  32 +++
 drivers/input/mouse/Kconfig                        |  10 +
 drivers/input/mouse/Makefile                       |   1 +
 drivers/input/mouse/elan_ektp1059.c                | 267 +++++++++++++++++++++
 5 files changed, 355 insertions(+)
---
base-commit: 1b237f190eb3d36f52dffe07a40b5eb210280e00
change-id: 20250824-ektp-submit-338c4bc30503

Best regards,
--  
Andreas Kemnade <andreas@kemnade.info>


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox