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