brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · 0c0beda Raw
128 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Lenovo WMI Camera Button Driver4 *5 * Author: Ai Chao <aichao@kylinos.cn>6 * Copyright (C) 2024 KylinSoft Corporation.7 */8 9#include <linux/acpi.h>10#include <linux/device.h>11#include <linux/input.h>12#include <linux/types.h>13#include <linux/module.h>14#include <linux/mutex.h>15#include <linux/wmi.h>16 17#define WMI_LENOVO_CAMERABUTTON_EVENT_GUID "50C76F1F-D8E4-D895-0A3D-62F4EA400013"18 19struct lenovo_wmi_priv {20	struct input_dev *idev;21	struct mutex notify_lock;	/* lenovo WMI camera button notify lock */22};23 24enum {25	SW_CAMERA_OFF	= 0,26	SW_CAMERA_ON	= 1,27};28 29static void lenovo_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)30{31	struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev);32	unsigned int keycode;33	u8 camera_mode;34 35	if (obj->type != ACPI_TYPE_BUFFER) {36		dev_err(&wdev->dev, "Bad response type %u\n", obj->type);37		return;38	}39 40	if (obj->buffer.length != 1) {41		dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length);42		return;43	}44 45	/*46	 * obj->buffer.pointer[0] is camera mode:47	 *      0 camera close48	 *      1 camera open49	 */50	camera_mode = obj->buffer.pointer[0];51	if (camera_mode > SW_CAMERA_ON) {52		dev_err(&wdev->dev, "Unknown camera mode %u\n", camera_mode);53		return;54	}55 56	mutex_lock(&priv->notify_lock);57 58	keycode = camera_mode == SW_CAMERA_ON ?59		   KEY_CAMERA_ACCESS_ENABLE : KEY_CAMERA_ACCESS_DISABLE;60	input_report_key(priv->idev, keycode, 1);61	input_sync(priv->idev);62	input_report_key(priv->idev, keycode, 0);63	input_sync(priv->idev);64 65	mutex_unlock(&priv->notify_lock);66}67 68static int lenovo_wmi_probe(struct wmi_device *wdev, const void *context)69{70	struct lenovo_wmi_priv *priv;71	int ret;72 73	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);74	if (!priv)75		return -ENOMEM;76 77	dev_set_drvdata(&wdev->dev, priv);78 79	priv->idev = devm_input_allocate_device(&wdev->dev);80	if (!priv->idev)81		return -ENOMEM;82 83	priv->idev->name = "Lenovo WMI Camera Button";84	priv->idev->phys = "wmi/input0";85	priv->idev->id.bustype = BUS_HOST;86	priv->idev->dev.parent = &wdev->dev;87	input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_ENABLE);88	input_set_capability(priv->idev, EV_KEY, KEY_CAMERA_ACCESS_DISABLE);89 90	ret = input_register_device(priv->idev);91	if (ret)92		return ret;93 94	mutex_init(&priv->notify_lock);95 96	return 0;97}98 99static void lenovo_wmi_remove(struct wmi_device *wdev)100{101	struct lenovo_wmi_priv *priv = dev_get_drvdata(&wdev->dev);102 103	mutex_destroy(&priv->notify_lock);104}105 106static const struct wmi_device_id lenovo_wmi_id_table[] = {107	{ .guid_string = WMI_LENOVO_CAMERABUTTON_EVENT_GUID },108	{  }109};110MODULE_DEVICE_TABLE(wmi, lenovo_wmi_id_table);111 112static struct wmi_driver lenovo_wmi_driver = {113	.driver = {114		.name = "lenovo-wmi-camera",115		.probe_type = PROBE_PREFER_ASYNCHRONOUS,116	},117	.id_table = lenovo_wmi_id_table,118	.no_singleton = true,119	.probe = lenovo_wmi_probe,120	.notify = lenovo_wmi_notify,121	.remove = lenovo_wmi_remove,122};123module_wmi_driver(lenovo_wmi_driver);124 125MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");126MODULE_DESCRIPTION("Lenovo WMI Camera Button Driver");127MODULE_LICENSE("GPL");128