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>alistair/sunxi64-5.4-dsi
parent
ad0d315b4d
commit
110ea1d833
|
@ -49,6 +49,7 @@ detailed description):
|
||||||
- Fan control and monitoring: fan speed, fan enable/disable
|
- Fan control and monitoring: fan speed, fan enable/disable
|
||||||
- WAN enable and disable
|
- WAN enable and disable
|
||||||
- UWB 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
|
A compatibility table by model and feature is maintained on the web
|
||||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
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.
|
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
|
EXPERIMENTAL: UWB
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -9711,6 +9711,107 @@ static struct ibm_struct battery_driver_data = {
|
||||||
.exit = tpacpi_battery_exit,
|
.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,
|
.init = tpacpi_battery_init,
|
||||||
.data = &battery_driver_data,
|
.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)
|
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
|
||||||
|
|
Loading…
Reference in New Issue