這一篇,我們來分析input_register_handler 這個非常重要的函數。就像之前說過的一樣,這是註冊一個驅動。
我們去input目錄下看看那些檔案調用的這個函數,分別有:evdev.c(evdev驅動)、joydev.c(joydev驅動)、keychord.c(按鍵驅動)、mousedev.c(滑鼠驅動)。
也即是每個檔案,對於一種驅動,並在裡面進行註冊驅動。
好的,那麼我們以evdev.c為例子分析就好了。因為,觸控螢幕裝置也是對應這個驅動。
1、看看入口函數
點擊(此處)摺疊或開啟 static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
入口函數裡面,啥都沒幹,就直接註冊了一個evdev_handler,夠直接把。哈哈!
struct input_handler evdev_handler 這幾個機構體裡面的幾個元素都比較重要,後面都會用到,現在先來個大概的瞭解。
.event = evdev_event, : 當時間上報的時候,會調用到此函數。
.connect = evdev_connect, :當驅動和裝置匹配的時候會調用到
.disconnect = evdev_disconnect, :這個還沒研究
.fops = &evdev_fops, :這個handler的操作函數
.minor = EVDEV_MINOR_BASE, :EVDEV 此裝置號的基值
.name = "evdev", : 名字啦
.id_table = evdev_ids, :驅動和裝置是否匹配,需要通過id_table來驗證。這裡的evdev_ids 看到上面的注釋沒“match all devices ”,就是匹配所有設
備。
2、詳細分析下input_register_handler 這個函數
點擊(此處)摺疊或開啟 /**
* input_register_handler - register a new input handler
* @handler: handler to be registered
*
* This function registers a new input handler (interface) for input
* devices in the system and attaches it to all input devices that
* are compatible with the handler.
*/
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
int retval;
retval = mutex_lock_interruptible(&input_mutex);
if (retval)
return retval;
INIT_LIST_HEAD(&handler->h_list); //初始化h_list頭部
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler; //將handler插入數組,其位置是handler->minor >> 5,也就是除以32 }
list_add_tail(&handler->node, &input_handler_list); // 將handler->node插入到input_handler_list鏈表,深入程式碼分析可知,是插在input_handler_list頭部的後面
list_for_each_entry(dev, &input_dev_list, node) //遍曆input_dev_list鏈表,對每一個dev調用input_attach_handler函數,看是否匹配。
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex);
return retval;
}
EXPORT_SYMBOL(input_register_handler); 上面的注釋也說的很清楚,就是註冊一個input_handler。函數的分析,代碼旁邊的注釋也說了。
2.1 我們將重點集中下面這句代碼。 list_for_each_entry ( dev , & input_dev_list , node )
input_attach_handler ( dev , handler ) ;
先看看list_for_each_entry是怎麼定義的
點擊(此處)摺疊或開啟 /**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member)) 注釋說得很清楚,就是對於給定的某種類型的鏈表進行遍曆,其實就是一個for 迴圈。我們帶入就是下面這樣