0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/init.h>
0019 #include <linux/slab.h>
0020 #include <linux/types.h>
0021 #include <linux/input.h>
0022 #include <linux/input/sparse-keymap.h>
0023 #include <linux/acpi.h>
0024 #include <linux/string.h>
0025 #include <linux/dmi.h>
0026 #include <linux/wmi.h>
0027 #include <acpi/video.h>
0028 #include "dell-smbios.h"
0029 #include "dell-wmi-descriptor.h"
0030 #include "dell-wmi-privacy.h"
0031
0032 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
0033 MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
0034 MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
0035 MODULE_LICENSE("GPL");
0036
0037 #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
0038
0039 static bool wmi_requires_smbios_request;
0040
0041 struct dell_wmi_priv {
0042 struct input_dev *input_dev;
0043 struct input_dev *tabletswitch_dev;
0044 u32 interface_version;
0045 };
0046
0047 static int __init dmi_matched(const struct dmi_system_id *dmi)
0048 {
0049 wmi_requires_smbios_request = 1;
0050 return 1;
0051 }
0052
0053 static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
0054 {
0055 .callback = dmi_matched,
0056 .ident = "Dell Inspiron M5110",
0057 .matches = {
0058 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0059 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
0060 },
0061 },
0062 {
0063 .callback = dmi_matched,
0064 .ident = "Dell Vostro V131",
0065 .matches = {
0066 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0067 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
0068 },
0069 },
0070 { }
0071 };
0072
0073
0074
0075
0076
0077
0078
0079
0080 static const struct key_entry dell_wmi_keymap_type_0000[] = {
0081 { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
0082
0083
0084 { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
0085 { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
0086
0087
0088 { KE_KEY, 0xe007, { KEY_BATTERY } },
0089
0090
0091 { KE_IGNORE, 0xe008, { KEY_RFKILL } },
0092
0093 { KE_KEY, 0xe009, { KEY_EJECTCD } },
0094
0095
0096 { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
0097
0098
0099 { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
0100
0101
0102 { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
0103
0104
0105 { KE_IGNORE, 0xe00e, { KEY_RESERVED } },
0106
0107
0108 { KE_KEY, 0xe011, { KEY_WLAN } },
0109
0110
0111 { KE_IGNORE, 0xe013, { KEY_RESERVED } },
0112
0113 { KE_IGNORE, 0xe020, { KEY_MUTE } },
0114
0115
0116
0117
0118
0119
0120
0121
0122 { KE_KEY, 0xe025, { KEY_PROG4 } },
0123
0124
0125 { KE_IGNORE, 0xe026, { KEY_RESERVED } },
0126
0127
0128 { KE_KEY, 0xe027, { KEY_DISPLAYTOGGLE } },
0129
0130
0131
0132
0133
0134 { KE_KEY, 0xe029, { KEY_PROG4 } },
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
0146 { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
0147 { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
0148 { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
0149 { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
0150
0151
0152 { KE_IGNORE, 0xe043, { KEY_RESERVED } },
0153
0154
0155 { KE_IGNORE, 0xe044, { KEY_RESERVED } },
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
0168
0169
0170 { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
0171
0172
0173
0174
0175
0176 { KE_IGNORE, 0xe06e, { KEY_RESERVED } },
0177
0178 { KE_IGNORE, 0xe0f7, { KEY_MUTE } },
0179 { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } },
0180 { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },
0181 };
0182
0183 struct dell_bios_keymap_entry {
0184 u16 scancode;
0185 u16 keycode;
0186 };
0187
0188 struct dell_bios_hotkey_table {
0189 struct dmi_header header;
0190 struct dell_bios_keymap_entry keymap[];
0191
0192 };
0193
0194 struct dell_dmi_results {
0195 int err;
0196 int keymap_size;
0197 struct key_entry *keymap;
0198 };
0199
0200
0201 static const u16 bios_to_linux_keycode[256] = {
0202 [0] = KEY_MEDIA,
0203 [1] = KEY_NEXTSONG,
0204 [2] = KEY_PLAYPAUSE,
0205 [3] = KEY_PREVIOUSSONG,
0206 [4] = KEY_STOPCD,
0207 [5] = KEY_UNKNOWN,
0208 [6] = KEY_UNKNOWN,
0209 [7] = KEY_UNKNOWN,
0210 [8] = KEY_WWW,
0211 [9] = KEY_UNKNOWN,
0212 [10] = KEY_VOLUMEDOWN,
0213 [11] = KEY_MUTE,
0214 [12] = KEY_VOLUMEUP,
0215 [13] = KEY_UNKNOWN,
0216 [14] = KEY_BATTERY,
0217 [15] = KEY_EJECTCD,
0218 [16] = KEY_UNKNOWN,
0219 [17] = KEY_SLEEP,
0220 [18] = KEY_PROG1,
0221 [19] = KEY_BRIGHTNESSDOWN,
0222 [20] = KEY_BRIGHTNESSUP,
0223 [21] = KEY_BRIGHTNESS_AUTO,
0224 [22] = KEY_KBDILLUMTOGGLE,
0225 [23] = KEY_UNKNOWN,
0226 [24] = KEY_SWITCHVIDEOMODE,
0227 [25] = KEY_UNKNOWN,
0228 [26] = KEY_UNKNOWN,
0229 [27] = KEY_SWITCHVIDEOMODE,
0230 [28] = KEY_UNKNOWN,
0231 [29] = KEY_UNKNOWN,
0232 [30] = KEY_PROG2,
0233 [31] = KEY_UNKNOWN,
0234 [32] = KEY_UNKNOWN,
0235 [33] = KEY_UNKNOWN,
0236 [34] = KEY_UNKNOWN,
0237 [35] = KEY_UNKNOWN,
0238 [36] = KEY_UNKNOWN,
0239 [37] = KEY_UNKNOWN,
0240 [38] = KEY_MICMUTE,
0241 [255] = KEY_PROG3,
0242 };
0243
0244
0245
0246
0247
0248
0249
0250 static const struct key_entry dell_wmi_keymap_type_0010[] = {
0251
0252 { KE_IGNORE, 0x0, { KEY_RESERVED } },
0253
0254
0255 { KE_IGNORE, 0x1, { KEY_RESERVED } },
0256
0257
0258 { KE_IGNORE, 0x3f, { KEY_RESERVED } },
0259
0260
0261 { KE_KEY, 0x57, { KEY_BRIGHTNESSDOWN } },
0262 { KE_KEY, 0x58, { KEY_BRIGHTNESSUP } },
0263
0264
0265 { KE_KEY, 0x150, { KEY_MICMUTE } },
0266
0267
0268 { KE_IGNORE, 0x151, { KEY_RESERVED } },
0269
0270
0271 { KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } },
0272
0273
0274
0275
0276
0277 { KE_IGNORE, 0x153, { KEY_RFKILL } },
0278
0279
0280 { KE_IGNORE, 0x154, { KEY_RESERVED } },
0281
0282
0283
0284
0285
0286
0287
0288 { KE_IGNORE, 0x155, { KEY_RESERVED } },
0289
0290
0291 { KE_IGNORE, 0x156, { KEY_RESERVED } },
0292 { KE_IGNORE, 0x157, { KEY_RESERVED } },
0293
0294
0295 { KE_KEY, 0x850, { KEY_PROG1 } },
0296 { KE_KEY, 0x851, { KEY_PROG2 } },
0297 { KE_KEY, 0x852, { KEY_PROG3 } },
0298
0299
0300
0301
0302
0303 { KE_IGNORE, 0xe008, { KEY_RFKILL } },
0304
0305
0306 { KE_IGNORE, 0xe035, { KEY_RESERVED } },
0307 };
0308
0309
0310
0311
0312 static const struct key_entry dell_wmi_keymap_type_0011[] = {
0313
0314 { KE_IGNORE, 0xe070, { KEY_RESERVED } },
0315
0316
0317 { KE_IGNORE, 0xfff0, { KEY_RESERVED } },
0318
0319
0320 { KE_IGNORE, 0xfff1, { KEY_RESERVED } },
0321
0322
0323
0324
0325
0326
0327 { KE_IGNORE, 0xfff2, { KEY_RESERVED } },
0328
0329
0330 { KE_IGNORE, 0xfff3, { KEY_RESERVED } },
0331
0332
0333 { KE_IGNORE, KBD_LED_OFF_TOKEN, { KEY_RESERVED } },
0334 { KE_IGNORE, KBD_LED_ON_TOKEN, { KEY_RESERVED } },
0335 { KE_IGNORE, KBD_LED_AUTO_TOKEN, { KEY_RESERVED } },
0336 { KE_IGNORE, KBD_LED_AUTO_25_TOKEN, { KEY_RESERVED } },
0337 { KE_IGNORE, KBD_LED_AUTO_50_TOKEN, { KEY_RESERVED } },
0338 { KE_IGNORE, KBD_LED_AUTO_75_TOKEN, { KEY_RESERVED } },
0339 { KE_IGNORE, KBD_LED_AUTO_100_TOKEN, { KEY_RESERVED } },
0340 };
0341
0342
0343
0344
0345
0346 static const struct key_entry dell_wmi_keymap_type_0012[] = {
0347
0348 { KE_IGNORE, 0x000d, { KEY_RESERVED } },
0349
0350
0351 { KE_IGNORE, 0xe035, { KEY_RESERVED } },
0352 };
0353
0354 static void dell_wmi_switch_event(struct input_dev **subdev,
0355 const char *devname,
0356 int switchid,
0357 int value)
0358 {
0359 if (!*subdev) {
0360 struct input_dev *dev = input_allocate_device();
0361
0362 if (!dev) {
0363 pr_warn("could not allocate device for %s\n", devname);
0364 return;
0365 }
0366 __set_bit(EV_SW, (dev)->evbit);
0367 __set_bit(switchid, (dev)->swbit);
0368
0369 (dev)->name = devname;
0370 (dev)->id.bustype = BUS_HOST;
0371 if (input_register_device(dev)) {
0372 input_free_device(dev);
0373 pr_warn("could not register device for %s\n", devname);
0374 return;
0375 }
0376 *subdev = dev;
0377 }
0378
0379 input_report_switch(*subdev, switchid, value);
0380 input_sync(*subdev);
0381 }
0382
0383 static int dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16 *buffer, int remaining)
0384 {
0385 struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
0386 const struct key_entry *key;
0387 int used = 0;
0388 int value = 1;
0389
0390 key = sparse_keymap_entry_from_scancode(priv->input_dev,
0391 (type << 16) | code);
0392 if (!key) {
0393 pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
0394 type, code);
0395 return 0;
0396 }
0397
0398 pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code);
0399
0400
0401 if ((key->keycode == KEY_BRIGHTNESSUP ||
0402 key->keycode == KEY_BRIGHTNESSDOWN) &&
0403 acpi_video_handles_brightness_key_presses())
0404 return 0;
0405
0406 if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request)
0407 return 0;
0408
0409 if (key->keycode == KEY_KBDILLUMTOGGLE) {
0410 dell_laptop_call_notifier(
0411 DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL);
0412 } else if (type == 0x0011 && code == 0xe070 && remaining > 0) {
0413 dell_wmi_switch_event(&priv->tabletswitch_dev,
0414 "Dell tablet mode switch",
0415 SW_TABLET_MODE, !buffer[0]);
0416 return 1;
0417 } else if (type == 0x0012 && code == 0x000d && remaining > 0) {
0418 value = (buffer[2] == 2);
0419 used = 1;
0420 }
0421
0422 sparse_keymap_report_entry(priv->input_dev, key, value, true);
0423
0424 return used;
0425 }
0426
0427 static void dell_wmi_notify(struct wmi_device *wdev,
0428 union acpi_object *obj)
0429 {
0430 struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
0431 u16 *buffer_entry, *buffer_end;
0432 acpi_size buffer_size;
0433 int len, i;
0434
0435 if (obj->type != ACPI_TYPE_BUFFER) {
0436 pr_warn("bad response type %x\n", obj->type);
0437 return;
0438 }
0439
0440 pr_debug("Received WMI event (%*ph)\n",
0441 obj->buffer.length, obj->buffer.pointer);
0442
0443 buffer_entry = (u16 *)obj->buffer.pointer;
0444 buffer_size = obj->buffer.length/2;
0445 buffer_end = buffer_entry + buffer_size;
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459 if (priv->interface_version == 0 && buffer_entry < buffer_end)
0460 if (buffer_end > buffer_entry + buffer_entry[0] + 1)
0461 buffer_end = buffer_entry + buffer_entry[0] + 1;
0462
0463 while (buffer_entry < buffer_end) {
0464
0465 len = buffer_entry[0];
0466 if (len == 0)
0467 break;
0468
0469 len++;
0470
0471 if (buffer_entry + len > buffer_end) {
0472 pr_warn("Invalid length of WMI event\n");
0473 break;
0474 }
0475
0476 pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry);
0477
0478 switch (buffer_entry[1]) {
0479 case 0x0000:
0480 if (len > 2)
0481 dell_wmi_process_key(wdev, buffer_entry[1],
0482 buffer_entry[2],
0483 buffer_entry + 3,
0484 len - 3);
0485
0486 break;
0487 case 0x0010:
0488 case 0x0011:
0489 for (i = 2; i < len; ++i)
0490 i += dell_wmi_process_key(wdev, buffer_entry[1],
0491 buffer_entry[i],
0492 buffer_entry + i,
0493 len - i - 1);
0494 break;
0495 case 0x0012:
0496 if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3],
0497 buffer_entry[4]))
0498 ;
0499 else if (len > 2)
0500 dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2],
0501 buffer_entry + 3, len - 3);
0502 break;
0503 default:
0504 pr_info("Unknown WMI event type 0x%x\n",
0505 (int)buffer_entry[1]);
0506 break;
0507 }
0508
0509 buffer_entry += len;
0510
0511 }
0512
0513 }
0514
0515 static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
0516 {
0517 int i;
0518
0519 for (i = 0; i < len; i++)
0520 if (keymap[i].code == scancode)
0521 return true;
0522
0523 return false;
0524 }
0525
0526 static void handle_dmi_entry(const struct dmi_header *dm, void *opaque)
0527 {
0528 struct dell_dmi_results *results = opaque;
0529 struct dell_bios_hotkey_table *table;
0530 int hotkey_num, i, pos = 0;
0531 struct key_entry *keymap;
0532
0533 if (results->err || results->keymap)
0534 return;
0535
0536
0537 if (dm->type != 0xb2)
0538 return;
0539
0540 table = container_of(dm, struct dell_bios_hotkey_table, header);
0541
0542 hotkey_num = (table->header.length -
0543 sizeof(struct dell_bios_hotkey_table)) /
0544 sizeof(struct dell_bios_keymap_entry);
0545 if (hotkey_num < 1) {
0546
0547
0548
0549
0550
0551
0552
0553 return;
0554 }
0555
0556 keymap = kcalloc(hotkey_num, sizeof(struct key_entry), GFP_KERNEL);
0557 if (!keymap) {
0558 results->err = -ENOMEM;
0559 return;
0560 }
0561
0562 for (i = 0; i < hotkey_num; i++) {
0563 const struct dell_bios_keymap_entry *bios_entry =
0564 &table->keymap[i];
0565
0566
0567 u16 keycode = (bios_entry->keycode <
0568 ARRAY_SIZE(bios_to_linux_keycode)) ?
0569 bios_to_linux_keycode[bios_entry->keycode] :
0570 (bios_entry->keycode == 0xffff ? KEY_UNKNOWN : KEY_RESERVED);
0571
0572
0573
0574
0575
0576
0577 if (keycode == KEY_RESERVED) {
0578 pr_info("firmware scancode 0x%x maps to unrecognized keycode 0x%x\n",
0579 bios_entry->scancode, bios_entry->keycode);
0580 continue;
0581 }
0582
0583 if (keycode == KEY_KBDILLUMTOGGLE)
0584 keymap[pos].type = KE_IGNORE;
0585 else
0586 keymap[pos].type = KE_KEY;
0587 keymap[pos].code = bios_entry->scancode;
0588 keymap[pos].keycode = keycode;
0589
0590 pos++;
0591 }
0592
0593 results->keymap = keymap;
0594 results->keymap_size = pos;
0595 }
0596
0597 static int dell_wmi_input_setup(struct wmi_device *wdev)
0598 {
0599 struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
0600 struct dell_dmi_results dmi_results = {};
0601 struct key_entry *keymap;
0602 int err, i, pos = 0;
0603
0604 priv->input_dev = input_allocate_device();
0605 if (!priv->input_dev)
0606 return -ENOMEM;
0607
0608 priv->input_dev->name = "Dell WMI hotkeys";
0609 priv->input_dev->id.bustype = BUS_HOST;
0610 priv->input_dev->dev.parent = &wdev->dev;
0611
0612 if (dmi_walk(handle_dmi_entry, &dmi_results)) {
0613
0614
0615
0616
0617
0618 pr_warn("no DMI; using the old-style hotkey interface\n");
0619 }
0620
0621 if (dmi_results.err) {
0622 err = dmi_results.err;
0623 goto err_free_dev;
0624 }
0625
0626 keymap = kcalloc(dmi_results.keymap_size +
0627 ARRAY_SIZE(dell_wmi_keymap_type_0000) +
0628 ARRAY_SIZE(dell_wmi_keymap_type_0010) +
0629 ARRAY_SIZE(dell_wmi_keymap_type_0011) +
0630 ARRAY_SIZE(dell_wmi_keymap_type_0012) +
0631 1,
0632 sizeof(struct key_entry), GFP_KERNEL);
0633 if (!keymap) {
0634 kfree(dmi_results.keymap);
0635 err = -ENOMEM;
0636 goto err_free_dev;
0637 }
0638
0639
0640 for (i = 0; i < dmi_results.keymap_size; i++) {
0641 keymap[pos] = dmi_results.keymap[i];
0642 keymap[pos].code |= (0x0010 << 16);
0643 pos++;
0644 }
0645
0646 kfree(dmi_results.keymap);
0647
0648
0649 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0010); i++) {
0650 const struct key_entry *entry = &dell_wmi_keymap_type_0010[i];
0651
0652
0653
0654
0655
0656
0657 if (dmi_results.keymap_size &&
0658 have_scancode(entry->code | (0x0010 << 16),
0659 keymap, dmi_results.keymap_size)
0660 )
0661 continue;
0662
0663 keymap[pos] = *entry;
0664 keymap[pos].code |= (0x0010 << 16);
0665 pos++;
0666 }
0667
0668
0669 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0011); i++) {
0670 keymap[pos] = dell_wmi_keymap_type_0011[i];
0671 keymap[pos].code |= (0x0011 << 16);
0672 pos++;
0673 }
0674
0675
0676 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
0677 keymap[pos] = dell_wmi_keymap_type_0012[i];
0678 keymap[pos].code |= (0x0012 << 16);
0679 pos++;
0680 }
0681
0682
0683
0684
0685
0686 for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0000); i++) {
0687 keymap[pos] = dell_wmi_keymap_type_0000[i];
0688 pos++;
0689 }
0690
0691 keymap[pos].type = KE_END;
0692
0693 err = sparse_keymap_setup(priv->input_dev, keymap, NULL);
0694
0695
0696
0697
0698 kfree(keymap);
0699 if (err)
0700 goto err_free_dev;
0701
0702 err = input_register_device(priv->input_dev);
0703 if (err)
0704 goto err_free_dev;
0705
0706 return 0;
0707
0708 err_free_dev:
0709 input_free_device(priv->input_dev);
0710 return err;
0711 }
0712
0713 static void dell_wmi_input_destroy(struct wmi_device *wdev)
0714 {
0715 struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
0716
0717 input_unregister_device(priv->input_dev);
0718 if (priv->tabletswitch_dev)
0719 input_unregister_device(priv->tabletswitch_dev);
0720 }
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738 static int dell_wmi_events_set_enabled(bool enable)
0739 {
0740 struct calling_interface_buffer *buffer;
0741 int ret;
0742
0743 buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
0744 if (!buffer)
0745 return -ENOMEM;
0746 buffer->cmd_class = CLASS_INFO;
0747 buffer->cmd_select = SELECT_APP_REGISTRATION;
0748 buffer->input[0] = 0x10000;
0749 buffer->input[1] = 0x51534554;
0750 buffer->input[3] = enable;
0751 ret = dell_smbios_call(buffer);
0752 if (ret == 0)
0753 ret = buffer->output[0];
0754 kfree(buffer);
0755
0756 return dell_smbios_error(ret);
0757 }
0758
0759 static int dell_wmi_probe(struct wmi_device *wdev, const void *context)
0760 {
0761 struct dell_wmi_priv *priv;
0762 int ret;
0763
0764 ret = dell_wmi_get_descriptor_valid();
0765 if (ret)
0766 return ret;
0767
0768 priv = devm_kzalloc(
0769 &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
0770 if (!priv)
0771 return -ENOMEM;
0772 dev_set_drvdata(&wdev->dev, priv);
0773
0774 if (!dell_wmi_get_interface_version(&priv->interface_version))
0775 return -EPROBE_DEFER;
0776
0777 return dell_wmi_input_setup(wdev);
0778 }
0779
0780 static void dell_wmi_remove(struct wmi_device *wdev)
0781 {
0782 dell_wmi_input_destroy(wdev);
0783 }
0784 static const struct wmi_device_id dell_wmi_id_table[] = {
0785 { .guid_string = DELL_EVENT_GUID },
0786 { },
0787 };
0788
0789 static struct wmi_driver dell_wmi_driver = {
0790 .driver = {
0791 .name = "dell-wmi",
0792 },
0793 .id_table = dell_wmi_id_table,
0794 .probe = dell_wmi_probe,
0795 .remove = dell_wmi_remove,
0796 .notify = dell_wmi_notify,
0797 };
0798
0799 static int __init dell_wmi_init(void)
0800 {
0801 int err;
0802
0803 dmi_check_system(dell_wmi_smbios_list);
0804
0805 if (wmi_requires_smbios_request) {
0806 err = dell_wmi_events_set_enabled(true);
0807 if (err) {
0808 pr_err("Failed to enable WMI events\n");
0809 return err;
0810 }
0811 }
0812
0813 err = dell_privacy_register_driver();
0814 if (err)
0815 return err;
0816
0817 return wmi_driver_register(&dell_wmi_driver);
0818 }
0819 late_initcall(dell_wmi_init);
0820
0821 static void __exit dell_wmi_exit(void)
0822 {
0823 if (wmi_requires_smbios_request)
0824 dell_wmi_events_set_enabled(false);
0825
0826 wmi_driver_unregister(&dell_wmi_driver);
0827 dell_privacy_unregister_driver();
0828 }
0829 module_exit(dell_wmi_exit);
0830
0831 MODULE_DEVICE_TABLE(wmi, dell_wmi_id_table);