linux/drivers/platform/x86/dell/dell-laptop.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 *  Driver for Dell laptop extras
 *
 *  Copyright (c) Red Hat <[email protected]>
 *  Copyright (c) 2014 Gabriele Mazzotta <[email protected]>
 *  Copyright (c) 2014 Pali Rohár <[email protected]>
 *
 *  Based on documentation in the libsmbios package:
 *  Copyright (C) 2005-2014 Dell Inc.
 */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/dmi.h>
#include <linux/io.h>
#include <linux/rfkill.h>
#include <linux/power_supply.h>
#include <linux/sysfs.h>
#include <linux/acpi.h>
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <acpi/battery.h>
#include <acpi/video.h>
#include "dell-rbtn.h"
#include "dell-smbios.h"

#include "dell-wmi-privacy.h"

struct quirk_entry {};

static struct quirk_entry *quirks;

static struct quirk_entry quirk_dell_vostro_v130 =;

static int __init dmi_matched(const struct dmi_system_id *dmi)
{}

/*
 * These values come from Windows utility provided by Dell. If any other value
 * is used then BIOS silently set timeout to 0 without any error message.
 */
static struct quirk_entry quirk_dell_xps13_9333 =;

static struct quirk_entry quirk_dell_xps13_9370 =;

static struct quirk_entry quirk_dell_latitude_e6410 =;

static struct quirk_entry quirk_dell_inspiron_1012 =;

static struct quirk_entry quirk_dell_latitude_7520 =;

static struct platform_driver platform_driver =;

static struct platform_device *platform_device;
static struct backlight_device *dell_backlight_device;
static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;
static bool force_rfkill;
static bool micmute_led_registered;
static bool mute_led_registered;

struct battery_mode_info {};

static const struct battery_mode_info battery_modes[] =;
static u32 battery_supported_modes;

module_param(force_rfkill, bool, 0444);
MODULE_PARM_DESC();

static const struct dmi_system_id dell_device_table[] __initconst =;
MODULE_DEVICE_TABLE(dmi, dell_device_table);

static const struct dmi_system_id dell_quirks[] __initconst =;

/* -1 is a sentinel value, telling us to use token->value */
#define USE_TVAL
static int dell_send_request_for_tokenid(struct calling_interface_buffer *buffer,
					 u16 class, u16 select, u16 tokenid,
					 u32 val)
{}

static inline int dell_set_std_token_value(struct calling_interface_buffer *buffer,
		u16 tokenid, u32 value)
{}

