字符设备驱动-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。

 

[cpp] view plaincopy技术分享技术分享
 
 
  1. public void acquire() {  
  2.     synchronized (mToken) {  
  3.         acquireLocked();  
  4.     }  
  5. }  
[cpp] view plaincopy技术分享技术分享
 
 
  1. private void acquireLocked() {  
  2.     if (!mRefCounted || mCount++ == 0) {  
  3.         // Do this even if the wake lock is already thought to be held (mHeld == true)  
  4.         // because non-reference counted wake locks are not always properly released.  
  5.         // For example, the keyguard‘s wake lock might be forcibly released by the  
  6.         // power manager without the keyguard knowing.  A subsequent call to acquire  
  7.         // should immediately acquire the wake lock once again despite never having  
  8.         // been explicitly released by the keyguard.  
  9.         mHandler.removeCallbacks(mReleaser);  
  10.         try {  
  11.             mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);  
  12.         } catch (RemoteException e) {  
  13.         }  
  14.         mHeld = true;  
  15.     }  
  16. }  
[cpp] view plaincopy技术分享技术分享
 
 
  1. @Override // Binder call  
  2. public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,  
  3.         WorkSource ws) {  
  4.     if (lock == null) {  
  5.         throw new IllegalArgumentException("lock must not be null");  
  6.     }  
  7.     if (packageName == null) {  
  8.         throw new IllegalArgumentException("packageName must not be null");  
  9.     }  
  10.     PowerManager.validateWakeLockParameters(flags, tag);  
  11.   
  12.     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);  
  13.     if (ws != null && ws.size() != 0) {  
  14.         mContext.enforceCallingOrSelfPermission(  
  15.                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);  
  16.     } else {  
  17.         ws = null;  
  18.     }  
  19.   
  20.     final int uid = Binder.getCallingUid();  
  21.     final int pid = Binder.getCallingPid();  
  22.     final long ident = Binder.clearCallingIdentity();  
  23.     try {  
  24.         acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);  
  25.     } finally {  
  26.         Binder.restoreCallingIdentity(ident);  
  27.     }  
  28. }  

 

acquireWakeLockInternal()->updatePowerStateLocked()->updateSuspendBlockerLocked()->

 

[cpp] view plaincopy技术分享技术分享
 
 
  1. private void updateSuspendBlockerLocked() {  
  2.     final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);  
  3.     final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();  
  4.   
  5.     // First acquire suspend blockers if needed.  
  6.     if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {  
  7.         mWakeLockSuspendBlocker.acquire();  
  8.         mHoldingWakeLockSuspendBlocker = true;  
  9.     }  
  10.     if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {  
  11.         mDisplaySuspendBlocker.acquire();  
  12.         mHoldingDisplaySuspendBlocker = true;  
  13.     }  
  14.   
  15.     // Then release suspend blockers if needed.  
  16.     if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {  
  17.         mWakeLockSuspendBlocker.release();  
  18.         mHoldingWakeLockSuspendBlocker = false;  
  19.     }  
  20.     if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {  
  21.         mDisplaySuspendBlocker.release();  
  22.         mHoldingDisplaySuspendBlocker = false;  
  23.     }  
  24. }  
acquire()是什么函数?需要看一下frameworks/base/services/java/com/android/server/PowerManagerService.java类的构造过程。

 

 

[cpp] view plaincopy技术分享技术分享
 
 
  1. public PowerManagerService() {  
  2.      synchronized (mLock) {  
  3.          mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");  
  4.          mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");  
  5.          mDisplaySuspendBlocker.acquire();  
  6.          mHoldingDisplaySuspendBlocker = true;  
  7.   
  8.          mScreenOnBlocker = new ScreenOnBlockerImpl();  
  9.          mDisplayBlanker = new DisplayBlankerImpl();  
  10.          mWakefulness = WAKEFULNESS_AWAKE;  
  11.      }  
  12.   
  13.      nativeInit();  
  14.      nativeSetPowerState(true, true);  
  15.  }  

 

[cpp] view plaincopy
 
 
  1. private SuspendBlocker createSuspendBlockerLocked(String name) {  
  2.     SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);  
  3.     mSuspendBlockers.add(suspendBlocker);  
  4.     return suspendBlocker;  
  5. }  

 


 

