三、pm_test属性文件读写
int pm_test_level = TEST_NONE;
static const char * const pm_tests[__TEST_AFTER_LAST] = {
[TEST_NONE] = "none",
[TEST_CORE] = "core",
[TEST_CPUS] = "processors",
[TEST_PLATFORM] = "platform",
[TEST_DEVICES] = "devices",
[TEST_FREEZER] = "freezer",
};
// core >> processors >> platform >> devices >> freezer, 控制范围示意
cat pm_test的时候最终会调用函数pm_test_show(),在终端上打印出上面数组中的字符串,当前的模式用[]表示出来。
echo devices > pm_test的时候会最终调用到函数pm_test_store()中去,该函数中设置全局变量pm_test_level的值,可以是0-5,分别代表上none ~ freezer。该全局变量会在后面的suspend和resume中被引用到。
memchr函数说明:
原型:extern void *memchr(void *buf, char ch, unsigned int count);
用法:#include 功能:从buf所指内存区域的前count个字节查找字符ch。 说明:当第一次遇到字符ch时停止查找。如果成功,返回指向字符ch的指针;否则返回NULL。 四、state属性文件 power_attr(state)宏定义了一个struct kobj_attribute结构体state_attr: static struct kobj_attribute state_attr = { .attr = { .name = __stringify(state), .mode = 0644, }, .show = state_show, .store = state_store, } kobj_attribute结构体封装了struct attribute结构体,新建属性文件是依据struct attribute结构体。最终通过函数kobj_attr_show和kobj_attr_store回调到实际的show和store函数(kobject.c)。 state_show()函数主要是显示当前系统支持哪几种省电模式。 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char *s = buf; #ifdef CONFIG_SUSPEND //def int i; for (i = 0; i < PM_SUSPEND_MAX; i++) { if (pm_states[i] && valid_state(i)) s += sprintf(s,"%s ", pm_states[i]); } #endif #ifdef CONFIG_HIBERNATION // undef, don't support STD mode s += sprintf(s, "%s/n", "disk"); #else if (s != buf) /* convert the last space to a newline */ *(s-1) = '/n'; #endif return (s - buf); } @ kernel/include/linux/suspend.h #define PM_SUSPEND_ON ((__force suspend_state_t) 0) #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1) #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) #define PM_SUSPEND_DISK ((__force suspend_state_t) 4) #define PM_SUSPEND_MAX ((__force suspend_state_t) 5) @ kernel/kernel/power/suspend.c const char *const pm_states[PM_SUSPEND_MAX] = { #ifdef CONFIG_EARLYSUSPEND // android修改了标准linux的休眠唤醒机制,增加了eraly suspend和late resume机制,如果是android内核,则这个宏是需要定义的。 [PM_SUSPEND_ON] = "on", #endif [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", }; 该函数中值得注意的地方应该是valid_state(i),这个函数是用户配置的支持省电模式的验证函数,如果没有这个验证过程,cat时候打印出来的模式则是on standby mem,给上层用户的使用造成困扰。 那这个valid_state()函数在哪里定义的呢?一般定义于文件kernel/kernel/power/suspend.c static struct platform_suspend_ops *suspend_ops; void suspend_set_ops(struct platform_suspend_ops *ops) // 该函数调用见后面 { mutex_lock(&pm_mutex); suspend_ops = ops; mutex_unlock(&pm_mutex); } bool valid_state(suspend_state_t state) { return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); } 而实际平台的platform_suspend_ops结构体一般都是在文件arch/arm/mach-xxxx/pm.c中进行定义,对于mtk的平台是文件mtkpm.c,如下: @ kernel/include/linux/suspend.h struct platform_suspend_ops { int (*valid)(suspend_state_t state); int (*begin)(suspend_state_t state); int (*prepare)(void); int (*prepare_late)(void); int (*enter)(suspend_state_t state); void (*wake)(void); void (*finish)(void); void (*end)(void); void (*recover)(void); }; 经过后面的代码分析,得出了如下结论: 休眠唤醒过程依次会执行的函数是:begin,prepare,prepare_late,enter,wake, finish, end。同颜色的函数执行了恰好相反的工作。休眠的时候代码执行是停留在函数enter中,wake之后也是从suspend的时候停留的地方继续运行。 至于recover函数貌似只有在pm_test处于devices的模式下,才会被调用到。 @ kernel/arch/arm/mach-mt6516/mtkpm.c static struct platform_suspend_ops mtk_pm_ops = { .valid = mtk_pm_state_valid, .begin = mtk_pm_begin, .prepare = mtk_pm_prepare, .enter = mtk_pm_enter, .finish = mtk_pm_finish, .end = mtk_pm_end, }; static int mtk_pm_state_valid(suspend_state_t pm_state) { return pm_state == PM_SUSPEND_MEM ; } void mtk_pm_init(void) { _Chip_PM_init(); /* Register and set suspend operation */ suspend_set_ops(&mtk_pm_ops); } 而函数mtk_pm_init()是在函数mt6516_init_irq()中调用。可以看出该平台只支持mem的省电模式。 state_store()函数: static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { #ifdef CONFIG_SUSPEND // set #ifdef CONFIG_EARLYSUSPEND //对标准linux而言,这个宏不存在 suspend_state_t state = PM_SUSPEND_ON; #else suspend_state_t state = PM_SUSPEND_STANDBY; #endif const char * const *s; #endif char *p; int len; int error = -EINVAL; p = memchr(buf, '/n', n); len = p ? p - buf : n; /* First, check if we are requested to hibernate */ if (len == 4 && !strncmp(buf, "disk", len)) { error = hibernate(); // 如果值是disk,那么进入STD模式,该模式暂不讨论 goto Exit; } #ifdef CONFIG_SUSPEND // def for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) break; } if (state < PM_SUSPEND_MAX && *s) #ifdef CONFIG_EARLYSUSPEND // android的linux内核会定义该宏,首先进入eraly suspend模式 if (state == PM_SUSPEND_ON || valid_state(state)) { error = 0; request_suspend_state(state); } #else // 标准linux内核直接enter_state()函数 error = enter_state(state); // kernel/kernel/power/suspend.c #endif #endif Exit: return error ? error : n; }