自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux input子系統(tǒng)編程、分析與模板

系統(tǒng) Linux 系統(tǒng)運(yùn)維
input對象描述了一個輸入設(shè)備,包括它可能上報的事件,這些事件使用位圖來描述,內(nèi)核提供的相應(yīng)的工具幫助我們構(gòu)建一個input對象,大家可以參考內(nèi)核文檔"Documentation/input/input-programming.txt",里面對于input子系統(tǒng)的使用有詳細(xì)的描述。

輸入設(shè)備都有共性:中斷驅(qū)動+字符IO,基于分層的思想,Linux內(nèi)核將這些設(shè)備的公有的部分提取出來,基于cdev提供接口,設(shè)計(jì)了輸入子系統(tǒng),所有使用輸入子系統(tǒng)構(gòu)建的設(shè)備都使用主設(shè)備號13,同時輸入子系統(tǒng)也支持自動創(chuàng)建設(shè)備文件,這些文件采用阻塞的IO讀寫方式,被創(chuàng)建在"/dev/input/"下。如下圖所示。內(nèi)核中的輸入子系統(tǒng)自底向上分為設(shè)備驅(qū)動層,輸入核心層,事件處理層。由于每種輸入的設(shè)備上報的事件都各有不同,所以為了應(yīng)用層能夠很好識別上報的事件,內(nèi)核中也為應(yīng)用層封裝了標(biāo)準(zhǔn)的接口來描述一個事件,這些接口在"/include/upai/linux/input"中。

  • 設(shè)備驅(qū)動層是具體硬件相關(guān)的實(shí)現(xiàn),也是驅(qū)動開發(fā)中主要完成的部分,
  • 輸入核心層主要提供一些API供設(shè)備驅(qū)動層調(diào)用,通過這些API設(shè)備驅(qū)動層上報的數(shù)據(jù)就可以傳遞到事件處理層,
  • 事件處理層負(fù)責(zé)創(chuàng)建設(shè)備文件以及將上報的事件傳遞到用戶空間, 

 

 

 

input的使用

input對象描述了一個輸入設(shè)備,包括它可能上報的事件,這些事件使用位圖來描述,內(nèi)核提供的相應(yīng)的工具幫助我們構(gòu)建一個input對象,大家可以參考內(nèi)核文檔"Documentation/input/input-programming.txt",里面對于input子系統(tǒng)的使用有詳細(xì)的描述。

  1. //input設(shè)備對象 
  2.  struct input_dev { 
  3.          const char *name
  4.          unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 
  5.          unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 
  6.          unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; 
  7.          unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; 
  8.          unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; 
  9.          unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; 
  10.          unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; 
  11.          unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; 
  12.          unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; 
  13.   
  14.          unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 
  15.          unsigned long led[BITS_TO_LONGS(LED_CNT)]; 
  16.          unsigned long snd[BITS_TO_LONGS(SND_CNT)]; 
  17.          unsigned long sw[BITS_TO_LONGS(SW_CNT)]; 
  18.   
  19.          struct input_handle __rcu *grab; 
  20.   
  21.          struct device dev; 
  22.   
  23.          struct list_head        h_list; 
  24.          struct list_head        node; 
  25.  }; 

struct input_dev

--122--> 這個name不是設(shè)備名,input子系統(tǒng)的設(shè)備名在子系統(tǒng)源碼中指定的,不是這。

--129--> 設(shè)備支持的輸入事件位圖,EV_KEY,EV_REL, etc

--130--> 對于按鍵事件,設(shè)備支持的輸入子事件位圖

--132--> 對于相對坐標(biāo)事件,設(shè)備支持的相對坐標(biāo)子事件位圖

--133--> 對于絕對坐標(biāo)事件,設(shè)備支持的絕對坐標(biāo)子事件位圖

--134--> 混雜設(shè)備的支持的子事件位圖

--180-->表示這是一個device。

--182-->h_list是用來鏈接相關(guān)handle的鏈表

--183-->node用來鏈接其他input_dev的鏈表

分配/釋放

  1. //drivers/input/input.c 
  2. //創(chuàng)建一個input對象 
  3.  
  4. struct input_dev *input_allocate_device(void);//釋放一個input對象 
  5.  
  6. void input_free_device(struct input_dev *dev); 

初始化

