Linux的notifier机制的应用

在linux内核系统中,各个模块、子系统之间是相互独立的。Linux内核可以通过通知链机制来获取由其它模块或子系统产生的它感兴趣的某些事件。

notifier_block结构体在include/linux/notifier.h中定义:

struct notifier_block {
    notifier_fn_t notifier_call;
    struct notifier_block __rcu *next;
    int priority;
};

priority用来定义优先级,高优先级的处理例程将被优先执行,数值越大,优先级越高。

回到函数的原型定义:

typedef    int (*notifier_fn_t)(struct notifier_block *nb,
            unsigned long action, void *data);

TP属于输入子系统,可以通过获取framebuffer子系统来实现亮屏和灭屏时触发相应的事件。

fb_register_client和fb_unregister_client函数定义在drivers/video/fb_notify.c:

/**
 *  fb_register_client - register a client notifier
 *  @nb: notifier block to callback on events
 */
int fb_register_client(struct notifier_block *nb)
{
    return blocking_notifier_chain_register(&fb_notifier_list, nb);
}
 
/**
 *    fb_unregister_client - unregister a client notifier
 *    @nb: notifier block to callback on events
 */
int fb_unregister_client(struct notifier_block *nb)
{
    return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
}

当framebuffer子系统发生事件时,调用notifier_call_chain()来触发相应的处理函数。

/**
 * fb_notifier_call_chain - notify clients of fb_events
 *
 */
int fb_notifier_call_chain(unsigned long val, void *v)
{
    return blocking_notifier_call_chain(&fb_notifier_list, val, v);
}

下面是一个实例:

struct msg21xx_ts_data {
    struct input_dev *input;
    struct hrtimer timer;
    struct work_struct work;
    int irq;
    struct dentry *dir;
    char *ts_info;
    u8 addr;
    int fw_major;
    int fw_minor;
#ifdef CONFIG_FB
    struct notifier_block fb_notif;
#endif
    bool suspended;
    struct i2c_client *client;
    struct regulator *vdd;
    struct regulator *vcc_i2c;
    struct msg21xx_platform_data *pdata;
    struct workqueue_struct *msg21xx_wq;
    struct mutex msg21xx_mutex;
};

probe函数中与notifier相关部分实现:

struct msg21xx_ts_data *data;
 
data = kzalloc(sizeof(struct msg21xx_ts_data), GFP_KERNEL);
if (!data) {
    dev_err(&client->dev, "%s: Alloc mem fail!", __func__);
    err = -ENOMEM;
    goto exit;
}
 
#ifdef CONFIG_FB
data->fb_notif.notifier_call = fb_notifier_callback;
err = fb_register_client(&data->fb_notif);
if (err)
    dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
        err);
#endif

fb_notifier_callback实现:

#ifdef CONFIG_FB
static int fb_notifier_callback(struct notifier_block *self,
            unsigned long event, void *data)
{
    struct fb_event *evdata = data;
    int *blank;
    struct msg21xx_ts_data *msg21xx_data =
        container_of(self, struct msg21xx_ts_data, fb_notif);
 
    if (evdata && evdata->data && event == FB_EVENT_BLANK &&
            msg21xx_data && msg21xx_data->client) {
        blank = evdata->data;
        if (*blank == FB_BLANK_UNBLANK)
            msg21xx_ts_resume(&msg21xx_data->client->dev);
        else if (*blank == FB_BLANK_POWERDOWN)
            msg21xx_ts_suspend(&msg21xx_data->client->dev);
    }
 
    return 0;
}
#endif

msg21xx_ts_suspend和msg21xx_ts_resume实现如下,主要是操作TP的电源和RST脚,LCD灭屏时,为了降低系统的功耗,需要将TP的power关闭,同时将TP的复位脚拉低,让TP自身进入低功耗模式。

#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME)
static int msg21xx_ts_suspend(struct device *dev)
{
    struct msg21xx_ts_data *data = dev_get_drvdata(dev);
    int err;
 
    if (data->suspended) {
        dev_info(dev, "Already in suspend state\n");
        return 0;
    }
 
    disable_irq(data->client->irq);
 
    err = msg21xx_power_on(data, false);
    if (err)
        dev_err(dev, "power off failed");
 
    gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
 
    data->suspended = true;
    return 0;
}
 
static int msg21xx_ts_resume(struct device *dev)
{
    struct msg21xx_ts_data *data = dev_get_drvdata(dev);
    int err;
 
    if (!data->suspended) {
        dev_dbg(dev, "Already in awake state\n");
        return 0;
    }
 
    err = msg21xx_power_on(data, true);
    if (err) {
        dev_err(dev, "power on failed");
        return err;
    }
 
    enable_irq(data->client->irq);
    gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
    data->suspended = false;
    return 0;
}
#endif

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏mini188

聊聊从web session的共享到可扩展缓存设计

先从web session的共享说起 许多系统需要提供7*24小时服务,这类系统肯定需要考虑灾备问题,单台服务器如果宕机可能无法立马恢复使用,这必定影响到服务。...

22860
来自专栏非典型技术宅

Swift多线程:使用Thread进行多线程间通讯,协调子线程任务1. Thread的三种建立方式2. Thread的基本使用3. 使用NSCondition实现线程间通讯4. pthread

24920
来自专栏阿杜的世界

Java Web技术经验总结(十六)

13760
来自专栏java一日一条

Java线程面试题 Top 50

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚...

15520
来自专栏Crossin的编程教室

【Python 第36课】 异常处理

在程序运行时,如果我们的代码引发了错误,python就会中断程序,并且输出错误提示。 比如我们写了一句: print int('0.5') 运行后程序得到错误...

29570
来自专栏程序你好

C# API中的模型和它们的接口设计

11420
来自专栏C/C++基础

腾讯2016春季校园实习招聘技术岗初试(一面)问题汇总(CC++后台)

2016.4.11日广州参加了腾讯的CC++后台技术一面,安全技术类的面试。面试官人很温和,经历了大概70分钟的问答,特将遇到的面试问题汇总如下,自己总结学习,...

10110
来自专栏刘望舒

设计模式(十五)状态模式

前言 建议在阅读本文前先阅读设计模式(十一)策略模式这篇文章,虽说状态模式和策略模式的结构几乎是相同的,但是它们所解决的问题是不同的,读完这两篇文章你就会有了答...

21260
来自专栏谭广健的专栏

devexpress CLR20r3错误记录

好久没写过winform程序了,用devexpress写了个小工具,连一个本地的数据库,感觉不会出什么异常,连接时就没加捕获,调通之后就没管,因为特殊需求,需要...

28440
来自专栏Play & Scala 技术分享

Scala之美 - Future & map & flatMap

39980

扫码关注云+社区

领取腾讯云代金券