Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

platform/x86: dell-privacy: Add support for Dell hardware privacy

add support for Dell privacy driver for the Dell units equipped
hardware privacy design, which protect users privacy of audio and
camera from hardware level. Once the audio or camera privacy mode
activated, any applications will not get any audio or video stream
when user pressed ctrl+F4 hotkey, audio privacy mode will be
enabled, micmute led will be also changed accordingly
The micmute led is fully controlled by hardware & EC(embedded controller)
and camera mute hotkey is Ctrl+F9. Currently design only emits
SW_CAMERA_LENS_COVER event while the camera lens shutter will be
changed by EC & HW(hardware) control

*The flow is like this:
1) User presses key. HW does stuff with this key (timeout timer is started)
2) WMI event is emitted from BIOS to kernel
3) WMI event is received by dell-privacy
4) KEY_MICMUTE emitted from dell-privacy
5) Userland picks up key and modifies kcontrol for SW mute
6) Codec kernel driver catches and calls ledtrig_audio_set
7) dell-privacy notifies EC, the timeout is cancelled and the HW mute
is activated. If the EC is not notified then the HW mic mute will
activate when the timeout triggers, just a bit later than with the
active ack.

Signed-off-by: Perry Yuan <perry_yuan@dell.com>
Link: https://lore.kernel.org/r/20210506115605.1504-1-Perry_Yuan@Dell.com
[hdegoede@redhat.com: Rework Kconfig/Makefile bits + other small fixups]
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Perry Yuan and committed by
Hans de Goede
8af9fa37 8bf388a0

