aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2015-06-06 04:23:29 -0400
committerDarren Hart <dvhart@linux.intel.com>2015-06-11 01:04:11 -0400
commitb05ffc95f9ed986534b67538e239e9c4ba254b55 (patch)
tree39d75408240f9b7154eee89ec9af54d883781cdd
parent817a5cdb40c8115eafe631b8e1de37cf8fe9fab8 (diff)
dell-rbtn: Export notifier for other kernel modules
This patch exports notifier functions so other modules can receive HW switch events. By default when some module register notifier, dell-rbtn driver automatically remove rfkill interfaces from system (it is expected that other module will use events for other rfkill interface). This behaviour can be changed with new module parameter "auto_remove_rfkill". This patch is designed for dell-laptop module for receiving those events. Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Tested-by: Gabriele Mazzotta <gabriele.mzt@gmail.com> [dvhart@linux.intel.com: Cleanup MODULE_PARM_DESC formatting and grammar] Signed-off-by: Darren Hart <dvhart@linux.intel.com>
-rw-r--r--drivers/platform/x86/dell-rbtn.c93
-rw-r--r--drivers/platform/x86/dell-rbtn.h24
2 files changed, 116 insertions, 1 deletions
diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c
index 1c19fff6d565..cd410e392550 100644
--- a/drivers/platform/x86/dell-rbtn.c
+++ b/drivers/platform/x86/dell-rbtn.c
@@ -233,6 +233,86 @@ static struct acpi_driver rbtn_driver = {
233 233
234 234
235/* 235/*
236 * notifier export functions
237 */
238
239static bool auto_remove_rfkill = true;
240
241static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head);
242
243static int rbtn_inc_count(struct device *dev, void *data)
244{
245 struct acpi_device *device = to_acpi_device(dev);
246 struct rbtn_data *rbtn_data = device->driver_data;
247 int *count = data;
248
249 if (rbtn_data->type == RBTN_SLIDER)
250 (*count)++;
251
252 return 0;
253}
254
255static int rbtn_switch_dev(struct device *dev, void *data)
256{
257 struct acpi_device *device = to_acpi_device(dev);
258 struct rbtn_data *rbtn_data = device->driver_data;
259 bool enable = data;
260
261 if (rbtn_data->type != RBTN_SLIDER)
262 return 0;
263
264 if (enable)
265 rbtn_rfkill_init(device);
266 else
267 rbtn_rfkill_exit(device);
268
269 return 0;
270}
271
272int dell_rbtn_notifier_register(struct notifier_block *nb)
273{
274 bool first;
275 int count;
276 int ret;
277
278 count = 0;
279 ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count,
280 rbtn_inc_count);
281 if (ret || count == 0)
282 return -ENODEV;
283
284 first = !rbtn_chain_head.head;
285
286 ret = atomic_notifier_chain_register(&rbtn_chain_head, nb);
287 if (ret != 0)
288 return ret;
289
290 if (auto_remove_rfkill && first)
291 ret = driver_for_each_device(&rbtn_driver.drv, NULL,
292 (void *)false, rbtn_switch_dev);
293
294 return ret;
295}
296EXPORT_SYMBOL_GPL(dell_rbtn_notifier_register);
297
298int dell_rbtn_notifier_unregister(struct notifier_block *nb)
299{
300 int ret;
301
302 ret = atomic_notifier_chain_unregister(&rbtn_chain_head, nb);
303 if (ret != 0)
304 return ret;
305
306 if (auto_remove_rfkill && !rbtn_chain_head.head)
307 ret = driver_for_each_device(&rbtn_driver.drv, NULL,
308 (void *)true, rbtn_switch_dev);
309
310 return ret;
311}
312EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister);
313
314
315/*
236 * acpi driver functions 316 * acpi driver functions
237 */ 317 */
238 318
@@ -266,7 +346,10 @@ static int rbtn_add(struct acpi_device *device)
266 ret = rbtn_input_init(rbtn_data); 346 ret = rbtn_input_init(rbtn_data);
267 break; 347 break;
268 case RBTN_SLIDER: 348 case RBTN_SLIDER:
269 ret = rbtn_rfkill_init(device); 349 if (auto_remove_rfkill && rbtn_chain_head.head)
350 ret = 0;
351 else
352 ret = rbtn_rfkill_init(device);
270 break; 353 break;
271 default: 354 default:
272 ret = -EINVAL; 355 ret = -EINVAL;
@@ -313,6 +396,7 @@ static void rbtn_notify(struct acpi_device *device, u32 event)
313 break; 396 break;
314 case RBTN_SLIDER: 397 case RBTN_SLIDER:
315 rbtn_rfkill_event(device); 398 rbtn_rfkill_event(device);
399 atomic_notifier_call_chain(&rbtn_chain_head, event, device);
316 break; 400 break;
317 default: 401 default:
318 break; 402 break;
@@ -326,6 +410,13 @@ static void rbtn_notify(struct acpi_device *device, u32 event)
326 410
327module_acpi_driver(rbtn_driver); 411module_acpi_driver(rbtn_driver);
328 412
413module_param(auto_remove_rfkill, bool, 0444);
414
415MODULE_PARM_DESC(auto_remove_rfkill, "Automatically remove rfkill devices when "
416 "other modules start receiving events "
417 "from this module and re-add them when "
418 "the last module stops receiving events "
419 "(default true)");
329MODULE_DEVICE_TABLE(acpi, rbtn_ids); 420MODULE_DEVICE_TABLE(acpi, rbtn_ids);
330MODULE_DESCRIPTION("Dell Airplane Mode Switch driver"); 421MODULE_DESCRIPTION("Dell Airplane Mode Switch driver");
331MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); 422MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
diff --git a/drivers/platform/x86/dell-rbtn.h b/drivers/platform/x86/dell-rbtn.h
new file mode 100644
index 000000000000..c59cc6b8ec2b
--- /dev/null
+++ b/drivers/platform/x86/dell-rbtn.h
@@ -0,0 +1,24 @@
1/*
2 Dell Airplane Mode Switch driver
3 Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14*/
15
16#ifndef _DELL_RBTN_H_
17#define _DELL_RBTN_H_
18
19struct notifier_block;
20
21int dell_rbtn_notifier_register(struct notifier_block *nb);
22int dell_rbtn_notifier_unregister(struct notifier_block *nb);
23
24#endif