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 <yuan1.liu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Yuan Liu 2019-03-07 13:40:01 +08:00 committed by wenlingz
parent 55f52978db
commit f6a989b7be
1 changed files with 116 additions and 7 deletions

View File

@ -37,6 +37,9 @@
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#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);