diff options
author | Matthew Garrett <mjg@redhat.com> | 2009-12-09 13:23:36 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2010-02-25 11:50:42 -0500 |
commit | 814cb8adbe2fb49302ac65bc31fa749143823860 (patch) | |
tree | 25309aa3682c52926c60470994240cdfb43a08e2 /drivers/platform/x86/dell-laptop.c | |
parent | 493e91433e966a50964e221db92756eeb90dd54e (diff) |
dell-laptop: Update rfkill state on kill switch
The rfkill interface on Dells only sends a notification that the switch
has been changed via the keyboard controller. Add a filter so we can
pick these notifications up and update the rfkill state appropriately.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/dell-laptop.c')
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 3780994dc8f2..9d7e0be6bb0f 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/rfkill.h> | 22 | #include <linux/rfkill.h> |
23 | #include <linux/power_supply.h> | 23 | #include <linux/power_supply.h> |
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include <linux/i8042.h> | ||
25 | #include "../../firmware/dcdbas.h" | 26 | #include "../../firmware/dcdbas.h" |
26 | 27 | ||
27 | #define BRIGHTNESS_TOKEN 0x7d | 28 | #define BRIGHTNESS_TOKEN 0x7d |
@@ -214,6 +215,18 @@ static const struct rfkill_ops dell_rfkill_ops = { | |||
214 | .query = dell_rfkill_query, | 215 | .query = dell_rfkill_query, |
215 | }; | 216 | }; |
216 | 217 | ||
218 | static void dell_update_rfkill(struct work_struct *ignored) | ||
219 | { | ||
220 | if (wifi_rfkill) | ||
221 | dell_rfkill_query(wifi_rfkill, (void *)1); | ||
222 | if (bluetooth_rfkill) | ||
223 | dell_rfkill_query(bluetooth_rfkill, (void *)2); | ||
224 | if (wwan_rfkill) | ||
225 | dell_rfkill_query(wwan_rfkill, (void *)3); | ||
226 | } | ||
227 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | ||
228 | |||
229 | |||
217 | static int __init dell_setup_rfkill(void) | 230 | static int __init dell_setup_rfkill(void) |
218 | { | 231 | { |
219 | struct calling_interface_buffer buffer; | 232 | struct calling_interface_buffer buffer; |
@@ -338,6 +351,30 @@ static struct backlight_ops dell_ops = { | |||
338 | .update_status = dell_send_intensity, | 351 | .update_status = dell_send_intensity, |
339 | }; | 352 | }; |
340 | 353 | ||
354 | bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, | ||
355 | struct serio *port) | ||
356 | { | ||
357 | static bool extended; | ||
358 | |||
359 | if (str & 0x20) | ||
360 | return false; | ||
361 | |||
362 | if (unlikely(data == 0xe0)) { | ||
363 | extended = true; | ||
364 | return false; | ||
365 | } else if (unlikely(extended)) { | ||
366 | switch (data) { | ||
367 | case 0x8: | ||
368 | schedule_delayed_work(&dell_rfkill_work, | ||
369 | round_jiffies_relative(HZ)); | ||
370 | break; | ||
371 | } | ||
372 | extended = false; | ||
373 | } | ||
374 | |||
375 | return false; | ||
376 | } | ||
377 | |||
341 | static int __init dell_init(void) | 378 | static int __init dell_init(void) |
342 | { | 379 | { |
343 | struct calling_interface_buffer buffer; | 380 | struct calling_interface_buffer buffer; |
@@ -373,6 +410,13 @@ static int __init dell_init(void) | |||
373 | goto fail_rfkill; | 410 | goto fail_rfkill; |
374 | } | 411 | } |
375 | 412 | ||
413 | ret = i8042_install_filter(dell_laptop_i8042_filter); | ||
414 | if (ret) { | ||
415 | printk(KERN_WARNING | ||
416 | "dell-laptop: Unable to install key filter\n"); | ||
417 | goto fail_filter; | ||
418 | } | ||
419 | |||
376 | #ifdef CONFIG_ACPI | 420 | #ifdef CONFIG_ACPI |
377 | /* In the event of an ACPI backlight being available, don't | 421 | /* In the event of an ACPI backlight being available, don't |
378 | * register the platform controller. | 422 | * register the platform controller. |
@@ -410,6 +454,8 @@ static int __init dell_init(void) | |||
410 | return 0; | 454 | return 0; |
411 | 455 | ||
412 | fail_backlight: | 456 | fail_backlight: |
457 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
458 | fail_filter: | ||
413 | dell_cleanup_rfkill(); | 459 | dell_cleanup_rfkill(); |
414 | fail_rfkill: | 460 | fail_rfkill: |
415 | platform_device_del(platform_device); | 461 | platform_device_del(platform_device); |
@@ -424,6 +470,8 @@ fail_platform_driver: | |||
424 | 470 | ||
425 | static void __exit dell_exit(void) | 471 | static void __exit dell_exit(void) |
426 | { | 472 | { |
473 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
474 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
427 | backlight_device_unregister(dell_backlight_device); | 475 | backlight_device_unregister(dell_backlight_device); |
428 | dell_cleanup_rfkill(); | 476 | dell_cleanup_rfkill(); |
429 | } | 477 | } |