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
沒有留言:
張貼留言