前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux的notifier机制的应用

Linux的notifier机制的应用

作者头像
233333
发布2018-12-06 10:39:37
1.4K0
发布2018-12-06 10:39:37
举报

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

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

代码语言:javascript
复制
struct notifier_block {
    notifier_fn_t notifier_call;
    struct notifier_block __rcu *next;
    int priority;
};

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

回到函数的原型定义:

代码语言:javascript
复制
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:

代码语言:javascript
复制
/**
 *  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()来触发相应的处理函数。

代码语言:javascript
复制
/**
 * 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);
}

下面是一个实例:

代码语言:javascript
复制
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相关部分实现:

代码语言:javascript
复制
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实现:

代码语言:javascript
复制
#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自身进入低功耗模式。

代码语言:javascript
复制
#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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-11-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档