input子系统三部分源码分析

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

1:先分析输入核心层源码分析input.c文件,分析完就能分析上层和下层了
注:从入口开始看input_init()输入核心层作为一个模块儿,为什么作为一个模块儿,就是因为linux内核是完全可以裁剪的,如果我的设备不需要输入就可以去掉这个模块儿
重要的函数如下,其余的后续继续自己研究
(1):核心层做的准备工作
<1>:class_register(&input_class)
input_class的数据结构 里有.name=input说明/sys/class一定能够找到input类 注册类就说明在/sys/class下
有了类,那么类里有很多设备,即一旦有class_register()就一定有device_register()

<2>:input_proc_init()跟proc文件系统有关/proc下

<3>:register_chrdev_region()
这里注册了一个字符设备驱动,主设备号为13将来在具体的驱动程序中,有了device_register就会和class_register产生效应了,每一个具体的硬件就由次设备号来区分

(2):那么在核心层里还要实现给设备驱动层提供操作接口,并且给事件驱动层提供接口
(2.1)给设备驱动层提供的接口
<1>input_allocate_device();
用来干嘛的?具体的硬件设备驱动只需要定义数据结构变量填充,调用专用接口来注册,这就是驱动层所做的事情,这里面使用了申请动态内存(该结构体太大了所以动态申请)并初始化一些必要的东西,和具体的硬件初始化无关
<2>input_set_capability()
这个函数就可以用来对具体的硬件设备进行初始化,具有向上层上报什么样的能力,注意每个能力就需要调用一次,比如左键调用一次,右键调用一次,中键如果不上报上层就人为你没有这个能力
Input_set_capability(dev,EV_KEY,BTN_LEFT);
Input_set_capability(dev,EV_KEY,BTN_LEFT);
Input_set_capability(dev,EV_KEY,BTN_MIDDLE);
dev:
type:在linux/input.h中已经定义
code:
value:

名称:设置输入能力:怎么理解设置输入能力,就是对上层能够输入什么事件的能力,左键右键,抬起还是按下,相对移动多少,或者触摸屏,触摸点坐标,压力是多少等 即说明 你这个输入设备是怎么的设备,具有怎样的能力
函数里封装了__set_bit
再注册进去就可以了
<3>input_register_device(structinput_dev *dev);传递一个已经填充好的设备结构体
{
init_time()
dev_set_name()这里就设置了具体的设备节点文件名,如event0,event1 ….
device_add()
真正的注册就是将当前的结构体连接到链表中去
list_add_tail()

list_for_each_entry()
用来遍历事件驱动层的handler链表(图中的四个已经被注册好)链表
遍历这些handler主要是看哪个能和当前的设备进行匹配,因为一个新的设备可以需要和handler绑定,生成对应的设备文件,用来给应用层提供接口,当可以和多个handler匹配时,则可以和多个handler一起绑定,应用层既可以打开mouseX也可以打开eventX这两个设备文件来访问该设备,这就是input子系统的设计理念

紧接着调用匹配函数
input_attach_handler()这个函数内部调用了如下两个函数

怎么匹配?
怎么算匹配上?

input_match_device()就是用来匹配device和handler,这里面有匹配的方法和规则
如果找到就返回structdevice_id匹配不上就返回NULL
匹配上之后就调用handler→connect函数来把id和dev绑定连接…..


evdev.c有个input_register_handler()函数,注册这个handler
input_handler{
.minor
.name
.table_id
}


绑定完后驱动只需要把数据得出来上报,事件层再把事件封装成input_event丢到缓冲区里去,(因为用户空间一直在阻塞等待读取数据)并且去激活内核空间里的read系统调用的在内核中的接口函数,用户空间再读取,
}

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

(2.2)事件驱动层的接口函数
<1>:input_register_handler();
<2>:input_register_handle();

input_register_handler() {函数里
input_table[8]里表示可以有八个handler
首先找到handler次设备号就是handlerMINOR_BASE再加上这个handler里的排位

input_register_device/handler都要到对方里面去遍历并且挂接上还没有被匹配上的设备
}
input_register_handle()的作用 就是用来记录devicehandler匹配上了

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
分析代码的作用,不是说让你去写,也没那个能力ls/dev
是为了提升架构意识和观念,学别人怎么架构的,对这一套架构熟悉,在写驱动时帮助我们分析遇到的问题
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
@3事件驱动层分析evdev.c
staticint __init evdev_init(void)
{
returninput_register_handler(&evdev_handler);
}
<1>evdev_handler的数据结构如下
structinput_handler {

void*private;

void(*event)(struct input_handle *handle, unsigned int type, unsigned intcode, int value);
void(*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool(*filter)(struct input_handle *handle, unsigned int type, unsignedint code, int value);
bool(*match)(struct input_handler *handler, struct input_dev *dev);
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);

boollegacy_minors;
intminor;
constchar *name;

conststruct input_device_id *id_table;

structlist_head h_list;
structlist_head node;
};


之前分析的input_match_device()上了之后就会去调用handler->connect函数

<2>:void(*event)(struct input_handle *handle, unsigned int type, unsigned intcode, int value);函数就是把报上来的硬件数据封装成input_event丢到缓冲区供用户(copy_to_usr)去读取
同id_table来做match噢
<2.1>event=evdev_event函数里面就涉及到把数据丢到缓冲区,并且里面
if(client)
evdev_pass_values(client,vals, count, time_mono, time_real);
else
list_for_each_entry_rcu(client,&evdev->client_list, node)
evdev_pass_values(client,vals, count,
time_mono, time_real);
这一段儿代码决定了那张图中要将得到的数据通过几条handler通道通知上去,有时间自行研究

<3>connet=evdev_connect函数里面对具体的设备驱动和handler结合起来,并且就做了具体的整个字符设备文件的创建的事情,如创建event0/event1等等
注意:里面的device_register函数就可以创建对应的设备文件而这里面是分开了,变成了device_initialize()device_add()了 而之前提到class_register()时注册了一个类/sys/class/input/下的子文件夹就是因为device_register的时候创建
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值