diff options
author | Lee, Chun-Yi <joeyli.kernel@gmail.com> | 2011-05-21 19:33:54 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-05-27 12:38:50 -0400 |
commit | 6d88ff0f8ef3529f68233d3963b2a7e07f8e4f69 (patch) | |
tree | 912af8d6b59aa899df34cdfe0cd0e6a93ea3c0e0 | |
parent | ab6a931620cfa5c565b351d1982306c3c8b97f96 (diff) |
acer-wmi: support to set communication device state by new wmid method
Have many Acer notebooks' BIOS already support new WMID_GUID3 method.
On those machines, that will be better set communication device by
evaluate WMID_GUID3 method.
Tested on Acer Travelmate 8572
Cc: Carlos Corbacho <carlos@strangeworlds.co.uk>
Cc: Matthew Garrett <mjg@redhat.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
Cc: Corentin Chary <corentincj@iksaif.net>
Cc: Thomas Renninger <trenn@suse.de>
Signed-off-by: Lee, Chun-Yi <jlee@novell.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r-- | drivers/platform/x86/acer-wmi.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 48219117823b..5dc843bfc6c2 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -135,6 +135,7 @@ struct event_return_value { | |||
135 | */ | 135 | */ |
136 | #define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */ | 136 | #define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */ |
137 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ | 137 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ |
138 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ | ||
138 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ | 139 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ |
139 | 140 | ||
140 | struct lm_input_params { | 141 | struct lm_input_params { |
@@ -1142,6 +1143,114 @@ static acpi_status get_device_status(u32 *value, u32 cap) | |||
1142 | } | 1143 | } |
1143 | } | 1144 | } |
1144 | 1145 | ||
1146 | static acpi_status wmid3_set_device_status(u32 value, u16 device) | ||
1147 | { | ||
1148 | struct wmid3_gds_return_value return_value; | ||
1149 | acpi_status status; | ||
1150 | union acpi_object *obj; | ||
1151 | u16 devices; | ||
1152 | struct wmid3_gds_input_param params = { | ||
1153 | .function_num = 0x1, | ||
1154 | .hotkey_number = 0x01, | ||
1155 | .devices = ACER_WMID3_GDS_WIRELESS & | ||
1156 | ACER_WMID3_GDS_THREEG & | ||
1157 | ACER_WMID3_GDS_WIMAX & | ||
1158 | ACER_WMID3_GDS_BLUETOOTH, | ||
1159 | }; | ||
1160 | struct acpi_buffer input = { | ||
1161 | sizeof(struct wmid3_gds_input_param), | ||
1162 | ¶ms | ||
1163 | }; | ||
1164 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1165 | struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1166 | |||
1167 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); | ||
1168 | if (ACPI_FAILURE(status)) | ||
1169 | return status; | ||
1170 | |||
1171 | obj = output.pointer; | ||
1172 | |||
1173 | if (!obj) | ||
1174 | return AE_ERROR; | ||
1175 | else if (obj->type != ACPI_TYPE_BUFFER) { | ||
1176 | kfree(obj); | ||
1177 | return AE_ERROR; | ||
1178 | } | ||
1179 | if (obj->buffer.length != 8) { | ||
1180 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); | ||
1181 | kfree(obj); | ||
1182 | return AE_ERROR; | ||
1183 | } | ||
1184 | |||
1185 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); | ||
1186 | kfree(obj); | ||
1187 | |||
1188 | if (return_value.error_code || return_value.ec_return_value) { | ||
1189 | pr_warning("Get Current Device Status failed: " | ||
1190 | "0x%x - 0x%x\n", return_value.error_code, | ||
1191 | return_value.ec_return_value); | ||
1192 | return status; | ||
1193 | } | ||
1194 | |||
1195 | devices = return_value.devices; | ||
1196 | params.function_num = 0x2; | ||
1197 | params.hotkey_number = 0x01; | ||
1198 | params.devices = (value) ? (devices | device) : (devices & ~device); | ||
1199 | |||
1200 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2); | ||
1201 | if (ACPI_FAILURE(status)) | ||
1202 | return status; | ||
1203 | |||
1204 | obj = output2.pointer; | ||
1205 | |||
1206 | if (!obj) | ||
1207 | return AE_ERROR; | ||
1208 | else if (obj->type != ACPI_TYPE_BUFFER) { | ||
1209 | kfree(obj); | ||
1210 | return AE_ERROR; | ||
1211 | } | ||
1212 | if (obj->buffer.length != 4) { | ||
1213 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); | ||
1214 | kfree(obj); | ||
1215 | return AE_ERROR; | ||
1216 | } | ||
1217 | |||
1218 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); | ||
1219 | kfree(obj); | ||
1220 | |||
1221 | if (return_value.error_code || return_value.ec_return_value) | ||
1222 | pr_warning("Set Device Status failed: " | ||
1223 | "0x%x - 0x%x\n", return_value.error_code, | ||
1224 | return_value.ec_return_value); | ||
1225 | |||
1226 | return status; | ||
1227 | } | ||
1228 | |||
1229 | static acpi_status set_device_status(u32 value, u32 cap) | ||
1230 | { | ||
1231 | if (wmi_has_guid(WMID_GUID3)) { | ||
1232 | u16 device; | ||
1233 | |||
1234 | switch (cap) { | ||
1235 | case ACER_CAP_WIRELESS: | ||
1236 | device = ACER_WMID3_GDS_WIRELESS; | ||
1237 | break; | ||
1238 | case ACER_CAP_BLUETOOTH: | ||
1239 | device = ACER_WMID3_GDS_BLUETOOTH; | ||
1240 | break; | ||
1241 | case ACER_CAP_THREEG: | ||
1242 | device = ACER_WMID3_GDS_THREEG; | ||
1243 | break; | ||
1244 | default: | ||
1245 | return AE_ERROR; | ||
1246 | } | ||
1247 | return wmid3_set_device_status(value, device); | ||
1248 | |||
1249 | } else { | ||
1250 | return set_u32(value, cap); | ||
1251 | } | ||
1252 | } | ||
1253 | |||
1145 | /* | 1254 | /* |
1146 | * Rfkill devices | 1255 | * Rfkill devices |
1147 | */ | 1256 | */ |
@@ -1178,7 +1287,7 @@ static int acer_rfkill_set(void *data, bool blocked) | |||
1178 | u32 cap = (unsigned long)data; | 1287 | u32 cap = (unsigned long)data; |
1179 | 1288 | ||
1180 | if (rfkill_inited) { | 1289 | if (rfkill_inited) { |
1181 | status = set_u32(!blocked, cap); | 1290 | status = set_device_status(!blocked, cap); |
1182 | if (ACPI_FAILURE(status)) | 1291 | if (ACPI_FAILURE(status)) |
1183 | return -ENODEV; | 1292 | return -ENODEV; |
1184 | } | 1293 | } |