diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input-polldev.c | 111 |
1 files changed, 105 insertions, 6 deletions
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 910220c127cb..31874275fed0 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c | |||
@@ -56,14 +56,10 @@ static void input_polldev_stop_workqueue(void) | |||
56 | mutex_unlock(&polldev_mutex); | 56 | mutex_unlock(&polldev_mutex); |
57 | } | 57 | } |
58 | 58 | ||
59 | static void input_polled_device_work(struct work_struct *work) | 59 | static void input_polldev_queue_work(struct input_polled_dev *dev) |
60 | { | 60 | { |
61 | struct input_polled_dev *dev = | ||
62 | container_of(work, struct input_polled_dev, work.work); | ||
63 | unsigned long delay; | 61 | unsigned long delay; |
64 | 62 | ||
65 | dev->poll(dev); | ||
66 | |||
67 | delay = msecs_to_jiffies(dev->poll_interval); | 63 | delay = msecs_to_jiffies(dev->poll_interval); |
68 | if (delay >= HZ) | 64 | if (delay >= HZ) |
69 | delay = round_jiffies_relative(delay); | 65 | delay = round_jiffies_relative(delay); |
@@ -71,6 +67,15 @@ static void input_polled_device_work(struct work_struct *work) | |||
71 | queue_delayed_work(polldev_wq, &dev->work, delay); | 67 | queue_delayed_work(polldev_wq, &dev->work, delay); |
72 | } | 68 | } |
73 | 69 | ||
70 | static void input_polled_device_work(struct work_struct *work) | ||
71 | { | ||
72 | struct input_polled_dev *dev = | ||
73 | container_of(work, struct input_polled_dev, work.work); | ||
74 | |||
75 | dev->poll(dev); | ||
76 | input_polldev_queue_work(dev); | ||
77 | } | ||
78 | |||
74 | static int input_open_polled_device(struct input_dev *input) | 79 | static int input_open_polled_device(struct input_dev *input) |
75 | { | 80 | { |
76 | struct input_polled_dev *dev = input_get_drvdata(input); | 81 | struct input_polled_dev *dev = input_get_drvdata(input); |
@@ -100,6 +105,83 @@ static void input_close_polled_device(struct input_dev *input) | |||
100 | dev->close(dev); | 105 | dev->close(dev); |
101 | } | 106 | } |
102 | 107 | ||
108 | /* SYSFS interface */ | ||
109 | |||
110 | static ssize_t input_polldev_get_poll(struct device *dev, | ||
111 | struct device_attribute *attr, char *buf) | ||
112 | { | ||
113 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
114 | |||
115 | return sprintf(buf, "%d\n", polldev->poll_interval); | ||
116 | } | ||
117 | |||
118 | static ssize_t input_polldev_set_poll(struct device *dev, | ||
119 | struct device_attribute *attr, const char *buf, | ||
120 | size_t count) | ||
121 | { | ||
122 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
123 | struct input_dev *input = polldev->input; | ||
124 | unsigned long interval; | ||
125 | |||
126 | if (strict_strtoul(buf, 0, &interval)) | ||
127 | return -EINVAL; | ||
128 | |||
129 | if (interval < polldev->poll_interval_min) | ||
130 | return -EINVAL; | ||
131 | |||
132 | if (interval > polldev->poll_interval_max) | ||
133 | return -EINVAL; | ||
134 | |||
135 | mutex_lock(&input->mutex); | ||
136 | |||
137 | polldev->poll_interval = interval; | ||
138 | |||
139 | if (input->users) { | ||
140 | cancel_delayed_work_sync(&polldev->work); | ||
141 | if (polldev->poll_interval > 0) | ||
142 | input_polldev_queue_work(polldev); | ||
143 | } | ||
144 | |||
145 | mutex_unlock(&input->mutex); | ||
146 | |||
147 | return count; | ||
148 | } | ||
149 | |||
150 | static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, | ||
151 | input_polldev_set_poll); | ||
152 | |||
153 | |||
154 | static ssize_t input_polldev_get_max(struct device *dev, | ||
155 | struct device_attribute *attr, char *buf) | ||
156 | { | ||
157 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
158 | |||
159 | return sprintf(buf, "%d\n", polldev->poll_interval_max); | ||
160 | } | ||
161 | |||
162 | static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); | ||
163 | |||
164 | static ssize_t input_polldev_get_min(struct device *dev, | ||
165 | struct device_attribute *attr, char *buf) | ||
166 | { | ||
167 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
168 | |||
169 | return sprintf(buf, "%d\n", polldev->poll_interval_min); | ||
170 | } | ||
171 | |||
172 | static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); | ||
173 | |||
174 | static struct attribute *sysfs_attrs[] = { | ||
175 | &dev_attr_poll.attr, | ||
176 | &dev_attr_max.attr, | ||
177 | &dev_attr_min.attr, | ||
178 | NULL | ||
179 | }; | ||
180 | |||
181 | static struct attribute_group input_polldev_attribute_group = { | ||
182 | .attrs = sysfs_attrs | ||
183 | }; | ||
184 | |||
103 | /** | 185 | /** |
104 | * input_allocate_polled_device - allocated memory polled device | 186 | * input_allocate_polled_device - allocated memory polled device |
105 | * | 187 | * |
@@ -153,15 +235,29 @@ EXPORT_SYMBOL(input_free_polled_device); | |||
153 | int input_register_polled_device(struct input_polled_dev *dev) | 235 | int input_register_polled_device(struct input_polled_dev *dev) |
154 | { | 236 | { |
155 | struct input_dev *input = dev->input; | 237 | struct input_dev *input = dev->input; |
238 | int error; | ||
156 | 239 | ||
157 | input_set_drvdata(input, dev); | 240 | input_set_drvdata(input, dev); |
158 | INIT_DELAYED_WORK(&dev->work, input_polled_device_work); | 241 | INIT_DELAYED_WORK(&dev->work, input_polled_device_work); |
159 | if (!dev->poll_interval) | 242 | if (!dev->poll_interval) |
160 | dev->poll_interval = 500; | 243 | dev->poll_interval = 500; |
244 | if (!dev->poll_interval_max) | ||
245 | dev->poll_interval_max = dev->poll_interval; | ||
161 | input->open = input_open_polled_device; | 246 | input->open = input_open_polled_device; |
162 | input->close = input_close_polled_device; | 247 | input->close = input_close_polled_device; |
163 | 248 | ||
164 | return input_register_device(input); | 249 | error = input_register_device(input); |
250 | if (error) | ||
251 | return error; | ||
252 | |||
253 | error = sysfs_create_group(&input->dev.kobj, | ||
254 | &input_polldev_attribute_group); | ||
255 | if (error) { | ||
256 | input_unregister_device(input); | ||
257 | return error; | ||
258 | } | ||
259 | |||
260 | return 0; | ||
165 | } | 261 | } |
166 | EXPORT_SYMBOL(input_register_polled_device); | 262 | EXPORT_SYMBOL(input_register_polled_device); |
167 | 263 | ||
@@ -177,6 +273,9 @@ EXPORT_SYMBOL(input_register_polled_device); | |||
177 | */ | 273 | */ |
178 | void input_unregister_polled_device(struct input_polled_dev *dev) | 274 | void input_unregister_polled_device(struct input_polled_dev *dev) |
179 | { | 275 | { |
276 | sysfs_remove_group(&dev->input->dev.kobj, | ||
277 | &input_polldev_attribute_group); | ||
278 | |||
180 | input_unregister_device(dev->input); | 279 | input_unregister_device(dev->input); |
181 | dev->input = NULL; | 280 | dev->input = NULL; |
182 | } | 281 | } |