1、框架介绍
实现所在文件:driversbasepowerwakeup.c
函数所在文件:includelinuxpm_wakeup.h
该文件函数较多,主要实现了wakesource的功能,用于系统判断当前是否有事件阻止睡眠。整套框架基本上是围绕着combined_event_count这个变量在处理逻辑,在此变量中,高16位记录系统所有的wakeup event总数,低16位记录是否有wakeup events在处理中。在每次调用wakeup_source_activate时,wakeup events会加1,;每次调用wakeup_source_deactivate时,wakeup events会减1,同步wakeup event会加1.对于每次系统是否能够进入睡眠,通过判定是否有wakeup events在处理来判断。接口pm_wakeup_pending就实现了该功能。
2、接口实现
对外提供的接口主要有以下几个,本文也主要介绍以下主要函数接口:
2.1 操作直接操作wakeup_source来达到持锁和释放锁的功能0、struct wakeup_source *wakeup_source_create(const char *name)
负责create一个struct wakeup_source类型的变量,注意该函数中有申请内存操作,不能在中断上下文中调用,通常在系统初始化时调用创建所需wakesource。
struct wakeup_source *wakeup_source_create(const char *name)
{
struct wakeup_source *ws;
const char *ws_name;
int id;
ws = kzalloc(sizeof(*ws), GFP_KERNEL);
if (!ws)
goto err_ws;
ws_name = kstrdup_const(name, GFP_KERNEL);
if (!ws_name)
goto err_name;
ws->name = ws_name;
id = ida_alloc(&wakeup_ida, GFP_KERNEL);
if (id < 0)
goto err_id;
ws->id = id;
return ws;
err_id:
kfree_const(ws->name);
err_name:
kfree(ws);
err_ws:
return NULL;
}
EXPORT_SYMBOL_GPL(wakeup_source_create);
1、void wakeup_source_destroy(struct wakeup_source *ws)
负责释放create创建的变量所占用的资源,通常不会被调用,一般一个wakesource创建后会一直使用。
void wakeup_source_destroy(struct wakeup_source *ws)
{
if (!ws)
return;
__pm_relax(ws);
wakeup_source_record(ws);
wakeup_source_free(ws);
}
2、void wakeup_source_add(struct wakeup_source *ws)
该函数负责把create创建的wakesource变量添加到wakeup_sources全局链表中统一维护记录。
void wakeup_source_add(struct wakeup_source *ws)
{
unsigned long flags;
if (WARN_ON(!ws))
return;
spin_lock_init(&ws->lock);
timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
ws->active = false;
raw_spin_lock_irqsave(&events_lock, flags);
list_add_rcu(&ws->entry, &wakeup_sources);
raw_spin_unlock_irqrestore(&events_lock, flags);
}
EXPORT_SYMBOL_GPL(wakeup_source_add);
3、void wakeup_source_remove(struct wakeup_source *ws)
该函数负责把对应wakesource从wakeup_sources中删除掉。
4、void __pm_stay_awake(struct wakeup_source *ws)
可以理解为持锁,阻止系统进入睡眠,通过调用wakeup_source_activate来达到增加wakeup events。
5、void __pm_relax(struct wakeup_source *ws)
释放锁,该wakesource同意系统进入睡眠,最终通过调用wakeup_source_deactivate来达到wakeup events减一的效果。
6、void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard)
可以理解为带超时时间的锁,在msec内,该锁会释放,超时回调机制通过定时器模块来实现。
2.2 通过dev来间接操作wakeup_source达到持锁和释放锁的功能0、struct wakeup_source *wakeup_source_register(struct device *dev,const char *name)
对create和add接口的封装,通常在系统初始化时调用注册wakesource,使用上要比单独调用create和add方便些,约束之处也可以看到,必须与一个dev相关联。在一个与dev无关的相关实现中,dev传参可以为NULL。
1、void wakeup_source_unregister(struct wakeup_source *ws)
register的逆操作,释放占用的资源
2、void pm_stay_awake(struct device *dev)
作用等同__pm_stay_awake,是对__pm_stay_awake进行了一次封装,取值为dev->power.wakeup。
3、void pm_relax(struct device *dev)
作用等同__pm_relax(struct wakeup_source *ws),是对__pm_relax(struct wakeup_source *ws)进行了一层封装,取值同样为dev->power.wakeup
4、void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard)
作用等同pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard),是对pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard)进行了一层封装,取值同样为dev->power.wakeup
2.3 提供获取相关wakesource值的接口0、bool pm_wakeup_pending(void)
确定当前是否还有event事件正在处理,以判定是否可以睡眠。在此多介绍一个函数:split_counters,该函数返回当前正在或者需要处理的wakeup_event个数和wakeup event总数。
1、bool pm_get_wakeup_count(unsigned int *count, bool block)
获取当前wakeup event总数,存储在count变量的地址中。同时,如果当前有event正在处理中,返回false,否则返回true.
2、bool pm_save_wakeup_count(unsigned int count)
保存当前wakeup event总数在saved_count变量中,该函数被autosleep的try_to_suspend函数调用,用于判断是否有wakeup event事件发生



