1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright (C) 2020 Red Hat, Inc. 4 * 5 * Authors: 6 * Hans de Goede <hdegoede@redhat.com> 7 */ 8 9 #include <linux/acpi.h> 10 #include <drm/drm_privacy_screen_machine.h> 11 12 #ifdef CONFIG_X86 13 static struct drm_privacy_screen_lookup arch_lookup; 14 15 struct arch_init_data { 16 struct drm_privacy_screen_lookup lookup; 17 bool (*detect)(void); 18 }; 19 20 #if IS_ENABLED(CONFIG_THINKPAD_ACPI) 21 static acpi_status __init acpi_set_handle(acpi_handle handle, u32 level, 22 void *context, void **return_value) 23 { 24 *(acpi_handle *)return_value = handle; 25 return AE_CTRL_TERMINATE; 26 } 27 28 static bool __init detect_thinkpad_privacy_screen(void) 29 { 30 union acpi_object obj = { .type = ACPI_TYPE_INTEGER }; 31 struct acpi_object_list args = { .count = 1, .pointer = &obj, }; 32 acpi_handle ec_handle = NULL; 33 unsigned long long output; 34 acpi_status status; 35 36 /* Get embedded-controller handle */ 37 status = acpi_get_devices("PNP0C09", acpi_set_handle, NULL, &ec_handle); 38 if (ACPI_FAILURE(status) || !ec_handle) 39 return false; 40 41 /* And call the privacy-screen get-status method */ 42 status = acpi_evaluate_integer(ec_handle, "HKEY.GSSS", &args, &output); 43 if (ACPI_FAILURE(status)) 44 return false; 45 46 return (output & 0x10000) ? true : false; 47 } 48 #endif 49 50 static const struct arch_init_data arch_init_data[] __initconst = { 51 #if IS_ENABLED(CONFIG_THINKPAD_ACPI) 52 { 53 .lookup = { 54 .dev_id = NULL, 55 .con_id = NULL, 56 .provider = "privacy_screen-thinkpad_acpi", 57 }, 58 .detect = detect_thinkpad_privacy_screen, 59 }, 60 #endif 61 }; 62 63 void __init drm_privacy_screen_lookup_init(void) 64 { 65 int i; 66 67 for (i = 0; i < ARRAY_SIZE(arch_init_data); i++) { 68 if (!arch_init_data[i].detect()) 69 continue; 70 71 pr_info("Found '%s' privacy-screen provider\n", 72 arch_init_data[i].lookup.provider); 73 74 /* Make a copy because arch_init_data is __initconst */ 75 arch_lookup = arch_init_data[i].lookup; 76 drm_privacy_screen_lookup_add(&arch_lookup); 77 break; 78 } 79 } 80 81 void drm_privacy_screen_lookup_exit(void) 82 { 83 if (arch_lookup.provider) 84 drm_privacy_screen_lookup_remove(&arch_lookup); 85 } 86 #endif /* ifdef CONFIG_X86 */ 87