输入子系统框架之我见

输入子系统是linux驱动中很重要的一部分,按键、触摸屏、鼠标等等的驱动都可以通过这个框架来构建,下面就来总结下输入子系统的框架。

核心层主要在input.c文件中,

 class_register(&input_class); 

register_chrdev(INPUT_MAJOR, "input", &input_fops);

先注册个类,类下创建设备,设备号为13,操作函数为input_fops。


static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
}

操作函数里面只有一个open函数,open可以得到inode、file结构体。由inode可以得到次设备号,

input_handler   *handler = input_table[iminor(inode) >> 5];

input_table中根据次设备号存放有输入设备的input_handler结构体,里面包含有真正的操作函数,然后存放于file中:

file->f_op = new_fops;

这就是大致流程,就是input.c中转站完成的任务。


下面做进一步的分析,主要是input_handler和input_dev两个部分的连接:

以evdev.c来说明input_handler:

在evdev.c中,先构造input_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_table中去:

input_register_handler(&evdev_handler);

---->>> input_table[handler->minor >> 5] = handler;

再构造input_dev结构体,里面包含了支持的事件类型等,然后注册设备:input_register_device(&input_dev),里面具体完成什么工作暂且先不分析。


来总起来看一下这两个注册,在input_dev和input_handler结构体中,都有两个双向链表,这是内核负责管理的,我们可以不用去理它,但是深入理解这几个链表,对输入子系统各个模块之间的关系会更加清晰。

注册input_handler时,在input_register_handler的最后有:

list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);

首先把input_handler结构体里的node放到input_handler_list中,构成了一个input_handler链表。然后对input_dev_list(这个链表在注册input_dev时会构造)中的每一项,都调用 input_attach_handler(dev, handler);就是把handler和dev看看是否匹配,就是说比较handler能否处理dev。


再看看注册input_dev时,在input_register_device的最后也有:

list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);

input_dev中也有两个双向链表,其一为node,把node放入input_dev_list中,就构造出了input_dev链表,然后对input_handler链表中的每一项调用input_attach_handler(dev, handler);看看input_handler是否支持input_dev。

由以上分析可知,无论是先注册input_dev还是input_handler,都会先把他们放入到设备链表、处理链表中去,注册一个input_dev时,就对input_handler链表中的每一项handler比较,看是否支持。当注册input_handler时,就会对input_dev链表中每一项比较,看是否可以支持。


当判断匹配时,比较input_handler的id_table和dev,当匹配时,就会调用input_handler的connect函数,在evdev.c中,connect函数构造了input_handle结构体,里面的handler指向input_handler,dev指向input_dev,input_handle里面也有两个链表,把它们分别放入input_dev和input_handler结构体的另外一个链表中,这样,input_handler、input_dev和input_handle三者就建立了联系。


当应用程序读数据时,如果缓冲区没数据,并且文件是非阻塞的,那么,程序就会睡眠,当硬件设备发生改变,就会上报事件input_event,然后就会调用input_handler的event中的处理函数,就会唤醒应用程序,来完成读操作。


我们在写输入子系统的驱动函数时,只需要构造出input_dev,并且,在中断处理函数中上报事件,就可以完成操作,input_handler系统已经帮我们完成。


以上就是输入子系统的大概框架,说的比较粗浅,待以后逐步完善。


你可能感兴趣的:(框架)