Input Core和evdev基本知识

1. 基本数据结构和使用示例

input_event数据结构如下:

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

input_dev数据结构如下:

  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; 


比如TouchScrenn报告一个TouchDown事件给Input子系统,其代码如下:

  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.     input_event(dev, EV_ABS, code, value); 
  7.  
  8. static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) 
  9.     input_event(dev, EV_KEY, code, !!value); 
  10.  
  11. /**
  12. * input_event() - report new input event
  13. * @dev: device that generated the event
  14. * @type: type of the event
  15. * @code: event code
  16. * @value: value of the event
  17. *
  18. * This function should be used by drivers implementing various input
  19. * devices to report input events. See also input_inject_event().
  20. */ 
  21. void input_event(struct input_dev *dev, 
  22.          unsigned int type, unsigned int code, int value) 
  23.     unsigned long flags; 
  24.  
  25.     if (is_event_supported(type, dev->evbit, EV_MAX)) { 
  26.  
  27.         spin_lock_irqsave(&dev->event_lock, flags); 
  28.         add_input_randomness(type, code, value); 
  29.         input_handle_event(dev, type, code, value); 
  30.         spin_unlock_irqrestore(&dev->event_lock, flags); 
  31.     } 

它将调用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.     struct input_handler *handler; 
  4.     struct input_handle *handle; 
  5.  
  6.     rcu_read_lock(); 
  7.  
  8.     handle = rcu_dereference(dev->grab); 
  9.     if (handle) 
  10.         handle->handler->event(handle, type, code, value); 
  11.     else
  12.         bool filtered = false
  13.  
  14.         list_for_each_entry_rcu(handle, &dev->h_list, d_node) { 
  15.             if (!handle->open) 
  16.                 continue
  17.  
  18.             handler = handle->handler; 
  19.             if (!handler->filter) { 
  20.                 if (filtered) 
  21.                     break
  22.  
  23.                 handler->event(handle, type, code, value); 
  24.  
  25.             } else if (handler->filter(handle, type, code, value)) 
  26.                 filtered = true
  27.         } 
  28.     } 
  29.  
  30.     rcu_read_unlock(); 

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

在kernel中,调用函数evdev_read,此函数从client->buffer中(evdev_client *client = file->private_data;)copy对应的input_event到用户提供的buffer。这些input_event数据如何从input_handle_event到client->buffer中的呢? 它是在evdev_event中实现的。

[plain] view plain copy
  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关联起来的呢? 它只在evdev_init中调用input_register_handler(&evdev_handler)被注册了。其关联关系如下:  

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

   b)在input_register_device中,通过input_attach_handler(dev, handler),寻找input_handler_list中哪一个input_handler与需要注册的设备相匹配,找到匹配的,则调用此input_handler的connect把input_handler与注册的input_device关联起来,这样新注册的input_device就有对应的处理方法了。

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


     c)如果匹配上了,就调用evdev_handler->connect函数(evdev_connect),它把此evdev_handler保存在新设备的handle->handler中(evdev->handle.handler = handler;)。这样在input_pass_event就可以调用evdev->handle.handler.event了。       

    d)input_handle把input_device和input_handler关联起来,其数据结构如下:

[plain] view plain copy
  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为事件字符设备( Event char devices)提供了访问原始输入设备事件的方法,即它是做具体事的东东,对于事件字符设备,当我们调用open, read, write最终都会调用它的函数,即evdev_fops中的对应函数。有了evdev和input core,设备驱动程序就很简单了.

   e.1)首先调用input_allocate_device 创建一个input_dev对象

   e.2)然后设备input_dev的各种属性以告诉input core你将提供哪些事件

   e.3)最后调用input_register_device把input_dev注册到input core

   f)input_register_device

       前面讲过,在input_register_device中,它将在input_handler_list 寻找与input_dev匹配的input_handler,然后调用input_handler的connect函数,即evdev_connect。在evdev_connect中,它将创建evdev对象,并以evdev->minor作为索引把它放在evdev_table数组中。evdev数据结构如下:

[plain] view plain copy
  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;   // 用户每调用一次open,将创建一个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[];  //存放所有这个设备产生的input_event,由evdev_event写入 
  26. }; 

        在evdev_connect,它设置设备名,初始化input_handle中各个数据成员(关键是其input_dev和input_handler),然后再调用input_register_handle把evdev中的input_handle添加到input_dev的h_lis链表中,并且把此input_handle添加到input_handler的h_list链表中。从此它们的三角关系建立完成。注:当用户每打开一次它就要创建一个evdev_client,并加入到client_list链表中,当input_dev产生事件时,evdev_event函数将把此input_event放入evdev->client_list链表中的每个evdev_client的buffer中。它们的关系如下图所示:

3. Kernel中数据读取流程

     在kernel中调用evdev_read来读取数据,其函数原型如下:

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

    其读取流程为:

    1)从前面得知在打开设备文件时,创建了一个evdev_client,并把此client保存在file的private_data中,所以现在从file->private_data中取出evdev_client

    2)从前面得知此evdev_client中保存有在evdev_connect时创建的evdev,从而可以得到对应的evdev对象

    3)从client->buffer中读取事件,并copy到用户提供的buffer中。前面讲过,client->buffer中的事件是当input_dev报告事件给Input core时,由evdev_event把input_event事件放入client->buffer中的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值