p { margin-bottom: 0.08in; }
static int __init pm_init( void )
{
power_kobj = kobject_create_and_add( "power" , NULL);
if (!power_kobj)
return -ENOMEM;
return sysfs_create_group(power_kobj, &attr_group);
}
core_initcall(pm_init);
static struct attribute_group attr_group = {
.attrs = g,
};
static struct attribute * g[] = {
&state_attr. attr , // 提供 给上面的一个接口
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
&pm_test_attr.attr, //
#endif
NULL,
};
在 cat /sys/power 下就会显示 disk image_size pm_test pm_trace resume state
在 state 下面就会显示 mem,disk 这两种状态
cat /pm_trace 下面就会显示 1 或者 0
而 state 下面 mem,disk 的显示 是在以下函数功能实现的
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);
}
而 state 下面的更改 是在以下函数功能实现的
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)) { // 这里检测是进入硬盘还是 mm, 由于 6410 没有使用 disk ,所以就进入没有
error = hibernate();
goto Exit;
}
pm_trace 下面就会显示 1 或者 0 ,是在以下函数功能实现的
static ssize_t pm_trace_show( struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d/n" , pm_trace_enabled);
}
对 pm_trace 状态的更改,是在以下函数功能实现的
pm_trace_store( struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
int val;
if (sscanf(buf, "%d" , &val) == 1) {
pm_trace_enabled = !!val;
return n;
}
return -EINVAL;
}
# echo mem > /sys/power/state
1. 驱动在收到这个数据时就调用 state_store 函数来处理输入的状态,函数首先检查是否进
入 Hibernation 状态;如果 Hibernation 状态,那么就会调用 hibernate() 函数进入
Hibernation 状态,如果不是就找到要进入的状态,并调用 suspend 的 enter_state 函数进
入 suspend 状态。我们看到在驱动的实现上把 Suspend 和 Hibernation 区分开了。因此
Linux 的 PM Suspend State 就有两个, standby 和 mem 。注意这里没有 on ,因此你不能
通过发送 on 命来到 /sys/power/state 或其他内核接口函数来唤醒系统,因为这是针对服务
器 /PC 的,只能通过按键的方式(大多数的 PC/ 笔记本都提供了 Suspend 键,也可能就是
Power 键)。
suspend_state_t state = PM_SUSPEND_STANDBY;
if (len == 4 && !strncmp(buf, "disk", len)) {
error = hibernate();
}
if (state < PM_SUSPEND_MAX && *s)
error = enter_state(state);
enter_state 是 suspend.c 里定义的接口函数,用来使系统进入指定的 suspend 状态。好了,
剩下的事情就交给 Suspend 系统来处理了。
2. 接下来调用会调用到 linux /kernel/power/mani.c 中的 enter_stare();
enter_state() 函数会进入和退出 suspend 状态时的一些常规处理,其过程是:
1). 调用 sys_sync();
同步文件系统以保证所有的数据都写到了存储设备上而不会因为 suspend 而丢失数据
2). 调用 suspend_prepare();
当进入到 suspend_prepare() 中以后,它使用 pm_prepare_console() 函数给 suspend
分配一个虚拟终端来输出信息 , 然后调用 pm_notifier_call_chain(PM_SUNPEND_PREPARE)
广播 一个系统要进入 suspend 的 notify, 使用 usermodehelper_disable() 关 掉 用户态的 helper 进 程 , 然 后 一 次 调用 suspend_freeze_processes() 冻 结所有的用户进 程 , 在这里也会 保
存当前进程的所有状态 .
3). 调用 suspend_devices_and_enter(state); 进入指定的 suspend 状态 ; 调用 device_suspend(
PMSG_SUSPEND); 跳到 linux/kernel/drivers/base/power/mani.c 中的 device_suspend(); 会调
用 dpm_prepare(); 然后再调用 dpm_suspend(); 调用 disable_noboot_cpus() 关闭非启动
cpu. 通过调用 suspend_device();
4). 接下来 suspend_enter() 会被调用, arch_suspend_disabled(); 然后
device_power_down(PMSG_SUSPEND); 会调用 suspend_device_noirq(); 最后调用
sysdev_suspend()
5).supend_ops->enter 来使 cpu 进入到 sleep 模 式;
在内核中的 /driver/base/core.c 中的 struct device 中的成员是在 /include/linux/device.h 中
struct device {
struct klist klist_children ;
struct klist_node knode_parent ; /* node in sibling list */
struct klist_node knode_driver ;
struct klist_node knode_bus ;
struct device * parent ;
struct kobject kobj ;
char bus_id [BUS_ID_SIZE]; /* position on parent bus */
const char * init_name ; /* initial name of the device */
struct device_type * type ;
unsigned uevent_suppress :1;
struct semaphore sem ; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type * bus ; /* type of bus device is on */
struct device_driver * driver ; /* which driver has allocated this
device */
void * driver_data ; /* data private to the driver */
void * platform_data ; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power ; 这个很重要进入它的结构可以看到如下信息:
在 /include/linux/pm.h 中可以看到 如下 : enum dpm_state {
DPM_INVALID ,
DPM_ON ,
DPM_PREPARING ,
DPM_RESUMING ,
DPM_SUSPENDING ,
DPM_OFF ,
DPM_OFF_IRQ ,
};
struct dev_pm_info {
pm_message_t power_state ;
unsigned can_wakeup :1;
unsigned should_wakeup :1;
enum dpm_state status ; /* Owned by the PM core */
#ifdef CONFIG_PM_SLEEP
struct list_head entry;
#endif
};