近期搜了很多有关Linux PM的相关资料,但是总感觉叙述晦涩难懂,一来是由于对kernel的理解还未到高度,二来确实手头事情太多,没有办法沉下心来阅读code,今天晚上偷了个闲,仔细读了一遍有关pm的技术文档与source code,颇有心得,记于此。
就构架上理解,pm主要有两个目录,一是 kernel/power下的code, 还有一份是 driver/base/power下的code。
kernel/power下的code,则是向kernel的其他module公开了一些pm driver的接口以及pm module的init,以实现对pm的操作。
main.c
static int __init pm_init(void)
{
int error = pm_start_workqueue();
if (error)
return error;
power_kobj = kobject_create_and_add("power", NULL); //在sys下创建一个名为"power"的节点
if (!power_kobj)
return -ENOMEM;
return sysfs_create_group(power_kobj, &attr_group); //在"power"节点下,添加我们所定义的属性。
}
看一下 attr_group, 它是一个attribute group 其中如果我们在complie kernel的时候,定义了CONFIG_PM_DEBUG macro,那么我们就会在power的属性下面看到pm_test的一项值。
power_attr(pm_trace);
#endif /** CONFIG_PM_TRACE */
static struct attribute * g[] = {
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
#ifdef CONFIG_PM_SLEEP
&pm_async_attr.attr,
&wakeup_count_attr.attr,
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
#endif
NULL,
};
static struct attribute_group attr_group = {
.attrs = g,
};
我们对pm的一些控制,就是在对这些属性值进行控制的。对外export的一个很重要的attribute 就是 status.
/***
* state - control system power state.
*
* show() returns what states are supported, which is hard-coded to
* 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
* 'disk' (Suspend-to-Disk).
*
* store() accepts one of those strings, translates it into the
* proper enumerated value, and initiates a suspend transition.
*/
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
#ifdef CONFIG_SUSPEND
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
s += sprintf(s, "%s\n", "disk");
#else
if (s != buf)
/** convert the last space to a newline */
*(s-1) = '\n';
#endif
return (s - buf);
}
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
suspend_state_t state = PM_SUSPEND_STANDBY;
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();
goto Exit;
}
#ifdef CONFIG_SUSPEND
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)
error = enter_state(state); ///根据传递进来的state,进入这个函数进行相应处理。
#endif
Exit:
return error error : n;
}
power_attr(state);
int device_add(struct device *dev)
{
...
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev); ///Add a device to the PM core's list of active devices
...
}
这样,就把我们向设备模型注册的device给加入到pmcore之中了。
今天先扯到这儿吧,明天再搞了。