三、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的時(shí)候最終會調(diào)用函數(shù)pm_test_show(),在終端上打印出上面數(shù)組中的字符串,當(dāng)前的模式用[]表示出來。 echo devices > pm_test的時(shí)候會最終調(diào)用到函數(shù)pm_test_store()中去,該函數(shù)中設(shè)置全局變量pm_test_level的值,可以是0-5,分別代表上none ~ freezer。該全局變量會在后面的suspend和resume中被引用到。 memchr函數(shù)說明: 原型:extern void *memchr(void *buf, char ch, unsigned int count); 用法:#include <string.h> 功能:從buf所指內(nèi)存區(qū)域的前count個(gè)字節(jié)查找字符ch。 說明:當(dāng)?shù)谝淮斡龅阶址鹀h時(shí)停止查找。如果成功,返回指向字符ch的指針;否則返回NULL。
四、state屬性文件 power_attr(state)宏定義了一個(gè)struct kobj_attribute結(jié)構(gòu)體state_attr: static struct kobj_attribute state_attr = { .attr = { .name = __stringify(state), .mode = 0644, }, .show = state_show, .store = state_store, } kobj_attribute結(jié)構(gòu)體封裝了struct attribute結(jié)構(gòu)體,新建屬性文件是依據(jù)struct attribute結(jié)構(gòu)體。最終通過函數(shù)kobj_attr_show和kobj_attr_store回調(diào)到實(shí)際的show和store函數(shù)(kobject.c)。
state_show()函數(shù)主要是顯示當(dāng)前系統(tǒng)支持哪幾種省電模式。 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修改了標(biāo)準(zhǔn)linux的休眠喚醒機(jī)制,增加了eraly suspend和late resume機(jī)制,如果是android內(nèi)核,則這個(gè)宏是需要定義的。 [PM_SUSPEND_ON] = "on", #endif [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", }; 該函數(shù)中值得注意的地方應(yīng)該是valid_state(i),這個(gè)函數(shù)是用戶配置的支持省電模式的驗(yàn)證函數(shù),如果沒有這個(gè)驗(yàn)證過程,cat時(shí)候打印出來的模式則是on standby mem,給上層用戶的使用造成困擾。 那這個(gè)valid_state()函數(shù)在哪里定義的呢?一般定義于文件kernel/kernel/power/suspend.c static struct platform_suspend_ops *suspend_ops; void suspend_set_ops(struct platform_suspend_ops *ops) // 該函數(shù)調(diào)用見后面 { 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); }
而實(shí)際平臺的platform_suspend_ops結(jié)構(gòu)體一般都是在文件arch/arm/mach-xxxx/pm.c中進(jìn)行定義,對于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); }; 經(jīng)過后面的代碼分析,得出了如下結(jié)論: 休眠喚醒過程依次會執(zhí)行的函數(shù)是:begin,prepare,prepare_late,enter,wake, finish, end。同顏色的函數(shù)執(zhí)行了恰好相反的工作。休眠的時(shí)候代碼執(zhí)行是停留在函數(shù)enter中,wake之后也是從suspend的時(shí)候停留的地方繼續(xù)運(yùn)行。 至于recover函數(shù)貌似只有在pm_test處于devices的模式下,才會被調(diào)用到。
@ 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); } 而函數(shù)mtk_pm_init()是在函數(shù)mt6516_init_irq()中調(diào)用??梢钥闯鲈撈脚_只支持mem的省電模式。
state_store()函數(shù): 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 //對標(biāo)準(zhǔn)linux而言,這個(gè)宏不存在 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,那么進(jìn)入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內(nèi)核會定義該宏,首先進(jìn)入eraly suspend模式 if (state == PM_SUSPEND_ON || valid_state(state)) { error = 0; request_suspend_state(state); } #else // 標(biāo)準(zhǔn)linux內(nèi)核直接enter_state()函數(shù) error = enter_state(state); // kernel/kernel/power/suspend.c #endif #endif
Exit: return error ? error : n; } |
|