歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux Input子系統(上)--概述

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

日期:2017/3/1 10:17:53   编辑:Linux編程

輸入設備總類繁雜,包括按鍵,鍵盤,觸摸屏,鼠標,搖桿等等,它們本身都是字符設備,不過內核為了能將這些設備的共性抽象出來,簡化驅動的開發,建立了一個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. unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //設備支持的事件類型
  7. unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按鍵事件支持的子事件類型
  8. unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相對坐標事件支持的子事件類型
  9. unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //絕對坐標事件支持的子事件類型
  10. unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
  11. unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
  12. unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
  13. unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
  14. unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
  15. unsigned int keycodemax;
  16. unsigned int keycodesize;
  17. void *keycode;
  18. int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
  19. int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
  20. struct ff_device *ff;
  21. unsigned int repeat_key; //最近一次的按鍵值
  22. struct timer_list timer;
  23. int sync;
  24. int abs[ABS_MAX + 1];
  25. int rep[REP_MAX + 1];
  26. unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反應設備當前的按鍵狀態
  27. unsigned long led[BITS_TO_LONGS(LED_CNT)];//反應設備當前的led狀態
  28. unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反應設備當前的聲音輸入狀態
  29. unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //反應設備當前的開關狀態
  30. int absmax[ABS_MAX + 1];//來自絕對坐標事件的最大鍵值
  31. int absmin[ABS_MAX + 1];//來自絕對坐標事件的最小鍵值
  32. int absfuzz[ABS_MAX + 1];
  33. int absflat[ABS_MAX + 1];
  34. int (*open)(struct input_dev *dev); //第一次打開設備時調用,初始化設備用
  35. void (*close)(struct input_dev *dev);//最後一個應用程序釋放設備時用,關閉設備
  36. int (*flush)(struct input_dev *dev, struct file *file);
  37. /*用於處理傳遞給設備的事件,如LED事件和聲音事件*/
  38. int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
  39. struct input_handle *grab;//當前占有該設備的input_handle
  40. spinlock_t event_lock;
  41. struct mutex mutex;
  42. unsigned int users;//打開該設備的用戶數量(input handlers)
  43. int going_away;
  44. struct device dev;
  45. struct list_head h_list;//該鏈表頭用於鏈接此設備所關聯的input_handle
  46. struct list_head node; //用於將此設備鏈接到input_dev_list
  47. };

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

我們可以看到,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