Input Subsystem 系統(tǒng)主要由 drivers/input/input.c input_register_device() 和 input_register_handler() 兩個(gè)函數(shù)實(shí)現(xiàn)。
Handler 組件通過(guò) input_register_handler 函數(shù)將邏輯設(shè)備操作結(jié)構(gòu)體注冊(cè)到 input_handler_list 鏈表中;
device 組件通過(guò) input_register_device 組件將直接對(duì)具體硬件的操作結(jié)構(gòu)體注冊(cè)到 input_dev_list 鏈表中
struct input_dev {
...
struct device dev;
...
struct list_head h_list; //與 input_dev關(guān)聯(lián)的 input_headle 的鏈表頭
struct list_head node; //用于將本設(shè)備連接到 input_dev_list
};
struct input_handler {
...
const struct file_operations *fops;
...
const struct input_device_id *id_table;//用戶和設(shè)備匹配, 這個(gè)是事件處理器所支持的input設(shè)備
...
struct list_head h_list; //所支持的 input_headle 結(jié)構(gòu)的鏈表的表頭
struct list_head node; //鏈入全局鏈表input_handler_list, 它連接了所有注冊(cè)到內(nèi)核的handler
};
struct input_handle {
...
struct input_dev *dev; //關(guān)聯(lián)的input_dev結(jié)構(gòu)
struct input_handler *handler; //關(guān)聯(lián)的input_headler結(jié)構(gòu)
struct list_head d_node; //input_headle通過(guò)d_node連接到了input_dev的h_list上
struct list_head h_node; //input_headle通過(guò)h_node連接到了input_headler的h_list上
};
input_dev / input_headler / input_headle 關(guān)系:
input_dev 是硬件驅(qū)動(dòng)層,代表一個(gè)input設(shè)備
input_headler 是事件處理層,代表一個(gè)事件處理器
input_headle 個(gè)人認(rèn)為屬于核心層, 代表一個(gè)配對(duì)的設(shè)備與事件處理器
那么input_dev 和input_handler是如何跟input子系統(tǒng)總線聯(lián)系起來(lái)的呢?
(linux)/drivers/input/input.c
input_init()
class_register(&input_class); //創(chuàng)建類
register_chrdev(INPUT_MAJOR, "input", &input_fops); //創(chuàng)建類下的設(shè)備, 并由此可知 file_operations結(jié)構(gòu)體變量為input_fops
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
//該結(jié)構(gòu)體只填充了 .open 方法, read / write / poll 等方法沒(méi)有填充, 那么肯定是由open做了些"工作"來(lái)間接實(shí)現(xiàn)了其他的功能, 那么就讓我們來(lái)看看 input_open_file的內(nèi)部
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
...
//以次設(shè)備號(hào)為下標(biāo),拿到一個(gè) input_handler, 在input_handler內(nèi)部有個(gè)file_operations成員
handler = input_table[iminor(inode) >> 5];
...
//將input_handler的file_operations成員拿出
new_fops = fops_get(handler->fops);
...
//將原來(lái)的fops保存起來(lái), 將新的fops給 file->f_op
old_fops = file->f_op;
file->f_op = new_fops;
//從此file->f_op都是 新的fops
err = new_fops->open(inode, file);
...
return err;
}
以上程序的關(guān)鍵是 input_table[], 那么input_table是怎么來(lái)的呢?
insmod時(shí)候調(diào)用
//注冊(cè)input_handler
input_register_handler()
input_table[handler->minor >> 5] = handler; //那么是誰(shuí)調(diào)用了input_register_handler 了呢?
//將handler加入 input_handler_list鏈表
list_add_tail(&handler->node, &input_handler_list);
//每個(gè) input_handler 都調(diào)用 input_attach_handler, 遍歷headler 查看是否支持dev
list_for_each_entry(handler, &input_handler_list, node)
//根據(jù)input_handler 的id_table 判斷能否支持該input_device
input_attach_handler(dev, handler);
插入設(shè)備調(diào)用
//注冊(cè)輸入設(shè)備
input_register_device()
//將每個(gè) input_device 都放入鏈表
list_add_tail(&dev->node, &input_dev_list);
//每個(gè) input_handler 都調(diào)用input_attach_handler, 遍歷handler, 查看能否支持dev
list_for_each_entry(handler, &input_handler_list, node)
//根據(jù)input_handler 的id_table 判斷能夠支持該input_device
input_attach_handler(dev, handler);
以上兩個(gè)函數(shù)非常對(duì)稱, 不管先調(diào)用哪個(gè)函數(shù)都最后調(diào)用了 input_attach_handler, 那么input_attach_handler 做了什么工作呢?
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
id = input_match_device(handler->id_table, dev);//遍歷id_table, 看找有沒(méi)有與dev匹配的
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);
它先比較了handler層的 input_handler的id_table和device層的input_dev, 如果handler能夠支持input_dev 則調(diào)用handler的connect將device和handler"連接"起來(lái)
//那么他們是怎么建立"連接"的呢? 主要看 handler 里的 connect 函數(shù) (這里以evdev為例來(lái)說(shuō)明)
evdev_connect
1. 申請(qǐng)一個(gè) handle 結(jié)構(gòu)體
2. 設(shè)置
handle.dev = input_dev;
handle.handler = input_handler;
3. input_dev->h_list = &handle;
input_hanlder->h_list = &handle;
這樣一來(lái)
device層可以通過(guò) input_dev的h_list先找到handle 然后再通過(guò)handle的handler找到 input_handler
handler層可以通過(guò)input_handler的h_list先找到handle然后再通過(guò)handle的dev找到 input_dev
兩者就靠 handle連接了起來(lái)
從編寫代碼的過(guò)程再捋一遍思緒:
1. 申請(qǐng)input_dev結(jié)構(gòu)體 input_allocate_device
2. 設(shè)置 input_dev
1) 可以產(chǎn)生哪類事件
2) 產(chǎn)生該類事件中的哪些事件
3. 將input_dev注冊(cè)到內(nèi)核
4. 實(shí)現(xiàn)業(yè)務(wù)邏輯代碼
申請(qǐng)中斷等...
問(wèn)題:
- input_table 是什么?
- 應(yīng)用層如何獲取input_event上報(bào)的事件?