input子系统驱动学习之一

    刚开始学习linux这门课就被分配编写一个设备的input子系统驱动,这对我的确有点困难。不过实际的操作中发现困难远比我想象的要大的多,本以为按照老师课上的步骤就能够很快的完成这项任务,后来发现是我想多了。刚一开始我就陷入了一个困境,理不清到底input子系统驱动哪些是我需要做的哪些是系统已经为我们完成的,为此花费了我一个星期的时间才真正的从这个困惑里走出来。当然后边还有很多其他的困难这里我就不多说了,下面我就来总结一下input子系统学习的过程。
首先我们要清楚input子系统分为几层,各层都有些什么,以及各自的功能
一、input子系统分层
input子系统分为三层如图所示,需要强调的是我们需要做的只是完成设备驱动层的编程。这一点困惑了我一个星期。



1.1 设备驱动层
提供驱动层对具体输入设备硬件寄存器的读写问以及将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过事件核心层提交给事件处理层;设备驱动层完成具体硬件设备驱动的实现。
这一层中包含一个input_dev结构体,它是用来描述一个设备的信息的。包含了对设备的各项设置及操作函数。



1.2 事件核心层
输入子系统的核心部分,负责初始化和管理整个输入子系统,它对设备驱动层提供输入设备的注册和初始化函数完成输入设备在事件核心层的注册;同时它也对事件处理层提供接口函数以完成事件处理层设备在事件核心层的注册;建立设备驱动层的输入设备和事件处理层设备之间的关联。
这一层包含一个input_handle结构体,它做为input_dev和input_handler之间的桥梁 ,将handle的list_headd_node添加到handle关联的dev的h_list中, 将handle的list_headh_node添加到handle关联的handler的h_list中。


1.3 事件处理层
为用户空间的应用程序提供统一访问设备的接口和驱动层提交来的事件处理。使设备驱动部分不再关心对设备文件的操作而只需关心对各硬件寄存器的操作和提交的输入事件即可 。
这一层包含了input_handler结构体,它是作为事件处理器对应用程序的接口。


input子系统的三层分别各自拥有一个结构体,驱动功能的实现就是这三个结构体连接传递信息的过程。


究竟这三个结构体如何实现连接,在总结完input子系统驱动实现的整个过程之后在总体描述。
二、input子系统驱动的实现过程

2.1 分配一个输入设备

struct input_dev *dev;//声明一个输入设备结构体

Struct input_dev

{

       

   const char *name;//输入设备的名称

   ...

      struct input_id id;//输入设备的ID

     ...

      unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//输入设备所支持的事件类型

      unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//保存设备所支持的事件码

     ...

//输入设备文件接口操作函数指针

      int (*open)(struct input_dev *dev);

      void (*close)(struct input_dev *dev);

      int (*flush)(struct input_dev *dev, struct file *file);

      int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

      struct input_handle __rcu *grab;

      struct device dev;// 表示SYS设备模型中的一个设备

      struct list_head        h_list;//

      struct list_head        node;

}

dev=input_allocate_device(void);//为声明的结构体分配空间

2.2 驱动支持什么事件

    这一步我们可以设置输入设备支持哪些事件类型,以鼠标为例我们可以设置设备支持按键事件和相对坐标事件,在设置完支持的事件类型后还需要设置事件类型的码表,即该事件所包含的子事件。

input_dev->evbit[0] = BIT(EV_KEY); //赋值使输入设备支持按键类型 

input_dev->keybit[BITS_TO_LONGS(KEY_CNT)=BIT(BTN_LEFT)| BIT(BTN_RIGHT)|BIT(BTN_MIDDLE); //按键类型的键码,左键、右键、中键 

2.3 注册一个输入设备

   这一步调用的是input_register_device()函数,该函数是输入子系统核心提供的函数。该函数将 input_dev结构体注册到输入子系统核心中。input_register_device()函数如果注册失败,必须调用 input_free_device()函数释放分配的input_dev空间。如果该函数注册成功,在卸载函数中应该调用 input_unregister_device()函数来注销输入设备结构体。注册输入设备的过程就是为输入设备设置默认值,并将其挂input_dev_list链上,与挂载在 input_handler_list 中的 handler 相匹配。如果匹配成功,就会调用 handler 的 connect函数。

int input_register_device(struct input_dev *dev)//input子系统注册一个新的输入设备

2.4 驱动事件报告

    这一步是有设备驱动层向核心层报告发生的事件,例如按键事件,相对坐标事件等,这些事件全都汇总到核心层由核心层统一分配到事件处理层。

input_report_key(dev,BTN_LEFT,value);

实质是函数:input_event(dev,type,value);

2.5 释放和注销设备

     这一步用来注销输入设备并清除为该设备分配的空间。

void input_unregister_device(struct input_dev *dev);

void input_free_device(struct input_dev *dev);

    通过以上的介绍我们了解了整个input子系统驱动程序的编写流程,下面让我们根据usb鼠标驱动程序来看一看input子系统驱动程序的实现过程。

下面就来说一说三个结构体的连接过程

    在我们编写的设备驱动中调用input_register_device()来注册一个设备。 input_register_device()完成的主要功能就是初始化一些默认的值,将自己的device结构添加到linux设备模型当中,将input_dev添加到input_dev_list链表中,然后寻找合适的handlerinput_handler配对,配对的核心函数是input_attach_handler

     input_attach_handler的主要功能是调用了两个函数,一个input_match_device进行配对,一个connect处理配对成功后续工作。这些函数我们可以在linux内核源码中进行查看。

   对于connect函数,每种事件处理器的实现都有差异,但原理都相同,事件处理器evdev为例,其connect函数为evdev_connect()evdev_connect函数做配对后的善后工作,分配一个evdev结构体,并初始化相关成员,evdev结构体中有input_handle结构,在函数evdev_connect()中实现该结构体的初始化并调用 input_register_handle实现注册

input_register_handle()就是把一个handle结构体通过d_node链表项,分别链接到input_devh_list,input_handlerh_list上。从而实现了3个结构体的连接。

总结

    Input子系统驱动的编写需要我们理清哪些操作是需要我们做的,哪些操作是子系统已经为我们完成了的。这一点很重要,只有我们明确了自己需要做些什么才能让我们更快的学会input子系统程序的编写。在这一个过程中我就走了很多弯路。起先对input子系统不是太多了解,通过网上查找相关介绍和浏览上课的PPT,我看到了很多关于input子系统驱动的介绍。但这些介绍不仅仅包含了我们需要做的而且还包含了系统已经为我们完成了的。这给我的学习带来了很大的困扰,我不明白究竟我该从何下手编写一个完整的input子系统设备驱动了。通过一遍又一遍的浏览体会我终于明白了哪些是我需要做的。在这个过程中我也学会了如何查看linux内核源码。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值