402 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Dell privacy notification driver4 *5 * Copyright (C) 2021 Dell Inc. All Rights Reserved.6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 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 0x125#define DELL_PRIVACY_CAMERA_EVENT 0x226#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 protecting30 */31static LIST_HEAD(wmi_list);32static DEFINE_MUTEX(list_mutex);33 34struct 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 */44enum 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 51static 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 0x001259 */60static 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_VSW, 0x0002, { SW_CAMERA_LENS_COVER } },65 { KE_END, 0},66};67 68bool 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}80EXPORT_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 BIOS86 * 3) WMI event is received by dell-privacy87 * 4) KEY_MICMUTE emitted from dell-privacy88 * 5) Userland picks up key and modifies kcontrol for SW mute89 * 6) Codec kernel driver catches and calls ledtrig_audio_set which will call90 * 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 timeout93 * triggers, just a bit later than with the active ack.94 */95bool 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 priv->last_status = status;119 sparse_keymap_report_entry(priv->input_dev, key, 1, true);120 ret = true;121 break;122 case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */123 priv->last_status = status;124 sparse_keymap_report_entry(priv->input_dev, key, !(status & CAMERA_STATUS), false);125 ret = true;126 break;127 default:128 dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code);129 }130 131error:132 mutex_unlock(&list_mutex);133 return ret;134}135 136static ssize_t dell_privacy_supported_type_show(struct device *dev,137 struct device_attribute *attr,138 char *buf)139{140 struct privacy_wmi_data *priv = dev_get_drvdata(dev);141 enum dell_hardware_privacy_type type;142 u32 privacy_list;143 int len = 0;144 145 privacy_list = priv->features_present;146 for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) {147 if (privacy_list & BIT(type))148 len += sysfs_emit_at(buf, len, "[%s] [supported]\n", privacy_types[type]);149 else150 len += sysfs_emit_at(buf, len, "[%s] [unsupported]\n", privacy_types[type]);151 }152 153 return len;154}155 156static ssize_t dell_privacy_current_state_show(struct device *dev,157 struct device_attribute *attr,158 char *buf)159{160 struct privacy_wmi_data *priv = dev_get_drvdata(dev);161 u32 privacy_supported = priv->features_present;162 enum dell_hardware_privacy_type type;163 u32 privacy_state = priv->last_status;164 int len = 0;165 166 for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) {167 if (privacy_supported & BIT(type)) {168 if (privacy_state & BIT(type))169 len += sysfs_emit_at(buf, len, "[%s] [unmuted]\n", privacy_types[type]);170 else171 len += sysfs_emit_at(buf, len, "[%s] [muted]\n", privacy_types[type]);172 }173 }174 175 return len;176}177 178static DEVICE_ATTR_RO(dell_privacy_supported_type);179static DEVICE_ATTR_RO(dell_privacy_current_state);180 181static struct attribute *privacy_attrs[] = {182 &dev_attr_dell_privacy_supported_type.attr,183 &dev_attr_dell_privacy_current_state.attr,184 NULL,185};186ATTRIBUTE_GROUPS(privacy);187 188/*189 * Describes the Device State class exposed by BIOS which can be consumed by190 * various applications interested in knowing the Privacy feature capabilities.191 * class DeviceState192 * {193 * [key, read] string InstanceName;194 * [read] boolean ReadOnly;195 *196 * [WmiDataId(1), read] uint32 DevicesSupported;197 * 0 - None; 0x1 - Microphone; 0x2 - Camera; 0x4 - ePrivacy Screen198 *199 * [WmiDataId(2), read] uint32 CurrentState;200 * 0 - Off; 1 - On; Bit0 - Microphone; Bit1 - Camera; Bit2 - ePrivacyScreen201 * };202 */203static int get_current_status(struct wmi_device *wdev)204{205 struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev);206 union acpi_object *obj_present;207 u32 *buffer;208 int ret = 0;209 210 if (!priv) {211 dev_err(&wdev->dev, "dell privacy priv is NULL\n");212 return -EINVAL;213 }214 /* check privacy support features and device states */215 obj_present = wmidev_block_query(wdev, 0);216 if (!obj_present) {217 dev_err(&wdev->dev, "failed to read Binary MOF\n");218 return -EIO;219 }220 221 if (obj_present->type != ACPI_TYPE_BUFFER) {222 dev_err(&wdev->dev, "Binary MOF is not a buffer!\n");223 ret = -EIO;224 goto obj_free;225 }226 /* Although it's not technically a failure, this would lead to227 * unexpected behavior228 */229 if (obj_present->buffer.length != 8) {230 dev_err(&wdev->dev, "Dell privacy buffer has unexpected length (%d)!\n",231 obj_present->buffer.length);232 ret = -EINVAL;233 goto obj_free;234 }235 buffer = (u32 *)obj_present->buffer.pointer;236 priv->features_present = buffer[0];237 priv->last_status = buffer[1];238 239obj_free:240 kfree(obj_present);241 return ret;242}243 244static int dell_privacy_micmute_led_set(struct led_classdev *led_cdev,245 enum led_brightness brightness)246{247 struct privacy_wmi_data *priv = led_to_priv(led_cdev);248 static char *acpi_method = (char *)"ECAK";249 acpi_status status;250 acpi_handle handle;251 252 handle = ec_get_handle();253 if (!handle)254 return -EIO;255 256 if (!acpi_has_method(handle, acpi_method))257 return -EIO;258 259 status = acpi_evaluate_object(handle, acpi_method, NULL, NULL);260 if (ACPI_FAILURE(status)) {261 dev_err(&priv->wdev->dev, "Error setting privacy EC ack value: %s\n",262 acpi_format_exception(status));263 return -EIO;264 }265 266 return 0;267}268 269/*270 * Pressing the mute key activates a time delayed circuit to physically cut271 * off the mute. The LED is in the same circuit, so it reflects the true272 * state of the HW mute. The reason for the EC "ack" is so that software273 * can first invoke a SW mute before the HW circuit is cut off. Without SW274 * cutting this off first does not affect the time delayed muting or status275 * of the LED but there is a possibility of a "popping" noise.276 *277 * If the EC receives the SW ack, the circuit will be activated before the278 * delay completed.279 *280 * Exposing as an LED device allows the codec drivers notification path to281 * EC ACK to work282 */283static int dell_privacy_leds_setup(struct device *dev)284{285 struct privacy_wmi_data *priv = dev_get_drvdata(dev);286 287 priv->cdev.name = "dell-privacy::micmute";288 priv->cdev.max_brightness = 1;289 priv->cdev.brightness_set_blocking = dell_privacy_micmute_led_set;290 priv->cdev.default_trigger = "audio-micmute";291 return devm_led_classdev_register(dev, &priv->cdev);292}293 294static 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, j;299 300 priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);301 if (!priv)302 return -ENOMEM;303 304 dev_set_drvdata(&wdev->dev, priv);305 priv->wdev = wdev;306 307 ret = get_current_status(priv->wdev);308 if (ret)309 return ret;310 311 /* create evdev passing interface */312 priv->input_dev = devm_input_allocate_device(&wdev->dev);313 if (!priv->input_dev)314 return -ENOMEM;315 316 /* remap the wmi keymap event to new keymap */317 keymap = kcalloc(ARRAY_SIZE(dell_wmi_keymap_type_0012),318 sizeof(struct key_entry), GFP_KERNEL);319 if (!keymap)320 return -ENOMEM;321 322 /* remap the keymap code with Dell privacy key type 0x12 as prefix323 * KEY_MICMUTE scancode will be reported as 0x120001324 */325 for (i = 0, j = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {326 /*327 * Unlike keys where only presses matter, userspace may act328 * on switches in both of their positions. Only register329 * SW_CAMERA_LENS_COVER if it is actually there.330 */331 if (dell_wmi_keymap_type_0012[i].type == KE_VSW &&332 dell_wmi_keymap_type_0012[i].sw.code == SW_CAMERA_LENS_COVER &&333 !(priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA)))334 continue;335 336 keymap[j] = dell_wmi_keymap_type_0012[i];337 keymap[j].code |= (0x0012 << 16);338 j++;339 }340 ret = sparse_keymap_setup(priv->input_dev, keymap, NULL);341 kfree(keymap);342 if (ret)343 return ret;344 345 priv->input_dev->dev.parent = &wdev->dev;346 priv->input_dev->name = "Dell Privacy Driver";347 priv->input_dev->id.bustype = BUS_HOST;348 349 /* Report initial camera-cover status */350 if (priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA))351 input_report_switch(priv->input_dev, SW_CAMERA_LENS_COVER,352 !(priv->last_status & CAMERA_STATUS));353 354 ret = input_register_device(priv->input_dev);355 if (ret)356 return ret;357 358 if (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)) {359 ret = dell_privacy_leds_setup(&priv->wdev->dev);360 if (ret)361 return ret;362 }363 mutex_lock(&list_mutex);364 list_add_tail(&priv->list, &wmi_list);365 mutex_unlock(&list_mutex);366 return 0;367}368 369static void dell_privacy_wmi_remove(struct wmi_device *wdev)370{371 struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev);372 373 mutex_lock(&list_mutex);374 list_del(&priv->list);375 mutex_unlock(&list_mutex);376}377 378static const struct wmi_device_id dell_wmi_privacy_wmi_id_table[] = {379 { .guid_string = DELL_PRIVACY_GUID },380 { },381};382 383static struct wmi_driver dell_privacy_wmi_driver = {384 .driver = {385 .name = "dell-privacy",386 .dev_groups = privacy_groups,387 },388 .probe = dell_privacy_wmi_probe,389 .remove = dell_privacy_wmi_remove,390 .id_table = dell_wmi_privacy_wmi_id_table,391};392 393int dell_privacy_register_driver(void)394{395 return wmi_driver_register(&dell_privacy_wmi_driver);396}397 398void dell_privacy_unregister_driver(void)399{400 wmi_driver_unregister(&dell_privacy_wmi_driver);401}402