板牙  
失败是什么?没有什么,只是更走近成功一步;而成功是走过了所有通向失败的路...只要你心够决!

17.2  handler注册分析

input_handler是输入子系统的主要数据结构,一般将其称为handler处理器,表示对输入事件的具体处理。 input_handler为输入设备的功能实现了一个接口,输入事件最终传递到handler处理器,handler处理器根据一定的规则,然后对事件 进行处理,具体的规则将在下面详细介绍。在此之前,需要了解一下输入子系统的组成。

17.2.1  输入子系统的组成

前面主要讲解了input_dev相关的函数,本节将总结前面的知识,并引出新的知识。为了使读者对输入子系统有整体的了解,本节将对输入子系统的组成进行简要的介绍。后面的章节将围绕输入子系统的各个组成部分来学习。首先,看看图17.3所示,为输入子系统的组成。


 
(点击查看大图)图17.3  输入子系统的组成

输入子系统由驱动层、输入子系统核心层(Input Core)和事件处理层(Event Handler)3部分组成。一个输入事件,如鼠标移动,键盘按键按下等通过驱动层->系统核心层->事件处理层->用户空间的顺序到 达用户空间并传给应用程序使用。其中Input Core即输入子系统核心层由driver/input/input.c及相关头文件实现。其对下提供了设备驱动的接口,对上提供了事件处理层的编程接 口。输入子系统主要设计input_dev、input_handler、input_handle等数据结构,它们的用途和功能如表17.1所示。

表17.1  关键数据结构

   

   

struct input_dev

input.h

物理输入设备的基本数据结构,

包含设备相关的一些信息

struct input_handler

input.h

事件处理结构体,定义怎么

处理事件的逻辑

struct input_handle

input.h

用来创建input_dev

input_handler之间关系的结构体

17.2.2  input_handler结构体

input_handler是输入设备的事件处理接口,为处理事件提供一个统一的函数模板,程序员应该根据具体的需要实现其中的一些函数,并将其注册到输入子系统中。该结构体的定义如下:

    01  struct input_handler {  
    
02      void *private;  
    
03      void (*event)(struct input_handle *handle, unsigned int type,unsigned int code, int value);  
    
04      int (*connect)(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id);  
    
05      void (*disconnect)(struct input_handle *handle);  
    
06      void (*start)(struct input_handle *handle);  
    
07      const struct file_operations *fops;  
    
08      int minor;  
    
09      const char *name;  
    
10      const struct input_device_id *id_table;  
    
11      const struct input_device_id *blacklist;  
    
12      struct list_head    h_list;  
    
13      struct list_head    node;  
    
14  };

对该结构体简要分析如下。

第02行,定义了一个private指针,表示驱动特定的数据。这里的驱动指的就是handler处理器。

第03行,定义了一个event()处理函数,这个函数将被输入子系统调用去处理发送给设备的事件。例如将发送一个事件命令LED灯点亮,实际控制硬件的点亮操作就可以放在event()函数中实现。

第04行,定义了一个connect()函数,该函数用来连接handler和input_dev。在input_attach_handler()函数的第10行,就是回调的这个自定义函数。

第05行,定义了一个disconnect()函数,这个函数用来断开handler和input_dev之间的联系。

第07行,表示handler实现的文件操作集,这里不是很重要。

第08行,表示设备的次设备号。

第09行,定义了一个name,表示handler的名字,显示在/proc/bus/input/handlers目录中。

第10行,定义了一个id_table表,表示驱动能够处理的表。

第11行,指向一个input_device_id表,这个表包含handler应该忽略的设备。

第12行,定义了一个链表h_list,表示与这个input_handler相联系的下一个handler。

第13行,定义了一个链表node,将其连接到全局的input_handler_list链表中,所有的input_handler都连接在其上。

17.2.3  注册input_handler

input_register_handler()函数注册一个新的input handler处理器。这个handler将为输入设备使用,一个handler可以添加到多个支持它的设备中,也就是一个handler可以处理多个输 入设备的事件。函数的参数传入简要注册的input_handler指针,该函数的代码如下:

    01  int input_register_handler(struct input_handler *handler)  
    