/*
 * Derived from information in smbios-wireless-ctl:
 *
 * cbSelect 17, Value 11
 *
 * Return Wireless Info
 * cbArg1, byte0 = 0x00
 *
 *     cbRes1 Standard return codes (0, -1, -2)
 *     cbRes2 Info bit flags:
 *
 *     0 Hardware switch supported (1)
 *     1 WiFi locator supported (1)
 *     2 WLAN supported (1)
 *     3 Bluetooth (BT) supported (1)
 *     4 WWAN supported (1)
 *     5 Wireless KBD supported (1)
 *     6 Uw b supported (1)
 *     7 WiGig supported (1)
 *     8 WLAN installed (1)
 *     9 BT installed (1)
 *     10 WWAN installed (1)
 *     11 Uw b installed (1)
 *     12 WiGig installed (1)
 *     13-15 Reserved (0)
 *     16 Hardware (HW) switch is On (1)
 *     17 WLAN disabled (1)
 *     18 BT disabled (1)
 *     19 WWAN disabled (1)
 *     20 Uw b disabled (1)
 *     21 WiGig disabled (1)
 *     20-31 Reserved (0)
 *
 *     cbRes3 NVRAM size in bytes
 *     cbRes4, byte 0 NVRAM format version number
 *
 *
 * Set QuickSet Radio Disable Flag
 *     cbArg1, byte0 = 0x01
 *     cbArg1, byte1
 *     Radio ID     value:
 *     0        Radio Status
 *     1        WLAN ID
 *     2        BT ID
 *     3        WWAN ID
 *     4        UWB ID
 *     5        WIGIG ID
 *     cbArg1, byte2    Flag bits:
 *             0 QuickSet disables radio (1)
 *             1-7 Reserved (0)
 *
 *     cbRes1    Standard return codes (0, -1, -2)
 *     cbRes2    QuickSet (QS) radio disable bit map:
 *     0 QS disables WLAN
 *     1 QS disables BT
 *     2 QS disables WWAN
 *     3 QS disables UWB
 *     4 QS disables WIGIG
 *     5-31 Reserved (0)
 *
 * Wireless Switch Configuration
 *     cbArg1, byte0 = 0x02
 *
 *     cbArg1, byte1
 *     Subcommand:
 *     0 Get config
 *     1 Set config
 *     2 Set WiFi locator enable/disable
 *     cbArg1,byte2
 *     Switch settings (if byte 1==1):
 *     0 WLAN sw itch control (1)
 *     1 BT sw itch control (1)
 *     2 WWAN sw itch control (1)
 *     3 UWB sw itch control (1)
 *     4 WiGig sw itch control (1)
 *     5-7 Reserved (0)
 *    cbArg1, byte2 Enable bits (if byte 1==2):
 *     0 Enable WiFi locator (1)
 *
 *    cbRes1     Standard return codes (0, -1, -2)
 *    cbRes2 QuickSet radio disable bit map:
 *     0 WLAN controlled by sw itch (1)
 *     1 BT controlled by sw itch (1)
 *     2 WWAN controlled by sw itch (1)
 *     3 UWB controlled by sw itch (1)
 *     4 WiGig controlled by sw itch (1)
 *     5-6 Reserved (0)
 *     7 Wireless sw itch config locked (1)
 *     8 WiFi locator enabled (1)
 *     9-14 Reserved (0)
 *     15 WiFi locator setting locked (1)
 *     16-31 Reserved (0)
 *
 * Read Local Config Data (LCD)
 *     cbArg1, byte0 = 0x10
 *     cbArg1, byte1 NVRAM index low byte
 *     cbArg1, byte2 NVRAM index high byte
 *     cbRes1 Standard return codes (0, -1, -2)
 *     cbRes2 4 bytes read from LCD[index]
 *     cbRes3 4 bytes read from LCD[index+4]
 *     cbRes4 4 bytes read from LCD[index+8]
 *
 * Write Local Config Data (LCD)
 *     cbArg1, byte0 = 0x11
 *     cbArg1, byte1 NVRAM index low byte
 *     cbArg1, byte2 NVRAM index high byte
 *     cbArg2 4 bytes to w rite at LCD[index]
 *     cbArg3 4 bytes to w rite at LCD[index+4]
 *     cbArg4 4 bytes to w rite at LCD[index+8]
 *     cbRes1 Standard return codes (0, -1, -2)
 *
 * Populate Local Config Data from NVRAM
 *     cbArg1, byte0 = 0x12
 *     cbRes1 Standard return codes (0, -1, -2)
 *
 * Commit Local Config Data to NVRAM
 *     cbArg1, byte0 = 0x13
 *     cbRes1 Standard return codes (0, -1, -2)
 */

static int dell_rfkill_set(void *data, bool blocked)
{}

static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
					int status)
{}

static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
					int status, int hwswitch)
{}

static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{}

static const struct rfkill_ops dell_rfkill_ops =;

static struct dentry *dell_laptop_dir;

static int dell_debugfs_show(struct seq_file *s, void *data)
{}
DEFINE_SHOW_ATTRIBUTE();

static void dell_update_rfkill(struct work_struct *ignored)
{}
static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);

static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
			      struct serio *port)
{}

static int (*dell_rbtn_notifier_register_func)(struct notifier_block *);
static int (*dell_rbtn_notifier_unregister_func)(struct notifier_block *);

static int dell_laptop_rbtn_notifier_call(struct notifier_block *nb,
					  unsigned long action, void *data)
{}

static struct notifier_block dell_laptop_rbtn_notifier =;

static int __init dell_setup_rfkill(void)
{}

