Linux驱动之输入子系统(张栖银详谈)

一、input子系统介绍

1.1 系统介绍

本文是基于linux-2.6.32内核进行分析的,如果使用的是其他版本的内核,其内核调用的函数可能有所不同,但是其实现原理是相通的。

1.2 input子系统的引入

以前我们写一些输入设备(键盘、鼠标等)的驱动都是采用字符设备、混杂设备处理的。问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以实现一种机制,可以对分散的、不同类别的输入设备进行统一的驱动,所以才出现了输入子系统。

输入设备(如按键、键盘,触摸屏,鼠标等)是典型的字符设备,其主设备号固定为13,其一般的工作机制是在底层在按键、触摸、鼠标点击等动作发生时产生一个中断(或驱动通过timer定时查询),然后CPU通过SPI、IIC或者外部存储器总线读取键值、坐标等数据,放在一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值、坐标等数据,其过程如图1.1所示。

image
image

在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(input core)和输入子系统事件处理层(Event handler)组成,如图1.2所示。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用户关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。

image
image

1.3 input子系统的优点

输入子系统的引入,也为我们带来了许多的好处:

  • 统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论PS/2、USB、还是蓝牙,都被同样处理。
  • 提供了用于分发输入报告给用户应用程序的简单的事件(event)接口。你的驱动不必创建、管理/dev节点以及相关的访问方法。因此它能够很方便的调用输入API以发送鼠标移动、键盘按键,或触摸事件给用户空间。X windows这样的应用程序能够无缝地运行于输入子系统提供的event接口之上。
  • 抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供了一个底层驱动(称为serio)的集合,支持对串口和键盘控制器等硬件输入的访问。

注:更多详细描述可参见《精通Linux设备驱动程序开发》这本书。

更重要的是,input子系统的引入,使我们在具体的开发中可以在输入硬件设备更换的情况下保持应用不做任何修改

1.4 input子系统与字符设备实现比较

在进行字符设备驱动程序开发的过程中,我们的实现步骤如下:

  • 申请一个字符设备号:可以自己指定,也可系统自动分配;
  • 构造一个file_operations结构体,其包含对设备的所有操作;
  • 实现file_operations结构体中的成员函数;
  • 将字符设备注册进系统中:register_chrdev();
  • 创建设备类和设备节点:class_create()、device_create();
  • 告诉内核入口与出口函数:module_init()、module_exit();

输入子系统与混杂设备驱动一样,也是一个典型的字符设备,那么其注册的过程与字符设备驱动一样,也必须经过上面的这些步骤。只是输入子系统中的输入设备一般只接收输入设备的中断和获取输入设备的数据,而不输出数据到输入设备而已。

在输入子系统中,将字符设备驱动分为了三个部分:与硬件操作相关的设备驱动层(由驱动工程师实现)、输入子系统核心层(input core)和输入子系统事件处理层(Event handler),其中后面两个部分都已经由系统帮我们实现了。其实后面两个部分可以把它看作是一个整体,就是与硬件操作无关的软件部分。那么我们实现input设备驱动的过程为:

  • 申请一个输入设备结构体:input_allocate_device();
  • 设置输入设备支持的事务类型:set_bit(xxx,devp->evbit);
  • 设置输入设备支持的具体哪些事务:set_bit(xxx,devp->xxxbit);
  • 注册输入设备到输入子系统:input_register_device(devp);
  • 实现具体的硬件相关操作,如注册中断等,并在中断处理函数中通知事务已发生:input_event()、input_sync();

也就是说:无论输入子系统多么强大、封装的多么的好,与硬件相关的操作还是得我们亲自实现。

1.5 input子系统与字符设备与应用层数据交互比较

编写过字符设备驱动的人都知道,应用程序与驱动之间实现数据交互就是通过应用API的read()、write()调用,从而产生一个SWI软件中断,然后通过主设备号找到对应的struct cdev结构体实体,从而找到具体硬件设备的struct file_operations结构体,然后具体调用底层的drv_read()、drv_write(),我们就是在具体的drv_read()和drv_write()中实现对硬件的操作的,其过程如下:

read()—>swi_read()—>drv_read()—>硬件操作

那么对应到输入子系统呢?前面已经说了,输入子系统也是字符设备,那么它也必须经历上面的这些步骤,只是中间穿插了几个查找具体输入设备的过程(毕竟将所有的输入设备都加入到输入子系统,就不止一个设备了)而已。那么是如何穿插的呢:

