ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2010年12月2日 星期四

Android -- Suspend (and wakeup ?)

Android 設定 power state 的 function 好像是在: hardware/libhardware_legacy/power/power.c 裡面的 int set_screen_state(int on) { QEMU_FALLBACK(set_screen_state(on)); LOGI("*** set_screen_state %d", on); initialize_fds(); //LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime, // systemTime(), strerror(g_error)); if (g_error) return g_error; char buf[32]; int len; if(on) len = sprintf(buf, on_state); else len = sprintf(buf, off_state); len = write(g_fds[REQUEST_STATE], buf, len); if(len < 0) { LOGE("Failed setting last user activity: g_error=%d\n", g_error); } return 0; } 其中的 g_fds[REQUEST_STATE] 就是: enum { ACQUIRE_PARTIAL_WAKE_LOCK = 0, RELEASE_WAKE_LOCK, REQUEST_STATE, OUR_FD_COUNT }; 對應 const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock", "/sys/power/state" }; 也就是 /sys/power/state 寫入 static const char *off_state = "mem"; static const char *on_state = "on";
suspend 就寫 "mem".



使用這個 function 的 source 在 ./frameworks/base/core/jni/android_os_Power.cpp: static int setScreenState(JNIEnv *env, jobject clazz, jboolean on) { return set_screen_state(on); } 這是一個 JNI function,包裝的 class 是: ./frameworks/base/core/java/android/os/Power.java
使用的 class 是 ./frameworks/base/services/java/com/android/server/PowerManagerService.java



kernel 層對應 /sys/power/state 的 device 是 kernel/power/main.c

對 /sys/power/state的 read/write 對應有點.. #define power_attr(_name) \ static struct kobj_attribute _name##_attr = { \ .attr = { \ .name = __stringify(_name), \ .mode = 0644, \ }, \ .show = _name##_show, \ .store = _name##_store, \ } 在 main.c 中: power_attr(state); 所以要找 state_store:
state_store( ) 會把 write 到 /sys/power/state 和 support 的 power state 比較,下面是suspend 的 state : (suspend.c) const char *const pm_states[PM_SUSPEND_MAX] = { #ifdef CONFIG_EARLYSUSPEND [PM_SUSPEND_ON] = "on", #endif [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", }; 然後call enter_state(state) -- state 就是 pm_states[] 對應的index。

這個在 suspend.c: int enter_state(suspend_state_t state) { int error; if (!valid_state(state)) return -ENODEV; if (!mutex_trylock(&pm_mutex)) return -EBUSY; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); error = suspend_prepare(); if (error) goto Unlock; if (suspend_test(TEST_FREEZER)) goto Finish; pr_debug("PM: Entering %s sleep\n", pm_states[state]); error = suspend_devices_and_enter(state); Finish: pr_debug("PM: Finishing wakeup.\n"); suspend_finish(); Unlock: mutex_unlock(&pm_mutex); return error; } 可以看到 .. suspend_device_and_enter(state);
然後是,. suspend_finish( );

上面的 debug message 是.. PM:Finishing wakeup.
所以 在 suspend_device_and_enter( ) 後,cpu 應該就進入 suspend state。
一直到有 wakeup event 後,才會wakeup 起來,繼續執行.. suspend_finish().



但是 user program 寫入 /sys/power/state 和 kernel/power/main.c 的執行沒有同步 (?)。
所以 user program 不知道在什麼時候停住。 (?)



suspend_enter( ) 實際作 cpu suspend 的動作是靠
static struct platform_suspend_ops *suspend_ops; 的 ops interface 來完成的。

這個變數是呼叫
void suspend_set_ops(struct platform_suspend_ops *ops) { mutex_lock(&pm_mutex); suspend_ops = ops; mutex_unlock(&pm_mutex); } 完成的,每個 platform 都會實作呼叫這個 function 的 code.
所以在 arch/ 下面的code 可以找到很多..
例如 arch/arm/mach-xxx/pm.c

platform 為了作 suspend,通常會 copy 最後一段的 code 到 internal ram 中,再跳過去執行,然後把 DRAM 設為 self-fresh mode,然後停止 clock.


ref: http://hi.baidu.com/linuxembedded/blog/item/4eeb143837879bd2d46225ca.html

沒有留言:

標籤

網誌存檔