linux驅動之輸入子系統

2021-07-27 18:36:48 字數 4586 閱讀 9307

輸入子系統框架,把核心開啟 搜尋input.c

輸入子系統的**在/driver/input目錄下面 最上一層,我們稱它為核心層

要看乙個驅動程式我們應該從他的入口函式開始看

有一行:err = register_chrdev_region(mkdev(input_major, 0),input_max_char_devices, "input");//註冊字元裝置,以前是我們自己寫的,現在這套**裡面已經有了

在 2.4 的核心我們使用 register_chrdev(0, "hello", &hello_fops) 來進行字元裝置裝置節點的分配,這種方式每乙個主裝置號只能存放一種裝置,它們使用相同的 file_operation 結構體,也就是說核心最多支援 256 個字元裝置驅動程式。

在 2.6 的核心之後,新增了乙個 register_chrdev_region 函式,它支援將同乙個主裝置號下的次裝置號進行分段,每一段供給乙個字元裝置驅動程式使用,使得資源利用率大大提公升,同時,2.6 的核心保留了原有的 register_chrdev 方法。在 2.6 的核心中這兩種方法都會呼叫

下一層是evdev.c,keyboard.c mousedev.c

static int __init evdev_init(void)

他們向上註冊input_register_handler 向input.c 

可以看下這個evdev_handler這個裡面有什麼東西

這裡面有個fops

handler是個純軟體的 handler處理

還乙個層,裝置層

裝置層向input.c註冊input_register_device  上面是純軟體的東西,這裡就代表硬體

這個handler能不能處理這個device呢 ,這裡肯定會有個聯絡 我們先看一下這個handler

這裡有個.id_table

= evdev_ids,就是表示支援哪一些裝置

當你註冊handler和註冊裝置的時候,他們會比較一下,看看這個handler能不能支援這個裝置

在這裡可以看出來,如果能夠支援的話就會呼叫這個connect函式

搜尋input_register_device會發現各種外設如滑鼠什麼的都呼叫了這個函式

我們input_register_device這個主要做了什麼事情,大概看一眼

list_add_tail(&dev->node, &input_dev_list);會把device結構體放到鍊錶裡面去

list_for_each_entry(handler, &input_handler_list, node)

input_attach_handler(dev, handler);

handler也會有乙個鍊錶,對這個鍊錶裡面的每一項都呼叫input_attach_handler(dev, handler);這個函式會根據input_handler的id_tabler判斷能否支援這個input_dev。

我們來看看另外一邊input_register_handler這裡面做了什麼事情

list_add_tail(&handler->node, &input_handler_list);//放到乙個鍊錶裡面去

list_for_each_entry(dev, &input_dev_list, node)//對於每個input_device呼叫input_attach_handler

input_attach_handler(dev, handler);這個函式會根據input_handler的id_tabler判斷能否支援這個input_dev。

來看看input_attach_handler這個函式

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

註冊input_dev和input_handler時,會兩兩比較左邊的input_dev和右邊的input_handler

根據input_handler的id_table判斷這個input_handler能否支援這個input_dev

如果能支援,則呼叫input_handler的connect函式建立「連線」

怎麼建立連線的

我們來看看 

evdev = kzalloc(sizeof(struct evdev), gfp_kernel);這裡分配乙個evdev結構體,分配了乙個input_handle,注意沒有r,跟之前相比沒有r,

然後來設定它

evdev->handle.dev = input_get_device(dev);指向左邊的input_device結構體

evdev->handle.name = dev_name(&evdev->dev);

evdev->handle.handler = handler; 指向右邊的input_handler結構體

evdev->handle.private = evdev;

evdev->dev.devt = mkdev(input_major, minor);

evdev->dev.class = &input_class;

evdev->dev.parent = &dev->dev;

evdev->dev.release = evdev_free;

error = input_register_handle(&evdev->handle);//然後註冊這個handle

然後我們進去看一看這個函式

if (handler->filter)

list_add_rcu(&handle->d_node, &dev->h_list); 

else

list_add_tail_rcu(&handle->d_node, &dev->h_list); 把這個handle放到乙個輸入裝置的鍊錶裡面

list_add_tail_rcu(&handle->h_node, &handler->h_list); 把這個handle放到handler的鍊錶裡面

連線的時候構造乙個input_handle 裡面有個dev指向輸入裝置,裡面有個handler指向handler

input_devie裡面有個h_list, handler也有乙個h_list

這兩個h_list都指向這個handle 所以我們device可以通過這個h_list找到這個handle,又可以通過這個handle找到這個handler,反過來也是一樣的

所以怎麼建立連線總結起來就是

1.分配乙個input_handle結構體

2.input_handle.dev=input_dev;//指向input_device

input_handle.handler=input_handler;//指向input_handler

3.註冊

註冊裡面幹了什麼事了 就是input_handler->h_list =&input_handle

input_device>h_list =&input_handle

所以我們handler可以通過h_list找到input_handle input_handle裡面有個input_handle.handler = handler;可以找到handler 反過來一樣的

我們拿按鍵驅動來舉例子

我們應用程式來讀,最終會導致相應的handler裡面的裡面的fops裡面的read函式被呼叫

我們拿evdev_read來說明

有休眠就有喚醒,那麼被誰喚醒呢,被誰喚醒不好找,那我們來搜尋evdev->wait這個東西,

結果可以發現在.event= evdev_event,這個裡面喚醒 從這個單詞就可以知道它是發生了某些事件

那麼問題有來了,被它喚醒,但是這個東西又是被誰呼叫

我們可以猜測應該是硬體相關的**,應該是input_device這一層呼叫的

有個例子比較好,搜尋gpio_keys.c這個,這只是乙個例子

如此可以看出 在裝置的中斷服務程式裡面,確定事件是什麼,然後呼叫相應的input_handler的event處理函式

實際上這就是我們的核心 input_event就是用來上報事件的

void input_event(struct input_dev *dev,

unsigned int type, unsigned int code, int value) 這個函式有個引數是input_device

函式裡有個成員是input_handler

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驅動子系統之輸入子系統 5

5.總結 5.1 事件資訊的上報過程分析 l 上報的大致過程 裝置驅動層 核心層 事件處理層 應用層 l 具體呼叫的函式 以evdev為例 input event input handle event input pass event handle handler event handle,type...

linux輸入子系統之按鍵驅動

上一節中,我們講解了linux input子系統的框架,到核心原始碼裡詳細分析了輸入子系統的分離分層的框架等。這一節,我們來以輸入子系統的框架來寫乙個按鍵驅動。問 怎麼寫符合輸入子系統框架的驅動程式?答 1.分配乙個input dev結構體 2.設定 3.註冊 4.硬體相關的 比如在中斷服務程式裡上...

Linux驅動之input輸入子系統

input輸入子系統在實際專案中用的也比較多,按鍵,觸控螢幕,滑鼠,鍵盤等,用來實現核心層和應用層資料之間的傳遞,這裡得說明不只有input,還有copy to user等,利用input的好處是我們用自己上傳資料到應用程式,我們直接上報這個事件發生了,input自帶的機制會實現上傳的功能。還有很多...