首先在input.c(输入子系统的核心)文件的打开函数中找到具体的input_handler,然后取出具体input_handler中的fops(也即struct file_operations结构体)填充struct file中的f_op成员,那么之后应用调用read()、write()函数就是调用具体input_handler指向的struct file_operations结构体中的成员了;最后再调用fops中的open()函数打开具体的函数:

struct input_handler *handler;
handler = input_table[iminor(inode) >> 5];
old_fops = file->f_op;
file->f_op = new_fops;
err = new_fops->open(inode, file);

这里说明一下:input.c是input子系统的核心,内核已经实现,各种input_handler(包含open、release、read、write、ioctl、fasync、poll等,即硬件处理函数)也由系统抽象出来帮我们实现了,后面会讲解其具体实现过程。

通过前面的介绍,不太理解也没有关系。你只需要记住,其实输入子系统就是一个典型的字符设备,它也逃不过字符设备的框架,其应用与驱动交互的流程也和字符设备驱动一样,没有什么不同就是了(要从心里小瞧它)。

要想搞明白输入子系统的框架,只需要弄明白应用程序是如何与具体的硬件设备驱动进行交互的就行了。而这个过程如下其实就是主设备号13的字符设备、input_handler、input_handle和input_dev几个的关系

  • Linux系统启动时注册输入子系统(注册主设备号为13的字符设备);
  • 应用程序调用open(),对应调用输入子系统的input_open_file();
  • input_open_file()找到对应的input_handler,并调用其中的open();
  • 应用程序调用read()函数,对应调用open()中找到的input_handler中的read()函数,阻塞;
  • 驱动收到硬件访问需求,进入中断处理函数,对应到input_dev;
  • 驱动调用input_event()上报事件,上报过程为:通过input_dev找到input_handle,再通过input_handle找到匹配的input_handler,然后调用该input_handler的event()函数,该函数即是唤醒对应read()、write()函数的实现;

详细过程如下三条线路所示:

  1. open()—>input_open_file()—>input_handler->fops->open()
  2. read()/write()/ioctl()—>input_handler->fops->read()/write()/ioctl()
  3. 硬件—>input_dev的中断处理程序—>input_event()—>input_handle->input_handler->event()

注意:->是指针;—>是下一步调用。

从应用到底层的匹配过程是通过input_handler,具体驱动中是通过静态全局指针数组变量input_table[]实现的;而硬件到应用程序的匹配过程是通过input_handle结构体找到对应的input_handler,从而实现数据传输的,具体到代码就是通过input_handler->connect()函数将input_dev、input_handler和input_handle三者进行绑定的,三者绑定的关系如图1.3所示。


image
image

二、input子系统实现

本章节将详细讲解input子系统的框架,也就是input子系统中如何实现应用层数据与底层硬件之间的数据交互、底层硬件(input_dev)如何与系统实现的驱动(input_handler)关联等

2.1 input子系统框架

正如前面的介绍,input子系统将所有的输入设备统称为像鼠标输入、键盘输入、joydev输入等,将输入的数据封装成统一的事务格式(struct input_event)上传到应用,而将具体的硬件设备分离出来(这才是我们要做的事),如图2.1所示。


image
image

在如上的系统分层结构下,我们的应用程序就可以不用关心获取到的数据是来源于SPI的键盘、还是IIC的键盘,它只需要关心获取到数据的具体含义就行了,这样就保证了更换不同的硬件设备,而不用修改一行应用程序代码,如图2.2所示。

还有 80% 的精彩内容
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
支付 ¥3.99 继续阅读
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容

  • 输入子系统概述 Linux内核为了能够处理各种不同类型的输入设备,比如 触摸屏 ,鼠标 , 键盘 , 操纵杆...
    JalynFang阅读 10,346评论 4 9
  • 大学的时候,帮朋友写的操作系统调研的作业,最近整理过去的文档时候偶然发现,遂作为博客发出来。 从串口驱动到Linu...
    free_will阅读 7,390评论 7 59
  • 本文开启 linux 内核 V4L2 框架部分的学习之旅,本文仅先对 V4L2 的框架做一个综述性的概括介绍,然后...
    yellowmax阅读 7,583评论 0 13
  • 1:InputChannel提供函数创建底层的Pipe对象 2: 1)客户端需要新建窗口 2)new ViewRo...
    自由人是工程师阅读 5,308评论 0 18
  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,490评论 1 11