zoukankan      html  css  js  c++  java
  • linux驱动程序之电源管理之标准linux休眠和唤醒机制分析(二)

    三、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 <string.h>   

    功能:从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;

    }

  • 相关阅读:
    扫移动护理系统mysql数据库视图的Database通讯点报错Caused by: java.sql.SQLException: Value '00000000 00:00:00' can not be represented as java.sql.Timestamp
    ORACLE sql insert case when
    解决超过4000字符的字符串insert的时候报错ORA01461: 仅能绑定要插入LONG列的LONG值
    将92服务器上面的加解密服务run.bat形式改为后台服务形式
    Oracle调整sga_max_size内存参后报ORA00844和ORA00851 SGA_MAX_SIZE 42949672960 cannot be set to more than MEMORY_TARGET 6979321856. 导致数据库连接不上去,提示ORA01034:ORACLE notavailable
    解决MATLAB一直初始化,加速MATLAB(转载)
    WIN7下隐藏或显示Lenovo_Recovery_Q盘(转载)
    flowable流程中心设计(一)
    mysqlgroup by原理
    SpringMVC系列导航
  • 原文地址:https://www.cnblogs.com/0822vaj/p/3935858.html
Copyright © 2011-2022 走看看