Linux input子系统分析之三 input device/handler注册与注销分析

上一章我们分析了input子系统主要的数据结构,本章我们主要分析input hander、input device、input handle的注册与注销。本章的主要内容如下:

一、input device的注册与注销说明

二、input handler的注册与注销说明

三、input handle的注册与注销说明

四、input事件分发说明


在分析input device、input handler、input handle的注册与注销时,我们还是看下这些数据结构的关联,如下图所示即为这三个数据结构的关联,而input device、input handler、input handle的注册与注销则注册用于建立或移除这些数据结构间的关联。


input device的注册与注销说明

Input device的注册

在前面我们也说了,input 子系统device、handler的注册与注销,与设备驱动模型子系统中设备、驱动的注册与注销机制类似,针对设备、驱动的注册,在设备和驱动的注册接口中,通过遍历总线上所有已注册的驱动与设备,进行设备与驱动的匹配检测,若设备与驱动完成一次匹配则不再继续遍历检测。

而针对input子系统的input device的注册,其流程与设备驱动模型中设备、驱动的注册流程相似,其实现的流程大致如下:

为input_dev创建struct device类型的变量,并设置其所属的class为input_class,并调用device_add完成device类型变量的注册,至此完成strcut device类型变量注册至input_class中,且完成了input_dev对应的sysfs属性文件的创建,包括 name 、phys、uevent、uniq、bustype、product、vendor version、abs、ev、ff、 key、led、msc、rel 、snd、sw(对应默认属性input_dev_attr_group、input_dev_id_attr_group、input_dev_caps_attr_group,在调用input_allocate_device、devm_input_allocate_device时,通过调用input_allocate_device时,会设置input dev的struct device类型的成员变量,并设置其所属的class为input_class、dev_type为input_dev_type);将该input_device注册至input_dev_list;遍历input_handler_list链表,针对input_handler_list上每一个input_handler,均与注册的input_device进行匹配检测,若匹配检测成功,则调用input_handler->connect接口,进行input_handler与input_device的绑定(通过调用input_register_handle实现,也可以理解为在input_handler、input_device上完成input_handler、input_device的事件消息的订阅操作)。因input_handler和input_device可实现多对多的绑定,因此,会遍历input_handler_list链表上所有已注册的input_handler,而不是检测到一个input_handler的匹配即返回。


以上即为input_device注册的主要过程,与设备驱动模型中设备、驱动的注册流程相比,input_device的注册相对简单很多,只是遍历input_handler_list上每一个input_handler,实现一个input_device可以绑定多个input_handler(也可以理解为在该input_device上,多个input_handler进行了input event消息的订阅,当input_device上触发input事件后,则input_device会将input event消息分发给所有订阅的input handler。同时该input_device也为每一个匹配的input_handler上进行了inject input event消息的订阅,当input_handler有event发送给input_device时,该input_handler也将该event消息分发给所有订阅的input device)。

当然以上流程主要是input device注册主要的处理流程,在input_register_device接口中,也会做一些参数的合理性检测、存储input event消息的内存申请等操作。如下为该函数的处理流程,具体的代码不在此处分析,读者可自行分析,处理流程也就是这些步骤。


Input device的注销

该函数实现的功能与上面刚好相反,主要功能如下:

针对该input device上所有订阅的input_handle,将其open引用计数设置为0,并设置input device的going_away值为true;针对该input device所有订阅的input_handle,调用其关联input_handler的disconnect接口,解除input_dev、input_handle、input_handle的关联;将该input_dev对应的struct device类型成员变量从设备驱动模型子系统中删除(即删除与input_class的关联,并移除相关的属性文件等)


如下是相关函数的定义,相对来说也比较好理解下面的代码。


input handler的注册与注销说明

Input handler的注册

Input handler的注册与input device的注册类似,其接口名称为input_register_handler,流程如下:

将该input_device注册至input_handler_list;遍历input_dev_list链表,针对input_dev_list上每一个input_dev,均与注册的input_device进行匹配检测,若匹配检测成功,则调用input_handler->connect接口,进行input_handler与input_device的绑定(通过调用input_register_handle实现,也可以理解为在input_handler、input_device上完成input_handler、input_device的事件消息的订阅操作)。因input_handler和input_device可实现多对多的绑定,因此,会遍历input_dev_list链表上所有已注册的input_dev,而不是检测到一个input_dev的匹配即返回。

如下即为input_register_handler的处理流程


与input device相比,仅需要input_handler注册至链表、遍历input_dev_list链表的每一个input

dev进行匹配检测并完成匹配绑定操作。


Input handler的注销

Input handler注销刚好与注册相反,针对已绑定的所有input device,均调用input_handler->disconnect,进行解绑操作(主要是调用input_unregister_handle,进行input_handle的注销,从而解除input device、input handle、input handler的关联),如下即为input_unregister_handler的代码实现,逻辑还是比较简单的,不再赘述。


Input handle的注册与注销

Input handle的注册

Input handle的注册函数为input_register_handle,input_handle主要用于实现input handler、input device的关联操作,其主要实现的内容如下:

完成input_handle与input_handler的关联;完成input_handle与input_dev的关联。

下面是函数input_register_handle的代码实现:

将该input_handle注册到input_dev的h_list链表上;将该input_handle注册到input_handler的h_list链表上;若该input handler提供start接口,则调用start接口,执行start中的操作。

Input handle的注销

注销接口为input_unregister_handle,主要是解除与input_handler、input_dev的关联,其代码实现较简单,此处不再细述。

Input handle的注册与注销是如何调用的呢?

在input_register_handler、input_register_device的接口中,当input dev、input handler匹配成功,则会调用input handler的connect函数指针,而其connect函数中,则会完成如下操作:

调用input_register_handle,完成input handler、input handle、input device的关联;调用input_open_device,执行input device的打开(若该input device已执行过打开操作,则只增加device的引用计数即可,即users++).


而input handle的注销,则一般在input handler的disconnect接口中调用input_unregister_handle,去除input handler、input handle、input device的关联。


Input event的事件分发机制

input子系统提供了两个事件分发接口,即input_event、input_inject_event,其中input_event主要由

input_dev使用,实现将input event分发给input handler;而input_inject_event则主要由input_handler调用,实现将event分发给input device。这两个函数最终均调用input_handle_event接口进行事件的分发操作,而在input_handle_event接口中,则主要实现如下功能:

若待分发事件是需要分发给input handler,则调用input_pass_values接口,将input event分发给input handler,最终针对每一个input event,均调用input_handler的events/event接口,由input _handler进行input事件的处理;若待分发事件时需要分发给input device,则调用input_dev->event,由input_dev的event接口进行事件的处理即可。


针对需要分发给input handler的事件,还有如下需要说明:

若input_dev发送了EV_SYN事件,则需要将事件立即分发给input handler,但此时需要保证该input_dev至少存在两个事件(即若只有一个EV_SYN事件,则并不会将事件发送给input handler);若input_dev没有使用EV_SYN事件,则当该input_dev存储的event个数大于等于dev->max_vals - 2时,也会将所有存储的事件分发给所有关联的input handler。


以上即为本章的内容,主要说明了input handler、input handle、input dev的注册与注销以及事件分发接口,相对来说input 子系统核心层的代码实现还是比较容易理解的。下一章我们将分析一个input handler实例evdev。