標準linux休眠過程:
l power management notifiers are executed with PM_SUSPEND_PREPARE
l tasks are frozen
l target system sleep state is announced to the platform-handling code
l devices are suspended
l platform-specific global suspend preparation methods are executed
l non-boot CPUs are taken off-line
l interrupts are disabled on the remaining (main) CPU
l late suspend of devices is carried out (一般有一些BUS driver的動作進行)?
l platform-specific global methods are invoked to put the system to sleep
標準linux喚醒過程:
l the main CPU is switched to the appropriate mode, if necessary
l early resume of devices is carried out (一般有一些BUS driver的動作進行)?
l interrupts are enabled on the main CPU
l non-boot CPUs are enabled
l platform-specific global resume preparation methods are invoked
l devices are woken up
l tasks are thawed
l power management notifiers are executed with PM_POST_SUSPEND
用戶可以通過sys文件系統控制系統進入休眠:
查看系統支持的休眠方式:
#cat /sys/power/state
常見有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗電更多,返回到正常工作狀態的時間更短。
通過 #echo mem > /sys/power/state 讓系統進入休眠。
Android休眠與喚醒
android是在傳統的linux內核電源管理設計的基礎上,結合手機設計的實際需求而進化出的一套電源管理系統,其核心內容有:wakelock 、early_suspend與late_resume。
wakelock在Android的電源管理系統中扮演一個核心的角色。wakelock是一種鎖的機制, 只要有人拿著這個鎖,系統就無法進入休眠,可以被用戶態程序和內核獲得。這個鎖可以是有超時的或者是沒有超時的,超時的鎖會在時間過去以后自動解鎖。如果沒有鎖了或者超時了,內核就會啟動休眠的那套機制來進入休眠。
當系統在啟動完畢后,會自己去加一把名為“main“的鎖,而當系統有意愿去睡眠時則會先去釋放這把“main”鎖,在android中,在early_suspend的最后一步會去釋放“main”鎖(wake_unlock: main)。釋放完后則會去檢查是否還有其他存在的鎖,如果沒有則直接進入睡眠過程。
它的缺點是,如果有某一應用獲鎖而不釋放或者因一直在執行某種操作而沒時間來釋放的話,則會導致系統一直進入不了睡眠狀態,功耗過大。
early_suspend:先與linux內核的睡眠過程被調用。一般在手機系統的設計中對背光的操作等采用此類方法,因為背光需要的能耗過大。當然此操作與late_resume是配套使用的。一些在內核中要預先進行處理的事件可以先注冊上early_suspend函數,當系統要進入睡眠之前會首先調用這些注冊的函數。
本文中,linux kernel版本為 linux-2.6.29,android版本為 android 2.1
與android休眠喚醒主要相關的文件主要有:
l linux_source/kernel/power/main.c
l linux_source/kernel/power/earlysuspend.c
l linux_source/kernel/power/wakelock.c
l linux_source/kernel/power/process.c
l linux_source/driver/base/power/main.c
l linux_source/arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.c
Android 休眠過程如下:
當用戶讀寫/sys/power/state時,linux_source/kernel/power/main.c中的state_store()函數會被調用。其中,android的early_suspend會執行request_suspend_state(state); 而標準的linux休眠則執行error = enter_state(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);
}
#else
error = enter_state(state);
#endif
#endif
Exit:
return error ? error : n;
}
在request_suspend_state(state)函數中,會調用early_suspend_work的工作隊列,從而進入early_suspend()函數中。
static DECLARE_WORK(early_suspend_work, early_suspend);
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);
}
在early_suspend()函數中,首先要判斷當前請求的狀態是否還是suspend,若不是,則直接退出了;若是,函數會調用已經注冊的early_suspend的函數。然后同步文件系統,最后釋放main_wake_lock。
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 %dn', state);
mutex_unlock(&early_suspend_lock);
goto abort;
}
if (debug_mask & DEBUG_SUSPEND)
pr_info('early_suspend: call handlersn');
list_for_each_entry(pos, &early_suspend_handlers, link) {
if (pos->suspend != NULL)
pos->suspend(pos);
}
mutex_unlock(&early_suspend_lock);
if (debug_mask & DEBUG_SUSPEND)
pr_info('early_suspend: syncn');
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);
}
在wake_unlock()中,刪除鏈表中wake_lock節點,判斷當前是否存在wake_lock,若wake_lock的數目為0,則調用工作隊列suspend_work,進入suspend狀態。
static DECLARE_WORK(suspend_work, suspend);
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: %sn', 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, '
'%ldn', lock->name, has_lock);
上一篇:LED 將為我閃爍: 控制發光二級管
下一篇:基于gnu-arm-linux的LPC2220的簡單工程模板
推薦閱讀最新更新時間:2025-04-18 18:01




設計資源 培訓 開發板 精華推薦
- LT1172HVIQ、5V/1.25A 高效 5V 降壓轉換器的典型應用
- 使用 Richtek Technology Corporation 的 RT8485GS 的參考設計
- MTRCCBP5604P,帶 Qorivva MPC5604P MCU 的三相 PMSM 電機控制開發套件
- cdsj relay
- EVAL_IPT015N10N5_TOLL:英飛凌針對大功率電機控制應用(如叉車或低速車)的逆變器級解決方案
- TYPE-C轉接板
- 尺子禮品
- 【數電課設】電子游戲轉盤
- #第七屆立創電賽#卡片型多參數監護儀-OpenECG
- ADR434A 4.096 Vout 超低噪聲 XFET 電壓基準的典型應用,具有灌電流和拉電流能力