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