LINUX輸入子系統詳解

2021-07-11 16:15:34 字數 4982 閱讀 3769

輸入子系統:

為何引入:

以前我們寫一些輸入裝置(鍵盤滑鼠等)的驅動都是採用字元裝置、混雜裝置處理的。

為了實現對分散的、不同類別的輸入裝置進行統一驅動,出現了輸入子系統

自己寫驅動程式時需要: 1 major

2 file_operation

3 register_chrdev

4 入口函式

5 出口函式

輸入子系統: 別人已經幫你做好上述

我們需要弄清楚把自己**融合進去

輸入子系統框架

總體框架:

//使用者程式設計的介面(裝置節點),並處理驅動層提交的資料

輸入子系統事件處理層 *evdev.c //輸入事件驅動

//為裝置驅動層提供了規範和介面。裝置驅動層只要關心如何驅動硬體並獲得硬體資料,然後呼叫核心層提供的介面,核心層會自動把資料提交給事件處理層

//它的存在遮蔽了使用者到裝置驅動的互動細節,為裝置驅動層和事件處理層提供了相互通訊的統一介面

輸入子系統核心層 input.c

//主要完成對硬體裝置的讀寫訪問,中斷設定,並把硬體產生的事件轉換成核心層定義的規範交給事件處理層

輸入子系統裝置驅動層 // 輸入裝置驅動

input_table 全域性 input_handler型別的陣列

input.c 核心層: 中轉作用

入口函式:

input_init: //建立裝置類並註冊裝置,對照自己寫的驅動,為了可以自動掛接,還沒有class_device_create,

//應該是在我們input_register_device之後,呼叫handler的connect函式建立連線時在類下建立裝置

err = class_register(&input_class);

err = register_chrdev(input_major, "input", &input_fops);

static const struct file_operations input_fops = ;

struct input_handler ;

問:只有乙個open函式如何讀

input_open_file:

struct input_handler *handler = input_table[iminor(inode) >> 5];

new_fops = fops_get(handler->fops)

file->f_op = new_fops; // ->&evdev_fops

err = new_fops->open(inode, file);

input_table陣列由誰構造:

input_register_handler:input_table[handler->minor >> 5] = handler; 純軟體構造

evdev.c keyboard.c mousedev.c -> input_register_handler向核心層註冊,裝置子系統已經向核心層註冊,我們不用管

裝置: input_register_device->input.c 硬體

建立handler與device聯絡:

input_device結構 與input_handler結構中的.id_table比較

可以的話呼叫input_handler.connect函式建立連線

input_register_device: //裝置驅動註冊為裝置委託核心做的事情

list_add_tail(&dev->node, &input_dev_list); //將輸入裝置掛接到輸入裝置鍊錶input_dev_list中

//查詢並匹配輸入裝置對應的事件處理層,通過input_handler_list鍊錶

list_for_each_entry(handler, &input_handler_list, node)

input_attach_handler(dev, handler); //根據input_handler的id_table判斷能否支援這個input_device

input_attach_handler:

id = input_match_device(handler->id_table, dev);

input_device結構 與input_handler結構中的.id_table比較

可以的話呼叫input_handler.connect函式建立連線

error = handler->connect(handler, dev, id);

handler->connect(handler, dev, id);:如何具體的連線:

通過evdev->handle,handle結構有兩個變數分別是dev,input_handler

輸入裝置驅動最終的目的就是能夠與事件處理層的事件驅動相互匹配,但是在drivers/input目錄下有evdev.c事件驅動、mousedev.c事件驅動、joydev.c事件驅動

等等,我們的輸入裝置產生的事件應該最終上報給誰,然後讓事件驅動再去處理呢?

其實evdev.c mousedev.c等genuine硬體輸入裝置的處理方式的不同抽象除了不同

的事件處理介面幫助上層去呼叫而我們寫的裝置驅動程式只不過是完成了硬體暫存器中數

據的讀寫,但提交給使用者的事件必須是經過事件處理層的封裝和同步才能夠完成的,事件處

理層提供給使用者乙個統一的介面來操作。

整個關聯過程:

input_register_device->input_attach_handler->input_match_device->handler->connect

->input_register_handle(evdev.c)->input_dev,handler->input_dev_list,input_handler_list

核心層與事件處理層建立聯絡:

err = class_register(&input_class); //建立類

err = register_chrdev(input_major, "input", &input_fops); //註冊input裝置

input_register_handler:

//放入陣列

input_table[handler->minor >> 5] = handler;

//放入鍊錶

list_add_tail(&handler->node, &input_handler_list);

list_for_each_entry(dev, &input_dev_list, node)

input_attach_handler(dev, handler);

怎麼建立連線:

1.分配乙個input_handle結構體

evdev = kzalloc(sizeof(struct evdev), gfp_kernel); //分配乙個input_handle結構

2.設定input_handle結構體

input_handle.dev = input_dev;

input_handle_handler = input_handler

3.註冊

input_handler->dev = &input_handle

input_dev->h_list = &input_handle

//設定

evdev->handle.dev = dev;

evdev->handle.name = evdev->name;

evdev->handle.handler = handler;

evdev->handle.private = evdev;

sprintf(evdev->name, "event%d", minor);

//註冊

error = input_register_handle(&evdev->handle);

input_device 與 input_handler中均有.h_list ,兩者通過.h_list找到input_handle,

然後分別通過input_handle的.handler與.dev找到相應的handler與.dev

怎麼讀按鍵?

---------------

.....

evdev_read

//無資料並且是非阻塞方式開啟,則立刻返回

if (client->head == client->tail && evdev->exist && (file->f_flags & o_nonblock))

return -eagain;

//否則休眠

retval = wait_event_interruptible(evdev->wait,

client->head != client->tail || !evdev->exist);

誰來喚醒:

evdev_event:

wake_up_interruptible(&evdev->wait);

evdev_event被誰呼叫:

應該是硬體相關的**,input_dev呼叫

在裝置的中斷服務程式裡,確定事件是什麼,然後呼叫相應的

input_handler的event處理函式

gpio_keys_isr

//上報事件

input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value):

struct input_handle *handle;

list_for_each_entry(handle, &dev->h_list, d_node)

if (handle->open)

handle->handler->event(handle, type, code, value);

怎麼寫符合輸入子系統框架的驅動:

1.分配乙個input_dev結構體

2.設定

3.註冊

4.硬體相關的**,比如在中斷服務程式裡上報事件

Linux輸入子系統

1.1.input子系統概述 輸入裝置 如按鍵,鍵盤,觸控螢幕,滑鼠等 是典型的字元裝置,其一般的工作機制是低層在按鍵,觸控等動作發生時產生乙個中斷 或驅動通過timer定時查詢 然後cpu通過spi,i2c或者外部儲存器匯流排讀取鍵值,座標等資料,放乙個緩衝區,字元裝置驅動管理該緩衝區,而驅動的r...

Linux輸入子系統

linux系統提供了input子系統,按鍵 觸控螢幕 鍵盤 滑鼠等輸入都可以利用input介面函式來實現裝置驅動,最重要的資料結構是struct input dev 在linux 核心中,input裝置用input dev 結構 體描述,使用input子系統實現輸入裝置驅動的時候,驅動的核心工作是向...

Linux輸入子系統

位址 linux輸入子系統 按鍵與觸控螢幕的裝置驅動,在linux系統中實現這類裝置驅動的方法是利用input子系統。linux系統提供了input子系統,按鍵 觸控螢幕 鍵盤 滑鼠等輸入都可以利用input介面函式來實現裝置驅動,按鍵和觸控螢幕裝置驅動都可以作為input裝置驅動而實現。在linu...