[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <C1C54D7FA3DF3958+20250710073148.3994900-1-wangyuli@uniontech.com>
Date: Thu, 10 Jul 2025 15:31:38 +0800
From: WangYuli <wangyuli@...ontech.com>
To: wangyuli@...ontech.com
Cc: dmitry.torokhov@...il.com,
guanwentao@...ontech.com,
linux-input@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-trace-kernel@...r.kernel.org,
mathieu.desnoyers@...icios.com,
mhiramat@...nel.org,
niecheng1@...ontech.com,
rostedt@...dmis.org,
wangyuli@...pin.org,
zhanjun@...ontech.com,
Winston Wen <wentao@...ontech.com>
Subject: [PATCH 1/2] input: Add tracepoint support
Introduce a set of tracepoints for the input subsystem to enable
better debugging, monitoring, and performance analysis of input
device operations.
Suggested-by: Winston Wen <wentao@...ontech.com>
Signed-off-by: WangYuli <wangyuli@...ontech.com>
---
MAINTAINERS | 1 +
drivers/input/input.c | 18 ++-
include/trace/events/input.h | 251 +++++++++++++++++++++++++++++++++++
3 files changed, 269 insertions(+), 1 deletion(-)
create mode 100644 include/trace/events/input.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 00d7dcee88cb..c1b03679a5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11933,6 +11933,7 @@ F: include/linux/i8042.h
F: include/linux/input.h
F: include/linux/input/
F: include/linux/libps2.h
+F: include/trace/events/input.h
F: include/linux/serio.h
F: include/uapi/linux/gameport.h
F: include/uapi/linux/input-event-codes.h
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 44887e51e049..925c76a50742 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -29,6 +29,9 @@
#include "input-core-private.h"
#include "input-poller.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/input.h>
+
MODULE_AUTHOR("Vojtech Pavlik <vojtech@...e.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
@@ -363,6 +366,7 @@ void input_handle_event(struct input_dev *dev,
disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT) {
+ trace_input_event(dev, type, code, value);
if (type != EV_SYN)
add_input_randomness(type, code, value);
@@ -525,6 +529,7 @@ int input_grab_device(struct input_handle *handle)
return -EBUSY;
rcu_assign_pointer(dev->grab, handle);
+ trace_input_grab_device(dev, handle);
}
return 0;
@@ -539,6 +544,7 @@ static void __input_release_device(struct input_handle *handle)
grabber = rcu_dereference_protected(dev->grab,
lockdep_is_held(&dev->mutex));
if (grabber == handle) {
+ trace_input_release_device(dev, handle);
rcu_assign_pointer(dev->grab, NULL);
/* Make sure input_pass_values() notices that grab is gone */
synchronize_rcu();
@@ -612,6 +618,7 @@ int input_open_device(struct input_handle *handle)
if (dev->poller)
input_dev_poller_start(dev->poller);
+ trace_input_open_device(dev);
}
return 0;
@@ -652,6 +659,7 @@ void input_close_device(struct input_handle *handle)
input_dev_poller_stop(dev->poller);
if (dev->close)
dev->close(dev);
+ trace_input_close_device(dev);
}
}
@@ -991,9 +999,13 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
return -ENODEV;
error = handler->connect(handler, dev, id);
- if (error && error != -ENODEV)
+ if (error && error != -ENODEV) {
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
+ } else if (!error) {
+ /* Connection successful, trace it */
+ trace_input_handler_connect(handler, dev, handler->minor);
+ }
return error;
}
@@ -1791,6 +1803,7 @@ static int input_inhibit_device(struct input_dev *dev)
}
dev->inhibited = true;
+ trace_input_inhibit_device(dev);
return 0;
}
@@ -1818,6 +1831,7 @@ static int input_uninhibit_device(struct input_dev *dev)
scoped_guard(spinlock_irq, &dev->event_lock)
input_dev_toggle(dev, true);
+ trace_input_uninhibit_device(dev);
return 0;
}
@@ -2216,6 +2230,7 @@ static void __input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;
+ trace_input_device_unregister(dev);
input_disconnect_device(dev);
scoped_guard(mutex, &input_mutex) {
@@ -2414,6 +2429,7 @@ int input_register_device(struct input_dev *dev)
input_wakeup_procfs_readers();
}
+ trace_input_device_register(dev);
if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&dev->dev));
diff --git a/include/trace/events/input.h b/include/trace/events/input.h
new file mode 100644
index 000000000000..3c5ffcfb7c8d
--- /dev/null
+++ b/include/trace/events/input.h
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* input tracepoints
+ *
+ * Copyright (C) 2025 WangYuli <wangyuli@...ontech.com>
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM input
+
+#if !defined(_TRACE_INPUT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INPUT_H
+
+#include <linux/tracepoint.h>
+#include <linux/input.h>
+
+/**
+ * input_event - called when an input event is processed
+ * @dev: input device that generated the event
+ * @type: event type (EV_KEY, EV_REL, EV_ABS, etc.)
+ * @code: event code within the type
+ * @value: event value
+ *
+ * This tracepoint fires for every input event processed by the input core.
+ * It can be used to monitor input device activity and debug input issues.
+ */
+TRACE_EVENT(
+ input_event,
+
+ TP_PROTO(struct input_dev *dev, unsigned int type, unsigned int code,
+ int value),
+
+ TP_ARGS(dev, type, code, value),
+
+ TP_STRUCT__entry(__string(name, dev->name ?: "unknown") __field(
+ unsigned int, type) __field(unsigned int, code)
+ __field(int, value) __field(u16, bustype)
+ __field(u16, vendor)
+ __field(u16, product)),
+
+ TP_fast_assign(__assign_str(name); __entry->type = type;
+ __entry->code = code; __entry->value = value;
+ __entry->bustype = dev->id.bustype;
+ __entry->vendor = dev->id.vendor;
+ __entry->product = dev->id.product;),
+
+ TP_printk(
+ "dev=%s type=%u code=%u value=%d bus=%04x vendor=%04x product=%04x",
+ __get_str(name), __entry->type, __entry->code, __entry->value,
+ __entry->bustype, __entry->vendor, __entry->product));
+
+/**
+ * input_device_register - called when an input device is registered
+ * @dev: input device being registered
+ *
+ * This tracepoint fires when a new input device is registered with the
+ * input subsystem. Useful for monitoring device hotplug events.
+ */
+TRACE_EVENT(
+ input_device_register,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev),
+
+ TP_STRUCT__entry(__string(name, dev->name ?: "unknown") __string(
+ phys, dev->phys ?: "") __field(u16, bustype)
+ __field(u16, vendor) __field(u16, product)
+ __field(u16, version)),
+
+ TP_fast_assign(__assign_str(name); __assign_str(phys);
+ __entry->bustype = dev->id.bustype;
+ __entry->vendor = dev->id.vendor;
+ __entry->product = dev->id.product;
+ __entry->version = dev->id.version;),
+
+ TP_printk(
+ "dev=%s phys=%s bus=%04x vendor=%04x product=%04x version=%04x",
+ __get_str(name), __get_str(phys), __entry->bustype,
+ __entry->vendor, __entry->product, __entry->version));
+
+/**
+ * input_device_unregister - called when an input device is unregistered
+ * @dev: input device being unregistered
+ *
+ * This tracepoint fires when an input device is unregistered from the
+ * input subsystem. Useful for monitoring device hotplug events.
+ */
+TRACE_EVENT(input_device_unregister,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev),
+
+ TP_STRUCT__entry(__string(name, dev->name ?: "unknown") __string(
+ phys, dev->phys ?: "") __field(u16, bustype)
+ __field(u16, vendor)
+ __field(u16, product)),
+
+ TP_fast_assign(__assign_str(name); __assign_str(phys);
+ __entry->bustype = dev->id.bustype;
+ __entry->vendor = dev->id.vendor;
+ __entry->product = dev->id.product;),
+
+ TP_printk("dev=%s phys=%s bus=%04x vendor=%04x product=%04x",
+ __get_str(name), __get_str(phys), __entry->bustype,
+ __entry->vendor, __entry->product));
+
+/**
+ * input_handler_connect - called when an input handler connects to a device
+ * @handler: input handler
+ * @dev: input device
+ * @minor: assigned minor number (if applicable)
+ *
+ * This tracepoint fires when an input handler (like evdev, mousedev) connects
+ * to an input device, creating a new input handle.
+ */
+TRACE_EVENT(input_handler_connect,
+
+ TP_PROTO(struct input_handler *handler, struct input_dev *dev,
+ int minor),
+
+ TP_ARGS(handler, dev, minor),
+
+ TP_STRUCT__entry(__string(handler_name, handler->name)
+ __string(dev_name, dev->name ?: "unknown")
+ __field(int, minor)),
+
+ TP_fast_assign(__assign_str(handler_name); __assign_str(dev_name);
+ __entry->minor = minor;),
+
+ TP_printk("handler=%s dev=%s minor=%d", __get_str(handler_name),
+ __get_str(dev_name), __entry->minor));
+
+/**
+ * input_grab_device - called when a device is grabbed by a handler
+ * @dev: input device being grabbed
+ * @handle: input handle doing the grab
+ *
+ * This tracepoint fires when an input device is grabbed exclusively
+ * by an input handler, typically for security or special processing.
+ */
+TRACE_EVENT(input_grab_device,
+
+ TP_PROTO(struct input_dev *dev, struct input_handle *handle),
+
+ TP_ARGS(dev, handle),
+
+ TP_STRUCT__entry(__string(dev_name, dev->name ?: "unknown")
+ __string(handler_name,
+ handle->handler->name)),
+
+ TP_fast_assign(__assign_str(dev_name); __assign_str(handler_name);),
+
+ TP_printk("dev=%s grabbed_by=%s", __get_str(dev_name),
+ __get_str(handler_name)));
+
+/**
+ * input_release_device - called when a grabbed device is released
+ * @dev: input device being released
+ * @handle: input handle releasing the grab
+ *
+ * This tracepoint fires when an input device grab is released.
+ */
+TRACE_EVENT(input_release_device,
+
+ TP_PROTO(struct input_dev *dev, struct input_handle *handle),
+
+ TP_ARGS(dev, handle),
+
+ TP_STRUCT__entry(__string(dev_name, dev->name ?: "unknown")
+ __string(handler_name,
+ handle->handler->name)),
+
+ TP_fast_assign(__assign_str(dev_name); __assign_str(handler_name);),
+
+ TP_printk("dev=%s released_by=%s", __get_str(dev_name),
+ __get_str(handler_name)));
+
+DECLARE_EVENT_CLASS(input_device_state,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev),
+
+ TP_STRUCT__entry(__string(name, dev->name ?: "unknown")
+ __field(unsigned int, users)
+ __field(bool, inhibited)),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->users = dev->users;
+ __entry->inhibited = dev->inhibited;),
+
+ TP_printk("dev=%s users=%u inhibited=%s", __get_str(name),
+ __entry->users,
+ __entry->inhibited ? "true" : "false"));
+
+/**
+ * input_open_device - called when an input device is opened
+ * @dev: input device being opened
+ *
+ * This tracepoint fires when the user count for an input device increases,
+ * typically when a userspace application opens the device.
+ */
+DEFINE_EVENT(input_device_state, input_open_device,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev));
+
+/**
+ * input_close_device - called when an input device is closed
+ * @dev: input device being closed
+ *
+ * This tracepoint fires when the user count for an input device decreases,
+ * typically when a userspace application closes the device.
+ */
+DEFINE_EVENT(input_device_state, input_close_device,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev));
+
+/**
+ * input_inhibit_device - called when an input device is inhibited
+ * @dev: input device being inhibited
+ *
+ * This tracepoint fires when an input device is inhibited (disabled),
+ * usually for power management or security reasons.
+ */
+DEFINE_EVENT(input_device_state, input_inhibit_device,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev));
+
+/**
+ * input_uninhibit_device - called when an input device is uninhibited
+ * @dev: input device being uninhibited
+ *
+ * This tracepoint fires when an input device is uninhibited (re-enabled)
+ * after being previously inhibited.
+ */
+DEFINE_EVENT(input_device_state, input_uninhibit_device,
+
+ TP_PROTO(struct input_dev *dev),
+
+ TP_ARGS(dev));
+
+#endif /* _TRACE_INPUT_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.50.0
Powered by blists - more mailing lists