diff options
Diffstat (limited to 'drivers/input/input-polldev.c')
-rw-r--r-- | drivers/input/input-polldev.c | 137 |
1 files changed, 123 insertions, 14 deletions
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 0d3ce7a50fb1..aa6713b4a988 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); |
@@ -80,11 +85,12 @@ static int input_open_polled_device(struct input_dev *input) | |||
80 | if (error) | 85 | if (error) |
81 | return error; | 86 | return error; |
82 | 87 | ||
83 | if (dev->flush) | 88 | if (dev->open) |
84 | dev->flush(dev); | 89 | dev->open(dev); |
85 | 90 | ||
86 | queue_delayed_work(polldev_wq, &dev->work, | 91 | /* Only start polling if polling is enabled */ |
87 | msecs_to_jiffies(dev->poll_interval)); | 92 | if (dev->poll_interval > 0) |
93 | queue_delayed_work(polldev_wq, &dev->work, 0); | ||
88 | 94 | ||
89 | return 0; | 95 | return 0; |
90 | } | 96 | } |
@@ -95,8 +101,88 @@ static void input_close_polled_device(struct input_dev *input) | |||
95 | 101 | ||
96 | cancel_delayed_work_sync(&dev->work); | 102 | cancel_delayed_work_sync(&dev->work); |
97 | input_polldev_stop_workqueue(); | 103 | input_polldev_stop_workqueue(); |
104 | |||
105 | if (dev->close) | ||
106 | dev->close(dev); | ||
98 | } | 107 | } |
99 | 108 | ||
109 | /* SYSFS interface */ | ||
110 | |||
111 | static ssize_t input_polldev_get_poll(struct device *dev, | ||
112 | struct device_attribute *attr, char *buf) | ||
113 | { | ||
114 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
115 | |||
116 | return sprintf(buf, "%d\n", polldev->poll_interval); | ||
117 | } | ||
118 | |||
119 | static ssize_t input_polldev_set_poll(struct device *dev, | ||
120 | struct device_attribute *attr, const char *buf, | ||
121 | size_t count) | ||
122 | { | ||
123 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
124 | struct input_dev *input = polldev->input; | ||
125 | unsigned long interval; | ||
126 | |||
127 | if (strict_strtoul(buf, 0, &interval)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | if (interval < polldev->poll_interval_min) | ||
131 | return -EINVAL; | ||
132 | |||
133 | if (interval > polldev->poll_interval_max) | ||
134 | return -EINVAL; | ||
135 | |||
136 | mutex_lock(&input->mutex); | ||
137 | |||
138 | polldev->poll_interval = interval; | ||
139 | |||
140 | if (input->users) { | ||
141 | cancel_delayed_work_sync(&polldev->work); | ||
142 | if (polldev->poll_interval > 0) | ||
143 | input_polldev_queue_work(polldev); | ||
144 | } | ||
145 | |||
146 | mutex_unlock(&input->mutex); | ||
147 | |||
148 | return count; | ||
149 | } | ||
150 | |||
151 | static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, | ||
152 | input_polldev_set_poll); | ||
153 | |||
154 | |||
155 | static ssize_t input_polldev_get_max(struct device *dev, | ||
156 | struct device_attribute *attr, char *buf) | ||
157 | { | ||
158 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
159 | |||
160 | return sprintf(buf, "%d\n", polldev->poll_interval_max); | ||
161 | } | ||
162 | |||
163 | static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); | ||
164 | |||
165 | static ssize_t input_polldev_get_min(struct device *dev, | ||
166 | struct device_attribute *attr, char *buf) | ||
167 | { | ||
168 | struct input_polled_dev *polldev = dev_get_drvdata(dev); | ||
169 | |||
170 | return sprintf(buf, "%d\n", polldev->poll_interval_min); | ||
171 | } | ||
172 | |||
173 | static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); | ||
174 | |||
175 | static struct attribute *sysfs_attrs[] = { | ||
176 | &dev_attr_poll.attr, | ||
177 | &dev_attr_max.attr, | ||
178 | &dev_attr_min.attr, | ||
179 | NULL | ||
180 | }; | ||
181 | |||
182 | static struct attribute_group input_polldev_attribute_group = { | ||
183 | .attrs = sysfs_attrs | ||
184 | }; | ||
185 | |||
100 | /** | 186 | /** |
101 | * input_allocate_polled_device - allocated memory polled device | 187 | * input_allocate_polled_device - allocated memory polled device |
102 | * | 188 | * |
@@ -126,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device); | |||
126 | * @dev: device to free | 212 | * @dev: device to free |
127 | * | 213 | * |
128 | * The function frees memory allocated for polling device and drops | 214 | * The function frees memory allocated for polling device and drops |
129 | * reference to the associated input device (if present). | 215 | * reference to the associated input device. |
130 | */ | 216 | */ |
131 | void input_free_polled_device(struct input_polled_dev *dev) | 217 | void input_free_polled_device(struct input_polled_dev *dev) |
132 | { | 218 | { |
@@ -150,15 +236,38 @@ EXPORT_SYMBOL(input_free_polled_device); | |||
150 | int input_register_polled_device(struct input_polled_dev *dev) | 236 | int input_register_polled_device(struct input_polled_dev *dev) |
151 | { | 237 | { |
152 | struct input_dev *input = dev->input; | 238 | struct input_dev *input = dev->input; |
239 | int error; | ||
153 | 240 | ||
154 | input_set_drvdata(input, dev); | 241 | input_set_drvdata(input, dev); |
155 | INIT_DELAYED_WORK(&dev->work, input_polled_device_work); | 242 | INIT_DELAYED_WORK(&dev->work, input_polled_device_work); |
156 | if (!dev->poll_interval) | 243 | if (!dev->poll_interval) |
157 | dev->poll_interval = 500; | 244 | dev->poll_interval = 500; |
245 | if (!dev->poll_interval_max) | ||
246 | dev->poll_interval_max = dev->poll_interval; | ||
158 | input->open = input_open_polled_device; | 247 | input->open = input_open_polled_device; |
159 | input->close = input_close_polled_device; | 248 | input->close = input_close_polled_device; |
160 | 249 | ||
161 | return input_register_device(input); | 250 | error = input_register_device(input); |
251 | if (error) | ||
252 | return error; | ||
253 | |||
254 | error = sysfs_create_group(&input->dev.kobj, | ||
255 | &input_polldev_attribute_group); | ||
256 | if (error) { | ||
257 | input_unregister_device(input); | ||
258 | return error; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * Take extra reference to the underlying input device so | ||
263 | * that it survives call to input_unregister_polled_device() | ||
264 | * and is deleted only after input_free_polled_device() | ||
265 | * has been invoked. This is needed to ease task of freeing | ||
266 | * sparse keymaps. | ||
267 | */ | ||
268 | input_get_device(input); | ||
269 | |||
270 | return 0; | ||
162 | } | 271 | } |
163 | EXPORT_SYMBOL(input_register_polled_device); | 272 | EXPORT_SYMBOL(input_register_polled_device); |
164 | 273 | ||
@@ -169,13 +278,13 @@ EXPORT_SYMBOL(input_register_polled_device); | |||
169 | * The function unregisters previously registered polled input | 278 | * The function unregisters previously registered polled input |
170 | * device from input layer. Polling is stopped and device is | 279 | * device from input layer. Polling is stopped and device is |
171 | * ready to be freed with call to input_free_polled_device(). | 280 | * ready to be freed with call to input_free_polled_device(). |
172 | * Callers should not attempt to access dev->input pointer | ||
173 | * after calling this function. | ||
174 | */ | 281 | */ |
175 | void input_unregister_polled_device(struct input_polled_dev *dev) | 282 | void input_unregister_polled_device(struct input_polled_dev *dev) |
176 | { | 283 | { |
284 | sysfs_remove_group(&dev->input->dev.kobj, | ||
285 | &input_polldev_attribute_group); | ||
286 | |||
177 | input_unregister_device(dev->input); | 287 | input_unregister_device(dev->input); |
178 | dev->input = NULL; | ||
179 | } | 288 | } |
180 | EXPORT_SYMBOL(input_unregister_polled_device); | 289 | EXPORT_SYMBOL(input_unregister_polled_device); |
181 | 290 | ||