diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 9486f46ae..6d1826c20 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -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 diff --git a/devicemodel/arch/x86/pm.c b/devicemodel/arch/x86/pm.c index ab9ce18f7..055cbc624 100644 --- a/devicemodel/arch/x86/pm.c +++ b/devicemodel/arch/x86/pm.c @@ -33,12 +33,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #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); diff --git a/devicemodel/arch/x86/power_button.c b/devicemodel/arch/x86/power_button.c new file mode 100644 index 000000000..97477ef8c --- /dev/null +++ b/devicemodel/arch/x86/power_button.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } +} diff --git a/devicemodel/include/acpi.h b/devicemodel/include/acpi.h index 43856583f..775a71d46 100644 --- a/devicemodel/include/acpi.h +++ b/devicemodel/include/acpi.h @@ -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_ */