fb的notifier
fb的notifier
背景
最近调试了一个BUG:
一个平板使用hall传感器检测键盘保护套的开合,但是发现有时候合上保护套时,屏幕并没有关闭。
最后发现是CONFIG_FB=y
配置没打开,导致hall传感器驱动里的fb的notifier
没起作用,从而使获取的 suspend/resume 的状态异常,具体的细节不在这详述了,这里主要想扩展并记录下这个fb
的notifier
。
使用
有时候,我们需要监听显示屏的一些事件,根据事件的状态来进行一些操作,比如常见的关闭显示屏时,触摸屏进入休眠等等
- 确认内核配置
确认已打开CONFIG_FB_NOTIFY
配置, 只要CONFIG_FB
打开默认就打开了CONFIG_FB_NOTIFY
CONFIG_FB_CMDLINE=y
CONFIG_FB_NOTIFY=y
CONFIG_FB=y
- 代码实现
这里主要以常用的FB_EVENT_BLANK
事件为例,下面是部分伪代码实现:
struct yyy {
...
struct notifier_block fb_notif; /*FB callback*/
};
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct yyy *xxx;
struct fb_event *event = data;
xxx = container_of(self, struct yyy, fb_notif);
if (action != FB_EVENT_BLANK)
return NOTIFY_DONE;
switch (*((int *)event->data)) {
case FB_BLANK_UNBLANK:
/* resume操作 */
break;
case FB_BLANK_POWERDOWN:
/* suspend操作 */
break;
default:
break;
}
return NOTIFY_OK;
}
static int zzz_probe(...)
{
struct yyy *xxx;
...
xxx->fb_notif.notifier_call = fb_notifier_callback;
err = fb_register_client(&xxx->fb_notif);
...
}
static int zzz_remove(...)
{
...
fb_unregister_client(&xxx->fb_notif);
...
}
fb blank的一些状态定义:
enum {
/* screen: unblanked, hsync: on, vsync: on */
FB_BLANK_UNBLANK = VESA_NO_BLANKING,
/* screen: blanked, hsync: on, vsync: on */
FB_BLANK_NORMAL = VESA_NO_BLANKING + 1,
/* screen: blanked, hsync: on, vsync: off */
FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1,
/* screen: blanked, hsync: off, vsync: on */
FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1,
/* screen: blanked, hsync: off, vsync: off */
FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1
};
内部实现流程
fb
的notifier
其实就是一个 blocking notifier 可阻塞通知链:
static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
fb_register_client()
函数里面就是调用的通知链注册函数,注册回调到fb的通知列表里面,fb_unregister_client()
对应的就是相应的注销操作,具体实现在:drivers/video/fbdev/core/fb_notify.c
,都是通知链常规操作的一层简单封装
然后在需要通知的地方调用fb_notifier_call_chain()
函数,fb的通知主要集中在drivers/video/fbdev/core/fbmem.c
里面,我们常用的 blank 事件的通知在fb_blank()
函数中:
int
fb_blank(struct fb_info *info, int blank)
{
struct fb_event event;
int ret = -EINVAL;
if (blank > FB_BLANK_POWERDOWN)
blank = FB_BLANK_POWERDOWN;
event.info = info;
event.data = ␣
if (info->fbops->fb_blank)
ret = info->fbops->fb_blank(blank, info);
if (!ret)
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
return ret;
}
EXPORT_SYMBOL(fb_blank);
参考
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论