mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-31 07:20:55 +00:00
dm: pm: move host power button related code out of pm.c
For the code which forwards the native power button event to guest, they are not related with guest pm related operation emulation. Move this part of code out of pm.c. And will make the power button as one possible method to notify guest about the shutdown operation. Tracked-On: #3564 Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Reviewed-by: Yuan Liu <yuan1.liu@intel.com> Acked-by: Wang Yu <yu1.wang@intel.com>
This commit is contained in:
parent
ca51cc9d8a
commit
1041384993
@ -153,6 +153,7 @@ SRCS += core/timer.c
|
||||
|
||||
# arch
|
||||
SRCS += arch/x86/pm.c
|
||||
SRCS += arch/x86/power_button.c
|
||||
|
||||
# log
|
||||
SRCS += log/log.c
|
||||
|
@ -33,12 +33,6 @@
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#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"
|
||||
@ -48,18 +42,10 @@
|
||||
#include "lpc.h"
|
||||
#include "monitor.h"
|
||||
|
||||
#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"
|
||||
#define POWER_BUTTON_PNP0C0C_DRV "/sys/bus/acpi/drivers/button/PNP0C0C:00/"
|
||||
#define POWER_BUTTON_PNP0C0C_DIR POWER_BUTTON_PNP0C0C_DRV"input"
|
||||
static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct mevent *power_button;
|
||||
static sig_t old_power_handler;
|
||||
|
||||
static struct mevent *input_evt0;
|
||||
static int pwrbtn_fd = -1;
|
||||
static bool monitor_run;
|
||||
/*
|
||||
* Reset Control register at I/O port 0xcf9. Bit 2 forces a system
|
||||
* reset when it transitions from 0 to 1. Bit 1 selects the type of
|
||||
@ -236,8 +222,8 @@ pm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);
|
||||
INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
|
||||
|
||||
static void
|
||||
power_button_press_emulation(struct vmctx *ctx)
|
||||
void
|
||||
inject_power_button_event(struct vmctx *ctx)
|
||||
{
|
||||
printf("%s", "press power button\n");
|
||||
pthread_mutex_lock(&pm_lock);
|
||||
@ -252,25 +238,7 @@ static void
|
||||
power_button_handler(int signal, enum ev_type type, void *arg)
|
||||
{
|
||||
if (arg)
|
||||
power_button_press_emulation(arg);
|
||||
}
|
||||
|
||||
static void
|
||||
input_event0_handler(int fd, enum ev_type type, void *arg)
|
||||
{
|
||||
struct input_event ev;
|
||||
int rc;
|
||||
|
||||
rc = read(fd, &ev, sizeof(ev));
|
||||
if (rc < 0 || rc != sizeof(ev))
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
inject_power_button_event(arg);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -309,150 +277,6 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
INOUT_PORT(pm1_control, VIRTUAL_PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
|
||||
SYSRES_IO(PM1A_EVT_ADDR, 8);
|
||||
|
||||
static int
|
||||
vm_stop_handler(void *arg)
|
||||
{
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
power_button_press_emulation(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vm_suspend_handler(void *arg)
|
||||
{
|
||||
/*
|
||||
* Invoke vm_stop_handler directly in here since suspend of UOS is
|
||||
* set by UOS power button setting.
|
||||
*/
|
||||
return vm_stop_handler(arg);
|
||||
}
|
||||
|
||||
static struct monitor_vm_ops vm_ops = {
|
||||
.stop = vm_stop_handler,
|
||||
.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(const char *drv, const char *dir)
|
||||
{
|
||||
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(drv, F_OK) != 0)
|
||||
return -1;
|
||||
/*
|
||||
* Scan path to get inputN
|
||||
* path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input
|
||||
*/
|
||||
ninput = scandir(dir, &input_dirs, input_dir_filter,
|
||||
alphasort);
|
||||
if (ninput < 0) {
|
||||
fprintf(stderr, "failed to scan power button %s\n",
|
||||
dir);
|
||||
goto err;
|
||||
} else if (ninput == 1) {
|
||||
rc = snprintf(path, sizeof(path), "%s/%s",
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
open_native_power_button()
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Open fixed power button firstly, if it can't be opened
|
||||
* try to open control method power button.
|
||||
*/
|
||||
fd = open_power_button_input_device(POWER_BUTTON_ACPI_DRV,
|
||||
POWER_BUTTON_INPUT_DIR);
|
||||
if (fd < 0)
|
||||
return open_power_button_input_device(
|
||||
POWER_BUTTON_PNP0C0C_DRV,
|
||||
POWER_BUTTON_PNP0C0C_DIR);
|
||||
else
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI SMI Command Register
|
||||
*
|
||||
@ -486,29 +310,6 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
power_button_handler, ctx, NULL, NULL);
|
||||
old_power_handler = signal(SIGTERM, SIG_IGN);
|
||||
}
|
||||
if (input_evt0 == NULL) {
|
||||
|
||||
pwrbtn_fd = open_native_power_button();
|
||||
if (pwrbtn_fd < 0)
|
||||
fprintf(stderr, "open power button error=%d\n",
|
||||
errno);
|
||||
else
|
||||
input_evt0 = mevent_add(pwrbtn_fd, EVF_READ,
|
||||
input_event0_handler, ctx, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Suspend or shutdown UOS by acrnctl suspend and
|
||||
* stop command.
|
||||
*/
|
||||
if (monitor_run == false) {
|
||||
if (monitor_register_vm_ops(&vm_ops, ctx,
|
||||
POWER_BUTTON_NAME) < 0)
|
||||
fprintf(stderr,
|
||||
"failed to register vm ops for power button\n");
|
||||
else
|
||||
monitor_run = true;
|
||||
}
|
||||
break;
|
||||
case ACPI_DISABLE:
|
||||
pm1_control &= ~VIRTUAL_PM1A_SCI_EN;
|
||||
@ -517,11 +318,6 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
power_button = NULL;
|
||||
signal(SIGTERM, old_power_handler);
|
||||
}
|
||||
if (input_evt0 != NULL) {
|
||||
mevent_delete_close(input_evt0);
|
||||
input_evt0 = NULL;
|
||||
pwrbtn_fd = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pthread_mutex_unlock(&pm_lock);
|
||||
|
234
devicemodel/arch/x86/power_button.c
Normal file
234
devicemodel/arch/x86/power_button.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#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"
|
||||
#include "mevent.h"
|
||||
#include "monitor.h"
|
||||
|
||||
#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"
|
||||
#define POWER_BUTTON_PNP0C0C_DRV "/sys/bus/acpi/drivers/button/PNP0C0C:00/"
|
||||
#define POWER_BUTTON_PNP0C0C_DIR POWER_BUTTON_PNP0C0C_DRV"input"
|
||||
|
||||
static struct mevent *input_evt0;
|
||||
static int pwrbtn_fd = -1;
|
||||
static bool monitor_run;
|
||||
|
||||
static void
|
||||
input_event0_handler(int fd, enum ev_type type, void *arg)
|
||||
{
|
||||
struct input_event ev;
|
||||
int rc;
|
||||
|
||||
rc = read(fd, &ev, sizeof(ev));
|
||||
if (rc < 0 || rc != sizeof(ev))
|
||||
return;
|
||||
|
||||
/*
|
||||
* The input key defines in input-event-codes.h
|
||||
* KEY_POWER 116 SC System Power Down
|
||||
*/
|
||||
if (ev.code == KEY_POWER && ev.value == 1)
|
||||
inject_power_button_event(arg);
|
||||
}
|
||||
|
||||
static int
|
||||
vm_stop_handler(void *arg)
|
||||
{
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
inject_power_button_event(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vm_suspend_handler(void *arg)
|
||||
{
|
||||
/*
|
||||
* Invoke vm_stop_handler directly in here since suspend of UOS is
|
||||
* set by UOS power button setting.
|
||||
*/
|
||||
return vm_stop_handler(arg);
|
||||
}
|
||||
|
||||
static struct monitor_vm_ops vm_ops = {
|
||||
.stop = vm_stop_handler,
|
||||
.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(const char *drv, const char *dir)
|
||||
{
|
||||
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(drv, F_OK) != 0)
|
||||
return -1;
|
||||
/*
|
||||
* Scan path to get inputN
|
||||
* path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input
|
||||
*/
|
||||
ninput = scandir(dir, &input_dirs, input_dir_filter,
|
||||
alphasort);
|
||||
if (ninput < 0) {
|
||||
fprintf(stderr, "failed to scan power button %s\n",
|
||||
dir);
|
||||
goto err;
|
||||
} else if (ninput == 1) {
|
||||
rc = snprintf(path, sizeof(path), "%s/%s",
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
open_native_power_button()
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Open fixed power button firstly, if it can't be opened
|
||||
* try to open control method power button.
|
||||
*/
|
||||
fd = open_power_button_input_device(POWER_BUTTON_ACPI_DRV,
|
||||
POWER_BUTTON_INPUT_DIR);
|
||||
if (fd < 0)
|
||||
return open_power_button_input_device(
|
||||
POWER_BUTTON_PNP0C0C_DRV,
|
||||
POWER_BUTTON_PNP0C0C_DIR);
|
||||
else
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
power_button_init(struct vmctx *ctx)
|
||||
{
|
||||
if (input_evt0 == NULL) {
|
||||
pwrbtn_fd = open_native_power_button();
|
||||
if (pwrbtn_fd < 0)
|
||||
fprintf(stderr, "open power button error=%d\n",
|
||||
errno);
|
||||
else
|
||||
input_evt0 = mevent_add(pwrbtn_fd, EVF_READ,
|
||||
input_event0_handler, ctx, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Suspend or shutdown UOS by acrnctl suspend and
|
||||
* stop command.
|
||||
*/
|
||||
if (monitor_run == false) {
|
||||
if (monitor_register_vm_ops(&vm_ops, ctx,
|
||||
POWER_BUTTON_NAME) < 0)
|
||||
fprintf(stderr,
|
||||
"failed to register vm ops for power button\n");
|
||||
else
|
||||
monitor_run = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
power_button_deinit(struct vmctx *ctx)
|
||||
{
|
||||
if (input_evt0 != NULL) {
|
||||
mevent_delete_close(input_evt0);
|
||||
input_evt0 = NULL;
|
||||
pwrbtn_fd = -1;
|
||||
}
|
||||
}
|
@ -59,5 +59,8 @@ void dsdt_unindent(int levels);
|
||||
void sci_init(struct vmctx *ctx);
|
||||
void pm_write_dsdt(struct vmctx *ctx, int ncpu);
|
||||
void pm_backto_wakeup(struct vmctx *ctx);
|
||||
void inject_power_button_event(struct vmctx *ctx);
|
||||
void power_button_init(struct vmctx *ctx);
|
||||
void power_button_deinit(struct vmctx *ctx);
|
||||
|
||||
#endif /* _ACPI_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user