linux输入子系统(5)

来源:互联网 发布:用matlab实现遗传算法 编辑:程序博客网 时间:2024/05/17 08:26

第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 都是将自己加入各自的链表,然后再和对方链表中匹配的进行连接。

原创粉丝点击