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驱动学 ...
随机推荐
- SharePoint 2010 最佳实践学习总结------第2章 SharePoint Windows PowerShell指南
第2章 SharePoint Windows PowerShell指南 SharePoint 2010是SharePoint系列产品中第一个开始支持Windows PowerShell的产品,在以前的 ...
- mysql中的null字段值的处理及大小写问题
在MySQL中,NULL字段的处理,需要注意,当在处理查询条件中有NULL,很有可能你得到的值不是想要的,因为,在MySQL中,判断NULL值相等(=)或者不等(!=)都会返回false.主要出现在常 ...
- openstack(liberty): 简单网络连接图
openstack起初的网络部分是和计算核心nova合在一起的,后来被拆分出来,独立成为一个模块, 现在名为Neutron. 本博文是学习记录,记录的是基于GRE tunnel技术的neutron和计 ...
- 读书笔记:应用随机过程:概率模型导论:Aloha协议问题
例4.16,Aloha协议:就本书例题所涉及的部分来说,几乎等同于CSMA.这个例题重写如下: 考察一个包含多个设备的通信系统,其中在每个时间段发送信息的设备个数是独立同分布的.......每个设备将 ...
- linux下查看系统进程占用的句柄数
---查看系统默认的最大文件句柄数,系统默认是1024 # ulimit -n 1024 ----查看当前进程打开了多少句柄数 # lsof -n|awk '{print $2}'|sort|uniq ...
- s3c2440存储控制器和地址以及启动的理解
转自:http://blog.sina.com.cn/s/blog_5ddb672b0100fkcf.html 1.首先应该先了解Flash ROM的种类 NOR FLASH地址线和数据线分开,来了地 ...
- 通过共享用户ID来实现多个应用程序使用同一个进程(一些情况的测试)
从很多方面来看,每个Android 应用程序都存在于它自己的世界之中:• 默认情况下,每个应用程序均运行于它自己的Linux 进程中.当应用程序中的任意代码开始执行时,Android 启动一个进程,而 ...
- FLEX 特效
一.简介: flex特效是ria应用程序的rich的重要组成部分. EffectManager类管理所有的特效实例以避免不必要的定时器和方法调用造成的内内存使用过大.一个效果由两部分组成:一是效果的E ...
- 黄聪:C#超级延时方法,延迟系统时间但系统又能同时能执行其它任务
private void Delay(int Millisecond) //延迟系统时间,但系统又能同时能执行其它任务: { DateTime current = DateTime.Now; whil ...
- OkHttp 详解
OkHttp使用: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html OkHttp源码: http:/ ...