Linux的notifier機制的應用


在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM