treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 157
[sfrench/cifs-2.6.git] / drivers / platform / x86 / dell-rbtn.c
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.rohar@gmail.com>
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 = &param;
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 int 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 int 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         return 0;
448 }
449
450 static void rbtn_notify(struct acpi_device *device, u32 event)
451 {
452         struct rbtn_data *rbtn_data = device->driver_data;
453
454         /*
455          * Some BIOSes send a notification at resume.
456          * Ignore it to prevent unwanted input events.
457          */
458         if (rbtn_data->suspended) {
459                 dev_dbg(&device->dev, "ACPI notification ignored\n");
460                 return;
461         }
462
463         if (event != 0x80) {
464                 dev_info(&device->dev, "Received unknown event (0x%x)\n",
465                          event);
466                 return;
467         }
468
469         switch (rbtn_data->type) {
470         case RBTN_TOGGLE:
471                 rbtn_input_event(rbtn_data);
472                 break;
473         case RBTN_SLIDER:
474                 rbtn_rfkill_event(device);
475                 atomic_notifier_call_chain(&rbtn_chain_head, event, device);
476                 break;
477         default:
478                 break;
479         }
480 }
481
482
483 /*
484  * module functions
485  */
486
487 module_acpi_driver(rbtn_driver);
488
489 module_param(auto_remove_rfkill, bool, 0444);
490
491 MODULE_PARM_DESC(auto_remove_rfkill, "Automatically remove rfkill devices when "
492                                      "other modules start receiving events "
493                                      "from this module and re-add them when "
494                                      "the last module stops receiving events "
495                                      "(default true)");
496 MODULE_DEVICE_TABLE(acpi, rbtn_ids);
497 MODULE_DESCRIPTION("Dell Airplane Mode Switch driver");
498 MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
499 MODULE_LICENSE("GPL");