Linux裝置模型之input子系統詳解 三

2021-06-08 09:47:57 字數 3799 閱讀 3608

十:evdev裝置結點的open()操作

對主裝置號為input_major的裝置節點進行操作,會將操作集轉換成handler的操作集.在evdev中,這個操作集就是evdev_fops.對應的open函式如下示:

static int evdev_open(struct inode *inode, struct file *file)

spin_lock_init(&client->buffer_lock);

client->evdev = evdev;

evdev_attach_client(evdev, client);

error = evdev_open_device(evdev);

if (error)

goto err_free_client;

file->private_da

ta = client;

return 0;

err_free_client:

evdev_detach_client(evdev, client);

kfree(client);

err_put_evdev:

put_device(&evdev->dev);

return error;

}iminor(inode) - evdev_minor_base就得到了在evdev_table[ ]中的序號.然後將陣列中對應的evdev取出.遞增devdev中device的引用計數.

分配並初始化乙個client.並將它和evdev關聯起來: client->evdev指向它所表示的evdev. 將client掛到evdev->client_list上. 將client賦為file的私有區.

對應handle的開啟是在此evdev_open_device()中完成的.**如下:

static int evdev_open_device(struct evdev *evdev)

mutex_unlock(&evdev->mutex);

return retval;

}如果evdev是第一次開啟,就會呼叫input_open_device()開啟evdev對應的handle.跟蹤一下這個函式:

int input_open_device(struct input_handle *handle)

handle->open++;

if (!dev->users++ && dev->open)

retval = dev->open(dev);

if (retval)

}out:

mutex_unlock(&dev->mutex);

return retval;

}在這個函式中可以看到.遞增handle的開啟計數.如果是第一次開啟.則呼叫input device的open()函式

(如果已經賦值的話,但是我在akm8976.c中沒有看到對input device的open函式指標賦值的地方,

所以這裡有個問題:open一般是用來幹嘛的? ).

十一:evdev的事件處理

經過上面的分析.每當input device上報乙個事件時,會將其交給和它匹配的handler的event函式處理.在evdev中.這個event函式對應的**為:

static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int co

de, int value)

首先構造乙個struct input_event結構.並裝置它的type.co

de,value為處理事件的相關屬性.如果該裝置被強制設定了handle.則呼叫與之對應的client.

在evdev_open的時候.會初始化clinet並將其鏈入到evdev->client_list. 這樣,就可以通過evdev->client_list找到這個client.

對於找到的每乙個client都會呼叫evdev_pass_event( ).**如下:

static void evdev_pass_event(struct evdev_client *client, struct input_event *event)

這裡的操作很簡單.就是將event儲存到client->buffer中.client->head就是當前的資料位置.注意這裡是乙個環形快取區.寫資料是從client->head寫.而讀資料則是從client->tail中讀.

十二:裝置節點的read處理

對於evdev裝置節點的read操作都會由evdev_read()完成.它的**如下:

static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)

return retval;

}首先,它判斷快取區大小是否足夠.在讀取資料的情況下,可能當前快取區內沒有資料可讀.在這裡先睡眠等待快取區中有資料.如果在睡眠的時候,.條件滿足.是不會進行睡眠狀態而直接返回的.

然後根據read()提夠的快取區大小.將client中的資料寫入到使用者空間的快取區中.

十三:裝置節點的寫操作

同樣.對裝置節點的寫操作是由evdev_write()完成的.**如下:

static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)

while (retval < count)

input_inject_event(&evdev->handle,

event.type, event.co

de, event.value);

retval += evdev_event_size();

}out:

mutex_unlock(&evdev->mutex);

return retval;

}首先取得操作裝置檔案所對應的evdev.

實際上,這裡寫入裝置檔案的是乙個event結構的陣列.在之前分析過,這個結構裡包含了事件的type.co

de和event.

將寫入裝置的event陣列取出.然後對每一項呼叫event_inject_event().

這個函式的操作和input_event()差不多.就是將第乙個引數handle轉換為輸入裝置結構.然後這個裝置再產生乙個事件.

**如下:

void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int co

de, int value)

}這裡可以跟input_event()對比一下,這裡裝置可以產生任意事件,而不需要和裝置所支援的事件型別相匹配.

由此可見.對於寫操作而言.就是讓與裝置檔案相關的輸入裝置產生乙個特定的事件.

將上述裝置檔案的操作過程以圖的方式表示如下:

十四:小結

在這一節點,分析了整個input子系統的架構,各個環節的流程.最後還以evdev為例.將各個流程貫穿在一起.以加深對input子系統的 理解.由此也可以看出.linux裝置驅動採用了分層的模式.從最下層的裝置模型到裝置,驅動,匯流排再到input子系統最後到input device.這樣的分層結構使得最上層的驅動不必關心下層是怎麼實現的.而下層驅動又為多種型號同樣功能的驅動提供了乙個統一的介面.

Linux裝置驅動之 input子系統

什麼是input input子系統處理輸入事務,任何輸入裝置的驅動程式都可以通過input輸入子系統提供的介面註冊到核心,利用子系統提供的功能來與使用者空間互動。輸入裝置一般包括鍵盤,滑鼠,觸控螢幕等,在核心中都是以輸入裝置出現的。下面分析input輸入子系統的結構,以及功能實現。linux中inp...

linux裝置模型之kobject

kobject 結構 在linux核心裡,kobject是組成linux裝置模型的基礎,乙個kobject對應sysfs裡的 乙個目錄。從物件導向的角度來說,kobject可以看作是所有裝置物件的基類,因為c 語言並沒有物件導向的語法,所以一般是把kobject內嵌到其他結構體裡來實現類似的 作用,...

Linux核心驅動之Input子系統裝置驅動層

android x windows qt等眾多應用對於linux系統中鍵盤 滑鼠 觸控螢幕等輸入裝置的支援都通過 或越來越傾向於標準的input輸入子系統。因為input子系統已經完成了字元驅動的檔案操作介面,所以編寫驅動的核心工作是完成input系統留出的介面,工作量不大。但如果你想更靈活的應用它...