From f6a989b7be4480a1fd6450c55fa6fd5d1d060272 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Thu, 7 Mar 2019 13:40:01 +0800 Subject: [PATCH] dm: use power button acpi device to find its input event check the power button acpi driver firstly, then find input event corresponding to the power button. Tracked-On: #2695 Signed-off-by: Yuan Liu Acked-by: Yu Wang --- devicemodel/arch/x86/pm.c | 123 +++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 7 deletions(-) diff --git a/devicemodel/arch/x86/pm.c b/devicemodel/arch/x86/pm.c index f960ed0af..dc8f3f143 100644 --- a/devicemodel/arch/x86/pm.c +++ b/devicemodel/arch/x86/pm.c @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include "vmmapi.h" #include "acpi.h" @@ -46,8 +49,9 @@ #include "lpc.h" #include "monitor.h" -#define POWER_BUTTON_EVENT 116 #define POWER_BUTTON_NAME "power_button" +#define POWER_BUTTON_ACPI_DRV "/sys/bus/acpi/drivers/button/LNXPWRBN:00/" +#define POWER_BUTTON_INPUT_DIR POWER_BUTTON_ACPI_DRV"input" static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER; static struct mevent *power_button; static sig_t old_power_handler; @@ -242,6 +246,7 @@ INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler); static void power_button_press_emulation(struct vmctx *ctx) { + printf("%s", "press power button\n"); pthread_mutex_lock(&pm_lock); if (!(pm1_status & PM1_PWRBTN_STS)) { pm1_status |= PM1_PWRBTN_STS; @@ -267,7 +272,11 @@ input_event0_handler(int fd, enum ev_type type, void *arg) if (rc < 0 || rc != sizeof(ev)) return; - if (ev.code == POWER_BUTTON_EVENT && ev.value == 1) + /* + * The input key defines in input-event-codes.h + * KEY_POWER 116 SC System Power Down + */ + if (ev.code == KEY_POWER && ev.value == 1) power_button_press_emulation(arg); } @@ -336,6 +345,109 @@ static struct monitor_vm_ops vm_ops = { .suspend = vm_suspend_handler, }; +static int +input_dir_filter(const struct dirent *dir) +{ + return !strncmp(dir->d_name, "input", 5); +} + +static int +event_dir_filter(const struct dirent *dir) +{ + return !strncmp(dir->d_name, "event", 5); +} + +static int +open_power_button_input_device() +{ + struct dirent **input_dirs = NULL; + struct dirent **event_dirs = NULL; + int ninput = 0; + int nevent = 0; + char path[256] = {0}; + char name[256] = {0}; + int rc, fd; + + if (access(POWER_BUTTON_ACPI_DRV, F_OK) != 0) { + fprintf(stderr, "failed to detect power button driver\n"); + return -1; + } + + /* + * Scan path to get inputN + * path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input + */ + ninput = scandir(POWER_BUTTON_INPUT_DIR, &input_dirs, input_dir_filter, + alphasort); + if (ninput < 0) { + fprintf(stderr, "failed to scan power button %s\n", + POWER_BUTTON_INPUT_DIR); + goto err; + } else if (ninput == 1) { + rc = snprintf(path, sizeof(path), "%s/%s", + POWER_BUTTON_INPUT_DIR, input_dirs[0]->d_name); + if (rc < 0 || rc >= sizeof(path)) { + fprintf(stderr, "failed to set power button path %d\n", + rc); + goto err_input; + } + + /* + * Scan path to get eventN + * path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input/inputN + */ + nevent = scandir(path, &event_dirs, event_dir_filter, + alphasort); + if (nevent < 0) { + fprintf(stderr, "failed to get power button event %s\n", + path); + goto err_input; + } else if (nevent == 1) { + + /* Get the power button input event name */ + rc = snprintf(name, sizeof(name), "/dev/input/%s", + event_dirs[0]->d_name); + if (rc < 0 || rc >= sizeof(name)) { + fprintf(stderr, "power button error %d\n", rc); + goto err_input; + } + } else { + fprintf(stderr, "power button event number error %d\n", + nevent); + goto err_event; + } + } else { + fprintf(stderr, "power button input number error %d\n", nevent); + goto err_input; + } + + /* Open the input device */ + fd = open(name, O_RDONLY); + if (fd > 0) + printf("Watching power button on %s\n", name); + + while (nevent--) + free(event_dirs[nevent]); + free(event_dirs); + while (ninput--) + free(input_dirs[ninput]); + free(input_dirs); + return fd; + +err_event: + while (nevent--) + free(event_dirs[nevent]); + free(event_dirs); + +err_input: + while (ninput--) + free(input_dirs[ninput]); + free(input_dirs); + +err: + return -1; +} + /* * ACPI SMI Command Register * @@ -371,11 +483,8 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, old_power_handler = signal(SIGTERM, SIG_IGN); } if (input_evt0 == NULL) { - /* - * FIXME: check /sys/bus/acpi/devices/LNXPWRBN\:00/input to - * get input event node instead hardcode in here. - */ - pwrbtn_fd = open("/dev/input/event0", O_RDONLY); + + pwrbtn_fd = open_power_button_input_device(); if (pwrbtn_fd < 0) fprintf(stderr, "open input event0 error=%d\n", errno);