文章目录
前言
两个驱动模组之间的通信:A驱动模组发生了一些事件,需要通知B驱动模组,这时就可以使用通知链。
通知链 内核中的具体实现就不描述了,感兴趣可以去查看一下。
一、接口函数
头文件:
#include <linux/notifier.h>
这里使用阻塞式的通知链
//初始化一个通知链
#define BLOCKING_NOTIFIER_HEAD(name)
//通知链的注册,模块需要被通知,根据前言,注册就使用在模块B
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
//通知链的通知,模块需要发出通知到其他模块,根据前言,通知就使用在模块A
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);
//哪里注册,就哪里使用解除注册,解除注册后,相应的就收不到通知链
int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb);
二、使用例子
2.1.创建通知链函数接口
2.1.1 kk_test_notifty.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2024 KKC Inc.
*/
#ifndef __KK_TEST_NOTIFY_H__
#define __KK_TEST_NOTIFY_H__
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/notifier.h>
/* The mipi dphy enable occurred */
#define KK_TEST_ENABLE 0x78
int kk_test_notifier_register(const char *source, struct notifier_block *nb);
int kk_test_notifier_unregister(struct notifier_block *nb);
int kk_test_notifier_call_chain(unsigned long val, void *v);
#endif
2.1.2 kk_test_notifty.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 KKC Inc.
*/
#include <linux/module.h>
#include "kk_test_notify.h"
static BLOCKING_NOTIFIER_HEAD(kk_test_notifier_list);
int kk_test_notifier_register(const char *source, struct notifier_block *nb)
{
if (!source)
return -EINVAL;
printk(":%s", source);
return blocking_notifier_chain_register(&kk_test_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(kk_test_notifier_register);
int kk_test_notifier_unregister(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&kk_test_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(kk_test_notifier_unregister);
int kk_test_notifier_call_chain(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&kk_test_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(kk_test_notifier_call_chain);
MODULE_AUTHOR("AIC <kk.z@kkc.com>");
MODULE_DESCRIPTION("kk test notify");
MODULE_LICENSE("GPL v2");
2.2 使用RK3568的代码进行测试
这里想在mipi的dphy上电前,让屏端那边做点事。
根据上述需求,mipi的dphy上电前可以做一个通知发送(dw-mipi-dsi.c代码里),屏端驱动(panel-simple.c代码里)那里可以做一个通知的接收处理
注意1:关于2.1的通知链的编译,我们直接放在drm/rockchip的Makefile里了
rockchipdrm-y := kk_test_notify.o
注意2:关于通知链的头文件包含问题
/*
* rockchip_drm_drv.h这个头文件,dw-mipi-dsi.c和panel-simple.c都引用了
* 因此,把#include "em_mipi_dphy_notify.h"放到rockchip_drm_drv.h中
*/
2.2.1 通知的发送(dw-mipi-dsi.c代码里)
mipi的dphy上电是在dw-mipi-dsi.c里,直接贴代码
//我们会在dw_mipi_dsi_encoder_enable这里func里进行操作
static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
{
...
//这里仅关注我们想要的内容
//仅encoder->crtc->state->active == 1时才通知
if (encoder->crtc->state->active) {
kk_test_notifier_call_chain(KK_TEST_ENABLE, "active:1");
}
//下面这个func就是mipi dphy上电了,下面会贴一部分代码
dw_mipi_dsi_pre_enable(dsi);
...
}
static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi)
{
...
//省略的大部分都是对寄存器做了一些操作,这里就不看了
//下面这个就是上电了
mipi_dphy_power_on(dsi);
...
}
2.2.2 通知的接收(panel-simple.c代码里)
static int __init panel_simple_init(void)
{
int err;
err = platform_driver_register(&panel_simple_platform_driver);
if (err < 0)
return err;
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
if (err < 0)
return err;
}
//上述代码注册成功后,才会注册这个通知链
kk_test_notifier_register("kk_test", &kk_test_active_notifier);
return 0;
}
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
rootfs_initcall(panel_simple_init);
#else
module_init(panel_simple_init);
#endif
//这里方便思路往下走,就不把kk_test_active_notifier按编译顺序贴上面了,直接往下贴
static int kk_test_active_notifier_callback(struct notifier_block *nb, unsigned long value, void *v)
{
printk("%s \n", __func__);
if (value == KK_TEST_ENABLE){
printk("%s KK_TEST_ENABLE\n", __func__);
}
return NOTIFY_DONE;
}
static struct notifier_block kk_test_active_notifier= {
.notifier_call = kk_test_active_notifier_callback,
};
2.3 Log
红线右侧是使用adb使系统进入休眠,然后休眠唤醒
红线左侧是我们的log,执行第二次input keyevent 26 休眠唤醒后,就会出现左侧log。