于是frameworks/base/services/java/com/android/server/PowerManagerService.java类的SuspendBlockerImpl类中的acquire(),便是我们要找的acquire()。

 

[cpp] view plaincopy技术分享技术分享
 
 
  1. @Override  
  2. public void acquire() {  
  3.     synchronized (this) {  
  4.         mReferenceCount += 1;  
  5.         if (mReferenceCount == 1) {  
  6.             if (DEBUG_SPEW) {  
  7.                 Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");  
  8.             }  
  9.             nativeAcquireSuspendBlocker(mName);  
  10.         }  
  11.     }  
  12. }  

 

而该方法调用了com_android_server_power_PowerManagerService.cpp中的nativeAcquireSuspendBlocker。
[cpp] view plaincopy技术分享技术分享
 
 
  1. static JNINativeMethod gPowerManagerServiceMethods[] = {  
  2.     /* name, signature, funcPtr */  
  3.     { "nativeInit", "()V",  
  4.             (void*) nativeInit },  
  5.     { "nativeSetPowerState", "(ZZ)V",  
  6.             (void*) nativeSetPowerState },  
  7.     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",  
  8.             (void*) nativeAcquireSuspendBlocker },  
  9.     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",  
  10.             (void*) nativeReleaseSuspendBlocker },  
  11.     { "nativeSetInteractive", "(Z)V",  
  12.             (void*) nativeSetInteractive },  
  13.     { "nativeSetAutoSuspend", "(Z)V",  
  14.             (void*) nativeSetAutoSuspend },  
  15. };  
[cpp] view plaincopy技术分享技术分享
 
 
  1. static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {  
  2.     ScopedUtfChars name(env, nameStr);  
  3.     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());  
  4. }  
函数 acquire_wake_lock()的实现在 power.c中,其定义如下:
[cpp] view plaincopy技术分享技术分享
 
 
  1. int  
  2. acquire_wake_lock(int lock, const char* id)  
  3. {  
  4.     initialize_fds();  
  5.   
  6. //    ALOGI("acquire_wake_lock lock=%d id=‘%s‘\n", lock, id);  
  7.   
  8.     if (g_error) return g_error;  
  9.   
  10.     int fd;  
  11.   
  12.     if (lock == PARTIAL_WAKE_LOCK) {  
  13.         fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];  
  14.     }  
  15.     else {  
  16.         return EINVAL;  
  17.     }  
  18.   
  19.     return write(fd, id, strlen(id));  
  20. }  
到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了。下面就应该是和kernel层进行交互了。
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊?最后的返回语句return write(fd, id, strlen(id))是一个系统调用,这里就实现了与kernel的交互。
kernel/power/main.c中的power_attr宏很多地方用到:

 

[cpp] view plaincopy技术分享技术分享
 
 
  1. #define power_attr(_name) \  
  2. static struct kobj_attribute _name##_attr = {   \  
  3.     .attr   = {             \  
  4.         .name = __stringify(_name), \  
  5.         .mode = 0644,           \  
  6.     },                  \  
  7.     .show   = _name##_show,         \  
  8.     .store  = _name##_store,        \  
  9. }  
[cpp] view plaincopy技术分享技术分享
 
 
  1. #ifdef CONFIG_USER_WAKELOCK  
  2. power_attr(wake_lock);  
  3. power_attr(wake_unlock);  
  4. #endif  
default y
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.
[cpp] view plaincopy技术分享技术分享
 
 
  1. #ifdef CONFIG_PM_WAKELOCKS  
  2. power_attr(wake_lock);  
  3. power_attr(wake_unlock);  
  4. #endif   
default n
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
[cpp] view plaincopy技术分享技术分享
 
 
  1. static struct kobj_attribute wake_lock_attr = {   
  2.     .attr   = {               
  3.         .name = “wake_lock”,      
  4.         .mode = 0644,             
  5.     },                    
  6.     .show   = wake_lock_show,             
  7.     .store  = wake_lock_store,        
  8. }  
[cpp] view plaincopy技术分享技术分享
 
 
  1. static struct kobj_attribute wake_unlock_attr = {     
  2.     .attr   = {               
  3.         .name = “wake_unlock”,    
  4.         .mode = 0644,             
  5.     },                    
  6.     .show   = wake_unlock_show,           
  7.     .store  = wake_unlock_store,          
  8. }  
