linux输入子系统(5)

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

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

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

2.1     重要的数据结构

首先介绍 input_handle ,这个结构体用来连接input_devinput_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;                                                                           

};

各个成员的含义如下:

⑴ 私有数据指针。

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

⑶ 创建此 handlehandler 所赋予的名字。

⑷ 指向附着的 input_dev

⑸ 指向创建此 handlehandler

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

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

程序清单1.11 中,我们看到input_devinput_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 )

⑶ 连接 handlerinput_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_listinput_table,然后与 input_dev_list 中的 input_dev 比较并与匹配的建立连接。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值