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