File Index
Files and directories
Sign in
FILE

input-poller.c

File preview with syntax highlighting.

linux-6.19.14/drivers/input/input-poller.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Support for polling mode for input devices.
  4 */
  5
  6#include <linux/device.h>
  7#include <linux/export.h>
  8#include <linux/input.h>
  9#include <linux/jiffies.h>
 10#include <linux/mutex.h>
 11#include <linux/slab.h>
 12#include <linux/types.h>
 13#include <linux/workqueue.h>
 14#include "input-poller.h"
 15
 16struct input_dev_poller {
 17	void (*poll)(struct input_dev *dev);
 18
 19	unsigned int poll_interval; /* msec */
 20	unsigned int poll_interval_max; /* msec */
 21	unsigned int poll_interval_min; /* msec */
 22
 23	struct input_dev *input;
 24	struct delayed_work work;
 25};
 26
 27static void input_dev_poller_queue_work(struct input_dev_poller *poller)
 28{
 29	unsigned long delay;
 30
 31	delay = msecs_to_jiffies(poller->poll_interval);
 32	if (delay >= HZ)
 33		delay = round_jiffies_relative(delay);
 34
 35	queue_delayed_work(system_freezable_wq, &poller->work, delay);
 36}
 37
 38static void input_dev_poller_work(struct work_struct *work)
 39{
 40	struct input_dev_poller *poller =
 41		container_of(work, struct input_dev_poller, work.work);
 42
 43	poller->poll(poller->input);
 44	input_dev_poller_queue_work(poller);
 45}
 46
 47void input_dev_poller_finalize(struct input_dev_poller *poller)
 48{
 49	if (!poller->poll_interval)
 50		poller->poll_interval = 500;
 51	if (!poller->poll_interval_max)
 52		poller->poll_interval_max = poller->poll_interval;
 53}
 54
 55void input_dev_poller_start(struct input_dev_poller *poller)
 56{
 57	/* Only start polling if polling is enabled */
 58	if (poller->poll_interval > 0) {
 59		poller->poll(poller->input);
 60		input_dev_poller_queue_work(poller);
 61	}
 62}
 63
 64void input_dev_poller_stop(struct input_dev_poller *poller)
 65{
 66	cancel_delayed_work_sync(&poller->work);
 67}
 68
 69int input_setup_polling(struct input_dev *dev,
 70			void (*poll_fn)(struct input_dev *dev))
 71{
 72	struct input_dev_poller *poller;
 73
 74	poller = kzalloc(sizeof(*poller), GFP_KERNEL);
 75	if (!poller) {
 76		/*
 77		 * We want to show message even though kzalloc() may have
 78		 * printed backtrace as knowing what instance of input
 79		 * device we were dealing with is helpful.
 80		 */
 81		dev_err(dev->dev.parent ?: &dev->dev,
 82			"%s: unable to allocate poller structure\n", __func__);
 83		return -ENOMEM;
 84	}
 85
 86	INIT_DELAYED_WORK(&poller->work, input_dev_poller_work);
 87	poller->input = dev;
 88	poller->poll = poll_fn;
 89
 90	dev->poller = poller;
 91	return 0;
 92}
 93EXPORT_SYMBOL(input_setup_polling);
 94
 95static bool input_dev_ensure_poller(struct input_dev *dev)
 96{
 97	if (!dev->poller) {
 98		dev_err(dev->dev.parent ?: &dev->dev,
 99			"poller structure has not been set up\n");
100		return false;
101	}
102
103	return true;
104}
105
106void input_set_poll_interval(struct input_dev *dev, unsigned int interval)
107{
108	if (input_dev_ensure_poller(dev))
109		dev->poller->poll_interval = interval;
110}
111EXPORT_SYMBOL(input_set_poll_interval);
112
113void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval)
114{
115	if (input_dev_ensure_poller(dev))
116		dev->poller->poll_interval_min = interval;
117}
118EXPORT_SYMBOL(input_set_min_poll_interval);
119
120void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval)
121{
122	if (input_dev_ensure_poller(dev))
123		dev->poller->poll_interval_max = interval;
124}
125EXPORT_SYMBOL(input_set_max_poll_interval);
126
127int input_get_poll_interval(struct input_dev *dev)
128{
129	if (!dev->poller)
130		return -EINVAL;
131
132	return dev->poller->poll_interval;
133}
134EXPORT_SYMBOL(input_get_poll_interval);
135
136/* SYSFS interface */
137
138static ssize_t input_dev_get_poll_interval(struct device *dev,
139					   struct device_attribute *attr,
140					   char *buf)
141{
142	struct input_dev *input = to_input_dev(dev);
143
144	return sprintf(buf, "%d\n", input->poller->poll_interval);
145}
146
147static ssize_t input_dev_set_poll_interval(struct device *dev,
148					   struct device_attribute *attr,
149					   const char *buf, size_t count)
150{
151	struct input_dev *input = to_input_dev(dev);
152	struct input_dev_poller *poller = input->poller;
153	unsigned int interval;
154	int err;
155
156	err = kstrtouint(buf, 0, &interval);
157	if (err)
158		return err;
159
160	if (interval < poller->poll_interval_min)
161		return -EINVAL;
162
163	if (interval > poller->poll_interval_max)
164		return -EINVAL;
165
166	guard(mutex)(&input->mutex);
167
168	poller->poll_interval = interval;
169
170	if (input_device_enabled(input)) {
171		cancel_delayed_work_sync(&poller->work);
172		if (poller->poll_interval > 0)
173			input_dev_poller_queue_work(poller);
174	}
175
176	return count;
177}
178
179static DEVICE_ATTR(poll, 0644,
180		   input_dev_get_poll_interval, input_dev_set_poll_interval);
181
182static ssize_t input_dev_get_poll_max(struct device *dev,
183				      struct device_attribute *attr, char *buf)
184{
185	struct input_dev *input = to_input_dev(dev);
186
187	return sprintf(buf, "%d\n", input->poller->poll_interval_max);
188}
189
190static DEVICE_ATTR(max, 0444, input_dev_get_poll_max, NULL);
191
192static ssize_t input_dev_get_poll_min(struct device *dev,
193				     struct device_attribute *attr, char *buf)
194{
195	struct input_dev *input = to_input_dev(dev);
196
197	return sprintf(buf, "%d\n", input->poller->poll_interval_min);
198}
199
200static DEVICE_ATTR(min, 0444, input_dev_get_poll_min, NULL);
201
202static umode_t input_poller_attrs_visible(struct kobject *kobj,
203					  struct attribute *attr, int n)
204{
205	struct device *dev = kobj_to_dev(kobj);
206	struct input_dev *input = to_input_dev(dev);
207
208	return input->poller ? attr->mode : 0;
209}
210
211static struct attribute *input_poller_attrs[] = {
212	&dev_attr_poll.attr,
213	&dev_attr_max.attr,
214	&dev_attr_min.attr,
215	NULL
216};
217
218struct attribute_group input_poller_attribute_group = {
219	.is_visible	= input_poller_attrs_visible,
220	.attrs		= input_poller_attrs,
221};
~/ Read-only file preview.