Suspend流程
参考linux2.6.32
Suspend锁流程
Suspend&resume流程
具体看main.c(kernel/power);上层通过属性节点写命令,最终会调到此文件中的state_store函数。
state_store()
{
request_suspend_state();
}
request_suspend_state()@ kernel/power/ earlysuspend.c
{
//early_suspend_work-> early_suspend,suspend处理
queue_work(suspend_work_queue, &early_suspend_work);
//early_suspend_work-> late_resume,resume处理,early suspend的模块resume
queue_work(suspend_work_queue, &late_resume_work);
}
static void early_suspend(struct work_struct *work) @
{
//处理earlysuspend,即一级休眠
list_for_each_entry(pos, &early_suspend_handlers, link) {
if (pos->suspend != NULL)
pos->suspend(pos);
}
// 系统suspend
wake_unlock(&main_wake_lock);
}
void wake_unlock(struct wake_lock *lock)@wakelock.c
{
// suspend_work-> suspend()
queue_work(suspend_work_queue, &suspend_work);
}
suspend()@wakelock.c
{
//判断系统suspend有没有被锁,如果被锁,则中断二级休眠处理
if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
return;
}
// suspend系统
pm_suspend();
}
pm_suspend()@kernel/power/suspend.c
{
enter_state();
}
int enter_state(suspend_state_t state)
{
error = suspend_devices_and_enter(state);
}
suspend_devices_and_enter()
{
error = dpm_suspend_start(PMSG_SUSPEND);//devices suspend
{
error = dpm_suspend(state);
}
suspend_enter();//系统相关suspend
}
static int suspend_enter(suspend_state_t state)
{
//disable all irq
error = dpm_suspend_noirq(PMSG_SUSPEND);
// system dev suspend
error = sysdev_suspend(PMSG_SUSPEND);
}
注意: evdev.c中的evdev_event()->evdev_pass_event ()函数会调用wake_lock_timeout()。功能还不知道
设备处理
int device_add(struct device *dev) ()@drivers/base/core.c
{
device_pm_add(dev);@drivers/base/power/main.c
}
中断处理
原理
系统通过enable_irq_wake()标记中断在系统suspend时不disable,没有标记的irq在系统suspend时会被disable。
static inline int enable_irq_wake(unsigned int irq)
{
return set_irq_wake(irq, 1);
}
int set_irq_wake(unsigned int irq, unsigned int on)
{
if (on) {
desc->status |= IRQ_WAKEUP;// 系统suspend是该中断不会被disable
}
}
实现过程
系统suspend时,先通过dpm_suspend_noirq()disable所有的中断,然后再sysdev_suspend()调用intc的sysdev的suspend函数,恢复desc->status |= IRQ_WAKEUP标记的中断。
/*
*@kernel/power/suspend.c
*/
static int suspend_enter(suspend_state_t state)
{
dpm_suspend_noirq();//关掉所有的中断
{
suspend_device_irqs();
}
/*
*在sys_device的suspend回调函数中唤醒系统suspend时需要保持有效的中断
*rk的架构参考arch/arm/mach-rk2818/gpio.c的
*struct sysdev_class rk2818_gpio_sysclass.suspend= rk2818_gpio_suspend();但是该架构
*的实现函数rk2818_gpio_suspend()实现的不太标准。标准实现见下面的intc_suspend()
*/
sysdev_suspend();
dpm_resume_noirq();//恢复所有被disable的中断
}
其他参考模式
/*
*drivers/sh/intc.c
* intc_sysdev_class. suspend = intc_suspend;@ drivers/sh/intc.c
*/
intc_suspend()
{
switch (state.event) {
case PM_EVENT_SUSPEND:
//将通过enable_irq_wake()函数设置的irq还原为enable状态
for_each_irq_desc(irq, desc) {
if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
intc_enable(irq);
}
break;
}
}