Linux輸入子系統架構分析(1)

來源:互聯網
上載者:User

標籤:linux輸入子系統   輸入子系統   input子系統   

在Linux下的輸入裝置鍵盤、觸控螢幕、滑鼠等都可以用輸入子系統來實現驅動。輸入子系統分為三層,核心層和裝置驅動層,事件層。核心層和事件層由Linux輸入子系統本身實現,裝置驅動層由我們實現。我們在裝置驅動層將輸入事件上報給核心層input.c,核心層找到匹配的事件層,將事件交給事件層處理,事件層處理完後傳遞到使用者空間。

我們最終要搞清楚的是在使用者空間調用open和read最終在核心中是怎樣處理的,向核心上報的事件又是誰處理的,處理完後是怎樣傳遞到使用者空間的?


上面兩個圖是輸入子系統的架構。

下面以按鍵驅動為例分析輸入子系統的工作流程。

裝置驅動層:

在裝置驅動層的init入口函數中調用input_allocate_device(),分配返回一個input_dev結構體,填充該結構體,調用input_register_device(button_dev),註冊裝置。跟蹤input_register_device如下:

list_add_tail(&dev->node, &input_dev_list);將input_dev結構體放進input_dev_list鏈表中
list_for_each_entry(handler, &input_handler_list, node)遍曆input_handler_list鏈表中的每一個handler

input_attach_handler(dev, handler);將input_dev和handler比較

input_match_device(handler->id_table, dev);<*input.c*>
handler->connect(handler, dev, id);<*input.c*>比較的方式是通過對比handler的id_table和input_dev,若找 到匹配的handler,則調用handler的connect方法。

在evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)中調用了input_register_handle,調用handle之前填充handle中成員dev和handler結構體。

evdev->handle.dev = input_get_device(dev);
evdev->handle.handler = handler;

在input_register_handle中list_add_tail_rcu(&handle->d_node, &dev->h_list)list_add_tail(&handle->h_node, &h andler->h_list)兩個函數將handle加入進handler和dev的h_list鏈表中。通過dev->h_list可以找到handle,通過handle找到handle.handler,同理,通過handler->h_list可以找到handle,再找到handle.dev。

關鍵的問題來了?handler到底是什嗎?由誰註冊的?handler是事件層調用核心層的函數註冊的。

事件層:(evdev.c,keyboard.c,ts.c)

 static struct input_handler evdev_handler = {//handler結構體
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};

在evdev_init(void)入口函數中調用input_register_handler(&evdev_handler)來註冊handler,註冊的handler會放入input_table[ ]數組中。

核心層:(input.c)

核心層的入口函數input_init(void)註冊裝置input。

當在應用程式層調用open時會在核心中調用input_open_file(struct inode *inode, struct file *file),根據handler =input_table[iminor(inode) >> 5];根據開啟的檔案的次裝置號從數組input_table中得到登入的對應的handler。

new_fops = fops_get(handler->fops)從handler中得到新的fop。

file->f_op = new_fops;
err = new_fops->open(inode, file);open最終調用的是handler->fops->open。原來的裝置驅動的open等方法是自己寫的,現在輸入子系統中的事件層幫我們寫好了open等裝置方法。同理在應用程式層調用read會呼叫事件層中的read,即handler->fops->read,即evdev_fops.read,在read中會阻塞。直到在裝置驅動層中過input_report_key上報事件:

input_event(dev, EV_KEY, code, !!value);

input_handle_event(dev, type, code, value); 

input_pass_event(dev, type, code, value);

handle->handler->event(handle,type, code, value);調用handler中的event事件方法,處理完上報的事件後,喚醒休眠的read,再read出事件的處理結果。

總結:

在使用者空間調用open將最終呼叫事件層中handler的fops的open裝置方法,具體是匹配到evdev.c還是keyboard.c的handler要根據裝置驅動init入口函數中填充的input_dev結構體的id_table。使用者空間調用read將調用handler的read。在裝置驅動中通過input_event上報事件到核心層,最終調用對應的handler的event方法來處理事件,處理完後通過read傳遞到使用者空間。這樣就搞清楚了open是誰調用的?read是誰調用的?



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.