初始化一個input對象是使用input子系統(tǒng)編寫驅(qū)動的主要工作,內(nèi)核在頭文件"include/uapi/linux/input.h"中規(guī)定了一些常見輸入設(shè)備的常見的輸入事件,這些宏和數(shù)組就是我們初始化input對象的工具。這些宏同時用在用戶空間的事件解析和驅(qū)動的事件注冊,可以看作是驅(qū)動和用戶空間的通信協(xié)議,所以理解其中的意義十分重要。在input子系統(tǒng)中,每一個事件的發(fā)生都使用事件(type)->子事件(code)->值(value)三級來描述,比如,按鍵事件->按鍵F1子事件->按鍵F1子事件觸發(fā)的值是高電平1。注意,事件和子事件和值是相輔相成的,只有注冊了事件EV_KEY,才可以注冊子事件BTN_0,也只有這樣做才是有意義的。

下面就是內(nèi)核約定的事件類型,對應(yīng)應(yīng)用層的事件對象的type域 

 

 

 

下面這些是按鍵子事件的類型,可以看到對PC鍵值的定義 

 

 

 

除了對常用的事件進(jìn)行描述,內(nèi)核同樣提供了工具將這些事件正確的填充到input對象中描述事件的位圖中。

  1. //***種//這種方式非常適合同時注冊多個事件 
  2.  
  3. button_dev->evbit[0] = BIT_MASK(EV_KEY);             
  4. button_dev->keybit[BIT_WORD(BTN_0|BTN_1)] = BIT_MASK(BTN_0|BTN_1);   

注冊/注銷

初始化好了一個input對象,接下來就需要將其注冊到內(nèi)核

  1. //注冊input對象到內(nèi)核 
  2. int input_register_device(struct input_dev *dev); 
  3. //從內(nèi)核注銷一個input對象 
  4. void input_unregister_device(struct input_dev *dev); 

驅(qū)動層報告事件

在合適的時機(jī)(由于輸入最終是中斷表示的,所以通常在驅(qū)動的中斷處理函數(shù)中)驅(qū)動可以將注冊好的事件上報,且可以同時上報多個事件,下面是內(nèi)核提供的API

  1. //上報指定的事件+子事件+值 
  2. void input_event( 
  3.    struct input_dev *dev,unsigned int type,unsigned int code,int value);//上報鍵值 
  4.    void input_report_key(struct input_dev *dev,unsigned int code,int value);//上報絕對坐標(biāo) 
  5.    void input_report_abs(struct input_dev *dev,unsigned int code,int value);//報告同步事件 
  6.    void input_report_rel(struct input_dev *dev,unsigned int code,int value);//同步所有的上報 
  7.    void input_sync(struct input_dev *dev); 

上報事件有2點(diǎn)需要注意:

  1. report函數(shù)們并不會真的上報,只是準(zhǔn)備上報,sync才會真的將剛剛report的事件真的上報搭input核心
  2. input核心會進(jìn)行裁決再上報的事件處理層,所以對于按鍵事件,一定要先報1再報0(或者反過來),不能只report 1或0, 這樣核心會認(rèn)為是一個事件被誤觸發(fā)了多次而只上報一次,雖然我們真的按下了多次。

應(yīng)用層解析

事件處理層最終會將驅(qū)動sync一次時所有report的事件組織成一個struct input_value[]的形式上報到應(yīng)用層,在應(yīng)用層從相應(yīng)的設(shè)備文件中獲取上報的事件的時候,需要注意:

  1. 收到數(shù)組元素的數(shù)量會比底層多一個空元素,類似于寫of_device_id[]時***的空元素,這點(diǎn)應(yīng)用層在解析的時候需要注意。
  2. 事件處理層并不會緩存收到的事件,如果有新的事件到來,即使舊的事件沒有被讀取,也會被覆蓋,所以應(yīng)用程序需要及時讀取。

前文已經(jīng)說過,"include/uapi/linux/input.h"中的宏是應(yīng)用層和驅(qū)動層共用的通信協(xié)議,所以應(yīng)用層在解析收到的struct input_value對象的時候,只需要"include <linux/input.h>"即可使用其中的宏。

  1. /* 
  2.  * The event structure itself 
  3.  */ 
  4.  
  5. struct input_event { 
  6.     struct timeval time
  7.     __u16 type; 
  8.     __u16 code; 
  9.     __s32 value; 
  10. };  

input分析

上文已經(jīng)說過,input子系統(tǒng)使用三層結(jié)構(gòu)來實(shí)現(xiàn)驅(qū)動事件到應(yīng)用層的傳遞。具體的,這三個層次每一個層次都由一條結(jié)構(gòu)體鏈表組成,在設(shè)備驅(qū)動層,核心結(jié)構(gòu)體是input_dev;在input核心層,是input_handle;在事件處理層,是input_handler。內(nèi)核通過鏈表和指針將三者結(jié)合到一起,最終實(shí)現(xiàn)了input_dev和input_handler的多對多的映射關(guān)系,這種關(guān)系可用下圖簡單描述。 

 

 

 

模板

下面的這個模板首先使用input子系統(tǒng)上報按鍵事件,然后在應(yīng)用層讀取。

