diff options
| -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 | } |
