diff options
| -rw-r--r-- | drivers/platform/x86/acer-wmi.c | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index a1c6141f463b..85d263349aac 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
| @@ -85,6 +85,7 @@ MODULE_LICENSE("GPL"); | |||
| 85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | 85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" |
| 86 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" | 86 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" |
| 87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" |
| 88 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" | ||
| 88 | 89 | ||
| 89 | /* | 90 | /* |
| 90 | * Acer ACPI event GUIDs | 91 | * Acer ACPI event GUIDs |
| @@ -121,6 +122,24 @@ struct event_return_value { | |||
| 121 | } __attribute__((packed)); | 122 | } __attribute__((packed)); |
| 122 | 123 | ||
| 123 | /* | 124 | /* |
| 125 | * GUID3 Get Device Status device flags | ||
| 126 | */ | ||
| 127 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ | ||
| 128 | |||
| 129 | struct wmid3_gds_input_param { /* Get Device Status input parameter */ | ||
| 130 | u8 function_num; /* Function Number */ | ||
| 131 | u8 hotkey_number; /* Hotkey Number */ | ||
| 132 | u16 devices; /* Get Device */ | ||
| 133 | } __attribute__((packed)); | ||
| 134 | |||
| 135 | struct wmid3_gds_return_value { /* Get Device Status return value*/ | ||
| 136 | u8 error_code; /* Error Code */ | ||
| 137 | u8 ec_return_value; /* EC Return Value */ | ||
| 138 | u16 devices; /* Current Device Status */ | ||
| 139 | u32 reserved; | ||
| 140 | } __attribute__((packed)); | ||
| 141 | |||
| 142 | /* | ||
| 124 | * Interface capability flags | 143 | * Interface capability flags |
| 125 | */ | 144 | */ |
| 126 | #define ACER_CAP_MAILLED (1<<0) | 145 | #define ACER_CAP_MAILLED (1<<0) |
| @@ -174,6 +193,7 @@ struct acer_debug { | |||
| 174 | 193 | ||
| 175 | static struct rfkill *wireless_rfkill; | 194 | static struct rfkill *wireless_rfkill; |
| 176 | static struct rfkill *bluetooth_rfkill; | 195 | static struct rfkill *bluetooth_rfkill; |
| 196 | static struct rfkill *threeg_rfkill; | ||
| 177 | 197 | ||
| 178 | /* Each low-level interface must define at least some of the following */ | 198 | /* Each low-level interface must define at least some of the following */ |
| 179 | struct wmi_interface { | 199 | struct wmi_interface { |
| @@ -982,6 +1002,54 @@ static void acer_backlight_exit(void) | |||
| 982 | backlight_device_unregister(acer_backlight_device); | 1002 | backlight_device_unregister(acer_backlight_device); |
| 983 | } | 1003 | } |
| 984 | 1004 | ||
| 1005 | static acpi_status wmid3_get_device_status(u32 *value, u16 device) | ||
| 1006 | { | ||
| 1007 | struct wmid3_gds_return_value return_value; | ||
| 1008 | acpi_status status; | ||
| 1009 | union acpi_object *obj; | ||
| 1010 | struct wmid3_gds_input_param params = { | ||
| 1011 | .function_num = 0x1, | ||
| 1012 | .hotkey_number = 0x01, | ||
| 1013 | .devices = device, | ||
| 1014 | }; | ||
| 1015 | struct acpi_buffer input = { | ||
| 1016 | sizeof(struct wmid3_gds_input_param), | ||
| 1017 | ¶ms | ||
| 1018 | }; | ||
| 1019 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1020 | |||
| 1021 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); | ||
| 1022 | if (ACPI_FAILURE(status)) | ||
| 1023 | return status; | ||
| 1024 | |||
| 1025 | obj = output.pointer; | ||
| 1026 | |||
| 1027 | if (!obj) | ||
| 1028 | return AE_ERROR; | ||
| 1029 | else if (obj->type != ACPI_TYPE_BUFFER) { | ||
| 1030 | kfree(obj); | ||
| 1031 | return AE_ERROR; | ||
| 1032 | } | ||
| 1033 | if (obj->buffer.length != 8) { | ||
| 1034 | printk(ACER_WARNING "Unknown buffer length %d\n", | ||
| 1035 | obj->buffer.length); | ||
| 1036 | kfree(obj); | ||
| 1037 | return AE_ERROR; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); | ||
| 1041 | kfree(obj); | ||
| 1042 | |||
| 1043 | if (return_value.error_code || return_value.ec_return_value) | ||
| 1044 | printk(ACER_WARNING "Get Device Status failed: " | ||
| 1045 | "0x%x - 0x%x\n", return_value.error_code, | ||
| 1046 | return_value.ec_return_value); | ||
| 1047 | else | ||
| 1048 | *value = !!(return_value.devices & device); | ||
| 1049 | |||
| 1050 | return status; | ||
| 1051 | } | ||
| 1052 | |||
| 985 | /* | 1053 | /* |
| 986 | * Rfkill devices | 1054 | * Rfkill devices |
| 987 | */ | 1055 | */ |
| @@ -1002,6 +1070,13 @@ static void acer_rfkill_update(struct work_struct *ignored) | |||
| 1002 | rfkill_set_sw_state(bluetooth_rfkill, !state); | 1070 | rfkill_set_sw_state(bluetooth_rfkill, !state); |
| 1003 | } | 1071 | } |
| 1004 | 1072 | ||
| 1073 | if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { | ||
| 1074 | status = wmid3_get_device_status(&state, | ||
| 1075 | ACER_WMID3_GDS_THREEG); | ||
| 1076 | if (ACPI_SUCCESS(status)) | ||
| 1077 | rfkill_set_sw_state(threeg_rfkill, !state); | ||
| 1078 | } | ||
| 1079 | |||
| 1005 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1080 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
| 1006 | } | 1081 | } |
| 1007 | 1082 | ||
| @@ -1058,6 +1133,19 @@ static int acer_rfkill_init(struct device *dev) | |||
| 1058 | } | 1133 | } |
| 1059 | } | 1134 | } |
| 1060 | 1135 | ||
| 1136 | if (has_cap(ACER_CAP_THREEG)) { | ||
| 1137 | threeg_rfkill = acer_rfkill_register(dev, | ||
| 1138 | RFKILL_TYPE_WWAN, "acer-threeg", | ||
| 1139 | ACER_CAP_THREEG); | ||
| 1140 | if (IS_ERR(threeg_rfkill)) { | ||
| 1141 | rfkill_unregister(wireless_rfkill); | ||
| 1142 | rfkill_destroy(wireless_rfkill); | ||
| 1143 | rfkill_unregister(bluetooth_rfkill); | ||
| 1144 | rfkill_destroy(bluetooth_rfkill); | ||
| 1145 | return PTR_ERR(threeg_rfkill); | ||
| 1146 | } | ||
| 1147 | } | ||
| 1148 | |||
| 1061 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1149 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
| 1062 | 1150 | ||
| 1063 | return 0; | 1151 | return 0; |
| @@ -1074,6 +1162,11 @@ static void acer_rfkill_exit(void) | |||
| 1074 | rfkill_unregister(bluetooth_rfkill); | 1162 | rfkill_unregister(bluetooth_rfkill); |
| 1075 | rfkill_destroy(bluetooth_rfkill); | 1163 | rfkill_destroy(bluetooth_rfkill); |
| 1076 | } | 1164 | } |
| 1165 | |||
| 1166 | if (has_cap(ACER_CAP_THREEG)) { | ||
| 1167 | rfkill_unregister(threeg_rfkill); | ||
| 1168 | rfkill_destroy(threeg_rfkill); | ||
| 1169 | } | ||
| 1077 | return; | 1170 | return; |
| 1078 | } | 1171 | } |
| 1079 | 1172 | ||
| @@ -1084,7 +1177,12 @@ static ssize_t show_bool_threeg(struct device *dev, | |||
| 1084 | struct device_attribute *attr, char *buf) | 1177 | struct device_attribute *attr, char *buf) |
| 1085 | { | 1178 | { |
| 1086 | u32 result; \ | 1179 | u32 result; \ |
| 1087 | acpi_status status = get_u32(&result, ACER_CAP_THREEG); | 1180 | acpi_status status; |
| 1181 | if (wmi_has_guid(WMID_GUID3)) | ||
| 1182 | status = wmid3_get_device_status(&result, | ||
| 1183 | ACER_WMID3_GDS_THREEG); | ||
| 1184 | else | ||
| 1185 | status = get_u32(&result, ACER_CAP_THREEG); | ||
| 1088 | if (ACPI_SUCCESS(status)) | 1186 | if (ACPI_SUCCESS(status)) |
| 1089 | return sprintf(buf, "%u\n", result); | 1187 | return sprintf(buf, "%u\n", result); |
| 1090 | return sprintf(buf, "Read error\n"); | 1188 | return sprintf(buf, "Read error\n"); |
