字符设备驱动-8.休眠唤醒机制
Posted fuzidage
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符设备驱动-8.休眠唤醒机制相关的知识,希望对你有一定的参考价值。
1 休眠与唤醒
1.APP 调用 read 等函数试图读取数据,比如读取按键;
2.APP 进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回;
3.如果 APP 在内核态,也就是在驱动程序中发现没有数据,则 APP 休眠;
4.当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒 APP;
5.APP 继续运行它的内核态代码,也就是驱动程序中的函数,复制数据到用户空间并马上返回
drv_read函数当没有数据时需要休眠等待有数据唤醒。当按下按键,驱动程序中的中断服务程序被调用,它会记录数据,并唤醒 APP的read函数。
app执行整个过程如下图,可以把它看作被拆分成2段:被叫做“上下文”。
或者这样说:红线所涉及的代码,都是APP调用的。但是按键的中断服务程序,不属于APP的“上下文”,这是突如其来的,当中断发生时,APP1 正在休眠呢。在 APP 的“上下文”,也就是在 APP的执行过程中,它是可以休眠的。
在中断的处理过程中,也就是 gpio_key_irq 的执行过程中,它不能休眠:“中断”怎么能休眠?“中断”休眠了,谁来调度其他 APP 啊?
所以:在中断处理函数中,不能休眠,也就不能调用会导致休眠的函数
1.1 休眠函数
内核源码:include\\linux\\wait.h
参数1:wq: waitqueue等待队列
用来等待条件值,condition不为0则立即返回
参数2:condition
这可以是一个变量,也可以是任何表达式。表示“一直等待,直到 condition为真
1.2 唤醒函数
1.3 使用
1.read函数中进行wait_event_interruptible,因此需要初始化一个wq,用init_waitqueue_head函数进行初始化等待队列。
wait_queue_head_t job_done_wq;
init_waitqueue_head(&job->job_done_wq);
或者用DECLARE_WAIT_QUEUE_HEAD声明定义初始化一起。
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
read函数判断是否有key,有key则直接返回,否则wait_event_interruptible休眠。
wait_event_interruptible(gpio_key_wait, g_key);
2.如果按键按下了,中断isr进行响应,调用wake_up_interruptible,并且设置condition为true.驱动的read函数将会被唤醒。
驱动代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
struct gpio_key
int gpio;
struct gpio_desc *gpiod;
int flag;
int irq;
;
static struct gpio_key *gpio_keys_100ask;
/* 主设备号 */
static int major = 0;
static struct class *gpio_key_class;
static int g_key = 0;
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
//printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
int err;
wait_event_interruptible(gpio_key_wait, g_key);
err = copy_to_user(buf, &g_key, 4);
g_key = 0;
return 4;
static struct file_operations gpio_key_drv =
.owner = THIS_MODULE,
.read = gpio_key_drv_read,
;
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
struct gpio_key *gpio_key = dev_id;
int val;
val = gpiod_get_value(gpio_key->gpiod);
printk("key %d %d\\n", gpio_key->gpio, val);
g_key = (gpio_key->gpio << 8) | val;
wake_up_interruptible(&gpio_key_wait);
return IRQ_HANDLED;
/* 1. 从platform_device获得GPIO
* 2. gpio=>irq
* 3. request_irq
*/
static int gpio_key_probe(struct platform_device *pdev)
int err;
struct device_node *node = pdev->dev.of_node;
int count;
int i;
enum of_gpio_flags flag;
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
count = of_gpio_count(node);
if (!count)
printk("%s %s line %d, there isn\'t any gpio available\\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
for (i = 0; i < count; i++)
gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
if (gpio_keys_100ask[i].gpio < 0)
printk("%s %s line %d, of_get_gpio_flags fail\\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
gpio_keys_100ask[i].irq = gpio_to_irq(gpio_keys_100ask[i].gpio);
for (i = 0; i < count; i++)
err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv); /* /dev/100ask_gpio_key */
gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
if (IS_ERR(gpio_key_class))
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "100ask_gpio_key");
return PTR_ERR(gpio_key_class);
device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */
return 0;
static int gpio_key_remove(struct platform_device *pdev)
//int err;
struct device_node *node = pdev->dev.of_node;
int count;
int i;
device_destroy(gpio_key_class, MKDEV(major, 0));
class_destroy(gpio_key_class);
unregister_chrdev(major, "100ask_gpio_key");
count = of_gpio_count(node);
for (i = 0; i < count; i++)
free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
kfree(gpio_keys_100ask);
return 0;
static const struct of_device_id ask100_keys[] =
.compatible = "100ask,gpio_key" ,
,
;
static struct platform_driver gpio_keys_driver =
.probe = gpio_key_probe,
.remove = gpio_key_remove,
.driver =
.name = "100ask_gpio_key",
.of_match_table = ask100_keys,
,
;
static int __init gpio_key_init(void)
int err;
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
err = platform_driver_register(&gpio_keys_driver);
return err;
static void __exit gpio_key_exit(void)
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
platform_driver_unregister(&gpio_keys_driver);
module_init(gpio_key_init);
module_exit(gpio_key_exit);
MODULE_LICENSE("GPL");
驱动代码2(使用环形buf存放键值)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
struct gpio_key
int gpio;
struct gpio_desc *gpiod;
int flag;
int irq;
;
static struct gpio_key *gpio_keys_100ask;
/* 主设备号 */
static int major = 0;
static struct class *gpio_key_class;
/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;
#define NEXT_POS(x) ((x+1) % BUF_LEN)
static int is_key_buf_empty(void)
return (r == w);
static int is_key_buf_full(void)
return (r == NEXT_POS(w));
static void put_key(int key)
if (!is_key_buf_full())
g_keys[w] = key;
w = NEXT_POS(w);
static int get_key(void)
int key = 0;
if (!is_key_buf_empty())
key = g_keys[r];
r = NEXT_POS(r);
return key;
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);
/* 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
//printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
int err;
int key;
wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());
key = get_key();
err = copy_to_user(buf, &key, 4);
return 4;
/* 定义自己的file_operations结构体 */
static struct file_operations gpio_key_drv =
.owner = THIS_MODULE,
.read = gpio_key_drv_read,
;
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
struct gpio_key *gpio_key = dev_id;
int val;
int key;
val = gpiod_get_value(gpio_key->gpiod);
printk("key %d %d\\n", gpio_key->gpio, val);
key = (gpio_key->gpio << 8) | val;
put_key(key);
wake_up_interruptible(&gpio_key_wait);
return IRQ_HANDLED;
/* 1. 从platform_device获得GPIO
* 2. gpio=>irq
* 3. request_irq
*/
static int gpio_key_probe(struct platform_device *pdev)
int err;
struct device_node *node = pdev->dev.of_node;
int count;
int i;
enum of_gpio_flags flag;
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
count = of_gpio_count(node);
if (!count)
printk("%s %s line %d, there isn\'t any gpio available\\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
for (i = 0; i < count; i++)
gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);
if (gpio_keys_100ask[i].gpio < 0)
printk("%s %s line %d, of_get_gpio_flags fail\\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);
gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;
gpio_keys_100ask[i].irq = gpio_to_irq(gpio_keys_100ask[i].gpio);
for (i = 0; i < count; i++)
err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);
/* 注册file_operations */
major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv); /* /dev/gpio_key */
gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");
if (IS_ERR(gpio_key_class))
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "100ask_gpio_key");
return PTR_ERR(gpio_key_class);
device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */
return 0;
static int gpio_key_remove(struct platform_device *pdev)
//int err;
struct device_node *node = pdev->dev.of_node;
int count;
int i;
device_destroy(gpio_key_class, MKDEV(major, 0));
class_destroy(gpio_key_class);
unregister_chrdev(major, "100ask_gpio_key");
count = of_gpio_count(node);
for (i = 0; i < count; i++)
free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
kfree(gpio_keys_100ask);
return 0;
static const struct of_device_id ask100_keys[] =
.compatible = "100ask,gpio_key" ,
,
;
/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver =
.probe = gpio_key_probe,
.remove = gpio_key_remove,
.driver =
.name = "100ask_gpio_key",
.of_match_table = ask100_keys,
,
;
/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
int err;
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
err = platform_driver_register(&gpio_keys_driver);
return err;
/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
* 卸载platform_driver
*/
static void __exit gpio_key_exit(void)
printk("%s %s line %d\\n", __FILE__, __FUNCTION__, __LINE__);
platform_driver_unregister(&gpio_keys_driver);
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(gpio_key_init);
module_exit(gpio_key_exit);
MODULE_LICENSE("GPL");
app代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./button_test /dev/100ask_button0
*
*/
int main(int argc, char **argv)
int fd;
int val;
/* 1. 判断参数 */
if (argc != 2)
printf("Usage: %s <dev>\\n", argv[0]);
return -1;
/* 2. 打开文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
printf("can not open file %s\\n", argv[1]);
return -1;
while (1)
/* 3. 读文件 */
read(fd, &val, 4);
printf("get button : 0x%x\\n", val);
close(fd);
return 0;
Android休眠唤醒机制简介
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911
Android休眠唤醒机制简介(二)
******************************************************************
作者:sean
日期:2012-11-29
修改历史:2014-1
******************************************************************
接上一节,结合code来分析一下:
具体流程
下面我将分别以两条路线(第一:获得wakelock唤醒锁。第二:系统进入睡眠。)来分别说明各自的流程,让读者对android睡眠唤醒机制有更深入的理解!第一部分:获得wakelock唤醒锁
比如在应用程序中,当获得wakelock唤醒锁的时候,它首先是调用frameworks/base/core/java/android/os/PowerManager.java类中的public void acquire()方法,而该方法通过android特有的通讯机制,会接着调用到PowerManagerService类中的public void acquireWakeLock。
- public void acquire() {
- synchronized (mToken) {
- acquireLocked();
- }
- }
- private void acquireLocked() {
- if (!mRefCounted || mCount++ == 0) {
- // Do this even if the wake lock is already thought to be held (mHeld == true)
- // because non-reference counted wake locks are not always properly released.
- // For example, the keyguard‘s wake lock might be forcibly released by the
- // power manager without the keyguard knowing. A subsequent call to acquire
- // should immediately acquire the wake lock once again despite never having
- // been explicitly released by the keyguard.
- mHandler.removeCallbacks(mReleaser);
- try {
- mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);
- } catch (RemoteException e) {
- }
- mHeld = true;
- }
- }
- @Override // Binder call
- public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
- WorkSource ws) {
- if (lock == null) {
- throw new IllegalArgumentException("lock must not be null");
- }
- if (packageName == null) {
- throw new IllegalArgumentException("packageName must not be null");
- }
- PowerManager.validateWakeLockParameters(flags, tag);
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
- if (ws != null && ws.size() != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS, null);
- } else {
- ws = null;
- }
- final int uid = Binder.getCallingUid();
- final int pid = Binder.getCallingPid();
- final long ident = Binder.clearCallingIdentity();
- try {
- acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
acquireWakeLockInternal()->updatePowerStateLocked()->updateSuspendBlockerLocked()->
- private void updateSuspendBlockerLocked() {
- final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
- final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
- // First acquire suspend blockers if needed.
- if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
- mWakeLockSuspendBlocker.acquire();
- mHoldingWakeLockSuspendBlocker = true;
- }
- if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
- mDisplaySuspendBlocker.acquire();
- mHoldingDisplaySuspendBlocker = true;
- }
- // Then release suspend blockers if needed.
- if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
- mWakeLockSuspendBlocker.release();
- mHoldingWakeLockSuspendBlocker = false;
- }
- if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
- mDisplaySuspendBlocker.release();
- mHoldingDisplaySuspendBlocker = false;
- }
- }
- public PowerManagerService() {
- synchronized (mLock) {
- mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
- mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
- mDisplaySuspendBlocker.acquire();
- mHoldingDisplaySuspendBlocker = true;
- mScreenOnBlocker = new ScreenOnBlockerImpl();
- mDisplayBlanker = new DisplayBlankerImpl();
- mWakefulness = WAKEFULNESS_AWAKE;
- }
- nativeInit();
- nativeSetPowerState(true, true);
- }
- private SuspendBlocker createSuspendBlockerLocked(String name) {
- SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
- mSuspendBlockers.add(suspendBlocker);
- return suspendBlocker;
- }
于是frameworks/base/services/java/com/android/server/PowerManagerService.java类的SuspendBlockerImpl类中的acquire(),便是我们要找的acquire()。
- @Override
- public void acquire() {
- synchronized (this) {
- mReferenceCount += 1;
- if (mReferenceCount == 1) {
- if (DEBUG_SPEW) {
- Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
- }
- nativeAcquireSuspendBlocker(mName);
- }
- }
- }
而该方法调用了com_android_server_power_PowerManagerService.cpp中的nativeAcquireSuspendBlocker。
- static JNINativeMethod gPowerManagerServiceMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit", "()V",
- (void*) nativeInit },
- { "nativeSetPowerState", "(ZZ)V",
- (void*) nativeSetPowerState },
- { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
- (void*) nativeAcquireSuspendBlocker },
- { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
- (void*) nativeReleaseSuspendBlocker },
- { "nativeSetInteractive", "(Z)V",
- (void*) nativeSetInteractive },
- { "nativeSetAutoSuspend", "(Z)V",
- (void*) nativeSetAutoSuspend },
- };
- static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
- ScopedUtfChars name(env, nameStr);
- acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
- }
- int
- acquire_wake_lock(int lock, const char* id)
- {
- initialize_fds();
- // ALOGI("acquire_wake_lock lock=%d id=‘%s‘\n", lock, id);
- if (g_error) return g_error;
- int fd;
- if (lock == PARTIAL_WAKE_LOCK) {
- fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
- }
- else {
- return EINVAL;
- }
- return write(fd, id, strlen(id));
- }
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊?最后的返回语句return write(fd, id, strlen(id))是一个系统调用,这里就实现了与kernel的交互。
kernel/power/main.c中的power_attr宏很多地方用到:
- #define power_attr(_name) \
- static struct kobj_attribute _name##_attr = { \
- .attr = { \
- .name = __stringify(_name), \
- .mode = 0644, \
- }, \
- .show = _name##_show, \
- .store = _name##_store, \
- }
- #ifdef CONFIG_USER_WAKELOCK
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
User-space wake lock api. Write "lockname" or "lockname timeout"
to /sys/power/wake_lock lock and if needed create a wake lock.
Write "lockname" to /sys/power/wake_unlock to unlock a user wake
lock.
- #ifdef CONFIG_PM_WAKELOCKS
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
- static struct kobj_attribute wake_lock_attr = {
- .attr = {
- .name = “wake_lock”,
- .mode = 0644,
- },
- .show = wake_lock_show,
- .store = wake_lock_store,
- }
- static struct kobj_attribute wake_unlock_attr = {
- .attr = {
- .name = “wake_unlock”,
- .mode = 0644,
- },
- .show = wake_unlock_show,
- .store = wake_unlock_store,
- }
- static struct attribute * g[] = {
- &state_attr.attr,
- #ifdef CONFIG_PM_TRACE
- &pm_trace_attr.attr,
- &pm_trace_dev_match_attr.attr,
- #endif
- #ifdef CONFIG_PM_SLEEP
- &pm_async_attr.attr,
- &wakeup_count_attr.attr,
- #ifdef CONFIG_USER_WAKELOCK
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdef CONFIG_PM_AUTOSLEEP
- &autosleep_attr.attr,
- #endif
- #ifdef CONFIG_PM_WAKELOCKS
- &wake_lock_attr.attr,
- &wake_unlock_attr.attr,
- #endif
- #ifdef CONFIG_PM_DEBUG
- &pm_test_attr.attr,
- #endif
- #ifdef CONFIG_PM_SLEEP_DEBUG
- &pm_print_times_attr.attr,
- #endif
- #endif
- #ifdef CONFIG_FREEZER
- &pm_freeze_timeout_attr.attr,
- #endif
- NULL,
- };
- static struct attribute_group attr_group = {
- .attrs = g,
- };
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。
- initialize_fds(void)
- {
- // XXX: should be this:
- //pthread_once(&g_initialized, open_file_descriptors);
- // XXX: not this:
- if (g_initialized == 0) {
- if(open_file_descriptors(NEW_PATHS) < 0)
- open_file_descriptors(OLD_PATHS);
- g_initialized = 1;
- }
- }
其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:
- static int
- open_file_descriptors(const char * const paths[])
- {
- int i;
- for (i=0; i<OUR_FD_COUNT; i++) {
- int fd = open(paths[i], O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
- g_error = errno;
- return -1;
- }
- g_fds[i] = fd;
- }
- g_error = 0;
- return 0;
- }
- const char * const NEW_PATHS[] = {
- "/sys/power/wake_lock",
- "/sys/power/wake_unlock",
- };
总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。
- ssize_t wake_lock_store(
- struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- long timeout;
- struct user_wake_lock *l;
- mutex_lock(&tree_lock);
- l = lookup_wake_lock_name(buf, 1, &timeout);
- if (IS_ERR(l)) {
- n = PTR_ERR(l);
- goto bad_name;
- }
- if (debug_mask & DEBUG_ACCESS)
- pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
- if (timeout)
- wake_lock_timeout(&l->wake_lock, timeout);
- else
- wake_lock(&l->wake_lock);
- bad_name:
- mutex_unlock(&tree_lock);
- return n;
- }
- struct rb_root user_wake_locks;
- static struct user_wake_lock *lookup_wake_lock_name(
- const char *buf, int allocate, long *timeoutptr)
- {
- struct rb_node **p = &user_wake_locks.rb_node;
- struct rb_node *parent = NULL;
- struct user_wake_lock *l;
- int diff;
- u64 timeout;
- int name_len;
- const char *arg;
- /* Find length of lock name and start of optional timeout string */
- arg = buf;
- while (*arg && !isspace(*arg))
- arg++;
- //lock name的长度
- name_len = arg - buf;
- if (!name_len)
- goto bad_arg;
- while (isspace(*arg))
- arg++;
- /* Process timeout string */
- if (timeoutptr && *arg) {
- //(char **)&arg存储的是解析string的结束字符
- timeout = simple_strtoull(arg, (char **)&arg, 0);
- while (isspace(*arg))
- arg++;
- //如果解析string的结束字符不是’\0’
- if (*arg)
- goto bad_arg;
- /* convert timeout from nanoseconds to jiffies > 0 */
- timeout += (NSEC_PER_SEC / HZ) - 1;
- //do_div(a,b)的返回值是余数,商保存到a中
- do_div(timeout, (NSEC_PER_SEC / HZ));
- if (timeout <= 0)
- timeout = 1;
- *timeoutptr = timeout;
- } else if (*arg)
- //timeoutptr为NULL
- goto bad_arg;
- else if (timeoutptr)
- //*arg为0,没有timeout
- *timeoutptr = 0;
- /* Lookup wake lock in rbtree */
- //对于一颗空的红黑树,略过while。wake lock按照name从小到大的顺序存储到user_wake_locks红黑树中
- while (*p) {
- parent = *p;
- l = rb_entry(parent, struct user_wake_lock, node);
- diff = strncmp(buf, l->name, name_len);
- //如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是buf[name_len]会为0
- if (!diff && l->name[name_len])
- diff = -1;
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",
- name_len, buf, l->name, diff);
- if (diff < 0)
- p = &(*p)->rb_left;
- else if (diff > 0)
- p = &(*p)->rb_right;
- else
- return l;
- }
- /* Allocate and add new wakelock to rbtree */
- //allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了
- if (!allocate) {
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: %.*s not found\n",
- name_len, buf);
- return ERR_PTR(-EINVAL);
- }
- l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);
- if (l == NULL) {
- if (debug_mask & DEBUG_FAILURE)
- pr_err("lookup_wake_lock_name: failed to allocate "
- "memory for %.*s\n", name_len, buf);
- return ERR_PTR(-ENOMEM);
- }
- memcpy(l->name, buf, name_len);
- if (debug_mask & DEBUG_NEW)
- pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);
- wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);
- //插入结点,并染成红色
- rb_link_node(&l->node, parent, p);
- rb_insert_color(&l->node, &user_wake_locks);
- return l;
- bad_arg:
- if (debug_mask & DEBUG_ERROR)
- pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",
- name_len, buf, arg);
- return ERR_PTR(-EINVAL);
- }
wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。
- static void wake_lock_internal(
- struct wake_lock *lock, long timeout, int has_timeout)
- {
- int type;
- unsigned long irqflags;
- long expire_in;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- //检查type是否合法
- BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
- //检查是否初始化过
- BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
- #ifdef CONFIG_WAKELOCK_STAT
- if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
- if (debug_mask & DEBUG_WAKEUP)
- pr_info("wakeup wake lock: %s\n", lock->name);
- wait_for_wakeup = 0;
- lock->stat.wakeup_count++;
- }
- if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
- (long)(lock->expires - jiffies) <= 0) {
- wake_unlock_stat_locked(lock, 0);
- lock->stat.last_time = ktime_get();
- }
- #endif
- if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
- lock->flags |= WAKE_LOCK_ACTIVE;
- #ifdef CONFIG_WAKELOCK_STAT
- lock->stat.last_time = ktime_get();
- #endif
- }
- //从inactive_locks上删除
- list_del(&lock->link);
- if (has_timeout) {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
- lock->name, type, timeout / HZ,
- (timeout % HZ) * MSEC_PER_SEC / HZ);
- lock->expires = jiffies + timeout;
- lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
- list_add_tail(&lock->link, &active_wake_locks[type]);
- } else {
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_lock: %s, type %d\n", lock->name, type);
- lock->expires = LONG_MAX;
- lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
- list_add(&lock->link, &active_wake_locks[type]);
- }
- if (type == WAKE_LOCK_SUSPEND) {
- current_event_num++;
- #ifdef CONFIG_WAKELOCK_STAT
- if (lock == &main_wake_lock)
- update_sleep_wait_stats_locked(1);
- else if (!wake_lock_active(&main_wake_lock))
- update_sleep_wait_stats_locked(0);
- #endif
- if (has_timeout)
- expire_in = has_wake_lock_locked(type);
- else
- expire_in = -1;
- if (expire_in > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, start expire timer, "
- "%ld\n", lock->name, expire_in);
- mod_timer(&expire_timer, jiffies + expire_in);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_lock: %s, stop expire timer\n",
- lock->name);
- if (expire_in == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
第二部分:系统进入睡眠
假如现在我们按了PAD上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的- public void goToSleep(long time) {
- try {
- mService.goToSleep(time, GO_TO_SLEEP_REASON_USER);
- } catch (RemoteException e) {
- }
- }
- @Override // Binder call
- public void goToSleep(long eventTime, int reason) {
- if (eventTime > SystemClock.uptimeMillis()) {
- throw new IllegalArgumentException("event time must not be in the future");
- }
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
- final long ident = Binder.clearCallingIdentity();
- try {
- goToSleepInternal(eventTime, reason);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- private void goToSleepInternal(long eventTime, int reason) {
- synchronized (mLock) {
- if (goToSleepNoUpdateLocked(eventTime, reason)) {
- updatePowerStateLocked();
- }
- }
- }
- private void updatePowerStateLocked() {
- if (!mSystemReady || mDirty == 0) {//如果系统没有准备好,或者power state没有发生任何变化,这个方法可以不用执行的
- return;
- }
- if(!SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)) {
- if (isHdmiPlugged()) {
- return;
- }
- }
- // Phase 0: Basic state updates.
- updateIsPoweredLocked(mDirty);
- updateStayOnLocked(mDirty);
- // Phase 1: Update wakefulness.
- // Loop because the wake lock and user activity computations are influenced
- // by changes in wakefulness.
- final long now = SystemClock.uptimeMillis();
- int dirtyPhase2 = 0;
- for (;;) {
- int dirtyPhase1 = mDirty;
- dirtyPhase2 |= dirtyPhase1;
- mDirty = 0;
- updateWakeLockSummaryLocked(dirtyPhase1);
- updateUserActivitySummaryLocked(now, dirtyPhase1);
- if (!updateWakefulnessLocked(dirtyPhase1)) {
- break;
- }
- }
- // Phase 2: Update dreams and display power state.
- updateDreamLocked(dirtyPhase2);
- updateDisplayPowerStateLocked(dirtyPhase2);
- // Phase 3: Send notifications, if needed.
- if (mDisplayReady) {
- sendPendingNotificationsLocked();
- }
- // Phase 4: Update suspend blocker.
- // Because we might release the last suspend blocker here, we need to make sure
- // we finished everything else first!
- updateSuspendBlockerLocked();
- }
Android特有的earlysuspend: request_suspend_state(state)
Linux标准的suspend: enter_state(state)
- 顶
- 0
- 踩
以上是关于字符设备驱动-8.休眠唤醒机制的主要内容,如果未能解决你的问题,请参考以下文章