input输入子系统详解

          今天又把input输入子系统这块重新看了一遍,下面我就对所理解的东西做一个总结,以便以后自己复习,也希望能给在这块还迷茫的同学给点帮助,下面是我针对所理解的input子系统所画的框架结构图:

   

        如图所示,input子系统是把驱动分为了好几个部分来实现的,其中核心层和纯软件的部分是内核帮助我们做好的,那我们只需要做跟硬件相关的部分就可以了。

        首先,我们来分析input子系统的核心层input.c这个文件,那我们从它的入口函数开始:

        

如图,核心层的init函数中只是注册了一个字符驱动,那我们接下来看看input_fops这个结构都实现了什么,我们发现这个结构里面只是实现了open这个函数,


那我们就有必要看看这个open函数里面都做了什么,


首先,在open函数中定义了一个input_handler结构体,如我最上面所画的input子系统框架图所示,在open函数中我们看到下面这句话

那这个input_table又是什么呢?


我们在input_register_handler()这个函数中看到了对input_table做了初始化,把这个数组的每项根据这个函数传入的hanlder参数做了初始化,

我们在evdev.c这个文件的入口函数中可以看到,只是调用了input_register_handler()这个函数来注册,


再来看看evdev_handler这个结构体:


这样的话我们就可以看到这个结构体正如input子系统框架结构图中所画的纯软件部分,它里面实现了event等等一系列函数,还有fops,那我们就可以理解了,上面的inut_table这个数组中正式存储着上面这个input_handler,


在open函数中,我们正式把上面的input_handler结构体中的fops赋给了file->f_op。

我们再来看看硬件相关的部分,我们用gpio_keys.c这个做为例子来说明:

在gpio_keys_probe()探测函数中,我们通过来初始化了一个input_dev结构体,接下来我们对这个结构体做了一系列的初始化:


最后我们调用input_register_device(input)向系统注册了这个input设备,下面我们就来分析一下这个注册函数是怎么实现的:


我们看到,函数里面把这个input_dev加入了一个链表里面,接着遍历input_handler_list这个链表,调用input_attach_handler来想handler建立连接,


我们再来看看input_match_device这个函数:


正是通过input_handler这个结构体中的id_table来比较进行匹配的,

这样我们就可以理解到,在注册input_dev或者input_handler时,会比较会比较input_dev和input_handler,根据input_handler的id_table判断这个input_handler能否支持这个input_dev,如果能支持,则会调用input_handler的connect函数来建立连接。



这里的connect就是input_handler的connect所指向的evdev_connect函数:里面定义了一个evdev结构体,我们来看看这个结构体


这个结构体里面定义了一个input_handle结构体,在connect函数中对这个结构体做了一系列的初始化:


接着调用来注册这个input_handle,这个就是input子系统框架图中连接input_handler和input_dev的核心,

在input_register_handle函数中有下面几句:


把这个input_handle添加到input_handler->h_list链表,和input_handle->dev->h_list链表中,至此input_dev和input_handler就建立起了连接。

那接下来我们看看应用层调用一系列函数后,驱动层是怎么工作的,假如应用层调用read函数,要读取一些数据,之前我们提到,file->f_op已经指向了input_handler的fops,所以read ——》file->f_op->evdev_read,在evdev_read函数中我们看到:


如上面的带面所示,如果当前没有数据可以返回,就会休眠,休眠被唤醒的条件就是当有数据可读时,那接下来,我们分析这个休眠是怎么被唤醒的:

在gpio_keys.c这个文件中我们看到了当有按键按下时就会在中断函数中进行处理,

我们看到input_event()这个函数,这个函数是用来想上层上报事件的,我们来看看它内部是如何实现的:

我们会看到其中对dev->h_list这个链表进行了遍历,

list_for_each_entry(handle,&dev->h_list,d_node);

if(handle->open)

handle->handler->event(handle,type,code,value);

我们看到是调用到了input_handler中的event()函数,我们再来看看这个函数实现了什么:


在event函数中我们看到了wake_up_interruptible(&evdev->wait);在这里唤醒了之前休眠的read,这样的话就可以读取按键按下的数据。

到这里,我们的input子系统根据几个例子就分析的差不多了,input子系统分为了三个部分input.c核心层,input_handler和input_dev,我们所要做的就是input_dev,其它两个部分是内核帮我们实现好的,那我们需要做什么呢:


1:分配一个input_dev结构体:

      struct input_dev *input;

      input = input_allocate_device();

2:对这个input_dev结构体的参数进行设置

3:注册input_dev

     input_register_device(&input);

4:硬件相关的部分的代码;比如在中断服务程序中上报事件;

到这里,我们的input子系统就彻底分析完了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值