linux/drivers/input/input-polldev.c
<<
>>
Prefs
   1/*
   2 * Generic implementation of a polled input device
   3
   4 * Copyright (c) 2007 Dmitry Torokhov
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 */
  10
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12
  13#include <linux/jiffies.h>
  14#include <linux/slab.h>
  15#include <linux/mutex.h>
  16#include <linux/workqueue.h>
  17#include <linux/module.h>
  18#include <linux/input-polldev.h>
  19
  20MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
  21MODULE_DESCRIPTION("Generic implementation of a polled input device");
  22MODULE_LICENSE("GPL v2");
  23MODULE_VERSION("0.1");
  24
  25static void input_polldev_queue_work(struct input_polled_dev *dev)
  26{
  27        unsigned long delay;
  28
  29        delay = msecs_to_jiffies(dev->poll_interval);
  30        if (delay >= HZ)
  31                delay = round_jiffies_relative(delay);
  32
  33        queue_delayed_work(system_freezable_wq, &dev->work, delay);
  34}
  35
  36static void input_polled_device_work(struct work_struct *work)
  37{
  38        struct input_polled_dev *dev =
  39                container_of(work, struct input_polled_dev, work.work);
  40
  41        dev->poll(dev);
  42        input_polldev_queue_work(dev);
  43}
  44
  45static int input_open_polled_device(struct input_dev *input)
  46{
  47        struct input_polled_dev *dev = input_get_drvdata(input);
  48
  49        if (dev->open)
  50                dev->open(dev);
  51
  52        /* Only start polling if polling is enabled */
  53        if (dev->poll_interval > 0) {
  54                dev->poll(dev);
  55                input_polldev_queue_work(dev);
  56        }
  57
  58        return 0;
  59}
  60
  61static void input_close_polled_device(struct input_dev *input)
  62{
  63        struct input_polled_dev *dev = input_get_drvdata(input);
  64
  65        cancel_delayed_work_sync(&dev->work);
  66
  67        if (dev->close)
  68                dev->close(dev);
  69}
  70
  71/* SYSFS interface */
  72
  73static ssize_t input_polldev_get_poll(struct device *dev,
  74                                      struct device_attribute *attr, char *buf)
  75{
  76        struct input_polled_dev *polldev = dev_get_drvdata(dev);
  77
  78        return sprintf(buf, "%d\n", polldev->poll_interval);
  79}
  80
  81static ssize_t input_polldev_set_poll(struct device *dev,
  82                                struct device_attribute *attr, const char *buf,
  83                                size_t count)
  84{
  85        struct input_polled_dev *polldev = dev_get_drvdata(dev);
  86        struct input_dev *input = polldev->input;
  87        unsigned int interval;
  88        int err;
  89
  90        err = kstrtouint(buf, 0, &interval);
  91        if (err)
  92                return err;
  93
  94        if (interval < polldev->poll_interval_min)
  95                return -EINVAL;
  96
  97        if (interval > polldev->poll_interval_max)
  98                return -EINVAL;
  99
 100        mutex_lock(&input->mutex);
 101
 102        polldev->poll_interval = interval;
 103
 104        if (input->users) {
 105                cancel_delayed_work_sync(&polldev->work);
 106                if (polldev->poll_interval > 0)
 107                        input_polldev_queue_work(polldev);
 108        }
 109
 110        mutex_unlock(&input->mutex);
 111
 112        return count;
 113}
 114
 115static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll,
 116                                            input_polldev_set_poll);
 117
 118
 119static ssize_t input_polldev_get_max(struct device *dev,
 120                                     struct device_attribute *attr, char *buf)
 121{
 122        struct input_polled_dev *polldev = dev_get_drvdata(dev);
 123
 124        return sprintf(buf, "%d\n", polldev->poll_interval_max);
 125}
 126
 127static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL);
 128
 129static ssize_t input_polldev_get_min(struct device *dev,
 130                                     struct device_attribute *attr, char *buf)
 131{
 132        struct input_polled_dev *polldev = dev_get_drvdata(dev);
 133
 134        return sprintf(buf, "%d\n", polldev->poll_interval_min);
 135}
 136
 137static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL);
 138
 139static struct attribute *sysfs_attrs[] = {
 140        &dev_attr_poll.attr,
 141        &dev_attr_max.attr,
 142        &dev_attr_min.attr,
 143        NULL
 144};
 145
 146static struct attribute_group input_polldev_attribute_group = {
 147        .attrs = sysfs_attrs
 148};
 149
 150/**
 151 * input_allocate_polled_device - allocate memory for polled device
 152 *
 153 * The function allocates memory for a polled device and also
 154 * for an input device associated with this polled device.
 155 */
 156struct input_polled_dev *input_allocate_polled_device(void)
 157{
 158        struct input_polled_dev *dev;
 159
 160        dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
 161        if (!dev)
 162                return NULL;
 163
 164        dev->input = input_allocate_device();
 165        if (!dev->input) {
 166                kfree(dev);
 167                return NULL;
 168        }
 169
 170        return dev;
 171}
 172EXPORT_SYMBOL(input_allocate_polled_device);
 173
 174/**
 175 * input_free_polled_device - free memory allocated for polled device
 176 * @dev: device to free
 177 *
 178 * The function frees memory allocated for polling device and drops
 179 * reference to the associated input device.
 180 */
 181void input_free_polled_device(struct input_polled_dev *dev)
 182{
 183        if (dev) {
 184                input_free_device(dev->input);
 185                kfree(dev);
 186        }
 187}
 188EXPORT_SYMBOL(input_free_polled_device);
 189
 190/**
 191 * input_register_polled_device - register polled device
 192 * @dev: device to register
 193 *
 194 * The function registers previously initialized polled input device
 195 * with input layer. The device should be allocated with call to
 196 * input_allocate_polled_device(). Callers should also set up poll()
 197 * method and set up capabilities (id, name, phys, bits) of the
 198 * corresponding input_dev structure.
 199 */
 200int input_register_polled_device(struct input_polled_dev *dev)
 201{
 202        struct input_dev *input = dev->input;
 203        int error;
 204
 205        input_set_drvdata(input, dev);
 206        INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
 207        if (!dev->poll_interval)
 208                dev->poll_interval = 500;
 209        if (!dev->poll_interval_max)
 210                dev->poll_interval_max = dev->poll_interval;
 211        input->open = input_open_polled_device;
 212        input->close = input_close_polled_device;
 213
 214        error = input_register_device(input);
 215        if (error)
 216                return error;
 217
 218        error = sysfs_create_group(&input->dev.kobj,
 219                                   &input_polldev_attribute_group);
 220        if (error) {
 221                input_unregister_device(input);
 222                return error;
 223        }
 224
 225        /*
 226         * Take extra reference to the underlying input device so
 227         * that it survives call to input_unregister_polled_device()
 228         * and is deleted only after input_free_polled_device()
 229         * has been invoked. This is needed to ease task of freeing
 230         * sparse keymaps.
 231         */
 232        input_get_device(input);
 233
 234        return 0;
 235}
 236EXPORT_SYMBOL(input_register_polled_device);
 237
 238/**
 239 * input_unregister_polled_device - unregister polled device
 240 * @dev: device to unregister
 241 *
 242 * The function unregisters previously registered polled input
 243 * device from input layer. Polling is stopped and device is
 244 * ready to be freed with call to input_free_polled_device().
 245 */
 246void input_unregister_polled_device(struct input_polled_dev *dev)
 247{
 248        sysfs_remove_group(&dev->input->dev.kobj,
 249                           &input_polldev_attribute_group);
 250
 251        input_unregister_device(dev->input);
 252}
 253EXPORT_SYMBOL(input_unregister_polled_device);
 254
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.