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 .owner = THIS_MODULE, 299 }; 300 301 302 /* 303 * notifier export functions 304 */ 305 306 static bool auto_remove_rfkill = true; 307 308 static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head); 309 310 static int rbtn_inc_count(struct device *dev, void *data) 311 { 312 struct acpi_device *device = to_acpi_device(dev); 313 struct rbtn_data *rbtn_data = device->driver_data; 314 int *count = data; 315 316 if (rbtn_data->type == RBTN_SLIDER) 317 (*count)++; 318 319 return 0; 320 } 321 322 static int rbtn_switch_dev(struct device *dev, void *data) 323 { 324 struct acpi_device *device = to_acpi_device(dev); 325 struct rbtn_data *rbtn_data = device->driver_data; 326 bool enable = data; 327 328 if (rbtn_data->type != RBTN_SLIDER) 329 return 0; 330 331 if (enable) 332 rbtn_rfkill_init(device); 333 else 334 rbtn_rfkill_exit(device); 335 336 return 0; 337 } 338 339 int dell_rbtn_notifier_register(struct notifier_block *nb) 340 { 341 bool first; 342 int count; 343 int ret; 344 345 count = 0; 346 ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count, 347 rbtn_inc_count); 348 if (ret || count == 0) 349 return -ENODEV; 350 351 first = !rbtn_chain_head.head; 352 353 ret = atomic_notifier_chain_register(&rbtn_chain_head, nb); 354 if (ret != 0) 355 return ret; 356 357 if (auto_remove_rfkill && first) 358 ret = driver_for_each_device(&rbtn_driver.drv, NULL, 359 (void *)false, rbtn_switch_dev); 360 361 return ret; 362 } 363 EXPORT_SYMBOL_GPL(dell_rbtn_notifier_register); 364 365 int dell_rbtn_notifier_unregister(struct notifier_block *nb) 366 { 367 int ret; 368 369 ret = atomic_notifier_chain_unregister(&rbtn_chain_head, nb); 370 if (ret != 0) 371 return ret; 372 373 if (auto_remove_rfkill && !rbtn_chain_head.head) 374 ret = driver_for_each_device(&rbtn_driver.drv, NULL, 375 (void *)true, rbtn_switch_dev); 376 377 return ret; 378 } 379 EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister); 380 381 382 /* 383 * acpi driver functions 384 */ 385 386 static int rbtn_add(struct acpi_device *device) 387 { 388 struct rbtn_data *rbtn_data; 389 enum rbtn_type type; 390 int ret = 0; 391 392 type = rbtn_check(device); 393 if (type == RBTN_UNKNOWN) { 394 dev_info(&device->dev, "Unknown device type\n"); 395 return -EINVAL; 396 } 397 398 ret = rbtn_acquire(device, true); 399 if (ret < 0) { 400 dev_err(&device->dev, "Cannot enable device\n"); 401 return ret; 402 } 403 404 rbtn_data = devm_kzalloc(&device->dev, sizeof(*rbtn_data), GFP_KERNEL); 405 if (!rbtn_data) 406 return -ENOMEM; 407 408 rbtn_data->type = type; 409 device->driver_data = rbtn_data; 410 411 switch (rbtn_data->type) { 412 case RBTN_TOGGLE: 413 ret = rbtn_input_init(rbtn_data); 414 break; 415 case RBTN_SLIDER: 416 if (auto_remove_rfkill && rbtn_chain_head.head) 417 ret = 0; 418 else 419 ret = rbtn_rfkill_init(device); 420 break; 421 default: 422 ret = -EINVAL; 423 } 424 425 return ret; 426 427 } 428 429 static void rbtn_remove(struct acpi_device *device) 430 { 431 struct rbtn_data *rbtn_data = device->driver_data; 432 433 switch (rbtn_data->type) { 434 case RBTN_TOGGLE: 435 rbtn_input_exit(rbtn_data); 436 break; 437 case RBTN_SLIDER: 438 rbtn_rfkill_exit(device); 439 break; 440 default: 441 break; 442 } 443 444 rbtn_acquire(device, false); 445 device->driver_data = NULL; 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