Root/
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 | #include <linux/jiffies.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/mutex.h> |
14 | #include <linux/input-polldev.h> |
15 | |
16 | MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); |
17 | MODULE_DESCRIPTION("Generic implementation of a polled input device"); |
18 | MODULE_LICENSE("GPL v2"); |
19 | MODULE_VERSION("0.1"); |
20 | |
21 | static DEFINE_MUTEX(polldev_mutex); |
22 | static int polldev_users; |
23 | static struct workqueue_struct *polldev_wq; |
24 | |
25 | static int input_polldev_start_workqueue(void) |
26 | { |
27 | int retval; |
28 | |
29 | retval = mutex_lock_interruptible(&polldev_mutex); |
30 | if (retval) |
31 | return retval; |
32 | |
33 | if (!polldev_users) { |
34 | polldev_wq = create_singlethread_workqueue("ipolldevd"); |
35 | if (!polldev_wq) { |
36 | printk(KERN_ERR "input-polldev: failed to create " |
37 | "ipolldevd workqueue\n"); |
38 | retval = -ENOMEM; |
39 | goto out; |
40 | } |
41 | } |
42 | |
43 | polldev_users++; |
44 | |
45 | out: |
46 | mutex_unlock(&polldev_mutex); |
47 | return retval; |
48 | } |
49 | |
50 | static void input_polldev_stop_workqueue(void) |
51 | { |
52 | mutex_lock(&polldev_mutex); |
53 | |
54 | if (!--polldev_users) |
55 | destroy_workqueue(polldev_wq); |
56 | |
57 | mutex_unlock(&polldev_mutex); |
58 | } |
59 | |
60 | static void input_polldev_queue_work(struct input_polled_dev *dev) |
61 | { |
62 | unsigned long delay; |
63 | |
64 | delay = msecs_to_jiffies(dev->poll_interval); |
65 | if (delay >= HZ) |
66 | delay = round_jiffies_relative(delay); |
67 | |
68 | queue_delayed_work(polldev_wq, &dev->work, delay); |
69 | } |
70 | |
71 | static void input_polled_device_work(struct work_struct *work) |
72 | { |
73 | struct input_polled_dev *dev = |
74 | container_of(work, struct input_polled_dev, work.work); |
75 | |
76 | dev->poll(dev); |
77 | input_polldev_queue_work(dev); |
78 | } |
79 | |
80 | static int input_open_polled_device(struct input_dev *input) |
81 | { |
82 | struct input_polled_dev *dev = input_get_drvdata(input); |
83 | int error; |
84 | |
85 | error = input_polldev_start_workqueue(); |
86 | if (error) |
87 | return error; |
88 | |
89 | if (dev->open) |
90 | dev->open(dev); |
91 | |
92 | /* Only start polling if polling is enabled */ |
93 | if (dev->poll_interval > 0) |
94 | queue_delayed_work(polldev_wq, &dev->work, 0); |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static void input_close_polled_device(struct input_dev *input) |
100 | { |
101 | struct input_polled_dev *dev = input_get_drvdata(input); |
102 | |
103 | cancel_delayed_work_sync(&dev->work); |
104 | /* |
105 | * Clean up work struct to remove references to the workqueue. |
106 | * It may be destroyed by the next call. This causes problems |
107 | * at next device open-close in case of poll_interval == 0. |
108 | */ |
109 | INIT_DELAYED_WORK(&dev->work, dev->work.work.func); |
110 | input_polldev_stop_workqueue(); |
111 | |
112 | if (dev->close) |
113 | dev->close(dev); |
114 | } |
115 | |
116 | /* SYSFS interface */ |
117 | |
118 | static ssize_t input_polldev_get_poll(struct device *dev, |
119 | struct device_attribute *attr, char *buf) |
120 | { |
121 | struct input_polled_dev *polldev = dev_get_drvdata(dev); |
122 | |
123 | return sprintf(buf, "%d\n", polldev->poll_interval); |
124 | } |
125 | |
126 | static ssize_t input_polldev_set_poll(struct device *dev, |
127 | struct device_attribute *attr, const char *buf, |
128 | size_t count) |
129 | { |
130 | struct input_polled_dev *polldev = dev_get_drvdata(dev); |
131 | struct input_dev *input = polldev->input; |
132 | unsigned long interval; |
133 | |
134 | if (strict_strtoul(buf, 0, &interval)) |
135 | return -EINVAL; |
136 | |
137 | if (interval < polldev->poll_interval_min) |
138 | return -EINVAL; |
139 | |
140 | if (interval > polldev->poll_interval_max) |
141 | return -EINVAL; |
142 | |
143 | mutex_lock(&input->mutex); |
144 | |
145 | polldev->poll_interval = interval; |
146 | |
147 | if (input->users) { |
148 | cancel_delayed_work_sync(&polldev->work); |
149 | if (polldev->poll_interval > 0) |
150 | input_polldev_queue_work(polldev); |
151 | } |
152 | |
153 | mutex_unlock(&input->mutex); |
154 | |
155 | return count; |
156 | } |
157 | |
158 | static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, |
159 | input_polldev_set_poll); |
160 | |
161 | |
162 | static ssize_t input_polldev_get_max(struct device *dev, |
163 | struct device_attribute *attr, char *buf) |
164 | { |
165 | struct input_polled_dev *polldev = dev_get_drvdata(dev); |
166 | |
167 | return sprintf(buf, "%d\n", polldev->poll_interval_max); |
168 | } |
169 | |
170 | static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); |
171 | |
172 | static ssize_t input_polldev_get_min(struct device *dev, |
173 | struct device_attribute *attr, char *buf) |
174 | { |
175 | struct input_polled_dev *polldev = dev_get_drvdata(dev); |
176 | |
177 | return sprintf(buf, "%d\n", polldev->poll_interval_min); |
178 | } |
179 | |
180 | static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); |
181 | |
182 | static struct attribute *sysfs_attrs[] = { |
183 | &dev_attr_poll.attr, |
184 | &dev_attr_max.attr, |
185 | &dev_attr_min.attr, |
186 | NULL |
187 | }; |
188 | |
189 | static struct attribute_group input_polldev_attribute_group = { |
190 | .attrs = sysfs_attrs |
191 | }; |
192 | |
193 | /** |
194 | * input_allocate_polled_device - allocated memory polled device |
195 | * |
196 | * The function allocates memory for a polled device and also |
197 | * for an input device associated with this polled device. |
198 | */ |
199 | struct input_polled_dev *input_allocate_polled_device(void) |
200 | { |
201 | struct input_polled_dev *dev; |
202 | |
203 | dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL); |
204 | if (!dev) |
205 | return NULL; |
206 | |
207 | dev->input = input_allocate_device(); |
208 | if (!dev->input) { |
209 | kfree(dev); |
210 | return NULL; |
211 | } |
212 | |
213 | return dev; |
214 | } |
215 | EXPORT_SYMBOL(input_allocate_polled_device); |
216 | |
217 | /** |
218 | * input_free_polled_device - free memory allocated for polled device |
219 | * @dev: device to free |
220 | * |
221 | * The function frees memory allocated for polling device and drops |
222 | * reference to the associated input device. |
223 | */ |
224 | void input_free_polled_device(struct input_polled_dev *dev) |
225 | { |
226 | if (dev) { |
227 | input_free_device(dev->input); |
228 | kfree(dev); |
229 | } |
230 | } |
231 | EXPORT_SYMBOL(input_free_polled_device); |
232 | |
233 | /** |
234 | * input_register_polled_device - register polled device |
235 | * @dev: device to register |
236 | * |
237 | * The function registers previously initialized polled input device |
238 | * with input layer. The device should be allocated with call to |
239 | * input_allocate_polled_device(). Callers should also set up poll() |
240 | * method and set up capabilities (id, name, phys, bits) of the |
241 | * corresponing input_dev structure. |
242 | */ |
243 | int input_register_polled_device(struct input_polled_dev *dev) |
244 | { |
245 | struct input_dev *input = dev->input; |
246 | int error; |
247 | |
248 | input_set_drvdata(input, dev); |
249 | INIT_DELAYED_WORK(&dev->work, input_polled_device_work); |
250 | if (!dev->poll_interval) |
251 | dev->poll_interval = 500; |
252 | if (!dev->poll_interval_max) |
253 | dev->poll_interval_max = dev->poll_interval; |
254 | input->open = input_open_polled_device; |
255 | input->close = input_close_polled_device; |
256 | |
257 | error = input_register_device(input); |
258 | if (error) |
259 | return error; |
260 | |
261 | error = sysfs_create_group(&input->dev.kobj, |
262 | &input_polldev_attribute_group); |
263 | if (error) { |
264 | input_unregister_device(input); |
265 | return error; |
266 | } |
267 | |
268 | /* |
269 | * Take extra reference to the underlying input device so |
270 | * that it survives call to input_unregister_polled_device() |
271 | * and is deleted only after input_free_polled_device() |
272 | * has been invoked. This is needed to ease task of freeing |
273 | * sparse keymaps. |
274 | */ |
275 | input_get_device(input); |
276 | |
277 | return 0; |
278 | } |
279 | EXPORT_SYMBOL(input_register_polled_device); |
280 | |
281 | /** |
282 | * input_unregister_polled_device - unregister polled device |
283 | * @dev: device to unregister |
284 | * |
285 | * The function unregisters previously registered polled input |
286 | * device from input layer. Polling is stopped and device is |
287 | * ready to be freed with call to input_free_polled_device(). |
288 | */ |
289 | void input_unregister_polled_device(struct input_polled_dev *dev) |
290 | { |
291 | sysfs_remove_group(&dev->input->dev.kobj, |
292 | &input_polldev_attribute_group); |
293 | |
294 | input_unregister_device(dev->input); |
295 | } |
296 | EXPORT_SYMBOL(input_unregister_polled_device); |
297 | |
298 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9