Use input device event support for notifying userspace of palm sensor state changes Co-developed-by: Nitin Joshi <njoshi1@xxxxxxxxxx> Signed-off-by: Nitin Joshi <njoshi1@xxxxxxxxxx> Signed-off-by: Mark Pearson <markpearson@xxxxxxxxxx> --- Changes in V2: - Update commit message to be correct Changes in V3: - remove unnecessary global state variable - clean up error handling code - set dangling pointer to null drivers/platform/x86/thinkpad_acpi.c | 95 +++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index eae3579f106f..3cb07c12a705 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4013,6 +4013,7 @@ static bool hotkey_notify_usrevent(const u32 hkey, } static void thermal_dump_all_sensors(void); +static void palmsensor_refresh(void); static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev, @@ -4079,8 +4080,8 @@ static bool hotkey_notify_6xxx(const u32 hkey, case TP_HKEY_EV_PALM_DETECTED: case TP_HKEY_EV_PALM_UNDETECTED: - /* palm detected hovering the keyboard, forward to user-space - * via netlink for consumption */ + /* palm detected - pass on to event handler */ + palmsensor_refresh(); return true; default: @@ -9918,6 +9919,92 @@ static struct ibm_struct dytc_driver_data = { .exit = dytc_exit, }; +/************************************************************************* + * Proximity sensor subdriver + */ + +#define PALMSENSOR_PRESENT_BIT 0 /* Determine if psensor present */ +#define PALMSENSOR_ON_BIT 1 /* psensor status */ + +struct input_dev *tpacpi_sw_dev; +bool has_palmsensor; + +static int palmsensor_get(bool *present, bool *state) +{ + acpi_handle psensor_handle; + int output; + + if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "GPSS", &psensor_handle))) + return -ENODEV; + if (!acpi_evalf(psensor_handle, &output, NULL, "d")) + return -EIO; + + *present = output & BIT(PALMSENSOR_PRESENT_BIT) ? true : false; + *state = output & BIT(PALMSENSOR_ON_BIT) ? true : false; + return 0; +} + +static void palmsensor_refresh(void) +{ + bool state; + int err; + + if (has_palmsensor) { + err = palmsensor_get(&has_palmsensor, &state); + if (err) + return; + input_report_switch(tpacpi_sw_dev, SW_PALMREST_PROXIMITY, state); + input_sync(tpacpi_sw_dev); + } +} + +static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) +{ + int palm_err, err; + bool palm_state; + + palm_err = palmsensor_get(&has_palmsensor, &palm_state); + /* If support isn't available (ENODEV) then quit, but don't return an error */ + if (palm_err == -ENODEV) + return 1; + + /* Otherwise, if there was an error return it */ + if (palm_err && (palm_err != ENODEV)) + return palm_err; + + if (has_palmsensor) { + tpacpi_sw_dev = input_allocate_device(); + if (!tpacpi_sw_dev) + return -ENOMEM; + tpacpi_sw_dev->name = "Thinkpad proximity switches"; + tpacpi_sw_dev->phys = TPACPI_DRVR_NAME "/input1"; + tpacpi_sw_dev->id.bustype = BUS_HOST; + tpacpi_sw_dev->id.vendor = thinkpad_id.vendor; + tpacpi_sw_dev->id.product = TPACPI_HKEY_INPUT_PRODUCT; + tpacpi_sw_dev->id.version = TPACPI_HKEY_INPUT_VERSION; + tpacpi_sw_dev->dev.parent = &tpacpi_pdev->dev; + + input_set_capability(tpacpi_sw_dev, EV_SW, SW_PALMREST_PROXIMITY); + input_report_switch(tpacpi_sw_dev, SW_PALMREST_PROXIMITY, palm_state); + err = input_register_device(tpacpi_sw_dev); + if (err) { + input_free_device(tpacpi_sw_dev); + tpacpi_sw_dev = NULL; + return 0; + } + } + return 1; +} + +static void proxsensor_exit(void) +{ + input_unregister_device(tpacpi_sw_dev); +} + +static struct ibm_struct proxsensor_driver_data = { + .name = "proximity-sensor", + .exit = proxsensor_exit, +}; /**************************************************************************** **************************************************************************** * @@ -10411,6 +10498,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = tpacpi_dytc_init, .data = &dytc_driver_data, }, + { + .init = tpacpi_proxsensor_init, + .data = &proxsensor_driver_data, + }, }; static int __init set_ibm_param(const char *val, const struct kernel_param *kp) -- 2.28.0