天天看點

Linux下的Input子系統(一)

版權所有,轉載請說明轉自 http://my.csdn.net/weiqing1981127    

一.系統理論

1.1 Input子系統概述

Input子系統是對不同類型的輸入裝置進行統一處理的驅動程式。一個輸入事件,如按鍵,是通過驅動層到系統核心層到事件處理層到使用者空間的順序到達使用者空間并傳給應用程式使用。

Input子系統由驅動層、輸入子系統核心層和事件處理層三部分組成。此子系統主要包括兩類驅動程式:事件驅動程式和裝置驅動程式。事件驅動程式負責和應用程式的接口,而裝置驅動程式負責和底層輸入裝置的通信。輸入事件驅動程式包括mousedev,evdev,joydev,鍵盤等。事件驅動程式是标準的,對所有的輸入裝置都是可用的,是以要實作的是裝置驅動程式而不是事件驅動程式,裝置驅動程式可用利用一個已經存在的、合适的事件驅動程式通過輸入核心和使用者應用程式接口。事件驅動程式和裝置驅動程式都可以利用輸入核心層為之服務。

我想先從宏觀上介紹下輸入子系統的構造和聯系,然後根據自己編寫的基于Mini2440的添加了Input子系統的按鍵裝置驅動執行個體和應用層測試程式執行個體,分析整個Input系統如何從驅動層到系統核心層到事件處理層到使用者空間來完成工作的。

1.2  Input子系統幾個重要資料結構

輸入子系統主要涉及input_dev,input_handler,input_handle等資料結構。其中input_dev是實體輸入裝置的基本資料結構,包括裝置相關的一些資訊。 input_handler是事件處理結構體,定義怎麼處理事件的邏輯。input_handle是用來建立input_dev和input_handler之間關系的結構體。

首先讓我們了解下input_dev,input_handler,input_handle之間的關系吧。

struct input_handle {

       void *private;   //表示handler的特定資料

       int open;       //表示handle是否正在被使用

       const char *name;  //handle名

       struct input_dev *dev;  //與handle相連的input_dev

       struct input_handler *handler; //與handle相連的input_handler

       struct list_head       d_node;  //handle結構體的該節點将與input_dev相連

       struct list_head       h_node;  //handle結構體的該節點将與input_handler相連

};

struct input_dev {

       const char *name;      

       const char *phys;

       const char *uniq;

       struct input_id id;

       unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

       unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];

       unsigned long relbit[BITS_TO_LONGS(REL_CNT)];

       unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];

       unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];

       unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];

       unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];

       unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];

       unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

       unsigned int keycodemax;

       unsigned int keycodesize;

       void *keycode;

       int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);

       int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

       struct ff_device *ff;

       unsigned int repeat_key;

       struct timer_list timer;

       int sync;

       int abs[ABS_MAX + 1];

       int rep[REP_MAX + 1];

       unsigned long key[BITS_TO_LONGS(KEY_CNT)];

       unsigned long led[BITS_TO_LONGS(LED_CNT)];

       unsigned long snd[BITS_TO_LONGS(SND_CNT)];

       unsigned long sw[BITS_TO_LONGS(SW_CNT)];

       int absmax[ABS_MAX + 1];

       int absmin[ABS_MAX + 1];

       int absfuzz[ABS_MAX + 1];

       int absflat[ABS_MAX + 1];

       int absres[ABS_MAX + 1];

       int (*open)(struct input_dev *dev); 

       void (*close)(struct input_dev *dev);

       int (*flush)(struct input_dev *dev, struct file *file);

       int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

       struct input_handle *grab;    //grab是強制為input device的handler

       spinlock_t event_lock;

       struct mutex mutex;

       unsigned int users;

       bool going_away;

       struct device dev;    

       struct list_head       h_list;    //handle的d_node就是挂在input_dev這裡的h_list;上

       struct list_head       node;    //挂在input_dev本身的連結清單input_dev_list上

};

struct input_handler {

       void *private;

       //event函數是向子系統報告後核心最終需要調用的函數

       void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

       //connect函數是input_dev和input_handler相比對的函數

       int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);     

       void (*disconnect)(struct input_handle *handle);

       void (*start)(struct input_handle *handle);

       const struct file_operations *fops;  //操作函數

       int minor;

       const char *name;

       const struct input_device_id *id_table;   //handler支援項

       const struct input_device_id *blacklist;   //handler不支援項

       struct list_head       h_list;  /handle的h_node就是挂在input_handler這裡的h_list;上

       struct list_head       node;  //挂在input_handler本身的連結清單input_handler_list上

};

總結下input_dev,input_handler,input_handle三者的關系吧。總共其實有四個連結清單,第一個連結清單就是input_dev本身的連結清單input_dev_list,該連結清單上挂接了所有的input_dev,主要通過input_dev->node挂接在input_dev_list上。第二個連結清單是input_handler本身的連結清單input_handler_list,該連結清單上挂接了所有的input_handler,主要通過input_handler->node挂接在input_handler_list上。第三個連結清單是input_dev與input_handle之間的連結清單,主要是通過input_handle->d_node挂在input_dev-> h_list連結清單上實作。第四個連結清單是input_handler與input_handle之間的連結清單,主要是通過input_handle->h_node挂在input_handler-> h_list連結清單上實作。

好了,我們再了解下input_dev,input_handler,input_handle分别在什麼時候被建立的吧。

input_dev是在裝置驅動層初始化函數中通過配置設定input_dev空間然後調用input_register_device注冊進核心的。input_handle是在事件驅動層初始化函數中通過調用input_register_handler注冊進核心的。那麼input_handle什麼時候被注冊進核心的呢?這個問題的答案有兩個情況。其一,當注冊input_dev時,系統會在input_handler_list尋找比對的input_handler,如果找到了就調用input_handler->evdev_connect函數中的input_register_handle函數完成input_handle注冊,并将這個input_handle與相應的input_dev和input_handler相連。其二,當注冊input_handler時,系統會在input_dev_list尋找比對的input_dev,如果找到了就調用input_handler->evdev_connect函數中的input_register_handle函數完成input_handle注冊,并将這個input_handle與相應的input_dev和input_handler相連。

1.3  Input子系統核心層和事件處理層函數概述

接着讓我們先了解下核心層和事件驅動層幾個比較重要的函數。

Input核心層input.c中主要我們需要關注的函數是input_event input_allocate_device  input_open_device  input_register_device  input_register_handler  input_register_handle和input_open_file。

Input事件驅動層Evdev.c主要是input_handler中定義的函數evdev_event,evdev_connect,包括file_operations。

繼續閱讀