0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/acpi.h>
0010 #include <linux/dmi.h>
0011 #include <linux/input.h>
0012 #include <linux/input/sparse-keymap.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/suspend.h>
0017 #include "../dual_accel_detect.h"
0018
0019
0020 #define TABLET_MODE_FLAG BIT(6)
0021
0022 MODULE_LICENSE("GPL");
0023 MODULE_AUTHOR("Alex Hung");
0024
0025 static const struct acpi_device_id intel_hid_ids[] = {
0026 {"INT33D5", 0},
0027 {"INTC1051", 0},
0028 {"INTC1054", 0},
0029 {"INTC1070", 0},
0030 {"", 0},
0031 };
0032 MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
0033
0034
0035 static const struct key_entry intel_hid_keymap[] = {
0036
0037
0038 { KE_KEY, 3, { KEY_NUMLOCK } },
0039 { KE_KEY, 4, { KEY_HOME } },
0040 { KE_KEY, 5, { KEY_END } },
0041 { KE_KEY, 6, { KEY_PAGEUP } },
0042 { KE_KEY, 7, { KEY_PAGEDOWN } },
0043 { KE_KEY, 8, { KEY_RFKILL } },
0044 { KE_KEY, 9, { KEY_POWER } },
0045 { KE_KEY, 11, { KEY_SLEEP } },
0046
0047 { KE_KEY, 14, { KEY_STOPCD } },
0048 { KE_KEY, 15, { KEY_PLAYPAUSE } },
0049 { KE_KEY, 16, { KEY_MUTE } },
0050 { KE_KEY, 17, { KEY_VOLUMEUP } },
0051 { KE_KEY, 18, { KEY_VOLUMEDOWN } },
0052 { KE_KEY, 19, { KEY_BRIGHTNESSUP } },
0053 { KE_KEY, 20, { KEY_BRIGHTNESSDOWN } },
0054
0055 { KE_END },
0056 };
0057
0058
0059 static const struct key_entry intel_array_keymap[] = {
0060 { KE_KEY, 0xC2, { KEY_LEFTMETA } },
0061 { KE_IGNORE, 0xC3, { KEY_LEFTMETA } },
0062 { KE_KEY, 0xC4, { KEY_VOLUMEUP } },
0063 { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } },
0064 { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } },
0065 { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } },
0066 { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } },
0067 { KE_IGNORE, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } },
0068 { KE_KEY, 0xCE, { KEY_POWER } },
0069 { KE_IGNORE, 0xCF, { KEY_POWER } },
0070 { KE_END },
0071 };
0072
0073 static const struct dmi_system_id button_array_table[] = {
0074 {
0075 .ident = "Wacom MobileStudio Pro 13",
0076 .matches = {
0077 DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
0078 DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"),
0079 },
0080 },
0081 {
0082 .ident = "Wacom MobileStudio Pro 16",
0083 .matches = {
0084 DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
0085 DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"),
0086 },
0087 },
0088 {
0089 .ident = "HP Spectre x2 (2015)",
0090 .matches = {
0091 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
0092 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x2 Detachable"),
0093 },
0094 },
0095 {
0096 .ident = "Lenovo ThinkPad X1 Tablet Gen 2",
0097 .matches = {
0098 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0099 DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Tablet Gen 2"),
0100 },
0101 },
0102 {
0103 .ident = "Microsoft Surface Go 3",
0104 .matches = {
0105 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0106 DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
0107 },
0108 },
0109 { }
0110 };
0111
0112
0113
0114
0115
0116
0117
0118 static const struct dmi_system_id dmi_vgbs_allow_list[] = {
0119 {
0120 .matches = {
0121 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
0122 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible 15-df0xxx"),
0123 },
0124 },
0125 {
0126 .matches = {
0127 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0128 DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go"),
0129 },
0130 },
0131 { }
0132 };
0133
0134
0135
0136
0137
0138 static const struct dmi_system_id dmi_auto_add_switch[] = {
0139 {
0140 .matches = {
0141 DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" ),
0142 },
0143 },
0144 {
0145 .matches = {
0146 DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" ),
0147 },
0148 },
0149 {}
0150 };
0151
0152 struct intel_hid_priv {
0153 struct input_dev *input_dev;
0154 struct input_dev *array;
0155 struct input_dev *switches;
0156 bool wakeup_mode;
0157 bool auto_add_switch;
0158 };
0159
0160 #define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054"
0161
0162 enum intel_hid_dsm_fn_codes {
0163 INTEL_HID_DSM_FN_INVALID,
0164 INTEL_HID_DSM_BTNL_FN,
0165 INTEL_HID_DSM_HDMM_FN,
0166 INTEL_HID_DSM_HDSM_FN,
0167 INTEL_HID_DSM_HDEM_FN,
0168 INTEL_HID_DSM_BTNS_FN,
0169 INTEL_HID_DSM_BTNE_FN,
0170 INTEL_HID_DSM_HEBC_V1_FN,
0171 INTEL_HID_DSM_VGBS_FN,
0172 INTEL_HID_DSM_HEBC_V2_FN,
0173 INTEL_HID_DSM_FN_MAX
0174 };
0175
0176 static const char *intel_hid_dsm_fn_to_method[INTEL_HID_DSM_FN_MAX] = {
0177 NULL,
0178 "BTNL",
0179 "HDMM",
0180 "HDSM",
0181 "HDEM",
0182 "BTNS",
0183 "BTNE",
0184 "HEBC",
0185 "VGBS",
0186 "HEBC"
0187 };
0188
0189 static unsigned long long intel_hid_dsm_fn_mask;
0190 static guid_t intel_dsm_guid;
0191
0192 static bool intel_hid_execute_method(acpi_handle handle,
0193 enum intel_hid_dsm_fn_codes fn_index,
0194 unsigned long long arg)
0195 {
0196 union acpi_object *obj, argv4, req;
0197 acpi_status status;
0198 char *method_name;
0199
0200 if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
0201 fn_index >= INTEL_HID_DSM_FN_MAX)
0202 return false;
0203
0204 method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
0205
0206 if (!(intel_hid_dsm_fn_mask & BIT(fn_index)))
0207 goto skip_dsm_exec;
0208
0209
0210 req.type = ACPI_TYPE_INTEGER;
0211 req.integer.value = arg;
0212
0213 argv4.type = ACPI_TYPE_PACKAGE;
0214 argv4.package.count = 1;
0215 argv4.package.elements = &req;
0216
0217 obj = acpi_evaluate_dsm(handle, &intel_dsm_guid, 1, fn_index, &argv4);
0218 if (obj) {
0219 acpi_handle_debug(handle, "Exec DSM Fn code: %d[%s] success\n",
0220 fn_index, method_name);
0221 ACPI_FREE(obj);
0222 return true;
0223 }
0224
0225 skip_dsm_exec:
0226 status = acpi_execute_simple_method(handle, method_name, arg);
0227 if (ACPI_SUCCESS(status))
0228 return true;
0229
0230 return false;
0231 }
0232
0233 static bool intel_hid_evaluate_method(acpi_handle handle,
0234 enum intel_hid_dsm_fn_codes fn_index,
0235 unsigned long long *result)
0236 {
0237 union acpi_object *obj;
0238 acpi_status status;
0239 char *method_name;
0240
0241 if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
0242 fn_index >= INTEL_HID_DSM_FN_MAX)
0243 return false;
0244
0245 method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
0246
0247 if (!(intel_hid_dsm_fn_mask & BIT(fn_index)))
0248 goto skip_dsm_eval;
0249
0250 obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid,
0251 1, fn_index,
0252 NULL, ACPI_TYPE_INTEGER);
0253 if (obj) {
0254 *result = obj->integer.value;
0255 acpi_handle_debug(handle,
0256 "Eval DSM Fn code: %d[%s] results: 0x%llx\n",
0257 fn_index, method_name, *result);
0258 ACPI_FREE(obj);
0259 return true;
0260 }
0261
0262 skip_dsm_eval:
0263 status = acpi_evaluate_integer(handle, method_name, NULL, result);
0264 if (ACPI_SUCCESS(status))
0265 return true;
0266
0267 return false;
0268 }
0269
0270 static void intel_hid_init_dsm(acpi_handle handle)
0271 {
0272 union acpi_object *obj;
0273
0274 guid_parse(HID_EVENT_FILTER_UUID, &intel_dsm_guid);
0275
0276 obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, 1, 0, NULL,
0277 ACPI_TYPE_BUFFER);
0278 if (obj) {
0279 switch (obj->buffer.length) {
0280 default:
0281 case 2:
0282 intel_hid_dsm_fn_mask = *(u16 *)obj->buffer.pointer;
0283 break;
0284 case 1:
0285 intel_hid_dsm_fn_mask = *obj->buffer.pointer;
0286 break;
0287 case 0:
0288 acpi_handle_warn(handle, "intel_hid_dsm_fn_mask length is zero\n");
0289 intel_hid_dsm_fn_mask = 0;
0290 break;
0291 }
0292 ACPI_FREE(obj);
0293 }
0294
0295 acpi_handle_debug(handle, "intel_hid_dsm_fn_mask = %llx\n",
0296 intel_hid_dsm_fn_mask);
0297 }
0298
0299 static int intel_hid_set_enable(struct device *device, bool enable)
0300 {
0301 acpi_handle handle = ACPI_HANDLE(device);
0302
0303
0304 if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN,
0305 enable)) {
0306 dev_warn(device, "failed to %sable hotkeys\n",
0307 enable ? "en" : "dis");
0308 return -EIO;
0309 }
0310
0311 return 0;
0312 }
0313
0314 static void intel_button_array_enable(struct device *device, bool enable)
0315 {
0316 struct intel_hid_priv *priv = dev_get_drvdata(device);
0317 acpi_handle handle = ACPI_HANDLE(device);
0318 unsigned long long button_cap;
0319 acpi_status status;
0320
0321 if (!priv->array)
0322 return;
0323
0324
0325 status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap);
0326 if (ACPI_FAILURE(status)) {
0327 dev_warn(device, "failed to get button capability\n");
0328 return;
0329 }
0330
0331
0332 if (!intel_hid_execute_method(handle, INTEL_HID_DSM_BTNE_FN,
0333 enable ? button_cap : 1))
0334 dev_warn(device, "failed to set button capability\n");
0335 }
0336
0337 static int intel_hid_pm_prepare(struct device *device)
0338 {
0339 if (device_may_wakeup(device)) {
0340 struct intel_hid_priv *priv = dev_get_drvdata(device);
0341
0342 priv->wakeup_mode = true;
0343 }
0344 return 0;
0345 }
0346
0347 static void intel_hid_pm_complete(struct device *device)
0348 {
0349 struct intel_hid_priv *priv = dev_get_drvdata(device);
0350
0351 priv->wakeup_mode = false;
0352 }
0353
0354 static int intel_hid_pl_suspend_handler(struct device *device)
0355 {
0356 intel_button_array_enable(device, false);
0357
0358 if (!pm_suspend_no_platform())
0359 intel_hid_set_enable(device, false);
0360
0361 return 0;
0362 }
0363
0364 static int intel_hid_pl_resume_handler(struct device *device)
0365 {
0366 intel_hid_pm_complete(device);
0367
0368 if (!pm_suspend_no_platform())
0369 intel_hid_set_enable(device, true);
0370
0371 intel_button_array_enable(device, true);
0372 return 0;
0373 }
0374
0375 static const struct dev_pm_ops intel_hid_pl_pm_ops = {
0376 .prepare = intel_hid_pm_prepare,
0377 .complete = intel_hid_pm_complete,
0378 .freeze = intel_hid_pl_suspend_handler,
0379 .thaw = intel_hid_pl_resume_handler,
0380 .restore = intel_hid_pl_resume_handler,
0381 .suspend = intel_hid_pl_suspend_handler,
0382 .resume = intel_hid_pl_resume_handler,
0383 };
0384
0385 static int intel_hid_input_setup(struct platform_device *device)
0386 {
0387 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
0388 int ret;
0389
0390 priv->input_dev = devm_input_allocate_device(&device->dev);
0391 if (!priv->input_dev)
0392 return -ENOMEM;
0393
0394 ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL);
0395 if (ret)
0396 return ret;
0397
0398 priv->input_dev->name = "Intel HID events";
0399 priv->input_dev->id.bustype = BUS_HOST;
0400
0401 return input_register_device(priv->input_dev);
0402 }
0403
0404 static int intel_button_array_input_setup(struct platform_device *device)
0405 {
0406 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
0407 int ret;
0408
0409
0410 priv->array = devm_input_allocate_device(&device->dev);
0411 if (!priv->array)
0412 return -ENOMEM;
0413
0414 ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
0415 if (ret)
0416 return ret;
0417
0418 priv->array->name = "Intel HID 5 button array";
0419 priv->array->id.bustype = BUS_HOST;
0420
0421 return input_register_device(priv->array);
0422 }
0423
0424 static int intel_hid_switches_setup(struct platform_device *device)
0425 {
0426 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
0427
0428
0429 priv->switches = devm_input_allocate_device(&device->dev);
0430 if (!priv->switches)
0431 return -ENOMEM;
0432
0433 __set_bit(EV_SW, priv->switches->evbit);
0434 __set_bit(SW_TABLET_MODE, priv->switches->swbit);
0435
0436 priv->switches->name = "Intel HID switches";
0437 priv->switches->id.bustype = BUS_HOST;
0438 return input_register_device(priv->switches);
0439 }
0440
0441 static void report_tablet_mode_state(struct platform_device *device)
0442 {
0443 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
0444 acpi_handle handle = ACPI_HANDLE(&device->dev);
0445 unsigned long long vgbs;
0446 int m;
0447
0448 if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_VGBS_FN, &vgbs))
0449 return;
0450
0451 m = !(vgbs & TABLET_MODE_FLAG);
0452 input_report_switch(priv->switches, SW_TABLET_MODE, m);
0453 input_sync(priv->switches);
0454 }
0455
0456 static bool report_tablet_mode_event(struct input_dev *input_dev, u32 event)
0457 {
0458 if (!input_dev)
0459 return false;
0460
0461 switch (event) {
0462 case 0xcc:
0463 input_report_switch(input_dev, SW_TABLET_MODE, 1);
0464 input_sync(input_dev);
0465 return true;
0466 case 0xcd:
0467 input_report_switch(input_dev, SW_TABLET_MODE, 0);
0468 input_sync(input_dev);
0469 return true;
0470 default:
0471 return false;
0472 }
0473 }
0474
0475 static void notify_handler(acpi_handle handle, u32 event, void *context)
0476 {
0477 struct platform_device *device = context;
0478 struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
0479 unsigned long long ev_index;
0480 int err;
0481
0482
0483
0484
0485
0486
0487 if (!priv->switches && priv->auto_add_switch && (event == 0xcc || event == 0xcd)) {
0488 dev_info(&device->dev, "switch event received, enable switches supports\n");
0489 err = intel_hid_switches_setup(device);
0490 if (err)
0491 pr_err("Failed to setup Intel HID switches\n");
0492 }
0493
0494 if (priv->wakeup_mode) {
0495
0496
0497
0498
0499
0500
0501 if (event == 0xce)
0502 goto wakeup;
0503
0504
0505
0506
0507
0508
0509
0510
0511 if (event == 0xcc || event == 0xcd) {
0512 report_tablet_mode_event(priv->switches, event);
0513 return;
0514 }
0515
0516
0517 if (event == 0xc0 || !priv->array)
0518 return;
0519
0520 if (!sparse_keymap_entry_from_scancode(priv->array, event)) {
0521 dev_info(&device->dev, "unknown event 0x%x\n", event);
0522 return;
0523 }
0524
0525 wakeup:
0526 pm_wakeup_hard_event(&device->dev);
0527
0528 return;
0529 }
0530
0531
0532
0533
0534
0535
0536
0537
0538 if (!priv->array) {
0539 if (event == 0xce) {
0540 input_report_key(priv->input_dev, KEY_POWER, 1);
0541 input_sync(priv->input_dev);
0542 return;
0543 }
0544
0545 if (event == 0xcf) {
0546 input_report_key(priv->input_dev, KEY_POWER, 0);
0547 input_sync(priv->input_dev);
0548 return;
0549 }
0550 }
0551
0552 if (report_tablet_mode_event(priv->switches, event))
0553 return;
0554
0555
0556 if (event != 0xc0) {
0557 if (!priv->array ||
0558 !sparse_keymap_report_event(priv->array, event, 1, true))
0559 dev_dbg(&device->dev, "unknown event 0x%x\n", event);
0560 return;
0561 }
0562
0563 if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDEM_FN,
0564 &ev_index)) {
0565 dev_warn(&device->dev, "failed to get event index\n");
0566 return;
0567 }
0568
0569 if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true))
0570 dev_dbg(&device->dev, "unknown event index 0x%llx\n",
0571 ev_index);
0572 }
0573
0574 static bool button_array_present(struct platform_device *device)
0575 {
0576 acpi_handle handle = ACPI_HANDLE(&device->dev);
0577 unsigned long long event_cap;
0578
0579 if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V2_FN,
0580 &event_cap)) {
0581
0582 if (event_cap & 0x60000)
0583 return true;
0584 }
0585
0586 if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V1_FN,
0587 &event_cap)) {
0588 if (event_cap & 0x20000)
0589 return true;
0590 }
0591
0592 if (dmi_check_system(button_array_table))
0593 return true;
0594
0595 return false;
0596 }
0597
0598 static int intel_hid_probe(struct platform_device *device)
0599 {
0600 acpi_handle handle = ACPI_HANDLE(&device->dev);
0601 unsigned long long mode;
0602 struct intel_hid_priv *priv;
0603 acpi_status status;
0604 int err;
0605
0606 intel_hid_init_dsm(handle);
0607
0608 if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) {
0609 dev_warn(&device->dev, "failed to read mode\n");
0610 return -ENODEV;
0611 }
0612
0613 if (mode != 0) {
0614
0615
0616
0617
0618
0619 dev_info(&device->dev, "platform is not in simple mode\n");
0620 return -ENODEV;
0621 }
0622
0623 priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
0624 if (!priv)
0625 return -ENOMEM;
0626 dev_set_drvdata(&device->dev, priv);
0627
0628
0629 priv->auto_add_switch = dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect();
0630
0631 err = intel_hid_input_setup(device);
0632 if (err) {
0633 pr_err("Failed to setup Intel HID hotkeys\n");
0634 return err;
0635 }
0636
0637
0638 if (button_array_present(device)) {
0639 dev_info(&device->dev, "platform supports 5 button array\n");
0640 err = intel_button_array_input_setup(device);
0641 if (err)
0642 pr_err("Failed to setup Intel 5 button array hotkeys\n");
0643 }
0644
0645
0646 if (dmi_check_system(dmi_vgbs_allow_list)) {
0647 dev_info(&device->dev, "platform supports switches\n");
0648 err = intel_hid_switches_setup(device);
0649 if (err)
0650 pr_err("Failed to setup Intel HID switches\n");
0651 else
0652 report_tablet_mode_state(device);
0653 }
0654
0655 status = acpi_install_notify_handler(handle,
0656 ACPI_DEVICE_NOTIFY,
0657 notify_handler,
0658 device);
0659 if (ACPI_FAILURE(status))
0660 return -EBUSY;
0661
0662 err = intel_hid_set_enable(&device->dev, true);
0663 if (err)
0664 goto err_remove_notify;
0665
0666 if (priv->array) {
0667 unsigned long long dummy;
0668
0669 intel_button_array_enable(&device->dev, true);
0670
0671
0672 if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN,
0673 &dummy)) {
0674 dev_warn(&device->dev,
0675 "failed to enable HID power button\n");
0676 }
0677 }
0678
0679 device_init_wakeup(&device->dev, true);
0680
0681
0682
0683
0684
0685 acpi_ec_mark_gpe_for_wake();
0686 return 0;
0687
0688 err_remove_notify:
0689 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
0690
0691 return err;
0692 }
0693
0694 static int intel_hid_remove(struct platform_device *device)
0695 {
0696 acpi_handle handle = ACPI_HANDLE(&device->dev);
0697
0698 device_init_wakeup(&device->dev, false);
0699 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
0700 intel_hid_set_enable(&device->dev, false);
0701 intel_button_array_enable(&device->dev, false);
0702
0703
0704
0705
0706
0707 return 0;
0708 }
0709
0710 static struct platform_driver intel_hid_pl_driver = {
0711 .driver = {
0712 .name = "intel-hid",
0713 .acpi_match_table = intel_hid_ids,
0714 .pm = &intel_hid_pl_pm_ops,
0715 },
0716 .probe = intel_hid_probe,
0717 .remove = intel_hid_remove,
0718 };
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731 static acpi_status __init
0732 check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
0733 {
0734 const struct acpi_device_id *ids = context;
0735 struct acpi_device *dev = acpi_fetch_acpi_dev(handle);
0736
0737 if (dev && acpi_match_device_ids(dev, ids) == 0)
0738 if (!IS_ERR_OR_NULL(acpi_create_platform_device(dev, NULL)))
0739 dev_info(&dev->dev,
0740 "intel-hid: created platform device\n");
0741
0742 return AE_OK;
0743 }
0744
0745 static int __init intel_hid_init(void)
0746 {
0747 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
0748 ACPI_UINT32_MAX, check_acpi_dev, NULL,
0749 (void *)intel_hid_ids, NULL);
0750
0751 return platform_driver_register(&intel_hid_pl_driver);
0752 }
0753 module_init(intel_hid_init);
0754
0755 static void __exit intel_hid_exit(void)
0756 {
0757 platform_driver_unregister(&intel_hid_pl_driver);
0758 }
0759 module_exit(intel_hid_exit);