aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/input-polldev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/input-polldev.c')
-rw-r--r--drivers/input/input-polldev.c131
1 files changed, 122 insertions, 9 deletions
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 7f161d93203c..3664f81655ca 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {
147 .attrs = sysfs_attrs 147 .attrs = sysfs_attrs
148}; 148};
149 149
150static const struct attribute_group *input_polldev_attribute_groups[] = {
151 &input_polldev_attribute_group,
152 NULL
153};
154
150/** 155/**
151 * input_allocate_polled_device - allocate memory for polled device 156 * input_allocate_polled_device - allocate memory for polled device
152 * 157 *
@@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)
171} 176}
172EXPORT_SYMBOL(input_allocate_polled_device); 177EXPORT_SYMBOL(input_allocate_polled_device);
173 178
179struct input_polled_devres {
180 struct input_polled_dev *polldev;
181};
182
183static int devm_input_polldev_match(struct device *dev, void *res, void *data)
184{
185 struct input_polled_devres *devres = res;
186
187 return devres->polldev == data;
188}
189
190static void devm_input_polldev_release(struct device *dev, void *res)
191{
192 struct input_polled_devres *devres = res;
193 struct input_polled_dev *polldev = devres->polldev;
194
195 dev_dbg(dev, "%s: dropping reference/freeing %s\n",
196 __func__, dev_name(&polldev->input->dev));
197
198 input_put_device(polldev->input);
199 kfree(polldev);
200}
201
202static void devm_input_polldev_unregister(struct device *dev, void *res)
203{
204 struct input_polled_devres *devres = res;
205 struct input_polled_dev *polldev = devres->polldev;
206
207 dev_dbg(dev, "%s: unregistering device %s\n",
208 __func__, dev_name(&polldev->input->dev));
209 input_unregister_device(polldev->input);
210
211 /*
212 * Note that we are still holding extra reference to the input
213 * device so it will stick around until devm_input_polldev_release()
214 * is called.
215 */
216}
217
218/**
219 * devm_input_allocate_polled_device - allocate managed polled device
220 * @dev: device owning the polled device being created
221 *
222 * Returns prepared &struct input_polled_dev or %NULL.
223 *
224 * Managed polled input devices do not need to be explicitly unregistered
225 * or freed as it will be done automatically when owner device unbinds
226 * from * its driver (or binding fails). Once such managed polled device
227 * is allocated, it is ready to be set up and registered in the same
228 * fashion as regular polled input devices (using
229 * input_register_polled_device() function).
230 *
231 * If you want to manually unregister and free such managed polled devices,
232 * it can be still done by calling input_unregister_polled_device() and
233 * input_free_polled_device(), although it is rarely needed.
234 *
235 * NOTE: the owner device is set up as parent of input device and users
236 * should not override it.
237 */
238struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev)
239{
240 struct input_polled_dev *polldev;
241 struct input_polled_devres *devres;
242
243 devres = devres_alloc(devm_input_polldev_release, sizeof(*devres),
244 GFP_KERNEL);
245 if (!devres)
246 return NULL;
247
248 polldev = input_allocate_polled_device();
249 if (!polldev) {
250 devres_free(devres);
251 return NULL;
252 }
253
254 polldev->input->dev.parent = dev;
255 polldev->devres_managed = true;
256
257 devres->polldev = polldev;
258 devres_add(dev, devres);
259
260 return polldev;
261}
262EXPORT_SYMBOL(devm_input_allocate_polled_device);
263
174/** 264/**
175 * input_free_polled_device - free memory allocated for polled device 265 * input_free_polled_device - free memory allocated for polled device
176 * @dev: device to free 266 * @dev: device to free
@@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);
181void input_free_polled_device(struct input_polled_dev *dev) 271void input_free_polled_device(struct input_polled_dev *dev)
182{ 272{
183 if (dev) { 273 if (dev) {
184 input_free_device(dev->input); 274 if (dev->devres_managed)
275 WARN_ON(devres_destroy(dev->input->dev.parent,
276 devm_input_polldev_release,
277 devm_input_polldev_match,
278 dev));
279 input_put_device(dev->input);
185 kfree(dev); 280 kfree(dev);
186 } 281 }
187} 282}
@@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);
199 */ 294 */
200int input_register_polled_device(struct input_polled_dev *dev) 295int input_register_polled_device(struct input_polled_dev *dev)
201{ 296{
297 struct input_polled_devres *devres = NULL;
202 struct input_dev *input = dev->input; 298 struct input_dev *input = dev->input;
203 int error; 299 int error;
204 300
301 if (dev->devres_managed) {
302 devres = devres_alloc(devm_input_polldev_unregister,
303 sizeof(*devres), GFP_KERNEL);
304 if (!devres)
305 return -ENOMEM;
306
307 devres->polldev = dev;
308 }
309
205 input_set_drvdata(input, dev); 310 input_set_drvdata(input, dev);
206 INIT_DELAYED_WORK(&dev->work, input_polled_device_work); 311 INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
312
207 if (!dev->poll_interval) 313 if (!dev->poll_interval)
208 dev->poll_interval = 500; 314 dev->poll_interval = 500;
209 if (!dev->poll_interval_max) 315 if (!dev->poll_interval_max)
210 dev->poll_interval_max = dev->poll_interval; 316 dev->poll_interval_max = dev->poll_interval;
317
211 input->open = input_open_polled_device; 318 input->open = input_open_polled_device;
212 input->close = input_close_polled_device; 319 input->close = input_close_polled_device;
213 320
214 error = input_register_device(input); 321 input->dev.groups = input_polldev_attribute_groups;
215 if (error)
216 return error;
217 322
218 error = sysfs_create_group(&input->dev.kobj, 323 error = input_register_device(input);
219 &input_polldev_attribute_group);
220 if (error) { 324 if (error) {
221 input_unregister_device(input); 325 devres_free(devres);
222 return error; 326 return error;
223 } 327 }
224 328
@@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)
231 */ 335 */
232 input_get_device(input); 336 input_get_device(input);
233 337
338 if (dev->devres_managed) {
339 dev_dbg(input->dev.parent, "%s: registering %s with devres.\n",
340 __func__, dev_name(&input->dev));
341 devres_add(input->dev.parent, devres);
342 }
343
234 return 0; 344 return 0;
235} 345}
236EXPORT_SYMBOL(input_register_polled_device); 346EXPORT_SYMBOL(input_register_polled_device);
@@ -245,8 +355,11 @@ EXPORT_SYMBOL(input_register_polled_device);
245 */ 355 */
246void input_unregister_polled_device(struct input_polled_dev *dev) 356void input_unregister_polled_device(struct input_polled_dev *dev)
247{ 357{
248 sysfs_remove_group(&dev->input->dev.kobj, 358 if (dev->devres_managed)
249 &input_polldev_attribute_group); 359 WARN_ON(devres_destroy(dev->input->dev.parent,
360 devm_input_polldev_unregister,
361 devm_input_polldev_match,
362 dev));
250 363
251 input_unregister_device(dev->input); 364 input_unregister_device(dev->input);
252} 365}