Linux驱动

L15. 休眠唤醒

2020-08-16  本文已影响0人  开源519

1.休眠方式

在内核中,休眠方式有很多种,可以通过下面命令查看

# cat /sys/power/state  //来得到内核支持哪几种休眠方式. 

常用的休眠方式有freeze,standby, mem, disk

示例:

 # echo standby > /sys/power/state  // 命令系统进入standby休眠.           

2.唤醒方式

当我们休眠时,如果想唤醒,则需要添加中断唤醒源,使得在休眠时,这些中断是设为开启的,当有中断来,则会退出唤醒,常见的中断源有按键,USB等。

3.底层实现

代码参考: kernel/drivers/input/keyboard/gpio_keys.c

static int __maybe_unused gpio_keys_suspend(struct device *dev)
{
……
    enable_irq_wake(irq);
……
    return 0;
}

static int __maybe_unused gpio_keys_resume(struct device *dev)
{
……
    disable_irq_wake(irq);
……
    return 0;
}

static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);

static struct platform_driver gpio_keys_device_driver = {
    .probe      = gpio_keys_probe,
    .shutdown   = gpio_keys_shutdown,
    .driver     = {
        .name   = "gpio-keys",
        .pm = &gpio_keys_pm_ops,
        .of_match_table = gpio_keys_of_match,
        .dev_groups = gpio_keys_groups,
    }
};

注: 上面代码中,gpio_keys_suspend,gpio_keys_resume中没有直接出现enable_irq_wake和disable_irq_wake,但是最终是会调用这俩API。

通过实例发现:休眠唤醒的设计,只需要在gpio_keys_device_driver 中实例driver成员的pm成员。SIMPLE_DEV_PM_OPS是Linux封装的一层结构体:

#ifdef CONFIG_PM_SLEEP
#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
    .suspend = suspend_fn, \
    .resume = resume_fn, \
    .freeze = suspend_fn, \
    .thaw = resume_fn, \
    .poweroff = suspend_fn, \
    .restore = resume_fn,
#else
#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#endif

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops name = { \
    SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

将源代码宏展开:

//static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
const struct dev_pm_ops name = { 
    .suspend = gpio_keys_suspend,
    .resume  = gpio_keys_resume,
}

3.总结

  1. 在实际应用中,需要按键实现休眠唤醒,只需要在platform_driver->driver->pm下实例suspend和resume成员函数即可。然后在suspend和resume中增加按键中断唤醒使能和按键唤醒失能。
  2. 流程:在linux要执行休眠时,换遍历一遍所有注册到内核驱动的suspend函数,执行suspend内部代码;在被唤醒时会遍历resume函数,执行内部代码。
  3. 至于为什么都要执行中断唤醒失能?网上的一种说法是如果在执行enable_irq_wake(irq)之前,中断已经处于可唤醒使能,会出现报错。所以在每次唤醒前先disable_irq_wake(irq),休眠时enable_irq_wake(irq)。
  4. 对于休眠唤醒,Linux内核实现起来很复杂,但是对于驱动开发来讲,使用起来较为方便,这也是操作系统的意义所在:严格的分层思想,复杂的流程由内核实现,并提供API供开发人员使用。学习内核的具体实现对编程功力有很大帮助,后续继续分章节介绍其内核休眠唤醒机制具体的内核实现流程。

参考文章:1.Linux电源管理-休眠与唤醒

如有技术交流需要,请关注“开源519”公众号。


开源519.jpg
上一篇 下一篇

猜你喜欢

热点阅读