基于MTK android电源管理:early_suspend分析

Android共支持3种suspend的模式:
early_suspend、suspned、hibernation
1,earlysuspend是一种低功耗的状态,某些设备可以选择进入某种功耗较低的状态,比如LCD可以降低亮度或灭掉;

2,suspend是指除电源管理以外的其他外围模块以及cpu均不工作,只有内存保持自刷新的状态;

3,hibernation是指所有内存镜像都被写入磁盘中,然后系统关机,恢复后系统将能恢复到“关机”之前的状态.


power manager的suspend状态有4种,可从suspend.h中查看
typedef int __bitwise suspend_state_t;

#define PM_SUSPEND_ON        ((__force suspend_state_t) 0)
#define PM_SUSPEND_STANDBY    ((__force suspend_state_t) 1)
#define PM_SUSPEND_MEM        ((__force suspend_state_t) 3)

#define PM_SUSPEND_MAX        ((__force suspend_state_t) 4)


其中在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",

};


至于第四种应该就是hibernation功能,目前所知道的android设备支持的很少;

#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);
在power maneger main.c中定义了电源管理的接口属性

static int __init pm_init(void)
{
    int error = pm_start_workqueue();
    if (error)
        return error;
    hibernate_image_size_init();
    hibernate_reserved_size_init();
    power_kobj = kobject_create_and_add("power", NULL);
    if (!power_kobj)
        return -ENOMEM;
    error = sysfs_create_group(power_kobj, &attr_group);
    if (error)
        return error;
    return pm_autosleep_init();
}

将该属性文件注册到/sys下面,之后用户层可以通过/sys/power/state来控制系统的休眠与唤醒,当用户层对该接口进行访问时,会调用store函数:


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;

#ifdef CONFIG_MTK_HIBERNATION
    state = decode_state(buf, n);
    hib_log("entry (%d)\n", state);
#endif
    if (no_suspend && len == 3 && !strncmp(buf, "mem", len))
    {
        printk("suspend disabled\n");
        goto Exit;
    }

#ifdef CONFIG_MTK_HIBERNATION
    if (len == 8 && !strncmp(buf, "hibabort", len)) {
        hib_log("abort hibernation...\n");
        error = mtk_hibernate_abort();
        goto Exit;
    }
#endif

    /* First, check if we are requested to hibernate */
    if (len == 4 && !strncmp(buf, "disk", len)) {
#ifdef CONFIG_MTK_HIBERNATION
        hib_log("trigger hibernation...\n");
#ifdef CONFIG_EARLYSUSPEND
        if (PM_SUSPEND_ON == get_suspend_state()) {
            hib_warn("\"on\" to \"disk\" (i.e., 0->4) is not supported !!!\n");
            error = -EINVAL;
            goto Exit;
        }
#endif
        if (!pre_hibernate()) {
            error = 0;
            error = mtk_hibernate();
        }
#else // !CONFIG_MTK_HIBERNATION
        error = hibernate();
#endif
        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 = -EINVAL;
#else
        error = enter_state(state);
#endif
    }
#endif

 Exit:
    return error ? error : n;

}


CONFIG_MTK_HIBERNATION用来判断是否有开启hibernation状态

    for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
        if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
            break;
    }
用来侦测目前powwer manager的状态,是on还是mem,还是suspened.
valid_state(state):用来判断该android的power manager是否支持该state,之后再进入request_suspend_state.
如果是标准的linux内核就会走enter_state(state)


void request_suspend_state(suspend_state_t new_state)
{
    unsigned long irqflags;
    int old_sleep;
    int wait_flag = 0;

    spin_lock_irqsave(&state_lock, irqflags);
    old_sleep = state & SUSPEND_REQUESTED;
    if (earlysuspend_debug_mask & DEBUG_USER_STATE) {
        struct timespec ts;
        struct rtc_time tm;
        getnstimeofday(&ts);
        rtc_time_to_tm(ts.tv_sec, &tm);
        pm_warn("%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;
        pm_warn("sys_sync_work_queue early_sys_sync_work\n");
        queue_work(sys_sync_work_queue, &early_sys_sync_work);
        pm_warn("suspend_work_queue early_suspend_work\n");
        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);
        ///cun
        if (queue_work(suspend_work_queue, &late_resume_work)) {
            /*
             * In order to synchronize the backlight turn on timing,egou
             * block the thread and wait for fb driver late_resume()
             * callback function is completed
             */
            wait_flag = 1;
        }
    }
    requested_suspend_state = new_state;
    spin_unlock_irqrestore(&state_lock, irqflags);
    if (wait_flag == 1) {
        wait_for_completion(&fb_drv_ready);
        pr_warn("wait done\n");
    }
}
通过上面的两条判断语句根据不同的power manager状态将对应的suspend、resume操作函数加入对应的工作队列中去;
先来看看suspend的操作函数:
queue_work(suspend_work_queue, &early_suspend_work):调度执行指定的工作对列suspend_work_queue中的任务,early_suspend_work是指定的任务指针
DECLARE_WORK(early_suspend_work, early_suspend)静态的创建工作对列结构,其中early_suspend是队列中的任务所对应的function;
suspend_work_queue是在什么时候创建的呢?