02  {  
    
03      struct input_dev *dev;  
    
04      int retval;  
    
05      retval = mutex_lock_interruptible(&input_mutex);  
    
06      if (retval)  
    
07          return retval;  
    
08      INIT_LIST_HEAD(&handler->h_list);  
    
09      if (handler->fops != NULL) {  
    
10          if (input_table[handler->minor >> 5]) {  
    
11              retval = -EBUSY;  
    
12              goto out;  
    
13          }  
    
14          input_table[handler->minor >> 5= handler;  
    
15      }  
    
16      list_add_tail(&handler->node, &input_handler_list);  
    
17      list_for_each_entry(dev, &input_dev_list, node)  
    
18          input_attach_handler(dev, handler);  
    
19      input_wakeup_procfs_readers();  
    
20   out:  
    
21      mutex_unlock(&input_mutex);  
    
22      return retval;  
    
23  }

下面对这个函数进行简要的分析。

第03、04行,定义了一些局部变量。

第05~07行,对input_mutex进行了加锁。当加锁失败后,则返回。

第08行,初始化h_hlist链表,该链表连接与这个input_handler相联系的下一个handler。

第09~14行,其中的handler->minor表示对应input设备结点的次设备号。以handler->minor右移5位作为索引值插入到input_table[ ]中,

第16行,调用list_add_tail()函数,将handler加入全局的input_handler_list链表中,该链表包含了系统中所有的input_handler。

第17、18行,主要调用了input_attach_handler()函数。该函数在17.1.2节 input_register_device()函数的第35行曾详细的介绍过。input_attach_handler()函数的作用是匹配 input_dev_list链表中的input_dev与handler。如果成功会将input_dev与handler联系起来。

第19行,与procfs文件系统有关,这里不需要关心。

第20~22行,解互斥锁并退出。

17.2.4  input_handle结构体

input_register_handle()函数用来注册一个新的handle到输入子系统中。input_handle的主要功能是用来连接input_dev和input_handler。其结构如下:

    01  struct input_handle {  
    
02      void *private;  
    
03      int open;  
    
04      const char *name;  
    
05      struct input_dev *dev;  
    
06      struct input_handler *handler;  
    
07      struct list_head    d_node;  
    
08      struct list_head    h_node;  
    
09  };

下面对该结构体的成员进行简要的介绍。

第02行,定义了private表示handler特定的数据。

第03行,定义了一个open变量,表示handle是否正在被使用,当使用时,会将事件分发给设备处理。

第04行,定义了一个name变量,表示handle的名字。

第05行,定义了dev变量指针,表示该handle依附的input_dev设备。

第06行,定义了一个handler变量指针,指向input_handler,该handler处理器就是与设备相关的处理器。

第07行,定义了一个d_node变量,使用这个变量将handle放到设备相关的链表中,也就是放到input_dev->h_list表示的链表中。

第08行,定义了一个h_node变量,使用这个变量将handle放到input_handler相关的链表中,也就是放到handler->h_list表示的链表中。

17.2.5  注册input_handle

input_handle是用来连接input_dev和input_handler的一个中间结构体。事件通过input_handle从 input_dev发送到input_handler,或者从input_handler发送到input_dev进行处理。在使用 input_handle之前,需要对其进行注册,注册函数是input_register_handle()。

1.注册函数input_register_handle()

input_register_handle()函数用来注册一个新的handle到输入子系统中。该函数接收一个input_handle类型的指针,该变量要在注册前对其成员初始化。input_register_handle()函数的代码如下:

  1. 01  int input_register_handle(struct input_handle *handle)  
  2. 02  {  
  3. 03      struct input_handler *handlehandler = handle->handler;  
  4. 04      struct input_dev *dev = handle->dev;  
  5. 05      int error;  
  6. 06      error = mutex_lock_interruptible(&dev->mutex);  
  7. 07      if (error)  
  8. 08          return error;  
  9. 09      list_add_tail_rcu(&handle->d_node, &dev->h_list);  
  10. 10      mutex_unlock(&dev->mutex);  
  11. 11      synchronize_rcu();  
  12. 12      list_add_tail(&handle->h_node, &handler->h_list);  
  13. 13      if (handler->start)  
  14. 14          handler->start(handle);  
  15. 15      return 0;  
  16. 16  } 

下面对该函数进行简要的解释。

第03行,从handle中取出一个指向input_handler的指针,为下面的操作使用。

第04行,从handle中取出一个指向input_dev的指针,为下面的操作使用。

第06行,给竞争区域加一个互斥锁。

第09行,调用list_add_tail_rcu()函数将handle加入输入设备的dev->h_list链表中。

第12行,调用list_add_tail()函数将handle加入input_handler的handler->h_list链表中。

第13、14行,如果定义了start()函数,则调用它。

2.input_dev、input_handler和input_handle之间的关系

从以上的代码分析可以看出,input_dev、input_handler和handle三者之间是相互联系的,如图17.4所示。


 
(点击查看大图)图17.4  input_dev、input_handler和input_handle的关系
结 点1、2、3表示input_dev设备,其通过input_dev->node变量连接到全局输入设备链表input_dev_list中。结点 4、5、6表示input_handler处理器,其通过input_handler->node连接到全局handler处理器链表 input_handler_list中。结点7是一个input_handle的结构体,其用来连接input_dev和input_handler。 input_handle的dev成员指向了对应的input_dev设备,input_handle的handler成员指向了对应的 input_handler。另外,结点7的input_handle通过d_node连接到了结点2的input_dev上的h_list链表上。另一 方面,结点7的input_handle通过h_node连接到了结点5的input_handler的h_list链表上。通过这种关系,将 input_dev和input_handler联系了起来。

posted on 2011-09-12 23:08  板牙  阅读(361)  评论(0编辑  收藏  举报