linux驱动学习之Input输入子系统
以前,看过国嵌关于input子系统的视频课程,说实话,我看完后脑子里很乱,给我的印象好像是input子系统驱动是一个全新的驱动架构,疑惑相当多。前几天在网上,看到有很多人介绍韦东山老师的linux驱动课程很不错,于是,我就买了第二期的视频,看了韦老师讲解的input子系统视频课程后,我完全明白了整个input子系统的工作机制。为了方便以后查阅,对input子系统的整体框架总结如下:
典型的输入设备(如键盘、鼠标)的工作机制都是差不多的,都是在设备有动作时,向CPU产生一个中断,通知它读取相应的数据。Linux为了方便开发这一类驱动,它实现了这类驱动的通用部分,只留下与设备相关的部分,这样使得开发这一类驱动更加方便。
在Linux中,Input子系统由三大部分组成,它们是Input子系统核心层、Input子系统事件处理层和Input子系统设备驱动层。在通常情况下,Input子系统核心层和Input子系统事件处理层都已经实现了,而作为驱动开发者,我们仅仅只需要完成Input子系统设备驱动层。
对于一个完整的驱动程序,我们首先需要确定设备的主设备号,次设备号,然后向系统注册该设备,最后实现file_operations结构体中的函数。在Input子系统中,这些步骤会分布到不同的层中,最后三个层通过一些联系构成了一个完整的驱动程序。
在input子系统中有三个比较中要的结构体,它们分别是input_handler结构体、input_dev结构体、input_handle结构体。它们的具体代码如下:
struct input_handler {
void *private; //driver相关数据
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); //input_event函数会调用此函数
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
const struct file_operations *fops; //file_operation结构体,会替换input.c里的file_operation结构体
int minor;
const char *name; //input_handler名称
const struct input_device_id *id_table;
const struct input_device_id *blacklist;
struct list_head h_list; //与该handler相关的handle
struct list_head node;
};
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
int absres[ABS_MAX + 1];
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 *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list; //与该input_dev相关的handle
struct list_head node;
};
struct input_handle {
void *private;
int open;
const char *name;
struct input_dev *dev; //指向input_dev
struct input_handler *handler; //指向input_handler
struct list_head d_node;
struct list_head h_node;
};
在Input.c(drivers/input)的input_init函数中,有:
err=register_chrdev(INPUT_MAJOR, "input", &input_fops)
它向系统中注册了一个主设备号为INPUT_MAJOR(13),名为input的设备。而它的file_operations结构体,如下所示:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
它仅仅实现了open函数,为没有实现其他函数。其实其他函数会在其open函数中实现。
在input_open_file函数中,会把Input子系统的事件处理层相关结构体handler的file_operations赋值给input_fops,从而完整的实现了file_operations结构体。具体实现的代码:
new_fops = fops_get(handler->fops)
file->f_op = new_fops;
从这里我们可以看出一个Input子系统的驱动的file_operations结构体是在handler结构体中实现的。
对于input_handler结构体,它是input子系统中事件处理层相关的结构体,对于一个具体的事件处理,需要向事件处理层注册这样一个结构体,如在鼠标的事件处理程序mousedev.c的mousedev_init函数中,会调用input_register_handler函数,注册一个具体的handler。而在input_register_handler函数中,会将handler添加到input_handler_list中,然后在input_dev_list中寻找相匹配的dev。具体代码:
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
因而,要形成一个完成的驱动,则必须有相应的dev。
对于input_dev结构体,它是input子系统中设备驱动层相关的结构体,对于一个具体的设备,需要向设备驱动层注册这样一个结构体,如在鼠标的设备驱动程序usbmouse.c的usb_mouse_probe函数中,会调用input_register_device函数,注册一个具体的dev。而在input_register_device函数中,会将dev添加到input_dev_list中,然后再input_handler_list寻找相匹配的handler。具体代码:
list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
在input_attach_handler函数中,会调用input_match_device函数,将input_dev_list中的dev与handler相匹配或将input_handler_list中的handler与dev相匹配,匹配成功后就会调用handler中的connect函数。而在connect函数中,会通过handle结构体将匹配好的handler和dev联系起来。如mousedev.c中,connect函数中调用了mousedev_create函数,而在mousedev_create函数中,将handle结构中的handler指向匹配好的handler,而dev指向匹配好的dev,然后会调用input_register_handle函数。
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev);
error = input_register_handle(&mousedev->handle);
在 input_register_handle函数中,将input_handle结构体中的d_node和h_node成员分别添加到了匹配好的dev结构体的h_list中和匹配好的handler结构体的h_list中。
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
list_add_tail_rcu(&handle->d_node, &dev->h_list);
list_add_tail(&handle->h_node, &handler->h_list);
这样,Input驱动程序中的设备驱动和事件处理就这样无缝连接起来了,无论是我们先有了handler还是先有了dev,input子系统都会找了与之匹配的dev或handler,使得三部分之间更加整体化。
linux驱动学习之Input输入子系统的更多相关文章
- linux-2.6内核驱动学习——jz2440之输入子系统
如果按照上一篇记录的那样,只有本公司的人或者自己才能使用驱动.想写出一个通用的驱动程序,让其他应用程序来无缝移植,需要使用现成的驱动——输入子系统. /drivers/input/input.c #d ...
- 嵌入式Linux驱动学习之路(十六)输入子系统
以前写的一些输入设备的驱动都是采用字符设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以实现一种机制,可以对分散的.不同类别的输入设备进行统一的驱动,所以 ...
- ARM Linux内核Input输入子系统浅解
--以触摸屏驱动为例 第一章.了解linux input子系统 Linux输入设备总类繁杂,常见的包括有按键.键盘.触摸屏.鼠标.摇杆等等,他们本身就是字符设备,而linux内核将这些 ...
- linux input输入子系统分析《四》:input子系统整体流程全面分析
1 input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...
- input输入子系统
一.什么是input输入子系统? 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型.不同原理.不同的输入信 ...
- INPUT输入子系统【转】
转自:https://www.cnblogs.com/deng-tao/p/6094049.html 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等 ...
- INPUT输入子系统——按键
一.什么是input输入子系统? 1.1. Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型.不同原理.不同的 ...
- linux 驱动学习笔记01--Linux 内核的编译
由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...
- linux驱动学习(二) Makefile高级【转】
转自:http://blog.csdn.net/ghostyu/article/details/6866863 版权声明:本文为博主原创文章,未经博主允许不得转载. 在我前一篇写的[ linux驱动学 ...
随机推荐
- mysql将字符转换成数字
在操作mysql时,经常需要将字符转换成数字,这一步虽然简单,但不常用的话也很容易忘记,现将在网上找到的方法记录如下: 1.将字符的数字转成数字,比如'0'转成0可以直接用加法来实现例如:将pony表 ...
- LINQ学习入门教程(一)
LINQ 查询简介 Linq 是一跨各种数据源和数据格式的数据模型:它在查询是,始终是把它作为一种对象来操作,可以使用基本相同的编码模型查询和数据的转换XML,SQL,ADO数据等: Li ...
- [转]session缓存机制和三种对象状态
摘自 http://blog.csdn.net/csh624366188/article/details/7612142 Hibernate 的Session就是其中的一个,它提供了基本的增,删,改, ...
- 【linux】linux如何进入单人维护模式修改root密码
- PHP中使用CURL实现get和post请求(总结)
一.什么是curl curl是利用url语法在命令行方式下工作的开源文件传输工具. 二.PHP curl函数
- Android手机平板两不误,使用Fragment实现兼容手机和平板的程序
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8744943 记得我之前参与开发过一个华为的项目,要求程序可以支持好几种终端设备,其 ...
- 【Spring学习笔记-0】Spring开发所需要的核心jar包
spring开发所需要的核心jar 1. libs目录下的核心jar包: 2. common-logging-xxx.jar 来自为知笔记(Wiz) 附件列表
- Learning Puppet — Resource Ordering
Learning Puppet — Resource Ordering Learn about dependencies and refresh events, manage the relation ...
- C语言每日一题之No.3
几天下来,感慨学习要坚持下来真的是件很难的事,本来说了每天一题,可是毕竟这是个细活,需要用心雕琢,有时候真的不能当天拿下来>_<.虽然说只是一题,却涉及到很多小细节,慢慢的琢磨直至完全摸透 ...
- activiti自定义流程之整合(一):整体环境配置
结合之前所说的自定义流程的思路,分别是后台.前台.整合,之前的内容也分别进行了相关的练习和尝试,现在就该到了最后的整合了,依旧是以实现功能为目的,细节暂且不去管他. 因为我们实际项目后端用的是spri ...