[Linux] 内核通知链 notifier

Linux 内核中每个模块之间都是独立的,如果模块需要感知其他模块的事件,就需要用到内核通知链。

最典型的通知链应用就是 LCD 和 TP 之间,TP 需要根据 LCD 的亮灭来控制是否打开关闭触摸功能。

通俗的讲,LCD 会创建一个函数链表,TP 会将 suspend 和 resume 函数添加到链表中,当 LCD 发生亮灭变化时,会根据情况执行链表上所有对应的函数,函数会根据不同的动作执行 TP 的 suspend 和 resume 函数。

 

下面参考 TP 写一个内核通知链 demo。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/notifier.h>

// 构造dmeo的结构体,包括需要执行的函数
struct demo_device {
    struct notifier_block fb_notif;
    void (*demo_suspend)(struct demo_device *dev);
    void (*demo_resume)(struct demo_device *dev);
    struct mutex ops_lock;
};

struct demo_device demo;

// 当LCD状态变化时执行的函数
static inline int fb_notifier_callback(struct notifier_block *self,
                unsigned long action, void *data)
{
    struct demo_device *notifier;
    struct fb_event *event = data;
    int blank_mode;
    int ret = 0;

    // 根据参数fb_notif查找结构体demo_device的首地址
    notifier = container_of(self, struct demo_device, fb_notif);

    mutex_lock(&notifier->ops_lock);

    switch (action) {
    // LCD灭屏
    case FB_EARLY_EVENT_BLANK:
        blank_mode = *((int *)event->data);
        if (blank_mode != FB_BLANK_UNBLANK)
            notifier->demo_suspend(notifier);
        break;

    // LCD亮屏
    case FB_EVENT_BLANK:
        blank_mode = *((int *)event->data);
        if (blank_mode == FB_BLANK_UNBLANK)
            notifier->demo_resume(notifier);
        break;

    default:
        break;
    }

    mutex_unlock(&notifier->ops_lock);

    if (ret < 0)
    {
        printk("demo_notifier_callback error action = %x, blank_mode = %x\n", (int)action, blank_mode);
        return ret;
    }

    return NOTIFY_OK;
}

static inline int demo_register_fb(struct demo_device *dev)
{
    memset(&dev->fb_notif, 0, sizeof(dev->fb_notif));
    // 给回调函数赋值,也就是LCD状态变化时执行的函数
    dev->fb_notif.notifier_call = fb_notifier_callback;
    mutex_init(&dev->ops_lock);

    // 将demo加入LCD的内核通知链
    return fb_register_client(&dev->fb_notif);
}

static inline void demo_unregister_fb(struct demo_device *dev)
{
    // 将demo从LCD的内核通知链删除
    fb_unregister_client(&dev->fb_notif);
}

static void demo_early_suspend(struct demo_device *dev)
{
    printk("%s\n", __func__);
}

static void demo_early_resume(struct demo_device *dev)
{
    printk("%s\n", __func__);
}

static int __init demo_init(void)
{
    printk("%s\n", __func__);

    demo.demo_suspend = demo_early_suspend;
    demo.demo_resume = demo_early_resume;
    
    demo_register_fb(&demo);
    
    return 0;
}

static void __exit demo_exit(void)
{
    printk("%s\n", __func__);

    demo_unregister_fb(&demo);
}

module_init(demo_init);
module_exit(demo_exit);

MODULE_DESCRIPTION("Notifier Demo Driver");
MODULE_AUTHOR("AaronLee");
MODULE_LICENSE("GPL");

 

posted @ 2019-10-30 11:35  LeeAaron  阅读(805)  评论(0编辑  收藏  举报