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 if (acpi_disabled) 37 return false; 38 39 /* Get embedded-controller handle */ 40 status = acpi_get_devices("PNP0C09", acpi_set_handle, NULL, &ec_handle); 41 if (ACPI_FAILURE(status) || !ec_handle) 42 return false; 43 44 /* And call the privacy-screen get-status method */ 45 status = acpi_evaluate_integer(ec_handle, "HKEY.GSSS", &args, &output); 46 if (ACPI_FAILURE(status)) 47 return false; 48 49 return (output & 0x10000) ? true : false; 50 } 51 #endif 52 53 static const struct arch_init_data arch_init_data[] __initconst = { 54 #if IS_ENABLED(CONFIG_THINKPAD_ACPI) 55 { 56 .lookup = { 57 .dev_id = NULL, 58 .con_id = NULL, 59 .provider = "privacy_screen-thinkpad_acpi", 60 }, 61 .detect = detect_thinkpad_privacy_screen, 62 }, 63 #endif 64 }; 65 66 void __init drm_privacy_screen_lookup_init(void) 67 { 68 int i; 69 70 for (i = 0; i < ARRAY_SIZE(arch_init_data); i++) { 71 if (!arch_init_data[i].detect()) 72 continue; 73 74 pr_info("Found '%s' privacy-screen provider\n", 75 arch_init_data[i].lookup.provider); 76 77 /* Make a copy because arch_init_data is __initconst */ 78 arch_lookup = arch_init_data[i].lookup; 79 drm_privacy_screen_lookup_add(&arch_lookup); 80 break; 81 } 82 } 83 84 void drm_privacy_screen_lookup_exit(void) 85 { 86 if (arch_lookup.provider) 87 drm_privacy_screen_lookup_remove(&arch_lookup); 88 } 89 #endif /* ifdef CONFIG_X86 */ 90