標籤:input handler input_dev handle evdev
在前文Linux/Android——input子系統核心 中概括了總體的結構,以及介紹了input核心的職責,其中有說道註冊input裝置時會去匹配已有的事件處理器handler,
而這個handler也是存放在一個鏈表裡面的,這裡介紹下input子系統中的事件處理input_handler機制.
撰寫不易,轉載需註明出處:http://blog.csdn.net/jscese/article/details/42238377#t6
evdev:
/kernel/drivers/input下眾多事件處理器handler其中的一個,可以看下源碼/kernel/drivers/input/evdev.c中的模組init:
static int __init evdev_init(void){return input_register_handler(&evdev_handler);}
這個初始化就是往input核心中註冊一個input_handler類型的evdev_handler,調用的是input.c提供的介面,input_handler結構前文有介紹,看下evdev_handler的賦值:
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,};
賦值各個函數指標!
input_register_handler:
可以看到上面的evdev handler 就是調用這個介面註冊到input核心中的,同樣evdev.c同目錄下也還有其它的handler,有興趣可以看看它們的init函數,都是會調用到這個介面去註冊的.
/** * 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); if (handler->fops != NULL) { if (input_table[handler->minor >> 5]) { retval = -EBUSY; goto out; } input_table[handler->minor >> 5] = handler; //給input.c定義的全域handler 數組賦值,evdev handler的次裝置號為64,這裡除以32,賦值在input_table[2] } list_add_tail(&handler->node, &input_handler_list); //添加進handler 鏈表 list_for_each_entry(dev, &input_dev_list, node) //同樣遍曆input_dev這個鏈表,依次調用下面的input_attach_handler去匹配input_dev,這個跟input_dev註冊的時候的情形類似 input_attach_handler(dev, handler); input_wakeup_procfs_readers(); out: mutex_unlock(&input_mutex); return retval;}
input核心中儲存的handler數組:
static struct input_handler *input_table[8];
這是儲存註冊到input核心中的handler數組,因為在之前input註冊的時候註冊的字元裝置主裝置號為13.字元裝置的次裝置號為0~255,可以有256個裝置,
這裡後面會看到一個handler可以connect處理32個input裝置,所以input體系中,最多擁有8個handler
這個匹配過程和上一篇中的過程是一樣的,最後匹配上的話會調用匹配上的handler 中connect指標指向的函數.
另外可以注意的是evdev是匹配所有裝置的,因為:
static const struct input_device_id evdev_ids[] = {{ .driver_info = 1 },/* Matches all devices */{ },/* Terminating zero entry */};
如果沒有特定的handler添加進handler鏈表,那麼在匹配的時候,只要有這個evdev的handler,最後都會匹配到evdev,這個具體可以去看看上篇的匹配過程.
我這邊調試的是usb觸控螢幕,所以用的是evdev的handler,下面看下evdev的connect.
evdev_connect:
註冊的evdev_handler中connect指向的函數為evdev_connect:
/* * Create new evdev device. Note that input core serializes calls * to connect and disconnect so we don't need to lock evdev_table here. */static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id){ struct evdev *evdev; int minor; int error; for (minor = 0; minor < EVDEV_MINORS; minor++) if (!evdev_table[minor]) break; if (minor == EVDEV_MINORS) { pr_err("no more free evdev devices\n"); return -ENFILE; }// 可以看到這裡evdev handler匹配串連好的裝置都以evdev 類型存在這個evdev_table數組的,這個數組大小為32個,這就是我上面說到的,為什麼只有8個handler//這裡是判斷evdev的32個位置中是否有空 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //為上面定義的*evdev分配記憶體空間 if (!evdev) return -ENOMEM; INIT_LIST_HEAD(&evdev->client_list); //以下都是對這個 evdev的初始化了 spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); dev_set_name(&evdev->dev, "event%d", minor); //給這個evdev命名 evdev->exist = true; evdev->minor = minor; // 以minor為索引賦值 evdev->handle.dev = input_get_device(dev); //evdev中的handle變數的初始化 ,後面分析這個handle ,這裡面儲存的就是已經匹配成功的input_dev 和 handler evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; device_initialize(&evdev->dev); error = input_register_handle(&evdev->handle); //把這個evdev中初始化好的handle 註冊到input核心中去,代表一個匹配成功的組合 if (error) goto err_free_evdev; error = evdev_install_chrdev(evdev); //把這個初始化好的evdev添加到上面說到過的evdev_table數組,以minor索引序號 if (error) goto err_unregister_handle; error = device_add(&evdev->dev); //把這個device 添加到/sys/class/input/下面,所以我們可以看到/dev/input下面看到:event0~31 字樣字元裝置檔案,這就是在上面命名的 if (error) goto err_cleanup_evdev; return 0; err_cleanup_evdev: evdev_cleanup(evdev); err_unregister_handle: input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); return error;}
evdev:
這裡的evdev變數的結構如下:
struct evdev{int open; //開啟標誌int minor; //次裝置號struct input_handle handle; //包含的handlewait_queue_head_t wait; //等待隊列struct evdev_client __rcu *grab; //強制綁定的evdev_client結構struct list_head client_list; //evdev_client 鏈表,這說明一個evdev裝置可以處理多個evdev_client,可以有多個進程訪問evdev裝置spinlock_t client_lock; /* protects client_list */struct mutex mutex;struct device dev;bool exist;};
關於這個結構變數我的理解是抽象出來一個裝置,代表一個
input_dev與其匹配好的
handler的組合(
handle),可以看作提供給事件處理層的一個封裝.
input_handle:
這個代表一個匹配成功的input dev和 handler組合,定義在input.h中,每個evdev中包含一個input_handle,並且註冊到input核心中:
/** * struct input_handle - links input device with an input handler * @private: handler-specific data * @open: counter showing whether the handle is 'open', i.e. should deliver * events from its device * @name: name given to the handle by handler that created it * @dev: input device the handle is attached to * @handler: handler that works with the device through this handle * @d_node: used to put the handle on device's list of attached handles * @h_node: used to put the handle on handler's list of handles from which * it gets events */struct input_handle { void *private; //指向上面封裝的evdev int open; const char *name; struct input_dev *dev; //input 裝置 struct input_handler *handler; // 一個input的handler struct list_head d_node; //鏈表結構 struct list_head h_node;};
input_register_handle:
看看這個handle的註冊,不要和handler搞混淆了,這不是一個概念~
/** * input_register_handle - register a new input handle * @handle: handle to register * * This function puts a new input handle onto device's * and handler's lists so that events can flow through * it once it is opened using input_open_device(). * * This function is supposed to be called from handler's * connect() method. */int input_register_handle(struct input_handle *handle){ struct input_handler *handler = handle->handler; struct input_dev *dev = handle->dev; //取出兩個成員... /* * Filters go to the head of the list, normal handlers * to the tail. */ if (handler->filter) list_add_rcu(&handle->d_node, &dev->h_list); else list_add_tail_rcu(&handle->d_node, &dev->h_list);//把這個handle的d_node 加到對應input_dev的h_list鏈表裡面... list_add_tail_rcu(&handle->h_node, &handler->h_list);//把這個handle的h_node 加到對應input_handler的h_list鏈表裡面...}
這個註冊是把handle 本身的鏈表加入到它自己的input_dev 以及 input_handler的h_list鏈表中,這樣以後就可以通過h_list遍曆到這個handle,
這樣就實現了三者的綁定聯絡.
另外在evdev中還有個結構:
struct evdev_client { unsigned int head; //buffer數組的索引頭 unsigned int tail; //buffer數組的索引尾 unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct wake_lock wake_lock; bool use_wake_lock; char name[28]; struct fasync_struct *fasync; //非同步通知函數 struct evdev *evdev; //包含一個evdev變數 struct list_head node; //鏈表 unsigned int bufsize; struct input_event buffer[]; //input_event資料結構的數組,input_event代表一個事件,基本成員:類型(type),編碼(code),值(value)};
這個結構會在evdev被開啟的時候 建立,這裡關於evdev的初始以及在input系統中承接作用暫時介紹到這裡,
前文 Linux/Android——輸入子系統input_event傳遞 中有記錄從裝置驅動傳遞上來的event是怎麼到input核心,然後接著往上傳遞的,接下來就是用到evdev傳遞了.下篇介紹.
Linux/Android——input_handler之evdev