[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(¬ifier->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(¬ifier->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");