diff options
-rw-r--r-- | drivers/platform/x86/asus-wmi.c | 99 |
1 files changed, 66 insertions, 33 deletions
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 34e6b4d83a9..fd5b08eecf1 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
@@ -67,6 +67,7 @@ MODULE_LICENSE("GPL"); | |||
67 | 67 | ||
68 | /* WMI Methods */ | 68 | /* WMI Methods */ |
69 | #define ASUS_WMI_METHODID_DSTS 0x53544344 | 69 | #define ASUS_WMI_METHODID_DSTS 0x53544344 |
70 | #define ASUS_WMI_METHODID_DSTS2 0x53545344 | ||
70 | #define ASUS_WMI_METHODID_DEVS 0x53564544 | 71 | #define ASUS_WMI_METHODID_DEVS 0x53564544 |
71 | #define ASUS_WMI_METHODID_CFVS 0x53564643 | 72 | #define ASUS_WMI_METHODID_CFVS 0x53564643 |
72 | 73 | ||
@@ -124,6 +125,8 @@ struct asus_rfkill { | |||
124 | }; | 125 | }; |
125 | 126 | ||
126 | struct asus_wmi { | 127 | struct asus_wmi { |
128 | int dsts_id; | ||
129 | |||
127 | struct input_dev *inputdev; | 130 | struct input_dev *inputdev; |
128 | struct backlight_device *backlight_device; | 131 | struct backlight_device *backlight_device; |
129 | struct platform_device *platform_device; | 132 | struct platform_device *platform_device; |
@@ -229,26 +232,26 @@ exit: | |||
229 | return 0; | 232 | return 0; |
230 | } | 233 | } |
231 | 234 | ||
232 | static int asus_wmi_get_devstate(u32 dev_id, u32 *retval) | 235 | static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) |
233 | { | 236 | { |
234 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, | 237 | return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); |
235 | 0, retval); | ||
236 | } | 238 | } |
237 | 239 | ||
238 | static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, | 240 | static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, |
239 | u32 *retval) | 241 | u32 *retval) |
240 | { | 242 | { |
241 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, | 243 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, |
242 | ctrl_param, retval); | 244 | ctrl_param, retval); |
243 | } | 245 | } |
244 | 246 | ||
245 | /* Helper for special devices with magic return codes */ | 247 | /* Helper for special devices with magic return codes */ |
246 | static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) | 248 | static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, |
249 | u32 dev_id, u32 mask) | ||
247 | { | 250 | { |
248 | u32 retval = 0; | 251 | u32 retval = 0; |
249 | int err; | 252 | int err; |
250 | 253 | ||
251 | err = asus_wmi_get_devstate(dev_id, &retval); | 254 | err = asus_wmi_get_devstate(asus, dev_id, &retval); |
252 | 255 | ||
253 | if (err < 0) | 256 | if (err < 0) |
254 | return err; | 257 | return err; |
@@ -264,9 +267,10 @@ static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) | |||
264 | return retval & mask; | 267 | return retval & mask; |
265 | } | 268 | } |
266 | 269 | ||
267 | static int asus_wmi_get_devstate_simple(u32 dev_id) | 270 | static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) |
268 | { | 271 | { |
269 | return asus_wmi_get_devstate_bits(dev_id, ASUS_WMI_DSTS_STATUS_BIT); | 272 | return asus_wmi_get_devstate_bits(asus, dev_id, |
273 | ASUS_WMI_DSTS_STATUS_BIT); | ||
270 | } | 274 | } |
271 | 275 | ||
272 | /* | 276 | /* |
@@ -302,7 +306,7 @@ static void tpd_led_set(struct led_classdev *led_cdev, | |||
302 | 306 | ||
303 | static int read_tpd_led_state(struct asus_wmi *asus) | 307 | static int read_tpd_led_state(struct asus_wmi *asus) |
304 | { | 308 | { |
305 | return asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_TOUCHPAD_LED); | 309 | return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); |
306 | } | 310 | } |
307 | 311 | ||
308 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | 312 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) |
@@ -353,7 +357,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) | |||
353 | */ | 357 | */ |
354 | static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) | 358 | static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) |
355 | { | 359 | { |
356 | int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); | 360 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); |
357 | 361 | ||
358 | if (result < 0) | 362 | if (result < 0) |
359 | return false; | 363 | return false; |
@@ -482,7 +486,8 @@ static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) | |||
482 | static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, | 486 | static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, |
483 | u8 *value) | 487 | u8 *value) |
484 | { | 488 | { |
485 | int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); | 489 | struct asus_wmi *asus = hotplug_slot->private; |
490 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
486 | 491 | ||
487 | if (result < 0) | 492 | if (result < 0) |
488 | return result; | 493 | return result; |
@@ -578,7 +583,7 @@ static void asus_rfkill_query(struct rfkill *rfkill, void *data) | |||
578 | struct asus_rfkill *priv = data; | 583 | struct asus_rfkill *priv = data; |
579 | int result; | 584 | int result; |
580 | 585 | ||
581 | result = asus_wmi_get_devstate_simple(priv->dev_id); | 586 | result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); |
582 | 587 | ||
583 | if (result < 0) | 588 | if (result < 0) |
584 | return; | 589 | return; |
@@ -619,7 +624,7 @@ static int asus_new_rfkill(struct asus_wmi *asus, | |||
619 | struct asus_rfkill *arfkill, | 624 | struct asus_rfkill *arfkill, |
620 | const char *name, enum rfkill_type type, int dev_id) | 625 | const char *name, enum rfkill_type type, int dev_id) |
621 | { | 626 | { |
622 | int result = asus_wmi_get_devstate_simple(dev_id); | 627 | int result = asus_wmi_get_devstate_simple(asus, dev_id); |
623 | struct rfkill **rfkill = &arfkill->rfkill; | 628 | struct rfkill **rfkill = &arfkill->rfkill; |
624 | 629 | ||
625 | if (result < 0) | 630 | if (result < 0) |
@@ -750,9 +755,9 @@ exit: | |||
750 | /* | 755 | /* |
751 | * Backlight | 756 | * Backlight |
752 | */ | 757 | */ |
753 | static int read_backlight_power(void) | 758 | static int read_backlight_power(struct asus_wmi *asus) |
754 | { | 759 | { |
755 | int ret = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BACKLIGHT); | 760 | int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); |
756 | 761 | ||
757 | if (ret < 0) | 762 | if (ret < 0) |
758 | return ret; | 763 | return ret; |
@@ -762,10 +767,11 @@ static int read_backlight_power(void) | |||
762 | 767 | ||
763 | static int read_brightness(struct backlight_device *bd) | 768 | static int read_brightness(struct backlight_device *bd) |
764 | { | 769 | { |
770 | struct asus_wmi *asus = bl_get_data(bd); | ||
765 | u32 retval; | 771 | u32 retval; |
766 | int err; | 772 | int err; |
767 | 773 | ||
768 | err = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval); | 774 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); |
769 | 775 | ||
770 | if (err < 0) | 776 | if (err < 0) |
771 | return err; | 777 | return err; |
@@ -775,6 +781,7 @@ static int read_brightness(struct backlight_device *bd) | |||
775 | 781 | ||
776 | static int update_bl_status(struct backlight_device *bd) | 782 | static int update_bl_status(struct backlight_device *bd) |
777 | { | 783 | { |
784 | struct asus_wmi *asus = bl_get_data(bd); | ||
778 | u32 ctrl_param; | 785 | u32 ctrl_param; |
779 | int power, err; | 786 | int power, err; |
780 | 787 | ||
@@ -786,7 +793,7 @@ static int update_bl_status(struct backlight_device *bd) | |||
786 | if (err < 0) | 793 | if (err < 0) |
787 | return err; | 794 | return err; |
788 | 795 | ||
789 | power = read_backlight_power(); | 796 | power = read_backlight_power(asus); |
790 | if (power != -ENODEV && bd->props.power != power) { | 797 | if (power != -ENODEV && bd->props.power != power) { |
791 | ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); | 798 | ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); |
792 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, | 799 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, |
@@ -825,9 +832,9 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) | |||
825 | int max; | 832 | int max; |
826 | int power; | 833 | int power; |
827 | 834 | ||
828 | max = asus_wmi_get_devstate_bits(ASUS_WMI_DEVID_BRIGHTNESS, | 835 | max = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_BRIGHTNESS, |
829 | ASUS_WMI_DSTS_MAX_BRIGTH_MASK); | 836 | ASUS_WMI_DSTS_MAX_BRIGTH_MASK); |
830 | power = read_backlight_power(); | 837 | power = read_backlight_power(asus); |
831 | 838 | ||
832 | if (max < 0 && power < 0) { | 839 | if (max < 0 && power < 0) { |
833 | /* Try to keep the original error */ | 840 | /* Try to keep the original error */ |
@@ -921,12 +928,13 @@ static int parse_arg(const char *buf, unsigned long count, int *val) | |||
921 | return count; | 928 | return count; |
922 | } | 929 | } |
923 | 930 | ||
924 | static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) | 931 | static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, |
932 | const char *buf, size_t count) | ||
925 | { | 933 | { |
926 | u32 retval; | 934 | u32 retval; |
927 | int rv, err, value; | 935 | int rv, err, value; |
928 | 936 | ||
929 | value = asus_wmi_get_devstate_simple(devid); | 937 | value = asus_wmi_get_devstate_simple(asus, devid); |
930 | if (value == -ENODEV) /* Check device presence */ | 938 | if (value == -ENODEV) /* Check device presence */ |
931 | return value; | 939 | return value; |
932 | 940 | ||
@@ -939,9 +947,9 @@ static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) | |||
939 | return rv; | 947 | return rv; |
940 | } | 948 | } |
941 | 949 | ||
942 | static ssize_t show_sys_wmi(int devid, char *buf) | 950 | static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) |
943 | { | 951 | { |
944 | int value = asus_wmi_get_devstate_simple(devid); | 952 | int value = asus_wmi_get_devstate_simple(asus, devid); |
945 | 953 | ||
946 | if (value < 0) | 954 | if (value < 0) |
947 | return value; | 955 | return value; |
@@ -954,13 +962,17 @@ static ssize_t show_sys_wmi(int devid, char *buf) | |||
954 | struct device_attribute *attr, \ | 962 | struct device_attribute *attr, \ |
955 | char *buf) \ | 963 | char *buf) \ |
956 | { \ | 964 | { \ |
957 | return show_sys_wmi(_cm, buf); \ | 965 | struct asus_wmi *asus = dev_get_drvdata(dev); \ |
966 | \ | ||
967 | return show_sys_wmi(asus, _cm, buf); \ | ||
958 | } \ | 968 | } \ |
959 | static ssize_t store_##_name(struct device *dev, \ | 969 | static ssize_t store_##_name(struct device *dev, \ |
960 | struct device_attribute *attr, \ | 970 | struct device_attribute *attr, \ |
961 | const char *buf, size_t count) \ | 971 | const char *buf, size_t count) \ |
962 | { \ | 972 | { \ |
963 | return store_sys_wmi(_cm, buf, count); \ | 973 | struct asus_wmi *asus = dev_get_drvdata(dev); \ |
974 | \ | ||
975 | return store_sys_wmi(asus, _cm, buf, count); \ | ||
964 | } \ | 976 | } \ |
965 | static struct device_attribute dev_attr_##_name = { \ | 977 | static struct device_attribute dev_attr_##_name = { \ |
966 | .attr = { \ | 978 | .attr = { \ |
@@ -1000,7 +1012,10 @@ static struct attribute *platform_attributes[] = { | |||
1000 | static mode_t asus_sysfs_is_visible(struct kobject *kobj, | 1012 | static mode_t asus_sysfs_is_visible(struct kobject *kobj, |
1001 | struct attribute *attr, int idx) | 1013 | struct attribute *attr, int idx) |
1002 | { | 1014 | { |
1003 | bool supported = true; | 1015 | struct device *dev = container_of(kobj, struct device, kobj); |
1016 | struct platform_device *pdev = to_platform_device(dev); | ||
1017 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
1018 | bool ok = true; | ||
1004 | int devid = -1; | 1019 | int devid = -1; |
1005 | 1020 | ||
1006 | if (attr == &dev_attr_camera.attr) | 1021 | if (attr == &dev_attr_camera.attr) |
@@ -1011,9 +1026,9 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, | |||
1011 | devid = ASUS_WMI_DEVID_TOUCHPAD; | 1026 | devid = ASUS_WMI_DEVID_TOUCHPAD; |
1012 | 1027 | ||
1013 | if (devid != -1) | 1028 | if (devid != -1) |
1014 | supported = asus_wmi_get_devstate_simple(devid) != -ENODEV; | 1029 | ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); |
1015 | 1030 | ||
1016 | return supported ? attr->mode : 0; | 1031 | return ok ? attr->mode : 0; |
1017 | } | 1032 | } |
1018 | 1033 | ||
1019 | static struct attribute_group platform_attribute_group = { | 1034 | static struct attribute_group platform_attribute_group = { |
@@ -1036,6 +1051,23 @@ static int asus_wmi_sysfs_init(struct platform_device *device) | |||
1036 | */ | 1051 | */ |
1037 | static int __init asus_wmi_platform_init(struct asus_wmi *asus) | 1052 | static int __init asus_wmi_platform_init(struct asus_wmi *asus) |
1038 | { | 1053 | { |
1054 | /* | ||
1055 | * Eee PC and Notebooks seems to have different method_id for DSTS, | ||
1056 | * but it may also be related to the BIOS's SPEC. | ||
1057 | * Note, on most Eeepc, there is no way to check if a method exist | ||
1058 | * or note, while on notebooks, they returns 0xFFFFFFFE on failure, | ||
1059 | * but once again, SPEC may probably be used for that kind of things. | ||
1060 | */ | ||
1061 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) | ||
1062 | asus->dsts_id = ASUS_WMI_METHODID_DSTS; | ||
1063 | else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) | ||
1064 | asus->dsts_id = ASUS_WMI_METHODID_DSTS2; | ||
1065 | |||
1066 | if (!asus->dsts_id) { | ||
1067 | pr_err("Can't find DSTS"); | ||
1068 | return -ENODEV; | ||
1069 | } | ||
1070 | |||
1039 | return asus_wmi_sysfs_init(asus->platform_device); | 1071 | return asus_wmi_sysfs_init(asus->platform_device); |
1040 | } | 1072 | } |
1041 | 1073 | ||
@@ -1059,7 +1091,7 @@ static int show_dsts(struct seq_file *m, void *data) | |||
1059 | int err; | 1091 | int err; |
1060 | u32 retval = -1; | 1092 | u32 retval = -1; |
1061 | 1093 | ||
1062 | err = asus_wmi_get_devstate(asus->debug.dev_id, &retval); | 1094 | err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); |
1063 | 1095 | ||
1064 | if (err < 0) | 1096 | if (err < 0) |
1065 | return err; | 1097 | return err; |
@@ -1262,7 +1294,7 @@ static int asus_hotk_thaw(struct device *device) | |||
1262 | * during suspend. Normally it restores it on resume, but | 1294 | * during suspend. Normally it restores it on resume, but |
1263 | * we should kick it ourselves in case hibernation is aborted. | 1295 | * we should kick it ourselves in case hibernation is aborted. |
1264 | */ | 1296 | */ |
1265 | wlan = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); | 1297 | wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); |
1266 | asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); | 1298 | asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); |
1267 | } | 1299 | } |
1268 | 1300 | ||
@@ -1279,15 +1311,16 @@ static int asus_hotk_restore(struct device *device) | |||
1279 | asus_rfkill_hotplug(asus); | 1311 | asus_rfkill_hotplug(asus); |
1280 | 1312 | ||
1281 | if (asus->bluetooth.rfkill) { | 1313 | if (asus->bluetooth.rfkill) { |
1282 | bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BLUETOOTH); | 1314 | bl = !asus_wmi_get_devstate_simple(asus, |
1315 | ASUS_WMI_DEVID_BLUETOOTH); | ||
1283 | rfkill_set_sw_state(asus->bluetooth.rfkill, bl); | 1316 | rfkill_set_sw_state(asus->bluetooth.rfkill, bl); |
1284 | } | 1317 | } |
1285 | if (asus->wimax.rfkill) { | 1318 | if (asus->wimax.rfkill) { |
1286 | bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WIMAX); | 1319 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); |
1287 | rfkill_set_sw_state(asus->wimax.rfkill, bl); | 1320 | rfkill_set_sw_state(asus->wimax.rfkill, bl); |
1288 | } | 1321 | } |
1289 | if (asus->wwan3g.rfkill) { | 1322 | if (asus->wwan3g.rfkill) { |
1290 | bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WWAN3G); | 1323 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); |
1291 | rfkill_set_sw_state(asus->wwan3g.rfkill, bl); | 1324 | rfkill_set_sw_state(asus->wwan3g.rfkill, bl); |
1292 | } | 1325 | } |
1293 | 1326 | ||