1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 Dell Airplane Mode Switch driver 4 Copyright (C) 2014-2015 Pali Rohár <pali@kernel.org> 5 6 */ 7 8 #include <linux/module.h> 9 #include <linux/acpi.h> 10 #include <linux/rfkill.h> 11 #include <linux/input.h> 12 13 #include "dell-rbtn.h" 14 15 enum rbtn_type { 16 RBTN_UNKNOWN, 17 RBTN_TOGGLE, 18 RBTN_SLIDER, 19 }; 20 21 struct rbtn_data { 22 enum rbtn_type type; 23 struct rfkill *rfkill; 24 struct input_dev *input_dev; 25 bool suspended; 26 }; 27 28 29 /* 30 * acpi functions 31 */ 32 33 static enum rbtn_type rbtn_check(struct acpi_device *device) 34 { 35 unsigned long long output; 36 acpi_status status; 37 38 status = acpi_evaluate_integer(device->handle, "CRBT", NULL, &output); 39 if (ACPI_FAILURE(status)) 40 return RBTN_UNKNOWN; 41 42 switch (output) { 43 case 0: 44 case 1: 45 return RBTN_TOGGLE; 46 case 2: 47 case 3: 48 return RBTN_SLIDER; 49 default: 50 return RBTN_UNKNOWN; 51 } 52 } 53 54 static int rbtn_get(struct acpi_device *device) 55 { 56 unsigned long long output; 57 acpi_status status; 58 59 status = acpi_evaluate_integer(device->handle, "GRBT", NULL, &output); 60 if (ACPI_FAILURE(status)) 61 return -EINVAL; 62 63 return !output; 64 } 65 66 static int rbtn_acquire(struct acpi_device *device, bool enable) 67 { 68 struct acpi_object_list input; 69 union acpi_object param; 70 acpi_status status; 71 72 param.type = ACPI_TYPE_INTEGER; 73 param.integer.value = enable; 74 input.count = 1; 75 input.pointer = ¶m; 76 77 status = acpi_evaluate_object(device->handle, "ARBT", &input, NULL); 78 if (ACPI_FAILURE(status)) 79 return -EINVAL; 80 81 return 0; 82 } 83 84 85 /* 86 * rfkill device 87 */ 88 89 static void rbtn_rfkill_query(struct rfkill *rfkill, void *data) 90 { 91 struct acpi_device *device = data; 92 int state; 93 94 state = rbtn_get(device); 95 if (state < 0) 96 return; 97 98 rfkill_set_states(rfkill, state, state); 99 } 100 101 static int rbtn_rfkill_set_block(void *data, bool blocked) 102 { 103 /* NOTE: setting soft rfkill state is not supported */ 104 return -EINVAL; 105 } 106 107 static const struct rfkill_ops rbtn_ops = { 108 .query = rbtn_rfkill_query, 109 .set_block = rbtn_rfkill_set_block, 110 }; 111 112 static int rbtn_rfkill_init(struct acpi_device *device) 113 { 114 struct rbtn_data *rbtn_data = device->driver_data; 115 int ret; 116 117 if (rbtn_data->rfkill) 118 return 0; 119 120 /* 121 * NOTE: rbtn controls all radio devices, not only WLAN 122 * but rfkill interface does not support "ANY" type 123 * so "WLAN" type is used 124 */ 125 rbtn_data->rfkill = rfkill_alloc("dell-rbtn", &device->dev, 126 RFKILL_TYPE_WLAN, &rbtn_ops, device); 127 if (!rbtn_data->rfkill) 128 return -ENOMEM; 129 130 ret = rfkill_register(rbtn_data->rfkill); 131 if (ret) { 132 rfkill_destroy(rbtn_data->rfkill); 133 rbtn_data->rfkill = NULL; 134 return ret; 135 } 136 137 return 0; 138 } 139 140 static void rbtn_rfkill_exit(struct acpi_device *device) 141 { 142 struct rbtn_data *rbtn_data = device->driver_data; 143 144 if (!rbtn_data->rfkill) 145 return; 146 147 rfkill_unregister(rbtn_data->rfkill); 148 rfkill_destroy(rbtn_data->rfkill); 149 rbtn_data->rfkill = NULL; 150 } 151 152 static void rbtn_rfkill_event(struct acpi_device *device) 153 { 154 struct rbtn_data *rbtn_data = device->driver_data; 155 156 if (rbtn_data->rfkill) 157 rbtn_rfkill_query(rbtn_data->rfkill, device); 158 } 159 160 161 /* 162 * input device 163 */ 164 165 static int rbtn_input_init(struct rbtn_data *rbtn_data) 166 { 167 int ret; 168 169 rbtn_data->input_dev = input_allocate_device(); 170 if (!rbtn_data->input_dev) 171 return -ENOMEM; 172 173 rbtn_data->input_dev->name = "DELL Wireless hotkeys"; 174 rbtn_data->input_dev->phys = "dellabce/input0"; 175 rbtn_data->input_dev->id.bustype = BUS_HOST; 176 rbtn_data->input_dev->evbit[0] = BIT(EV_KEY); 177 set_bit(KEY_RFKILL, rbtn_data->input_dev->keybit); 178 179 ret = input_register_device(rbtn_data->input_dev); 180 if (ret) { 181 input_free_device(rbtn_data->input_dev); 182 rbtn_data->input_dev = NULL; 183 return ret; 184 } 185 186 return 0; 187 } 188 189 static void rbtn_input_exit(struct rbtn_data *rbtn_data) 190 { 191 input_unregister_device(rbtn_data->input_dev); 192 rbtn_data->input_dev = NULL; 193 } 194 195 static void rbtn_input_event(struct rbtn_data *rbtn_data) 196 { 197 input_report_key(rbtn_data->input_dev, KEY_RFKILL, 1); 198 input_sync(rbtn_data->input_dev); 199 input_report_key(rbtn_data->input_dev, KEY_RFKILL, 0); 200 input_sync(rbtn_data->input_dev); 201 } 202 203 204 /* 205 * acpi driver 206 */ 207 208 static int rbtn_add(struct acpi_device *device); 209 static void rbtn_remove(struct acpi_device *device); 210 static void rbtn_notify(struct acpi_device *device, u32 event); 211 212 static const struct acpi_device_id rbtn_ids[] = { 213 { "DELRBTN", 0 }, 214 { "DELLABCE", 0 }, 215 216 /* 217 * This driver can also handle the "DELLABC6" device that 218 * appears on the XPS 13 9350, but that device is disabled by 219 * the DSDT unless booted with acpi_osi="!Windows 2012" 220 * acpi_osi="!Windows 2013". 221 * 222 * According to Mario at Dell: 223 * 224 * DELLABC6 is a custom interface that was created solely to 225 * have airplane mode support for Windows 7. For Windows 10 226 * the proper interface is to use that which is handled by 227 * intel-hid. A OEM airplane mode driver is not used. 228 * 229 * Since the kernel doesn't identify as Windows 7 it would be 230 * incorrect to do attempt to use that interface. 231 * 232 * Even if we override _OSI and bind to DELLABC6, we end up with 233 * inconsistent behavior in which userspace can get out of sync 234 * with the rfkill state as it conflicts with events from 235 * intel-hid. 236 * 237 * The upshot is that it is better to just ignore DELLABC6 238 * devices. 239 */ 240 241 { "", 0 }, 242 }; 243 244 #ifdef CONFIG_PM_SLEEP 245 static void ACPI_SYSTEM_XFACE rbtn_clear_suspended_flag(void *context) 246 { 247 struct rbtn_data *rbtn_data = context; 248 249 rbtn_data->suspended = false; 250 } 251 252 static int rbtn_suspend(struct device *dev) 253 { 254 struct acpi_device *device = to_acpi_device(dev); 255 struct rbtn_data *rbtn_data = acpi_driver_data(device); 256 257 rbtn_data->suspended = true; 258 259 return 0; 260 } 261 262 static int rbtn_resume(struct device *dev) 263 { 264 struct acpi_device *device = to_acpi_device(dev); 265 struct rbtn_data *rbtn_data = acpi_driver_data(device); 266 acpi_status status; 267 268 /* 269 * Upon resume, some BIOSes send an ACPI notification thet triggers 270 * an unwanted input event. In order to ignore it, we use a flag 271 * that we set at suspend and clear once we have received the extra 272 * ACPI notification. Since ACPI notifications are delivered 273 * asynchronously to drivers, we clear the flag from the workqueue 274 * used to deliver the notifications. This should be enough 275 * to have the flag cleared only after we received the extra 276 * notification, if any. 277 */ 278 status = acpi_os_execute(OSL_NOTIFY_HANDLER, 279 rbtn_clear_suspended_flag, rbtn_data); 280 if (ACPI_FAILURE(status)) 281 rbtn_clear_suspended_flag(rbtn_data); 282 283 return 0; 284 } 285 #endif 286 287 static SIMPLE_DEV_PM_OPS(rbtn_pm_ops, rbtn_suspend, rbtn_resume); 288 289 static struct acpi_driver rbtn_driver = { 290 .name = "dell-rbtn", 291 .ids = rbtn_ids, 292 .drv.pm = &rbtn_pm_ops, 293 .ops = { 294 .add = rbtn_add, 295 .remove = rbtn_remove, 296 .notify = rbtn_notify, 297 }, 298 }; 299 300 301 /* 302 * notifier export functions 303 */ 304 305 static bool auto_remove_rfkill = true; 306 307 static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head); 308 309 static int rbtn_inc_count(struct device *dev, void *data) 310 { 311 struct acpi_device *device = to_acpi_device(dev); 312 struct rbtn_data *rbtn_data = device->driver_data; 313 int *count = data; 314 315 if (rbtn_data->type == RBTN_SLIDER) 316 (*count)++; 317 318 return 0; 319 } 320 321 static int rbtn_switch_dev(struct device *dev, void *data) 322 { 323 struct acpi_device *device = to_acpi_device(dev); 324 struct rbtn_data *rbtn_data = device->driver_data; 325 bool enable = data; 326 327 if (rbtn_data->type != RBTN_SLIDER) 328 return 0; 329 330 if (enable) 331 rbtn_rfkill_init(device); 332 else 333 rbtn_rfkill_exit(device); 334 335 return 0; 336 } 337 338 int dell_rbtn_notifier_register(struct notifier_block *nb) 339 { 340 bool first; 341 int count; 342 int ret; 343 344 count = 0; 345 ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count, 346 rbtn_inc_count); 347 if (ret || count == 0) 348 return -ENODEV; 349 350 first = !rbtn_chain_head.head; 351 352 ret = atomic_notifier_chain_register(&rbtn_chain_head, nb); 353 if (ret != 0) 354 return ret; 355 356 if (auto_remove_rfkill && first) 357 ret = driver_for_each_device(&rbtn_driver.drv, NULL, 358 (void *)false, rbtn_switch_dev); 359 360 return ret; 361 } 362 EXPORT_SYMBOL_GPL(dell_rbtn_notifier_register); 363 364 int dell_rbtn_notifier_unregister(struct notifier_block *nb) 365 { 366 int ret; 367 368 ret = atomic_notifier_chain_unregister(&rbtn_chain_head, nb); 369 if (ret != 0) 370 return ret; 371 372 if (auto_remove_rfkill && !rbtn_chain_head.head) 373 ret = driver_for_each_device(&rbtn_driver.drv, NULL, 374 (void *)true, rbtn_switch_dev); 375 376 return ret; 377 } 378 EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister); 379 380 381 /* 382 * acpi driver functions 383 */ 384 385 static int rbtn_add(struct acpi_device *device) 386 { 387 struct rbtn_data *rbtn_data; 388 enum rbtn_type type; 389 int ret = 0; 390 391 type = rbtn_check(device); 392 if (type == RBTN_UNKNOWN) { 393 dev_info(&device->dev, "Unknown device type\n"); 394 return -EINVAL; 395 } 396 397 rbtn_data = devm_kzalloc(&device->dev, sizeof(*rbtn_data), GFP_KERNEL); 398 if (!rbtn_data) 399 return -ENOMEM; 400 401 ret = rbtn_acquire(device, true); 402 if (ret < 0) { 403 dev_err(&device->dev, "Cannot enable device\n"); 404 return ret; 405 } 406 407 rbtn_data->type = type; 408 device->driver_data = rbtn_data; 409 410 switch (rbtn_data->type) { 411 case RBTN_TOGGLE: 412 ret = rbtn_input_init(rbtn_data); 413 break; 414 case RBTN_SLIDER: 415 if (auto_remove_rfkill && rbtn_chain_head.head) 416 ret = 0; 417 else 418 ret = rbtn_rfkill_init(device); 419 break; 420 default: 421 ret = -EINVAL; 422 break; 423 } 424 if (ret) 425 rbtn_acquire(device, false); 426 427 return ret; 428 } 429 430 static void rbtn_remove(struct acpi_device *device) 431 { 432 struct rbtn_data *rbtn_data = device->driver_data; 433 434 switch (rbtn_data->type) { 435 case RBTN_TOGGLE: 436 rbtn_input_exit(rbtn_data); 437 break; 438 case RBTN_SLIDER: 439 rbtn_rfkill_exit(device); 440 break; 441 default: 442 break; 443 } 444 445 rbtn_acquire(device, false); 446 } 447 448 static void rbtn_notify(struct acpi_device *device, u32 event) 449 { 450 struct rbtn_data *rbtn_data = device->driver_data; 451 452 /* 453 * Some BIOSes send a notification at resume. 454 * Ignore it to prevent unwanted input events. 455 */ 456 if (rbtn_data->suspended) { 457 dev_dbg(&device->dev, "ACPI notification ignored\n"); 458 return; 459 } 460 461 if (event != 0x80) { 462 dev_info(&device->dev, "Received unknown event (0x%x)\n", 463 event); 464 return; 465 } 466 467 switch (rbtn_data->type) { 468 case RBTN_TOGGLE: 469 rbtn_input_event(rbtn_data); 470 break; 471 case RBTN_SLIDER: 472 rbtn_rfkill_event(device); 473 atomic_notifier_call_chain(&rbtn_chain_head, event, device); 474 break; 475 default: 476 break; 477 } 478 } 479 480 481 /* 482 * module functions 483 */ 484 485 module_acpi_driver(rbtn_driver); 486 487 module_param(auto_remove_rfkill, bool, 0444); 488 489 MODULE_PARM_DESC(auto_remove_rfkill, "Automatically remove rfkill devices when " 490 "other modules start receiving events " 491 "from this module and re-add them when " 492 "the last module stops receiving events " 493 "(default true)"); 494 MODULE_DEVICE_TABLE(acpi, rbtn_ids); 495 MODULE_DESCRIPTION("Dell Airplane Mode Switch driver"); 496 MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); 497 MODULE_LICENSE("GPL"); 498