* [PATCH 1/4] HID: hid-msi-claw: Add MSI Claw configuration driver
From: Derek J. Clark @ 2026-05-10 4:35 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
Derek J . Clark, linux-input, linux-doc, linux-kernel
In-Reply-To: <20260510043510.442807-1-derekjohn.clark@gmail.com>
Adds configuration HID driver for the MSI Claw series of handheld PC's.
In this initial patch add the initial driver outline and attributes for
changing the gamepad mode, M-key behavior, and add a WO reset function.
Sending the SWITCH_MODE and RESET commands causes a USB disconnect in
the device. The completion will therefore never get hit and would trigger
an -EIO. To avoid showing the user an error for every write to these
attrs a bypass for the completion handling is introduced when timeout ==
0.
The initial version of this patch was written by Denis Benato, which
contained the initial reverse-engineering and implementation for the
gamepad mode switching. This work was later expanded by Zhouwang Huang
to include more gamepad modes. Finally, I refactored the drivers data
in/out flow and overall format to conform to kernel driver best
practices and style guides. Claude was used as an initial reviewer of
this patch.
Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Denis Benato <denis.benato@linux.dev>
Signed-off-by: Denis Benato <denis.benato@linux.dev>
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
MAINTAINERS | 6 +
drivers/hid/Kconfig | 12 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 6 +
drivers/hid/hid-msi-claw.c | 538 +++++++++++++++++++++++++++++++++++++
5 files changed, 563 insertions(+)
create mode 100644 drivers/hid/hid-msi-claw.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 6f6517bf4f97..5de5e62d9c92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17965,6 +17965,12 @@ S: Odd Fixes
F: Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
F: drivers/net/ieee802154/mrf24j40.c
+MSI CLAW HID DRIVER
+M: Derek J. Clark <derekjohn.clark@gmail.com>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: drivers/hid/hid-msi-claw.c
+
MSI EC DRIVER
M: Nikita Kravets <teackot@gmail.com>
L: platform-driver-x86@vger.kernel.org
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 10c12d8e6557..0cbe10ad6367 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -492,6 +492,18 @@ config HID_GT683R
Currently the following devices are know to be supported:
- MSI GT683R
+config HID_MSI_CLAW
+ tristate "MSI Claw Gamepad Support"
+ depends on USB_HID
+ select LEDS_CLASS
+ select LEDS_CLASS_MULTICOLOR
+ help
+ Support for the MSI Claw RGB and controller configuration
+
+ Say Y here to include configuration interface support for the MSI Claw Line
+ of Handheld Console Controllers. Say M here to compile this driver as a
+ module. The module will be called hid-msi-claw.
+
config HID_KEYTOUCH
tristate "Keytouch HID devices"
help
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 07dfdb6a49c5..c1dea89f1e87 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o
obj-$(CONFIG_HID_GOOGLE_STADIA_FF) += hid-google-stadiaff.o
obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o
obj-$(CONFIG_HID_GT683R) += hid-gt683r.o
+obj-$(CONFIG_HID_MSI_CLAW) += hid-msi-claw.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 933b7943bdb5..6d0d34806931 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1047,7 +1047,13 @@
#define USB_DEVICE_ID_MOZA_R16_R21_2 0x0010
#define USB_VENDOR_ID_MSI 0x1770
+#define USB_VENDOR_ID_MSI_2 0x0db0
#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00
+#define USB_DEVICE_ID_MSI_CLAW_XINPUT 0x1901
+#define USB_DEVICE_ID_MSI_CLAW_DINPUT 0x1902
+#define USB_DEVICE_ID_MSI_CLAW_DESKTOP 0x1903
+#define USB_DEVICE_ID_MSI_CLAW_BIOS 0x1904
+
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
diff --git a/drivers/hid/hid-msi-claw.c b/drivers/hid/hid-msi-claw.c
new file mode 100644
index 000000000000..7a3cd940ec49
--- /dev/null
+++ b/drivers/hid/hid-msi-claw.c
@@ -0,0 +1,538 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HID driver for MSI Claw Handheld PC gamepads.
+ *
+ * Provides configuration support for the MSI Claw series of handheld PC
+ * gamepads. Multiple iterations of the device firmware has led to some
+ * quirks for how certain attributes are handled. The original firmware
+ * did not support remapping of the M1 (right) and M2 (left) rear paddles.
+ * Additionally, the MCU RAM address for writing configuration data has
+ * changed twice. Checks are done during probe to enumerate these variances.
+ *
+ * Copyright (c) 2026 Zhouwang Huang <honjow311@gmail.com>
+ * Copyright (c) 2026 Denis Benato <denis.benato@linux.dev>
+ * Copyright (c) 2026 Valve Corporation
+ */
+
+#include <linux/array_size.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/kobject.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include "hid-ids.h"
+
+#define CLAW_OUTPUT_REPORT_ID 0x0f
+#define CLAW_INPUT_REPORT_ID 0x10
+
+#define CLAW_PACKET_SIZE 64
+
+#define CLAW_DINPUT_CFG_INTF_IN 0x82
+#define CLAW_XINPUT_CFG_INTF_IN 0x83
+
+enum claw_command_index {
+ CLAW_COMMAND_TYPE_READ_PROFILE = 0x04,
+ CLAW_COMMAND_TYPE_READ_PROFILE_ACK = 0x05,
+ CLAW_COMMAND_TYPE_ACK = 0x06,
+ CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA = 0x21,
+ CLAW_COMMAND_TYPE_SYNC_TO_ROM = 0x22,
+ CLAW_COMMAND_TYPE_SWITCH_MODE = 0x24,
+ CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE = 0x26,
+ CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK = 0x27,
+ CLAW_COMMAND_TYPE_RESET_DEVICE = 0x28,
+};
+
+enum claw_gamepad_mode_index {
+ CLAW_GAMEPAD_MODE_XINPUT = 0x01,
+ CLAW_GAMEPAD_MODE_DINPUT = 0x02,
+ CLAW_GAMEPAD_MODE_DESKTOP = 0x04,
+};
+
+static const char * const claw_gamepad_mode_text[] = {
+ [CLAW_GAMEPAD_MODE_XINPUT] = "xinput",
+ [CLAW_GAMEPAD_MODE_DINPUT] = "dinput",
+ [CLAW_GAMEPAD_MODE_DESKTOP] = "desktop",
+};
+
+enum claw_mkeys_function_index {
+ CLAW_MKEY_FUNCTION_MACRO,
+ CLAW_MKEY_FUNCTION_COMBO,
+ CLAW_MKEY_FUNCTION_DISABLED,
+};
+
+static const char * const claw_mkeys_function_text[] = {
+ [CLAW_MKEY_FUNCTION_MACRO] = "macro",
+ [CLAW_MKEY_FUNCTION_COMBO] = "combination",
+ [CLAW_MKEY_FUNCTION_DISABLED] = "disabled",
+};
+
+struct claw_command_report {
+ u8 report_id;
+ u8 padding[2];
+ u8 header_tail;
+ u8 cmd;
+ u8 data[59];
+} __packed;
+
+struct claw_drvdata {
+ /* MCU General Variables */
+ struct completion send_cmd_complete;
+ struct delayed_work cfg_resume;
+ struct delayed_work cfg_setup;
+ struct hid_device *hdev;
+ struct mutex cfg_mutex; /* mutex for synchronous data */
+ int endpoint;
+
+ /* Gamepad Variables */
+ enum claw_mkeys_function_index mkeys_function;
+ enum claw_gamepad_mode_index gamepad_mode;
+};
+
+static int get_endpoint_address(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_host_endpoint *ep;
+
+ ep = intf->cur_altsetting->endpoint;
+ if (ep)
+ return ep->desc.bEndpointAddress;
+
+ return -ENODEV;
+}
+
+static int claw_gamepad_mode_event(struct claw_drvdata *drvdata,
+ struct claw_command_report *cmd_rep)
+{
+ if (cmd_rep->data[0] >= ARRAY_SIZE(claw_gamepad_mode_text) ||
+ cmd_rep->data[1] >= ARRAY_SIZE(claw_mkeys_function_text))
+ return -EINVAL;
+
+ drvdata->gamepad_mode = cmd_rep->data[0];
+ drvdata->mkeys_function = cmd_rep->data[1];
+
+ return 0;
+}
+
+static int claw_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct claw_command_report *cmd_rep;
+ int ret = 0;
+
+ if (size != CLAW_PACKET_SIZE)
+ return 0;
+
+ if (drvdata->endpoint != CLAW_XINPUT_CFG_INTF_IN &&
+ drvdata->endpoint != CLAW_DINPUT_CFG_INTF_IN)
+ return 0;
+
+ cmd_rep = (struct claw_command_report *)data;
+
+ if (cmd_rep->report_id != CLAW_INPUT_REPORT_ID || cmd_rep->header_tail != 0x3c)
+ return 0;
+
+ dev_dbg(&hdev->dev, "Rx data as raw input report: [%*ph]\n",
+ CLAW_PACKET_SIZE, data);
+
+ switch (cmd_rep->cmd) {
+ case CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK:
+ ret = claw_gamepad_mode_event(drvdata, cmd_rep);
+ break;
+ case CLAW_COMMAND_TYPE_ACK:
+ break;
+ default:
+ dev_dbg(&hdev->dev, "Unknown command: %x\n", cmd_rep->cmd);
+ return 0;
+ }
+
+ complete(&drvdata->send_cmd_complete);
+ return ret;
+}
+
+static int mcu_property_out(struct hid_device *hdev, u8 index, u8 *data,
+ size_t len, unsigned int timeout)
+{
+ unsigned char *dmabuf __free(kfree) = NULL;
+ u8 header[] = { CLAW_OUTPUT_REPORT_ID, 0, 0, 0x3c, index };
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ size_t header_size = ARRAY_SIZE(header);
+ int ret;
+
+ if (header_size + len > CLAW_PACKET_SIZE)
+ return -EINVAL;
+
+ /* We can't use a devm_alloc reusable buffer without side effects during suspend */
+ dmabuf = kzalloc(CLAW_PACKET_SIZE, GFP_KERNEL);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ memcpy(dmabuf, header, header_size);
+ if (data && len)
+ memcpy(dmabuf + header_size, data, len);
+
+ /* Don't hold a mutex when timeout=0, those commands cause USB disconnect */
+ if (timeout) {
+ guard(mutex)(&drvdata->cfg_mutex);
+ reinit_completion(&drvdata->send_cmd_complete);
+ }
+
+ dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n",
+ CLAW_PACKET_SIZE, dmabuf);
+
+ ret = hid_hw_output_report(hdev, dmabuf, CLAW_PACKET_SIZE);
+ if (ret < 0)
+ return ret;
+
+ ret = ret == CLAW_PACKET_SIZE ? 0 : -EIO;
+ if (ret)
+ return ret;
+
+ if (timeout) {
+ ret = wait_for_completion_interruptible_timeout(&drvdata->send_cmd_complete,
+ msecs_to_jiffies(timeout));
+
+ dev_dbg(&hdev->dev, "Remaining timeout: %u\n", ret);
+ if (ret >= 0) /* preserve errors */
+ ret = ret == 0 ? -EBUSY : 0; /* timeout occurred : time remained */
+ }
+
+ return ret;
+}
+
+static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ u8 data[2] = { 0x00, drvdata->mkeys_function };
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) {
+ if (claw_gamepad_mode_text[i] && sysfs_streq(buf, claw_gamepad_mode_text[i])) {
+ ret = i;
+ break;
+ }
+ }
+ if (ret < 0)
+ return ret;
+
+ data[0] = ret;
+
+ ret = mcu_property_out(hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data, ARRAY_SIZE(data), 0);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t gamepad_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ int ret, i;
+
+ ret = mcu_property_out(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 8);
+ if (ret)
+ return ret;
+
+ i = drvdata->gamepad_mode;
+
+ if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0')
+ return sysfs_emit(buf, "unsupported\n");
+
+ return sysfs_emit(buf, "%s\n", claw_gamepad_mode_text[i]);
+}
+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;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) {
+ if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0')
+ continue;
+ count += sysfs_emit_at(buf, count, "%s ", claw_gamepad_mode_text[i]);
+ }
+
+ buf[count - 1] = '\n';
+
+ return count;
+}
+static DEVICE_ATTR_RO(gamepad_mode_index);
+
+static ssize_t mkeys_function_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ u8 data[2] = { drvdata->gamepad_mode, 0x00 };
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++) {
+ if (claw_mkeys_function_text[i] && sysfs_streq(buf, claw_mkeys_function_text[i])) {
+ ret = i;
+ break;
+ }
+ }
+ if (ret < 0)
+ return ret;
+
+ data[1] = ret;
+
+ ret = mcu_property_out(hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data, ARRAY_SIZE(data), 0);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t mkeys_function_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+ int ret, i;
+
+ ret = mcu_property_out(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 8);
+ if (ret)
+ return ret;
+
+ i = drvdata->mkeys_function;
+
+ if (i >= ARRAY_SIZE(claw_mkeys_function_text))
+ return sysfs_emit(buf, "unsupported\n");
+
+ return sysfs_emit(buf, "%s\n", claw_mkeys_function_text[i]);
+}
+static DEVICE_ATTR_RW(mkeys_function);
+
+static ssize_t mkeys_function_index_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, count = 0;
+
+ for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++)
+ count += sysfs_emit_at(buf, count, "%s ", claw_mkeys_function_text[i]);
+
+ buf[count - 1] = '\n';
+
+ return count;
+}
+static DEVICE_ATTR_RO(mkeys_function_index);
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return -EINVAL;
+
+ ret = mcu_property_out(hdev, CLAW_COMMAND_TYPE_RESET_DEVICE, NULL, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct hid_device *hdev = to_hid_device(kobj_to_dev(kobj));
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+ if (!drvdata) {
+ dev_warn(&hdev->dev,
+ "Failed to get drvdata from kobj. Gamepad attributes are not available.\n");
+ return 0;
+ }
+
+ return attr->mode;
+}
+
+static struct attribute *claw_gamepad_attrs[] = {
+ &dev_attr_gamepad_mode.attr,
+ &dev_attr_gamepad_mode_index.attr,
+ &dev_attr_mkeys_function.attr,
+ &dev_attr_mkeys_function_index.attr,
+ &dev_attr_reset.attr,
+ NULL,
+};
+
+static const struct attribute_group claw_gamepad_attr_group = {
+ .attrs = claw_gamepad_attrs,
+ .is_visible = claw_gamepad_attr_is_visible,
+};
+
+static void claw_remove(struct hid_device *hdev);
+
+static void cfg_setup_fn(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_setup);
+ int ret;
+
+ ret = mcu_property_out(drvdata->hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 8);
+ if (ret) {
+ dev_err(&drvdata->hdev->dev,
+ "Failed to setup device, can't read gamepad mode: %d\n", ret);
+ claw_remove(drvdata->hdev);
+ }
+
+ /* Add sysfs attributes after we get the device state */
+ ret = sysfs_create_group(&drvdata->hdev->dev.kobj, &claw_gamepad_attr_group);
+ if (ret) {
+ dev_err(&drvdata->hdev->dev,
+ "Failed to setup device, can't create gamepad attrs: %d\n", ret);
+ claw_remove(drvdata->hdev);
+ }
+
+ kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static void cfg_resume_fn(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_resume);
+ u8 data[2] = { drvdata->gamepad_mode, drvdata->mkeys_function };
+ int ret;
+
+ ret = mcu_property_out(drvdata->hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data,
+ ARRAY_SIZE(data), 0);
+ if (ret)
+ dev_err(&drvdata->hdev->dev, "Failed to set gamepad mode settings: %d\n", ret);
+}
+
+static int claw_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct claw_drvdata *drvdata;
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ int ret;
+
+ if (!hid_is_usb(hdev)) {
+ ret = -ENODEV;
+ goto err_probe;
+ }
+
+ intf = to_usb_interface(hdev->dev.parent);
+ udev = interface_to_usbdev(intf);
+ drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata) {
+ ret = -ENOMEM;
+ goto err_probe;
+ }
+
+ mutex_init(&drvdata->cfg_mutex);
+
+ hid_set_drvdata(hdev, drvdata);
+ drvdata->hdev = hdev;
+
+ ret = hid_parse(hdev);
+ if (ret)
+ goto err_probe;
+
+ /* Set quirk to create separate input devices per HID application */
+ hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT;
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret)
+ goto err_probe;
+
+ /* For non-control interfaces (keyboard/mouse), allow userspace to grab the devices. */
+ drvdata->endpoint = get_endpoint_address(hdev);
+ if (drvdata->endpoint != CLAW_XINPUT_CFG_INTF_IN &&
+ drvdata->endpoint != CLAW_DINPUT_CFG_INTF_IN)
+ return 0;
+
+ /* For control interface: open the HID transport for sending commands. */
+ ret = hid_hw_open(hdev);
+ if (ret)
+ goto err_stop_hw;
+
+ init_completion(&drvdata->send_cmd_complete);
+
+ INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn);
+ INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn);
+ schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500));
+
+ return 0;
+
+err_stop_hw:
+ hid_hw_stop(hdev);
+err_probe:
+ return dev_err_probe(&hdev->dev, ret, "Failed to init configuration device\n");
+}
+
+static void claw_remove(struct hid_device *hdev)
+{
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+ if (!drvdata)
+ return;
+
+ if (drvdata->endpoint == CLAW_XINPUT_CFG_INTF_IN ||
+ drvdata->endpoint == CLAW_DINPUT_CFG_INTF_IN) {
+ sysfs_remove_group(&hdev->dev.kobj, &claw_gamepad_attr_group);
+ cancel_delayed_work_sync(&drvdata->cfg_setup);
+ cancel_delayed_work_sync(&drvdata->cfg_resume);
+ hid_hw_close(hdev);
+ }
+
+ hid_hw_stop(hdev);
+}
+
+static int claw_resume(struct hid_device *hdev)
+{
+ struct claw_drvdata *drvdata = hid_get_drvdata(hdev);
+
+ /* MCU can take up to 500ms to be ready after resume */
+ schedule_delayed_work(&drvdata->cfg_resume, msecs_to_jiffies(500));
+
+ return 0;
+}
+
+static const struct hid_device_id claw_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_XINPUT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DINPUT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DESKTOP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_BIOS) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, claw_devices);
+
+static struct hid_driver claw_driver = {
+ .name = "hid-msi-claw",
+ .id_table = claw_devices,
+ .raw_event = claw_raw_event,
+ .probe = claw_probe,
+ .remove = claw_remove,
+ .resume = claw_resume,
+};
+module_hid_driver(claw_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Denis Benato <denis.benato@linux.dev>");
+MODULE_AUTHOR("Zhouwang Huang <honjow311@gmail.com>");
+MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
+MODULE_DESCRIPTION("HID driver for MSI Claw Handheld PC gamepads");
--
2.53.0
^ permalink raw reply related
* [PATCH 0/4] Add MSI Claw HID Configuration Driver
From: Derek J. Clark @ 2026-05-10 4:35 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Pierre-Loup A . Griffais, Denis Benato, Zhouwang Huang,
Derek J . Clark, linux-input, linux-doc, linux-kernel
This series adds and HID Configuration driver for the MSI Claw line of
Handheld Gaming PC's. The MSI Claw HID interface provides multiple
features, such as the ability to switch between xinput, dinput, and a
desktop mode, RGB control, rumble intensity, and mapping of the rear "M"
keys. There are additional gamepad modes that are not included in this
driver as they appear to be used in assembly line testing or are
incomplete in the firmware. During my testing I found them to be unstable.
The initial version of this driver was written by Denis Benato, which
contained the initial reverse-engineering and implementation for the
gamepad mode switching. This work was later expanded by Zhouwang Huang
to include more gamepad modes and additional features. Finally, I
refactored the entire driver, fixed multiple bugs, and refined the overall
format to conform to kernel driver best practices and style guide.
Claude was used initially by Zhouwang Huang to quickly parse HID captures
during the reverse-engineering of some of the features. Since Claude had
already been used, as a test of its capabilities I had it implement the
rumble intensity attribute after I had already rewritten most of the
driver, which I then manually edited to fix some mistakes. I also used
Claude to review the driver and these patches for any mistakes and bugs.
Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Denis Benato <denis.benato@linux.dev>
Signed-off-by: Denis Benato <denis.benato@linux.dev>
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Derek J. Clark (4):
HID: hid-msi-claw: Add MSI Claw configuration driver
HID: hid-msi-claw: Add M-key mapping attributes
HID: hid-msi-claw: Add RGB control interface
HID: hid-msi-claw: Add Rumble Intensity Attributes
MAINTAINERS | 6 +
drivers/hid/Kconfig | 12 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 6 +
drivers/hid/hid-msi-claw.c | 1577 ++++++++++++++++++++++++++++++++++++
5 files changed, 1602 insertions(+)
create mode 100644 drivers/hid/hid-msi-claw.c
--
2.53.0
^ permalink raw reply
* Re: [PATCH] ARM: riscpc: convert to sparse IRQs
From: Ethan Nelson-Moore @ 2026-05-10 3:55 UTC (permalink / raw)
To: linux-arm-kernel, linux-input
Cc: Russell King, Dmitry Torokhov, Russell King (Oracle),
Arnd Bergmann, Linus Walleij, Kees Cook, Nathan Chancellor,
Steven Rostedt, Thomas Weissschuh, Sebastian Andrzej Siewior,
Peter Zijlstra
In-Reply-To: <20260510034652.349166-1-enelsonmoore@gmail.com>
On Sat, May 9, 2026 at 8:47 PM Ethan Nelson-Moore
<enelsonmoore@gmail.com> wrote:
> This commit depends on my previous submission "ARM: <asm/floppy.h>: fix
> build with sparse IRQs".
It also depends on these commits, which I neglected to mention,
because it modifies the same sections of code:
ARM: riscpc: use iomd.h everywhere and remove redundant ioc.h header
ARM: move Risc PC-specific <asm/hardware/iomd.h> header into mach-rpc
^ permalink raw reply
* [PATCH] ARM: riscpc: convert to sparse IRQs
From: Ethan Nelson-Moore @ 2026-05-10 3:46 UTC (permalink / raw)
To: linux-arm-kernel, linux-input
Cc: Ethan Nelson-Moore, Russell King, Dmitry Torokhov,
Russell King (Oracle), Arnd Bergmann, Linus Walleij, Kees Cook,
Nathan Chancellor, Steven Rostedt, Thomas Weissschuh,
Sebastian Andrzej Siewior, Peter Zijlstra
To improve future maintainability, change the interrupt handling for
mach-rpc to use sparse IRQs.
Since the number of possible interrupts is already fixed and relatively
small, just make it use all legacy interrupts preallocated using the
.nr_irqs field in the machine descriptor, rather than actually
allocating domains on the fly.
Several files had to be adjusted to include <mach/irqs.h>
explicitly because it is no longer implicitly included with sparse
IRQs.
Description adapted from commit c78a41fc04f0 ("ARM: s3c24xx: convert
to sparse-irq").
Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
This commit depends on my previous submission "ARM: <asm/floppy.h>: fix
build with sparse IRQs".
arch/arm/Kconfig | 2 +-
arch/arm/mach-rpc/dma.c | 1 +
arch/arm/mach-rpc/ecard.c | 2 +-
arch/arm/mach-rpc/include/mach/irqs.h | 2 +-
arch/arm/mach-rpc/irq.c | 3 ++-
arch/arm/mach-rpc/riscpc.c | 2 ++
arch/arm/mach-rpc/time.c | 1 +
drivers/input/mouse/rpcmouse.c | 2 +-
drivers/input/serio/rpckbd.c | 1 +
9 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 71fc5dd4123f..09b2767fee0f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -153,7 +153,7 @@ config ARM
select PCI_SYSCALL if PCI
select PERF_USE_VMALLOC
select RTC_LIB
- select SPARSE_IRQ if !(ARCH_FOOTBRIDGE || ARCH_RPC)
+ select SPARSE_IRQ if !ARCH_FOOTBRIDGE
select SYS_SUPPORTS_APM_EMULATION
select THREAD_INFO_IN_TASK
select TIMER_OF if OF
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index 717a81475670..238aa59612a8 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -17,6 +17,7 @@
#include <asm/fiq.h>
#include <asm/irq.h>
#include <mach/hardware.h>
+#include <mach/irqs.h>
#include <linux/uaccess.h>
#include <asm/mach/dma.h>
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
index 972465840548..27af35bd6a79 100644
--- a/arch/arm/mach-rpc/ecard.c
+++ b/arch/arm/mach-rpc/ecard.c
@@ -46,9 +46,9 @@
#include <asm/dma.h>
#include <asm/ecard.h>
#include <mach/hardware.h>
+#include <mach/irqs.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
-#include <asm/mach/irq.h>
#include <asm/tlbflush.h>
#include "ecard.h"
diff --git a/arch/arm/mach-rpc/include/mach/irqs.h b/arch/arm/mach-rpc/include/mach/irqs.h
index 0c3428fd9729..738a9457c473 100644
--- a/arch/arm/mach-rpc/include/mach/irqs.h
+++ b/arch/arm/mach-rpc/include/mach/irqs.h
@@ -39,4 +39,4 @@
*/
#define FIQ_START 64
-#define NR_IRQS 128
+#define RPC_NR_IRQS 128
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index 649d81874c86..5e3414fc3657 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -5,6 +5,7 @@
#include <asm/mach/irq.h>
#include <mach/iomd.h>
+#include <mach/irqs.h>
#include <asm/irq.h>
#include <asm/fiq.h>
@@ -177,7 +178,7 @@ void __init rpc_init_irq(void)
set_handle_irq(iomd_handle_irq);
- for (irq = 0; irq < NR_IRQS; irq++) {
+ for (irq = 0; irq < RPC_NR_IRQS; irq++) {
clr = IRQ_NOREQUEST;
set = 0;
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index d068f5e4873d..bdad13226c6d 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -23,6 +23,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/iomd.h>
+#include <mach/irqs.h>
#include <asm/page.h>
#include <asm/domain.h>
#include <asm/setup.h>
@@ -219,6 +220,7 @@ MACHINE_START(RISCPC, "Acorn-RiscPC")
.reserve_lp0 = 1,
.reserve_lp1 = 1,
.map_io = rpc_map_io,
+ .nr_irqs = RPC_NR_IRQS,
.init_irq = rpc_init_irq,
.init_time = ioc_timer_init,
.restart = rpc_restart,
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
index 566113f9774f..02f0fd58c7da 100644
--- a/arch/arm/mach-rpc/time.c
+++ b/arch/arm/mach-rpc/time.c
@@ -18,6 +18,7 @@
#include <mach/hardware.h>
#include <mach/iomd.h>
+#include <mach/irqs.h>
#include <asm/mach/time.h>
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 475c3ca22fd4..cead12069319 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -22,8 +22,8 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/irq.h>
#include <mach/iomd.h>
+#include <mach/irqs.h>
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index e452ad07e2fa..7bcaed28c7a4 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -18,6 +18,7 @@
#include <mach/hardware.h>
#include <mach/iomd.h>
+#include <mach/irqs.h>
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
--
2.43.0
^ permalink raw reply related
* [PATCH] ARM: move Risc PC-specific <asm/hardware/iomd.h> header into mach-rpc
From: Ethan Nelson-Moore @ 2026-05-10 3:10 UTC (permalink / raw)
To: linux-arm-kernel, linux-i2c, linux-input, linux-fbdev
Cc: Russell King, Ethan Nelson-Moore, Andi Shyti, Dmitry Torokhov,
Helge Deller, Kees Cook
The <asm/hardware/iomd.h> header is specific to the IOMD chip used on
the Risc PC. Move it into mach-rpc to avoid polluting asm/hardware/
with machine-specific headers.
Also take the opportunity to remove a comment with the file path from
the header, which is bad style.
Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
MAINTAINERS | 1 -
arch/arm/mach-rpc/dma.c | 2 +-
arch/arm/{include/asm/hardware => mach-rpc/include/mach}/iomd.h | 2 --
arch/arm/mach-rpc/irq.c | 2 +-
arch/arm/mach-rpc/riscpc.c | 2 +-
arch/arm/mach-rpc/time.c | 2 +-
drivers/i2c/busses/i2c-acorn.c | 2 +-
drivers/input/mouse/rpcmouse.c | 2 +-
drivers/input/serio/rpckbd.c | 2 +-
drivers/video/fbdev/acornfb.h | 2 +-
10 files changed, 8 insertions(+), 11 deletions(-)
rename arch/arm/{include/asm/hardware => mach-rpc/include/mach}/iomd.h (98%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 211cc683e25b..6a1da8903c04 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3398,7 +3398,6 @@ M: Russell King <linux@armlinux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
W: http://www.armlinux.org.uk/
-F: arch/arm/include/asm/hardware/iomd.h
F: arch/arm/mach-rpc/
F: drivers/net/ethernet/8390/etherh.c
F: drivers/net/ethernet/i825xx/ether1*
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index 50e0f97afd75..717a81475670 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -20,7 +20,7 @@
#include <linux/uaccess.h>
#include <asm/mach/dma.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
struct iomd_dma {
struct dma_struct dma;
diff --git a/arch/arm/include/asm/hardware/iomd.h b/arch/arm/mach-rpc/include/mach/iomd.h
similarity index 98%
rename from arch/arm/include/asm/hardware/iomd.h
rename to arch/arm/mach-rpc/include/mach/iomd.h
index e3f130345ebc..2a3f4a5f3fd9 100644
--- a/arch/arm/include/asm/hardware/iomd.h
+++ b/arch/arm/mach-rpc/include/mach/iomd.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * arch/arm/include/asm/hardware/iomd.h
- *
* Copyright (C) 1999 Russell King
*
* This file contains information out the IOMD ASIC used in the
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index e924c9b813ab..649d81874c86 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -4,7 +4,7 @@
#include <linux/io.h>
#include <asm/mach/irq.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
#include <asm/irq.h>
#include <asm/fiq.h>
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index f70fb9c4b0cb..d068f5e4873d 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -22,7 +22,7 @@
#include <asm/elf.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
#include <asm/page.h>
#include <asm/domain.h>
#include <asm/setup.h>
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
index ad93c4dfafcd..566113f9774f 100644
--- a/arch/arm/mach-rpc/time.c
+++ b/arch/arm/mach-rpc/time.c
@@ -17,7 +17,7 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
#include <asm/mach/time.h>
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 99b6b1c3fd9e..703b4a42f466 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
#define FORCE_ONES 0xdc
#define SCL 0x02
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 6774029e0a1a..475c3ca22fd4 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -23,7 +23,7 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 4d817850ba3b..e452ad07e2fa 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -17,7 +17,7 @@
#include <linux/slab.h>
#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
diff --git a/drivers/video/fbdev/acornfb.h b/drivers/video/fbdev/acornfb.h
index f8df4ecb4fd7..e65388587f80 100644
--- a/drivers/video/fbdev/acornfb.h
+++ b/drivers/video/fbdev/acornfb.h
@@ -7,7 +7,7 @@
* Frame buffer code for Acorn platforms
*/
#if defined(HAS_VIDC20)
-#include <asm/hardware/iomd.h>
+#include <mach/iomd.h>
#define VIDC_PALETTE_SIZE 256
#define VIDC_NAME "VIDC20"
#endif
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v3 0/9] iio: introduce devm_ API for hid sensro setup and cleanup
From: David Lechner @ 2026-05-09 21:44 UTC (permalink / raw)
To: Sanjay Chitroda, jikos, jic23, srinivas.pandruvada
Cc: nuno.sa, andy, sakari.ailus, linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
On 5/9/26 5:10 AM, Sanjay Chitroda wrote:
> From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
>
> Key highlights:
> - Prepare change as pre-requisite for devm conversion for HID IIO
> drivers by removing redundant argument
> - Add devm API to setup trigger and clenaup resource using
> devm_add_action_or_reset()
> - few cleanup and prepratory changes before updating driver for devm_
> - few sample driver update using devm conversion to auto release resource
>
> changes in v3:
> - Added cleanup and prepratory changes before adding devm_ API
> conversion based on self review: 0002, 0004, 0006, 0007 and 0008
> - Address andy's review comment on commit message and coding style
> - v2 series -> https://lore.kernel.org/all/20260429175918.2541914-1-sanjayembedded@gmail.com/
> changes in v2:
> - Following input from Jonathan and Andy, squash initial patch v1
> series in single change as individual change should not break anything
> - Add devm API support and two driver using the same
> - v1 series -> https://lore.kernel.org/all/20260428071613.1134053-1-sanjayembedded@gmail.com/
>
> Testing:
> - Compiled with W=1
> - Build-tested on QEMU x86_64
>
> Based on further feedback and reviews, I would extend this series to convert all HID IIO driver to use devm_* API.
>
> Thanks,
> Sanjay Chitroda
>
>
> Sanjay Chitroda (9):
> iio: hid-sensors: drop redundant iio_dev argument
> iio: hid-sensors: cleanup codestyle warning
> iio: hid-sensors: introduce device managed API
> iio: gyro: hid-sensor-gyro-3d: cleanup codestyle warning
> iio: gyro: hid-sensor-gyro-3d: drop hid_sensor_remove_trigger() using
> devm API
> iio: humidity: hid-sensor-humidity: cleanup codestyle check
> iio: humidity: hid-sensor-humidity: use common device for devres
> iio: humidity: hid-sensor-humidity: use local struct device
> iio: humidity: hid-sensor-humidity: drop hid_sensor_remove_trigger()
> using devm API
The series would be easier to follow if all of the cleanups
were first and then all of the new code was the last 3
patches.
>
> drivers/iio/accel/hid-sensor-accel-3d.c | 4 +-
> .../common/hid-sensors/hid-sensor-trigger.c | 24 +++++++-
> .../common/hid-sensors/hid-sensor-trigger.h | 5 +-
> drivers/iio/gyro/hid-sensor-gyro-3d.c | 16 ++---
> drivers/iio/humidity/hid-sensor-humidity.c | 61 +++++++++----------
> drivers/iio/light/hid-sensor-als.c | 4 +-
> drivers/iio/light/hid-sensor-prox.c | 4 +-
> drivers/iio/magnetometer/hid-sensor-magn-3d.c | 4 +-
> drivers/iio/orientation/hid-sensor-incl-3d.c | 4 +-
> drivers/iio/orientation/hid-sensor-rotation.c | 4 +-
> .../position/hid-sensor-custom-intel-hinge.c | 4 +-
> drivers/iio/pressure/hid-sensor-press.c | 4 +-
> .../iio/temperature/hid-sensor-temperature.c | 4 +-
> 13 files changed, 78 insertions(+), 64 deletions(-)
>
>
> base-commit: 39b80c5c9830d12d2d6531059001301c4265322a
^ permalink raw reply
* Re: [PATCH v3 4/9] iio: gyro: hid-sensor-gyro-3d: cleanup codestyle warning
From: David Lechner @ 2026-05-09 21:38 UTC (permalink / raw)
To: Sanjay Chitroda, jikos, jic23, srinivas.pandruvada
Cc: nuno.sa, andy, sakari.ailus, linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-5-sanjayembedded@gmail.com>
On 5/9/26 5:10 AM, Sanjay Chitroda wrote:
> From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
>
> Reported by checkpatch:
> FILE: drivers/iio/gyro/hid-sensor-gyro-3d.c
>
> WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
> + unsigned usage_id,
Even better would be to use u32 since this driver already uses
that type.
>
> Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
> ---
> drivers/iio/gyro/hid-sensor-gyro-3d.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
> index fe663b19e902..87537f9c58fb 100644
> --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
> +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
> @@ -187,7 +187,7 @@ static const struct iio_info gyro_3d_info = {
>
> /* Callback handler to send event after all samples are received and captured */
> static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
> - unsigned usage_id,
> + unsigned int usage_id,
> void *priv)
> {
> struct iio_dev *indio_dev = platform_get_drvdata(priv);
> @@ -209,7 +209,7 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
>
> /* Capture samples in local storage */
> static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
> - unsigned usage_id,
> + unsigned int usage_id,
> size_t raw_len, char *raw_data,
> void *priv)
> {
> @@ -244,7 +244,7 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
> static int gyro_3d_parse_report(struct platform_device *pdev,
> struct hid_sensor_hub_device *hsdev,
> struct iio_chan_spec *channels,
> - unsigned usage_id,
> + unsigned int usage_id,
> struct gyro_3d_state *st)
> {
> int ret;
^ permalink raw reply
* Re: [PATCH v3 2/9] iio: hid-sensors: cleanup codestyle warning
From: David Lechner @ 2026-05-09 21:35 UTC (permalink / raw)
To: Sanjay Chitroda, jikos, jic23, srinivas.pandruvada
Cc: nuno.sa, andy, sakari.ailus, linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-3-sanjayembedded@gmail.com>
On 5/9/26 5:10 AM, Sanjay Chitroda wrote:
> From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
>
> Reported by checkpatch:
> FILE: drivers/iio/common/hid-sensors/hid-sensor-trigger.c
checkpatch (or any other linter) says so is not a good reason
for a change. They are suggestions, not requirements. If the code
is improved, say why this is better. I.e. improve readability.
>
> WARNING: Missing a blank line after declarations
>
> Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
> ---
> drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> index 28d050b45c74..98fadc61a68a 100644
> --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
> @@ -313,7 +313,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev)
> {
> struct iio_dev *indio_dev = dev_get_drvdata(dev);
> struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
> +
> schedule_work(&attrb->work);
> +
> return 0;
> }
>
> @@ -321,6 +323,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
> {
> struct iio_dev *indio_dev = dev_get_drvdata(dev);
> struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
> +
> return _hid_sensor_power_state(attrb, true);
> }
>
^ permalink raw reply
* Re: [PATCH v3 1/9] iio: hid-sensors: drop redundant iio_dev argument
From: David Lechner @ 2026-05-09 21:32 UTC (permalink / raw)
To: Sanjay Chitroda, jikos, jic23, srinivas.pandruvada
Cc: nuno.sa, andy, sakari.ailus, linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-2-sanjayembedded@gmail.com>
On 5/9/26 5:10 AM, Sanjay Chitroda wrote:
> From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
>
> hid_sensor_remove_trigger() uses struct hid_sensor_common to release
> resources acquired during trigger setup.
>
> Earlier implementations required struct iio_dev to clean up buffers,
> but with the current code this argument is no longer used and is
> redundant.
>
> Adapt to hid_sensor_remove_trigger() API change across all HID IIO
> drivers to match updated prototype.
>
> Removing it simplifies the API and is a preparatory step toward
> converting the trigger handling to a devm-based API.
The subject and commit message don't make sense to me. It looks like
it is just removing an unused argument.
Code looks fine though.
^ permalink raw reply
* Re: [PATCH v3 7/9] iio: humidity: hid-sensor-humidity: use common device for devres
From: sashiko-bot @ 2026-05-09 13:06 UTC (permalink / raw)
To: Sanjay Chitroda; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260509101040.791404-8-sanjayembedded@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Use-After-Free due to lifetime mismatch between IIO device and platform device devres
--
commit 2edcf899b7cb430d80f56a0ef1506dd20ea46d9d
Author: Sanjay Chitroda <sanjayembeddedse@gmail.com>
iio: humidity: hid-sensor-humidity: use common device for devres
This commit changes the devres allocation of humidity channels to use the
platform device instead of the IIO device. The goal is to have a single,
well-defined parent device for devres ownership.
> diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
> --- a/drivers/iio/humidity/hid-sensor-humidity.c
> +++ b/drivers/iio/humidity/hid-sensor-humidity.c
> @@ -215,7 +215,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
> + humid_chans = devm_kmemdup(&pdev->dev, humidity_channels,
> sizeof(humidity_channels), GFP_KERNEL);
Could this change introduce a use-after-free if the IIO device outlives the
driver binding?
The indio_dev object is allocated using devm_iio_device_alloc(), meaning it is
reference-counted and its lifetime can exceed the platform device binding if
consumers hold a reference.
If the driver unbinds, the pdev devres callbacks will execute and free the
humid_chans memory. However, indio_dev->channels still points to this freed
array.
If a consumer later calls IIO APIs like iio_read_channel_ext_info(), they
will dereference the freed humid_chans memory.
> if (!humid_chans)
> return -ENOMEM;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509101040.791404-1-sanjayembedded@gmail.com?part=7
^ permalink raw reply
* Re: [PATCH v3 1/9] iio: hid-sensors: drop redundant iio_dev argument
From: sashiko-bot @ 2026-05-09 10:42 UTC (permalink / raw)
To: Sanjay Chitroda; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260509101040.791404-2-sanjayembedded@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] This problem wasn't introduced by this patch, but the removal sequence across HID IIO drivers cancels asynchronous suspend requests, leaving the hardware powered on, which violates PM subsystem guidelines.
- [High] This problem wasn't introduced by this patch, but in `hid-sensor-temperature.c`, the trigger is manually unregistered and freed in the `remove` callback while the IIO device is still active and registered, creating a use-after-free vulnerability.
--
commit 774f02b73d8b538afc5af51312b8682afec55f98
Author: Sanjay Chitroda <sanjayembeddedse@gmail.com>
iio: hid-sensors: drop redundant iio_dev argument
This commit removes the unused iio_dev argument from
hid_sensor_remove_trigger() across all HID IIO drivers, adapting the
function prototype to simplify the API for a future devm-based conversion.
> diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
> index 2ff591b3458f7..a63dae90dadc5 100644
> --- a/drivers/iio/accel/hid-sensor-accel-3d.c
> +++ b/drivers/iio/accel/hid-sensor-accel-3d.c
[ ... ]
> @@ -429,7 +429,7 @@ static void hid_accel_3d_remove(struct platform_device *pdev)
>
> sensor_hub_remove_callback(hsdev, hsdev->usage);
> iio_device_unregister(indio_dev);
> - hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
> + hid_sensor_remove_trigger(&accel_state->common_attributes);
> }
This problem wasn't introduced by this patch, but could this removal sequence
leave the hardware powered on?
Looking at the removal path across these drivers, iio_device_unregister()
disables the IIO buffers, which eventually calls hid_sensor_power_state()
and queues an asynchronous suspend via pm_runtime_put_autosuspend().
Immediately afterward, hid_sensor_remove_trigger() calls
pm_runtime_disable(). Does calling pm_runtime_disable() immediately after an
async put cancel the pending suspend work, leaving the physical device active
while marking it suspended in the PM core?
[ ... ]
> diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
> index 9f628a8e5cfbe..60d4fcc8043b6 100644
> --- a/drivers/iio/temperature/hid-sensor-temperature.c
> +++ b/drivers/iio/temperature/hid-sensor-temperature.c
[ ... ]
> @@ -265,7 +265,7 @@ static void hid_temperature_remove(struct platform_device *pdev)
> struct temperature_state *temp_st = iio_priv(indio_dev);
>
> sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
> - hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
> + hid_sensor_remove_trigger(&temp_st->common_attributes);
> }
This problem also wasn't introduced by this patch, but is there a
use-after-free risk in this specific driver's removal sequence?
The temperature driver uses devm_iio_device_register() to register the IIO
device, which means the device unregistration is deferred until the devres
cleanup phase after hid_temperature_remove() returns.
However, hid_sensor_remove_trigger() is called manually here and it calls
iio_trigger_free(). Since the IIO device remains fully registered and exposed
to user-space until devres runs, could concurrent sysfs access or buffer
operations dereference the freed trigger pointer?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509101040.791404-1-sanjayembedded@gmail.com?part=1
^ permalink raw reply
* Re: [PATCH] HID: mcp2221: fix OOB write in mcp2221_raw_event()
From: sashiko-bot @ 2026-05-09 10:36 UTC (permalink / raw)
To: Florian Pradines; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260509094517.2691246-1-florian.pradines@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] The patch adds a size bound but leaves a dangling pointer in `mcp->rxbuf` when a read times out, resulting in a Use-After-Free.
- [High] Unsynchronized updates to `mcp->rxbuf` and `mcp->rxbuf_size` allow an attacker to bypass the new bounds check completely, causing an Out-Of-Bounds (OOB) write.
- [High] The patch fails to prevent stack buffer overflows for `I2C_SMBUS_BLOCK_DATA` reads because it bases `mcp->rxbuf_size` on uninitialized stack memory.
- [High] The raw event handler blindly accesses payload data without validating against the actual received HID report size, leading to out-of-bounds kernel heap reads.
--
commit 2cea5cadcf6c54079354cc3c519d5621e3b06d74
Author: Florian Pradines <florian.pradines@gmail.com>
HID: mcp2221: fix OOB write in mcp2221_raw_event()
This commit attempts to fix an out-of-bounds write in mcp2221_raw_event()
by adding a rxbuf_size field. It sets this field alongside rxbuf in
mcp_i2c_smbus_read() and validates the incoming data length against it
before copying.
> diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
> index be80970ab48e2..e4ddd8e9293b6 100644
> --- a/drivers/hid/hid-mcp2221.c
> +++ b/drivers/hid/hid-mcp2221.c
[ ... ]
> @@ -330,12 +331,14 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
> mcp->txbuf[3] = (u8)(msg->addr << 1);
> total_len = msg->len;
> mcp->rxbuf = msg->buf;
> + mcp->rxbuf_size = msg->len;
> } else {
> mcp->txbuf[1] = smbus_len;
> mcp->txbuf[2] = 0;
> mcp->txbuf[3] = (u8)(smbus_addr << 1);
> total_len = smbus_len;
> mcp->rxbuf = smbus_buf;
> + mcp->rxbuf_size = smbus_len;
Does this code fail to prevent stack buffer overflows for
I2C_SMBUS_BLOCK_DATA reads?
In i2c_smbus_read_block_data(), the i2c_smbus_data union is allocated
on the stack but its first byte (data.block[0]) is not initialized before
the read. In mcp_smbus_xfer(), the driver uses data->block[0] + 1 to
determine the read length, which is then assigned here to mcp->rxbuf_size.
If this uninitialized stack memory contains a large value (e.g., 255), the
new bounds check will pass for large responses, and memcpy can write past
the 34-byte data->block array, overflowing the stack.
Also, are these updates to mcp->rxbuf and mcp->rxbuf_size safe from
concurrent access?
These are updated non-atomically in process context, while
mcp2221_raw_event() runs asynchronously.
If a previous read timed out leaving rxbuf_idx = 0 and rxbuf_size = 60,
could a late 60-byte response arrive just after mcp->rxbuf is assigned a new
2-byte buffer but before mcp->rxbuf_size is updated to 2?
This would cause the event handler to read the old rxbuf_size (60), pass the
check, and copy 60 bytes into the 2-byte buffer, bypassing the protection.
> }
>
> ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
If mcp_send_data_req_status() times out, it returns -ETIMEDOUT without
setting mcp->rxbuf to NULL.
If the caller then frees or pops the buffer, and a delayed or malicious
MCP2221_I2C_GET_DATA report is processed by mcp2221_raw_event(), could this
result in a use-after-free?
Since rxbuf is not NULL and rxbuf_idx < rxbuf_size, the new check passes,
and memcpy would write data directly into the freed memory.
[ ... ]
> @@ -919,6 +922,10 @@ static int mcp2221_raw_event(struct hid_device *hdev,
> mcp->status = -EINVAL;
> break;
> }
> + if (mcp->rxbuf_idx + data[3] > mcp->rxbuf_size) {
> + mcp->status = -EINVAL;
> + break;
> + }
> buf = mcp->rxbuf;
> memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
This isn't a regression from this patch, but does the raw event handler
blindly access payload data without validating against the actual received
HID report size?
The mcp2221_raw_event() function receives a size parameter representing the
length of the HID report but ignores it.
If a malicious USB device presents a HID report descriptor with a small
maximum report size (e.g., 4 bytes), the HID core will allocate a 4-byte
buffer.
If the device then sends data[3] = 60, this memcpy will read 60 bytes past
the end of the 4-byte kernel heap buffer, potentially leaking adjacent
kernel memory to user-space.
> mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509094517.2691246-1-florian.pradines@gmail.com?part=1
^ permalink raw reply
* [PATCH v3 9/9] iio: humidity: hid-sensor-humidity: drop hid_sensor_remove_trigger() using devm API
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Use devm_hid_sensor_setup_trigger() to automatically release resources
during failure, unbind or removal of driver using devres framework.
This is done in a way to simplify the setup, remove goto and avoid manual
resource cleanup in teardown path.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
changes in v3:
- Update commit message based on review comment from Andy
- Based on discussion using parent device of HID platform driver used
with devres framework for this driver
- v2 link -> https://lore.kernel.org/all/20260429175918.2541914-5-sanjayembedded@gmail.com/
---
drivers/iio/humidity/hid-sensor-humidity.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index d310ec43a118..4d4282e4b6e4 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -234,8 +234,8 @@ static int hid_humidity_probe(struct platform_device *pdev)
atomic_set(&humid_st->common_attributes.data_ready, 0);
- ret = hid_sensor_setup_trigger(indio_dev, name,
- &humid_st->common_attributes);
+ ret = devm_hid_sensor_setup_trigger(dev, indio_dev, name,
+ &humid_st->common_attributes);
if (ret)
return ret;
@@ -245,7 +245,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
&humidity_callbacks);
if (ret)
- goto error_remove_trigger;
+ return ret;
ret = iio_device_register(indio_dev);
if (ret)
@@ -255,8 +255,6 @@ static int hid_humidity_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
-error_remove_trigger:
- hid_sensor_remove_trigger(&humid_st->common_attributes);
return ret;
}
@@ -265,11 +263,9 @@ static void hid_humidity_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct hid_humidity_state *humid_st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
- hid_sensor_remove_trigger(&humid_st->common_attributes);
}
static const struct platform_device_id hid_humidity_ids[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 8/9] iio: humidity: hid-sensor-humidity: use local struct device
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Introduce a local struct device pointer derived from &pdev->dev.
This avoids repeated &pdev->dev usage and improves readability.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/humidity/hid-sensor-humidity.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index 18d4e376376d..d310ec43a118 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -196,10 +196,11 @@ static int hid_humidity_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct hid_humidity_state *humid_st;
struct iio_chan_spec *humid_chans;
- struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct hid_sensor_hub_device *hsdev = dev_get_platdata(dev);
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*humid_st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*humid_st));
if (!indio_dev)
return -ENOMEM;
@@ -215,7 +216,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
if (ret)
return ret;
- humid_chans = devm_kmemdup(&pdev->dev, humidity_channels,
+ humid_chans = devm_kmemdup(dev, humidity_channels,
sizeof(humidity_channels), GFP_KERNEL);
if (!humid_chans)
return -ENOMEM;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 7/9] iio: humidity: hid-sensor-humidity: use common device for devres
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
kmemdup() is used for memory that is logically tied to the HID
platform device, even though the driver binds into the IIO framework.
Using &indio_dev->dev for devres allocations works functionally, but it
results in two separate devres ownership trees—one for the HID
platform device (pdev) and another for the IIO device (indio_dev).
The devres framework is intended to have a single, well-defined parent
device. Since the memory originates from HID sensor probing and is not
IIO-specific, &pdev->dev is the correct and logical owner.
Switch to using the platform device for devm_kmemdup() so that all
resources are released deterministically and consistently.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/humidity/hid-sensor-humidity.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index 968dd8d4bb35..18d4e376376d 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -215,7 +215,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
if (ret)
return ret;
- humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
+ humid_chans = devm_kmemdup(&pdev->dev, humidity_channels,
sizeof(humidity_channels), GFP_KERNEL);
if (!humid_chans)
return -ENOMEM;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 6/9] iio: humidity: hid-sensor-humidity: cleanup codestyle check
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Reported by checkpatch:
FILE: drivers/iio/humidity/hid-sensor-humidity.c
CHECK: Alignment should match open parenthesis
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/humidity/hid-sensor-humidity.c | 46 +++++++++++-----------
1 file changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index e580a2af9562..968dd8d4bb35 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -45,7 +45,7 @@ static const struct iio_chan_spec humidity_channels[] = {
/* Adjust channel real bits based on report descriptor */
static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
+ int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -55,8 +55,8 @@ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
}
static int humidity_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -101,8 +101,8 @@ static int humidity_read_raw(struct iio_dev *indio_dev,
}
static int humidity_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -127,7 +127,7 @@ static const struct iio_info humidity_info = {
/* Callback handler to send event after all samples are received and captured */
static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, void *pdev)
+ unsigned int usage_id, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -141,8 +141,8 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, size_t raw_len,
- char *raw_data, void *pdev)
+ unsigned int usage_id, size_t raw_len,
+ char *raw_data, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -159,17 +159,17 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id */
static int humidity_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned int usage_id,
- struct hid_humidity_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ unsigned int usage_id,
+ struct hid_humidity_state *st)
{
int ret;
ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
- usage_id,
- HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
- &st->humidity_attr);
+ usage_id,
+ HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
+ &st->humidity_attr);
if (ret < 0)
return ret;
@@ -208,20 +208,20 @@ static int hid_humidity_probe(struct platform_device *pdev)
humid_st->common_attributes.pdev = pdev;
ret = hid_sensor_parse_common_attributes(hsdev,
- HID_USAGE_SENSOR_HUMIDITY,
- &humid_st->common_attributes,
- humidity_sensitivity_addresses,
- ARRAY_SIZE(humidity_sensitivity_addresses));
+ HID_USAGE_SENSOR_HUMIDITY,
+ &humid_st->common_attributes,
+ humidity_sensitivity_addresses,
+ ARRAY_SIZE(humidity_sensitivity_addresses));
if (ret)
return ret;
humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
- sizeof(humidity_channels), GFP_KERNEL);
+ sizeof(humidity_channels), GFP_KERNEL);
if (!humid_chans)
return -ENOMEM;
ret = humidity_parse_report(pdev, hsdev, humid_chans,
- HID_USAGE_SENSOR_HUMIDITY, humid_st);
+ HID_USAGE_SENSOR_HUMIDITY, humid_st);
if (ret)
return ret;
@@ -234,7 +234,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
atomic_set(&humid_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &humid_st->common_attributes);
+ &humid_st->common_attributes);
if (ret)
return ret;
@@ -242,7 +242,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
humidity_callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
- &humidity_callbacks);
+ &humidity_callbacks);
if (ret)
goto error_remove_trigger;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 5/9] iio: gyro: hid-sensor-gyro-3d: drop hid_sensor_remove_trigger() using devm API
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Use devm_hid_sensor_setup_trigger() to automatically release resource
during fail, unbind or removal of driver using devres framework.
This simplify the setup, remove goto, avoid manual resource cleanup in
teardown path.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/gyro/hid-sensor-gyro-3d.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 87537f9c58fb..72e7db8ce3b2 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -326,8 +326,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
atomic_set(&gyro_state->common_attributes.data_ready, 0);
- ret = hid_sensor_setup_trigger(indio_dev, name,
- &gyro_state->common_attributes);
+ ret = devm_hid_sensor_setup_trigger(&pdev->dev, indio_dev, name,
+ &gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
@@ -336,7 +336,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
+ return ret;
}
gyro_state->callbacks.send_event = gyro_3d_proc_event;
@@ -353,8 +353,6 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
-error_remove_trigger:
- hid_sensor_remove_trigger(&gyro_state->common_attributes);
return ret;
}
@@ -363,11 +361,9 @@ static void hid_gyro_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(&gyro_state->common_attributes);
}
static const struct platform_device_id hid_gyro_3d_ids[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 4/9] iio: gyro: hid-sensor-gyro-3d: cleanup codestyle warning
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Reported by checkpatch:
FILE: drivers/iio/gyro/hid-sensor-gyro-3d.c
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
+ unsigned usage_id,
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/gyro/hid-sensor-gyro-3d.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index fe663b19e902..87537f9c58fb 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -187,7 +187,7 @@ static const struct iio_info gyro_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
+ unsigned int usage_id,
void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
@@ -209,7 +209,7 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
+ unsigned int usage_id,
size_t raw_len, char *raw_data,
void *priv)
{
@@ -244,7 +244,7 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
static int gyro_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
- unsigned usage_id,
+ unsigned int usage_id,
struct gyro_3d_state *st)
{
int ret;
--
2.34.1
^ permalink raw reply related
* [PATCH v3 3/9] iio: hid-sensors: introduce device managed API
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
hid_sensor_setup_trigger() is common API used for the HID IIO drivers,
prepare devm API devm_hid_sensor_setup_trigger() to acquire resource
during setup and release using device managed framework during drivers
fail, unbind or remove path.
Register action with devm_add_action_or_reset() to release resource with
devres framework.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
Changes in v3:
- Remove cast and update function based on review comment from Andy
- v2 link -> https://lore.kernel.org/all/20260429175918.2541914-3-sanjayembedded@gmail.com/
---
.../common/hid-sensors/hid-sensor-trigger.c | 18 ++++++++++++++++++
.../common/hid-sensors/hid-sensor-trigger.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 98fadc61a68a..fb6a4587ae03 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -301,6 +301,24 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
}
EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID");
+static void hid_sensor_remove_trigger_action(void *attrb)
+{
+ hid_sensor_remove_trigger(attrb);
+}
+
+int devm_hid_sensor_setup_trigger(struct device *dev, struct iio_dev *indio_dev,
+ const char *name, struct hid_sensor_common *attrb)
+{
+ int ret;
+
+ ret = hid_sensor_setup_trigger(indio_dev, name, attrb);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, hid_sensor_remove_trigger_action, attrb);
+}
+EXPORT_SYMBOL_NS(devm_hid_sensor_setup_trigger, "IIO_HID");
+
static int __maybe_unused hid_sensor_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index afec46ecbe71..6fd7c39a240d 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -17,6 +17,8 @@ extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
+int devm_hid_sensor_setup_trigger(struct device *dev, struct iio_dev *indio_dev,
+ const char *name, struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/9] iio: hid-sensors: cleanup codestyle warning
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Reported by checkpatch:
FILE: drivers/iio/common/hid-sensors/hid-sensor-trigger.c
WARNING: Missing a blank line after declarations
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 28d050b45c74..98fadc61a68a 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -313,7 +313,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
schedule_work(&attrb->work);
+
return 0;
}
@@ -321,6 +323,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
return _hid_sensor_power_state(attrb, true);
}
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/9] iio: hid-sensors: drop redundant iio_dev argument
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
In-Reply-To: <20260509101040.791404-1-sanjayembedded@gmail.com>
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
hid_sensor_remove_trigger() uses struct hid_sensor_common to release
resources acquired during trigger setup.
Earlier implementations required struct iio_dev to clean up buffers,
but with the current code this argument is no longer used and is
redundant.
Adapt to hid_sensor_remove_trigger() API change across all HID IIO
drivers to match updated prototype.
Removing it simplifies the API and is a preparatory step toward
converting the trigger handling to a devm-based API.
Signed-off-by: Sanjay Chitroda <sanjayembeddedse@gmail.com>
---
drivers/iio/accel/hid-sensor-accel-3d.c | 4 ++--
drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 3 +--
drivers/iio/common/hid-sensors/hid-sensor-trigger.h | 3 +--
drivers/iio/gyro/hid-sensor-gyro-3d.c | 4 ++--
drivers/iio/humidity/hid-sensor-humidity.c | 4 ++--
drivers/iio/light/hid-sensor-als.c | 4 ++--
drivers/iio/light/hid-sensor-prox.c | 4 ++--
drivers/iio/magnetometer/hid-sensor-magn-3d.c | 4 ++--
drivers/iio/orientation/hid-sensor-incl-3d.c | 4 ++--
drivers/iio/orientation/hid-sensor-rotation.c | 4 ++--
drivers/iio/position/hid-sensor-custom-intel-hinge.c | 4 ++--
drivers/iio/pressure/hid-sensor-press.c | 4 ++--
drivers/iio/temperature/hid-sensor-temperature.c | 4 ++--
13 files changed, 24 insertions(+), 26 deletions(-)
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 2ff591b3458f..a63dae90dadc 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -416,7 +416,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
+ hid_sensor_remove_trigger(&accel_state->common_attributes);
return ret;
}
@@ -429,7 +429,7 @@ static void hid_accel_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
+ hid_sensor_remove_trigger(&accel_state->common_attributes);
}
static const struct platform_device_id hid_accel_3d_ids[] = {
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 417c4ab8c1b2..28d050b45c74 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -218,8 +218,7 @@ static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = {
.predisable = buffer_predisable,
};
-void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
- struct hid_sensor_common *attrb)
+void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
if (atomic_read(&attrb->runtime_pm_enable))
pm_runtime_disable(&attrb->pdev->dev);
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index f94fca4f1edf..afec46ecbe71 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -16,8 +16,7 @@ extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb);
-void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
- struct hid_sensor_common *attrb);
+void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
#endif
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index c340cc899a7c..fe663b19e902 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -354,7 +354,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
+ hid_sensor_remove_trigger(&gyro_state->common_attributes);
return ret;
}
@@ -367,7 +367,7 @@ static void hid_gyro_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
+ hid_sensor_remove_trigger(&gyro_state->common_attributes);
}
static const struct platform_device_id hid_gyro_3d_ids[] = {
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index be2338d5f407..e580a2af9562 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -255,7 +255,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
+ hid_sensor_remove_trigger(&humid_st->common_attributes);
return ret;
}
@@ -268,7 +268,7 @@ static void hid_humidity_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
- hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
+ hid_sensor_remove_trigger(&humid_st->common_attributes);
}
static const struct platform_device_id hid_humidity_ids[] = {
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 384572844162..9b57cdced18a 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -432,7 +432,7 @@ static int hid_als_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
+ hid_sensor_remove_trigger(&als_state->common_attributes);
return ret;
}
@@ -445,7 +445,7 @@ static void hid_als_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
+ hid_sensor_remove_trigger(&als_state->common_attributes);
}
static const struct platform_device_id hid_als_ids[] = {
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index efa904a70d0e..473c45626487 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -340,7 +340,7 @@ static int hid_prox_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
return ret;
}
@@ -353,7 +353,7 @@ static void hid_prox_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
}
static const struct platform_device_id hid_prox_ids[] = {
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index b01dd53eb100..8be3dfe4dd58 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -542,7 +542,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
+ hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
return ret;
}
@@ -555,7 +555,7 @@ static void hid_magn_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
+ hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
}
static const struct platform_device_id hid_magn_3d_ids[] = {
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 4e23a598a3fb..56fd9c53dfc2 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -378,7 +378,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
+ hid_sensor_remove_trigger(&incl_state->common_attributes);
return ret;
}
@@ -391,7 +391,7 @@ static void hid_incl_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
+ hid_sensor_remove_trigger(&incl_state->common_attributes);
}
static const struct platform_device_id hid_incl_3d_ids[] = {
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index 4a11e4555099..56fdb3412fe3 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -353,7 +353,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
+ hid_sensor_remove_trigger(&rot_state->common_attributes);
return ret;
}
@@ -366,7 +366,7 @@ static void hid_dev_rot_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
+ hid_sensor_remove_trigger(&rot_state->common_attributes);
}
static const struct platform_device_id hid_dev_rot_ids[] = {
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index a26d391661fd..5288b63f4e21 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -337,7 +337,7 @@ static int hid_hinge_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
+ hid_sensor_remove_trigger(&st->common_attributes);
return ret;
}
@@ -350,7 +350,7 @@ static void hid_hinge_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, hsdev->usage);
- hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
+ hid_sensor_remove_trigger(&st->common_attributes);
}
static const struct platform_device_id hid_hinge_ids[] = {
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 5f1d6abda3e4..2bf5d055e175 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -319,7 +319,7 @@ static int hid_press_probe(struct platform_device *pdev)
error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
+ hid_sensor_remove_trigger(&press_state->common_attributes);
return ret;
}
@@ -332,7 +332,7 @@ static void hid_press_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
- hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
+ hid_sensor_remove_trigger(&press_state->common_attributes);
}
static const struct platform_device_id hid_press_ids[] = {
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index 9f628a8e5cfb..60d4fcc8043b 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -253,7 +253,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
error_remove_callback:
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
error_remove_trigger:
- hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
+ hid_sensor_remove_trigger(&temp_st->common_attributes);
return ret;
}
@@ -265,7 +265,7 @@ static void hid_temperature_remove(struct platform_device *pdev)
struct temperature_state *temp_st = iio_priv(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
- hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
+ hid_sensor_remove_trigger(&temp_st->common_attributes);
}
static const struct platform_device_id hid_temperature_ids[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/9] iio: introduce devm_ API for hid sensro setup and cleanup
From: Sanjay Chitroda @ 2026-05-09 10:10 UTC (permalink / raw)
To: jikos, jic23, srinivas.pandruvada
Cc: dlechner, nuno.sa, andy, sanjayembeddedse, sakari.ailus,
linux-input, linux-iio, linux-kernel
From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
Key highlights:
- Prepare change as pre-requisite for devm conversion for HID IIO
drivers by removing redundant argument
- Add devm API to setup trigger and clenaup resource using
devm_add_action_or_reset()
- few cleanup and prepratory changes before updating driver for devm_
- few sample driver update using devm conversion to auto release resource
changes in v3:
- Added cleanup and prepratory changes before adding devm_ API
conversion based on self review: 0002, 0004, 0006, 0007 and 0008
- Address andy's review comment on commit message and coding style
- v2 series -> https://lore.kernel.org/all/20260429175918.2541914-1-sanjayembedded@gmail.com/
changes in v2:
- Following input from Jonathan and Andy, squash initial patch v1
series in single change as individual change should not break anything
- Add devm API support and two driver using the same
- v1 series -> https://lore.kernel.org/all/20260428071613.1134053-1-sanjayembedded@gmail.com/
Testing:
- Compiled with W=1
- Build-tested on QEMU x86_64
Based on further feedback and reviews, I would extend this series to convert all HID IIO driver to use devm_* API.
Thanks,
Sanjay Chitroda
Sanjay Chitroda (9):
iio: hid-sensors: drop redundant iio_dev argument
iio: hid-sensors: cleanup codestyle warning
iio: hid-sensors: introduce device managed API
iio: gyro: hid-sensor-gyro-3d: cleanup codestyle warning
iio: gyro: hid-sensor-gyro-3d: drop hid_sensor_remove_trigger() using
devm API
iio: humidity: hid-sensor-humidity: cleanup codestyle check
iio: humidity: hid-sensor-humidity: use common device for devres
iio: humidity: hid-sensor-humidity: use local struct device
iio: humidity: hid-sensor-humidity: drop hid_sensor_remove_trigger()
using devm API
drivers/iio/accel/hid-sensor-accel-3d.c | 4 +-
.../common/hid-sensors/hid-sensor-trigger.c | 24 +++++++-
.../common/hid-sensors/hid-sensor-trigger.h | 5 +-
drivers/iio/gyro/hid-sensor-gyro-3d.c | 16 ++---
drivers/iio/humidity/hid-sensor-humidity.c | 61 +++++++++----------
drivers/iio/light/hid-sensor-als.c | 4 +-
drivers/iio/light/hid-sensor-prox.c | 4 +-
drivers/iio/magnetometer/hid-sensor-magn-3d.c | 4 +-
drivers/iio/orientation/hid-sensor-incl-3d.c | 4 +-
drivers/iio/orientation/hid-sensor-rotation.c | 4 +-
.../position/hid-sensor-custom-intel-hinge.c | 4 +-
drivers/iio/pressure/hid-sensor-press.c | 4 +-
.../iio/temperature/hid-sensor-temperature.c | 4 +-
13 files changed, 78 insertions(+), 64 deletions(-)
base-commit: 39b80c5c9830d12d2d6531059001301c4265322a
--
2.34.1
^ permalink raw reply
* Re: [PATCH] Input: analog: replace deprecated simple_strtoul() with kstrtouint()
From: David Laight @ 2026-05-09 9:55 UTC (permalink / raw)
To: Akash Sukhavasi; +Cc: dmitry.torokhov, linux-input, linux-kernel
In-Reply-To: <20260509024048.46132-1-akash.sukhavasi@gmail.com>
On Fri, 8 May 2026 21:40:48 -0500
Akash Sukhavasi <akash.sukhavasi@gmail.com> wrote:
> The simple_strtoul() function is deprecated because it ignores
> trailing garbage characters, which can mask typos in input.
>
> Replace it with kstrtouint() in analog_parse_options() to enforce
> strict input parsing.
>
> Note that this introduces a minor, intended behavior change: while
> the old code would silently parse a malformed string like "12abc"
> as 12, the new code will reject it entirely and fall back to the
> unconfigured state (0xff). This strict parsing is the preferred
> modern behavior for kernel parameters.
However that might break existing systems.
So I'm not at all sure it should be done.
David
>
> Signed-off-by: Akash Sukhavasi <akash.sukhavasi@gmail.com>
> ---
> drivers/input/joystick/analog.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
> index b6f7bce1c..07ad360f8 100644
> --- a/drivers/input/joystick/analog.c
> +++ b/drivers/input/joystick/analog.c
> @@ -653,7 +653,7 @@ static struct analog_types analog_types[] = {
> static void analog_parse_options(void)
> {
> int i, j;
> - char *end;
> + unsigned int parsed_val;
>
> for (i = 0; i < js_nargs; i++) {
>
> @@ -664,8 +664,10 @@ static void analog_parse_options(void)
> }
> if (analog_types[j].name) continue;
>
> - analog_options[i] = simple_strtoul(js[i], &end, 0);
> - if (end != js[i]) continue;
> + if (kstrtouint(js[i], 0, &parsed_val) == 0) {
> + analog_options[i] = parsed_val;
> + continue;
> + }
>
> analog_options[i] = 0xff;
> if (!strlen(js[i])) continue;
^ permalink raw reply
* [PATCH] HID: mcp2221: fix OOB write in mcp2221_raw_event()
From: Florian Pradines @ 2026-05-09 9:45 UTC (permalink / raw)
To: gupt21, jikos, bentiss; +Cc: linux-i2c, linux-input, Florian Pradines
mcp2221_raw_event() copies device-supplied data into mcp->rxbuf at
offset rxbuf_idx without checking that the copy fits within the
destination buffer. A device responding with up to 60 bytes to a
small I2C/SMBus read can overflow the buffer.
Add a rxbuf_size field to struct mcp2221, set it alongside rxbuf in
mcp_i2c_smbus_read(), and check rxbuf_idx + data[3] <= rxbuf_size
before the memcpy.
Signed-off-by: Florian Pradines <florian.pradines@gmail.com>
---
drivers/hid/hid-mcp2221.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index be80970ab48e..e4ddd8e9293b 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -128,6 +128,7 @@ struct mcp2221 {
u8 *rxbuf;
u8 txbuf[64];
int rxbuf_idx;
+ int rxbuf_size;
int status;
u8 cur_i2c_clk_div;
struct gpio_chip *gc;
@@ -330,12 +331,14 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
mcp->txbuf[3] = (u8)(msg->addr << 1);
total_len = msg->len;
mcp->rxbuf = msg->buf;
+ mcp->rxbuf_size = msg->len;
} else {
mcp->txbuf[1] = smbus_len;
mcp->txbuf[2] = 0;
mcp->txbuf[3] = (u8)(smbus_addr << 1);
total_len = smbus_len;
mcp->rxbuf = smbus_buf;
+ mcp->rxbuf_size = smbus_len;
}
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
@@ -919,6 +922,10 @@ static int mcp2221_raw_event(struct hid_device *hdev,
mcp->status = -EINVAL;
break;
}
+ if (mcp->rxbuf_idx + data[3] > mcp->rxbuf_size) {
+ mcp->status = -EINVAL;
+ break;
+ }
buf = mcp->rxbuf;
memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
--
2.47.3
^ permalink raw reply related
* [PATCH] HID: i2c-hid: add reset quirk for BLTP7853 touchpad
From: Xu Rao @ 2026-05-09 8:21 UTC (permalink / raw)
To: jikos, bentiss; +Cc: linux-input, linux-kernel, raoxu
The BLTP7853 I2C HID touchpad may fail to probe after reboot or
reprobe because reset completion is not signalled to the host. The
driver then waits for the reset-complete interrupt until it times out
and the device probe fails:
i2c_hid i2c-BLTP7853:00: failed to reset device.
i2c_hid i2c-BLTP7853:00: can't add hid device: -61
i2c_hid: probe of i2c-BLTP7853:00 failed with error -61
Add I2C_HID_QUIRK_NO_IRQ_AFTER_RESET for the device so i2c-hid does
not wait for a reset interrupt that may never arrive.
Signed-off-by: Xu Rao <raoxu@uniontech.com>
---
drivers/hid/hid-ids.h | 3 +++
drivers/hid/i2c-hid/i2c-hid-core.c | 2 ++
2 files changed, 5 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0cf63742315b..dcb0b34cd069 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -277,6 +277,9 @@
#define USB_VENDOR_ID_BIGBEN 0x146b
#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902
+#define I2C_VENDOR_ID_BLTP 0x36b6
+#define I2C_PRODUCT_ID_BLTP7853 0xc001
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 5a183af3d5c6..baff2728603e 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -149,6 +149,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_BOGUS_IRQ },
{ I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_0D42,
I2C_HID_QUIRK_DELAY_WAKEUP_AFTER_RESUME },
+ { I2C_VENDOR_ID_BLTP, I2C_PRODUCT_ID_BLTP7853,
+ I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
{ 0, 0 }
};
--
2.50.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox