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 <linux/platform_device.h> #include <linux/gpio_keys.h> #include <linux/input.h> 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 d