Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /*
0004  *  ChromeOS Privacy Screen support
0005  *
0006  * Copyright (C) 2022 Google LLC
0007  *
0008  * This is the Chromeos privacy screen provider, present on certain chromebooks,
0009  * represented by a GOOG0010 device in the ACPI. This ACPI device, if present,
0010  * will cause the i915 drm driver to probe defer until this driver registers
0011  * the privacy-screen.
0012  */
0013 
0014 #include <linux/acpi.h>
0015 #include <drm/drm_privacy_screen_driver.h>
0016 
0017 /*
0018  * The DSM (Device Specific Method) constants below are the agreed API with
0019  * the firmware team, on how to control privacy screen using ACPI methods.
0020  */
0021 #define PRIV_SCRN_DSM_REVID     1   /* DSM version */
0022 #define PRIV_SCRN_DSM_FN_GET_STATUS 1   /* Get privacy screen status */
0023 #define PRIV_SCRN_DSM_FN_ENABLE     2   /* Enable privacy screen */
0024 #define PRIV_SCRN_DSM_FN_DISABLE    3   /* Disable privacy screen */
0025 
0026 static const guid_t chromeos_privacy_screen_dsm_guid =
0027             GUID_INIT(0xc7033113, 0x8720, 0x4ceb,
0028                   0x90, 0x90, 0x9d, 0x52, 0xb3, 0xe5, 0x2d, 0x73);
0029 
0030 static void
0031 chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen
0032                      *drm_privacy_screen)
0033 {
0034     union acpi_object *obj;
0035     acpi_handle handle;
0036     struct device *privacy_screen =
0037         drm_privacy_screen_get_drvdata(drm_privacy_screen);
0038 
0039     handle = acpi_device_handle(to_acpi_device(privacy_screen));
0040     obj = acpi_evaluate_dsm(handle, &chromeos_privacy_screen_dsm_guid,
0041                 PRIV_SCRN_DSM_REVID,
0042                 PRIV_SCRN_DSM_FN_GET_STATUS, NULL);
0043     if (!obj) {
0044         dev_err(privacy_screen,
0045             "_DSM failed to get privacy-screen state\n");
0046         return;
0047     }
0048 
0049     if (obj->type != ACPI_TYPE_INTEGER)
0050         dev_err(privacy_screen,
0051             "Bad _DSM to get privacy-screen state\n");
0052     else if (obj->integer.value == 1)
0053         drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
0054             PRIVACY_SCREEN_ENABLED;
0055     else
0056         drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
0057             PRIVACY_SCREEN_DISABLED;
0058 
0059     ACPI_FREE(obj);
0060 }
0061 
0062 static int
0063 chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen
0064                      *drm_privacy_screen,
0065                      enum drm_privacy_screen_status state)
0066 {
0067     union acpi_object *obj = NULL;
0068     acpi_handle handle;
0069     struct device *privacy_screen =
0070         drm_privacy_screen_get_drvdata(drm_privacy_screen);
0071 
0072     handle = acpi_device_handle(to_acpi_device(privacy_screen));
0073 
0074     if (state == PRIVACY_SCREEN_DISABLED) {
0075         obj = acpi_evaluate_dsm(handle,
0076                     &chromeos_privacy_screen_dsm_guid,
0077                     PRIV_SCRN_DSM_REVID,
0078                     PRIV_SCRN_DSM_FN_DISABLE, NULL);
0079     } else if (state == PRIVACY_SCREEN_ENABLED) {
0080         obj = acpi_evaluate_dsm(handle,
0081                     &chromeos_privacy_screen_dsm_guid,
0082                     PRIV_SCRN_DSM_REVID,
0083                     PRIV_SCRN_DSM_FN_ENABLE, NULL);
0084     } else {
0085         dev_err(privacy_screen,
0086             "Bad attempt to set privacy-screen status to %u\n",
0087             state);
0088         return -EINVAL;
0089     }
0090 
0091     if (!obj) {
0092         dev_err(privacy_screen,
0093             "_DSM failed to set privacy-screen state\n");
0094         return -EIO;
0095     }
0096 
0097     drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = state;
0098     ACPI_FREE(obj);
0099     return 0;
0100 }
0101 
0102 static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = {
0103     .get_hw_state = chromeos_privacy_screen_get_hw_state,
0104     .set_sw_state = chromeos_privacy_screen_set_sw_state,
0105 };
0106 
0107 static int chromeos_privacy_screen_add(struct acpi_device *adev)
0108 {
0109     struct drm_privacy_screen *drm_privacy_screen =
0110         drm_privacy_screen_register(&adev->dev,
0111                         &chromeos_privacy_screen_ops,
0112                         &adev->dev);
0113 
0114     if (IS_ERR(drm_privacy_screen)) {
0115         dev_err(&adev->dev, "Error registering privacy-screen\n");
0116         return PTR_ERR(drm_privacy_screen);
0117     }
0118 
0119     adev->driver_data = drm_privacy_screen;
0120     dev_info(&adev->dev, "registered privacy-screen '%s'\n",
0121          dev_name(&drm_privacy_screen->dev));
0122 
0123     return 0;
0124 }
0125 
0126 static int chromeos_privacy_screen_remove(struct acpi_device *adev)
0127 {
0128     struct drm_privacy_screen *drm_privacy_screen = acpi_driver_data(adev);
0129 
0130     drm_privacy_screen_unregister(drm_privacy_screen);
0131     return 0;
0132 }
0133 
0134 static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = {
0135     {"GOOG0010", 0}, /* Google's electronic privacy screen for eDP-1 */
0136     {}
0137 };
0138 MODULE_DEVICE_TABLE(acpi, chromeos_privacy_screen_device_ids);
0139 
0140 static struct acpi_driver chromeos_privacy_screen_driver = {
0141     .name = "chromeos_privacy_screen_driver",
0142     .class = "ChromeOS",
0143     .ids = chromeos_privacy_screen_device_ids,
0144     .ops = {
0145         .add = chromeos_privacy_screen_add,
0146         .remove = chromeos_privacy_screen_remove,
0147     },
0148 };
0149 
0150 module_acpi_driver(chromeos_privacy_screen_driver);
0151 MODULE_LICENSE("GPL v2");
0152 MODULE_DESCRIPTION("ChromeOS ACPI Privacy Screen driver");
0153 MODULE_AUTHOR("Rajat Jain <rajatja@google.com>");