--- /dev/null
+#include <libsyscommon/list.h>
+#include <libsyscommon/file.h>
+#include <libsyscommon/ini-parser.h>
+#include <hal/device/hal-board.h>
+
+#include "power-state-manager.h"
+
+#define INIT_CONF_PATH "/etc/deviced/init.conf"
+
+static struct trans_info initial_transition_info = {
+ .reason = -1,
+ .curr = PSM_START,
+ .next = PSM_NORMAL,
+};
+
+static void parse_transition_info(const char *action)
+{
+ char curr[16] = { 0, };
+ char next[16] = { 0, };
+
+ if (sscanf(action, "%15[^,],%15s", curr, next) == 2) {
+ initial_transition_info.curr = convert_action_string_to_psm_state(curr);
+ initial_transition_info.next = convert_action_string_to_psm_state(next);
+ }
+}
+
+static void parse_initial_transition_info(const struct parse_result *result)
+{
+ GList *elem;
+ struct section_property *prop;
+
+ SYS_G_LIST_FOREACH(result->props, elem, prop) {
+ if (MATCH(prop->key, "Enum"))
+ initial_transition_info.reason = atoi(prop->value);
+ else if (MATCH(prop->key, "Action"))
+ parse_transition_info(prop->value);
+ }
+}
+
+static int parse_matching_bootreason(const struct parse_result *result, void *data)
+{
+ GList *elem;
+ struct section_property *prop;
+ char *bootreason = (char *) data;
+
+ if (!MATCH(result->section, "EVENT_ACTION"))
+ return 0;
+
+ SYS_G_LIST_FOREACH(result->props, elem, prop) {
+ if (MATCH(prop->key, "BootReason") && MATCH(prop->value, bootreason))
+ parse_initial_transition_info(result);
+ }
+
+ return 0;
+}
+
+void parse_initial_transition(void *data)
+{
+ int retval;
+ char bootreason[64] = "Unknown";
+ GList **head = (GList **) data;
+
+ if (!head)
+ return;
+
+ retval = hal_device_board_get_boot_reason(bootreason, sizeof(bootreason));
+ if (retval == 0)
+ libsys_config_parse_by_section(INIT_CONF_PATH, parse_matching_bootreason, bootreason);
+
+ CRITICAL_LOG("BootReason=%s", bootreason);
+
+ *head = g_list_append(*head, &initial_transition_info);
+}
#include "power-dbus.h"
#include "power-state-wait.h"
#include "power-event-lock.h"
+#include "power-config-parse.h"
#define EVENT_TYPE_SLEEP 0
#define EVENT_TYPE_WAKEUP 1
char *psm_name[PSM_MAX] = {
+ [PSM_START] = "PSM_START",
[PSM_NORMAL] = "PSM_NORMAL",
[PSM_SLEEP] = "PSM_SLEEP",
[PSM_POWEROFF] = "PSM_POWEROFF",
};
static guint64 state_transition_counter = 0;
-static enum psm_state current;
+static enum psm_state current = PSM_START;
static void psm_wake_unlock(void)
{
{
// mapping deviced state to capi signame
static const char *capi_signame[PSM_MAX] = {
+ [PSM_START] = SIGNAME_CHANGE_STATE_TO_START,
[PSM_NORMAL] = SIGNAME_CHANGE_STATE_TO_NORMAL,
[PSM_SLEEP] = SIGNAME_CHANGE_STATE_TO_SLEEP,
[PSM_POWEROFF] = SIGNAME_CHANGE_STATE_TO_POWEROFF,
// mapping deviced state to capi state
static const guint64 capi_state[PSM_MAX] = {
+ [PSM_START] = POWER_STATE_START,
[PSM_NORMAL] = POWER_STATE_NORMAL,
[PSM_SLEEP] = POWER_STATE_SLEEP,
[PSM_POWEROFF] = POWER_STATE_POWEROFF,
g_variant_new("(ttti)", capi_state[ti->curr], capi_state[ti->next], state_transition_counter, ti->reason));
}
+static void psm_transition_start_to_normal(const struct trans_info *ti)
+{
+ current = PSM_NORMAL;
+
+ device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
+ broadcast_transition_info(ti);
+}
+
+static void psm_transition_start_to_sleep(const struct trans_info *ti)
+{
+ int waiting;
+
+ current = PSM_SLEEP;
+
+ device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
+ broadcast_transition_info(ti);
+ waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock);
+ if (waiting > 0) {
+ _D("Defer wake unlock");
+ return;
+ }
+
+ psm_wake_unlock();
+}
+
static void psm_transition_normal_to_normal(const struct trans_info *ti)
{
broadcast_transition_info(ti);
{
current = PSM_NORMAL;
- broadcast_transition_info(ti);
device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
+ broadcast_transition_info(ti);
update_change_state_wait(state_transition_counter, ti, NULL);
}
{
int waiting;
- broadcast_transition_info(ti);
device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
+ broadcast_transition_info(ti);
waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock);
if (waiting > 0) {
_D("Defer wake unlock");
/* transition */
++state_transition_counter;
- if (current == PSM_NORMAL) {
+ if (current == PSM_START) {
+ if (next == PSM_NORMAL)
+ psm_transition_start_to_normal(ti);
+ else if (next == PSM_SLEEP)
+ psm_transition_start_to_sleep(ti);
+ } else if (current == PSM_NORMAL) {
if (next == PSM_NORMAL)
psm_transition_normal_to_normal(ti);
else if (next == PSM_SLEEP)
return 0;
}
-void power_state_manager_init(void *data)
+static int defer_autosleep_enable(void *data)
{
- /* initialize state */
- current = PSM_NORMAL;
+ /* Deferred autosleep enable,
+ * This prevents system go suspend during booting */
device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL);
- device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
+ return 0;
+}
+
+void power_state_manager_init(void *data)
+{
+ GList *initial_ti = NULL;
+
+ register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, defer_autosleep_enable);
register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, psm_transition_state_cb);
power_plugin_dbus_init(NULL);
power_event_lock_init();
+
+ /* initialize the power state */
+ parse_initial_transition(&initial_ti);
+ psm_transition_state_cb(initial_ti);
+ g_list_free(initial_ti);
}
static const struct device_ops power_state_manager_device_ops = {