chromeos_privacy_screen.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * ChromeOS Privacy Screen support
  4. *
  5. * Copyright (C) 2022 Google LLC
  6. *
  7. * This is the Chromeos privacy screen provider, present on certain chromebooks,
  8. * represented by a GOOG0010 device in the ACPI. This ACPI device, if present,
  9. * will cause the i915 drm driver to probe defer until this driver registers
  10. * the privacy-screen.
  11. */
  12. #include <linux/acpi.h>
  13. #include <drm/drm_privacy_screen_driver.h>
  14. /*
  15. * The DSM (Device Specific Method) constants below are the agreed API with
  16. * the firmware team, on how to control privacy screen using ACPI methods.
  17. */
  18. #define PRIV_SCRN_DSM_REVID 1 /* DSM version */
  19. #define PRIV_SCRN_DSM_FN_GET_STATUS 1 /* Get privacy screen status */
  20. #define PRIV_SCRN_DSM_FN_ENABLE 2 /* Enable privacy screen */
  21. #define PRIV_SCRN_DSM_FN_DISABLE 3 /* Disable privacy screen */
  22. static const guid_t chromeos_privacy_screen_dsm_guid =
  23. GUID_INIT(0xc7033113, 0x8720, 0x4ceb,
  24. 0x90, 0x90, 0x9d, 0x52, 0xb3, 0xe5, 0x2d, 0x73);
  25. static void
  26. chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen
  27. *drm_privacy_screen)
  28. {
  29. union acpi_object *obj;
  30. acpi_handle handle;
  31. struct device *privacy_screen =
  32. drm_privacy_screen_get_drvdata(drm_privacy_screen);
  33. handle = acpi_device_handle(to_acpi_device(privacy_screen));
  34. obj = acpi_evaluate_dsm(handle, &chromeos_privacy_screen_dsm_guid,
  35. PRIV_SCRN_DSM_REVID,
  36. PRIV_SCRN_DSM_FN_GET_STATUS, NULL);
  37. if (!obj) {
  38. dev_err(privacy_screen,
  39. "_DSM failed to get privacy-screen state\n");
  40. return;
  41. }
  42. if (obj->type != ACPI_TYPE_INTEGER)
  43. dev_err(privacy_screen,
  44. "Bad _DSM to get privacy-screen state\n");
  45. else if (obj->integer.value == 1)
  46. drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
  47. PRIVACY_SCREEN_ENABLED;
  48. else
  49. drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
  50. PRIVACY_SCREEN_DISABLED;
  51. ACPI_FREE(obj);
  52. }
  53. static int
  54. chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen
  55. *drm_privacy_screen,
  56. enum drm_privacy_screen_status state)
  57. {
  58. union acpi_object *obj = NULL;
  59. acpi_handle handle;
  60. struct device *privacy_screen =
  61. drm_privacy_screen_get_drvdata(drm_privacy_screen);
  62. handle = acpi_device_handle(to_acpi_device(privacy_screen));
  63. if (state == PRIVACY_SCREEN_DISABLED) {
  64. obj = acpi_evaluate_dsm(handle,
  65. &chromeos_privacy_screen_dsm_guid,
  66. PRIV_SCRN_DSM_REVID,
  67. PRIV_SCRN_DSM_FN_DISABLE, NULL);
  68. } else if (state == PRIVACY_SCREEN_ENABLED) {
  69. obj = acpi_evaluate_dsm(handle,
  70. &chromeos_privacy_screen_dsm_guid,
  71. PRIV_SCRN_DSM_REVID,
  72. PRIV_SCRN_DSM_FN_ENABLE, NULL);
  73. } else {
  74. dev_err(privacy_screen,
  75. "Bad attempt to set privacy-screen status to %u\n",
  76. state);
  77. return -EINVAL;
  78. }
  79. if (!obj) {
  80. dev_err(privacy_screen,
  81. "_DSM failed to set privacy-screen state\n");
  82. return -EIO;
  83. }
  84. drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = state;
  85. ACPI_FREE(obj);
  86. return 0;
  87. }
  88. static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = {
  89. .get_hw_state = chromeos_privacy_screen_get_hw_state,
  90. .set_sw_state = chromeos_privacy_screen_set_sw_state,
  91. };
  92. static int chromeos_privacy_screen_add(struct acpi_device *adev)
  93. {
  94. struct drm_privacy_screen *drm_privacy_screen =
  95. drm_privacy_screen_register(&adev->dev,
  96. &chromeos_privacy_screen_ops,
  97. &adev->dev);
  98. if (IS_ERR(drm_privacy_screen)) {
  99. dev_err(&adev->dev, "Error registering privacy-screen\n");
  100. return PTR_ERR(drm_privacy_screen);
  101. }
  102. adev->driver_data = drm_privacy_screen;
  103. dev_info(&adev->dev, "registered privacy-screen '%s'\n",
  104. dev_name(&drm_privacy_screen->dev));
  105. return 0;
  106. }
  107. static void chromeos_privacy_screen_remove(struct acpi_device *adev)
  108. {
  109. struct drm_privacy_screen *drm_privacy_screen = acpi_driver_data(adev);
  110. drm_privacy_screen_unregister(drm_privacy_screen);
  111. }
  112. static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = {
  113. {"GOOG0010", 0}, /* Google's electronic privacy screen for eDP-1 */
  114. {}
  115. };
  116. MODULE_DEVICE_TABLE(acpi, chromeos_privacy_screen_device_ids);
  117. static struct acpi_driver chromeos_privacy_screen_driver = {
  118. .name = "chromeos_privacy_screen_driver",
  119. .class = "ChromeOS",
  120. .ids = chromeos_privacy_screen_device_ids,
  121. .ops = {
  122. .add = chromeos_privacy_screen_add,
  123. .remove = chromeos_privacy_screen_remove,
  124. },
  125. };
  126. module_acpi_driver(chromeos_privacy_screen_driver);
  127. MODULE_LICENSE("GPL v2");
  128. MODULE_DESCRIPTION("ChromeOS ACPI Privacy Screen driver");
  129. MODULE_AUTHOR("Rajat Jain <rajatja@google.com>");