show和store函数的源码位于kernel/power/userwakelock.c。
[cpp] view plaincopy技术分享技术分享
 
 
  1. static struct attribute * g[] = {  
  2.     &state_attr.attr,  
  3. #ifdef CONFIG_PM_TRACE  
  4.     &pm_trace_attr.attr,  
  5.     &pm_trace_dev_match_attr.attr,  
  6. #endif  
  7. #ifdef CONFIG_PM_SLEEP  
  8.     &pm_async_attr.attr,  
  9.     &wakeup_count_attr.attr,  
  10. #ifdef CONFIG_USER_WAKELOCK  
  11.     &wake_lock_attr.attr,  
  12.     &wake_unlock_attr.attr,  
  13. #endif  
  14. #ifdef CONFIG_PM_AUTOSLEEP  
  15.     &autosleep_attr.attr,  
  16. #endif  
  17. #ifdef CONFIG_PM_WAKELOCKS  
  18.     &wake_lock_attr.attr,  
  19.     &wake_unlock_attr.attr,  
  20. #endif  
  21. #ifdef CONFIG_PM_DEBUG  
  22.     &pm_test_attr.attr,  
  23. #endif  
  24. #ifdef CONFIG_PM_SLEEP_DEBUG  
  25.     &pm_print_times_attr.attr,  
  26. #endif  
  27. #endif  
  28. #ifdef CONFIG_FREEZER  
  29.     &pm_freeze_timeout_attr.attr,  
  30. #endif  
  31.     NULL,  
  32. };  
[cpp] view plaincopy技术分享技术分享
 
 
  1. static struct attribute_group attr_group = {  
  2.     .attrs = g,  
  3. };  
pm_init()->
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。
[cpp] view plaincopy技术分享技术分享
 
 
  1. initialize_fds(void)  
  2. {  
  3.     // XXX: should be this:  
  4.     //pthread_once(&g_initialized, open_file_descriptors);  
  5.     // XXX: not this:  
  6.     if (g_initialized == 0) {  
  7.         if(open_file_descriptors(NEW_PATHS) < 0)  
  8.             open_file_descriptors(OLD_PATHS);  
  9.         g_initialized = 1;  
  10.     }  
  11. }  

其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:

[cpp] view plaincopy技术分享技术分享
 
 
  1. static int  
  2. open_file_descriptors(const char * const paths[])  
  3. {  
  4.     int i;  
  5.     for (i=0; i<OUR_FD_COUNT; i++) {  
  6.         int fd = open(paths[i], O_RDWR);  
  7.         if (fd < 0) {  
  8.             fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);  
  9.             g_error = errno;  
  10.             return -1;  
  11.         }  
  12.         g_fds[i] = fd;  
  13.     }  
  14.   
  15.     g_error = 0;  
  16.     return 0;  
  17. }  

 

[cpp] view plaincopy
 
 
  1. const char * const NEW_PATHS[] = {  
  2.     "/sys/power/wake_lock",  
  3.     "/sys/power/wake_unlock",  
  4. };  

 

总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。

 

 

[cpp] view plaincopy
 
 
  1. ssize_t wake_lock_store(  
  2.     struct kobject *kobj, struct kobj_attribute *attr,  
  3.     const char *buf, size_t n)  
  4. {  
  5.     long timeout;  
  6.     struct user_wake_lock *l;  
  7.   
  8.     mutex_lock(&tree_lock);  
  9.     l = lookup_wake_lock_name(buf, 1, &timeout);  
  10.     if (IS_ERR(l)) {  
  11.         n = PTR_ERR(l);  
  12.         goto bad_name;  
  13.     }  
  14.   
  15.     if (debug_mask & DEBUG_ACCESS)  
  16.         pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);  
  17.   
  18.     if (timeout)  
  19.         wake_lock_timeout(&l->wake_lock, timeout);  
  20.     else  
  21.         wake_lock(&l->wake_lock);  
  22. bad_name:  
  23.     mutex_unlock(&tree_lock);  
  24.     return n;  
  25. }  
