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