brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · 4b65e16 Raw
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