int ongoing;
struct trans_info ti;
GList *waitings;
+ int transient_step;
int max_wait_timer;
} transition_context;
int state;
};
+static const uint64_t transient_scenario_suspending[] = {
+ POWER_STATE_TRANSIENT_SUSPENDING_EARLY,
+ POWER_STATE_TRANSIENT_SUSPENDING,
+ POWER_STATE_TRANSIENT_SUSPENDING_LATE,
+};
+
+static const uint64_t transient_scenario_resuming[] = {
+ POWER_STATE_TRANSIENT_RESUMING_EARLY,
+ POWER_STATE_TRANSIENT_RESUMING,
+ POWER_STATE_TRANSIENT_RESUMING_LATE,
+};
+
+static const struct {
+ int max_step;
+ const uint64_t *scenario;
+} transient[POWER_STATE_MAX_INDEX][POWER_STATE_MAX_INDEX] = {
+ [POWER_STATE_NORMAL_INDEX][POWER_STATE_SLEEP_INDEX] = {
+ .max_step = ARRAY_SIZE(transient_scenario_suspending),
+ .scenario = transient_scenario_suspending,
+ },
+ [POWER_STATE_SLEEP_INDEX][POWER_STATE_NORMAL_INDEX] = {
+ .max_step = ARRAY_SIZE(transient_scenario_resuming),
+ .scenario = transient_scenario_resuming,
+ },
+};
+
static int transition_request_callback(void *data);
static void prepare_transition(const struct trans_info *ti);
static void action_transition(void);
+static uint64_t get_next_state(void);
static void power_action_normal(void *data);
static void power_action_sleep(void *data);
{
const char *signame;
- if (transition_context.ti.next == POWER_STATE_START)
+ uint64_t next = get_next_state();
+
+ if (next == POWER_STATE_START)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START;
- else if (transition_context.ti.next == POWER_STATE_NORMAL)
+ else if (next == POWER_STATE_NORMAL)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL;
- else if (transition_context.ti.next == POWER_STATE_SLEEP)
+ else if (next == POWER_STATE_SLEEP)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SLEEP;
- else if (transition_context.ti.next == POWER_STATE_POWEROFF)
+ else if (next == POWER_STATE_POWEROFF)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_POWEROFF;
- else if (transition_context.ti.next == POWER_STATE_REBOOT)
+ else if (next == POWER_STATE_REBOOT)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_REBOOT;
- else if (transition_context.ti.next == POWER_STATE_EXIT)
+ else if (next == POWER_STATE_EXIT)
signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_EXIT;
+ else if (next == POWER_STATE_TRANSIENT_SUSPENDING_EARLY)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY;
+ else if (next == POWER_STATE_TRANSIENT_SUSPENDING)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING;
+ else if (next == POWER_STATE_TRANSIENT_SUSPENDING_LATE)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE;
+ else if (next == POWER_STATE_TRANSIENT_RESUMING_EARLY)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY;
+ else if (next == POWER_STATE_TRANSIENT_RESUMING)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING;
+ else if (next == POWER_STATE_TRANSIENT_RESUMING_LATE)
+ signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE;
else
return;
gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, signame,
g_variant_new("(ttti)",
transition_context.ti.curr,
- transition_context.ti.next,
+ next,
transition_context.id,
transition_context.ti.reason));
}
g_queue_push_head(transition_queue, memcpy(ti_new, ti, sizeof(struct trans_info)));
}
+// intermediate state of ongoing transition
+// it might be a transient state or a destination state
+static uint64_t get_next_state(void)
+{
+ int curr = POWER_STATE_INDEX(transition_context.ti.curr);
+ int next = POWER_STATE_INDEX(transition_context.ti.next);
+ int step = transition_context.transient_step;
+
+ if (step >= transient[curr][next].max_step)
+ return transition_context.ti.next;
+ else
+ return transient[curr][next].scenario[step];
+}
+
static void init_waiting_list(gpointer data, gpointer udata)
{
uint64_t waiting_state;
struct proc_info *pi = (struct proc_info *) data;
struct change_state_wait *csw = NULL;
- waiting_state = transition_context.ti.next;
+ waiting_state = get_next_state();
if ((pi->state_bitmap & waiting_state) == 0)
return;
return "REBOOT";
if (state == POWER_STATE_EXIT)
return "EXIT";
+ if (state == POWER_STATE_TRANSIENT_SUSPENDING_EARLY)
+ return "SUSPENDING_EARLY";
+ if (state == POWER_STATE_TRANSIENT_SUSPENDING)
+ return "SUSPENDING";
+ if (state == POWER_STATE_TRANSIENT_SUSPENDING_LATE)
+ return "SUSPENDING_LATE";
+ if (state == POWER_STATE_TRANSIENT_RESUMING_EARLY)
+ return "RESUMING_EARLY";
+ if (state == POWER_STATE_TRANSIENT_RESUMING)
+ return "RESUMING";
+ if (state == POWER_STATE_TRANSIENT_RESUMING_LATE)
+ return "RESUMING_LATE";
return "INVALID";
}
static void reload_transition_sequence(GList **sequence)
{
GList *new_sequence = NULL;
+ int curr, next, step;
g_list_free(g_steal_pointer(sequence));
+ curr = POWER_STATE_INDEX(transition_context.ti.curr);
+ next = POWER_STATE_INDEX(transition_context.ti.next);
+
new_sequence = g_list_append(new_sequence, state_abbr_name(transition_context.ti.curr));
+ for (step = 0; step < transient[curr][next].max_step; ++step)
+ new_sequence = g_list_append(new_sequence, state_abbr_name(transient[curr][next].scenario[step]));
new_sequence = g_list_append(new_sequence, state_abbr_name(transition_context.ti.next));
*sequence = new_sequence;
static void action_transition(void)
{
- struct trans_info ti = { 0 , };
- int retval;
+ uint64_t state = get_next_state();
transition_description(0);
- current = transition_context.ti.next;
-
- if (action_on_state[POWER_STATE_INDEX(current)])
- action_on_state[POWER_STATE_INDEX(current)](transition_context.ti.data);
-
- // transition end
- transition_context.ongoing = 0;
- event_wake_unlock(EL_POWER_TRANSITION_STATE);
-
- // trigger next transition if exist
- retval = dequeue_transition(&ti);
- if (retval == 0) {
- prepare_transition(&ti);
+ if (state == transition_context.ti.next) {
+ // it has reached the destination state
+ struct trans_info ti = { 0 , };
+ int retval;
+
+ current = transition_context.ti.next;
+
+ if (action_on_state[POWER_STATE_INDEX(current)])
+ action_on_state[POWER_STATE_INDEX(current)](transition_context.ti.data);
+
+ // transition end
+ transition_context.ongoing = 0;
+ event_wake_unlock(EL_POWER_TRANSITION_STATE);
+
+ // trigger next transition if exist
+ retval = dequeue_transition(&ti);
+ if (retval == 0) {
+ prepare_transition(&ti);
+ trigger_transition();
+ }
+ } else {
+ // step into the next transient state
+ ++transition_context.transient_step;
trigger_transition();
}
}
}
transition_context.ongoing = 0;
+ transition_context.transient_step = 0;
transition_description(1);
}