Input子系統詳解-基於Linux2.6.22內核

(1)輸入子系統框架 

Input子系統框架

app: open() read()  write()   
---------------------------------------------
內核: xxx_drv的 fos 結構體裏面的
            xxx_open() xxx_write xxx_write 
----------------------------------------------
硬件:按鍵、鼠標、鍵盤等

問:設備和驅動如何聯繫起來?
答:當我們註冊input_device結構體時,調用到register_input_devece函數(),該函數調用 input_match_device() 函數, 如果 input_handler結構體成員的id_table函數支持該設備類型,則調用 input_handler結構體成員函數connect()函數。在connect函數裏面,我們做三件事:分配一個input_handle(注意不是handler)結構體;設置成員分別指向已匹配的設備和驅動(兩邊聯繫起來了);註冊。

問:應用程序讀取的鍵值的時候會阻塞,誰來喚醒?
答:由硬件中斷來喚醒。在硬件中斷服務程序裏面調用 input_enent() 函數,這個函數會調用到已匹配驅動的 input_handler 結構體裏面的enent()成員函數,該函數首先填充信息結構體,同時喚醒進程。

(2)輸入子系統源碼分析
/drivers/input.c
 input_init
    class_register
         INIT_LIST_HEAD(&cls->children);
         INIT_LIST_HEAD(&cls->devices);
         INIT_LIST_HEAD(&cls->interfaces);
         kobject_set_name                             //爲子系統命名
         subsys_set_kset                               //輸入子系統 設置
         subsystem_register                          //註冊子系統
    input_proc_init                                       // 在/proc目錄下創建輸入子系統信息條目
    register_chrdev                                      //創建字符設備 input

解析 file_operations 結構體
input_open_file(struct inode *inode, struct file *file)
     根據節點號從數組中取出 input_handler
     new_fops = fops_get(handler->fops);
     old_fops = file->f_op;
     file->f_op = new_fops
     new_fops->open(inode, file)                //打開設備
     fops_put(old_fops)                               //喚醒進程

驅動 input_handler:
input_register_handler
    INIT_LIST_HEAD(&handler->h_list);                   //初始化鏈表
    input_table[handler->minor >> 5] = handler         //放入數組
    list_for_each_entry:input_attach_handler          //尋找input_device匹配項
    input_match_device((handler->id_table, dev))

    handler->connect(handler, dev, id);                                           //調用handler的 connect函數
                evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)  //分配一個evdev結構體
                init_waitqueue_head(&evdev->wait);                             //初始化等待隊列頭部
                evdev->handle.dev = dev;                                              //分別指向 dev 和 handler,設備和驅動就聯繫起來了
                evdev->handle.handler = handler
                class_device_create()
                sysfs_create_link()                                                          //創建連接
                input_register_handle()                                                  //註冊handle結構體       
結構體成員函數分析:                        
handler->evdev_event:                                    //被input_enent函數調用
     首先填充信息結構體
     wake_up_interruptible                 //喚醒進程
handler->fops->evdev_open:
    int i = iminor(inode) - EVDEV_MINOR_BASE;
    evdev = evdev_table[i];
    input_open_device(&evdev->handle)
           input_dev *dev = handle->dev
           dev->open                                                                          //用到 已匹配的註冊設備的 open 函數

handler->fops->evdev_read:
    wait_event_interruptible                 // sleep until a condition gets true
    evdev_event_to_user                    // 把消息傳遞給用戶

設備:input_device
input_register_device:
    init_timer
    class_device_add
    list_for_each_entry : input_attach_handler
            input_match_device(handler->id_table, dev)
             handler->connect
   input_wakeup_procfs_readers
             wake_up(&input_devices_poll_wait)

(4)輸入子系統設備驅動編寫步驟
由於內核已經提供了input_handler驅動程序,我們要做的就是編寫設備側的程序。
1.分配一個input_dev結構體
2.設置該結構體(能產生哪類時間,能產生該類事件的哪些事件)
3.硬件相關設置(管腳設置等)
4.申請中斷,在中斷服務程序裏面上報事件(調用 input_event 結構體)
5.註冊input_dev結構體


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章