linux输入子系统(5)

第2章 输入子系统的事件驱动

上一章已经说过输入子系统分为三层,最上面的一层是事件处理层,我们暂时称它为事件驱动,这是相对于上一章的设备驱动来讲的。

上一章介绍了设备驱动注册时要与匹配的 handler 连接,报告的事件也会分发给连接的 handler ,这一章介绍 handler 的相关操作。

2.1      重要的数据结构

首先介绍 input_handle ,这个结构体用来连接 input_dev input_handler 。它的代码如 程序清单 2 .1 所示。

程序清单 2 . 1   input_handle

/* include/linux/input.h */

struct input_handle {

         void *private;                                                                                                                                                 

 

         int open;                                                                                                                                                         

         const char *name;                                                                                                                                           

 

         struct input_dev *dev;                                                                                                                                    

         struct input_handler *handler;                                                                                                                        

 

         struct list_head    d_node;                                                                                                                              

         struct list_head    h_node;                                                                                                                              

};

各个成员的含义如下:

私有数据指针。

记录本设备被打开的次数。

创建此 handle handler 所赋予的名字。

指向附着的 input_dev

指向创建此 handle handler

链表节点,用来加入附着的 input_dev

链表节点,用来加入附着的 input_handler

程序清单 1.11 中,我们看到 input_dev input_handler 匹配过程中用到了 input_device_id 。它的代码如 程序清单 2.2 所示。

程序清单 2 . 2   input_device_id

/* include/linux/mod_devicetable.h */

struct input_device_id {

         kernel_ulong_t flags;                                                                                                                            

 

         __u16 bustype;                                                                                                                                     

         __u16 vendor;

         __u16 product;

         __u16 version;

 

         kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];                           

         kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];

         kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

 

         kernel_ulong_t driver_info;                                                                                                                  

};

各个成员的含义如下:

定义需要匹配 input_id 的哪些域(使用方法参考 程序清单 1.11 )。

对应 input_id 的四个数据域。

存储支持事件的位图,与 input_dev 中的同名数据成员功能一致。

指示结构体中是否含有驱动信息。

input_handler 这个结构体是事件驱动的主体,每一种处理方式对应一个 handler 结构体。它的定义如 程序清单 2.3 所示。

程序清单 2 . 3     input_handler

/* include/linux/input.h */

struct input_handler {

         void *private;                                                                                                                                                 

 

         void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);                         

         int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);        

         void (*disconnect)(struct input_handle *handle);                                                                                           

         void (*start)(struct input_handle *handle);                                                                                                     

 

         const struct file_operations *fops;                                                                                                                  

         int minor;                                                                                                                                                        

         const char *name;                                                                                                                                           

 

         const struct input_device_id *id_table;                                                                                                           

         const struct input_device_id *blacklist;                                                                                                          

 

         struct list_head    h_list;                                                                                                                                 

         struct list_head    node;                                                                                                                                  

};

每个成员的具体解释如下:

私有数据指针。

事件处理函数指针。设备驱动报告的事件最终由这个函数来处理 ( 参考 程序清单 1.14 )

连接 handler input_dev 的函数指针。

断开连接函数指针。

为给定的 handle 启动 handler 函数指针。

文件操作结构体。

这个 handler 可以使用的 32 个次设备号的最小值。

handler 的名字。

可以处理的 input_device_ids 列表(用法参考 程序清单 1.11 )。

需要被忽略的 input_device_ids 列表。

用来连接 handle 的链表链表节点。每个与此 handler 相关的 handle 都放入此链表。

用来放入全局 handler 链表的节点。

2.2      input_handler 的注册

首先介绍存放注册的 input_handler 所用的数据结构。如所 程序清单 2.4 示。

程序清单 2 . 4   input core 全局数据

/* driver/input/input.c */

static LIST_HEAD(input_dev_list);                                                       /* 设备链表头                                         */

static LIST_HEAD(input_handler_list);                                                 /* handler 链表头                                      */

 

static DEFINE_MUTEX(input_mutex);                                                 /* 保护以上两个链表                             */

 

static struct input_handler *input_table[8];                                              /* 存放注册的 input_handler 的指针数组 */

程序清单 1.9 处注册的 input_dev 结构体加入到上面的 input_dev_list 当中,下面将要介绍的注册 input_handler ,其实就是将 input_hangler 加入到 input_handler_list 当中。 input_table 中存放进行文件操作的 handler ,使用它们次设备号的最高三比特在 input_table 中寻址,因此每个 handler 最多支持 32 个设备节点。由上面的代码可以看出输入子系统最多允许 8 个进行文件操作的 input_handler 同时存在。

input_register_handler 的代码如 程序清单 2.5 所示。

程序清单 2 . 5   input_register_handler

int input_register_handler(struct input_handler *handler)

{

         struct input_dev *dev;

         int retval;

 

         retval = mutex_lock_interruptible(&input_mutex);

         if (retval)

                   return retval;

 

         INIT_LIST_HEAD(&handler->h_list);                                                                                               

 

         if (handler->fops != NULL) {                                                                                                              

                   if (input_table[handler->minor >> 5]) {                                                                                      

                            retval = -EBUSY;

                            goto out;

                   }

                   input_table[handler->minor >> 5] = handler;                                                                              

         }

 

         list_add_tail(&handler->node, &input_handler_list);                                                                  

 

         list_for_each_entry(dev, &input_dev_list, node)                                                                                  

                   input_attach_handler(dev, handler);                                                                                    

 

         input_wakeup_procfs_readers();

 

  out:

         mutex_unlock(&input_mutex);

         return retval;

}

EXPORT_SYMBOL(input_register_handler);

程序含义如下:

初始化 handler 中的链表节点,为加入 input_handler_list 做准备。

如果此 handler 需要进行文件操作。

如果相应的次设备号段被占用。

handler 注册进 input_table

handler 加入 input_handler_list 链表。

遍历 input_dev_list 链表中的每一个 input_dev 结构体。

handler 与每一个 input_dev 进行匹配。

input_attach_handler 的代码如 程序清单 1 .10 所示,这里不再赘述。

总结一下 input_handler 的注册过程:见自己加入 input_handler_list input_table ,然后与 input_dev_list 中的 input_dev 比较并与匹配的建立连接。

参考 1.4 input_dev 的注册 这一节,我们发现 input_dev input_handler 都是将自己加入各自的链表,然后再和对方链表中匹配的进行连接。

你可能感兴趣的:(linux输入子系统(5))