3.Linux休眠锁

1.Android的休眠机制

Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作。wake_lock一般在关闭lcd、tp但系统仍然需要正常运行的情况下使用,比如听歌、传输很大的文件等。
wake lock - wakelock在android的电源管理系统中扮演一个核心的角色,wakelock是一种锁的机制, 只要有task拿着这个锁, 系统就无法进入休眠, 可以被用户态进程和内核线程获得。这个锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动标准linux的那套休眠机制机制来进入休眠。

2.driver层wake_lock的实现

a.相关文件:
kernel/kernel/power/wakelock.c
kernel/include/linux/wakelock.h

enum {  
    WAKE_LOCK_SUSPEND, // 阻止进入深度休眠模式  
    WAKE_LOCK_IDLE,    // 阻止进入空闲模式  
    WAKE_LOCK_TYPE_COUNT  
};  
  
struct wake_lock {  
#ifdef CONFIG_HAS_WAKELOCK  
    struct list_head    link;     // 链表节点  
    int                 flags;    // 标志  
    const char         *name;     // 名称  
    unsigned long       expires;  // 超时时间  
#ifdef CONFIG_WAKELOCK_STAT  
    struct {  
        int             count;         // 使用计数  
        int             expire_count;  // 超时计数  
        int             wakeup_count;  // 唤醒计数  
        ktime_t         total_time;    // 锁使用时间  
        ktime_t         prevent_suspend_time;  // 锁阻止休眠的时间  
        ktime_t         max_time;      // 锁使用时间最长的一次  
        ktime_t         last_time;     // 锁上次操作时间  
    } stat;  
#endif  
#endif  
};  

可以看到wake_lock按功能分为休眠锁和空闲锁两种类型,用于阻止系统进入深度休眠模式或者空闲模式。
b.wake_lock对外提供的操作接口:

void wake_lock_init(struct wake_lock *lock, int type, const char *name);  //用于初始化一个新锁,type参数指定了锁的类型
void wake_lock_destroy(struct wake_lock *lock);  //注销一个锁
void wake_lock(struct wake_lock *lock);  //激活锁(永久锁)
void wake_lock_timeout(struct wake_lock *lock, long timeout);  //激活锁(超时锁)
void wake_unlock(struct wake_lock *lock);  //解锁(无效锁)
int wake_lock_active(struct wake_lock *lock);  //判断锁当前是否有效,如果有效则返回非0值
long has_wake_lock(int type);  //判断系统中是否还存在有效的type型锁,如果存在超时锁则返回最长的一个锁的超时时间,如果存在永久锁则返回-1,如果系统中不存在有效锁则返回0

3.实例

案例:展讯平台深睡后tp中断唤不醒CPU,导致如手势、tp模拟距离传感功能休眠后唤不醒的bug,这时就可以在驱动中加入休眠锁来阻止CPU深睡。

#include   
struct wake_lock ps_wakelock;//定义锁

//probe中添加:
wake_lock_init(&ps_wakelock, WAKE_LOCK_SUSPEND, "elan-touchscreen");//初始化锁

//suspend中:
wake_lock(&ps_wakelock); //激活锁(上锁)

//resume中:
wake_unlock(&ps_wakelock); //解锁

//remove中:
wake_lock_destroy(&ps_wakelock); //销毁锁

注:也可在pin-map里面修改中断脚gpio的模式为eic模式使中断可以唤醒CPU:
{REG_PIN_EXTINT0, BIT_PIN_SLP_AP|BIT_PIN_NULL|BITS_PIN_DS(1)|BITS_PIN_AF(3)|BIT_PIN_WPU|BIT_PIN_SLP_WPU|BIT_PIN_SLP_IE},//CTP_INT
参考:
http://blog.csdn.net/qq_20678703/article/details/52189274
另见使用enable_irq_wake的方法(待验证):
enable_irq():用于使能中断,只在系统正常运行状态下产生的IRQ会上报。
enable_irq_wake():用于使能中断,不仅在系统正常运行状态下产生的IRQ会上报,同时在系统休眠的情况下产生的IRQ会上报。

你可能感兴趣的:(Linux-驱动)