內核輸入子系統分析

2.6內核輸入子系統分析
前面對s3c2410的觸摸屏驅動進行了分析,現深入一層,對其所在的輸入子系統進行刺探。
首先引用一個不錯的帖子,對2.6內核的輸入子系統進行一個大致的描述:
引:
在做觸摸屏?對於輸入子系統,相信你也早看了網上一些介紹文章文章了,
讀一下就可瞭解對其基本架構,剩下的只是一些源碼細節閱讀。
輸入子系統的3層間的聯繫是非常簡單的,驅動層的核心結構爲struct input_dev:
struct input_dev {
    ...
    struct list_head        h_list;
    ...
};
在input_register_device時就會將input_dev和input_handle聯繫起來;
所謂聯繫就是將有關的input_handle鏈入以input_dev中h_list爲Hash頭的鏈中;
而事件處理層的核心結構是struct input_handler:
struct input_handler {
    ...
    struct list_head        h_list;
    ...
};
在input_register_handler時同樣會將input_handler和input_handle聯繫起來,
所謂聯繫就是將有關的input_handle鏈入以input_handler中h_list爲Hash頭的鏈中;
由上可見input_handle即是個用於關聯驅動層input_dev和事件處理
層input_handler的中間結構:
struct input_handle {
    ...
    struct input_dev *dev;
    struct input_handler *handler;
    struct list_head        d_node;
    struct list_head        h_node;
};
其中d_node用於input_dev鏈,h_node用於input_handler鏈,有了input_handle,
就把相關dev和handler聯繫起來,相互能容易的找到。
看了以上的內容,相信你對2.6內核的輸入子系統應該有個大概的瞭解了,
目前我就input_dev、input_handle、input_handler這三者建立聯繫的過程進行周詳的分析:
觸摸屏驅動中,s3c2410ts_probe函數的最後一步,調用input_register_device函數開始進入三者建立聯繫的過程:
void input_register_device(struct input_dev *dev)
{
        struct input_handle *handle;
        struct input_handler *handler;
        struct input_device_id *id;
........................................................................................
        INIT_LIST_HEAD(&dev->h_list);
        list_add_tail(&dev->node, &input_dev_list);
        list_for_each_entry(handler, &input_handler_list, node)
                if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
                        if ((id = input_match_device(handler->id_table, dev)))
                                if ((handle = handler->connect(handler, dev, id)))
                                        input_link_handle(handle);
..........................................................................................
}
注:
        我只保留重要的部分,省略號部分不是我關心的,以下同。