+522 -4
+55
Documentation/ABI/testing/sysfs-platform-dell-privacy-wmi
··· 1 + What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type 2 + Date: Apr 2021 3 + KernelVersion: 5.13 4 + Contact: "perry.yuan@dell.com>" 5 + Description: 6 + Display which dell hardware level privacy devices are supported 7 + “Dell Privacy” is a set of HW, FW, and SW features to enhance 8 + Dell’s commitment to platform privacy for MIC, Camera, and 9 + ePrivacy screens. 10 + The supported hardware privacy devices are: 11 + Attributes: 12 + Microphone Mute: 13 + Identifies the local microphone can be muted by hardware, no applications 14 + is available to capture system mic sound 15 + 16 + Camera Shutter: 17 + Identifies camera shutter controlled by hardware, which is a micromechanical 18 + shutter assembly that is built onto the camera module to block capturing images 19 + from outside the laptop 20 + 21 + supported: 22 + The privacy device is supported by this system 23 + 24 + unsupported: 25 + The privacy device is not supported on this system 26 + 27 + For example to check which privacy devices are supported: 28 + 29 + # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type 30 + [Microphone Mute] [supported] 31 + [Camera Shutter] [supported] 32 + [ePrivacy Screen] [unsupported] 33 + 34 + What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state 35 + Date: Apr 2021 36 + KernelVersion: 5.13 37 + Contact: "perry.yuan@dell.com>" 38 + Description: 39 + Allow user space to check current dell privacy device state. 40 + Describes the Device State class exposed by BIOS which can be 41 + consumed by various applications interested in knowing the Privacy 42 + feature capabilities 43 + Attributes: 44 + muted: 45 + Identifies the privacy device is turned off and cannot send stream to OS applications 46 + 47 + unmuted: 48 + Identifies the privacy device is turned on ,audio or camera driver can get 49 + stream from mic and camera module to OS applications 50 + 51 + For example to check all supported current privacy device states: 52 + 53 + # cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state 54 + [Microphone] [unmuted] 55 + [Camera Shutter] [unmuted]
+7
MAINTAINERS
··· 5172 5172 S: Maintained 5173 5173 F: drivers/platform/x86/dell/dell-wmi-base.c 5174 5174 5175 + DELL WMI HARDWARE PRIVACY SUPPORT 5176 + M: Perry Yuan <Perry.Yuan@dell.com> 5177 + L: Dell.Client.Kernel@dell.com 5178 + L: platform-driver-x86@vger.kernel.org 5179 + S: Maintained 5180 + F: drivers/platform/x86/dell/dell-wmi-privacy.c 5181 + 5175 5182 DELTA ST MEDIA DRIVER 5176 5183 M: Hugues Fruchet <hugues.fruchet@foss.st.com> 5177 5184 L: linux-media@vger.kernel.org
+9
drivers/platform/x86/dell/Kconfig
··· 53 53 depends on BACKLIGHT_CLASS_DEVICE 54 54 depends on ACPI_VIDEO || ACPI_VIDEO = n 55 55 depends on RFKILL || RFKILL = n 56 + depends on DELL_WMI || DELL_WMI = n 56 57 depends on SERIO_I8042 57 58 depends on DELL_SMBIOS 58 59 select POWER_SUPPLY ··· 164 163 165 164 To compile this driver as a module, choose M here: the module will 166 165 be called dell-wmi. 166 + 167 + config DELL_WMI_PRIVACY 168 + bool "Dell WMI Hardware Privacy Support" 169 + depends on DELL_WMI 170 + depends on LEDS_TRIGGER_AUDIO 171 + help 172 + This option adds integration with the "Dell Hardware Privacy" 173 + feature of Dell laptops to the dell-wmi driver. 167 174 168 175 config DELL_WMI_AIO 169 176 tristate "WMI Hotkeys for Dell All-In-One series"
+1
drivers/platform/x86/dell/Makefile
··· 16 16 obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 17 17 obj-$(CONFIG_DELL_WMI) += dell-wmi.o 18 18 dell-wmi-objs := dell-wmi-base.o 19 + dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o 19 20 obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 20 21 obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o 21 22 obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
+10 -3
drivers/platform/x86/dell/dell-laptop.c
··· 31 31 #include "dell-rbtn.h" 32 32 #include "dell-smbios.h" 33 33 34 + #include "dell-wmi-privacy.h" 35 + 34 36 struct quirk_entry { 35 37 bool touchpad_led; 36 38 bool kbd_led_not_present; ··· 92 90 static struct rfkill *bluetooth_rfkill; 93 91 static struct rfkill *wwan_rfkill; 94 92 static bool force_rfkill; 93 + static bool micmute_led_registered; 95 94 96 95 module_param(force_rfkill, bool, 0444); 97 96 MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models"); ··· 2208 2205 dell_laptop_register_notifier(&dell_laptop_notifier); 2209 2206 2210 2207 if (dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE) && 2211 - dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE)) { 2208 + dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE) && 2209 + !dell_privacy_has_mic_mute()) { 2212 2210 micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); 2213 2211 ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev); 2214 2212 if (ret < 0) 2215 2213 goto fail_led; 2214 + micmute_led_registered = true; 2216 2215 } 2217 2216 2218 2217 if (acpi_video_get_backlight_type() != acpi_backlight_vendor) ··· 2262 2257 fail_get_brightness: 2263 2258 backlight_device_unregister(dell_backlight_device); 2264 2259 fail_backlight: 2265 - led_classdev_unregister(&micmute_led_cdev); 2260 + if (micmute_led_registered) 2261 + led_classdev_unregister(&micmute_led_cdev); 2266 2262 fail_led: 2267 2263 dell_cleanup_rfkill(); 2268 2264 fail_rfkill: ··· 2284 2278 touchpad_led_exit(); 2285 2279 kbd_led_exit(); 2286 2280 backlight_device_unregister(dell_backlight_device); 2287 - led_classdev_unregister(&micmute_led_cdev); 2281 + if (micmute_led_registered) 2282 + led_classdev_unregister(&micmute_led_cdev); 2288 2283 dell_cleanup_rfkill(); 2289 2284 if (platform_device) { 2290 2285 platform_device_unregister(platform_device);
+13 -1
drivers/platform/x86/dell/dell-wmi-base.c
··· 27 27 #include <acpi/video.h> 28 28 #include "dell-smbios.h" 29 29 #include "dell-wmi-descriptor.h" 30 + #include "dell-wmi-privacy.h" 30 31 31 32 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 32 33 MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); ··· 428 427 429 428 switch (buffer_entry[1]) { 430 429 case 0x0000: /* One key pressed or event occurred */ 431 - case 0x0012: /* Event with extended data occurred */ 432 430 if (len > 2) 433 431 dell_wmi_process_key(wdev, buffer_entry[1], 434 432 buffer_entry[2]); ··· 438 438 for (i = 2; i < len; ++i) 439 439 dell_wmi_process_key(wdev, buffer_entry[1], 440 440 buffer_entry[i]); 441 + break; 442 + case 0x0012: 443 + if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3], 444 + buffer_entry[4])) 445 + /* dell_privacy_process_event has handled the event */; 446 + else if (len > 2) 447 + dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]); 441 448 break; 442 449 default: /* Unknown event */ 443 450 pr_info("Unknown WMI event type 0x%x\n", ··· 754 747 } 755 748 } 756 749 750 + err = dell_privacy_register_driver(); 751 + if (err) 752 + return err; 753 + 757 754 return wmi_driver_register(&dell_wmi_driver); 758 755 } 759 756 late_initcall(dell_wmi_init); ··· 768 757 dell_wmi_events_set_enabled(false); 769 758 770 759 wmi_driver_unregister(&dell_wmi_driver); 760 + dell_privacy_unregister_driver(); 771 761 } 772 762 module_exit(dell_wmi_exit); 773 763
+391
drivers/platform/x86/dell/dell-wmi-privacy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Dell privacy notification driver 4 + * 5 + * Copyright (C) 2021 Dell Inc. All Rights Reserved. 6 + */ 7 + 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 + 10 + #include <linux/acpi.h> 11 + #include <linux/bitops.h> 12 + #include <linux/input.h> 13 + #include <linux/input/sparse-keymap.h> 14 + #include <linux/list.h> 15 + #include <linux/leds.h> 16 + #include <linux/module.h> 17 + #include <linux/wmi.h> 18 + 19 + #include "dell-wmi-privacy.h" 20 + 21 + #define DELL_PRIVACY_GUID "6932965F-1671-4CEB-B988-D3AB0A901919" 22 + #define MICROPHONE_STATUS BIT(0) 23 + #define CAMERA_STATUS BIT(1) 24 + #define DELL_PRIVACY_AUDIO_EVENT 0x1 25 + #define DELL_PRIVACY_CAMERA_EVENT 0x2 26 + #define led_to_priv(c) container_of(c, struct privacy_wmi_data, cdev) 27 + 28 + /* 29 + * The wmi_list is used to store the privacy_priv struct with mutex protecting 30 + */ 31 + static LIST_HEAD(wmi_list); 32 + static DEFINE_MUTEX(list_mutex); 33 + 34 + struct privacy_wmi_data { 35 + struct input_dev *input_dev; 36 + struct wmi_device *wdev; 37 + struct list_head list; 38 + struct led_classdev cdev; 39 + u32 features_present; 40 + u32 last_status; 41 + }; 42 + 43 + /* DELL Privacy Type */ 44 + enum dell_hardware_privacy_type { 45 + DELL_PRIVACY_TYPE_AUDIO = 0, 46 + DELL_PRIVACY_TYPE_CAMERA, 47 + DELL_PRIVACY_TYPE_SCREEN, 48 + DELL_PRIVACY_TYPE_MAX, 49 + }; 50 + 51 + static const char * const privacy_types[DELL_PRIVACY_TYPE_MAX] = { 52 + [DELL_PRIVACY_TYPE_AUDIO] = "Microphone", 53 + [DELL_PRIVACY_TYPE_CAMERA] = "Camera Shutter", 54 + [DELL_PRIVACY_TYPE_SCREEN] = "ePrivacy Screen", 55 + }; 56 + 57 + /* 58 + * Keymap for WMI privacy events of type 0x0012 59 + */ 60 + static const struct key_entry dell_wmi_keymap_type_0012[] = { 61 + /* privacy mic mute */ 62 + { KE_KEY, 0x0001, { KEY_MICMUTE } }, 63 + /* privacy camera mute */ 64 + { KE_SW, 0x0002, { SW_CAMERA_LENS_COVER } }, 65 + { KE_END, 0}, 66 + }; 67 + 68 + bool dell_privacy_has_mic_mute(void) 69 + { 70 + struct privacy_wmi_data *priv; 71 + 72 + mutex_lock(&list_mutex); 73 + priv = list_first_entry_or_null(&wmi_list, 74 + struct privacy_wmi_data, 75 + list); 76 + mutex_unlock(&list_mutex); 77 + 78 + return priv && (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)); 79 + } 80 + EXPORT_SYMBOL_GPL(dell_privacy_has_mic_mute); 81 + 82 + /* 83 + * The flow of privacy event: 84 + * 1) User presses key. HW does stuff with this key (timeout is started) 85 + * 2) WMI event is emitted from BIOS 86 + * 3) WMI event is received by dell-privacy 87 + * 4) KEY_MICMUTE emitted from dell-privacy 88 + * 5) Userland picks up key and modifies kcontrol for SW mute 89 + * 6) Codec kernel driver catches and calls ledtrig_audio_set which will call 90 + * led_set_brightness() on the LED registered by dell_privacy_leds_setup() 91 + * 7) dell-privacy notifies EC, the timeout is cancelled and the HW mute activates. 92 + * If the EC is not notified then the HW mic mute will activate when the timeout 93 + * triggers, just a bit later than with the active ack. 94 + */ 95 + bool dell_privacy_process_event(int type, int code, int status) 96 + { 97 + struct privacy_wmi_data *priv; 98 + const struct key_entry *key; 99 + bool ret = false; 100 + 101 + mutex_lock(&list_mutex); 102 + priv = list_first_entry_or_null(&wmi_list, 103 + struct privacy_wmi_data, 104 + list); 105 + if (!priv) 106 + goto error; 107 + 108 + key = sparse_keymap_entry_from_scancode(priv->input_dev, (type << 16) | code); 109 + if (!key) { 110 + dev_warn(&priv->wdev->dev, "Unknown key with type 0x%04x and code 0x%04x pressed\n", 111 + type, code); 112 + goto error; 113 + } 114 + dev_dbg(&priv->wdev->dev, "Key with type 0x%04x and code 0x%04x pressed\n", type, code); 115 + 116 + switch (code) { 117 + case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */ 118 + case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */ 119 + priv->last_status = status; 120 + sparse_keymap_report_entry(priv->input_dev, key, 1, true); 121 + ret = true; 122 + break; 123 + default: 124 + dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code); 125 + } 126 + 127 + error: 128 + mutex_unlock(&list_mutex); 129 + return ret; 130 + } 131 + 132 + static ssize_t dell_privacy_supported_type_show(struct device *dev, 133 + struct device_attribute *attr, 134 + char *buf) 135 + { 136 + struct privacy_wmi_data *priv = dev_get_drvdata(dev); 137 + enum dell_hardware_privacy_type type; 138 + u32 privacy_list; 139 + int len = 0; 140 + 141 + privacy_list = priv->features_present; 142 + for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) { 143 + if (privacy_list & BIT(type)) 144 + len += sysfs_emit_at(buf, len, "[%s] [supported]\n", privacy_types[type]); 145 + else 146 + len += sysfs_emit_at(buf, len, "[%s] [unsupported]\n", privacy_types[type]); 147 + } 148 + 149 + return len; 150 + } 151 + 152 + static ssize_t dell_privacy_current_state_show(struct device *dev, 153 + struct device_attribute *attr, 154 + char *buf) 155 + { 156 + struct privacy_wmi_data *priv = dev_get_drvdata(dev); 157 + u32 privacy_supported = priv->features_present; 158 + enum dell_hardware_privacy_type type; 159 + u32 privacy_state = priv->last_status; 160 + int len = 0; 161 + 162 + for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) { 163 + if (privacy_supported & BIT(type)) { 164 + if (privacy_state & BIT(type)) 165 + len += sysfs_emit_at(buf, len, "[%s] [unmuted]\n", privacy_types[type]); 166 + else 167 + len += sysfs_emit_at(buf, len, "[%s] [muted]\n", privacy_types[type]); 168 + } 169 + } 170 + 171 + return len; 172 + } 173 + 174 + static DEVICE_ATTR_RO(dell_privacy_supported_type); 175 + static DEVICE_ATTR_RO(dell_privacy_current_state); 176 + 177 + static struct attribute *privacy_attributes[] = { 178 + &dev_attr_dell_privacy_supported_type.attr, 179 + &dev_attr_dell_privacy_current_state.attr, 180 + NULL, 181 + }; 182 + 183 + static const struct attribute_group privacy_attribute_group = { 184 + .attrs = privacy_attributes 185 + }; 186 + 187 + /* 188 + * Describes the Device State class exposed by BIOS which can be consumed by 189 + * various applications interested in knowing the Privacy feature capabilities. 190 + * class DeviceState 191 + * { 192 + * [key, read] string InstanceName; 193 + * [read] boolean ReadOnly; 194 + * 195 + * [WmiDataId(1), read] uint32 DevicesSupported; 196 + * 0 - None; 0x1 - Microphone; 0x2 - Camera; 0x4 - ePrivacy Screen 197 + * 198 + * [WmiDataId(2), read] uint32 CurrentState; 199 + * 0 - Off; 1 - On; Bit0 - Microphone; Bit1 - Camera; Bit2 - ePrivacyScreen 200 + * }; 201 + */ 202 + static int get_current_status(struct wmi_device *wdev) 203 + { 204 + struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev); 205 + union acpi_object *obj_present; 206 + u32 *buffer; 207 + int ret = 0; 208 + 209 + if (!priv) { 210 + dev_err(&wdev->dev, "dell privacy priv is NULL\n"); 211 + return -EINVAL; 212 + } 213 + /* check privacy support features and device states */ 214 + obj_present = wmidev_block_query(wdev, 0); 215 + if (!obj_present) { 216 + dev_err(&wdev->dev, "failed to read Binary MOF\n"); 217 + return -EIO; 218 + } 219 + 220 + if (obj_present->type != ACPI_TYPE_BUFFER) { 221 + dev_err(&wdev->dev, "Binary MOF is not a buffer!\n"); 222 + ret = -EIO; 223 + goto obj_free; 224 + } 225 + /* Although it's not technically a failure, this would lead to 226 + * unexpected behavior 227 + */ 228 + if (obj_present->buffer.length != 8) { 229 + dev_err(&wdev->dev, "Dell privacy buffer has unexpected length (%d)!\n", 230 + obj_present->buffer.length); 231 + ret = -EINVAL; 232 + goto obj_free; 233 + } 234 + buffer = (u32 *)obj_present->buffer.pointer; 235 + priv->features_present = buffer[0]; 236 + priv->last_status = buffer[1]; 237 + 238 + obj_free: 239 + kfree(obj_present); 240 + return ret; 241 + } 242 + 243 + static int dell_privacy_micmute_led_set(struct led_classdev *led_cdev, 244 + enum led_brightness brightness) 245 + { 246 + struct privacy_wmi_data *priv = led_to_priv(led_cdev); 247 + static char *acpi_method = (char *)"ECAK"; 248 + acpi_status status; 249 + acpi_handle handle; 250 + 251 + handle = ec_get_handle(); 252 + if (!handle) 253 + return -EIO; 254 + 255 + if (!acpi_has_method(handle, acpi_method)) 256 + return -EIO; 257 + 258 + status = acpi_evaluate_object(handle, acpi_method, NULL, NULL); 259 + if (ACPI_FAILURE(status)) { 260 + dev_err(&priv->wdev->dev, "Error setting privacy EC ack value: %s\n", 261 + acpi_format_exception(status)); 262 + return -EIO; 263 + } 264 + 265 + return 0; 266 + } 267 + 268 + /* 269 + * Pressing the mute key activates a time delayed circuit to physically cut 270 + * off the mute. The LED is in the same circuit, so it reflects the true 271 + * state of the HW mute. The reason for the EC "ack" is so that software 272 + * can first invoke a SW mute before the HW circuit is cut off. Without SW 273 + * cutting this off first does not affect the time delayed muting or status 274 + * of the LED but there is a possibility of a "popping" noise. 275 + * 276 + * If the EC receives the SW ack, the circuit will be activated before the 277 + * delay completed. 278 + * 279 + * Exposing as an LED device allows the codec drivers notification path to 280 + * EC ACK to work 281 + */ 282 + static int dell_privacy_leds_setup(struct device *dev) 283 + { 284 + struct privacy_wmi_data *priv = dev_get_drvdata(dev); 285 + 286 + priv->cdev.name = "dell-privacy::micmute"; 287 + priv->cdev.max_brightness = 1; 288 + priv->cdev.brightness_set_blocking = dell_privacy_micmute_led_set; 289 + priv->cdev.default_trigger = "audio-micmute"; 290 + priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); 291 + return devm_led_classdev_register(dev, &priv->cdev); 292 + } 293 + 294 + static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context) 295 + { 296 + struct privacy_wmi_data *priv; 297 + struct key_entry *keymap; 298 + int ret, i; 299 + 300 + ret = wmi_has_guid(DELL_PRIVACY_GUID); 301 + if (!ret) 302 + pr_debug("Unable to detect available Dell privacy devices!\n"); 303 + 304 + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); 305 + if (!priv) 306 + return -ENOMEM; 307 + 308 + dev_set_drvdata(&wdev->dev, priv); 309 + priv->wdev = wdev; 310 + /* create evdev passing interface */ 311 + priv->input_dev = devm_input_allocate_device(&wdev->dev); 312 + if (!priv->input_dev) 313 + return -ENOMEM; 314 + 315 + /* remap the wmi keymap event to new keymap */ 316 + keymap = kcalloc(ARRAY_SIZE(dell_wmi_keymap_type_0012), 317 + sizeof(struct key_entry), GFP_KERNEL); 318 + if (!keymap) 319 + return -ENOMEM; 320 + 321 + /* remap the keymap code with Dell privacy key type 0x12 as prefix 322 + * KEY_MICMUTE scancode will be reported as 0x120001 323 + */ 324 + for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) { 325 + keymap[i] = dell_wmi_keymap_type_0012[i]; 326 + keymap[i].code |= (0x0012 << 16); 327 + } 328 + ret = sparse_keymap_setup(priv->input_dev, keymap, NULL); 329 + kfree(keymap); 330 + if (ret) 331 + return ret; 332 + 333 + priv->input_dev->dev.parent = &wdev->dev; 334 + priv->input_dev->name = "Dell Privacy Driver"; 335 + priv->input_dev->id.bustype = BUS_HOST; 336 + 337 + ret = input_register_device(priv->input_dev); 338 + if (ret) 339 + return ret; 340 + 341 + ret = get_current_status(priv->wdev); 342 + if (ret) 343 + return ret; 344 + 345 + ret = devm_device_add_group(&wdev->dev, &privacy_attribute_group); 346 + if (ret) 347 + return ret; 348 + 349 + if (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)) { 350 + ret = dell_privacy_leds_setup(&priv->wdev->dev); 351 + if (ret) 352 + return ret; 353 + } 354 + mutex_lock(&list_mutex); 355 + list_add_tail(&priv->list, &wmi_list); 356 + mutex_unlock(&list_mutex); 357 + return 0; 358 + } 359 + 360 + static void dell_privacy_wmi_remove(struct wmi_device *wdev) 361 + { 362 + struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev); 363 + 364 + mutex_lock(&list_mutex); 365 + list_del(&priv->list); 366 + mutex_unlock(&list_mutex); 367 + } 368 + 369 + static const struct wmi_device_id dell_wmi_privacy_wmi_id_table[] = { 370 + { .guid_string = DELL_PRIVACY_GUID }, 371 + { }, 372 + }; 373 + 374 + static struct wmi_driver dell_privacy_wmi_driver = { 375 + .driver = { 376 + .name = "dell-privacy", 377 + }, 378 + .probe = dell_privacy_wmi_probe, 379 + .remove = dell_privacy_wmi_remove, 380 + .id_table = dell_wmi_privacy_wmi_id_table, 381 + }; 382 + 383 + int dell_privacy_register_driver(void) 384 + { 385 + return wmi_driver_register(&dell_privacy_wmi_driver); 386 + } 387 + 388 + void dell_privacy_unregister_driver(void) 389 + { 390 + wmi_driver_unregister(&dell_privacy_wmi_driver); 391 + }
+36
drivers/platform/x86/dell/dell-wmi-privacy.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Dell privacy notification driver 4 + * 5 + * Copyright (C) 2021 Dell Inc. All Rights Reserved. 6 + */ 7 + 8 + #ifndef _DELL_PRIVACY_WMI_H_ 9 + #define _DELL_PRIVACY_WMI_H_ 10 + 11 + #if IS_ENABLED(CONFIG_DELL_WMI_PRIVACY) 12 + bool dell_privacy_has_mic_mute(void); 13 + bool dell_privacy_process_event(int type, int code, int status); 14 + int dell_privacy_register_driver(void); 15 + void dell_privacy_unregister_driver(void); 16 + #else /* CONFIG_DELL_PRIVACY */ 17 + static inline bool dell_privacy_has_mic_mute(void) 18 + { 19 + return false; 20 + } 21 + 22 + static inline bool dell_privacy_process_event(int type, int code, int status) 23 + { 24 + return false; 25 + } 26 + 27 + static inline int dell_privacy_register_driver(void) 28 + { 29 + return 0; 30 + } 31 + 32 + static inline void dell_privacy_unregister_driver(void) 33 + { 34 + } 35 + #endif /* CONFIG_DELL_PRIVACY */ 36 + #endif