1 // SPDX-License-Identifier: GPL-2.0
3 * Lenovo WMI Camera Button Driver
5 * Author: Ai Chao <aichao@kylinos.cn>
6 * Copyright (C) 2024 KylinSoft Corporation.
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>
17 #define WMI_LENOVO_CAMERABUTTON_EVENT_GUID "50C76F1F-D8E4-D895-0A3D-62F4EA400013"
19 struct lenovo_wmi_priv
{
20 struct input_dev
*idev
;
21 struct mutex notify_lock
; /* lenovo WMI camera button notify lock */
29 static void lenovo_wmi_notify(struct wmi_device
*wdev
, union acpi_object
*obj
)
31 struct lenovo_wmi_priv
*priv
= dev_get_drvdata(&wdev
->dev
);
35 if (obj
->type
!= ACPI_TYPE_BUFFER
) {
36 dev_err(&wdev
->dev
, "Bad response type %u\n", obj
->type
);
40 if (obj
->buffer
.length
!= 1) {
41 dev_err(&wdev
->dev
, "Invalid buffer length %u\n", obj
->buffer
.length
);
46 * obj->buffer.pointer[0] is camera mode:
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
);
56 mutex_lock(&priv
->notify_lock
);
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
);
65 mutex_unlock(&priv
->notify_lock
);
68 static int lenovo_wmi_probe(struct wmi_device
*wdev
, const void *context
)
70 struct lenovo_wmi_priv
*priv
;
73 priv
= devm_kzalloc(&wdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
77 dev_set_drvdata(&wdev
->dev
, priv
);
79 priv
->idev
= devm_input_allocate_device(&wdev
->dev
);
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
);
90 ret
= input_register_device(priv
->idev
);
94 mutex_init(&priv
->notify_lock
);
99 static void lenovo_wmi_remove(struct wmi_device
*wdev
)
101 struct lenovo_wmi_priv
*priv
= dev_get_drvdata(&wdev
->dev
);
103 mutex_destroy(&priv
->notify_lock
);
106 static const struct wmi_device_id lenovo_wmi_id_table
[] = {
107 { .guid_string
= WMI_LENOVO_CAMERABUTTON_EVENT_GUID
},
110 MODULE_DEVICE_TABLE(wmi
, lenovo_wmi_id_table
);
112 static struct wmi_driver lenovo_wmi_driver
= {
114 .name
= "lenovo-wmi-camera",
115 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
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
,
123 module_wmi_driver(lenovo_wmi_driver
);
125 MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");
126 MODULE_DESCRIPTION("Lenovo WMI Camera Button Driver");
127 MODULE_LICENSE("GPL");