list_for_each_entry(handler, &input_handler_list, node)的作用在於:
從input_handler_list的鏈表中提取input_handler的指針。
##################################################################################
那這個input_handler的指針又是何時存放在input_handler_list鏈表裏面的呢?
答案是像tsdev.c這些接口驅動裏面調用input_register_handler
進而調用list_add_tail(&handler->node, &input_handler_list);
把其input_handler指針加進input_handler_list裏面,周詳請查看源碼,在此不做周詳分析。
###################################################################################
獲取了input_handler指針後通過input_match_device進行匹配選擇:
static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
{
        int i;
        for (; id->flags || id->driver_info; id++) {
................................................................
                MATCH_BIT(evbit,  EV_MAX);
                MATCH_BIT(keybit, KEY_MAX);
                MATCH_BIT(relbit, REL_MAX);
                MATCH_BIT(absbit, ABS_MAX);
                MATCH_BIT(mscbit, MSC_MAX);
                MATCH_BIT(ledbit, LED_MAX);
                MATCH_BIT(sndbit, SND_MAX);
                MATCH_BIT(ffbit,  FF_MAX);
                MATCH_BIT(swbit,  SW_MAX);
                return id;
        }
        return NULL;
}
該函數拿剛纔獲得的input_handler指針所擁有的特性表handler->id_table
和我們所註冊的input_dev的特性表dev.id進行對照。
仍以觸摸屏驅動s3c2410-ts.c和觸摸屏接口tsdev.c爲例:
s3c2410-ts.c:
        ts.dev.evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
        ts.dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
        input_set_abs_params(&ts.dev, ABS_X, 0, 0x3FF, 0, 0);
        input_set_abs_params(&ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
        input_set_abs_params(&ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
        ts.dev.id.bustype = BUS_RS232;
        ts.dev.id.vendor = 0xDEAD;
        ts.dev.id.product = 0xBEEF;
        ts.dev.id.version = S3C2410TSVERSION;
tsdev.c:
static struct input_device_id tsdev_ids[] = {
        {
              .flags        = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT
                        | INPUT_DEVICE_ID_MATCH_RELBIT,
              .evbit        = { BIT(EV_KEY) | BIT(EV_REL) },
              .keybit        = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
              .relbit        = { BIT(REL_X) | BIT(REL_Y) },
         },/* A mouse like device, at least one button, two relative axes */
        {
              .flags        = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT
                        | INPUT_DEVICE_ID_MATCH_ABSBIT,
              .evbit        = { BIT(EV_KEY) | BIT(EV_ABS) },
              .keybit        = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
              .absbit        = { BIT(ABS_X) | BIT(ABS_Y) },
         },/* A tablet like device, at least touch detection, two absolute axes */
        {
              .flags        = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
              .evbit        = { BIT(EV_ABS) },
              .absbit        = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
         },/* A tablet like device with several gradations of pressure */
        {},/* Terminating entry */
};
能看到,tsdev.c接口定義了三項特性,對應id爲0、1、2,
input_match_device函數依次取出其中的選項和s3c2410-ts.c裏面定義的input_dev的選項進行對比。
這裏對比的標準是tsdev.c裏面定義的選項s3c2410-ts.c裏面必須滿足,否則continue,繼續判斷下一個id號的選項。
周詳請看MATCH_BIT這個宏的定義:
#define MATCH_BIT(bit, max) \
                for (i = 0; i bit & dev->bit) != id->bit) \
                                break; \
                if (i != NBITS(max)) \
                        continue;
例如:
        在這裏,tsdev.c定義的id爲0的選項裏面定義的BIT(EV_REL)這一項
在s3c2410-ts.c裏面定義的input_dev設備上是不具有的,
所以,執行到MATCH_BIT(evbit,  EV_MAX);後直接continue,
繼續判斷tsdev.c裏面id爲1的選項,直到找到合適的,然後返回真,否則返回NULL。
###########################################################################################
在list_for_each_entry(handler, &input_handler_list, node)
這個大循環裏和我們所註冊的input_dev所匹配的不限於一個接口,
例如,以下是我的調試記錄:
s3c2410 TouchScreen successfully loaded
kbd
input_match_device
mousedev
input_match_device
mousedev_connect
joydev
input_match_device
evdev
input_match_device
evdev_connect
tsdev
input_match_device
tsdev_connect
evbug
input_match_device
evbug_connect
能看到,對於s3c2410-ts.c裏面定義的input_dev設備,同時和其匹配的就有
mousedev、evdev、tsdev、evbug等衆多接口(不知道我的理解是否正確,如果理解錯了,還望指正^_^)
###########################################################################################
找到匹配的選項以後,就能開始着手把input_dev、input_handle、input_handler這三者聯繫齊來了,具體調用
handle = handler->connect(handler, dev, id)函數,
主要的目的是填充input_handle結構,然後接着調用
input_link_handle(handle)函數:
static void input_link_handle(struct input_handle *handle)
{
        list_add_tail(&handle->d_node, &handle->dev->h_list);
        list_add_tail(&handle->h_node, &handle->handler->h_list);
}
看到吧,就是上面那位大俠提到的,把input_handle分別鏈入input_dev和input_handler中h_list爲Hash頭的鏈中。
好了,到此,input_dev、input_handle、input_handler這三者總算是聯繫起來了.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章