input按鍵設(shè)備驅(qū)動

  1.            key@26{ 
  2.                       compatible = "xj4412,key"
  3.                       interrupt-parent = <&gpx1>; 
  4.                       interrupts = <2 2>; 
  5.            }; 
  6. };  
  1. static struct input_dev *button_dev; 
  2. static int button_irq; 
  3. static int irqflags; 
  4. static irqreturn_t button_interrupt(int irq, void *dummy){ 
  5.     input_report_key(button_dev, BTN_0, 0); 
  6.     input_report_key(button_dev, BTN_0, 1); 
  7.     input_sync(button_dev);    return IRQ_HANDLED; 
  8. }  
  9. static int button_init(void){ 
  10.     request_irq(button_irq, button_interrupt,irqflags, "button"NULL)) ; 
  11.      
  12.     button_dev = input_allocate_device(); 
  13.     button_dev->name = "button"
  14.     button_dev->evbit[0] = BIT_MASK(EV_KEY); 
  15.     button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); 
  16.      
  17.     input_register_device(button_dev);    return 0; 
  18. static int button_exit(void){ 
  19.     input_free_device(button_dev); 
  20.     free_irq(button_irq, button_interrupt);    return 0;    
  21. static int key_probe(struct platform_device *pdev){ 
  22.     struct resource *irq_res; 
  23.     irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 
  24.     if(irq_res){ 
  25.         button_irq = irq_res->start; 
  26.         irqflags = irq_res->flags & IRQF_TRIGGER_MASK; 
  27.     }else
  28.          return -EINVAL;      
  29.     }    return button_init(); 
  30. static int key_remove(struct platform_device *dev){ 
  31.     return button_exit(); 
  32. struct of_device_id of_tbl[] = { 
  33.     {.compatible = "xj4412,key",}, 
  34.     {}, 
  35. }; 
  36. MODULE_DEVICE_TABLE(of, of_tbl);struct platform_driver key_drv = { 
  37.     .probe = key_probe, 
  38.     .remove = key_remove, 
  39.     .driver.name = "keydrv"
  40.     .driver.of_match_table = of_tbl, 
  41. }; 
  42. module_platform_driver_register(key_drv); 
  43. MODULE_LICENSE("GPL");  

應(yīng)用層獲取鍵值

  1. #include <linux/input.h> 
  2. struct input_event {    struct timeval time
  3.     unsigned short type; 
  4.     unsigned short code;    int value; 
  5. }; 
  6. int main(int argc, char * const argv[]){ 
  7.     int fd = 0; 
  8.     struct input_event event[3] = {0};      //3?。?!,驅(qū)動上傳了2個事件,第三個用來裝空元素  
  9.     int ret = 0; 
  10.     fd = open(argv[1],O_RDONLY); 
  11.     while(1){ 
  12.         ret = read(fd,&event,sizeof(event)); 
  13.         printf("ret:%d,val0:%d,val1:%d,val12:%d\n",ret,event[0].value,event[1].value,event[2].value);          //2?。?!,***一個是空 
  14.         sleep(1); 
  15.     } 
  16.     return 0; 
責(zé)任編輯:龐桂玉 來源: 嵌入式Linux中文站
相關(guān)推薦

2021-08-31 11:53:38

Linux inputLinux 系統(tǒng)

2020-10-10 07:18:14

Linux系統(tǒng)編程管道

2020-10-18 07:13:44

Linux系統(tǒng)編程信號捕捉

2020-09-26 21:43:59

Linux系統(tǒng)編程條件變量

2020-10-05 22:01:02

Linux系統(tǒng)編程線程屬性

2020-09-28 06:49:50

Linux系統(tǒng)編程互斥量mutex

2020-09-26 23:09:00

Linux系統(tǒng)編程讀寫鎖

2020-09-22 07:35:06

Linux線程進(jìn)程

2020-09-25 07:34:40

Linux系統(tǒng)編程信號量

2020-10-05 22:05:10

Linux系統(tǒng)編程時序競態(tài)

2020-10-08 10:10:51

Linux系統(tǒng)編程信號集

2020-10-09 07:13:11

Linux系統(tǒng)編程mmap

2009-07-03 11:57:18

系統(tǒng)編程安全linux

2009-10-12 12:46:55

Linux內(nèi)核SCSI IO

2017-07-14 14:35:27

Linux中斷系統(tǒng)

2017-09-11 15:35:43

AndroidInput系統(tǒng)框架

2010-03-05 13:34:54

2021-05-06 07:53:20

LinuxUBI子系統(tǒng)

2019-03-15 09:30:09

Linux系統(tǒng)CPU

2014-09-22 13:31:46

Linux
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號