[cpp] view plaincopy
 
 
  1. struct rb_root user_wake_locks;  
  2. static struct user_wake_lock *lookup_wake_lock_name(  
  3.     const char *buf, int allocate, long *timeoutptr)  
  4. {  
  5.     struct rb_node **p = &user_wake_locks.rb_node;  
  6.     struct rb_node *parent = NULL;  
  7.     struct user_wake_lock *l;  
  8.     int diff;  
  9.     u64 timeout;  
  10.     int name_len;  
  11.     const char *arg;  
  12.   
  13.     /* Find length of lock name and start of optional timeout string */  
  14.     arg = buf;  
  15.     while (*arg && !isspace(*arg))  
  16.         arg++;  
  17. //lock name的长度  
  18.     name_len = arg - buf;  
  19.     if (!name_len)  
  20.         goto bad_arg;  
  21.     while (isspace(*arg))  
  22.         arg++;  
  23.   
  24.     /* Process timeout string */  
  25.     if (timeoutptr && *arg) {  
  26. //(char **)&arg存储的是解析string的结束字符  
  27.         timeout = simple_strtoull(arg, (char **)&arg, 0);  
  28.         while (isspace(*arg))  
  29.             arg++;  
  30. //如果解析string的结束字符不是’\0’  
  31.         if (*arg)  
  32.             goto bad_arg;  
  33.         /* convert timeout from nanoseconds to jiffies > 0 */  
  34.         timeout += (NSEC_PER_SEC / HZ) - 1;  
  35. //do_div(a,b)的返回值是余数,商保存到a中  
  36.         do_div(timeout, (NSEC_PER_SEC / HZ));  
  37.         if (timeout <= 0)  
  38.             timeout = 1;  
  39.         *timeoutptr = timeout;  
  40.     } else if (*arg)  
  41. //timeoutptr为NULL  
  42.         goto bad_arg;  
  43.     else if (timeoutptr)  
  44. //*arg为0,没有timeout  
  45.         *timeoutptr = 0;  
  46.   
  47.     /* Lookup wake lock in rbtree */  
  48. //对于一颗空的红黑树,略过while。wake lock按照name从小到大的顺序存储到user_wake_locks红黑树中  
  49.     while (*p) {  
  50.         parent = *p;  
  51.         l = rb_entry(parent, struct user_wake_lock, node);  
  52.         diff = strncmp(buf, l->name, name_len);  
  53. //如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是buf[name_len]会为0  
  54.         if (!diff && l->name[name_len])  
  55.             diff = -1;  
  56.         if (debug_mask & DEBUG_ERROR)  
  57.             pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",  
  58.                 name_len, buf, l->name, diff);  
  59.   
  60.         if (diff < 0)  
  61.             p = &(*p)->rb_left;  
  62.         else if (diff > 0)  
  63.             p = &(*p)->rb_right;  
  64.         else  
  65.             return l;  
  66.     }  
  67.   
  68.     /* Allocate and add new wakelock to rbtree */  
  69. //allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了  
  70.     if (!allocate) {  
  71.         if (debug_mask & DEBUG_ERROR)  
  72.             pr_info("lookup_wake_lock_name: %.*s not found\n",  
  73.                 name_len, buf);  
  74.         return ERR_PTR(-EINVAL);  
  75.     }  
  76.     l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);  
  77.     if (l == NULL) {  
  78.         if (debug_mask & DEBUG_FAILURE)  
  79.             pr_err("lookup_wake_lock_name: failed to allocate "  
  80.                 "memory for %.*s\n", name_len, buf);  
  81.         return ERR_PTR(-ENOMEM);  
  82.     }  
  83.     memcpy(l->name, buf, name_len);  
  84.     if (debug_mask & DEBUG_NEW)  
  85.         pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);  
  86.     wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);  
  87. //插入结点,并染成红色  
  88.     rb_link_node(&l->node, parent, p);  
  89.     rb_insert_color(&l->node, &user_wake_locks);  
  90.     return l;  
  91.   
  92. bad_arg:  
  93.     if (debug_mask & DEBUG_ERROR)  
  94.         pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",  
  95.             name_len, buf, arg);  
  96.     return ERR_PTR(-EINVAL);  
  97. }  

 

wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。

