Skip to content

Commit

Permalink
dell-rbtn: Export notifier for other kernel modules
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pali Rohár authored and Darren Hart committed Jun 11, 2015
1 parent 817a5cd commit b05ffc9
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
93 changes: 92 additions & 1 deletion drivers/platform/x86/dell-rbtn.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,86 @@ static struct acpi_driver rbtn_driver = {
};


/*
* notifier export functions
*/

static bool auto_remove_rfkill = true;

static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head);

static int rbtn_inc_count(struct device *dev, void *data)
{
struct acpi_device *device = to_acpi_device(dev);
struct rbtn_data *rbtn_data = device->driver_data;
int *count = data;

if (rbtn_data->type == RBTN_SLIDER)
(*count)++;

return 0;
}

static int rbtn_switch_dev(struct device *dev, void *data)
{
struct acpi_device *device = to_acpi_device(dev);
struct rbtn_data *rbtn_data = device->driver_data;
bool enable = data;

if (rbtn_data->type != RBTN_SLIDER)
return 0;

if (enable)
rbtn_rfkill_init(device);
else
rbtn_rfkill_exit(device);

return 0;
}

int dell_rbtn_notifier_register(struct notifier_block *nb)
{
bool first;
int count;
int ret;

count = 0;
ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count,
rbtn_inc_count);
if (ret || count == 0)
return -ENODEV;

first = !rbtn_chain_head.head;

ret = atomic_notifier_chain_register(&rbtn_chain_head, nb);
if (ret != 0)
return ret;

if (auto_remove_rfkill && first)
ret = driver_for_each_device(&rbtn_driver.drv, NULL,
(void *)false, rbtn_switch_dev);

return ret;
}
EXPORT_SYMBOL_GPL(dell_rbtn_notifier_register);

int dell_rbtn_notifier_unregister(struct notifier_block *nb)
{
int ret;

ret = atomic_notifier_chain_unregister(&rbtn_chain_head, nb);
if (ret != 0)
return ret;

if (auto_remove_rfkill && !rbtn_chain_head.head)
ret = driver_for_each_device(&rbtn_driver.drv, NULL,
(void *)true, rbtn_switch_dev);

return ret;
}
EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister);


/*
* acpi driver functions
*/
Expand Down Expand Up @@ -266,7 +346,10 @@ static int rbtn_add(struct acpi_device *device)
ret = rbtn_input_init(rbtn_data);
break;
case RBTN_SLIDER:
ret = rbtn_rfkill_init(device);
if (auto_remove_rfkill && rbtn_chain_head.head)
ret = 0;
else
ret = rbtn_rfkill_init(device);
break;
default:
ret = -EINVAL;
Expand Down Expand Up @@ -313,6 +396,7 @@ static void rbtn_notify(struct acpi_device *device, u32 event)
break;
case RBTN_SLIDER:
rbtn_rfkill_event(device);
atomic_notifier_call_chain(&rbtn_chain_head, event, device);
break;
default:
break;
Expand All @@ -326,6 +410,13 @@ static void rbtn_notify(struct acpi_device *device, u32 event)

module_acpi_driver(rbtn_driver);

module_param(auto_remove_rfkill, bool, 0444);

MODULE_PARM_DESC(auto_remove_rfkill, "Automatically remove rfkill devices when "
"other modules start receiving events "
"from this module and re-add them when "
"the last module stops receiving events "
"(default true)");
MODULE_DEVICE_TABLE(acpi, rbtn_ids);
MODULE_DESCRIPTION("Dell Airplane Mode Switch driver");
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
Expand Down
24 changes: 24 additions & 0 deletions drivers/platform/x86/dell-rbtn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Dell Airplane Mode Switch driver
Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

#ifndef _DELL_RBTN_H_
#define _DELL_RBTN_H_

struct notifier_block;

int dell_rbtn_notifier_register(struct notifier_block *nb);
int dell_rbtn_notifier_unregister(struct notifier_block *nb);

#endif

0 comments on commit b05ffc9

Please sign in to comment.