blob: de6d7959e3d0855493302c9deffa9cf10b2133f7 [file] [log] [blame]
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "common.h"
#include "task.h"
#include "usb_pd.h"
#include "usb_sm.h"
#include "util.h"
#include "console.h"
void init_state(int port, struct sm_obj *obj, sm_state target)
{
#if (CONFIG_SM_NESTING_NUM > 0)
int i;
sm_state tmp_super[CONFIG_SM_NESTING_NUM];
#endif
obj->last_state = NULL;
obj->task_state = target;
#if (CONFIG_SM_NESTING_NUM > 0)
/* Prepare to execute all entry actions of the target's super states */
/*
* Get targets super state. This will be NULL if the target
* has no super state
*/
tmp_super[CONFIG_SM_NESTING_NUM - 1] =
(sm_state)(uintptr_t)target(port, SUPER_SIG);
/* Get all super states of the target */
for (i = CONFIG_SM_NESTING_NUM - 1; i > 0; i--) {
if (tmp_super[i] != NULL)
tmp_super[i - 1] =
(sm_state)(uintptr_t)tmp_super[i](port, SUPER_SIG);
else
tmp_super[i - 1] = NULL;
}
/* Execute all super state entry actions in forward order */
for (i = 0; i < CONFIG_SM_NESTING_NUM; i++)
if (tmp_super[i] != NULL)
tmp_super[i](port, ENTRY_SIG);
#endif
/* Now execute the target entry action */
target(port, ENTRY_SIG);
}
int set_state(int port, struct sm_obj *obj, sm_state target)
{
#if (CONFIG_SM_NESTING_NUM > 0)
int i;
int no_execute;
sm_state tmp_super[CONFIG_SM_NESTING_NUM];
sm_state target_super;
sm_state last_super;
sm_state super;
/* Execute all exit actions is reverse order */
/* Get target's super state */
target_super = (sm_state)(uintptr_t)target(port, SUPER_SIG);
tmp_super[0] = obj->task_state;
do {
/* Execute exit action */
tmp_super[0](port, EXIT_SIG);
/* Get super state */
tmp_super[0] =
(sm_state)(uintptr_t)tmp_super[0](port, SUPER_SIG);
/*
* No need to execute a super state's exit action that has
* shared ancestry with the target.
*/
super = target_super;
while (super != NULL) {
if (tmp_super[0] == super) {
tmp_super[0] = NULL;
break;
}
/* Get target state next super state if it exists */
super = (sm_state)(uintptr_t)super(port, SUPER_SIG);
}
} while (tmp_super[0] != NULL);
/* All done executing the exit actions */
#else
obj->task_state(port, EXIT_SIG);
#endif
/* update the state variables */
obj->last_state = obj->task_state;
obj->task_state = target;
#if (CONFIG_SM_NESTING_NUM > 0)
/* Prepare to execute all entry actions of the target's super states */
tmp_super[CONFIG_SM_NESTING_NUM - 1] =
(sm_state)(uintptr_t)target(port, SUPER_SIG);
/* Get all super states of the target */
for (i = CONFIG_SM_NESTING_NUM - 1; i > 0; i--) {
if (tmp_super[i] != NULL)
tmp_super[i - 1] =
(sm_state)(uintptr_t)tmp_super[i](port, SUPER_SIG);
else
tmp_super[i - 1] = NULL;
}
/* Get super state of last state */
last_super = (sm_state)(uintptr_t)obj->last_state(port, SUPER_SIG);
/* Execute all super state entry actions in forward order */
for (i = 0; i < CONFIG_SM_NESTING_NUM; i++) {
/* No super state */
if (tmp_super[i] == NULL)
continue;
/*
* We only want to execute the target state's super state entry
* action if it doesn't share a super state with the previous
* state.
*/
super = last_super;
no_execute = 0;
while (super != NULL) {
if (tmp_super[i] == super) {
no_execute = 1;
break;
}
/* Get last state's next super state if it exists */
super = (sm_state)(uintptr_t)super(port, SUPER_SIG);
}
/* Execute super state's entry */
if (!no_execute)
tmp_super[i](port, ENTRY_SIG);
}
#endif
/* Now execute the target entry action */
target(port, ENTRY_SIG);
return 0;
}
void exe_state(int port, struct sm_obj *obj, enum signal sig)
{
#if (CONFIG_SM_NESTING_NUM > 0)
sm_state state = obj->task_state;
do {
state = (sm_state)(uintptr_t)state(port, sig);
} while (state != NULL);
#else
obj->task_state(port, sig);
#endif
}
unsigned int do_nothing_exit(int port)
{
return 0;
}
unsigned int get_super_state(int port)
{
return RUN_SUPER;
}