static void dell_cleanup_rfkill(void)
{}

static int dell_send_intensity(struct backlight_device *bd)
{}

static int dell_get_intensity(struct backlight_device *bd)
{}

static const struct backlight_ops dell_ops =;

static void touchpad_led_on(void)
{}

static void touchpad_led_off(void)
{}

static void touchpad_led_set(struct led_classdev *led_cdev,
	enum led_brightness value)
{}

static struct led_classdev touchpad_led =;

static int __init touchpad_led_init(struct device *dev)
{}

static void touchpad_led_exit(void)
{}

/*
 * Derived from information in smbios-keyboard-ctl:
 *
 * cbClass 4
 * cbSelect 11
 * Keyboard illumination
 * cbArg1 determines the function to be performed
 *
 * cbArg1 0x0 = Get Feature Information
 *  cbRES1         Standard return codes (0, -1, -2)
 *  cbRES2, word0  Bitmap of user-selectable modes
 *     bit 0     Always off (All systems)
 *     bit 1     Always on (Travis ATG, Siberia)
 *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
 *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
 *     bit 4     Auto: Input-activity-based On; input-activity based Off
 *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
 *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
 *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
 *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
 *     bits 9-15 Reserved for future use
 *  cbRES2, byte2  Reserved for future use
 *  cbRES2, byte3  Keyboard illumination type
 *     0         Reserved
 *     1         Tasklight
 *     2         Backlight
 *     3-255     Reserved for future use
 *  cbRES3, byte0  Supported auto keyboard illumination trigger bitmap.
 *     bit 0     Any keystroke
 *     bit 1     Touchpad activity
 *     bit 2     Pointing stick
 *     bit 3     Any mouse
 *     bits 4-7  Reserved for future use
 *  cbRES3, byte1  Supported timeout unit bitmap
 *     bit 0     Seconds
 *     bit 1     Minutes
 *     bit 2     Hours
 *     bit 3     Days
 *     bits 4-7  Reserved for future use
 *  cbRES3, byte2  Number of keyboard light brightness levels
 *  cbRES4, byte0  Maximum acceptable seconds value (0 if seconds not supported).
 *  cbRES4, byte1  Maximum acceptable minutes value (0 if minutes not supported).
 *  cbRES4, byte2  Maximum acceptable hours value (0 if hours not supported).
 *  cbRES4, byte3  Maximum acceptable days value (0 if days not supported)
 *
 * cbArg1 0x1 = Get Current State
 *  cbRES1         Standard return codes (0, -1, -2)
 *  cbRES2, word0  Bitmap of current mode state
 *     bit 0     Always off (All systems)
 *     bit 1     Always on (Travis ATG, Siberia)
 *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
 *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
 *     bit 4     Auto: Input-activity-based On; input-activity based Off
 *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
 *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
 *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
 *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
 *     bits 9-15 Reserved for future use
 *     Note: Only One bit can be set
 *  cbRES2, byte2  Currently active auto keyboard illumination triggers.
 *     bit 0     Any keystroke
 *     bit 1     Touchpad activity
 *     bit 2     Pointing stick
 *     bit 3     Any mouse
 *     bits 4-7  Reserved for future use
 *  cbRES2, byte3  Current Timeout on battery
 *     bits 7:6  Timeout units indicator:
 *     00b       Seconds
 *     01b       Minutes
 *     10b       Hours
 *     11b       Days
 *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
 *     NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte
 *     are set upon return from the [Get feature information] call.
 *  cbRES3, byte0  Current setting of ALS value that turns the light on or off.
 *  cbRES3, byte1  Current ALS reading
 *  cbRES3, byte2  Current keyboard light level.
 *  cbRES3, byte3  Current timeout on AC Power
 *     bits 7:6  Timeout units indicator:
 *     00b       Seconds
 *     01b       Minutes
 *     10b       Hours
 *     11b       Days
 *     Bits 5:0  Timeout value (0-63) in sec/min/hr/day
 *     NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2
 *     are set upon return from the upon return from the [Get Feature information] call.
 *
 * cbArg1 0x2 = Set New State
 *  cbRES1         Standard return codes (0, -1, -2)
 *  cbArg2, word0  Bitmap of current mode state
 *     bit 0     Always off (All systems)
 *     bit 1     Always on (Travis ATG, Siberia)
 *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
 *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
 *     bit 4     Auto: Input-activity-based On; input-activity based Off
 *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
 *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
 *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
 *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
 *     bits 9-15 Reserved for future use
 *     Note: Only One bit can be set
 *  cbArg2, byte2  Desired auto keyboard illumination triggers. Must remain inactive to allow
 *                 keyboard to turn off automatically.
 *     bit 0     Any keystroke
 *     bit 1     Touchpad activity
 *     bit 2     Pointing stick
 *     bit 3     Any mouse
 *     bits 4-7  Reserved for future use
 *  cbArg2, byte3  Desired Timeout on battery
 *     bits 7:6  Timeout units indicator:
 *     00b       Seconds
 *     01b       Minutes
 *     10b       Hours
 *     11b       Days
 *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
 *  cbArg3, byte0  Desired setting of ALS value that turns the light on or off.
 *  cbArg3, byte2  Desired keyboard light level.
 *  cbArg3, byte3  Desired Timeout on AC power
 *     bits 7:6  Timeout units indicator:
 *     00b       Seconds
 *     01b       Minutes
 *     10b       Hours
 *     11b       Days
 *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
 */


