]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/platform/x86/huawei-wmi.c
platform/x86: huawei-wmi: No need to check for battery name
[linux.git] / drivers / platform / x86 / huawei-wmi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Huawei WMI laptop extras driver
4  *
5  *  Copyright (C) 2018        Ayman Bagabas <ayman.bagabas@gmail.com>
6  */
7
8 #include <linux/acpi.h>
9 #include <linux/debugfs.h>
10 #include <linux/delay.h>
11 #include <linux/dmi.h>
12 #include <linux/input.h>
13 #include <linux/input/sparse-keymap.h>
14 #include <linux/leds.h>
15 #include <linux/module.h>
16 #include <linux/mutex.h>
17 #include <linux/platform_device.h>
18 #include <linux/power_supply.h>
19 #include <linux/sysfs.h>
20 #include <linux/wmi.h>
21 #include <acpi/battery.h>
22
23 /*
24  * Huawei WMI GUIDs
25  */
26 #define HWMI_METHOD_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000"
27 #define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
28
29 /* Legacy GUIDs */
30 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
31 #define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
32
33 /* HWMI commands */
34
35 enum {
36         BATTERY_THRESH_GET              = 0x00001103, /* \GBTT */
37         BATTERY_THRESH_SET              = 0x00001003, /* \SBTT */
38         FN_LOCK_GET                     = 0x00000604, /* \GFRS */
39         FN_LOCK_SET                     = 0x00000704, /* \SFRS */
40         MICMUTE_LED_SET                 = 0x00000b04, /* \SMLS */
41 };
42
43 union hwmi_arg {
44         u64 cmd;
45         u8 args[8];
46 };
47
48 struct quirk_entry {
49         bool battery_reset;
50         bool ec_micmute;
51         bool report_brightness;
52 };
53
54 static struct quirk_entry *quirks;
55
56 struct huawei_wmi_debug {
57         struct dentry *root;
58         u64 arg;
59 };
60
61 struct huawei_wmi {
62         bool battery_available;
63         bool fn_lock_available;
64
65         struct huawei_wmi_debug debug;
66         struct input_dev *idev[2];
67         struct led_classdev cdev;
68         struct device *dev;
69
70         struct mutex battery_lock;
71         struct mutex wmi_lock;
72 };
73
74 static struct huawei_wmi *huawei_wmi;
75
76 static const struct key_entry huawei_wmi_keymap[] = {
77         { KE_KEY,    0x281, { KEY_BRIGHTNESSDOWN } },
78         { KE_KEY,    0x282, { KEY_BRIGHTNESSUP } },
79         { KE_KEY,    0x284, { KEY_MUTE } },
80         { KE_KEY,    0x285, { KEY_VOLUMEDOWN } },
81         { KE_KEY,    0x286, { KEY_VOLUMEUP } },
82         { KE_KEY,    0x287, { KEY_MICMUTE } },
83         { KE_KEY,    0x289, { KEY_WLAN } },
84         // Huawei |M| key
85         { KE_KEY,    0x28a, { KEY_CONFIG } },
86         // Keyboard backlit
87         { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
88         { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
89         { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
90         { KE_END,        0 }
91 };
92
93 static int battery_reset = -1;
94 static int report_brightness = -1;
95
96 module_param(battery_reset, bint, 0444);
97 MODULE_PARM_DESC(battery_reset,
98                 "Reset battery charge values to (0-0) before disabling it using (0-100)");
99 module_param(report_brightness, bint, 0444);
100 MODULE_PARM_DESC(report_brightness,
101                 "Report brightness keys.");
102
103 /* Quirks */
104
105 static int __init dmi_matched(const struct dmi_system_id *dmi)
106 {
107         quirks = dmi->driver_data;
108         return 1;
109 }
110
111 static struct quirk_entry quirk_unknown = {
112 };
113
114 static struct quirk_entry quirk_battery_reset = {
115         .battery_reset = true,
116 };
117
118 static struct quirk_entry quirk_matebook_x = {
119         .ec_micmute = true,
120         .report_brightness = true,
121 };
122
123 static const struct dmi_system_id huawei_quirks[] = {
124         {
125                 .callback = dmi_matched,
126                 .ident = "Huawei MACH-WX9",
127                 .matches = {
128                         DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
129                         DMI_MATCH(DMI_PRODUCT_NAME, "MACH-WX9"),
130                 },
131                 .driver_data = &quirk_battery_reset
132         },
133         {
134                 .callback = dmi_matched,
135                 .ident = "Huawei MateBook X",
136                 .matches = {
137                         DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
138                         DMI_MATCH(DMI_PRODUCT_NAME, "HUAWEI MateBook X")
139                 },
140                 .driver_data = &quirk_matebook_x
141         },
142         {  }
143 };
144
145 /* Utils */
146
147 static int huawei_wmi_call(struct huawei_wmi *huawei,
148                            struct acpi_buffer *in, struct acpi_buffer *out)
149 {
150         acpi_status status;
151
152         mutex_lock(&huawei->wmi_lock);
153         status = wmi_evaluate_method(HWMI_METHOD_GUID, 0, 1, in, out);
154         mutex_unlock(&huawei->wmi_lock);
155         if (ACPI_FAILURE(status)) {
156                 dev_err(huawei->dev, "Failed to evaluate wmi method\n");
157                 return -ENODEV;
158         }
159
160         return 0;
161 }
162
163 /* HWMI takes a 64 bit input and returns either a package with 2 buffers, one of
164  * 4 bytes and the other of 256 bytes, or one buffer of size 0x104 (260) bytes.
165  * The first 4 bytes are ignored, we ignore the first 4 bytes buffer if we got a
166  * package, or skip the first 4 if a buffer of 0x104 is used. The first byte of
167  * the remaining 0x100 sized buffer has the return status of every call. In case
168  * the return status is non-zero, we return -ENODEV but still copy the returned
169  * buffer to the given buffer parameter (buf).
170  */
171 static int huawei_wmi_cmd(u64 arg, u8 *buf, size_t buflen)
172 {
173         struct huawei_wmi *huawei = huawei_wmi;
174         struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
175         struct acpi_buffer in;
176         union acpi_object *obj;
177         size_t len;
178         int err, i;
179
180         in.length = sizeof(arg);
181         in.pointer = &arg;
182
183         /* Some models require calling HWMI twice to execute a command. We evaluate
184          * HWMI and if we get a non-zero return status we evaluate it again.
185          */
186         for (i = 0; i < 2; i++) {
187                 err = huawei_wmi_call(huawei, &in, &out);
188                 if (err)
189                         goto fail_cmd;
190
191                 obj = out.pointer;
192                 if (!obj) {
193                         err = -EIO;
194                         goto fail_cmd;
195                 }
196
197                 switch (obj->type) {
198                 /* Models that implement both "legacy" and HWMI tend to return a 0x104
199                  * sized buffer instead of a package of 0x4 and 0x100 buffers.
200                  */
201                 case ACPI_TYPE_BUFFER:
202                         if (obj->buffer.length == 0x104) {
203                                 // Skip the first 4 bytes.
204                                 obj->buffer.pointer += 4;
205                                 len = 0x100;
206                         } else {
207                                 dev_err(huawei->dev, "Bad buffer length, got %d\n", obj->buffer.length);
208                                 err = -EIO;
209                                 goto fail_cmd;
210                         }
211
212                         break;
213                 /* HWMI returns a package with 2 buffer elements, one of 4 bytes and the
214                  * other is 256 bytes.
215                  */
216                 case ACPI_TYPE_PACKAGE:
217                         if (obj->package.count != 2) {
218                                 dev_err(huawei->dev, "Bad package count, got %d\n", obj->package.count);
219                                 err = -EIO;
220                                 goto fail_cmd;
221                         }
222
223                         obj = &obj->package.elements[1];
224                         if (obj->type != ACPI_TYPE_BUFFER) {
225                                 dev_err(huawei->dev, "Bad package element type, got %d\n", obj->type);
226                                 err = -EIO;
227                                 goto fail_cmd;
228                         }
229                         len = obj->buffer.length;
230
231                         break;
232                 /* Shouldn't get here! */
233                 default:
234                         dev_err(huawei->dev, "Unexpected obj type, got: %d\n", obj->type);
235                         err = -EIO;
236                         goto fail_cmd;
237                 }
238
239                 if (!*obj->buffer.pointer)
240                         break;
241         }
242
243         err = (*obj->buffer.pointer) ? -ENODEV : 0;
244
245         if (buf) {
246                 len = min(buflen, len);
247                 memcpy(buf, obj->buffer.pointer, len);
248         }
249
250 fail_cmd:
251         kfree(out.pointer);
252         return err;
253 }
254
255 /* LEDs */
256
257 static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
258                 enum led_brightness brightness)
259 {
260         /* This is a workaround until the "legacy" interface is implemented. */
261         if (quirks && quirks->ec_micmute) {
262                 char *acpi_method;
263                 acpi_handle handle;
264                 acpi_status status;
265                 union acpi_object args[3];
266                 struct acpi_object_list arg_list = {
267                         .pointer = args,
268                         .count = ARRAY_SIZE(args),
269                 };
270
271                 handle = ec_get_handle();
272                 if (!handle)
273                         return -ENODEV;
274
275                 args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
276                 args[1].integer.value = 0x04;
277
278                 if (acpi_has_method(handle, "SPIN")) {
279                         acpi_method = "SPIN";
280                         args[0].integer.value = 0;
281                         args[2].integer.value = brightness ? 1 : 0;
282                 } else if (acpi_has_method(handle, "WPIN")) {
283                         acpi_method = "WPIN";
284                         args[0].integer.value = 1;
285                         args[2].integer.value = brightness ? 0 : 1;
286                 } else {
287                         return -ENODEV;
288                 }
289
290                 status = acpi_evaluate_object(handle, acpi_method, &arg_list, NULL);
291                 if (ACPI_FAILURE(status))
292                         return -ENODEV;
293
294                 return 0;
295         } else {
296                 union hwmi_arg arg;
297
298                 arg.cmd = MICMUTE_LED_SET;
299                 arg.args[2] = brightness;
300
301                 return huawei_wmi_cmd(arg.cmd, NULL, 0);
302         }
303 }
304
305 static void huawei_wmi_leds_setup(struct device *dev)
306 {
307         struct huawei_wmi *huawei = dev_get_drvdata(dev);
308
309         huawei->cdev.name = "platform::micmute";
310         huawei->cdev.max_brightness = 1;
311         huawei->cdev.brightness_set_blocking = &huawei_wmi_micmute_led_set;
312         huawei->cdev.default_trigger = "audio-micmute";
313         huawei->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
314         huawei->cdev.dev = dev;
315         huawei->cdev.flags = LED_CORE_SUSPENDRESUME;
316
317         devm_led_classdev_register(dev, &huawei->cdev);
318 }
319
320 /* Battery protection */
321
322 static int huawei_wmi_battery_get(int *start, int *end)
323 {
324         u8 ret[0x100];
325         int err, i;
326
327         err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100);
328         if (err)
329                 return err;
330
331         /* Find the last two non-zero values. Return status is ignored. */
332         i = 0xff;
333         do {
334                 if (start)
335                         *start = ret[i-1];
336                 if (end)
337                         *end = ret[i];
338         } while (i > 2 && !ret[i--]);
339
340         return 0;
341 }
342
343 static int huawei_wmi_battery_set(int start, int end)
344 {
345         union hwmi_arg arg;
346         int err;
347
348         if (start < 0 || end < 0 || start > 100 || end > 100)
349                 return -EINVAL;
350
351         arg.cmd = BATTERY_THRESH_SET;
352         arg.args[2] = start;
353         arg.args[3] = end;
354
355         /* This is an edge case were some models turn battery protection
356          * off without changing their thresholds values. We clear the
357          * values before turning off protection. Sometimes we need a sleep delay to
358          * make sure these values make their way to EC memory.
359          */
360         if (quirks && quirks->battery_reset && start == 0 && end == 100) {
361                 err = huawei_wmi_battery_set(0, 0);
362                 if (err)
363                         return err;
364
365                 msleep(1000);
366         }
367
368         err = huawei_wmi_cmd(arg.cmd, NULL, 0);
369
370         return err;
371 }
372
373 static ssize_t charge_control_start_threshold_show(struct device *dev,
374                 struct device_attribute *attr,
375                 char *buf)
376 {
377         int err, start;
378
379         err = huawei_wmi_battery_get(&start, NULL);
380         if (err)
381                 return err;
382
383         return sprintf(buf, "%d\n", start);
384 }
385
386 static ssize_t charge_control_end_threshold_show(struct device *dev,
387                 struct device_attribute *attr,
388                 char *buf)
389 {
390         int err, end;
391
392         err = huawei_wmi_battery_get(NULL, &end);
393         if (err)
394                 return err;
395
396         return sprintf(buf, "%d\n", end);
397 }
398
399 static ssize_t charge_control_thresholds_show(struct device *dev,
400                 struct device_attribute *attr,
401                 char *buf)
402 {
403         int err, start, end;
404
405         err = huawei_wmi_battery_get(&start, &end);
406         if (err)
407                 return err;
408
409         return sprintf(buf, "%d %d\n", start, end);
410 }
411
412 static ssize_t charge_control_start_threshold_store(struct device *dev,
413                 struct device_attribute *attr,
414                 const char *buf, size_t size)
415 {
416         int err, start, end;
417
418         err = huawei_wmi_battery_get(NULL, &end);
419         if (err)
420                 return err;
421
422         if (sscanf(buf, "%d", &start) != 1)
423                 return -EINVAL;
424
425         err = huawei_wmi_battery_set(start, end);
426         if (err)
427                 return err;
428
429         return size;
430 }
431
432 static ssize_t charge_control_end_threshold_store(struct device *dev,
433                 struct device_attribute *attr,
434                 const char *buf, size_t size)
435 {
436         int err, start, end;
437
438         err = huawei_wmi_battery_get(&start, NULL);
439         if (err)
440                 return err;
441
442         if (sscanf(buf, "%d", &end) != 1)
443                 return -EINVAL;
444
445         err = huawei_wmi_battery_set(start, end);
446         if (err)
447                 return err;
448
449         return size;
450 }
451
452 static ssize_t charge_control_thresholds_store(struct device *dev,
453                 struct device_attribute *attr,
454                 const char *buf, size_t size)
455 {
456         int err, start, end;
457
458         if (sscanf(buf, "%d %d", &start, &end) != 2)
459                 return -EINVAL;
460
461         err = huawei_wmi_battery_set(start, end);
462         if (err)
463                 return err;
464
465         return size;
466 }
467
468 static DEVICE_ATTR_RW(charge_control_start_threshold);
469 static DEVICE_ATTR_RW(charge_control_end_threshold);
470 static DEVICE_ATTR_RW(charge_control_thresholds);
471
472 static int huawei_wmi_battery_add(struct power_supply *battery)
473 {
474         device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold);
475         device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold);
476
477         return 0;
478 }
479
480 static int huawei_wmi_battery_remove(struct power_supply *battery)
481 {
482         device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold);
483         device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold);
484
485         return 0;
486 }
487
488 static struct acpi_battery_hook huawei_wmi_battery_hook = {
489         .add_battery = huawei_wmi_battery_add,
490         .remove_battery = huawei_wmi_battery_remove,
491         .name = "Huawei Battery Extension"
492 };
493
494 static void huawei_wmi_battery_setup(struct device *dev)
495 {
496         struct huawei_wmi *huawei = dev_get_drvdata(dev);
497
498         huawei->battery_available = true;
499         if (huawei_wmi_battery_get(NULL, NULL)) {
500                 huawei->battery_available = false;
501                 return;
502         }
503
504         battery_hook_register(&huawei_wmi_battery_hook);
505         device_create_file(dev, &dev_attr_charge_control_thresholds);
506 }
507
508 static void huawei_wmi_battery_exit(struct device *dev)
509 {
510         struct huawei_wmi *huawei = dev_get_drvdata(dev);
511
512         if (huawei->battery_available) {
513                 battery_hook_unregister(&huawei_wmi_battery_hook);
514                 device_remove_file(dev, &dev_attr_charge_control_thresholds);
515         }
516 }
517
518 /* Fn lock */
519
520 static int huawei_wmi_fn_lock_get(int *on)
521 {
522         u8 ret[0x100] = { 0 };
523         int err, i;
524
525         err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100);
526         if (err)
527                 return err;
528
529         /* Find the first non-zero value. Return status is ignored. */
530         i = 1;
531         do {
532                 if (on)
533                         *on = ret[i] - 1; // -1 undefined, 0 off, 1 on.
534         } while (i < 0xff && !ret[i++]);
535
536         return 0;
537 }
538
539 static int huawei_wmi_fn_lock_set(int on)
540 {
541         union hwmi_arg arg;
542
543         arg.cmd = FN_LOCK_SET;
544         arg.args[2] = on + 1; // 0 undefined, 1 off, 2 on.
545
546         return huawei_wmi_cmd(arg.cmd, NULL, 0);
547 }
548
549 static ssize_t fn_lock_state_show(struct device *dev,
550                 struct device_attribute *attr,
551                 char *buf)
552 {
553         int err, on;
554
555         err = huawei_wmi_fn_lock_get(&on);
556         if (err)
557                 return err;
558
559         return sprintf(buf, "%d\n", on);
560 }
561
562 static ssize_t fn_lock_state_store(struct device *dev,
563                 struct device_attribute *attr,
564                 const char *buf, size_t size)
565 {
566         int on, err;
567
568         if (kstrtoint(buf, 10, &on) ||
569                         on < 0 || on > 1)
570                 return -EINVAL;
571
572         err = huawei_wmi_fn_lock_set(on);
573         if (err)
574                 return err;
575
576         return size;
577 }
578
579 static DEVICE_ATTR_RW(fn_lock_state);
580
581 static void huawei_wmi_fn_lock_setup(struct device *dev)
582 {
583         struct huawei_wmi *huawei = dev_get_drvdata(dev);
584
585         huawei->fn_lock_available = true;
586         if (huawei_wmi_fn_lock_get(NULL)) {
587                 huawei->fn_lock_available = false;
588                 return;
589         }
590
591         device_create_file(dev, &dev_attr_fn_lock_state);
592 }
593
594 static void huawei_wmi_fn_lock_exit(struct device *dev)
595 {
596         struct huawei_wmi *huawei = dev_get_drvdata(dev);
597
598         if (huawei->fn_lock_available)
599                 device_remove_file(dev, &dev_attr_fn_lock_state);
600 }
601
602 /* debugfs */
603
604 static void huawei_wmi_debugfs_call_dump(struct seq_file *m, void *data,
605                 union acpi_object *obj)
606 {
607         struct huawei_wmi *huawei = m->private;
608         int i;
609
610         switch (obj->type) {
611         case ACPI_TYPE_INTEGER:
612                 seq_printf(m, "0x%llx", obj->integer.value);
613                 break;
614         case ACPI_TYPE_STRING:
615                 seq_printf(m, "\"%.*s\"", obj->string.length, obj->string.pointer);
616                 break;
617         case ACPI_TYPE_BUFFER:
618                 seq_puts(m, "{");
619                 for (i = 0; i < obj->buffer.length; i++) {
620                         seq_printf(m, "0x%02x", obj->buffer.pointer[i]);
621                         if (i < obj->buffer.length - 1)
622                                 seq_puts(m, ",");
623                 }
624                 seq_puts(m, "}");
625                 break;
626         case ACPI_TYPE_PACKAGE:
627                 seq_puts(m, "[");
628                 for (i = 0; i < obj->package.count; i++) {
629                         huawei_wmi_debugfs_call_dump(m, huawei, &obj->package.elements[i]);
630                         if (i < obj->package.count - 1)
631                                 seq_puts(m, ",");
632                 }
633                 seq_puts(m, "]");
634                 break;
635         default:
636                 dev_err(huawei->dev, "Unexpected obj type, got %d\n", obj->type);
637                 return;
638         }
639 }
640
641 static int huawei_wmi_debugfs_call_show(struct seq_file *m, void *data)
642 {
643         struct huawei_wmi *huawei = m->private;
644         struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
645         struct acpi_buffer in;
646         union acpi_object *obj;
647         int err;
648
649         in.length = sizeof(u64);
650         in.pointer = &huawei->debug.arg;
651
652         err = huawei_wmi_call(huawei, &in, &out);
653         if (err)
654                 return err;
655
656         obj = out.pointer;
657         if (!obj) {
658                 err = -EIO;
659                 goto fail_debugfs_call;
660         }
661
662         huawei_wmi_debugfs_call_dump(m, huawei, obj);
663
664 fail_debugfs_call:
665         kfree(out.pointer);
666         return err;
667 }
668
669 DEFINE_SHOW_ATTRIBUTE(huawei_wmi_debugfs_call);
670
671 static void huawei_wmi_debugfs_setup(struct device *dev)
672 {
673         struct huawei_wmi *huawei = dev_get_drvdata(dev);
674
675         huawei->debug.root = debugfs_create_dir("huawei-wmi", NULL);
676
677         debugfs_create_x64("arg", 0644, huawei->debug.root,
678                 &huawei->debug.arg);
679         debugfs_create_file("call", 0400,
680                 huawei->debug.root, huawei, &huawei_wmi_debugfs_call_fops);
681 }
682
683 static void huawei_wmi_debugfs_exit(struct device *dev)
684 {
685         struct huawei_wmi *huawei = dev_get_drvdata(dev);
686
687         debugfs_remove_recursive(huawei->debug.root);
688 }
689
690 /* Input */
691
692 static void huawei_wmi_process_key(struct input_dev *idev, int code)
693 {
694         const struct key_entry *key;
695
696         /*
697          * WMI0 uses code 0x80 to indicate a hotkey event.
698          * The actual key is fetched from the method WQ00
699          * using WMI0_EXPENSIVE_GUID.
700          */
701         if (code == 0x80) {
702                 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
703                 union acpi_object *obj;
704                 acpi_status status;
705
706                 status = wmi_query_block(WMI0_EXPENSIVE_GUID, 0, &response);
707                 if (ACPI_FAILURE(status))
708                         return;
709
710                 obj = (union acpi_object *)response.pointer;
711                 if (obj && obj->type == ACPI_TYPE_INTEGER)
712                         code = obj->integer.value;
713
714                 kfree(response.pointer);
715         }
716
717         key = sparse_keymap_entry_from_scancode(idev, code);
718         if (!key) {
719                 dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code);
720                 return;
721         }
722
723         if (quirks && !quirks->report_brightness &&
724                         (key->sw.code == KEY_BRIGHTNESSDOWN ||
725                         key->sw.code == KEY_BRIGHTNESSUP))
726                 return;
727
728         sparse_keymap_report_entry(idev, key, 1, true);
729 }
730
731 static void huawei_wmi_input_notify(u32 value, void *context)
732 {
733         struct input_dev *idev = (struct input_dev *)context;
734         struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
735         union acpi_object *obj;
736         acpi_status status;
737
738         status = wmi_get_event_data(value, &response);
739         if (ACPI_FAILURE(status)) {
740                 dev_err(&idev->dev, "Unable to get event data\n");
741                 return;
742         }
743
744         obj = (union acpi_object *)response.pointer;
745         if (obj && obj->type == ACPI_TYPE_INTEGER)
746                 huawei_wmi_process_key(idev, obj->integer.value);
747         else
748                 dev_err(&idev->dev, "Bad response type\n");
749
750         kfree(response.pointer);
751 }
752
753 static int huawei_wmi_input_setup(struct device *dev,
754                 const char *guid,
755                 struct input_dev **idev)
756 {
757         *idev = devm_input_allocate_device(dev);
758         if (!*idev)
759                 return -ENOMEM;
760
761         (*idev)->name = "Huawei WMI hotkeys";
762         (*idev)->phys = "wmi/input0";
763         (*idev)->id.bustype = BUS_HOST;
764         (*idev)->dev.parent = dev;
765
766         return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) ||
767                 input_register_device(*idev) ||
768                 wmi_install_notify_handler(guid, huawei_wmi_input_notify,
769                                 *idev);
770 }
771
772 static void huawei_wmi_input_exit(struct device *dev, const char *guid)
773 {
774         wmi_remove_notify_handler(guid);
775 }
776
777 /* Huawei driver */
778
779 static const struct wmi_device_id huawei_wmi_events_id_table[] = {
780         { .guid_string = WMI0_EVENT_GUID },
781         { .guid_string = HWMI_EVENT_GUID },
782         {  }
783 };
784
785 static int huawei_wmi_probe(struct platform_device *pdev)
786 {
787         const struct wmi_device_id *guid = huawei_wmi_events_id_table;
788         int err;
789
790         platform_set_drvdata(pdev, huawei_wmi);
791         huawei_wmi->dev = &pdev->dev;
792
793         while (*guid->guid_string) {
794                 struct input_dev *idev = *huawei_wmi->idev;
795
796                 if (wmi_has_guid(guid->guid_string)) {
797                         err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev);
798                         if (err) {
799                                 dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string);
800                                 return err;
801                         }
802                 }
803
804                 idev++;
805                 guid++;
806         }
807
808         if (wmi_has_guid(HWMI_METHOD_GUID)) {
809                 mutex_init(&huawei_wmi->wmi_lock);
810                 mutex_init(&huawei_wmi->battery_lock);
811
812                 huawei_wmi_leds_setup(&pdev->dev);
813                 huawei_wmi_fn_lock_setup(&pdev->dev);
814                 huawei_wmi_battery_setup(&pdev->dev);
815                 huawei_wmi_debugfs_setup(&pdev->dev);
816         }
817
818         return 0;
819 }
820
821 static int huawei_wmi_remove(struct platform_device *pdev)
822 {
823         const struct wmi_device_id *guid = huawei_wmi_events_id_table;
824
825         while (*guid->guid_string) {
826                 if (wmi_has_guid(guid->guid_string))
827                         huawei_wmi_input_exit(&pdev->dev, guid->guid_string);
828
829                 guid++;
830         }
831
832         if (wmi_has_guid(HWMI_METHOD_GUID)) {
833                 huawei_wmi_debugfs_exit(&pdev->dev);
834                 huawei_wmi_battery_exit(&pdev->dev);
835                 huawei_wmi_fn_lock_exit(&pdev->dev);
836         }
837
838         return 0;
839 }
840
841 static struct platform_driver huawei_wmi_driver = {
842         .driver = {
843                 .name = "huawei-wmi",
844         },
845         .probe = huawei_wmi_probe,
846         .remove = huawei_wmi_remove,
847 };
848
849 static __init int huawei_wmi_init(void)
850 {
851         struct platform_device *pdev;
852         int err;
853
854         huawei_wmi = kzalloc(sizeof(struct huawei_wmi), GFP_KERNEL);
855         if (!huawei_wmi)
856                 return -ENOMEM;
857
858         quirks = &quirk_unknown;
859         dmi_check_system(huawei_quirks);
860         if (battery_reset != -1)
861                 quirks->battery_reset = battery_reset;
862         if (report_brightness != -1)
863                 quirks->report_brightness = report_brightness;
864
865         err = platform_driver_register(&huawei_wmi_driver);
866         if (err)
867                 goto pdrv_err;
868
869         pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
870         if (IS_ERR(pdev)) {
871                 err = PTR_ERR(pdev);
872                 goto pdev_err;
873         }
874
875         return 0;
876
877 pdev_err:
878         platform_driver_unregister(&huawei_wmi_driver);
879 pdrv_err:
880         kfree(huawei_wmi);
881         return err;
882 }
883
884 static __exit void huawei_wmi_exit(void)
885 {
886         struct platform_device *pdev = to_platform_device(huawei_wmi->dev);
887
888         platform_device_unregister(pdev);
889         platform_driver_unregister(&huawei_wmi_driver);
890
891         kfree(huawei_wmi);
892 }
893
894 module_init(huawei_wmi_init);
895 module_exit(huawei_wmi_exit);
896
897 MODULE_ALIAS("wmi:"HWMI_METHOD_GUID);
898 MODULE_DEVICE_TABLE(wmi, huawei_wmi_events_id_table);
899 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
900 MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
901 MODULE_LICENSE("GPL v2");