static int __init org_wakelocks_init(void)
{
    int ret;
   
    wake_lock_init(&sys_sync_wake_lock, WAKE_LOCK_SUSPEND, "sys_sync");

    sys_sync_work_queue = create_singlethread_workqueue("fs_sync");
    if (sys_sync_work_queue == NULL) {
        pr_err("[wakelocks_init] fs_sync workqueue create failed\n");
    }

    suspend_work_queue = create_singlethread_workqueue("suspend");
    if (suspend_work_queue == NULL) {
        ret = -ENOMEM;
        goto err_suspend_work_queue;
    }
    return 0;

err_suspend_work_queue:

    return ret;
}
整个suspend的核心就是在创建suspend_work_queue的工作队列中完成

static void early_suspend(struct work_struct *work)
{
    struct early_suspend *pos;
    unsigned long irqflags;
    int abort = 0, count = 0;

    pr_warn("@@@@@@@@@@@@@@@@@@@@@@@\n@@@__early_suspend__@@@\n@@@@@@@@@@@@@@@@@@@@@@@\n");

    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 (earlysuspend_debug_mask & DEBUG_SUSPEND)
            pm_warn("abort, state %d\n", state);
        mutex_unlock(&early_suspend_lock);
        goto abort;
    }

    pr_warn("early_suspend_count = %d, forbid_id = 0x%x\n", early_suspend_count, forbid_id);
    if (earlysuspend_debug_mask & DEBUG_SUSPEND)
        pm_warn("call handlers\n");
    list_for_each_entry(pos, &early_suspend_handlers, link) {
        if (pos->suspend != NULL) {
            if (!(forbid_id & (0x1 << count))) {
                //if (earlysuspend_debug_mask & DEBUG_VERBOSE)
                    pr_warn("ES handlers %d: [%pf], level: %d\n", count, pos->suspend, pos->level);
                pos->suspend(pos);
            }
            count++;
        }
    }
    mutex_unlock(&early_suspend_lock);

    /* Remove sys_sync from early_suspend, and use work queue to complete sys_sync */

abort:
    if (state == SUSPEND_REQUESTED_AND_SUSPENDED) {
        //wake_unlock(&main_wake_lock);
#ifdef CONFIG_MTK_HIBERNATION
        suspend_state_t susp_state = get_suspend_state();
        pm_warn("calling pm_autosleep_set_state() with parameter: %d\n", susp_state);
        pm_autosleep_set_state(susp_state);
#else
        pm_autosleep_set_state(PM_SUSPEND_MEM);
#endif
    }
}
关键性的函数: list_for_each_entry(pos, &early_suspend_handlers, link),会遍历early_suspend_handlers
链表中的所有handler,然后回调所有加入该链表中的模块的suspend handle函数,最后会释放main lock,到此early_suspend结束,每个模块又是如何加入到该early_suspend_handlers链表中的呢

每个模块如果需要进入suspend,就需要将对应的处理函数加入到handles的链表中,register_early_suspend(&obj->early_drv),该函数就是用来将处理函数注册到handles链表中
    obj->early_drv.level    = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1,
    obj->early_drv.suspend  = bma220_early_suspend,
    其中level是表示该结构在handlers链表中的位置,suspend时该level值越小那么在回调函数中执行的就越早,resume则反过来
    android在earlysuspened.h中先定义了如下几个level值:
    enum {
    EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
    EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
    EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
};

    struct early_suspend {
    #ifdef CONFIG_HAS_EARLYSUSPEND
        struct list_head link;
        int level;
        void (*suspend)(struct early_suspend *h);
        void (*resume)(struct early_suspend *h);
    #endif
    };
    如果需要将suspend的顺序调到这其中之前的话,只需将level值改成比这个小就可以了
    下面看看register_early_suspend这个函数的处理过程:
    
void register_early_suspend(struct early_suspend *handler)
{
    struct list_head *pos;

    mutex_lock(&early_suspend_lock);
    list_for_each(pos, &early_suspend_handlers) {
        struct early_suspend *e;
        e = list_entry(pos, struct early_suspend, link);
        if (e->level > handler->level)
            break;
    }
    list_add_tail(&handler->link, pos);
    early_suspend_count++;
    if ((state & SUSPENDED) && handler->suspend)
        handler->suspend(handler);
    mutex_unlock(&early_suspend_lock);
}

    可以到source code详细查看这段函数体的实现过程,大意如下;
    
    通过扫描链表中的每一项来与将要注册的handle的level进行比较,将level小的这项加入到与之对比的链表项的后面
    
    下面看看有关suspend的hal层代码;
    
    const char * const NEW_PATHS[] = {
    "/sys/power/wake_lock",
    "/sys/power/wake_unlock",
    "/sys/power/state"
};
    首先定义了操作的接口,这些接口在kernel起来后就已注册好,任何一个要操作的接口,首先就需先打开:
    static int
open_file_descriptors(const char * const paths[])
{
    int i;
    for (i=0; i         int fd = open(paths[i], O_RDWR);
        if (fd < 0) {
            fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
            g_error = errno;
            return -1;
        }
        g_fds[i] = fd;
    }

    g_error = 0;
    return 0;
}

用户空间的电源管理系统会通过调用set_screen_state来触发底层的suspend流程
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 = snprintf(buf, sizeof(buf), "%s", on_state);
    else
        len = snprintf(buf, sizeof(buf), "%s", off_state);

    buf[sizeof(buf) - 1] = '\0';
    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;
}
该函数实质上是往接口中写men或on等字符串命令
    
    



你可能感兴趣的:(smart,phone,driver)