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: Alexander Schremmer <alex@alexanderweb.de>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:
Alexander Schremmer 2019-08-22 13:48:33 +02:00 committed by Andy Shevchenko
parent ad0d315b4d
commit 110ea1d833
2 changed files with 128 additions and 0 deletions

View File

@ -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
-----------------

View File

@ -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)