root/drivers/platform/x86/intel-hid.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intel_hid_execute_method
  2. intel_hid_evaluate_method
  3. intel_hid_init_dsm
  4. intel_hid_set_enable
  5. intel_button_array_enable
  6. intel_hid_pm_prepare
  7. intel_hid_pm_complete
  8. intel_hid_pl_suspend_handler
  9. intel_hid_pl_resume_handler
  10. intel_hid_input_setup
  11. intel_button_array_input_setup
  12. notify_handler
  13. button_array_present
  14. intel_hid_probe
  15. intel_hid_remove
  16. check_acpi_dev
  17. intel_hid_init
  18. intel_hid_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  *  Intel HID event & 5 button array driver
   4  *
   5  *  Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
   6  *  Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org>
   7  */
   8 
   9 #include <linux/acpi.h>
  10 #include <linux/dmi.h>
  11 #include <linux/input.h>
  12 #include <linux/input/sparse-keymap.h>
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/suspend.h>
  17 
  18 MODULE_LICENSE("GPL");
  19 MODULE_AUTHOR("Alex Hung");
  20 
  21 static const struct acpi_device_id intel_hid_ids[] = {
  22         {"INT33D5", 0},
  23         {"", 0},
  24 };
  25 
  26 /* In theory, these are HID usages. */
  27 static const struct key_entry intel_hid_keymap[] = {
  28         /* 1: LSuper (Page 0x07, usage 0xE3) -- unclear what to do */
  29         /* 2: Toggle SW_ROTATE_LOCK -- easy to implement if seen in wild */
  30         { KE_KEY, 3, { KEY_NUMLOCK } },
  31         { KE_KEY, 4, { KEY_HOME } },
  32         { KE_KEY, 5, { KEY_END } },
  33         { KE_KEY, 6, { KEY_PAGEUP } },
  34         { KE_KEY, 7, { KEY_PAGEDOWN } },
  35         { KE_KEY, 8, { KEY_RFKILL } },
  36         { KE_KEY, 9, { KEY_POWER } },
  37         { KE_KEY, 11, { KEY_SLEEP } },
  38         /* 13 has two different meanings in the spec -- ignore it. */
  39         { KE_KEY, 14, { KEY_STOPCD } },
  40         { KE_KEY, 15, { KEY_PLAYPAUSE } },
  41         { KE_KEY, 16, { KEY_MUTE } },
  42         { KE_KEY, 17, { KEY_VOLUMEUP } },
  43         { KE_KEY, 18, { KEY_VOLUMEDOWN } },
  44         { KE_KEY, 19, { KEY_BRIGHTNESSUP } },
  45         { KE_KEY, 20, { KEY_BRIGHTNESSDOWN } },
  46         /* 27: wake -- needs special handling */
  47         { KE_END },
  48 };
  49 
  50 /* 5 button array notification value. */
  51 static const struct key_entry intel_array_keymap[] = {
  52         { KE_KEY,    0xC2, { KEY_LEFTMETA } },                /* Press */
  53         { KE_IGNORE, 0xC3, { KEY_LEFTMETA } },                /* Release */
  54         { KE_KEY,    0xC4, { KEY_VOLUMEUP } },                /* Press */
  55         { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } },                /* Release */
  56         { KE_KEY,    0xC6, { KEY_VOLUMEDOWN } },              /* Press */
  57         { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } },              /* Release */
  58         { KE_KEY,    0xC8, { KEY_ROTATE_LOCK_TOGGLE } },      /* Press */
  59         { KE_IGNORE, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } },      /* Release */
  60         { KE_KEY,    0xCE, { KEY_POWER } },                   /* Press */
  61         { KE_IGNORE, 0xCF, { KEY_POWER } },                   /* Release */
  62         { KE_END },
  63 };
  64 
  65 static const struct dmi_system_id button_array_table[] = {
  66         {
  67                 .ident = "Wacom MobileStudio Pro 13",
  68                 .matches = {
  69                         DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
  70                         DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"),
  71                 },
  72         },
  73         {
  74                 .ident = "Wacom MobileStudio Pro 16",
  75                 .matches = {
  76                         DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
  77                         DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"),
  78                 },
  79         },
  80         { }
  81 };
  82 
  83 struct intel_hid_priv {
  84         struct input_dev *input_dev;
  85         struct input_dev *array;
  86         bool wakeup_mode;
  87 };
  88 
  89 #define HID_EVENT_FILTER_UUID   "eeec56b3-4442-408f-a792-4edd4d758054"
  90 
  91 enum intel_hid_dsm_fn_codes {
  92         INTEL_HID_DSM_FN_INVALID,
  93         INTEL_HID_DSM_BTNL_FN,
  94         INTEL_HID_DSM_HDMM_FN,
  95         INTEL_HID_DSM_HDSM_FN,
  96         INTEL_HID_DSM_HDEM_FN,
  97         INTEL_HID_DSM_BTNS_FN,
  98         INTEL_HID_DSM_BTNE_FN,
  99         INTEL_HID_DSM_HEBC_V1_FN,
 100         INTEL_HID_DSM_VGBS_FN,
 101         INTEL_HID_DSM_HEBC_V2_FN,
 102         INTEL_HID_DSM_FN_MAX
 103 };
 104 
 105 static const char *intel_hid_dsm_fn_to_method[INTEL_HID_DSM_FN_MAX] = {
 106         NULL,
 107         "BTNL",
 108         "HDMM",
 109         "HDSM",
 110         "HDEM",
 111         "BTNS",
 112         "BTNE",
 113         "HEBC",
 114         "VGBS",
 115         "HEBC"
 116 };
 117 
 118 static unsigned long long intel_hid_dsm_fn_mask;
 119 static guid_t intel_dsm_guid;
 120 
 121 static bool intel_hid_execute_method(acpi_handle handle,
 122                                      enum intel_hid_dsm_fn_codes fn_index,
 123                                      unsigned long long arg)
 124 {
 125         union acpi_object *obj, argv4, req;
 126         acpi_status status;
 127         char *method_name;
 128 
 129         if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
 130             fn_index >= INTEL_HID_DSM_FN_MAX)
 131                 return false;
 132 
 133         method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
 134 
 135         if (!(intel_hid_dsm_fn_mask & fn_index))
 136                 goto skip_dsm_exec;
 137 
 138         /* All methods expects a package with one integer element */
 139         req.type = ACPI_TYPE_INTEGER;
 140         req.integer.value = arg;
 141 
 142         argv4.type = ACPI_TYPE_PACKAGE;
 143         argv4.package.count = 1;
 144         argv4.package.elements = &req;
 145 
 146         obj = acpi_evaluate_dsm(handle, &intel_dsm_guid, 1, fn_index, &argv4);
 147         if (obj) {
 148                 acpi_handle_debug(handle, "Exec DSM Fn code: %d[%s] success\n",
 149                                   fn_index, method_name);
 150                 ACPI_FREE(obj);
 151                 return true;
 152         }
 153 
 154 skip_dsm_exec:
 155         status = acpi_execute_simple_method(handle, method_name, arg);
 156         if (ACPI_SUCCESS(status))
 157                 return true;
 158 
 159         return false;
 160 }
 161 
 162 static bool intel_hid_evaluate_method(acpi_handle handle,
 163                                       enum intel_hid_dsm_fn_codes fn_index,
 164                                       unsigned long long *result)
 165 {
 166         union acpi_object *obj;
 167         acpi_status status;
 168         char *method_name;
 169 
 170         if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
 171             fn_index >= INTEL_HID_DSM_FN_MAX)
 172                 return false;
 173 
 174         method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
 175 
 176         if (!(intel_hid_dsm_fn_mask & fn_index))
 177                 goto skip_dsm_eval;
 178 
 179         obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid,
 180                                       1, fn_index,
 181                                       NULL,  ACPI_TYPE_INTEGER);
 182         if (obj) {
 183                 *result = obj->integer.value;
 184                 acpi_handle_debug(handle,
 185                                   "Eval DSM Fn code: %d[%s] results: 0x%llx\n",
 186                                   fn_index, method_name, *result);
 187                 ACPI_FREE(obj);
 188                 return true;
 189         }
 190 
 191 skip_dsm_eval:
 192         status = acpi_evaluate_integer(handle, method_name, NULL, result);
 193         if (ACPI_SUCCESS(status))
 194                 return true;
 195 
 196         return false;
 197 }
 198 
 199 static void intel_hid_init_dsm(acpi_handle handle)
 200 {
 201         union acpi_object *obj;
 202 
 203         guid_parse(HID_EVENT_FILTER_UUID, &intel_dsm_guid);
 204 
 205         obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, 1, 0, NULL,
 206                                       ACPI_TYPE_BUFFER);
 207         if (obj) {
 208                 intel_hid_dsm_fn_mask = *obj->buffer.pointer;
 209                 ACPI_FREE(obj);
 210         }
 211 
 212         acpi_handle_debug(handle, "intel_hid_dsm_fn_mask = %llx\n",
 213                           intel_hid_dsm_fn_mask);
 214 }
 215 
 216 static int intel_hid_set_enable(struct device *device, bool enable)
 217 {
 218         acpi_handle handle = ACPI_HANDLE(device);
 219 
 220         /* Enable|disable features - power button is always enabled */
 221         if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN,
 222                                       enable)) {
 223                 dev_warn(device, "failed to %sable hotkeys\n",
 224                          enable ? "en" : "dis");
 225                 return -EIO;
 226         }
 227 
 228         return 0;
 229 }
 230 
 231 static void intel_button_array_enable(struct device *device, bool enable)
 232 {
 233         struct intel_hid_priv *priv = dev_get_drvdata(device);
 234         acpi_handle handle = ACPI_HANDLE(device);
 235         unsigned long long button_cap;
 236         acpi_status status;
 237 
 238         if (!priv->array)
 239                 return;
 240 
 241         /* Query supported platform features */
 242         status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap);
 243         if (ACPI_FAILURE(status)) {
 244                 dev_warn(device, "failed to get button capability\n");
 245                 return;
 246         }
 247 
 248         /* Enable|disable features - power button is always enabled */
 249         if (!intel_hid_execute_method(handle, INTEL_HID_DSM_BTNE_FN,
 250                                       enable ? button_cap : 1))
 251                 dev_warn(device, "failed to set button capability\n");
 252 }
 253 
 254 static int intel_hid_pm_prepare(struct device *device)
 255 {
 256         if (device_may_wakeup(device)) {
 257                 struct intel_hid_priv *priv = dev_get_drvdata(device);
 258 
 259                 priv->wakeup_mode = true;
 260         }
 261         return 0;
 262 }
 263 
 264 static void intel_hid_pm_complete(struct device *device)
 265 {
 266         struct intel_hid_priv *priv = dev_get_drvdata(device);
 267 
 268         priv->wakeup_mode = false;
 269 }
 270 
 271 static int intel_hid_pl_suspend_handler(struct device *device)
 272 {
 273         intel_button_array_enable(device, false);
 274 
 275         if (!pm_suspend_no_platform())
 276                 intel_hid_set_enable(device, false);
 277 
 278         return 0;
 279 }
 280 
 281 static int intel_hid_pl_resume_handler(struct device *device)
 282 {
 283         intel_hid_pm_complete(device);
 284 
 285         if (!pm_suspend_no_platform())
 286                 intel_hid_set_enable(device, true);
 287 
 288         intel_button_array_enable(device, true);
 289         return 0;
 290 }
 291 
 292 static const struct dev_pm_ops intel_hid_pl_pm_ops = {
 293         .prepare = intel_hid_pm_prepare,
 294         .complete = intel_hid_pm_complete,
 295         .freeze  = intel_hid_pl_suspend_handler,
 296         .thaw  = intel_hid_pl_resume_handler,
 297         .restore  = intel_hid_pl_resume_handler,
 298         .suspend  = intel_hid_pl_suspend_handler,
 299         .resume  = intel_hid_pl_resume_handler,
 300 };
 301 
 302 static int intel_hid_input_setup(struct platform_device *device)
 303 {
 304         struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
 305         int ret;
 306 
 307         priv->input_dev = devm_input_allocate_device(&device->dev);
 308         if (!priv->input_dev)
 309                 return -ENOMEM;
 310 
 311         ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL);
 312         if (ret)
 313                 return ret;
 314 
 315         priv->input_dev->name = "Intel HID events";
 316         priv->input_dev->id.bustype = BUS_HOST;
 317 
 318         return input_register_device(priv->input_dev);
 319 }
 320 
 321 static int intel_button_array_input_setup(struct platform_device *device)
 322 {
 323         struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
 324         int ret;
 325 
 326         /* Setup input device for 5 button array */
 327         priv->array = devm_input_allocate_device(&device->dev);
 328         if (!priv->array)
 329                 return -ENOMEM;
 330 
 331         ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
 332         if (ret)
 333                 return ret;
 334 
 335         priv->array->name = "Intel HID 5 button array";
 336         priv->array->id.bustype = BUS_HOST;
 337 
 338         return input_register_device(priv->array);
 339 }
 340 
 341 static void notify_handler(acpi_handle handle, u32 event, void *context)
 342 {
 343         struct platform_device *device = context;
 344         struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
 345         unsigned long long ev_index;
 346 
 347         if (priv->wakeup_mode) {
 348                 /*
 349                  * Needed for wakeup from suspend-to-idle to work on some
 350                  * platforms that don't expose the 5-button array, but still
 351                  * send notifies with the power button event code to this
 352                  * device object on power button actions while suspended.
 353                  */
 354                 if (event == 0xce)
 355                         goto wakeup;
 356 
 357                 /* Wake up on 5-button array events only. */
 358                 if (event == 0xc0 || !priv->array)
 359                         return;
 360 
 361                 if (!sparse_keymap_entry_from_scancode(priv->array, event)) {
 362                         dev_info(&device->dev, "unknown event 0x%x\n", event);
 363                         return;
 364                 }
 365 
 366 wakeup:
 367                 pm_wakeup_hard_event(&device->dev);
 368                 return;
 369         }
 370 
 371         /*
 372          * Needed for suspend to work on some platforms that don't expose
 373          * the 5-button array, but still send notifies with power button
 374          * event code to this device object on power button actions.
 375          *
 376          * Report the power button press and release.
 377          */
 378         if (!priv->array) {
 379                 if (event == 0xce) {
 380                         input_report_key(priv->input_dev, KEY_POWER, 1);
 381                         input_sync(priv->input_dev);
 382                         return;
 383                 }
 384 
 385                 if (event == 0xcf) {
 386                         input_report_key(priv->input_dev, KEY_POWER, 0);
 387                         input_sync(priv->input_dev);
 388                         return;
 389                 }
 390         }
 391 
 392         /* 0xC0 is for HID events, other values are for 5 button array */
 393         if (event != 0xc0) {
 394                 if (!priv->array ||
 395                     !sparse_keymap_report_event(priv->array, event, 1, true))
 396                         dev_dbg(&device->dev, "unknown event 0x%x\n", event);
 397                 return;
 398         }
 399 
 400         if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDEM_FN,
 401                                        &ev_index)) {
 402                 dev_warn(&device->dev, "failed to get event index\n");
 403                 return;
 404         }
 405 
 406         if (!sparse_keymap_report_event(priv->input_dev, ev_index, 1, true))
 407                 dev_dbg(&device->dev, "unknown event index 0x%llx\n",
 408                          ev_index);
 409 }
 410 
 411 static bool button_array_present(struct platform_device *device)
 412 {
 413         acpi_handle handle = ACPI_HANDLE(&device->dev);
 414         unsigned long long event_cap;
 415 
 416         if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V2_FN,
 417                                       &event_cap)) {
 418                 /* Check presence of 5 button array or v2 power button */
 419                 if (event_cap & 0x60000)
 420                         return true;
 421         }
 422 
 423         if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V1_FN,
 424                                       &event_cap)) {
 425                 if (event_cap & 0x20000)
 426                         return true;
 427         }
 428 
 429         if (dmi_check_system(button_array_table))
 430                 return true;
 431 
 432         return false;
 433 }
 434 
 435 static int intel_hid_probe(struct platform_device *device)
 436 {
 437         acpi_handle handle = ACPI_HANDLE(&device->dev);
 438         unsigned long long mode;
 439         struct intel_hid_priv *priv;
 440         acpi_status status;
 441         int err;
 442 
 443         intel_hid_init_dsm(handle);
 444 
 445         if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) {
 446                 dev_warn(&device->dev, "failed to read mode\n");
 447                 return -ENODEV;
 448         }
 449 
 450         if (mode != 0) {
 451                 /*
 452                  * This driver only implements "simple" mode.  There appear
 453                  * to be no other modes, but we should be paranoid and check
 454                  * for compatibility.
 455                  */
 456                 dev_info(&device->dev, "platform is not in simple mode\n");
 457                 return -ENODEV;
 458         }
 459 
 460         priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
 461         if (!priv)
 462                 return -ENOMEM;
 463         dev_set_drvdata(&device->dev, priv);
 464 
 465         err = intel_hid_input_setup(device);
 466         if (err) {
 467                 pr_err("Failed to setup Intel HID hotkeys\n");
 468                 return err;
 469         }
 470 
 471         /* Setup 5 button array */
 472         if (button_array_present(device)) {
 473                 dev_info(&device->dev, "platform supports 5 button array\n");
 474                 err = intel_button_array_input_setup(device);
 475                 if (err)
 476                         pr_err("Failed to setup Intel 5 button array hotkeys\n");
 477         }
 478 
 479         status = acpi_install_notify_handler(handle,
 480                                              ACPI_DEVICE_NOTIFY,
 481                                              notify_handler,
 482                                              device);
 483         if (ACPI_FAILURE(status))
 484                 return -EBUSY;
 485 
 486         err = intel_hid_set_enable(&device->dev, true);
 487         if (err)
 488                 goto err_remove_notify;
 489 
 490         if (priv->array) {
 491                 unsigned long long dummy;
 492 
 493                 intel_button_array_enable(&device->dev, true);
 494 
 495                 /* Call button load method to enable HID power button */
 496                 if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN,
 497                                                &dummy)) {
 498                         dev_warn(&device->dev,
 499                                  "failed to enable HID power button\n");
 500                 }
 501         }
 502 
 503         device_init_wakeup(&device->dev, true);
 504         /*
 505          * In order for system wakeup to work, the EC GPE has to be marked as
 506          * a wakeup one, so do that here (this setting will persist, but it has
 507          * no effect until the wakeup mask is set for the EC GPE).
 508          */
 509         acpi_ec_mark_gpe_for_wake();
 510         return 0;
 511 
 512 err_remove_notify:
 513         acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
 514 
 515         return err;
 516 }
 517 
 518 static int intel_hid_remove(struct platform_device *device)
 519 {
 520         acpi_handle handle = ACPI_HANDLE(&device->dev);
 521 
 522         device_init_wakeup(&device->dev, false);
 523         acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
 524         intel_hid_set_enable(&device->dev, false);
 525         intel_button_array_enable(&device->dev, false);
 526 
 527         /*
 528          * Even if we failed to shut off the event stream, we can still
 529          * safely detach from the device.
 530          */
 531         return 0;
 532 }
 533 
 534 static struct platform_driver intel_hid_pl_driver = {
 535         .driver = {
 536                 .name = "intel-hid",
 537                 .acpi_match_table = intel_hid_ids,
 538                 .pm = &intel_hid_pl_pm_ops,
 539         },
 540         .probe = intel_hid_probe,
 541         .remove = intel_hid_remove,
 542 };
 543 MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
 544 
 545 /*
 546  * Unfortunately, some laptops provide a _HID="INT33D5" device with
 547  * _CID="PNP0C02".  This causes the pnpacpi scan driver to claim the
 548  * ACPI node, so no platform device will be created.  The pnpacpi
 549  * driver rejects this device in subsequent processing, so no physical
 550  * node is created at all.
 551  *
 552  * As a workaround until the ACPI core figures out how to handle
 553  * this corner case, manually ask the ACPI platform device code to
 554  * claim the ACPI node.
 555  */
 556 static acpi_status __init
 557 check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
 558 {
 559         const struct acpi_device_id *ids = context;
 560         struct acpi_device *dev;
 561 
 562         if (acpi_bus_get_device(handle, &dev) != 0)
 563                 return AE_OK;
 564 
 565         if (acpi_match_device_ids(dev, ids) == 0)
 566                 if (acpi_create_platform_device(dev, NULL))
 567                         dev_info(&dev->dev,
 568                                  "intel-hid: created platform device\n");
 569 
 570         return AE_OK;
 571 }
 572 
 573 static int __init intel_hid_init(void)
 574 {
 575         acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 576                             ACPI_UINT32_MAX, check_acpi_dev, NULL,
 577                             (void *)intel_hid_ids, NULL);
 578 
 579         return platform_driver_register(&intel_hid_pl_driver);
 580 }
 581 module_init(intel_hid_init);
 582 
 583 static void __exit intel_hid_exit(void)
 584 {
 585         platform_driver_unregister(&intel_hid_pl_driver);
 586 }
 587 module_exit(intel_hid_exit);

/* [<][>][^][v][top][bottom][index][help] */