dell-rbtn.c 10 KB

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