enum kbd_timeout_unit {};

enum kbd_mode_bit {};

#define kbd_is_als_mode_bit(bit)
#define kbd_is_trigger_mode_bit(bit)
#define kbd_is_level_mode_bit(bit)

struct kbd_info {};

struct kbd_state {};

static const int kbd_tokens[] =;

static u16 kbd_token_bits;

static struct kbd_info kbd_info;
static bool kbd_als_supported;
static bool kbd_triggers_supported;
static bool kbd_timeout_ac_supported;

static u8 kbd_mode_levels[16];
static int kbd_mode_levels_count;

static u8 kbd_previous_level;
static u8 kbd_previous_mode_bit;

static bool kbd_led_present;
static DEFINE_MUTEX(kbd_led_mutex);
static enum led_brightness kbd_led_level;

/*
 * NOTE: there are three ways to set the keyboard backlight level.
 * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value).
 * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels).
 * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens)
 *
 * There are laptops which support only one of these methods. If we want to
 * support as many machines as possible we need to implement all three methods.
 * The first two methods use the kbd_state structure. The third uses SMBIOS
 * tokens. If kbd_info.levels == 0, the machine does not support setting the
 * keyboard backlight level via kbd_state.level.
 */

static int kbd_get_info(struct kbd_info *info)
{}

static unsigned int kbd_get_max_level(void)
{}

static int kbd_get_level(struct kbd_state *state)
{}

static int kbd_set_level(struct kbd_state *state, u8 level)
{}

static int kbd_get_state(struct kbd_state *state)
{}

static int kbd_set_state(struct kbd_state *state)
{}

static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
{}

static int kbd_set_token_bit(u8 bit)
{}

static int kbd_get_token_bit(u8 bit)
{}

static int kbd_get_first_active_token_bit(void)
{}

static int kbd_get_valid_token_counts(void)
{}

static inline int kbd_init_info(void)
{}

static inline void __init kbd_init_tokens(void)
{}

static void __init kbd_init(void)
{}

static ssize_t kbd_led_timeout_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}

static ssize_t kbd_led_timeout_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR,
		   kbd_led_timeout_show, kbd_led_timeout_store);

static const char * const kbd_led_triggers[] =;

static ssize_t kbd_led_triggers_store(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{}

static ssize_t kbd_led_triggers_show(struct device *dev,
				     struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR,
		   kbd_led_triggers_show, kbd_led_triggers_store);

static ssize_t kbd_led_als_enabled_store(struct device *dev,
					 struct device_attribute *attr,
					 const char *buf, size_t count)
{}

static ssize_t kbd_led_als_enabled_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{}

static DEVICE_ATTR(als_enabled, S_IRUGO | S_IWUSR,
		   kbd_led_als_enabled_show, kbd_led_als_enabled_store);

static ssize_t kbd_led_als_setting_store(struct device *dev,
					 struct device_attribute *attr,
					 const char *buf, size_t count)
{}

static ssize_t kbd_led_als_setting_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{}

static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR,
		   kbd_led_als_setting_show, kbd_led_als_setting_store);

