展锐8910DM休眠问题的处理主要在于理解底层osiPmSource是如何链接的,理解了osiPmSource的链接机制也就基本上深入理解了休眠机制的处理大致处理流程;
备注:结合处理8910DM 休眠流程,去梳理8910DM 休眠相关的链表处理工作,文档略显粗糙,但基本上是讲解到了核心流程;
1:先来做static osiPmContext_t gOsiPmCtx全局变量的分析
1:老规矩先上代码:
第一部分:
typedef struct
{
bool started;
osiPmSourceHead_t resume_list;
osiPmSourceHead_t active_list;
osiPmSourceHead_t inactive_list;
osiPmSourceHead_t prepare_list;
osiShutdownRegHead_t shutdown_reg_list;
osiPmSleep_t sleep;
uint32_t boot_causes;
osiBootMode_t boot_mode;
uint32_t sleep32k_flags;
} osiPmContext_t;
第二部分:
typedef TAILQ_HEAD(osiPmSourceHead, osiPmSource) osiPmSourceHead_t;
#define TAILQ_HEAD(name, type)
struct name {
struct type tqh_first; / first element */
struct type *tqh_last; / addr of last next element */
TRACEBUF
}
第三部分:结合上述第二部分理解即可看出osiPmSourceHead_t的本质
struct osiPmSourceHead {
struct osiPmSource tqh_first; / first element */
struct osiPmSource *tqh_last; / addr of last next element */
TRACEBUF
}
总结整个static osiPmContext_t gOsiPmCtx结构体的图片:
2:待插入元素typedef struct osiPmSource osiPmSource_t 代码的分析
第一部分:
typedef struct osiPmSource osiPmSource_t;
struct osiPmSource
{
osiPmSourceIter_t resume_iter;
osiPmSourceIter_t state_iter;
uint32_t tag;
void *cb_ctx;
bool active;
osiPmSourceOps_t ops;
};
第二部分:
typedef TAILQ_ENTRY(osiPmSource) osiPmSourceIter_t;
#define TAILQ_ENTRY(type)
struct {
struct type tqe_next; / next element */
struct type *tqe_prev; / address of previous next element */
TRACEBUF
}
第三部分:结合第二部分理解typedef TAILQ_ENTRY(osiPmSource) osiPmSourceIter_t;其就相当于
一下结构体
struct {
struct osiPmSource tqe_next; / next element */
struct osiPmSource *tqe_prev; / address of previous next element */
TRACEBUF
}
总结:struct osiPmSource osiPmSource_t 如下所示
3:初始化流程以及列表插入分析
3.1 第一次初始化
3.2 初始化插入一个元素时
TAILQ_INSERT_TAIL(&d->inactive_list, p, state_iter);
3.3 初始化插入2个元素:
TAILQ_INSERT_TAIL(&d->inactive_list, p, state_iter);
3.4 初始化插入3个元素时:
4:分析一下TAILQ_FOREACH(p, &d->active_list, state_iter)
static osiPmSource_t *prvFindSourceByTag(osiPmContext_t *d, uint32_t tag)
{
osiPmSource_t *p;
TAILQ_FOREACH(p, &d->active_list, state_iter)
{
if (p->tag == tag)
return p;
}
TAILQ_FOREACH(p, &d->inactive_list, state_iter)
{
if (p->tag == tag)
return p;
}
TAILQ_FOREACH(p, &d->prepare_list, state_iter)
{
if (p->tag == tag)
return p;
}
return NULL;
}
首先了解一下这里的宏定义:
#define TAILQ_FOREACH(var, head, field)
for ((var) = ((head)->tqh_first);
(var);
(var) = ((var)->field.tqe_next))
总结如下:核心流程TAILQ_FOREACH 如下图所描述
5:分析一下prvSuspend函数
static uint32_t prvSuspend(osiPmContext_t *d, osiSuspendMode_t mode, int64_t sleep_ms)
{
// when PSM sleep condition isn't satisfied, it will return harmless
osiShutdown(OSI_SHUTDOWN_PSM_SLEEP);
OSI_LOGD(0, "deep sleep mode/%d sleep/%u", mode, (unsigned)sleep_ms);
osiPmSource_t *p;
//执行suspend list中的回调
TAILQ_FOREACH_REVERSE(p, &d->resume_list, osiPmSourceHead, resume_iter)
}
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
for ((var) = ( *( ( (struct headname *)( (head)->tqh_last) )->tqh_last) ); \
(var);
(var) = ( ( ( (struct headname *)( (var)->field.tqe_prev) )->tqh_last) )
5.1:赏析一下TAILQ_FOREACH_REVERSE(p, &d->resume_list, osiPmSourceHead, resume_iter)
TAILQ_FOREACH_REVERSE(p, &d->resume_list, osiPmSourceHead, resume_iter)
我们这边经过转化后
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
//一句代码干了3件事。太厉害了
for ((var) = ( *( ( (struct osiPmSourceHead *)( (head)->tqh_last) )->tqh_last) ); \
(var);
(var) = ( ( ( (struct osiPmSourceHead *)( (var)->field.tqe_prev) )->tqh_last) ) 5