在按下电源键后,会调用autosuspend_enable()函数,可参考https://blog.csdn.net/mike8825/article/details/80423842
system/core/libsuspend/autosuspend.c
int autosuspend_enable(void)
{
autosuspend_init();
autosuspend_ops->enable();
}
int autosuspend_disable(void)
{
autosuspend_init();
autosuspend_ops->disable();
}
static int autosuspend_init(void)
{
autosuspend_ops = autosuspend_wakeup_count_init();
}
system/core/libsuspend/autosuspend_wakeup_count.c
#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
struct autosuspend_ops *autosuspend_wakeup_count_init(void)
{
wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
}
//没有锁,写mem>/sys/power/state
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
while (1) {
usleep(100000);
wakeup_count_len = read(wakeup_count_fd, wakeup_count,sizeof(wakeup_count));
sem_wait(&suspend_lockout);
ret=write(wakeup_count_fd, wakeup_count, wakeup_count_len));
if (ret < 0)
{
}
else
{
write(state_fd, sleep_state, strlen(sleep_state));
}
}
}
static int autosuspend_wakeup_count_enable(void)
{
sem_post(&suspend_lockout);
}
static int autosuspend_wakeup_count_disable(void)
{
sem_wait(&suspend_lockout);
}
kernel/kernel/power/main.c
static ssize_t wakeup_count_show(struct kobject *kobj,struct kobj_attribute *attr,char *buf)
{
unsigned int val;
return pm_get_wakeup_count(&val, true) ?
sprintf(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t n)
{
unsigned int val;
error = -EINVAL;
if (sscanf(buf, "%u", &val) == 1) {
if (pm_save_wakeup_count(val))
error = n;
}
out:
return error;
}
power_attr(wakeup_count);
bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
if (block) {
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(&wakeup_count_wait_queue, &wait,
TASK_INTERRUPTIBLE);
split_counters(&cnt, &inpr);
if (inpr == 0 || signal_pending(current))
break;
schedule();
}
finish_wait(&wakeup_count_wait_queue, &wait);
}
split_counters(&cnt, &inpr);
*count = cnt;
return !inpr;
}
/**
* pm_save_wakeup_count - Save the current number of registered wakeup events.
* @count: Value to compare with the current number of registered wakeup events.
*
* If @count is equal to the current number of registered wakeup events and the
* current number of wakeup events being processed is zero, store @count as the
* old number of registered wakeup events for pm_check_wakeup_events(), enable
* wakeup events detection and return 'true'. Otherwise disable wakeup events
* detection and return 'false'.
*/
bool pm_save_wakeup_count(unsigned int count)
{
unsigned int cnt, inpr;
unsigned long flags;
events_check_enabled = false;
spin_lock_irqsave(&events_lock, flags);
split_counters(&cnt, &inpr);
if (cnt == count && inpr == 0) {
saved_count = count;
events_check_enabled = true;
}
spin_unlock_irqrestore(&events_lock, flags);
return events_check_enabled;
}
上面的作用是对/sys/power/wakeup_count进行读写(涉及到变量combined_event_count,
可参考https://blog.csdn.net/mike8825/article/details/80422993),如果所有的锁都已解锁,
则写"mem"到/sys/power/state进行休眠
kernel/kernel/power/main.c
sys/power/state节点生成
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = { \
.attr = { \
.name = __stringify(_name), \
.mode = 0644, \
}, \
.show = _name##_show, \
.store = _name##_store, \
}
power_attr(state);
static struct attribute * g[] = {
&state_attr.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = g,
};
static int __init pm_init(void)
{
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
error = sysfs_create_group(power_kobj, &attr_group);
}
core_initcall(pm_init);
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{
state = decode_state(buf, n);//将"mem"转换成对应的数字
error = pm_suspend(state);
}
int pm_suspend(suspend_state_t state)
{
pm_suspend_marker("entry");
error = enter_state(state);
pm_suspend_marker("exit");
}
static void pm_suspend_marker(char *annotation)
{
struct timespec ts;
struct rtc_time tm;
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec, &tm);
pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",
annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}
static int enter_state(suspend_state_t state)
{
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(state);
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
pm_restrict_gfp_mask();
error = suspend_devices_and_enter(state);
pm_restore_gfp_mask();
Finish:
pr_debug("PM: Finishing wakeup.\n");
suspend_finish();
}
static inline int suspend_freeze_processes(void)
{
error = freeze_processes();
error = freeze_kernel_threads();
}
static int suspend_prepare(suspend_state_t state)
{
if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter)) //kernel/drivers/cpuidle/lpm-levels.c suspend_set_ops(&lpm_suspend_ops);
return -EPERM;
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
error = suspend_freeze_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
return error;
}
int suspend_devices_and_enter(suspend_state_t state)
{
int error;
bool wakeup = false;
if (need_suspend_ops(state) && !suspend_ops)
return -ENOSYS;
if (need_suspend_ops(state) && suspend_ops->begin) {
error = suspend_ops->begin(state);
if (error)
goto Close;
}
suspend_console();
error = dpm_suspend_start(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "PM: Some devices failed to suspend\n");
goto Recover_platform;
}
suspend_test_finish("suspend devices");
if (suspend_test(TEST_DEVICES))
goto Recover_platform;
do {
error = suspend_enter(state, &wakeup); //正常休眠会停在该函数,如果唤醒了,则走下面的流程
} while (!error && !wakeup && need_suspend_ops(state)
&& suspend_ops->suspend_again && suspend_ops->suspend_again());
Resume_devices:
dpm_resume_end(PMSG_RESUME);
resume_console();
Close:
if (need_suspend_ops(state) && suspend_ops->end)
suspend_ops->end();
return error;
Recover_platform:
if (need_suspend_ops(state) && suspend_ops->recover)
suspend_ops->recover();
goto Resume_devices;
}
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
error = dpm_suspend_end(PMSG_SUSPEND);
error = disable_nonboot_cpus();
arch_suspend_disable_irqs();
error = syscore_suspend();
if (!error) {
*wakeup = pm_wakeup_pending();
if (!(suspend_test(TEST_CORE) || *wakeup)) {
error = suspend_ops->enter(state);//停在这..........
events_check_enabled = false;
}
syscore_resume();
}
arch_suspend_enable_irqs();
Enable_cpus:
enable_nonboot_cpus();
Platform_wake:
if (need_suspend_ops(state) && suspend_ops->wake)
suspend_ops->wake();
dpm_resume_start(PMSG_RESUME);
Platform_finish:
if (need_suspend_ops(state) && suspend_ops->finish)
suspend_ops->finish();
return error;
}
dpm(Device power management),有几个dpm开头的函数,其作用是运行设备的电源管理函数
int dpm_suspend_start(pm_message_t state)
{
dpm_prepare(state); //prepare dpm_list
dpm_suspend(state); //suspend dpm_prepared_list
}
int dpm_suspend_end(pm_message_t state)
{
dpm_suspend_late(state); //suspend_late dpm_suspended_list
dpm_suspend_noirq(state); //suspend_noirq dpm_late_early_list
}
void dpm_resume_start(pm_message_t state)
{
dpm_resume_noirq(state); //resume_noirq
dpm_resume_early(state); //resume_early
}
void dpm_resume_end(pm_message_t state)
{
dpm_resume(state); //resume
dpm_complete(state);//complete
}
休眠prepare--->suspend--->suspend_late--->suspend_noirq
唤醒resume_noirq--->resume_early--->resume--->complete
struct dev_pm_ops {
int (*prepare)(struct device *dev);
void (*complete)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*freeze)(struct device *dev);
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume_early)(struct device *dev);
int (*freeze_late)(struct device *dev);
int (*thaw_early)(struct device *dev);
int (*poweroff_late)(struct device *dev);
int (*restore_early)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*freeze_noirq)(struct device *dev);
int (*thaw_noirq)(struct device *dev);
int (*poweroff_noirq)(struct device *dev);
int (*restore_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
};
如
static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
.suspend = goodix_ts_suspend,
.resume = goodix_ts_resume,
};
类dpm函数的作用是按顺序执行相关的电源函数
上面有个suspend_ops的指针(cpu休眠时的动作),其定义在
kernel/drivers/cpuidle/lpm-levels.c
static int lpm_probe(struct platform_device *pdev)
{
suspend_set_ops(&lpm_suspend_ops);
}
static const struct platform_suspend_ops lpm_suspend_ops = {
.enter = lpm_suspend_enter,
.valid = suspend_valid_only_mem,
.prepare_late = lpm_suspend_prepare,
.wake = lpm_suspend_wake,
};
kernel/kernel/power/suspend.c
void suspend_set_ops(const struct platform_suspend_ops *ops)
{
suspend_ops = ops;
}
参考的内核打印如下
52.402471: <6> PM: suspend entry 1970-01-01 00:13:08.409503329 UTC
52.402486: <2> PM: Syncing filesystems ... done.
52.410354: <6> Error: returning -512 value
52.409207: <2> Freezing user space processes ... (elapsed 0.005 seconds) done.
52.415161: <2> Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
52.418063: <2> Suspending console(s) (use no_console_suspend to debug)
52.451064: <6> PM: suspend of devices complete after 31.502 msecs
52.452177: <6> PM: late suspend of devices complete after 1.102 msecs
52.456733: <6> PM: noirq suspend of devices complete after 4.546 msecs
52.456743: <2> Disabling non-boot CPUs ...
52.458561: <6> migrate_irqs: 1510 callbacks suppressed
52.458564: <6> IRQ32 no longer affine to CPU3
52.458572: <6> IRQ33 no longer affine to CPU3
52.458579: <6> IRQ34 no longer affine to CPU3
52.458586: <6> IRQ36 no longer affine to CPU3
52.458593: <6> IRQ37 no longer affine to CPU3
52.458600: <6> IRQ38 no longer affine to CPU3
52.458608: <6> IRQ40 no longer affine to CPU3
52.458615: <6> IRQ41 no longer affine to CPU3
52.458622: <6> IRQ42 no longer affine to CPU3
52.458628: <6> IRQ43 no longer affine to CPU3
52.460298: <6> CPU3: shutdown
52.464728: <6> CPU4: shutdown
52.469291: <6> CPU5: shutdown
52.473567: <6> CPU6: shutdown
52.477904: <6> CPU7: shutdown
52.479231: <6> CPU0:msm_cpu_pm_enter_sleep mode:3 during suspend