Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 110ea1d8 authored by Alexander Schremmer's avatar Alexander Schremmer Committed by Andy Shevchenko
Browse files

platform/x86: thinkpad_acpi: Add ThinkPad PrivacyGuard



This feature is found optionally in T480s, T490, T490s.

The feature is called lcdshadow and visible via
/proc/acpi/ibm/lcdshadow.

The ACPI methods \_SB.PCI0.LPCB.EC.HKEY.{GSSS,SSSS,TSSS,CSSS} are
available in these machines. They get, set, toggle or change the state
apparently.

The patch was tested on a 5.0 series kernel on a T480s.

Signed-off-by: default avatarAlexander Schremmer <alex@alexanderweb.de>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent ad0d315b
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ detailed description):
	- Fan control and monitoring: fan speed, fan enable/disable
	- WAN enable and disable
	- UWB enable and disable
	- LCD Shadow (PrivacyGuard) enable and disable

A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -1409,6 +1410,28 @@ Sysfs notes
	Documentation/driver-api/rfkill.rst for details.


LCD Shadow control
------------------

procfs: /proc/acpi/ibm/lcdshadow

Some newer T480s and T490s ThinkPads provide a feature called
PrivacyGuard. By turning this feature on, the usable vertical and
horizontal viewing angles of the LCD can be limited (as if some privacy
screen was applied manually in front of the display).

procfs notes
^^^^^^^^^^^^

The available commands are::

	echo '0' >/proc/acpi/ibm/lcdshadow
	echo '1' >/proc/acpi/ibm/lcdshadow

The first command ensures the best viewing angle and the latter one turns
on the feature, restricting the viewing angles.


EXPERIMENTAL: UWB
-----------------

+105 −0
Original line number Diff line number Diff line
@@ -9711,6 +9711,107 @@ static struct ibm_struct battery_driver_data = {
	.exit = tpacpi_battery_exit,
};

/*************************************************************************
 * LCD Shadow subdriver, for the Lenovo PrivacyGuard feature
 */

static int lcdshadow_state;

static int lcdshadow_on_off(bool state)
{
	acpi_handle set_shadow_handle;
	int output;

	if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "SSSS", &set_shadow_handle))) {
		pr_warn("Thinkpad ACPI has no %s interface.\n", "SSSS");
		return -EIO;
	}

	if (!acpi_evalf(set_shadow_handle, &output, NULL, "dd", (int)state))
		return -EIO;

	lcdshadow_state = state;
	return 0;
}

static int lcdshadow_set(bool on)
{
	if (lcdshadow_state < 0)
		return lcdshadow_state;
	if (lcdshadow_state == on)
		return 0;
	return lcdshadow_on_off(on);
}

static int tpacpi_lcdshadow_init(struct ibm_init_struct *iibm)
{
	acpi_handle get_shadow_handle;
	int output;

	if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "GSSS", &get_shadow_handle))) {
		lcdshadow_state = -ENODEV;
		return 0;
	}

	if (!acpi_evalf(get_shadow_handle, &output, NULL, "dd", 0)) {
		lcdshadow_state = -EIO;
		return -EIO;
	}
	if (!(output & 0x10000)) {
		lcdshadow_state = -ENODEV;
		return 0;
	}
	lcdshadow_state = output & 0x1;

	return 0;
}

static void lcdshadow_resume(void)
{
	if (lcdshadow_state >= 0)
		lcdshadow_on_off(lcdshadow_state);
}

static int lcdshadow_read(struct seq_file *m)
{
	if (lcdshadow_state < 0) {
		seq_puts(m, "status:\t\tnot supported\n");
	} else {
		seq_printf(m, "status:\t\t%d\n", lcdshadow_state);
		seq_puts(m, "commands:\t0, 1\n");
	}

	return 0;
}

static int lcdshadow_write(char *buf)
{
	char *cmd;
	int state = -1;

	if (lcdshadow_state < 0)
		return -ENODEV;

	while ((cmd = next_cmd(&buf))) {
		if (strlencmp(cmd, "0") == 0)
			state = 0;
		else if (strlencmp(cmd, "1") == 0)
			state = 1;
	}

	if (state == -1)
		return -EINVAL;

	return lcdshadow_set(state);
}

static struct ibm_struct lcdshadow_driver_data = {
	.name = "lcdshadow",
	.resume = lcdshadow_resume,
	.read = lcdshadow_read,
	.write = lcdshadow_write,
};

/****************************************************************************
 ****************************************************************************
 *
@@ -10192,6 +10293,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
		.init = tpacpi_battery_init,
		.data = &battery_driver_data,
	},
	{
		.init = tpacpi_lcdshadow_init,
		.data = &lcdshadow_driver_data,
	},
};

static int __init set_ibm_param(const char *val, const struct kernel_param *kp)