Until now module dell-laptop registered rfkill device which used i8042 filter function for receiving HW switch rfkill events (handling special keycode). But for some dell laptops there is native ACPI driver dell-rbtn which can receive rfkill events (without i8042 hacks). On some machines it can also control rfkill devices, but can turn on/off all radio devices. So this patch will combine best from both sides. It will use native ACPI driver dell-rbtn for receiving events and dell-laptop SMBIOS interface for enabling or disabling radio devices. If ACPI driver or device will not be available fallback to i8042 filter function will be used. Signed-off-by: Pali Rohár <pali.rohar@xxxxxxxxx> --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/dell-laptop.c | 67 +++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9d065c2..357e17f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -97,6 +97,7 @@ config DELL_LAPTOP depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL || RFKILL = n depends on SERIO_I8042 + select DELL_RBTN select POWER_SUPPLY select LEDS_CLASS select NEW_LEDS diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index d688d80..c9ea0f8 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -32,6 +32,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include "../../firmware/dcdbas.h" +#include "dell-rbtn.h" #define BRIGHTNESS_TOKEN 0x7d #define KBD_LED_OFF_TOKEN 0x01E1 @@ -642,6 +643,20 @@ static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, return false; } +static bool dell_laptop_use_rbtn; + +static int dell_laptop_rbtn_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + schedule_delayed_work(&dell_rfkill_work, + round_jiffies_relative(HZ / 4)); + return NOTIFY_OK; +} + +static struct notifier_block dell_laptop_rbtn_notifier = { + .notifier_call = dell_laptop_rbtn_notifier_call, +}; + static int __init dell_setup_rfkill(void) { int status, ret, whitelisted; @@ -718,10 +733,46 @@ static int __init dell_setup_rfkill(void) goto err_wwan; } - ret = i8042_install_filter(dell_laptop_i8042_filter); - if (ret) { - pr_warn("Unable to install key filter\n"); + /* + * Dell Airplane Mode Switch driver (dell-rbtn) supports ACPI devices + * which can receive HW button switch events and also can control radio + * devices. Somtimes ACPI device supports only reciving events (without + * enable/disable software control). + * + * Dell SMBIOS on whitelisted models supports controlling radio devices + * but does not support receiving HW button switch events. We can use + * i8042 filter hook function to receive keyboard data and handle + * keycode for HW button. + * + * Dell Airplane Mode Switch driver supports only one rfkill switch + * which enable/disable all radio devices. But Dell SMBIOS supports more + * granularity and can enable/disable also one type of radio device + * (e.g disable only bluetooth device without touching wifi device). + * + * So if it is possible we will use Dell Airplane Mode Switch ACPI + * driver for receiving HW events and Dell SMBIOS for setting rfkill + * states. If ACPI driver or device is not available we will fallback to + * i8042 filter hook function. + * + * To prevent duplicate rfkill devices which control and do same thing, + * dell-rbtn driver will automatically remove its own rfkill devices + * once function dell_rbtn_notifier_register() is called. + */ + + ret = dell_rbtn_notifier_register(&dell_laptop_rbtn_notifier); + if (ret == 0) { + pr_info("Using dell-rbtn acpi driver for receiving events\n"); + dell_laptop_use_rbtn = true; + } else if (ret != -ENODEV) { + pr_warn("Unable to register dell rbtn notifier\n"); goto err_filter; + } else { + ret = i8042_install_filter(dell_laptop_i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + goto err_filter; + } + pr_info("Using i8042 filter function for receiving events\n"); } return 0; @@ -1961,7 +2012,10 @@ static int __init dell_init(void) return 0; fail_backlight: - i8042_remove_filter(dell_laptop_i8042_filter); + if (dell_laptop_use_rbtn) + dell_rbtn_notifier_unregister(&dell_laptop_rbtn_notifier); + else + i8042_remove_filter(dell_laptop_i8042_filter); cancel_delayed_work_sync(&dell_rfkill_work); dell_cleanup_rfkill(); fail_rfkill: @@ -1983,7 +2037,10 @@ static void __exit dell_exit(void) if (quirks && quirks->touchpad_led) touchpad_led_exit(); kbd_led_exit(); - i8042_remove_filter(dell_laptop_i8042_filter); + if (dell_laptop_use_rbtn) + dell_rbtn_notifier_unregister(&dell_laptop_rbtn_notifier); + else + i8042_remove_filter(dell_laptop_i8042_filter); cancel_delayed_work_sync(&dell_rfkill_work); backlight_device_unregister(dell_backlight_device); dell_cleanup_rfkill(); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html