小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Input Core和evdev基本知識(shí) - Kernel3.0.8 .

 wanwanstudy 2012-02-28

 1. 基本數(shù)據(jù)結(jié)構(gòu)和使用示例

input_event數(shù)據(jù)結(jié)構(gòu)如下:

  1. struct input_event {  
  2.     struct timeval time;  
  3.     __u16 type;  
  4.     __u16 code;  
  5.     __s32 value;  
  6. };  

input_dev數(shù)據(jù)結(jié)構(gòu)如下:

  1. struct input_dev {  
  2.     const char *name;  
  3.     const char *phys;  
  4.     const char *uniq;  
  5.     struct input_id id;  
  6.   
  7.     unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];  
  8.   
  9.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];  
  10.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  
  11.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  
  12.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  
  13.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  
  14.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  
  15.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  
  16.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  
  17.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  
  18.   
  19.     unsigned int hint_events_per_packet;  
  20.   
  21.     unsigned int keycodemax;  
  22.     unsigned int keycodesize;  
  23.     void *keycode;  
  24.   
  25.     int (*setkeycode)(struct input_dev *dev,  
  26.               const struct input_keymap_entry *ke,  
  27.               unsigned int *old_keycode);  
  28.     int (*getkeycode)(struct input_dev *dev,  
  29.               struct input_keymap_entry *ke);  
  30.   
  31.     struct ff_device *ff;  
  32.   
  33.     unsigned int repeat_key;  
  34.     struct timer_list timer;  
  35.   
  36.     int rep[REP_CNT];  
  37.   
  38.     struct input_mt_slot *mt;  
  39.     int mtsize;  
  40.     int slot;  
  41.     int trkid;  
  42.   
  43.     struct input_absinfo *absinfo;  
  44.   
  45.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];  
  46.     unsigned long led[BITS_TO_LONGS(LED_CNT)];  
  47.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];  
  48.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];  
  49.   
  50.     int (*open)(struct input_dev *dev);  
  51.     void (*close)(struct input_dev *dev);  
  52.     int (*flush)(struct input_dev *dev, struct file *file);  
  53.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  54.   
  55.     struct input_handle __rcu *grab;  
  56.   
  57.     spinlock_t event_lock;  
  58.     struct mutex mutex;  
  59.   
  60.     unsigned int users;  
  61.     bool going_away;  
  62.   
  63.     bool sync;  
  64.   
  65.     struct device dev;  
  66.   
  67.     struct list_head    h_list;  
  68.     struct list_head    node;  
  69. }  


比如TouchScrenn報(bào)告一個(gè)TouchDown事件給Input子系統(tǒng),其代碼如下:

  1. input_report_abs(inputdevice, ABS_X, 100);  
  2. input_report_abs(inputdevice, ABS_Y, 200);  
  3. input_report_key(inputdevice, BTN_TOUCH,  1);  
  4.   
  5. static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)  
  6. {  
  7.     input_event(dev, EV_ABS, code, value);  
  8. }  
  9.   
  10. static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)  
  11. {  
  12.     input_event(dev, EV_KEY, code, !!value);  
  13. }  
  14.   
  15. /** 
  16.  * input_event() - report new input event 
  17.  * @dev: device that generated the event 
  18.  * @type: type of the event 
  19.  * @code: event code 
  20.  * @value: value of the event 
  21.  * 
  22.  * This function should be used by drivers implementing various input 
  23.  * devices to report input events. See also input_inject_event(). 
  24.  */  
  25. void input_event(struct input_dev *dev,  
  26.          unsigned int type, unsigned int code, int value)  
  27. {  
  28.     unsigned long flags;  
  29.   
  30.     if (is_event_supported(type, dev->evbit, EV_MAX)) {  
  31.   
  32.         spin_lock_irqsave(&dev->event_lock, flags);  
  33.         add_input_randomness(type, code, value);  
  34.         input_handle_event(dev, type, code, value);  
  35.         spin_unlock_irqrestore(&dev->event_lock, flags);  
  36.     }  
  37. }  

