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