字符设备驱动之输入子系统分析(三)

发布时间 2023-07-12 17:37:30作者: Bright-Ho~蜗牛~

 

作者:Bright-Ho

联系方式:836665637@qq.com


input输入子系统之“事件处理层”分析:


注意:我们现在只是涉及输入子系统的框架;具体细节会涉及到硬件的工作原理,在后面我们写驱动的时候会说到细节方面;


这一节,我们接触到了“事件处理层”;事件处理层包含了evdev.c(事件设备)tsdev.c(触摸屏设备)keyborad.c(键盘设备),以及mousedev.c(鼠标设备)等;

我们选取evdev.c(事件设备)内核源代码进行分析;该代码位于:drivers/input中;


上一节,我们说到,input_handler这个结构体就是在evdev.c这个事件处理文件中构造出来的;接下来,我们就继续分析“事件处理层”的代码;分析事件设备evdev.c的代码;


1)入口函数evdev_init();

static int __init evdev_init(void)

{

return input_register_handler(&evdev_handler);

}


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,

};


里面直接调用input_register_handler(&evdev_handler);该函数是“核心层”提供的;

前面一节我们大概分析了该函数;这里最重要的是evdev_handler结构体;之前分析核心层的代码时候,一直都有evdev_handler这个结构体的出现,我们一直在寻找该结构的源头,现在我们清楚了,该结构体在“事件处理层”实现的;那么现在我们来分析input_handler结构体的成员;

evdev_connect函数:当devhandler匹配成功后,就会调用该函数建立“连接”,怎么建立连接呢?对于每个不同的handler都有不同的连接方式,也就是不同的设备,有不同的连接方式。后面具体讲到设备驱动的时候,会讲到如何连接;

evdev_fops结构:该结构很重要,这个结构就是最终提供给应用层的调用接口,open,read,write,等;

evdev_ids:就是id号,用来匹配硬件设备和事件处理的;一旦匹配成功,就会调用connect函数建立“连接”;

EVDEV_MINOR_BASE:次设备号;

"evdev":名字;


那么这里重点看一下evdev_fops结构,也就是file_operations结构;我们自己写字符设备驱动的时候,就是自己构造这个结构,然后,通过register_chadev()函数来注册;那么引入“输入子系统”后,这个file_operations结构,就是由具体的“事件处理层”来实现;

不用我们自己手动实现!

609 static const struct file_operations evdev_fops = {

610 .owner = THIS_MODULE,

611 .read = evdev_read,

612 .write = evdev_write,

613 .poll = evdev_poll,

614 .open = evdev_open,

615 .release = evdev_release,

616 .unlocked_ioctl = evdev_ioctl,

617 #ifdef CONFIG_COMPAT

618 .compat_ioctl = evdev_ioctl_compat,

619 #endif

620 .fasync = evdev_fasync,

621 .flush = evdev_flush

622 };


应用程序open,read,write一个设备文件,就会调用到“事件处理层”里面提供的接口,这里就暂时不讲各个接口里面具体怎么实现的,等到讲到具体的硬件设备的时候,再来讲解;这里重点是讲解输入子系统的框架!!!


总结:“事件处理层”做了哪些事情?

1)构造一个input_handler结构体,该结构体包含了,事件上报函数 evdev_event;设备和事件处理的连接函数evdev_connectid号:evdev_ids用于匹配设备和事件处理;evdev_fops结构:驱动接口;

2)调用核心层提供的注册函数input_register_handler(&evdev_handler);

该函数把input_handler结构体:

先放入一个input_table[]数组;

然后再把该结构体放入input_handler_list的链表;

把设备链表里面的每一项设备取出来和input_handler进行匹配,一旦匹配成功就调用input_handler结构里面的connect连接函数,把设备和事件连接在一起;当应用程序open,read,write,设备接口的时候就会调用“事件处理层”里面提供的file_operations里的面的驱动接口来处理具体的硬件设备;


下一节我们继续讲解设备驱动层的东西;