首页 > 代码库 > 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睡眠后唤醒的具体细节