它將調(diào)用input_pass_event,input_pass_event代碼如下:

  1. static void input_pass_event(struct input_dev *dev,  
  2.                  unsigned int type, unsigned int code, int value)  
  3. {  
  4.     struct input_handler *handler;  
  5.     struct input_handle *handle;  
  6.   
  7.     rcu_read_lock();  
  8.   
  9.     handle = rcu_dereference(dev->grab);  
  10.     if (handle)  
  11.         handle->handler->event(handle, type, code, value);  
  12.     else {  
  13.         bool filtered = false;  
  14.   
  15.         list_for_each_entry_rcu(handle, &dev->h_list, d_node) {  
  16.             if (!handle->open)  
  17.                 continue;  
  18.   
  19.             handler = handle->handler;  
  20.             if (!handler->filter) {  
  21.                 if (filtered)  
  22.                     break;  
  23.   
  24.                 handler->event(handle, type, code, value);  
  25.   
  26.             } else if (handler->filter(handle, type, code, value))  
  27.                 filtered = true;  
  28.         }  
  29.     }  
  30.   
  31.     rcu_read_unlock();  
  32. }  

上面的handler就是下面的evdev_handler.
2. evdev & input core & input_dev初始化

在kernel中,調(diào)用函數(shù)evdev_read,此函數(shù)從client->buffer中(evdev_client *client = file->private_data;)copy對(duì)應(yīng)的input_event到用戶提供的buffer。這些input_event數(shù)據(jù)如何從input_handle_event到client->buffer中的呢? 它是在evdev_event中實(shí)現(xiàn)的。

  1. <span style="font-size:10px;">static struct input_handler evdev_handler = {  
  2.     .event      = evdev_event,  
  3.     .connect    = evdev_connect,  
  4.     .disconnect = evdev_disconnect,  
  5.     .fops       = &evdev_fops,  
  6.     .minor      = EVDEV_MINOR_BASE,  
  7.     .name       = "evdev",  
  8.     .id_table   = evdev_ids,  
  9. };</span>  


    input_dev如何與evdev_handler關(guān)聯(lián)起來(lái)的呢? 它只在evdev_init中調(diào)用input_register_handler(&evdev_handler)被注冊(cè)了。其關(guān)聯(lián)關(guān)系如下:   

   a)在input_register_handler中,把evdev_handler增加到input_handler_list中   

   b)在input_register_device中,通過(guò)input_attach_handler(dev, handler),尋找input_handler_list中哪一個(gè)input_handler與需要注冊(cè)的設(shè)備相匹配,找到匹配的,則調(diào)用此input_handler的connect把input_handler與注冊(cè)的input_device關(guān)聯(lián)起來(lái),這樣新注冊(cè)的input_device就有對(duì)應(yīng)的處理方法了。

 

  1. <span style="font-size:10px;">static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)  
  2. {  
  3.     const struct input_device_id *id;  
  4.     int error;  
  5.   
  6.     id = input_match_device(handler, dev);  
  7.     if (!id)  
  8.         return -ENODEV;  
  9.   
  10.     error = handler->connect(handler, dev, id);  
  11.     if (error && error != -ENODEV)  
  12.         pr_err("failed to attach handler %s to device %s, error: %d\n",  
  13.                handler->name, kobject_name(&dev->dev.kobj), error);  
  14.   
  15.     return error;  
  16. } </span>  


     c)如果匹配上了,就調(diào)用evdev_handler->connect函數(shù)(evdev_connect),它把此evdev_handler保存在新設(shè)備的handle->handler中(evdev->handle.handler = handler;)。這樣在input_pass_event就可以調(diào)用evdev->handle.handler.event了。        

    d)input_handle把input_device和input_handler關(guān)聯(lián)起來(lái),其數(shù)據(jù)結(jié)構(gòu)如下: 

 

  1. struct input_handle {  
  2.   
  3.     void *private;  
  4.   
  5.     int open;  
  6.     const char *name;  
  7.   
  8.     struct input_dev *dev;  
  9.     struct input_handler *handler;  
  10.   
  11.     struct list_head    d_node;  
  12.     struct list_head    h_node;  
  13. };  

  e)evdev為事件字符設(shè)備( Event char devices)提供了訪問(wèn)原始輸入設(shè)備事件的方法,即它是做具體事的東東,對(duì)于事件字符設(shè)備,當(dāng)我們調(diào)用open, read, write最終都會(huì)調(diào)用它的函數(shù),即evdev_fops中的對(duì)應(yīng)函數(shù)。有了evdev和input core,設(shè)備驅(qū)動(dòng)程序就很簡(jiǎn)單了.

   e.1)首先調(diào)用input_allocate_device 創(chuàng)建一個(gè)input_dev對(duì)象

   e.2)然后設(shè)備input_dev的各種屬性以告訴input core你將提供哪些事件

   e.3)最后調(diào)用input_register_device把input_dev注冊(cè)到input core

   f)input_register_device

       前面講過(guò),在input_register_device中,它將在input_handler_list 尋找與input_dev匹配的input_handler,然后調(diào)用input_handler的connect函數(shù),即evdev_connect。在evdev_connect中,它將創(chuàng)建evdev對(duì)象,并以evdev->minor作為索引把它放在evdev_table數(shù)組中。evdev數(shù)據(jù)結(jié)構(gòu)如下:

  1. struct evdev {  
  2.     int open;  
  3.     int minor;   //在evdev_table中的索引  
  4.     struct input_handle handle;  //連接input_dev和input_handler  
  5.     wait_queue_head_t wait;  
  6.     struct evdev_client __rcu *grab;   // 用戶每調(diào)用一次open,將創(chuàng)建一個(gè)evdev_client  
  7.     struct list_head client_list;  
  8.     spinlock_t client_lock; /* protects client_list */  
  9.     struct mutex mutex;  
  10.     struct device dev;  
  11.     bool exist;  
  12. };  
  13.   
  14. struct evdev_client {  
  15.     unsigned int head;  
  16.     unsigned int tail;  
  17.     unsigned int packet_head; /* [future] position of the first element of next packet */  
  18.     spinlock_t buffer_lock; /* protects access to buffer, head and tail */  
  19.     struct wake_lock wake_lock;  
  20.     char name[28];  
  21.     struct fasync_struct *fasync;  
  22.     struct evdev *evdev;  
  23.     struct list_head node;  
  24.     unsigned int bufsize;  
  25.     struct input_event buffer[];  //存放所有這個(gè)設(shè)備產(chǎn)生的input_event,由evdev_event寫入  
  26. };  

        在evdev_connect,它設(shè)置設(shè)備名,初始化input_handle中各個(gè)數(shù)據(jù)成員(關(guān)鍵是其input_dev和input_handler),然后再調(diào)用input_register_handle把evdev中的input_handle添加到input_dev的h_lis鏈表中,并且把此input_handle添加到input_handler的h_list鏈表中。從此它們的三角關(guān)系建立完成。注:當(dāng)用戶每打開一次它就要?jiǎng)?chuàng)建一個(gè)evdev_client,并加入到client_list鏈表中,當(dāng)input_dev產(chǎn)生事件時(shí),evdev_event函數(shù)將把此input_event放入evdev->client_list鏈表中的每個(gè)evdev_client的buffer中。它們的關(guān)系如下圖所示:

3. Kernel中數(shù)據(jù)讀取流程

     在kernel中調(diào)用evdev_read來(lái)讀取數(shù)據(jù),其函數(shù)原型如下:

static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)

    其讀取流程為:

    1)從前面得知在打開設(shè)備文件時(shí),創(chuàng)建了一個(gè)evdev_client,并把此client保存在file的private_data中,所以現(xiàn)在從file->private_data中取出evdev_client

    2)從前面得知此evdev_client中保存有在evdev_connect時(shí)創(chuàng)建的evdev,從而可以得到對(duì)應(yīng)的evdev對(duì)象

    3)從client->buffer中讀取事件,并copy到用戶提供的buffer中。前面講過(guò),client->buffer中的事件是當(dāng)input_dev報(bào)告事件給Input core時(shí),由evdev_event把input_event事件放入client->buffer中的。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多