aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2011-02-26 04:20:36 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:07:21 -0400
commit1d070f89a723bd296865dd7eb61c8050763e6e3b (patch)
tree4ac93d5cfc8b69da16cdee231ae4ee1b0fd94b66 /drivers/platform
parentd33da3b6866975b17fbec67540f6153f5dcdcec7 (diff)
asus-wmi: try to guess the right DSTS methods
This is tricky, new WMI aware notebooks seems to use 0x53545344 while Eee PCs are using 0x53544344. But there is no way to know if there is an Eee PC in that wild that is using 0x53545344 or a notebook using 0x53544344. So the driver try to guess the available DSTS method ... But most Eee PCs never return 0xFFFFFFFE when a method is not available, they return 0 instead (and that's useless). So, first, try 0x53544344 then 0x53545344. We will find a better way when we got more data. Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/asus-wmi.c99
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
126struct asus_wmi { 127struct 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
232static int asus_wmi_get_devstate(u32 dev_id, u32 *retval) 235static 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
238static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, 240static 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 */
246static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) 248static 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
267static int asus_wmi_get_devstate_simple(u32 dev_id) 270static 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
303static int read_tpd_led_state(struct asus_wmi *asus) 307static 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
308static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) 312static 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 */
354static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) 358static 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)
482static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, 486static 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 */
753static int read_backlight_power(void) 758static 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
763static int read_brightness(struct backlight_device *bd) 768static 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
776static int update_bl_status(struct backlight_device *bd) 782static 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
924static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) 931static 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
942static ssize_t show_sys_wmi(int devid, char *buf) 950static 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[] = {
1000static mode_t asus_sysfs_is_visible(struct kobject *kobj, 1012static 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
1019static struct attribute_group platform_attribute_group = { 1034static struct attribute_group platform_attribute_group = {
@@ -1036,6 +1051,23 @@ static int asus_wmi_sysfs_init(struct platform_device *device)
1036 */ 1051 */
1037static int __init asus_wmi_platform_init(struct asus_wmi *asus) 1052static 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