首页 > 代码库 > S3C2416睡眠后唤醒的具体细节
S3C2416睡眠后唤醒的具体细节
〇、引子
书接上回,即:S3C2416睡眠的底层实现。
话说,春梦了无痕,秋鸿有信终需醒。睡醒后的恢复操作以及恢复哪些东西,在s3c_pm_enter(suspend_state_t state)函数的后半部分有具体实现:
arch/arm/plat-samsung/pm.c
<span style="font-family:Courier New;">static int s3c_pm_enter(suspend_state_t state) { ...... /* restore the system state */ s3c_pm_restore_core(); s3c_pm_restore_uarts(); samsung_pm_restore_gpios(); s3c_pm_restored_gpios(); s3c_pm_debug_init(); /* check what irq (if any) restored the system */ s3c_pm_arch_show_resume_irqs(); S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); /* LEDs should now be 1110 */ s3c_pm_debug_smdkled(1 << 1, 0); s3c_pm_check_restore(); /* ok, let's return from sleep */ S3C_PMDBG("S3C PM Resume (post-restore)\n"); return 0; }</span>这里一笔带过。接下来从唤醒源入手,看怎么把指定的外部中断或RTC设置为唤醒源,以及,唤醒源是怎么被内核识别的。
一、插曲:
开始,是从以下两个全局变了入手的,但最后进入了死胡同,出口渺然无踪:
<span style="font-family:Courier New;">unsigned long s3c_irqwake_intmask = 0xffffffffL; unsigned long s3c_irqwake_eintmask = 0xffffffffL;</span>茫茫然时突然想到,为何不从唤醒源处入手?
二、正文:
以IRQ_EINT0作为唤醒源,添加在smdk_machine_init()函数中:
arch/arm/mach-s3c24xx/common-smdk.c
void __init smdk_machine_init(void)
{
request_irq(IRQ_EINT0, button_irq, IRQ_TYPE_EDGE_FALLING, "BUTTON_IRQ_EINT0", NULL);
enable_irq_wake(IRQ_EINT0);
s3c_pm_init();
}
enable_irq_wake()函数的入参作为唤醒源标号:
include/linux/interrupt.h
static inline intenable_irq_wake(unsigned int irq)
{
return irq_set_irq_wake(irq, 1);
}
irq_set_irq_wake()函数的第二个参数非零,就使能唤醒源IRQ_EINT0:
kernel/irq/manage.c
intirq_set_irq_wake(unsigned int irq, unsigned int on)
{
/* Wakeup mode lets this IRQ wake the system from sleep
* states like "suspend to RAM".
*/
if (on) {
if (desc->wake_depth++ == 0) {
ret = set_irq_wake_real(irq, on);
if (ret)
desc->wake_depth = 0;
else
irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
}
}
}
static intset_irq_wake_real(unsigned int irq, unsigned int on)
{
struct irq_desc *desc = irq_to_desc(irq);
int ret = -ENXIO;
if (irq_desc_get_chip(desc)->flags & IRQCHIP_SKIP_SET_WAKE)
return 0;
if (desc->irq_data.chip->irq_set_wake)
ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);
return ret;
}
irq_set_wake是函数指针,原型定义:
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
到了这里,死胡同由出现了;它指向哪里?也即功能的实现实在哪里呢?
这时,先前提到的两个全局变量s3c_irqwake_intmask、s3c_irqwake_eintmask就“粉墨登场”了,irq_set_wake指向函数s3c_irq_wake()就在这两个变量的下面:
arch/arm/mach-s3c24xx/irq-pm.c
s3c_irq_wake()函数提供至关重要的两点信息:
1、作为唤醒源的中断,必须被允许具有唤醒功能,即配置s3c_irqwake_eintallow变量;
2、允许之后,开启该中断的唤醒功能,即取消中断的屏蔽,具体就是s3c_irqwake_intmask变量设置,else分支中。
三、真正想讲明的:
其实,以上内容并不是真正要讲述的,原因很明显,大部分都是函数调用关系。
我真正要说的是:
如果需要查看Linux的源代码,一定记得使用如下网站:
http://lxr.free-electrons.com/ident?i=
至此,Linux内核对睡眠/唤醒的支持流程分析完毕。
S3C2416睡眠后唤醒的具体细节