diff options
author | AceLan Kao <acelan.kao@canonical.com> | 2012-07-27 04:51:59 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2013-02-24 17:49:52 -0500 |
commit | 6cae06e603339f99334bc6b276e2ac619cf0d476 (patch) | |
tree | 8c42fb743dd64b92d54973de71b984e49f81d7c0 /drivers/platform | |
parent | 9e2d59ad580d590134285f361a0e80f0e98c0207 (diff) |
asus-wmi: update wlan LED through rfkill led trigger
For those machines with wapf=4, BIOS won't update the wireless LED,
since wapf=4 means user application will take in chage of the wifi and bt.
So, we have to update wlan LED status explicitly.
But I found there is another wireless LED bug in launchpad and which is
not in the wapf=4 quirk.
So, it might be better to set wireless LED status explicitly for all
machines.
BugLink: https://launchpad.net/bugs/901105
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index f80ae4d10f68..912ec7de71f4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -187,6 +187,8 @@ struct asus_wmi { | |||
187 | struct device *hwmon_device; | 187 | struct device *hwmon_device; |
188 | struct platform_device *platform_device; | 188 | struct platform_device *platform_device; |
189 | 189 | ||
190 | struct led_classdev wlan_led; | ||
191 | int wlan_led_wk; | ||
190 | struct led_classdev tpd_led; | 192 | struct led_classdev tpd_led; |
191 | int tpd_led_wk; | 193 | int tpd_led_wk; |
192 | struct led_classdev kbd_led; | 194 | struct led_classdev kbd_led; |
@@ -194,6 +196,7 @@ struct asus_wmi { | |||
194 | struct workqueue_struct *led_workqueue; | 196 | struct workqueue_struct *led_workqueue; |
195 | struct work_struct tpd_led_work; | 197 | struct work_struct tpd_led_work; |
196 | struct work_struct kbd_led_work; | 198 | struct work_struct kbd_led_work; |
199 | struct work_struct wlan_led_work; | ||
197 | 200 | ||
198 | struct asus_rfkill wlan; | 201 | struct asus_rfkill wlan; |
199 | struct asus_rfkill bluetooth; | 202 | struct asus_rfkill bluetooth; |
@@ -456,12 +459,65 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) | |||
456 | return value; | 459 | return value; |
457 | } | 460 | } |
458 | 461 | ||
462 | static int wlan_led_unknown_state(struct asus_wmi *asus) | ||
463 | { | ||
464 | u32 result; | ||
465 | |||
466 | asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); | ||
467 | |||
468 | return result & ASUS_WMI_DSTS_UNKNOWN_BIT; | ||
469 | } | ||
470 | |||
471 | static int wlan_led_presence(struct asus_wmi *asus) | ||
472 | { | ||
473 | u32 result; | ||
474 | |||
475 | asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); | ||
476 | |||
477 | return result & ASUS_WMI_DSTS_PRESENCE_BIT; | ||
478 | } | ||
479 | |||
480 | static void wlan_led_update(struct work_struct *work) | ||
481 | { | ||
482 | int ctrl_param; | ||
483 | struct asus_wmi *asus; | ||
484 | |||
485 | asus = container_of(work, struct asus_wmi, wlan_led_work); | ||
486 | |||
487 | ctrl_param = asus->wlan_led_wk; | ||
488 | asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL); | ||
489 | } | ||
490 | |||
491 | static void wlan_led_set(struct led_classdev *led_cdev, | ||
492 | enum led_brightness value) | ||
493 | { | ||
494 | struct asus_wmi *asus; | ||
495 | |||
496 | asus = container_of(led_cdev, struct asus_wmi, wlan_led); | ||
497 | |||
498 | asus->wlan_led_wk = !!value; | ||
499 | queue_work(asus->led_workqueue, &asus->wlan_led_work); | ||
500 | } | ||
501 | |||
502 | static enum led_brightness wlan_led_get(struct led_classdev *led_cdev) | ||
503 | { | ||
504 | struct asus_wmi *asus; | ||
505 | u32 result; | ||
506 | |||
507 | asus = container_of(led_cdev, struct asus_wmi, wlan_led); | ||
508 | asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); | ||
509 | |||
510 | return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; | ||
511 | } | ||
512 | |||
459 | static void asus_wmi_led_exit(struct asus_wmi *asus) | 513 | static void asus_wmi_led_exit(struct asus_wmi *asus) |
460 | { | 514 | { |
461 | if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) | 515 | if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) |
462 | led_classdev_unregister(&asus->kbd_led); | 516 | led_classdev_unregister(&asus->kbd_led); |
463 | if (!IS_ERR_OR_NULL(asus->tpd_led.dev)) | 517 | if (!IS_ERR_OR_NULL(asus->tpd_led.dev)) |
464 | led_classdev_unregister(&asus->tpd_led); | 518 | led_classdev_unregister(&asus->tpd_led); |
519 | if (!IS_ERR_OR_NULL(asus->wlan_led.dev)) | ||
520 | led_classdev_unregister(&asus->wlan_led); | ||
465 | if (asus->led_workqueue) | 521 | if (asus->led_workqueue) |
466 | destroy_workqueue(asus->led_workqueue); | 522 | destroy_workqueue(asus->led_workqueue); |
467 | } | 523 | } |
@@ -498,6 +554,23 @@ static int asus_wmi_led_init(struct asus_wmi *asus) | |||
498 | 554 | ||
499 | rv = led_classdev_register(&asus->platform_device->dev, | 555 | rv = led_classdev_register(&asus->platform_device->dev, |
500 | &asus->kbd_led); | 556 | &asus->kbd_led); |
557 | if (rv) | ||
558 | goto error; | ||
559 | } | ||
560 | |||
561 | if (wlan_led_presence(asus)) { | ||
562 | INIT_WORK(&asus->wlan_led_work, wlan_led_update); | ||
563 | |||
564 | asus->wlan_led.name = "asus::wlan"; | ||
565 | asus->wlan_led.brightness_set = wlan_led_set; | ||
566 | if (!wlan_led_unknown_state(asus)) | ||
567 | asus->wlan_led.brightness_get = wlan_led_get; | ||
568 | asus->wlan_led.flags = LED_CORE_SUSPENDRESUME; | ||
569 | asus->wlan_led.max_brightness = 1; | ||
570 | asus->wlan_led.default_trigger = "asus-wlan"; | ||
571 | |||
572 | rv = led_classdev_register(&asus->platform_device->dev, | ||
573 | &asus->wlan_led); | ||
501 | } | 574 | } |
502 | 575 | ||
503 | error: | 576 | error: |
@@ -813,6 +886,9 @@ static int asus_new_rfkill(struct asus_wmi *asus, | |||
813 | if (!*rfkill) | 886 | if (!*rfkill) |
814 | return -EINVAL; | 887 | return -EINVAL; |
815 | 888 | ||
889 | if (dev_id == ASUS_WMI_DEVID_WLAN) | ||
890 | rfkill_set_led_trigger_name(*rfkill, "asus-wlan"); | ||
891 | |||
816 | rfkill_init_sw_state(*rfkill, !result); | 892 | rfkill_init_sw_state(*rfkill, !result); |
817 | result = rfkill_register(*rfkill); | 893 | result = rfkill_register(*rfkill); |
818 | if (result) { | 894 | if (result) { |