static struct attribute *kbd_led_attrs[] =;

static const struct attribute_group kbd_led_group =;

static struct attribute *kbd_led_als_attrs[] =;

static const struct attribute_group kbd_led_als_group =;

static const struct attribute_group *kbd_led_groups[] =;

static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
{}

static int kbd_led_level_set(struct led_classdev *led_cdev,
			     enum led_brightness value)
{}

static struct led_classdev kbd_led =;

static int __init kbd_led_init(struct device *dev)
{}

static void brightness_set_exit(struct led_classdev *led_cdev,
				enum led_brightness value)
{
	/* Don't change backlight level on exit */
};

static void kbd_led_exit(void)
{}

static int dell_laptop_notifier_call(struct notifier_block *nb,
				     unsigned long action, void *data)
{}

static struct notifier_block dell_laptop_notifier =;

static int micmute_led_set(struct led_classdev *led_cdev,
			   enum led_brightness brightness)
{}

static struct led_classdev micmute_led_cdev =;

static int mute_led_set(struct led_classdev *led_cdev,
			   enum led_brightness brightness)
{}

static struct led_classdev mute_led_cdev =;

static int dell_battery_set_mode(const u16 tokenid)
{}

static int dell_battery_read(const u16 tokenid)
{}

static bool dell_battery_mode_is_active(const u16 tokenid)
{}

/*
 * The rules: the minimum start charging value is 50%. The maximum
 * start charging value is 95%. The minimum end charging value is
 * 55%. The maximum end charging value is 100%. And finally, there
 * has to be at least a 5% difference between start & end values.
 */
#define CHARGE_START_MIN
#define CHARGE_START_MAX
#define CHARGE_END_MIN
#define CHARGE_END_MAX
#define CHARGE_MIN_DIFF

static int dell_battery_set_custom_charge_start(int start)
{}

static int dell_battery_set_custom_charge_end(int end)
{}

static ssize_t charge_types_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{}

static ssize_t charge_types_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t size)
{}

static ssize_t charge_control_start_threshold_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{}

static ssize_t charge_control_start_threshold_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t size)
{}

static ssize_t charge_control_end_threshold_show(struct device *dev,
		struct device_attribute *attr,
		char *buf)
{}

static ssize_t charge_control_end_threshold_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t size)
{}

static DEVICE_ATTR_RW(charge_control_start_threshold);
static DEVICE_ATTR_RW(charge_control_end_threshold);
static DEVICE_ATTR_RW(charge_types);

static struct attribute *dell_battery_attrs[] =;
ATTRIBUTE_GROUPS();

static bool dell_battery_supported(struct power_supply *battery)
{}

static int dell_battery_add(struct power_supply *battery,
		struct acpi_battery_hook *hook)
{}

static int dell_battery_remove(struct power_supply *battery,
		struct acpi_battery_hook *hook)
{}

static struct acpi_battery_hook dell_battery_hook =;

static u32 __init battery_get_supported_modes(void)
{}

static void __init dell_battery_init(struct device *dev)
{}

static void dell_battery_exit(void)
{}

static int __init dell_init(void)
{}

static void __exit dell_exit(void)
{}

/* dell-rbtn.c driver export functions which will not work correctly (and could
 * cause kernel crash) if they are called before dell-rbtn.c init code. This is
 * not problem when dell-rbtn.c is compiled as external module. When both files
 * (dell-rbtn.c and dell-laptop.c) are compiled statically into kernel, then we
 * need to ensure that dell_init() will be called after initializing dell-rbtn.
 * This can be achieved by late_initcall() instead module_init().
 */
late_initcall(dell_init);
module_exit(dell_exit);

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();