[cpp] view plaincopy
 
 
  1. static void wake_lock_internal(  
  2.     struct wake_lock *lock, long timeout, int has_timeout)  
  3. {  
  4.  int type;  
  5.    unsigned long irqflags;  
  6.  long expire_in;  
  7.   
  8.  spin_lock_irqsave(&list_lock, irqflags);  
  9.     type = lock->flags & WAKE_LOCK_TYPE_MASK;  
  10. //检查type是否合法  
  11.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);  
  12. //检查是否初始化过  
  13.   BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));  
  14. #ifdef CONFIG_WAKELOCK_STAT  
  15.    if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {  
  16.      if (debug_mask & DEBUG_WAKEUP)  
  17.           pr_info("wakeup wake lock: %s\n", lock->name);  
  18.        wait_for_wakeup = 0;  
  19.         lock->stat.wakeup_count++;  
  20.    }  
  21.    if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&  
  22.      (long)(lock->expires - jiffies) <= 0) {  
  23.        wake_unlock_stat_locked(lock, 0);  
  24.        lock->stat.last_time = ktime_get();  
  25.   }  
  26. #endif  
  27.  if (!(lock->flags & WAKE_LOCK_ACTIVE)) {  
  28.      lock->flags |= WAKE_LOCK_ACTIVE;  
  29. #ifdef CONFIG_WAKELOCK_STAT  
  30.       lock->stat.last_time = ktime_get();  
  31. #endif  
  32.     }  
  33. //从inactive_locks上删除  
  34.    list_del(&lock->link);  
  35.    if (has_timeout) {  
  36.       if (debug_mask & DEBUG_WAKE_LOCK)  
  37.            pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",  
  38.               lock->name, type, timeout / HZ,  
  39.               (timeout % HZ) * MSEC_PER_SEC / HZ);  
  40.         lock->expires = jiffies + timeout;  
  41.        lock->flags |= WAKE_LOCK_AUTO_EXPIRE;  
  42.         list_add_tail(&lock->link, &active_wake_locks[type]);  
  43.     } else {  
  44.         if (debug_mask & DEBUG_WAKE_LOCK)  
  45.            pr_info("wake_lock: %s, type %d\n", lock->name, type);  
  46.        lock->expires = LONG_MAX;  
  47.         lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;  
  48.        list_add(&lock->link, &active_wake_locks[type]);  
  49.  }  
  50.    if (type == WAKE_LOCK_SUSPEND) {  
  51.         current_event_num++;  
  52. #ifdef CONFIG_WAKELOCK_STAT  
  53.      if (lock == &main_wake_lock)  
  54.             update_sleep_wait_stats_locked(1);  
  55.       else if (!wake_lock_active(&main_wake_lock))  
  56.             update_sleep_wait_stats_locked(0);  
  57. #endif  
  58.         if (has_timeout)  
  59.             expire_in = has_wake_lock_locked(type);  
  60.      else  
  61.             expire_in = -1;  
  62.      if (expire_in > 0) {  
  63.          if (debug_mask & DEBUG_EXPIRE)  
  64.               pr_info("wake_lock: %s, start expire timer, "  
  65.                    "%ld\n", lock->name, expire_in);  
  66.          mod_timer(&expire_timer, jiffies + expire_in);  
  67.       } else {  
  68.             if (del_timer(&expire_timer))  
  69.                if (debug_mask & DEBUG_EXPIRE)  
  70.                   pr_info("wake_lock: %s, stop expire timer\n",  
  71.                        lock->name);  
  72.          if (expire_in == 0)  
  73.              queue_work(suspend_work_queue, &suspend_work);  
  74.       }  
  75.    }  
  76.    spin_unlock_irqrestore(&list_lock, irqflags);  
  77. }  

第二部分:系统进入睡眠

假如现在我们按了PAD上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的
[cpp] view plaincopy
 
 
  1. public void goToSleep(long time) {  
  2.     try {  
  3.         mService.goToSleep(time, GO_TO_SLEEP_REASON_USER);  
  4.     } catch (RemoteException e) {  
  5.     }  
  6. }  
