linux待机唤醒_Linux电源管理-休眠与唤醒

本文详细介绍了Linux系统中的休眠和唤醒过程,包括休眠方式(freeze、standby、mem、disk)及其区别,以及唤醒方式。特别讨论了如何通过按键驱动作为唤醒源,涉及平台设备注册、中断处理、防抖动机制和电源管理操作。通过对内核源码的分析,展示了按键驱动如何注册、休眠函数如何调用`enable_irq_wake()`以及中断服务函数如何利用`pm_stay_awake()`和`pm_relax()`处理唤醒事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.休眠方式

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

# cat /sys/power/state

//来得到内核支持哪几种休眠方式.

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

freeze:  冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高

standby:除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高

mem:      将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高

disk:      将运行状态数据存到硬盘,然后关机,唤醒最慢

示例:

# echo standby > /sys/power/state

// 命令系统进入standby休眠.

2.唤醒方式

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

3.以按键驱动为例(基于内核3.10.14)

在内核中,有个input按键子系统"gpio-keys"(位于driver/input/keyboard/gpio.keys.c),该平台驱动platform_driver已经在内核中写好了(后面会简单分析)

我们只需要在内核启动时,注册"gpio-keys"平台设备platform_device,即可实现一个按键驱动.

3.1首先使板卡支持input按键子系统(基于mips君正X1000的板卡)

查看Makefile,找到driver/input/keyboard/gpio.keys.c需要CONFIG_KEYBOARD_GPIO宏

方式1-修改对应板卡的defconfig文件,添加宏:

CONFIG_INPUT=y                            //支持input子系统(加载driver/input文件)

CONFIG_INPUT_KEYBOARD=y             //支持input->keyboards(加载driver/input/keyboard文件)

CONFIG_KEYBOARD_GPIO=y                  //支持input->keyboards->gpio按键(加载gpio.keys.c)

方式2-进入make menuconfig

-> Device Drivers

-> Input device support

->  [*]Keyboards

[*]  GPIO Buttons

3.2修改好后,接下来写my_button.c文件,来注册platform_device

#include

#include

#include

struct gpio_keys_button __attribute__((weak)) board_buttons[] = {

{

.gpio                = GPIO_PB(31),    //按键引脚

.code  = KEY_POWER,                    //用来定义按键产生事件时,要上传什么按键值

.desc                = "power key",    //描述信息,不填的话会默认设置为"gpio-keys"

.wakeup          =1,                  //设置为唤醒源

. debounce_interval =10,                //设置按键防抖动时间,也可以不设置

.type                = EV_KEY,

.active_low    = 1,                  //低电平有效

},

};

static struct gpio_keys_platform_data  board_button_data = {

.buttons  = board_buttons,

.nbuttons        = ARRAY_SIZE(board_buttons),

};

struct platform_device  my_button_device = {

.name              = "gpio-keys",

.id            = -1,

.num_resources      = 0,

.dev          = {

.platform_data      = &board_button_data,

}

};

static int __init button_base_init(void)

{

platform_device_register(&my_button_device);

return 0;

}

arch_initcall(button_base_init);

上面的arch_initcall()表示:

会将button_base_init函数放在内核链接脚本.initcall3.init段中,然后在内核启动时,会去读链接脚本,然后找到button_base_init()函数,并执行它.

通常,在内核中,platform 设备的初始化(注册)用arch_initcall()调用

而驱动的注册则用module_init()调用,因为module_init()在arch_initcall()之后才调用

因为在init.h中定义:

#define pure_initcall(fn)                  __define_initcall(fn, 0)

#define core_initcall(fn)                  __define_initcall(fn, 1)

#define core_initcall_sync(fn)                __define_initcall(fn, 1s)

#define postcore_initcall(fn)          __define_initcall(fn, 2)

#define postcore_initcall_sync(fn)        __define_initcall(fn, 2s)

#define arch_initcall(fn)        __define_initcall(fn, 3)            // arch_initcall()优先级为3,比module_init()先执行

#define arch_initcall_sync(fn)                __define_initcall(fn, 3s)

#define subsys_initcall(fn)              __define_initcall(fn, 4)

#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)

#define fs_initcall(fn)                      __define_initcall(fn, 5)

#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)

#define rootfs_initcall(fn)              __define_initcall(fn, rootfs)

#define device_initcall(fn)              __define_initcall(fn, 6)                    //module_init()优先级为6

#define device_initcall_sync(fn)    __define_initcall(fn, 6s)

#define late_initcall(fn)          __define_initcall(fn, 7)

#define late_initcall_sync(fn)   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值