• [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
    ", (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
    ", __func__);
    }
    
    static void demo_early_resume(struct demo_device *dev)
    {
        printk("%s
    ", __func__);
    }
    
    static int __init demo_init(void)
    {
        printk("%s
    ", __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
    ", __func__);
    
        demo_unregister_fb(&demo);
    }
    
    module_init(demo_init);
    module_exit(demo_exit);
    
    MODULE_DESCRIPTION("Notifier Demo Driver");
    MODULE_AUTHOR("AaronLee");
    MODULE_LICENSE("GPL");
  • 相关阅读:
    刷题19. Remove Nth Node From End of List
    刷题17. Letter Combinations of a Phone Number
    mysql图形化工具基本操作
    报错:ER_NO_DEFAULT_FOR_FIELD: Field 'status' doesn't have a default value
    express综合用法
    npm自定义上传
    node_第三方包下载文件package.jon详解
    正则表达式修改文字元素对齐方式
    初始化文章分类的方法 下拉的layui框
    标准git请求
  • 原文地址:https://www.cnblogs.com/lialong1st/p/11760272.html
Copyright © 2020-2023  润新知