18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for polling mode for input devices. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/device.h> 78c2ecf20Sopenharmony_ci#include <linux/input.h> 88c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 98c2ecf20Sopenharmony_ci#include <linux/mutex.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 138c2ecf20Sopenharmony_ci#include "input-poller.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct input_dev_poller { 168c2ecf20Sopenharmony_ci void (*poll)(struct input_dev *dev); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci unsigned int poll_interval; /* msec */ 198c2ecf20Sopenharmony_ci unsigned int poll_interval_max; /* msec */ 208c2ecf20Sopenharmony_ci unsigned int poll_interval_min; /* msec */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci struct input_dev *input; 238c2ecf20Sopenharmony_ci struct delayed_work work; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void input_dev_poller_queue_work(struct input_dev_poller *poller) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci unsigned long delay; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci delay = msecs_to_jiffies(poller->poll_interval); 318c2ecf20Sopenharmony_ci if (delay >= HZ) 328c2ecf20Sopenharmony_ci delay = round_jiffies_relative(delay); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci queue_delayed_work(system_freezable_wq, &poller->work, delay); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void input_dev_poller_work(struct work_struct *work) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct input_dev_poller *poller = 408c2ecf20Sopenharmony_ci container_of(work, struct input_dev_poller, work.work); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci poller->poll(poller->input); 438c2ecf20Sopenharmony_ci input_dev_poller_queue_work(poller); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_civoid input_dev_poller_finalize(struct input_dev_poller *poller) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci if (!poller->poll_interval) 498c2ecf20Sopenharmony_ci poller->poll_interval = 500; 508c2ecf20Sopenharmony_ci if (!poller->poll_interval_max) 518c2ecf20Sopenharmony_ci poller->poll_interval_max = poller->poll_interval; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_civoid input_dev_poller_start(struct input_dev_poller *poller) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci /* Only start polling if polling is enabled */ 578c2ecf20Sopenharmony_ci if (poller->poll_interval > 0) { 588c2ecf20Sopenharmony_ci poller->poll(poller->input); 598c2ecf20Sopenharmony_ci input_dev_poller_queue_work(poller); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_civoid input_dev_poller_stop(struct input_dev_poller *poller) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&poller->work); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciint input_setup_polling(struct input_dev *dev, 698c2ecf20Sopenharmony_ci void (*poll_fn)(struct input_dev *dev)) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct input_dev_poller *poller; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci poller = kzalloc(sizeof(*poller), GFP_KERNEL); 748c2ecf20Sopenharmony_ci if (!poller) { 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * We want to show message even though kzalloc() may have 778c2ecf20Sopenharmony_ci * printed backtrace as knowing what instance of input 788c2ecf20Sopenharmony_ci * device we were dealing with is helpful. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci dev_err(dev->dev.parent ?: &dev->dev, 818c2ecf20Sopenharmony_ci "%s: unable to allocate poller structure\n", __func__); 828c2ecf20Sopenharmony_ci return -ENOMEM; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&poller->work, input_dev_poller_work); 868c2ecf20Sopenharmony_ci poller->input = dev; 878c2ecf20Sopenharmony_ci poller->poll = poll_fn; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci dev->poller = poller; 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(input_setup_polling); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic bool input_dev_ensure_poller(struct input_dev *dev) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (!dev->poller) { 978c2ecf20Sopenharmony_ci dev_err(dev->dev.parent ?: &dev->dev, 988c2ecf20Sopenharmony_ci "poller structure has not been set up\n"); 998c2ecf20Sopenharmony_ci return false; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return true; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_civoid input_set_poll_interval(struct input_dev *dev, unsigned int interval) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci if (input_dev_ensure_poller(dev)) 1088c2ecf20Sopenharmony_ci dev->poller->poll_interval = interval; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(input_set_poll_interval); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_civoid input_set_min_poll_interval(struct input_dev *dev, unsigned int interval) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci if (input_dev_ensure_poller(dev)) 1158c2ecf20Sopenharmony_ci dev->poller->poll_interval_min = interval; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(input_set_min_poll_interval); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid input_set_max_poll_interval(struct input_dev *dev, unsigned int interval) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if (input_dev_ensure_poller(dev)) 1228c2ecf20Sopenharmony_ci dev->poller->poll_interval_max = interval; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(input_set_max_poll_interval); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint input_get_poll_interval(struct input_dev *dev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (!dev->poller) 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return dev->poller->poll_interval; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(input_get_poll_interval); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* SYSFS interface */ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic ssize_t input_dev_get_poll_interval(struct device *dev, 1388c2ecf20Sopenharmony_ci struct device_attribute *attr, 1398c2ecf20Sopenharmony_ci char *buf) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct input_dev *input = to_input_dev(dev); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", input->poller->poll_interval); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic ssize_t input_dev_set_poll_interval(struct device *dev, 1478c2ecf20Sopenharmony_ci struct device_attribute *attr, 1488c2ecf20Sopenharmony_ci const char *buf, size_t count) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct input_dev *input = to_input_dev(dev); 1518c2ecf20Sopenharmony_ci struct input_dev_poller *poller = input->poller; 1528c2ecf20Sopenharmony_ci unsigned int interval; 1538c2ecf20Sopenharmony_ci int err; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci err = kstrtouint(buf, 0, &interval); 1568c2ecf20Sopenharmony_ci if (err) 1578c2ecf20Sopenharmony_ci return err; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (interval < poller->poll_interval_min) 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (interval > poller->poll_interval_max) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mutex_lock(&input->mutex); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci poller->poll_interval = interval; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (input->users) { 1708c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&poller->work); 1718c2ecf20Sopenharmony_ci if (poller->poll_interval > 0) 1728c2ecf20Sopenharmony_ci input_dev_poller_queue_work(poller); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci mutex_unlock(&input->mutex); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return count; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(poll, 0644, 1818c2ecf20Sopenharmony_ci input_dev_get_poll_interval, input_dev_set_poll_interval); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic ssize_t input_dev_get_poll_max(struct device *dev, 1848c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct input_dev *input = to_input_dev(dev); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", input->poller->poll_interval_max); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max, 0444, input_dev_get_poll_max, NULL); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic ssize_t input_dev_get_poll_min(struct device *dev, 1948c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct input_dev *input = to_input_dev(dev); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", input->poller->poll_interval_min); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic DEVICE_ATTR(min, 0444, input_dev_get_poll_min, NULL); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic umode_t input_poller_attrs_visible(struct kobject *kobj, 2048c2ecf20Sopenharmony_ci struct attribute *attr, int n) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 2078c2ecf20Sopenharmony_ci struct input_dev *input = to_input_dev(dev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return input->poller ? attr->mode : 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic struct attribute *input_poller_attrs[] = { 2138c2ecf20Sopenharmony_ci &dev_attr_poll.attr, 2148c2ecf20Sopenharmony_ci &dev_attr_max.attr, 2158c2ecf20Sopenharmony_ci &dev_attr_min.attr, 2168c2ecf20Sopenharmony_ci NULL 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistruct attribute_group input_poller_attribute_group = { 2208c2ecf20Sopenharmony_ci .is_visible = input_poller_attrs_visible, 2218c2ecf20Sopenharmony_ci .attrs = input_poller_attrs, 2228c2ecf20Sopenharmony_ci}; 223