|
@@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void)
|
|
|
mutex_unlock(&polldev_mutex);
|
|
|
}
|
|
|
|
|
|
-static void input_polled_device_work(struct work_struct *work)
|
|
|
+static void input_polldev_queue_work(struct input_polled_dev *dev)
|
|
|
{
|
|
|
- struct input_polled_dev *dev =
|
|
|
- container_of(work, struct input_polled_dev, work.work);
|
|
|
unsigned long delay;
|
|
|
|
|
|
- dev->poll(dev);
|
|
|
-
|
|
|
delay = msecs_to_jiffies(dev->poll_interval);
|
|
|
if (delay >= HZ)
|
|
|
delay = round_jiffies_relative(delay);
|
|
@@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work)
|
|
|
queue_delayed_work(polldev_wq, &dev->work, delay);
|
|
|
}
|
|
|
|
|
|
+static void input_polled_device_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct input_polled_dev *dev =
|
|
|
+ container_of(work, struct input_polled_dev, work.work);
|
|
|
+
|
|
|
+ dev->poll(dev);
|
|
|
+ input_polldev_queue_work(dev);
|
|
|
+}
|
|
|
+
|
|
|
static int input_open_polled_device(struct input_dev *input)
|
|
|
{
|
|
|
struct input_polled_dev *dev = input_get_drvdata(input);
|
|
@@ -100,6 +105,83 @@ static void input_close_polled_device(struct input_dev *input)
|
|
|
dev->close(dev);
|
|
|
}
|
|
|
|
|
|
+/* SYSFS interface */
|
|
|
+
|
|
|
+static ssize_t input_polldev_get_poll(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct input_polled_dev *polldev = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "%d\n", polldev->poll_interval);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t input_polldev_set_poll(struct device *dev,
|
|
|
+ struct device_attribute *attr, const char *buf,
|
|
|
+ size_t count)
|
|
|
+{
|
|
|
+ struct input_polled_dev *polldev = dev_get_drvdata(dev);
|
|
|
+ struct input_dev *input = polldev->input;
|
|
|
+ unsigned long interval;
|
|
|
+
|
|
|
+ if (strict_strtoul(buf, 0, &interval))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (interval < polldev->poll_interval_min)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (interval > polldev->poll_interval_max)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mutex_lock(&input->mutex);
|
|
|
+
|
|
|
+ polldev->poll_interval = interval;
|
|
|
+
|
|
|
+ if (input->users) {
|
|
|
+ cancel_delayed_work_sync(&polldev->work);
|
|
|
+ if (polldev->poll_interval > 0)
|
|
|
+ input_polldev_queue_work(polldev);
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&input->mutex);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll,
|
|
|
+ input_polldev_set_poll);
|
|
|
+
|
|
|
+
|
|
|
+static ssize_t input_polldev_get_max(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct input_polled_dev *polldev = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "%d\n", polldev->poll_interval_max);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL);
|
|
|
+
|
|
|
+static ssize_t input_polldev_get_min(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct input_polled_dev *polldev = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "%d\n", polldev->poll_interval_min);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL);
|
|
|
+
|
|
|
+static struct attribute *sysfs_attrs[] = {
|
|
|
+ &dev_attr_poll.attr,
|
|
|
+ &dev_attr_max.attr,
|
|
|
+ &dev_attr_min.attr,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group input_polldev_attribute_group = {
|
|
|
+ .attrs = sysfs_attrs
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* input_allocate_polled_device - allocated memory polled device
|
|
|
*
|
|
@@ -153,15 +235,29 @@ EXPORT_SYMBOL(input_free_polled_device);
|
|
|
int input_register_polled_device(struct input_polled_dev *dev)
|
|
|
{
|
|
|
struct input_dev *input = dev->input;
|
|
|
+ int error;
|
|
|
|
|
|
input_set_drvdata(input, dev);
|
|
|
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
|
|
|
if (!dev->poll_interval)
|
|
|
dev->poll_interval = 500;
|
|
|
+ if (!dev->poll_interval_max)
|
|
|
+ dev->poll_interval_max = dev->poll_interval;
|
|
|
input->open = input_open_polled_device;
|
|
|
input->close = input_close_polled_device;
|
|
|
|
|
|
- return input_register_device(input);
|
|
|
+ error = input_register_device(input);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ error = sysfs_create_group(&input->dev.kobj,
|
|
|
+ &input_polldev_attribute_group);
|
|
|
+ if (error) {
|
|
|
+ input_unregister_device(input);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(input_register_polled_device);
|
|
|
|
|
@@ -177,6 +273,9 @@ EXPORT_SYMBOL(input_register_polled_device);
|
|
|
*/
|
|
|
void input_unregister_polled_device(struct input_polled_dev *dev)
|
|
|
{
|
|
|
+ sysfs_remove_group(&dev->input->dev.kobj,
|
|
|
+ &input_polldev_attribute_group);
|
|
|
+
|
|
|
input_unregister_device(dev->input);
|
|
|
dev->input = NULL;
|
|
|
}
|