而该函数会调用到PowerManagerService类中的public void goToSleep()方法;
[cpp] view plaincopy
 
 
  1. @Override // Binder call  
  2. public void goToSleep(long eventTime, int reason) {  
  3.     if (eventTime > SystemClock.uptimeMillis()) {  
  4.         throw new IllegalArgumentException("event time must not be in the future");  
  5.     }  
  6.   
  7.     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);  
  8.   
  9.     final long ident = Binder.clearCallingIdentity();  
  10.     try {  
  11.         goToSleepInternal(eventTime, reason);  
  12.     } finally {  
  13.         Binder.restoreCallingIdentity(ident);  
  14.     }  
  15. }  
[cpp] view plaincopy
 
 
  1. private void goToSleepInternal(long eventTime, int reason) {  
  2.     synchronized (mLock) {  
  3.         if (goToSleepNoUpdateLocked(eventTime, reason)) {  
  4.             updatePowerStateLocked();  
  5.         }  
  6.     }  
  7. }  
goToSleepNoUpdateLocked是goToSleep功能的计算者,来决定是否要休眠,而updatePowerStateLocked函数算是功能的执行者,而且这个执行者同时负责执行了很多其他的功能。其实goToSleepNoUpdateLocked并没有真正地让device进行sleep,仅仅只是把PowerManagerService中一些必要的属性进行了赋值,等会在分析updatePowerStateLocked的时候,再给出解释。在PowerManagerService的代码中,有很多的方法的名字中都含有xxxNoUpdateLocked这样的后缀,我觉得这样做大概是因为,都类似于goToSleepNoUpdateLocked方法,并没有真正地执行方法名字所描述的功能,仅仅是更新了一些必要的属性。 所以在Android系统中可以把多个power state属性的多个变化放在一起共同执行的,而真正的功能执行者就是updatePowerStateLocked。
[cpp] view plaincopy
 
 
  1. private void updatePowerStateLocked() {  
  2.        if (!mSystemReady || mDirty == 0) {//如果系统没有准备好,或者power state没有发生任何变化,这个方法可以不用执行的  
  3.            return;  
  4.        }  
  5.   
  6.   if(!SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)) {  
  7.            if (isHdmiPlugged()) {  
  8.                return;  
  9.            }  
  10.    }  
  11.        // Phase 0: Basic state updates.  
  12.        updateIsPoweredLocked(mDirty);  
  13.        updateStayOnLocked(mDirty);  
  14.   
  15.        // Phase 1: Update wakefulness.  
  16.        // Loop because the wake lock and user activity computations are influenced  
  17.        // by changes in wakefulness.  
  18.        final long now = SystemClock.uptimeMillis();  
  19.        int dirtyPhase2 = 0;  
  20.        for (;;) {  
  21.            int dirtyPhase1 = mDirty;  
  22.            dirtyPhase2 |= dirtyPhase1;  
  23.            mDirty = 0;  
  24.   
  25.            updateWakeLockSummaryLocked(dirtyPhase1);  
  26.            updateUserActivitySummaryLocked(now, dirtyPhase1);  
  27.            if (!updateWakefulnessLocked(dirtyPhase1)) {  
  28.                break;  
  29.            }  
  30.        }  
  31.   
  32.        // Phase 2: Update dreams and display power state.  
  33.        updateDreamLocked(dirtyPhase2);  
  34.        updateDisplayPowerStateLocked(dirtyPhase2);  
  35.   
  36.        // Phase 3: Send notifications, if needed.  
  37.        if (mDisplayReady) {  
  38.            sendPendingNotificationsLocked();  
  39.        }  
  40.   
  41.        // Phase 4: Update suspend blocker.  
  42.        // Because we might release the last suspend blocker here, we need to make sure  
  43.        // we finished everything else first!  
  44.        updateSuspendBlockerLocked();  
  45.    }  
对sys/power/state进行读写操作的时候,(linux/kernel/power/main.c)中的state_store()函数会被调用,在该函数中会分成两个分支:
Android特有的earlysuspend: request_suspend_state(state)
Linux标准的suspend: enter_state(state)
 
0

以上是关于字符设备驱动-8.休眠唤醒机制的主要内容,如果未能解决你的问题,请参考以下文章

Linux块设备驱动

触摸屏唤醒实现

android睡眠后唤醒键没有反映

Android休眠唤醒机制简介

Linux嵌入式驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入

Android休眠唤醒机制