Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 174231
b: refs/heads/master
c: dad725d
h: refs/heads/master
i:
  174229: afcdc97
  174227: 0245ace
  174223: 54d28ef
v: v3
  • Loading branch information
Samu Onkalo authored and Dmitry Torokhov committed Nov 20, 2009
1 parent c9592c0 commit 0e092a6
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bc8f1eaf68a8aa1d993492f1ad2d74502665f578
refs/heads/master: dad725d089b94bce8bbc769b7471dcfba3fbda0e
111 changes: 105 additions & 6 deletions trunk/drivers/input/input-polldev.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,26 @@ 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);

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);
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}
Expand Down
11 changes: 10 additions & 1 deletion trunk/include/linux/input-polldev.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
* longer being polled. Used to put device into low power mode.
* @poll: driver-supplied method that polls the device and posts
* input events (mandatory).
* @poll_interval: specifies how often the poll() method shoudl be called.
* @poll_interval: specifies how often the poll() method should be called.
* Defaults to 500 msec unless overriden when registering the device.
* @poll_interval_max: specifies upper bound for the poll interval.
* Defaults to the initial value of @poll_interval.
* @poll_interval_min: specifies lower bound for the poll interval.
* Defaults to 0.
* @input: input device structire associated with the polled device.
* Must be properly initialized by the driver (id, name, phys, bits).
*
Expand All @@ -36,8 +41,12 @@ struct input_polled_dev {
void (*close)(struct input_polled_dev *dev);
void (*poll)(struct input_polled_dev *dev);
unsigned int poll_interval; /* msec */
unsigned int poll_interval_max; /* msec */
unsigned int poll_interval_min; /* msec */

struct input_dev *input;

/* private: */
struct delayed_work work;
};

Expand Down

0 comments on commit 0e092a6

Please sign in to comment.