歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux Input子系統(上)--概述

輸入設備總類繁雜,包括按鍵,鍵盤,觸摸屏,鼠標,搖桿等等,它們本身都是字符設備,不過內核為了能將這些設備的共性抽象出來,簡化驅動的開發,建立了一個Input子系統。Input子系統分為三層,從下至上分別是輸入設備驅動層,輸入核心層以及輸入事件驅動層。這三層中的輸入核心層和輸入事件驅動層都是內核已經完成了的,因此需要我們完成的只有輸入設備驅動層。考慮輸入設備主要的工作過程都是 動作產生(按鍵,觸屏……)-->產生中斷-->讀取數值(鍵值,坐標……)-->將數值傳遞給應用程序。最後一個步驟就屬於事件的處理,對於同一類設備,他們的處理方式都是相同的,因此內核已在事件驅動層為我們做好了,不需我們操心,而產生中斷-->讀取數值是因設備而異的,需要我們根據具體的設備來編寫驅動。一個大致的工作流程就是,input device向上層報告-->input core接收報告,並根據在注冊input device時建立好的連接選擇哪一類handler來處理事件-->通過handler將數據存放在相應的dev(evdev,mousedev…)實例的緩沖區中,等待應用程序來讀取。當然,有時候也需要從應用層向設備層逆向傳遞,比如控制一些和設備相關的LED,蜂鳴器等。設備驅動層,輸入核心層和事件處理層之間的關系可以用下圖來闡釋:

下面來看看Input子系統的關鍵數據結構

  1. struct input_dev {  
  2.     const char *name;  
  3.     const char *phys;  
  4.     const char *uniq;  
  5.     struct input_id id;//與input_handler匹配用的id,包括   
  6.   
  7.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];    //設備支持的事件類型   
  8.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  //按鍵事件支持的子事件類型   
  9.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  //相對坐標事件支持的子事件類型   
  10.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  //絕對坐標事件支持的子事件類型   
  11.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];    
  12.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];    
  13.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];    
  14.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];       
  15.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  
  16.   
  17.     unsigned int keycodemax;  
  18.     unsigned int keycodesize;  
  19.     void *keycode;  
  20.     int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);  
  21.     int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);  
  22.   
  23.     struct ff_device *ff;  
  24.   
  25.     unsigned int repeat_key; //最近一次的按鍵值   
  26.     struct timer_list timer;  
  27.   
  28.     int sync;  
  29.   
  30.     int abs[ABS_MAX + 1];  
  31.     int rep[REP_MAX + 1];  
  32.   
  33.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反應設備當前的按鍵狀態   
  34.     unsigned long led[BITS_TO_LONGS(LED_CNT)];//反應設備當前的led狀態   
  35.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反應設備當前的聲音輸入狀態   
  36.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];  //反應設備當前的開關狀態   
  37.   
  38.     int absmax[ABS_MAX + 1];//來自絕對坐標事件的最大鍵值   
  39.     int absmin[ABS_MAX + 1];//來自絕對坐標事件的最小鍵值   
  40.     int absfuzz[ABS_MAX + 1];  
  41.     int absflat[ABS_MAX + 1];  
  42.   
  43.     int (*open)(struct input_dev *dev);  //第一次打開設備時調用,初始化設備用   
  44.     void (*close)(struct input_dev *dev);//最後一個應用程序釋放設備時用,關閉設備   
  45.     int (*flush)(struct input_dev *dev, struct file *file);  
  46.     /*用於處理傳遞給設備的事件,如LED事件和聲音事件*/  
  47.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  48.   
  49.     struct input_handle *grab;//當前占有該設備的input_handle   
  50.   
  51.     spinlock_t event_lock;  
  52.     struct mutex mutex;  
  53.   
  54.     unsigned int users;//打開該設備的用戶數量(input handlers)   
  55.     int going_away;  
  56.   
  57.     struct device dev;  
  58.   
  59.     struct list_head    h_list;//該鏈表頭用於鏈接此設備所關聯的input_handle   
  60.     struct list_head    node;  //用於將此設備鏈接到input_dev_list   
  61. };  

 

  1. struct input_handler {  
  2.   
  3.     void *private;  
  4.   
  5.     /*event用於處理事件*/  
  6.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);  
  7.     /*connect用於建立handler和device的聯系*/  
  8.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);  
  9.     /*disconnect用於解除handler和device的聯系*/  
  10.     void (*disconnect)(struct input_handle *handle);  
  11.     void (*start)(struct input_handle *handle);  
  12.   
  13.     const struct file_operations *fops;//handler的一些處理函數   
  14.     int minor;//次設備號   
  15.     const char *name;  
  16.   
  17.     const struct input_device_id *id_table;//用於和device匹配   
  18.     const struct input_device_id *blacklist;//匹配黑名單   
  19.   
  20.     struct list_head    h_list;//用於鏈接和此handler相關的handle   
  21.     struct list_head    node;  //用於將該handler鏈入input_handler_list   
  22. };  
  1. struct input_handle {  
  2.   
  3.     void *private;  
  4.   
  5.     int open;//記錄設備的打開次數(有多少個應用程序訪問設備)   
  6.     const char *name;  
  7.   
  8.     struct input_dev *dev;//指向所屬的device   
  9.     struct input_handler *handler;//指向所屬的handler   
  10.   
  11.     struct list_head    d_node;//用於鏈入所屬device的handle鏈表   
  12.     struct list_head    h_node;//用於鏈入所屬handler的handle鏈表   
  13. };  

我們可以看到,input_device和input_handler中都有一個h_list,而input_handle擁有指向input_dev和input_handler的指針,也就是說input_handle是用來關聯input_dev和input_handler的,那麼為什麼一個input_device和input_handler

中擁有的是h_list而不是一個handle呢?因為一個device可能對應多個handler,而一個handler也不能只處理一個device,比如說一個鼠標,它可以對應even handler,也可以對應mouse handler,因此當其注冊時與系統中的handler進行匹配,就有可能產生兩個實例,一個是evdev,另一個是mousedev,而任何一個實例中都只有一個handle。至於以何種方式來傳遞事件,就由用戶程序打開哪個實例來決定。後面一個情況很容易理解,一個事件驅動不能只為一個甚至一種設備服務,系統中可能有多種設備都能使用這類handler,比如event handler就可以匹配所有的設備。在input子系統中,有8種事件驅動,每種事件驅動最多可以對應32個設備,因此dev實例總數最多可以達到256個。下一節將以even handler為例介紹設備注冊以及打開的過程。

Copyright © Linux教程網 All Rights Reserved