0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/acpi.h>
0009 #include <linux/debugfs.h>
0010 #include <linux/delay.h>
0011 #include <linux/dmi.h>
0012 #include <linux/input.h>
0013 #include <linux/input/sparse-keymap.h>
0014 #include <linux/leds.h>
0015 #include <linux/module.h>
0016 #include <linux/mutex.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/power_supply.h>
0019 #include <linux/sysfs.h>
0020 #include <linux/wmi.h>
0021 #include <acpi/battery.h>
0022
0023
0024
0025
0026 #define HWMI_METHOD_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000"
0027 #define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
0028
0029
0030 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
0031 #define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
0032
0033
0034
0035 enum {
0036 BATTERY_THRESH_GET = 0x00001103,
0037 BATTERY_THRESH_SET = 0x00001003,
0038 FN_LOCK_GET = 0x00000604,
0039 FN_LOCK_SET = 0x00000704,
0040 MICMUTE_LED_SET = 0x00000b04,
0041 };
0042
0043 union hwmi_arg {
0044 u64 cmd;
0045 u8 args[8];
0046 };
0047
0048 struct quirk_entry {
0049 bool battery_reset;
0050 bool ec_micmute;
0051 bool report_brightness;
0052 };
0053
0054 static struct quirk_entry *quirks;
0055
0056 struct huawei_wmi_debug {
0057 struct dentry *root;
0058 u64 arg;
0059 };
0060
0061 struct huawei_wmi {
0062 bool battery_available;
0063 bool fn_lock_available;
0064
0065 struct huawei_wmi_debug debug;
0066 struct input_dev *idev[2];
0067 struct led_classdev cdev;
0068 struct device *dev;
0069
0070 struct mutex wmi_lock;
0071 };
0072
0073 static struct huawei_wmi *huawei_wmi;
0074
0075 static const struct key_entry huawei_wmi_keymap[] = {
0076 { KE_KEY, 0x281, { KEY_BRIGHTNESSDOWN } },
0077 { KE_KEY, 0x282, { KEY_BRIGHTNESSUP } },
0078 { KE_KEY, 0x284, { KEY_MUTE } },
0079 { KE_KEY, 0x285, { KEY_VOLUMEDOWN } },
0080 { KE_KEY, 0x286, { KEY_VOLUMEUP } },
0081 { KE_KEY, 0x287, { KEY_MICMUTE } },
0082 { KE_KEY, 0x289, { KEY_WLAN } },
0083
0084 { KE_KEY, 0x28a, { KEY_CONFIG } },
0085
0086 { KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
0087 { KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
0088 { KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
0089 { KE_END, 0 }
0090 };
0091
0092 static int battery_reset = -1;
0093 static int report_brightness = -1;
0094
0095 module_param(battery_reset, bint, 0444);
0096 MODULE_PARM_DESC(battery_reset,
0097 "Reset battery charge values to (0-0) before disabling it using (0-100)");
0098 module_param(report_brightness, bint, 0444);
0099 MODULE_PARM_DESC(report_brightness,
0100 "Report brightness keys.");
0101
0102
0103
0104 static int __init dmi_matched(const struct dmi_system_id *dmi)
0105 {
0106 quirks = dmi->driver_data;
0107 return 1;
0108 }
0109
0110 static struct quirk_entry quirk_unknown = {
0111 };
0112
0113 static struct quirk_entry quirk_battery_reset = {
0114 .battery_reset = true,
0115 };
0116
0117 static struct quirk_entry quirk_matebook_x = {
0118 .ec_micmute = true,
0119 .report_brightness = true,
0120 };
0121
0122 static const struct dmi_system_id huawei_quirks[] = {
0123 {
0124 .callback = dmi_matched,
0125 .ident = "Huawei MACH-WX9",
0126 .matches = {
0127 DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
0128 DMI_MATCH(DMI_PRODUCT_NAME, "MACH-WX9"),
0129 },
0130 .driver_data = &quirk_battery_reset
0131 },
0132 {
0133 .callback = dmi_matched,
0134 .ident = "Huawei MateBook X",
0135 .matches = {
0136 DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
0137 DMI_MATCH(DMI_PRODUCT_NAME, "HUAWEI MateBook X")
0138 },
0139 .driver_data = &quirk_matebook_x
0140 },
0141 { }
0142 };
0143
0144
0145
0146 static int huawei_wmi_call(struct huawei_wmi *huawei,
0147 struct acpi_buffer *in, struct acpi_buffer *out)
0148 {
0149 acpi_status status;
0150
0151 mutex_lock(&huawei->wmi_lock);
0152 status = wmi_evaluate_method(HWMI_METHOD_GUID, 0, 1, in, out);
0153 mutex_unlock(&huawei->wmi_lock);
0154 if (ACPI_FAILURE(status)) {
0155 dev_err(huawei->dev, "Failed to evaluate wmi method\n");
0156 return -ENODEV;
0157 }
0158
0159 return 0;
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170 static int huawei_wmi_cmd(u64 arg, u8 *buf, size_t buflen)
0171 {
0172 struct huawei_wmi *huawei = huawei_wmi;
0173 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
0174 struct acpi_buffer in;
0175 union acpi_object *obj;
0176 size_t len;
0177 int err, i;
0178
0179 in.length = sizeof(arg);
0180 in.pointer = &arg;
0181
0182
0183
0184
0185 for (i = 0; i < 2; i++) {
0186 err = huawei_wmi_call(huawei, &in, &out);
0187 if (err)
0188 goto fail_cmd;
0189
0190 obj = out.pointer;
0191 if (!obj) {
0192 err = -EIO;
0193 goto fail_cmd;
0194 }
0195
0196 switch (obj->type) {
0197
0198
0199
0200 case ACPI_TYPE_BUFFER:
0201 if (obj->buffer.length == 0x104) {
0202
0203 obj->buffer.pointer += 4;
0204 len = 0x100;
0205 } else {
0206 dev_err(huawei->dev, "Bad buffer length, got %d\n", obj->buffer.length);
0207 err = -EIO;
0208 goto fail_cmd;
0209 }
0210
0211 break;
0212
0213
0214
0215 case ACPI_TYPE_PACKAGE:
0216 if (obj->package.count != 2) {
0217 dev_err(huawei->dev, "Bad package count, got %d\n", obj->package.count);
0218 err = -EIO;
0219 goto fail_cmd;
0220 }
0221
0222 obj = &obj->package.elements[1];
0223 if (obj->type != ACPI_TYPE_BUFFER) {
0224 dev_err(huawei->dev, "Bad package element type, got %d\n", obj->type);
0225 err = -EIO;
0226 goto fail_cmd;
0227 }
0228 len = obj->buffer.length;
0229
0230 break;
0231
0232 default:
0233 dev_err(huawei->dev, "Unexpected obj type, got: %d\n", obj->type);
0234 err = -EIO;
0235 goto fail_cmd;
0236 }
0237
0238 if (!*obj->buffer.pointer)
0239 break;
0240 }
0241
0242 err = (*obj->buffer.pointer) ? -ENODEV : 0;
0243
0244 if (buf) {
0245 len = min(buflen, len);
0246 memcpy(buf, obj->buffer.pointer, len);
0247 }
0248
0249 fail_cmd:
0250 kfree(out.pointer);
0251 return err;
0252 }
0253
0254
0255
0256 static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
0257 enum led_brightness brightness)
0258 {
0259
0260 if (quirks && quirks->ec_micmute) {
0261 char *acpi_method;
0262 acpi_handle handle;
0263 acpi_status status;
0264 union acpi_object args[3];
0265 struct acpi_object_list arg_list = {
0266 .pointer = args,
0267 .count = ARRAY_SIZE(args),
0268 };
0269
0270 handle = ec_get_handle();
0271 if (!handle)
0272 return -ENODEV;
0273
0274 args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
0275 args[1].integer.value = 0x04;
0276
0277 if (acpi_has_method(handle, "SPIN")) {
0278 acpi_method = "SPIN";
0279 args[0].integer.value = 0;
0280 args[2].integer.value = brightness ? 1 : 0;
0281 } else if (acpi_has_method(handle, "WPIN")) {
0282 acpi_method = "WPIN";
0283 args[0].integer.value = 1;
0284 args[2].integer.value = brightness ? 0 : 1;
0285 } else {
0286 return -ENODEV;
0287 }
0288
0289 status = acpi_evaluate_object(handle, acpi_method, &arg_list, NULL);
0290 if (ACPI_FAILURE(status))
0291 return -ENODEV;
0292
0293 return 0;
0294 } else {
0295 union hwmi_arg arg;
0296
0297 arg.cmd = MICMUTE_LED_SET;
0298 arg.args[2] = brightness;
0299
0300 return huawei_wmi_cmd(arg.cmd, NULL, 0);
0301 }
0302 }
0303
0304 static void huawei_wmi_leds_setup(struct device *dev)
0305 {
0306 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0307
0308 huawei->cdev.name = "platform::micmute";
0309 huawei->cdev.max_brightness = 1;
0310 huawei->cdev.brightness_set_blocking = &huawei_wmi_micmute_led_set;
0311 huawei->cdev.default_trigger = "audio-micmute";
0312 huawei->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
0313 huawei->cdev.dev = dev;
0314 huawei->cdev.flags = LED_CORE_SUSPENDRESUME;
0315
0316 devm_led_classdev_register(dev, &huawei->cdev);
0317 }
0318
0319
0320
0321 static int huawei_wmi_battery_get(int *start, int *end)
0322 {
0323 u8 ret[0x100];
0324 int err, i;
0325
0326 err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100);
0327 if (err)
0328 return err;
0329
0330
0331 i = 0xff;
0332 do {
0333 if (start)
0334 *start = ret[i-1];
0335 if (end)
0336 *end = ret[i];
0337 } while (i > 2 && !ret[i--]);
0338
0339 return 0;
0340 }
0341
0342 static int huawei_wmi_battery_set(int start, int end)
0343 {
0344 union hwmi_arg arg;
0345 int err;
0346
0347 if (start < 0 || end < 0 || start > 100 || end > 100)
0348 return -EINVAL;
0349
0350 arg.cmd = BATTERY_THRESH_SET;
0351 arg.args[2] = start;
0352 arg.args[3] = end;
0353
0354
0355
0356
0357
0358
0359 if (quirks && quirks->battery_reset && start == 0 && end == 100) {
0360 err = huawei_wmi_battery_set(0, 0);
0361 if (err)
0362 return err;
0363
0364 msleep(1000);
0365 }
0366
0367 err = huawei_wmi_cmd(arg.cmd, NULL, 0);
0368
0369 return err;
0370 }
0371
0372 static ssize_t charge_control_start_threshold_show(struct device *dev,
0373 struct device_attribute *attr,
0374 char *buf)
0375 {
0376 int err, start;
0377
0378 err = huawei_wmi_battery_get(&start, NULL);
0379 if (err)
0380 return err;
0381
0382 return sprintf(buf, "%d\n", start);
0383 }
0384
0385 static ssize_t charge_control_end_threshold_show(struct device *dev,
0386 struct device_attribute *attr,
0387 char *buf)
0388 {
0389 int err, end;
0390
0391 err = huawei_wmi_battery_get(NULL, &end);
0392 if (err)
0393 return err;
0394
0395 return sprintf(buf, "%d\n", end);
0396 }
0397
0398 static ssize_t charge_control_thresholds_show(struct device *dev,
0399 struct device_attribute *attr,
0400 char *buf)
0401 {
0402 int err, start, end;
0403
0404 err = huawei_wmi_battery_get(&start, &end);
0405 if (err)
0406 return err;
0407
0408 return sprintf(buf, "%d %d\n", start, end);
0409 }
0410
0411 static ssize_t charge_control_start_threshold_store(struct device *dev,
0412 struct device_attribute *attr,
0413 const char *buf, size_t size)
0414 {
0415 int err, start, end;
0416
0417 err = huawei_wmi_battery_get(NULL, &end);
0418 if (err)
0419 return err;
0420
0421 if (sscanf(buf, "%d", &start) != 1)
0422 return -EINVAL;
0423
0424 err = huawei_wmi_battery_set(start, end);
0425 if (err)
0426 return err;
0427
0428 return size;
0429 }
0430
0431 static ssize_t charge_control_end_threshold_store(struct device *dev,
0432 struct device_attribute *attr,
0433 const char *buf, size_t size)
0434 {
0435 int err, start, end;
0436
0437 err = huawei_wmi_battery_get(&start, NULL);
0438 if (err)
0439 return err;
0440
0441 if (sscanf(buf, "%d", &end) != 1)
0442 return -EINVAL;
0443
0444 err = huawei_wmi_battery_set(start, end);
0445 if (err)
0446 return err;
0447
0448 return size;
0449 }
0450
0451 static ssize_t charge_control_thresholds_store(struct device *dev,
0452 struct device_attribute *attr,
0453 const char *buf, size_t size)
0454 {
0455 int err, start, end;
0456
0457 if (sscanf(buf, "%d %d", &start, &end) != 2)
0458 return -EINVAL;
0459
0460 err = huawei_wmi_battery_set(start, end);
0461 if (err)
0462 return err;
0463
0464 return size;
0465 }
0466
0467 static DEVICE_ATTR_RW(charge_control_start_threshold);
0468 static DEVICE_ATTR_RW(charge_control_end_threshold);
0469 static DEVICE_ATTR_RW(charge_control_thresholds);
0470
0471 static int huawei_wmi_battery_add(struct power_supply *battery)
0472 {
0473 int err = 0;
0474
0475 err = device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold);
0476 if (err)
0477 return err;
0478
0479 err = device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold);
0480 if (err)
0481 device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold);
0482
0483 return err;
0484 }
0485
0486 static int huawei_wmi_battery_remove(struct power_supply *battery)
0487 {
0488 device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold);
0489 device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold);
0490
0491 return 0;
0492 }
0493
0494 static struct acpi_battery_hook huawei_wmi_battery_hook = {
0495 .add_battery = huawei_wmi_battery_add,
0496 .remove_battery = huawei_wmi_battery_remove,
0497 .name = "Huawei Battery Extension"
0498 };
0499
0500 static void huawei_wmi_battery_setup(struct device *dev)
0501 {
0502 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0503
0504 huawei->battery_available = true;
0505 if (huawei_wmi_battery_get(NULL, NULL)) {
0506 huawei->battery_available = false;
0507 return;
0508 }
0509
0510 battery_hook_register(&huawei_wmi_battery_hook);
0511 device_create_file(dev, &dev_attr_charge_control_thresholds);
0512 }
0513
0514 static void huawei_wmi_battery_exit(struct device *dev)
0515 {
0516 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0517
0518 if (huawei->battery_available) {
0519 battery_hook_unregister(&huawei_wmi_battery_hook);
0520 device_remove_file(dev, &dev_attr_charge_control_thresholds);
0521 }
0522 }
0523
0524
0525
0526 static int huawei_wmi_fn_lock_get(int *on)
0527 {
0528 u8 ret[0x100] = { 0 };
0529 int err, i;
0530
0531 err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100);
0532 if (err)
0533 return err;
0534
0535
0536 i = 1;
0537 do {
0538 if (on)
0539 *on = ret[i] - 1;
0540 } while (i < 0xff && !ret[i++]);
0541
0542 return 0;
0543 }
0544
0545 static int huawei_wmi_fn_lock_set(int on)
0546 {
0547 union hwmi_arg arg;
0548
0549 arg.cmd = FN_LOCK_SET;
0550 arg.args[2] = on + 1;
0551
0552 return huawei_wmi_cmd(arg.cmd, NULL, 0);
0553 }
0554
0555 static ssize_t fn_lock_state_show(struct device *dev,
0556 struct device_attribute *attr,
0557 char *buf)
0558 {
0559 int err, on;
0560
0561 err = huawei_wmi_fn_lock_get(&on);
0562 if (err)
0563 return err;
0564
0565 return sprintf(buf, "%d\n", on);
0566 }
0567
0568 static ssize_t fn_lock_state_store(struct device *dev,
0569 struct device_attribute *attr,
0570 const char *buf, size_t size)
0571 {
0572 int on, err;
0573
0574 if (kstrtoint(buf, 10, &on) ||
0575 on < 0 || on > 1)
0576 return -EINVAL;
0577
0578 err = huawei_wmi_fn_lock_set(on);
0579 if (err)
0580 return err;
0581
0582 return size;
0583 }
0584
0585 static DEVICE_ATTR_RW(fn_lock_state);
0586
0587 static void huawei_wmi_fn_lock_setup(struct device *dev)
0588 {
0589 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0590
0591 huawei->fn_lock_available = true;
0592 if (huawei_wmi_fn_lock_get(NULL)) {
0593 huawei->fn_lock_available = false;
0594 return;
0595 }
0596
0597 device_create_file(dev, &dev_attr_fn_lock_state);
0598 }
0599
0600 static void huawei_wmi_fn_lock_exit(struct device *dev)
0601 {
0602 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0603
0604 if (huawei->fn_lock_available)
0605 device_remove_file(dev, &dev_attr_fn_lock_state);
0606 }
0607
0608
0609
0610 static void huawei_wmi_debugfs_call_dump(struct seq_file *m, void *data,
0611 union acpi_object *obj)
0612 {
0613 struct huawei_wmi *huawei = m->private;
0614 int i;
0615
0616 switch (obj->type) {
0617 case ACPI_TYPE_INTEGER:
0618 seq_printf(m, "0x%llx", obj->integer.value);
0619 break;
0620 case ACPI_TYPE_STRING:
0621 seq_printf(m, "\"%.*s\"", obj->string.length, obj->string.pointer);
0622 break;
0623 case ACPI_TYPE_BUFFER:
0624 seq_puts(m, "{");
0625 for (i = 0; i < obj->buffer.length; i++) {
0626 seq_printf(m, "0x%02x", obj->buffer.pointer[i]);
0627 if (i < obj->buffer.length - 1)
0628 seq_puts(m, ",");
0629 }
0630 seq_puts(m, "}");
0631 break;
0632 case ACPI_TYPE_PACKAGE:
0633 seq_puts(m, "[");
0634 for (i = 0; i < obj->package.count; i++) {
0635 huawei_wmi_debugfs_call_dump(m, huawei, &obj->package.elements[i]);
0636 if (i < obj->package.count - 1)
0637 seq_puts(m, ",");
0638 }
0639 seq_puts(m, "]");
0640 break;
0641 default:
0642 dev_err(huawei->dev, "Unexpected obj type, got %d\n", obj->type);
0643 return;
0644 }
0645 }
0646
0647 static int huawei_wmi_debugfs_call_show(struct seq_file *m, void *data)
0648 {
0649 struct huawei_wmi *huawei = m->private;
0650 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
0651 struct acpi_buffer in;
0652 union acpi_object *obj;
0653 int err;
0654
0655 in.length = sizeof(u64);
0656 in.pointer = &huawei->debug.arg;
0657
0658 err = huawei_wmi_call(huawei, &in, &out);
0659 if (err)
0660 return err;
0661
0662 obj = out.pointer;
0663 if (!obj) {
0664 err = -EIO;
0665 goto fail_debugfs_call;
0666 }
0667
0668 huawei_wmi_debugfs_call_dump(m, huawei, obj);
0669
0670 fail_debugfs_call:
0671 kfree(out.pointer);
0672 return err;
0673 }
0674
0675 DEFINE_SHOW_ATTRIBUTE(huawei_wmi_debugfs_call);
0676
0677 static void huawei_wmi_debugfs_setup(struct device *dev)
0678 {
0679 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0680
0681 huawei->debug.root = debugfs_create_dir("huawei-wmi", NULL);
0682
0683 debugfs_create_x64("arg", 0644, huawei->debug.root,
0684 &huawei->debug.arg);
0685 debugfs_create_file("call", 0400,
0686 huawei->debug.root, huawei, &huawei_wmi_debugfs_call_fops);
0687 }
0688
0689 static void huawei_wmi_debugfs_exit(struct device *dev)
0690 {
0691 struct huawei_wmi *huawei = dev_get_drvdata(dev);
0692
0693 debugfs_remove_recursive(huawei->debug.root);
0694 }
0695
0696
0697
0698 static void huawei_wmi_process_key(struct input_dev *idev, int code)
0699 {
0700 const struct key_entry *key;
0701
0702
0703
0704
0705
0706
0707 if (code == 0x80) {
0708 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
0709 union acpi_object *obj;
0710 acpi_status status;
0711
0712 status = wmi_query_block(WMI0_EXPENSIVE_GUID, 0, &response);
0713 if (ACPI_FAILURE(status))
0714 return;
0715
0716 obj = (union acpi_object *)response.pointer;
0717 if (obj && obj->type == ACPI_TYPE_INTEGER)
0718 code = obj->integer.value;
0719
0720 kfree(response.pointer);
0721 }
0722
0723 key = sparse_keymap_entry_from_scancode(idev, code);
0724 if (!key) {
0725 dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code);
0726 return;
0727 }
0728
0729 if (quirks && !quirks->report_brightness &&
0730 (key->sw.code == KEY_BRIGHTNESSDOWN ||
0731 key->sw.code == KEY_BRIGHTNESSUP))
0732 return;
0733
0734 sparse_keymap_report_entry(idev, key, 1, true);
0735 }
0736
0737 static void huawei_wmi_input_notify(u32 value, void *context)
0738 {
0739 struct input_dev *idev = (struct input_dev *)context;
0740 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
0741 union acpi_object *obj;
0742 acpi_status status;
0743
0744 status = wmi_get_event_data(value, &response);
0745 if (ACPI_FAILURE(status)) {
0746 dev_err(&idev->dev, "Unable to get event data\n");
0747 return;
0748 }
0749
0750 obj = (union acpi_object *)response.pointer;
0751 if (obj && obj->type == ACPI_TYPE_INTEGER)
0752 huawei_wmi_process_key(idev, obj->integer.value);
0753 else
0754 dev_err(&idev->dev, "Bad response type\n");
0755
0756 kfree(response.pointer);
0757 }
0758
0759 static int huawei_wmi_input_setup(struct device *dev,
0760 const char *guid,
0761 struct input_dev **idev)
0762 {
0763 *idev = devm_input_allocate_device(dev);
0764 if (!*idev)
0765 return -ENOMEM;
0766
0767 (*idev)->name = "Huawei WMI hotkeys";
0768 (*idev)->phys = "wmi/input0";
0769 (*idev)->id.bustype = BUS_HOST;
0770 (*idev)->dev.parent = dev;
0771
0772 return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) ||
0773 input_register_device(*idev) ||
0774 wmi_install_notify_handler(guid, huawei_wmi_input_notify,
0775 *idev);
0776 }
0777
0778 static void huawei_wmi_input_exit(struct device *dev, const char *guid)
0779 {
0780 wmi_remove_notify_handler(guid);
0781 }
0782
0783
0784
0785 static const struct wmi_device_id huawei_wmi_events_id_table[] = {
0786 { .guid_string = WMI0_EVENT_GUID },
0787 { .guid_string = HWMI_EVENT_GUID },
0788 { }
0789 };
0790
0791 static int huawei_wmi_probe(struct platform_device *pdev)
0792 {
0793 const struct wmi_device_id *guid = huawei_wmi_events_id_table;
0794 int err;
0795
0796 platform_set_drvdata(pdev, huawei_wmi);
0797 huawei_wmi->dev = &pdev->dev;
0798
0799 while (*guid->guid_string) {
0800 struct input_dev *idev = *huawei_wmi->idev;
0801
0802 if (wmi_has_guid(guid->guid_string)) {
0803 err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev);
0804 if (err) {
0805 dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string);
0806 return err;
0807 }
0808 }
0809
0810 idev++;
0811 guid++;
0812 }
0813
0814 if (wmi_has_guid(HWMI_METHOD_GUID)) {
0815 mutex_init(&huawei_wmi->wmi_lock);
0816
0817 huawei_wmi_leds_setup(&pdev->dev);
0818 huawei_wmi_fn_lock_setup(&pdev->dev);
0819 huawei_wmi_battery_setup(&pdev->dev);
0820 huawei_wmi_debugfs_setup(&pdev->dev);
0821 }
0822
0823 return 0;
0824 }
0825
0826 static int huawei_wmi_remove(struct platform_device *pdev)
0827 {
0828 const struct wmi_device_id *guid = huawei_wmi_events_id_table;
0829
0830 while (*guid->guid_string) {
0831 if (wmi_has_guid(guid->guid_string))
0832 huawei_wmi_input_exit(&pdev->dev, guid->guid_string);
0833
0834 guid++;
0835 }
0836
0837 if (wmi_has_guid(HWMI_METHOD_GUID)) {
0838 huawei_wmi_debugfs_exit(&pdev->dev);
0839 huawei_wmi_battery_exit(&pdev->dev);
0840 huawei_wmi_fn_lock_exit(&pdev->dev);
0841 }
0842
0843 return 0;
0844 }
0845
0846 static struct platform_driver huawei_wmi_driver = {
0847 .driver = {
0848 .name = "huawei-wmi",
0849 },
0850 .probe = huawei_wmi_probe,
0851 .remove = huawei_wmi_remove,
0852 };
0853
0854 static __init int huawei_wmi_init(void)
0855 {
0856 struct platform_device *pdev;
0857 int err;
0858
0859 huawei_wmi = kzalloc(sizeof(struct huawei_wmi), GFP_KERNEL);
0860 if (!huawei_wmi)
0861 return -ENOMEM;
0862
0863 quirks = &quirk_unknown;
0864 dmi_check_system(huawei_quirks);
0865 if (battery_reset != -1)
0866 quirks->battery_reset = battery_reset;
0867 if (report_brightness != -1)
0868 quirks->report_brightness = report_brightness;
0869
0870 err = platform_driver_register(&huawei_wmi_driver);
0871 if (err)
0872 goto pdrv_err;
0873
0874 pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
0875 if (IS_ERR(pdev)) {
0876 err = PTR_ERR(pdev);
0877 goto pdev_err;
0878 }
0879
0880 return 0;
0881
0882 pdev_err:
0883 platform_driver_unregister(&huawei_wmi_driver);
0884 pdrv_err:
0885 kfree(huawei_wmi);
0886 return err;
0887 }
0888
0889 static __exit void huawei_wmi_exit(void)
0890 {
0891 struct platform_device *pdev = to_platform_device(huawei_wmi->dev);
0892
0893 platform_device_unregister(pdev);
0894 platform_driver_unregister(&huawei_wmi_driver);
0895
0896 kfree(huawei_wmi);
0897 }
0898
0899 module_init(huawei_wmi_init);
0900 module_exit(huawei_wmi_exit);
0901
0902 MODULE_ALIAS("wmi:"HWMI_METHOD_GUID);
0903 MODULE_DEVICE_TABLE(wmi, huawei_wmi_events_id_table);
0904 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
0905 MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
0906 MODULE_LICENSE("GPL v2");