Linux的notifier机制在TP中的应用

本文介绍了Linux内核中的通知链机制,详细解释了notifier_block结构体的作用及优先级设定,并通过实例展示了如何利用通知链机制实现触摸屏模块响应帧缓冲区子系统的屏幕开关事件。

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

struct notifier_block {
	notifier_fn_t notifier_call;
	struct notifier_block __rcu *next;
	int priority;
};
priority用来定义优先级,高优先级的处理例程将被优先执行,数值越大,优先级越高。
回到函数的原型定义:
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:
/**
 *	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()来触发相应的处理函数。
/**
 * 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);
}
下面是一个实例:
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相关部分实现:
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实现:
#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自身进入低功耗模式。
#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

Linux 中的 notifier 机制是一种用于内核子系统之间通信的重要机制,它允许在某些事件发生时,相关的组件能够接收到通知并作出相应的处理。这种机制常用于各种内核子系统,如网络、文件系统、设备驱动等,以确保当系统状态发生变化时,所有相关部分都能得到更新[^1]。 ### 核心原理 notifier 机制的核心在于**通知链(notifier chain)**,其本质是一个由 `struct notifier_block` 结构体组成的链表。每个注册到通知链的组件都提供一个回调函数(`notifier_call`),当特定事件发生时,内核会遍历整个链表,并调用这些回调函数以通知各个组件。 核心结构体如下: ```c struct notifier_block { notifier_fn_t notifier_call; // 回调函数 struct notifier_block_rcu *next; int priority; // 优先级 }; ``` 回调函数的原型为: ```c typedef int (*notifier_fn_t)(struct notifier_block *nb, unsigned long action, void *data); ``` 其中,`action` 表示事件类型,`data` 是传递给回调函数的参数[^2]。 ### 使用方法 #### 1. 定义并注册回调函数 首先,定义一个 `struct notifier_block` 实例,并实现其回调函数。例如: ```c static int my_notifier_callback(struct notifier_block *nb, unsigned long action, void *data) { switch (action) { case MY_EVENT_1: printk(KERN_INFO "Received event MY_EVENT_1\n"); break; case MY_EVENT_2: printk(KERN_INFO "Received event MY_EVENT_2\n"); break; default: return NOTIFY_DONE; } return NOTIFY_OK; } static struct notifier_block my_notifier = { .notifier_call = my_notifier_callback, .priority = 0, }; ``` 然后,在模块初始化时注册该回调函数: ```c static int __init my_module_init(void) { blocking_notifier_chain_register(&my_notifier_chain, &my_notifier); return 0; } ``` #### 2. 触发通知 当某个事件发生时,通过调用 `blocking_notifier_call_chain` 函数触发回调函数: ```c blocking_notifier_call_chain(&my_notifier_chain, MY_EVENT_1, NULL); ``` 这会通知所有注册到该链表的组件,并执行它们的回调函数[^2]。 ### 应用场景 notifier 机制广泛应用Linux 内核中,例如: - **网络子系统**:如 IPv4 路由变更通知机制(FIB Notifier),用于在路由表发生变化时通知相关模块[^4]。 - **设备驱动**:用于设备状态变化的通知,如设备插入或移除。 - **电源管理**:用于系统进入或退出休眠状态时的通知。 ### 注意事项 - notifier 机制只能在内核空间中使用,不能用于内核与用户空间之间的通信。用户空间与内核之间的通信通常使用 `ioctl` 或 `sysfs` 等机制。 - 多个回调函数可以注册到同一个通知链上,优先级(`priority`)决定了它们的执行顺序。 - 通知链的实现位于 `kernel/notifier.c`,头文件为 `include/linux/notifier.h`[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值