最近研究如何让Android不休眠。听组里人说,机器在充电的时候不休眠。我试了一下,确实是,串口可以使用(CONFIG_PM_DEBUG并没有打开)。
这个时候,LCD显示屏是休眠了,触摸屏也休眠了,其他的比如重力传感器等就没有看了,但是标准的Linux系统并没有进入休眠。看了网上好多关于Android系统的休眠与唤醒
例子,感觉有些懵懵懂懂的。于是,还是看内核代码吧。
Android在标准的Linux休眠与唤醒机制上又加了一层,就是early_suspend / late_resume。顾名思意,使用early_suspend()进行休眠的设备,它休眠的时刻早于其他设备,使用late_resume()唤醒的设备,它被唤醒的时刻要晚于其他设备。这对函数通常成对出现,当内核打开了CONFIG_EARLY_SUSPEND(Android默认打开)后,就可以使
用这组函数来代替驱动中标准的 suspend / resume接口。
好了,讲到early_suspend和late_resume,似乎必须要扯到一种叫做wake_lock的锁定机制了。其实,单纯从某个设备的驱动程序上来讲,未必需要用到wake_lock机制,
比如我们的触摸屏驱动中使用了early_suspend,就没有使用wake_lock.
目前,我了解到的,wake_lock的用途只有一个,那就是防止系统进入休眠(这里的休眠,指的是标准的Linux的休眠,不包含使用early_suspend()进行休眠的设备,
使用early_suspend()的设备,在系统还有wake_lock锁的时候,也是要休眠的)。
好吧,现在是时候分析下Android/Linux的休眠与唤醒了,虽然好多先人 都已经讲了这些,而且讲的还不错,这里我还是要提一下。
root@android:/ # ls /sys/power/
pm_async
state
wait_for_fb_sleep
wait_for_fb_wake
wake_lock
wake_unlock
wakeup_count
这里,我只关注state,当state 的值变化时,内核会调用
[cpp] view plaincopyprint?
- static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- #ifdef CONFIG_SUSPEND
- #ifdef CONFIG_EARLYSUSPEND
- suspend_state_t state = PM_SUSPEND_ON;
- #else
- suspend_state_t state = PM_SUSPEND_STANDBY;
- #endif
- const char * const *s;
- #endif
- char *p;
- int len;
- int error = -EINVAL;
-
- p = memchr(buf, '\n', n);
- len = p ? p - buf : n;
-
-
- if (len == 4 && !strncmp(buf, "disk", len)) {
- error = hibernate();
- goto Exit;
- }
-
- #ifdef CONFIG_SUSPEND
- for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
- if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
- break;
- }
- if (state < PM_SUSPEND_MAX && *s)
- #ifdef CONFIG_EARLYSUSPEND
- if (state == PM_SUSPEND_ON || valid_state(state)) {
- error = 0;
- request_suspend_state(state);
- }
- #else
- error = enter_state(state);
- #endif
- #endif
-
- Exit:
- return error ? error : n;
- }
-
- power_attr(state);
[cpp] view plain copy print ?
- static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- #ifdef CONFIG_SUSPEND
- #ifdef CONFIG_EARLYSUSPEND
- suspend_state_t state = PM_SUSPEND_ON;
- #else
- suspend_state_t state = PM_SUSPEND_STANDBY;
- #endif
- const char * const *s;
- #endif
- char *p;
- int len;
- int error = -EINVAL;
-
- p = memchr(buf, '\n', n);
- len = p ? p - buf : n;
-
-
- if (len == 4 && !strncmp(buf, "disk", len)) {
- error = hibernate();
- goto Exit;
- }
-
- #ifdef CONFIG_SUSPEND
- for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
- if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
- break;
- }
- if (state < PM_SUSPEND_MAX && *s)
- #ifdef CONFIG_EARLYSUSPEND
- if (state == PM_SUSPEND_ON || valid_state(state)) {
- error = 0;
- request_suspend_state(state);
- }
- #else
- error = enter_state(state);
- #endif
- #endif
-
- Exit:
- return error ? error : n;
- }
-
- power_attr(state);
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
suspend_state_t state = PM_SUSPEND_ON;
#else
suspend_state_t state = PM_SUSPEND_STANDBY;
#endif
const char * const *s;
#endif
char *p;
int len;
int error = -EINVAL;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
/* First, check if we are requested to hibernate */
if (len == 4 && !strncmp(buf, "disk", len)) {
error = hibernate();
goto Exit;
}
#ifdef CONFIG_SUSPEND
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;
}
if (state < PM_SUSPEND_MAX && *s)
#ifdef CONFIG_EARLYSUSPEND
if (state == PM_SUSPEND_ON || valid_state(state)) {
error = 0;
request_suspend_state(state);//这里,进入了Android的休眠与唤醒的处理函数
}
#else
error = enter_state(state);
#endif
#endif
Exit:
return error ? error : n;
}
power_attr(state);
看看
[cpp] view plaincopyprint?
- request_suspend_state()都干了些什么事情
[cpp] view plain copy print ?
- request_suspend_state()都干了些什么事情
request_suspend_state()都干了些什么事情
[cpp] view plaincopyprint?
- void request_suspend_state(suspend_state_t new_state)
- {
- unsigned long irqflags;
- int old_sleep;
-
- spin_lock_irqsave(&state_lock, irqflags);
- old_sleep = state & SUSPEND_REQUESTED;
- if (debug_mask & DEBUG_USER_STATE) {
- struct timespec ts;
- struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
- pr_info("request_suspend_state: %s (%d->%d) at %lld "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
- new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
- requested_suspend_state, new_state,
- ktime_to_ns(ktime_get()),
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
- }
- if (!old_sleep && new_state != PM_SUSPEND_ON) {
- state |= SUSPEND_REQUESTED;
- queue_work(suspend_work_queue, &early_suspend_work);
- } else if (old_sleep && new_state == PM_SUSPEND_ON) {
- state &= ~SUSPEND_REQUESTED;
- wake_lock(&main_wake_lock);
- queue_work(suspend_work_queue, &late_resume_work);
- }
- requested_suspend_state = new_state;
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
[cpp] view plain copy print ?
- void request_suspend_state(suspend_state_t new_state)
- {
- unsigned long irqflags;
- int old_sleep;
-
- spin_lock_irqsave(&state_lock, irqflags);
- old_sleep = state & SUSPEND_REQUESTED;
- if (debug_mask & DEBUG_USER_STATE) {
- struct timespec ts;
- struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
- pr_info("request_suspend_state: %s (%d->%d) at %lld "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
- new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
- requested_suspend_state, new_state,
- ktime_to_ns(ktime_get()),
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
- }
- if (!old_sleep && new_state != PM_SUSPEND_ON) {
- state |= SUSPEND_REQUESTED;
- queue_work(suspend_work_queue, &early_suspend_work);
- } else if (old_sleep && new_state == PM_SUSPEND_ON) {
- state &= ~SUSPEND_REQUESTED;
- wake_lock(&main_wake_lock);
- queue_work(suspend_work_queue, &late_resume_work);
- }
- requested_suspend_state = new_state;
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
void request_suspend_state(suspend_state_t new_state)
{
unsigned long irqflags;
int old_sleep;
spin_lock_irqsave(&state_lock, irqflags);
old_sleep = state & SUSPEND_REQUESTED;
if (debug_mask & DEBUG_USER_STATE) {
struct timespec ts;
struct rtc_time tm;
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
pr_info("request_suspend_state: %s (%d->%d) at %lld "
"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
requested_suspend_state, new_state,
ktime_to_ns(ktime_get()),
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
if (!old_sleep && new_state != PM_SUSPEND_ON) {
state |= SUSPEND_REQUESTED;
queue_work(suspend_work_queue, &early_suspend_work);//在休眠的时候,去遍历执行early_suspend_work这个队列
} else if (old_sleep && new_state == PM_SUSPEND_ON) {
state &= ~SUSPEND_REQUESTED;
wake_lock(&main_wake_lock);
queue_work(suspend_work_queue, &late_resume_work);//在唤醒的时候,去遍历执行late_resume_work这个队列
}
requested_suspend_state = new_state;
spin_unlock_irqrestore(&state_lock, irqflags);
}
怎么样,是不是很简单,根据用户/系统所请求的状态,去做相应的动作(休眠/唤醒)
能用到的一些变量的声明在这里
[cpp] view plaincopyprint?
- static void early_suspend(struct work_struct *work);
- static void late_resume(struct work_struct *work);
- static DECLARE_WORK(early_suspend_work, early_suspend);
- static DECLARE_WORK(late_resume_work, late_resume);
[cpp] view plain copy print ?
- static void early_suspend(struct work_struct *work);
- static void late_resume(struct work_struct *work);
- static DECLARE_WORK(early_suspend_work, early_suspend);
- static DECLARE_WORK(late_resume_work, late_resume);
static void early_suspend(struct work_struct *work);
static void late_resume(struct work_struct *work);
static DECLARE_WORK(early_suspend_work, early_suspend);
static DECLARE_WORK(late_resume_work, late_resume);
看名字也知道了,early_suspend这个函数指针来处理early_suspend_work这条队列,late_resume 这个函数指针来处理late_resume_work这条队列。
虽然函数early_suspend()和late_resume()的实现都非常易懂,这里还是要贴出来,因为还有些东西要分析一下。
[cpp] view plaincopyprint?
- static void early_suspend(struct work_struct *work)
- {
- struct early_suspend *pos;
- unsigned long irqflags;
- int abort = 0;
-
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPEND_REQUESTED)
- state |= SUSPENDED;
- else
- abort = 1;
- spin_unlock_irqrestore(&state_lock, irqflags);
-
- if (abort) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: abort, state %d\n", state);
- mutex_unlock(&early_suspend_lock);
- goto abort;
- }
-
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: call handlers\n");
- list_for_each_entry(pos, &early_suspend_handlers, link) {
- if (pos->suspend != NULL) {
- if (debug_mask & DEBUG_VERBOSE)
- pr_info("early_suspend: calling %pf\n", pos->suspend);
- pos->suspend(pos);
- }
- }
- mutex_unlock(&early_suspend_lock);
-
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: sync\n");
-
- sys_sync();
- abort:
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
- wake_unlock(&main_wake_lock);
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
[cpp] view plain copy print ?
- static void early_suspend(struct work_struct *work)
- {
- struct early_suspend *pos;
- unsigned long irqflags;
- int abort = 0;
-
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPEND_REQUESTED)
- state |= SUSPENDED;
- else
- abort = 1;
- spin_unlock_irqrestore(&state_lock, irqflags);
-
- if (abort) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: abort, state %d\n", state);
- mutex_unlock(&early_suspend_lock);
- goto abort;
- }
-
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: call handlers\n");
- list_for_each_entry(pos, &early_suspend_handlers, link) {
- if (pos->suspend != NULL) {
- if (debug_mask & DEBUG_VERBOSE)
- pr_info("early_suspend: calling %pf\n", pos->suspend);
- pos->suspend(pos);
- }
- }
- mutex_unlock(&early_suspend_lock);
-
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: sync\n");
-
- sys_sync();
- abort:
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
- wake_unlock(&main_wake_lock);
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
static void early_suspend(struct work_struct *work)
{
struct early_suspend *pos;
unsigned long irqflags;
int abort = 0;
mutex_lock(&early_suspend_lock);
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED)
state |= SUSPENDED;
else
abort = 1;
spin_unlock_irqrestore(&state_lock, irqflags);
if (abort) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("early_suspend: abort, state %d\n", state);
mutex_unlock(&early_suspend_lock);
goto abort;
}
if (debug_mask & DEBUG_SUSPEND)
pr_info("early_suspend: call handlers\n");
list_for_each_entry(pos, &early_suspend_handlers, link) {//这里就是关键了,遍历early_suspend_handler这条链表(在驱动中注册early_suspend的时候,都注册到这条链表上了)
if (pos->suspend != NULL) {
if (debug_mask & DEBUG_VERBOSE)
pr_info("early_suspend: calling %pf\n", pos->suspend);
pos->suspend(pos);//调用各个实现进行各设备的休眠
}
}
mutex_unlock(&early_suspend_lock);
if (debug_mask & DEBUG_SUSPEND)
pr_info("early_suspend: sync\n");
sys_sync();
abort:
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
wake_unlock(&main_wake_lock);//这里很重要,别小看这个一个wake_unlock,起初我也以为这仅仅是一个释放main锁,其实里面有玄机呢。还记得wake_lock主要用来干嘛么,用来防止系统休眠,也就是说,只要系统中其他地方还拥有wake_lock锁(类型WAKE_LOCK_SUSPEND),系统就没法进入休眠,如果没有锁了,那就要接着走标准Linux的那一套休眠机制了
spin_unlock_irqrestore(&state_lock, irqflags);
}
[cpp] view plaincopyprint?
-
[cpp] view plain copy print ?
-
先跳过late_resume()。来看下wake_unlock()的实现吧
[cpp] view plaincopyprint?
- void wake_unlock(struct wake_lock *lock)
- {
- int type;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- #ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 0);
- #endif
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_unlock: %s\n", lock->name);
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- if (type == WAKE_LOCK_SUSPEND) {
- long has_lock = has_wake_lock_locked(type);
- if (has_lock > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, start expire timer, "
- "%ld\n", lock->name, has_lock);
- mod_timer(&expire_timer, jiffies + has_lock);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- if (lock == &main_wake_lock) {
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- #ifdef CONFIG_WAKELOCK_STAT
- update_sleep_wait_stats_locked(0);
- #endif
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_unlock);
[cpp] view plain copy print ?
- void wake_unlock(struct wake_lock *lock)
- {
- int type;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- #ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 0);
- #endif
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_unlock: %s\n", lock->name);
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- if (type == WAKE_LOCK_SUSPEND) {
- long has_lock = has_wake_lock_locked(type);
- if (has_lock > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, start expire timer, "
- "%ld\n", lock->name, has_lock);
- mod_timer(&expire_timer, jiffies + has_lock);
- } else {
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- }
- if (lock == &main_wake_lock) {
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- #ifdef CONFIG_WAKELOCK_STAT
- update_sleep_wait_stats_locked(0);
- #endif
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- EXPORT_SYMBOL(wake_unlock);
void wake_unlock(struct wake_lock *lock)
{
int type;
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
type = lock->flags & WAKE_LOCK_TYPE_MASK;
#ifdef CONFIG_WAKELOCK_STAT
wake_unlock_stat_locked(lock, 0);
#endif
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info("wake_unlock: %s\n", lock->name);
lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
list_del(&lock->link);
list_add(&lock->link, &inactive_locks);
if (type == WAKE_LOCK_SUSPEND) {//类型,驱动中一般只有这一种类型
long has_lock = has_wake_lock_locked(type);
if (has_lock > 0) {
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, start expire timer, "
"%ld\n", lock->name, has_lock);
mod_timer(&expire_timer, jiffies + has_lock);
} else {
if (del_timer(&expire_timer))
if (debug_mask & DEBUG_EXPIRE)
pr_info("wake_unlock: %s, stop expire "
"timer\n", lock->name);
if (has_lock == 0)//如果没有锁了,要进入标准Linux的休眠机制了,咱们接着往下跟
queue_work(suspend_work_queue, &suspend_work);
}
if (lock == &main_wake_lock) {
if (debug_mask & DEBUG_SUSPEND)
print_active_locks(WAKE_LOCK_SUSPEND);
#ifdef CONFIG_WAKELOCK_STAT
update_sleep_wait_stats_locked(0);
#endif
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_unlock);
这里就是进入标准Linux的休眠的地方了
[cpp] view plaincopyprint?
- static void suspend(struct work_struct *work)
- {
- int ret;
- int entry_event_num;
- struct timespec ts_entry, ts_exit;
-
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
-
- entry_event_num = current_event_num;
- sys_sync();
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- getnstimeofday(&ts_entry);
- ret = pm_suspend(requested_suspend_state);
- getnstimeofday(&ts_exit);
-
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct rtc_time tm;
- rtc_time_to_tm(ts_exit.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
- }
-
- if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
- ++suspend_short_count;
-
- if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
- suspend_backoff();
- suspend_short_count = 0;
- }
- } else {
- suspend_short_count = 0;
- }
-
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- wake_lock_timeout(&unknown_wakeup, HZ / 2);
- }
- }
- static DECLARE_WORK(suspend_work, suspend);
[cpp] view plain copy print ?
- static void suspend(struct work_struct *work)
- {
- int ret;
- int entry_event_num;
- struct timespec ts_entry, ts_exit;
-
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
-
- entry_event_num = current_event_num;
- sys_sync();
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- getnstimeofday(&ts_entry);
- ret = pm_suspend(requested_suspend_state);
- getnstimeofday(&ts_exit);
-
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct rtc_time tm;
- rtc_time_to_tm(ts_exit.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
- }
-
- if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
- ++suspend_short_count;
-
- if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
- suspend_backoff();
- suspend_short_count = 0;
- }
- } else {
- suspend_short_count = 0;
- }
-
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- wake_lock_timeout(&unknown_wakeup, HZ / 2);
- }
- }
- static DECLARE_WORK(suspend_work, suspend);
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;
struct timespec ts_entry, ts_exit;
if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: abort suspend\n");
return;
}
entry_event_num = current_event_num;
sys_sync();
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: enter suspend\n");
getnstimeofday(&ts_entry);
ret = pm_suspend(requested_suspend_state);//这里是关键点
getnstimeofday(&ts_exit);
if (debug_mask & DEBUG_EXIT_SUSPEND) {
struct rtc_time tm;
rtc_time_to_tm(ts_exit.tv_sec, &tm);
pr_info("suspend: exit suspend, ret = %d "
"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
}
if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
++suspend_short_count;
if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
suspend_backoff();
suspend_short_count = 0;
}
} else {
suspend_short_count = 0;
}
if (current_event_num == entry_event_num) {
if (debug_mask & DEBUG_SUSPEND)
pr_info("suspend: pm_suspend returned with no event\n");
wake_lock_timeout(&unknown_wakeup, HZ / 2);
}
}
static DECLARE_WORK(suspend_work, suspend);
[cpp] view plaincopyprint?
- int pm_suspend(suspend_state_t state)
- {
- if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
- return enter_state(state);
- return -EINVAL;
- }
- EXPORT_SYMBOL(pm_suspend);
[cpp] view plain copy print ?
- int pm_suspend(suspend_state_t state)
- {
- if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
- return enter_state(state);
- return -EINVAL;
- }
- EXPORT_SYMBOL(pm_suspend);
int pm_suspend(suspend_state_t state)
{
if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
return enter_state(state);//正如你所料,开始走Linux那套休眠的流程了
return -EINVAL;
}
EXPORT_SYMBOL(pm_suspend);
唤醒相关的代码就不贴 了,跟休眠类似的。
下面讲下驱动中如何使用wake_lock和early_suspend,总的来说,还是挺简单的
比如在设备probe的时候做如下操作
struct early_suspend early_suspend;
early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; //等级,等级大小和suspend顺序一致,和resume顺序相反
early_suspend.suspend = xxx_early_suspend;//指定函数指针,需自己实现
early_suspend.resume = xxx_late_resume;
register_early_suspend(&early_suspend);//注册进核心,也就是加入刚才early_suspend_handlers那个链表
struct wake_lock chrg_lock;
wake_lock_init(&chrg_lock, WAKE_LOCK_SUSPEND, "xxx_wake_lock");//初始化类型为WAKE_LOCK_SUSPEND的wake_lock锁
#ifdef CONFIG_HAS_EARLYSUSPEND
static void xxx_early_suspend(struct early_suspend *h)
{
....
wake_lock(&chrg_lock);
....
}
static void xxx_late_resume(struct early_suspend *h)
{
.....
wake_unlock(&chrg_lock);
....
}
#endif