Linux Power Management分析一

来源:互联网 发布:mysql修改密码语句 编辑:程序博客网 时间:2024/06/18 06:29
最近研究marvell平台上的PMU管理机制,算是边学边写吧。 自己是个菜鸟,可能写起来就信马由缰了,毕竟懂得东西实在太少了。

marvell主要PMU管理在pxa3xx_pm.c中,而很多函数是建立在kernel/power目录下的main.c上的。下面先分析main.c文件吧

首先当然是注册了:
static int __init pm_init(void);
    这个函数使用了core_initcall(pm_init); 这个就涉及到linux driver启动顺序的问题。 core_initcall确保可以在比较靠前的顺序进行注册,防止了后面如果有用到这个驱动里的函数,但是此时此驱动还没有注册。(据说如果默认使用module_init,注册顺序是不固定的)。

在pm_init里注册了subsystem,
    subsystem_register(&power_subsys);
当然在进行注册前,先声明了变量power_subsys,使用方法是 decl_subsys(power,NULL,NULL);
可以对应源代码,看看decl_subsys到底干了啥事情,说白了就是初始化呗,声明并初始化了一个叫power_subsys的变量。
##在linux还是蛮常用的嘛。
#define decl_subsys(_name,_type,_uevent_ops) /
struct kset _name##_subsys = { /
        .kobj = { .name = __stringify(_name) }, /
        .ktype = _type, /
        .uevent_ops =_uevent_ops, /
}


Ok,子系统注册完了,该在sys下生成文件了。可以使用sysfs_create_group,在指定目录生成sys文件了,刚开始还很奇怪为啥使用sysfs_create_group,而不是使用sysfs_create_file,后来发现作者为了便于调试,通过宏定义,定义了一个trace的sysfs。这样,使用group函数可以在该目录同时生成两个,不用一步一步分别create了。代码如下:
#ifdef CONFIG_PM_TRACE
。。。。。。
static struct attribute * g[] = {
&state_attr.attr,
&pm_trace_attr.attr,
NULL,
};
#else
static struct attribute * g[] = {
&state_attr.attr,
NULL,
};
#endif /* CONFIG_PM_TRACE */
static struct attribute_group attr_group = {
.attrs = g,
};


Ok,到这里init就完成了。还算是比较简单。但是linux的作者们各种技巧确实给俺留下了深刻的印象。
例如sysfs的operation的声明,已经不止一次看到使用一个宏定义进行sysfs的operation声明了。
power_attr(pm_trace); //这样就声明了一个叫做pm_trace_attr的sysfs操作,attr为pm_trace。
欣赏一下它的原型吧:

#define power_attr(_name) /
static struct subsys_attribute _name##_attr = {/
.attr= {/
.name = __stringify(_name),/
.mode = 0644,/
},/
.show= _name##_show,/
.store= _name##_store,/
}

很帅,至少我认为是这样。特别是有2个以上的sysfs文件是。 不过带来的坏处就是使用source insight时,经常不知所踪。唉。

pm_trace其实是使用sysfs来控制trace的显示,不过看代码,没有看到它控制哪里的trace啊,奇怪。

学学sysfs的show和store。嘿嘿,跑题了,不过谁让俺水平就那么低了,经过坎坷的找工作,刚开始入手linux。

static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
显示文件里的内容,直接使用sprintf就可以啦。 sprintf(buf, "%d/n", pm_trace_enabled);

static ssize_t pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
当往文件里写入时,执行该函数。 sscanf(buf, "%d", &val), 然后pm_trace_enabled = !!val;哈哈。结束了。多么简单。

其实proc文件系统也蛮简单的,以后阅读到的时候再分析吧。

还有有必要看看state的show和store吧,我们可以通过写state文件,来进入不同的PM状态,如standby, mem, lcdfresh, deepsleep等。下面看看咋实现的:
static ssize_t state_show(struct subsystem * subsys, char * buf)

s += sprintf(s,"%s ", pm_states[i]);
。。。。。
s += sprintf(s,"/n");

在state中,将这几种状态都打印出来。
static const char * const pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_STANDBY]= "standby",
[PM_SUSPEND_MEM]= "mem",
#ifdef CONFIG_SOFTWARE_SUSPEND
[PM_SUSPEND_DISK]= "disk",
#endif
[PM_SUSPEND_LCDREFRESH]= "lcdrefresh",
[PM_SUSPEND_DEEPSLEEP]= "deepsleep",
NULL,
};

#define PM_SUSPEND_ON((__force suspend_state_t) 0)
注意__force的用法。:)

static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
如果向state写入standby,则会进入standby模式。
p = memchr(buf, '/n', n);
len = p ? p - buf : n;
剥离回车换行符。memchr函数是在指定的n字节内查找'/n'字符,并返回所在位置。

for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && !strncmp(buf, *s, len))
break;
}
查找匹配的状态。
if (state < PM_SUSPEND_MAX && *s)
error = enter_state(state);
进入指定状态。 enter_state()。。。。。

唉,这才进入main.c文件的核心部分 enter_state。

        
原创粉丝点击