dm: power button emulation by acrnctl command.

when UOS is running, "acrnctl suspend vm" and "acrnctl stop vm" commands are
able to trigger a SCI interrupt, then UOS enters sleep or shutdown according
to the default behavior of the power button. The default behavior is based on
UOS power button setting.

Tracked-On: #2560
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-02-28 14:34:29 +08:00 committed by Eddie Dong
parent 32a7b4f179
commit 566e8824da

View File

@ -44,14 +44,17 @@
#include "mevent.h" #include "mevent.h"
#include "irq.h" #include "irq.h"
#include "lpc.h" #include "lpc.h"
#include "monitor.h"
#define POWER_BUTTON_EVENT 116 #define POWER_BUTTON_EVENT 116
#define POWER_BUTTON_NAME "power_button"
static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
static struct mevent *power_button; static struct mevent *power_button;
static sig_t old_power_handler; static sig_t old_power_handler;
static struct mevent *input_evt0; static struct mevent *input_evt0;
static int pwrbtn_fd = -1; static int pwrbtn_fd = -1;
static bool monitor_run;
/* /*
* Reset Control register at I/O port 0xcf9. Bit 2 forces a system * 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 * reset when it transitions from 0 to 1. Bit 1 selects the type of
@ -217,11 +220,8 @@ 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); INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
static void static void
power_button_handler(int signal, enum ev_type type, void *arg) power_button_press_emulation(struct vmctx *ctx)
{ {
struct vmctx *ctx;
ctx = arg;
pthread_mutex_lock(&pm_lock); pthread_mutex_lock(&pm_lock);
if (!(pm1_status & PM1_PWRBTN_STS)) { if (!(pm1_status & PM1_PWRBTN_STS)) {
pm1_status |= PM1_PWRBTN_STS; pm1_status |= PM1_PWRBTN_STS;
@ -230,6 +230,13 @@ power_button_handler(int signal, enum ev_type type, void *arg)
pthread_mutex_unlock(&pm_lock); pthread_mutex_unlock(&pm_lock);
} }
static void
power_button_handler(int signal, enum ev_type type, void *arg)
{
if (arg)
power_button_press_emulation(arg);
}
static void static void
input_event0_handler(int fd, enum ev_type type, void *arg) input_event0_handler(int fd, enum ev_type type, void *arg)
{ {
@ -241,7 +248,7 @@ input_event0_handler(int fd, enum ev_type type, void *arg)
return; return;
if (ev.code == POWER_BUTTON_EVENT && ev.value == 1) if (ev.code == POWER_BUTTON_EVENT && ev.value == 1)
power_button_handler(fd, type, arg); power_button_press_emulation(arg);
} }
/* /*
@ -297,6 +304,31 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler); INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
SYSRES_IO(PM1A_EVT_ADDR, 8); 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,
};
/* /*
* ACPI SMI Command Register * ACPI SMI Command Register
* *
@ -314,6 +346,11 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
switch (*eax) { switch (*eax) {
case ACPI_ENABLE: case ACPI_ENABLE:
pm1_control |= PM1_SCI_EN; pm1_control |= PM1_SCI_EN;
/*
* FIXME: ACPI_ENABLE/ACPI_DISABLE only impacts SCI_EN via SMI
* command register, not impact power button emulation. so need
* to remove all power button emulation from here.
*/
if (power_button == NULL) { if (power_button == NULL) {
/* /*
@ -327,6 +364,10 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
old_power_handler = signal(SIGTERM, SIG_IGN); old_power_handler = signal(SIGTERM, SIG_IGN);
} }
if (input_evt0 == NULL) { 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("/dev/input/event0", O_RDONLY);
if (pwrbtn_fd < 0) if (pwrbtn_fd < 0)
fprintf(stderr, "open input event0 error=%d\n", fprintf(stderr, "open input event0 error=%d\n",
@ -335,6 +376,19 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
input_evt0 = mevent_add(pwrbtn_fd, EVF_READ, input_evt0 = mevent_add(pwrbtn_fd, EVF_READ,
input_event0_handler, ctx, NULL, NULL); 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; break;
case ACPI_DISABLE: case ACPI_DISABLE:
pm1_control &= ~PM1_SCI_EN; pm1_control &= ~PM1_SCI_EN;