天嵌 ARM开发社区

 找回密码
 注册
查看: 3110|回复: 2

输入子系统框架

[复制链接]
yywhut 发表于 2012-2-18 20:15:01 | 显示全部楼层 |阅读模式
输入子系统框架
新人报道,试着发个帖子试试。

字符设备驱动程序框架:
1.    major
2.    file-operation
3.    register
4.    入口函数
5.    出口函数
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

如果写的程序想很通用,要引入输入子系统框架
输入子系统由 输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,通过 Driver -> InputCore -> Eventhandler -> userspace 的顺序到达用户空间传给应用程序。
        其中Input Core 即 Input Layer 由 driver/input/input.c及相关头文件实现。对下提供了设备驱动的接口,对上提供了Event Handler层的编程接口。
具体过程需要仔细体会代码。

这部分可以仔细看韦东山老师的视频讲解,理解会更快些,百度下有很多。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

目的:我们写驱动的目的是为了构造一些函数,使上层可以调用,也就是构造file-operation。
先看下别人写的驱动程序是什么样子
drivers/input/input.c:
static int __init input_init(void)中有注册驱动的过程,调用了
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);

找一下input_fops,发现只有一个结构体,那再看看input_open_file都做了什么事情。

struct input_handler *handler = input_table[iminor(inode) >> 5];
定义一个input_handler指针,根据传入文件的次设备号从input_table中提取出一个input_handler

new_fops = fops_get(handler->fops);//从input_handler中提取出new_fops
file->f_op = new_fops;//将new_fops赋值给当前文件的file_operations

其实目的是将打开的新的文件的fop 指向所找到的 handler的里面的fop,将两者对应起来,这样以后操作这个文件的fop 实际上是操作handler的里面的fop。所以这里的驱动程序最重要的是怎么来构造这个handler里面的fop,也就是怎么来构造input_table里面的东西。这样看来input.c只是起到了一个中转的作用。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

找到input_table数组由谁构造?在input_register_handler这个函数里面来构造
搜索内核可知:
    evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c等文件调用了    input_register_handler,在每种设备里面,都构造了 input_handler 这种结构,我们以evdev.c为例。这些通用的文件已经将常规的操作都写好了,也就是fop结构。
static struct input_handler evdev_handler = {
    .event =    evdev_event,
    .connect =    evdev_connect,
    .disconnect =    evdev_disconnect,
    .fops =        &evdev_fops,
    .minor =    EVDEV_MINOR_BASE,
    .name =        "evdev",
    .id_table =    evdev_ids,
};
evdev_fops 可以看到很多读写函数,相当于帮我们去写了那些驱动函数。看下EVDEV_MINOR_BASE = 64,那么input_table[iminor(inode) >> 5];相当于
input_table[2].
id_table 表示这个evdev_handler里面有个列表,记录了可以支持的硬件设备。因为这里的handler是个软件的概念,写的是通用的函数,最后要转化的还是具体各种不同的硬件,比如有很多的鼠标,很多的键盘,这里提供一个通用的接口,开发人员要用一种新的鼠标,只要自己把硬件相关的模块写好就行。所以这个evdev_handler可能会支持很多硬件,要找到他跟硬件之间的联系。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
反过来看input.c中有注册input_handler跟注册输入设备的两个过程。
**********************************************************************************************
注册input_handler:
input_register_handler
    // 放入数组
    input_table[handler->minor >> 5] = handler;
    // 放入链表
    list_add_tail(&handler->node, &input_handler_list);
    // 对于每个input_dev,调用input_attach_handler
    list_for_each_entry(dev, &input_dev_list, node)
        input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev

**********************************************************************************************
注册输入设备:
input_register_device
    // 放入链表
    list_add_tail(&dev->node, &input_dev_list);
              // 对于每一个input_handler,都调用input_attach_handler
    list_for_each_entry(handler, &input_handler_list, node)
        input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev
**********************************************************************************************
两边是个对称的过程。
注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
如果能支持,则调用input_handler的connect函数建立"连接
注意这里的每一种类型的设备只有一个input_handler的结构,而device的结构有很多钟,那我们的目标就要去建立这些device.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

看下dev 跟 handler两者怎么样建立连接:
struct input_handle handle;  
input_handle结构是个核心的结构体,在每个设备中都建立了这个结构体,这个结构体是在input.h中定义的,这样被很多文件调用比如evdev,里面建立了自己的input_handle结构。这个结构体里面又定义了两种结构

struct input_dev *dev;
struct input_handler *handler;

这样就把dev 跟handler进行了关联(通过h_list 进行关联)。
这样搞清楚了之间的联系,evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c等文件,已经写好了,里面是软件的操作代码,具体操作会用到dev设备的代码,我们写驱动,主要就是写这些设备的驱动,然后将这些设备驱动进行注册跟evdev等进行关联就行。最后上层调用读写等函数,实际上是调用evdev等里面的读写函数,进而通过h_list 找到对应的dev函数进行操作
TQ-lkp 发表于 2012-2-19 09:29:51 | 显示全部楼层
本帖最后由 TQ-lkp 于 2012-2-19 09:30 编辑

感谢楼主分享不知道有没有做好的可以参考下
cestlavie007 发表于 2013-1-30 00:03:02 | 显示全部楼层
好贴,该顶!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-4-28 02:54 , Processed in 1.062507 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表