diff options
Diffstat (limited to 'drivers/platform/x86')
50 files changed, 2988 insertions, 276 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 60592fb88e7a..7d385c3b2239 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -415,16 +415,17 @@ config HP_ACCEL To compile this driver as a module, choose M here: the module will be called hp_accel. -config HP_WIRELESS - tristate "HP wireless button" +config WIRELESS_HOTKEY + tristate "Wireless hotkey button" depends on ACPI depends on INPUT help - This driver provides supports for new HP wireless button for Windows 8. + This driver provides supports for the wireless buttons found on some AMD, + HP, & Xioami laptops. On such systems the driver should load automatically (via ACPI alias). To compile this driver as a module, choose M here: the module will - be called hp-wireless. + be called wireless-hotkey. config HP_WMI tristate "HP WMI extras" @@ -639,6 +640,19 @@ config THINKPAD_ACPI_HOTKEY_POLL If you are not sure, say Y here. The driver enables polling only if it is strictly necessary to do so. +config THINKPAD_LMI + tristate "Lenovo WMI-based systems management driver" + depends on ACPI_WMI + select FW_ATTR_CLASS + help + This driver allows changing BIOS settings on Lenovo machines whose + BIOS support the WMI interface. + + To compile this driver as a module, choose M here: the module will + be called think-lmi. + +source "drivers/platform/x86/intel/Kconfig" + config INTEL_ATOMISP2_LED tristate "Intel AtomISP2 camera LED driver" depends on GPIOLIB && LEDS_GPIO @@ -673,30 +687,6 @@ config INTEL_ATOMISP2_PM To compile this driver as a module, choose M here: the module will be called intel_atomisp2_pm. -config INTEL_CHT_INT33FE - tristate "Intel Cherry Trail ACPI INT33FE Driver" - depends on X86 && ACPI && I2C && REGULATOR - depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) - depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) - depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) - help - This driver add support for the INT33FE ACPI device found on - some Intel Cherry Trail devices. - - There are two kinds of INT33FE ACPI device possible: for hardware - with USB Type-C and Micro-B connectors. This driver supports both. - - The INT33FE ACPI device has a CRS table with I2cSerialBusV2 - resources for Fuel Gauge Controller and (in the Type-C variant) - FUSB302 USB Type-C Controller and PI3USB30532 USB switch. - This driver instantiates i2c-clients for these, so that standard - i2c drivers for these chips can bind to the them. - - If you enable this driver it is advised to also select - CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B - device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m - for Type-C device. - config INTEL_HID_EVENT tristate "INTEL HID Event" depends on ACPI @@ -1076,6 +1066,9 @@ config TOUCHSCREEN_DMI the OS-image for the device. This option supplies the missing info. Enable this for x86 tablets with Silead or Chipone touchscreens. +config FW_ATTR_CLASS + tristate + config INTEL_IMR bool "Intel Isolated Memory Region support" depends on X86_INTEL_QUARK && IOSF_MBI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index dcc8cdb95b4d..7ee369aab10d 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -52,7 +52,6 @@ obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o # Hewlett Packard obj-$(CONFIG_HP_ACCEL) += hp_accel.o -obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o @@ -64,14 +63,13 @@ obj-$(CONFIG_IBM_RTL) += ibm_rtl.o obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o +obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o # Intel +obj-$(CONFIG_X86_PLATFORM_DRIVERS_INTEL) += intel/ + obj-$(CONFIG_INTEL_ATOMISP2_LED) += intel_atomisp2_led.o obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o -obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o -intel_cht_int33fe-objs := intel_cht_int33fe_common.o \ - intel_cht_int33fe_typec.o \ - intel_cht_int33fe_microb.o obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o @@ -112,9 +110,11 @@ obj-$(CONFIG_SYSTEM76_ACPI) += system76_acpi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o # Platform drivers +obj-$(CONFIG_FW_ATTR_CLASS) += firmware_attributes_class.o obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o +obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o # Intel uncore drivers obj-$(CONFIG_INTEL_IPS) += intel_ips.o diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index d41d7ad14be0..0cb927f0f301 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -110,11 +110,6 @@ static struct quirk_entry quirk_asus_forceals = { .wmi_force_als_set = true, }; -static struct quirk_entry quirk_asus_vendor_backlight = { - .wmi_backlight_power = true, - .wmi_backlight_set_devstate = true, -}; - static struct quirk_entry quirk_asus_use_kbd_dock_devid = { .use_kbd_dock_devid = true, }; @@ -427,78 +422,6 @@ static const struct dmi_system_id asus_quirks[] = { }, { .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA401IH", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401IH"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA401II", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401II"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA401IU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401IU"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA401IV", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401IV"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA401IVC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA401IVC"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA502II", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA502II"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA502IU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA502IU"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, - .ident = "ASUSTeK COMPUTER INC. GA502IV", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA502IV"), - }, - .driver_data = &quirk_asus_vendor_backlight, - }, - { - .callback = dmi_matched, .ident = "Asus Transformer T100TA / T100HA / T100CHI", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index e0a55337f51a..9e7314d90bea 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -5,7 +5,6 @@ menuconfig X86_PLATFORM_DRIVERS_DELL bool "Dell X86 Platform Specific Device Drivers" - default n depends on X86_PLATFORM_DEVICES help Say Y here to get to see options for device drivers for various @@ -53,6 +52,7 @@ config DELL_LAPTOP depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n + depends on DELL_WMI || DELL_WMI = n depends on SERIO_I8042 depends on DELL_SMBIOS select POWER_SUPPLY @@ -164,6 +164,14 @@ config DELL_WMI To compile this driver as a module, choose M here: the module will be called dell-wmi. +config DELL_WMI_PRIVACY + bool "Dell WMI Hardware Privacy Support" + depends on DELL_WMI + depends on LEDS_TRIGGER_AUDIO + help + This option adds integration with the "Dell Hardware Privacy" + feature of Dell laptops to the dell-wmi driver. + config DELL_WMI_AIO tristate "WMI Hotkeys for Dell All-In-One series" default m @@ -197,6 +205,7 @@ config DELL_WMI_SYSMAN depends on ACPI_WMI depends on DMI select NLS + select FW_ATTR_CLASS help This driver allows changing BIOS settings on many Dell machines from 2018 and newer without the use of any additional software. diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile index d720a3e42ae3..ddba1df71e80 100644 --- a/drivers/platform/x86/dell/Makefile +++ b/drivers/platform/x86/dell/Makefile @@ -15,6 +15,8 @@ dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o +dell-wmi-objs := dell-wmi-base.o +dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c index d513a59a5d47..28447c180be8 100644 --- a/drivers/platform/x86/dell/dcdbas.c +++ b/drivers/platform/x86/dell/dcdbas.c @@ -394,8 +394,7 @@ static int host_control_smi(void) /* wait a few to see if it executed */ num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING; - while ((cmd_status = inb(PCAT_APM_STATUS_PORT)) - == ESM_STATUS_CMD_UNSUCCESSFUL) { + while ((s8)inb(PCAT_APM_STATUS_PORT) == ESM_STATUS_CMD_UNSUCCESSFUL) { num_ticks--; if (num_ticks == EXPIRED_TIMER) return -ETIME; diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c index 70edc5bb3a14..8230e7a68a5e 100644 --- a/drivers/platform/x86/dell/dell-laptop.c +++ b/drivers/platform/x86/dell/dell-laptop.c @@ -31,6 +31,8 @@ #include "dell-rbtn.h" #include "dell-smbios.h" +#include "dell-wmi-privacy.h" + struct quirk_entry { bool touchpad_led; bool kbd_led_not_present; @@ -90,6 +92,7 @@ static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *wwan_rfkill; static bool force_rfkill; +static bool micmute_led_registered; module_param(force_rfkill, bool, 0444); MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models"); @@ -2205,11 +2208,13 @@ static int __init dell_init(void) dell_laptop_register_notifier(&dell_laptop_notifier); if (dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE) && - dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE)) { + dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE) && + !dell_privacy_has_mic_mute()) { micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev); if (ret < 0) goto fail_led; + micmute_led_registered = true; } if (acpi_video_get_backlight_type() != acpi_backlight_vendor) @@ -2257,7 +2262,8 @@ static int __init dell_init(void) fail_get_brightness: backlight_device_unregister(dell_backlight_device); fail_backlight: - led_classdev_unregister(&micmute_led_cdev); + if (micmute_led_registered) + led_classdev_unregister(&micmute_led_cdev); fail_led: dell_cleanup_rfkill(); fail_rfkill: @@ -2278,7 +2284,8 @@ static void __exit dell_exit(void) touchpad_led_exit(); kbd_led_exit(); backlight_device_unregister(dell_backlight_device); - led_classdev_unregister(&micmute_led_cdev); + if (micmute_led_registered) + led_classdev_unregister(&micmute_led_cdev); dell_cleanup_rfkill(); if (platform_device) { platform_device_unregister(platform_device); diff --git a/drivers/platform/x86/dell/dell-wmi.c b/drivers/platform/x86/dell/dell-wmi-base.c index 5e1b7f897df5..089c125e18f7 100644 --- a/drivers/platform/x86/dell/dell-wmi.c +++ b/drivers/platform/x86/dell/dell-wmi-base.c @@ -27,6 +27,7 @@ #include <acpi/video.h> #include "dell-smbios.h" #include "dell-wmi-descriptor.h" +#include "dell-wmi-privacy.h" MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); MODULE_AUTHOR("Pali Rohár <pali@kernel.org>"); @@ -427,7 +428,6 @@ static void dell_wmi_notify(struct wmi_device *wdev, switch (buffer_entry[1]) { case 0x0000: /* One key pressed or event occurred */ - case 0x0012: /* Event with extended data occurred */ if (len > 2) dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]); @@ -439,6 +439,13 @@ static void dell_wmi_notify(struct wmi_device *wdev, dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[i]); break; + case 0x0012: + if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3], + buffer_entry[4])) + /* dell_privacy_process_event has handled the event */; + else if (len > 2) + dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]); + break; default: /* Unknown event */ pr_info("Unknown WMI event type 0x%x\n", (int)buffer_entry[1]); @@ -747,6 +754,10 @@ static int __init dell_wmi_init(void) } } + err = dell_privacy_register_driver(); + if (err) + return err; + return wmi_driver_register(&dell_wmi_driver); } late_initcall(dell_wmi_init); @@ -757,6 +768,7 @@ static void __exit dell_wmi_exit(void) dell_wmi_events_set_enabled(false); wmi_driver_unregister(&dell_wmi_driver); + dell_privacy_unregister_driver(); } module_exit(dell_wmi_exit); diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c new file mode 100644 index 000000000000..074b7e68c227 --- /dev/null +++ b/drivers/platform/x86/dell/dell-wmi-privacy.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Dell privacy notification driver + * + * Copyright (C) 2021 Dell Inc. All Rights Reserved. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/bitops.h> +#include <linux/input.h> +#include <linux/input/sparse-keymap.h> +#include <linux/list.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/wmi.h> + +#include "dell-wmi-privacy.h" + +#define DELL_PRIVACY_GUID "6932965F-1671-4CEB-B988-D3AB0A901919" +#define MICROPHONE_STATUS BIT(0) +#define CAMERA_STATUS BIT(1) +#define DELL_PRIVACY_AUDIO_EVENT 0x1 +#define DELL_PRIVACY_CAMERA_EVENT 0x2 +#define led_to_priv(c) container_of(c, struct privacy_wmi_data, cdev) + +/* + * The wmi_list is used to store the privacy_priv struct with mutex protecting + */ +static LIST_HEAD(wmi_list); +static DEFINE_MUTEX(list_mutex); + +struct privacy_wmi_data { + struct input_dev *input_dev; + struct wmi_device *wdev; + struct list_head list; + struct led_classdev cdev; + u32 features_present; + u32 last_status; +}; + +/* DELL Privacy Type */ +enum dell_hardware_privacy_type { + DELL_PRIVACY_TYPE_AUDIO = 0, + DELL_PRIVACY_TYPE_CAMERA, + DELL_PRIVACY_TYPE_SCREEN, + DELL_PRIVACY_TYPE_MAX, +}; + +static const char * const privacy_types[DELL_PRIVACY_TYPE_MAX] = { + [DELL_PRIVACY_TYPE_AUDIO] = "Microphone", + [DELL_PRIVACY_TYPE_CAMERA] = "Camera Shutter", + [DELL_PRIVACY_TYPE_SCREEN] = "ePrivacy Screen", +}; + +/* + * Keymap for WMI privacy events of type 0x0012 + */ +static const struct key_entry dell_wmi_keymap_type_0012[] = { + /* privacy mic mute */ + { KE_KEY, 0x0001, { KEY_MICMUTE } }, + /* privacy camera mute */ + { KE_SW, 0x0002, { SW_CAMERA_LENS_COVER } }, + { KE_END, 0}, +}; + +bool dell_privacy_has_mic_mute(void) +{ + struct privacy_wmi_data *priv; + + mutex_lock(&list_mutex); + priv = list_first_entry_or_null(&wmi_list, + struct privacy_wmi_data, + list); + mutex_unlock(&list_mutex); + + return priv && (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)); +} +EXPORT_SYMBOL_GPL(dell_privacy_has_mic_mute); + +/* + * The flow of privacy event: + * 1) User presses key. HW does stuff with this key (timeout is started) + * 2) WMI event is emitted from BIOS + * 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 which will call + * led_set_brightness() on the LED registered by dell_privacy_leds_setup() + * 7) dell-privacy notifies EC, the timeout is cancelled and the HW mute activates. + * 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. + */ +bool dell_privacy_process_event(int type, int code, int status) +{ + struct privacy_wmi_data *priv; + const struct key_entry *key; + bool ret = false; + + mutex_lock(&list_mutex); + priv = list_first_entry_or_null(&wmi_list, + struct privacy_wmi_data, + list); + if (!priv) + goto error; + + key = sparse_keymap_entry_from_scancode(priv->input_dev, (type << 16) | code); + if (!key) { + dev_warn(&priv->wdev->dev, "Unknown key with type 0x%04x and code 0x%04x pressed\n", + type, code); + goto error; + } + dev_dbg(&priv->wdev->dev, "Key with type 0x%04x and code 0x%04x pressed\n", type, code); + + switch (code) { + case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */ + case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */ + priv->last_status = status; + sparse_keymap_report_entry(priv->input_dev, key, 1, true); + ret = true; + break; + default: + dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code); + } + +error: + mutex_unlock(&list_mutex); + return ret; +} + +static ssize_t dell_privacy_supported_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct privacy_wmi_data *priv = dev_get_drvdata(dev); + enum dell_hardware_privacy_type type; + u32 privacy_list; + int len = 0; + + privacy_list = priv->features_present; + for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) { + if (privacy_list & BIT(type)) + len += sysfs_emit_at(buf, len, "[%s] [supported]\n", privacy_types[type]); + else + len += sysfs_emit_at(buf, len, "[%s] [unsupported]\n", privacy_types[type]); + } + + return len; +} + +static ssize_t dell_privacy_current_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct privacy_wmi_data *priv = dev_get_drvdata(dev); + u32 privacy_supported = priv->features_present; + enum dell_hardware_privacy_type type; + u32 privacy_state = priv->last_status; + int len = 0; + + for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) { + if (privacy_supported & BIT(type)) { + if (privacy_state & BIT(type)) + len += sysfs_emit_at(buf, len, "[%s] [unmuted]\n", privacy_types[type]); + else + len += sysfs_emit_at(buf, len, "[%s] [muted]\n", privacy_types[type]); + } + } + + return len; +} + +static DEVICE_ATTR_RO(dell_privacy_supported_type); +static DEVICE_ATTR_RO(dell_privacy_current_state); + +static struct attribute *privacy_attributes[] = { + &dev_attr_dell_privacy_supported_type.attr, + &dev_attr_dell_privacy_current_state.attr, + NULL, +}; + +static const struct attribute_group privacy_attribute_group = { + .attrs = privacy_attributes +}; + +/* + * Describes the Device State class exposed by BIOS which can be consumed by + * various applications interested in knowing the Privacy feature capabilities. + * class DeviceState + * { + * [key, read] string InstanceName; + * [read] boolean ReadOnly; + * + * [WmiDataId(1), read] uint32 DevicesSupported; + * 0 - None; 0x1 - Microphone; 0x2 - Camera; 0x4 - ePrivacy Screen + * + * [WmiDataId(2), read] uint32 CurrentState; + * 0 - Off; 1 - On; Bit0 - Microphone; Bit1 - Camera; Bit2 - ePrivacyScreen + * }; + */ +static int get_current_status(struct wmi_device *wdev) +{ + struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev); + union acpi_object *obj_present; + u32 *buffer; + int ret = 0; + + if (!priv) { + dev_err(&wdev->dev, "dell privacy priv is NULL\n"); + return -EINVAL; + } + /* check priv |
