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:
parent
ad0d315b4d
commit
110ea1d833
|
@ -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
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue