10_6 input输入子系统,流程解析

简单分层

在这里插入图片描述

应用层
内核层
---------------------------
input handler 数据处理层 driver/input/evdev.c1.和用户空间交互,实现fops2.不知道数据怎么得到的,但是可以把数据上传给用户---------------------------
input core层1.维护上面和下面的两个链表2.为上下两层提供接口----------------------------
input device层---driver/input/input.c1.初始化硬件,获取硬件数据2.知道数据是什么样,不知道如何把数据给用户

具体

第一步

注册顺序最开始应该是 input_coer层,锁定函数 input/input.c
核心层,得创建链表把,图中的两个链表,方便进行匹配
class_register() //注册这个输入子系统类,同时这个类的主设备号都分配为13
同时这里两个链表
第一个是 input_handler_list 存放结构体 input_handler 可以理解是对这个输入dev的操作实例或方案
第二个是 input_dev_list 这么多输入设备,需要放进来和第一个链表进行匹配

1.input_coer应该是第一个核心层,得创建链表把,看看input_.c文件
同时input.c中还注册了主设备号为13的类和fopsinput_init(void)class_register(&input_class);err = input_proc_init();//感觉像bus总线的新玩法,注册bus总线上的input子系统proc_bus_input_dir = proc_mkdir("bus/input", NULL);entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);//应该是bus总线里面的注册device文件夹static const struct file_operations input_devices_fileops = { //对这个文件夹里面的文件增加fops.owner		= THIS_MODULE,.open		= input_proc_devices_open,.poll		= input_proc_devices_poll,.read		= seq_read,.llseek		= seq_lseek,.release	= seq_release,};entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops);//应该是bus总线里面的注册handlers文件夹err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES, "input");//这里的主设备号是13
static LIST_HEAD(input_dev_list); //全局static 初始化链表
static LIST_HEAD(input_handler_list);//全局static 初始化链表
第二步

input handler 数据处理层
input/evdev.c

为了构建input_handler 先看看handler结构体里面有些什么
里面有主次设备号,还有fops操作参数,看起来就是能创建设备节点的 这里的主设备号 同时次设备号还是64
64那就是/dev/input/event 开始的次设备号

//如果看struct input_handler 有下面这些成员 和/dev/input/event 13 64 里面次设备一致
struct input_handler(void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);file_operation *fops = evdev_opsint minor; =EVDEV_MINOR_BASE 64.connect	= evdev_connect,.event		= evdev_event,}
上面构造号后 就注册到 input_hadle_list 链表中
input_handler层中 叫数据处理者  注册进core层的链表 就是看看哪些数据能被处理假如上面的handler和下面的input_dev匹配成功 就直接调用 handler中的connect()方法
connect()方法会做以下事情,1 创建设备节点 如/dev/event0 主次设备编号13 64	
2 创建创建input_dev对象  1.input_dev里面有event clinet(描述的缓冲区对象)  这个缓冲区是个队列 每个队列都是struct input_dev结构体2.input_dev里面有handle 对象 里面放了handler指针和dev指针  我也画了图了  所以说 evdev对象就能有handle 就能找到input_dev* 和event_hadle*connect完就等下一层上报数据了
好开始读代码 一步一步来
static int __init evdev_init(void) //驱动程序的函数,自动注册return input_register_handler(&evdev_handler);//注册了一个 evdev_handler结构体static struct input_handler evdev_handler = {.event		= evdev_event,.events		= evdev_events,.connect	= evdev_connect,
第三步

input_coer层
上面第二步调用了input_register_handler()函数
这个函数其实在 input_coer层 为了把上面的 evdev_handler 注册进链表

struct input_dev *dev;
input_register_handler(struct input_handler *handler) //就是我们的handlerlist_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler);//遍历链表,就是把core层两个链表进行匹配id = input_match_device(handler, dev);//根据id进行匹配error = handler->connect(handler, dev, id); //这里调用了 handler的connect函数
第四步

input handler 数据处理层
input/evdev.c
匹配成功后,注册进入链表的 evdev_handler结构体的.connect函数被调用
好的又回去 input handler 层了
重点看图中 这里调用了connect函数后
1.生成了 对象 evdev
2.创建设备节点 /dev/input/event0
先说第一点生成了 对象 evdev

生成了 对象 evdev
这个evdev对象 里面会有两个对象 evdedv_client 和 input_handle 注意这个地方是handle

input_handler evdev_handler.connect	= evdev_connect,
evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//初始化evdev结构体INIT_LIST_HEAD(&evdev->client_list); //初始化里面的client_list ,也就是后面说的bufinit_waitqueue_head(&evdev->wait); //初始化里面的等待队列//下面是初始化evdev的handle 也就是用 handle 连接了handler层和input device层evdev->handle.dev = input_get_device(dev);evdev->handle.name = dev_name(&evdev->dev);evdev->handle.handler = handler; //handle的作用是能指向handlerevdev->handle.private = evdev; //handle的作用是能指向evdev//注册这个handleinput_register_handle(&evdev->handle);
第五步

input handler 数据处理层
input/evdev.c
上面的connect的第二点还没说完
2.创建设备节点 /dev/input/event0

input_handler evdev_handler.connect	= evdev_connect,
evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);//查找次设备号看哪个能用//注意这里的dev是device  就是字符设备哪个device//创建设备节点,之前我们都是用device_create(),其实就是做了下面的事情dev_set_name(&evdev->dev, "event%d", dev_no);evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);//这里主设备号13 次设备号从65开始evdev->dev.class = &input_class;evdev->dev.parent = &dev->dev;evdev->dev.release = evdev_free;device_initialize(&evdev->dev);device_add(&evdev->dev)cdev_init(&evdev->cdev, &evdev_fops);  //cdev的fops在这里cdev_device_add(&evdev->cdev, &evdev->dev);
note:以前用device_create()创建设备节点
device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)//这个函数要的参数上面竟然都有device_create_vargs(class, parent, devt, drvdata, fmt, vargs);device_initialize(dev);dev = kzalloc(sizeof(*dev), GFP_KERNEL);dev->devt = devt;dev->class = class;dev->parent = parent;dev->groups = groups;dev->release = device_create_release;device_add(dev);//所以知道了 上面就是在创建设备节点		

做完那不就/dev/input/event0 就出来了

第六步

device层
注册自己写的函数

module_init(simple_btn_input_init);
static int __init simple_btn_input_init(void)//a, 分配一个input device对象btn_input = input_allocate_device();//b, 初始化input device对象//该设备能够产生哪种数据类型---EV_KEY表示产生按键数据btn_input->evbit[0] |= BIT_MASK(EV_KEY);//能够产生哪个按键---比如能够产生下键 KEY_DOWN, KEY_ESC// btn_input->keybit[108/32] |= 1<<(108%32);btn_input->keybit[BIT_WORD(KEY_DOWN)] |= BIT_MASK(KEY_DOWN);//c, 注册input device对象ret = input_register_device(btn_input);//这个函数里面最后也是调用了handler->connect(handler, dev, id);//匹配成功就是handle的connect方法,也就是 evdev_connect()

note: 可能这里要问了,有没有和palntfrom一样的匹配规则呢 啥设备树匹配 name匹配的
我们看到handler层的注册的结构体 input_handler evdev_handler
evdev_handler.id_table =evdev_ids
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices / //这里的意思是匹配所有设备,来了就匹配,我不要规则
{ }, /
Terminating zero entry */
};
那为啥还有个idtable 拿来匹配呢
是因为我们用的是公共驱动,所有都匹配 但是有其他的handler驱动,需要用支持哪些输入事件和键值对 来看是否能匹配这个设备了
举个例子在input_hadler这一层 我们看的是evdev.c这个万能驱动 起始还有mousedevhandler mousedev.c鼠标handler 和joydey_handle游戏杆的handler
所以鼠标设备会和 evdev.c匹配 也会和鼠标handler匹配 所以鼠标插入的时候 有个/dev/input/event0 和 /dev/input/mouse0
起始两个是同一个设备 所以用哪个都可以

第7步

应用程序调用open()
到vfsopen 根据设备号找到cdev
到驱动的open函数
我们之前是在core层 申请的设备号 所以找到了 input.c的代码 这个地方也要回顾为啥是到这里!!!
有可能推理错了,应该是open直接调用evdev的open,需要回去看cdev那节
因为这里又register_chrdev_region()
err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
INPUT_MAX_CHAR_DEVICES, “input”);
在input_open函数中 找到input_hadle 那么也能找到input_hadler层的fops
register_chrdev(Input_major,“input”,&input_fops)
input_fops.open()
new_fops = fops_get(hadler->fops)
//把文件节点的fop全改成了 handler层的fop了
file_fop = new_file

第八步

input handler 数据处理层
input/evdev.c
上一步找到了 input handler的open()

//当时的fop是这样注册的evdev_connect() //造connect注册了fopcdev_init(&evdev->cdev, &evdev_fops);evdev_fops.open = evdev_open() //open函数这里 初始化client struct evdev_client *client;client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);client->bufsize = bufsize;client->evdev = evdev;evdev_attach_client(evdev, client);//把文件节点的fop全改成了  handler层的fop了file_fop = new_file //使用file节点私有空间传输数据,那read,write都能拿到了clientevdev_open_device() //查看第三层 input_dev xx层有没有open函数,有的话继续调用  但这里没有
第九步

app开始read
vfs_erad
到evdev.c 开始进行evdev_read 也就是调用到evdev_read()
从之前的client中 拿取最新的上报数据 返回给用户层

evdev_read()evdev_client *client = file->private_data;//从fd文件的私有属性拿到clientevdev *evdev = client->evdev; //从clinet拿到evdevstruct input_event event;//构造一个要返换给用户空间的结构体 input_eventif (client->packet_head == client->tail &&(file->f_flags & O_NONBLOCK))//如果当前用非阻塞的方式,还没有数据,那应该马上返回return -EAGAIN;if (!(file->f_flags & O_NONBLOCK)) //正常的阻塞形式error = wait_event_interruptible(evdev->wait,client->packet_head != client->tail ||!evdev->exist || client->revoked);//这个进程丢进等待队列把,等中断唤醒继续往下走//下面是有中断了,阻塞解除,进程继续往下走//下面的进行用户空间数据发送while()evdev_fetch_next_event(client, &event)*event = client->buffer[client->tail++];//这里构造input_event,也就是从client里面拿一个bufferinput_event_to_user(buffer + read, &event)copy_to_user(buffer, event, sizeof(struct input_event)//拿了buffer后给到用户空间
第十步

那么中断是谁发起的
就到了我们写的程序 input_device 层

//按下
input_event(btn_input, EV_KEY, KEY_DOWN,  1);
input_sync(btn_input);  //我们的中断函数执行上报数据INPUT.C  //跑到中间层进行数据封装input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)input_pass_values(dev, dev->vals, dev->num_vals);struct input_handle *handle; struct input_value *v;handle = rcu_dereference(dev->grab);//从dev中拿到handlelist_for_each_entry_rcu(handle, &dev->h_list, d_node)//这个也是想办法拿到handlehandle_event(handle,type,code,value)
第十一步

input handler 数据处理层
input/evdev.c
第11步,就把中断传输来的 evdev_event数据放入了 event_client队列里面
就等着 app被唤醒后来拿数据就行了

调用到 input_handler evdev_handler->event = evdev_eventstruct evdev *evdev = handle->private; //通过private找到evdevstruct evdev_client *client;list_for_each_entry_rcu(client, &evdev->client_list, node)//也找到clinet

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/152026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面试经典150 | 数学】回文数

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;反转一半数字 其他语言python3 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本…

StoneDB顺利通过中科院软件所 2023 开源之夏 结项审核

近日&#xff0c;中科院软件所-开源软件供应链点亮计划-开源之夏2023的结项名单正式出炉&#xff0c;经过三个月的项目开发和一个多月的严格审核&#xff0c;共产生 418个成功结项项目&#xff01;其中&#xff0c;StoneDB 作为本次参与开源社区&#xff0c;社区入选的两个项目…

单片非晶磁性测量系统磁参量指标

1. 概述 单片非晶磁性测量系统是专用于测量非晶或纳米晶薄片(带)交流磁特性的装置&#xff0c;由精密励磁及测量装置 ( 40 Hz&#xff5e;65 Hz&#xff0c;可定制至400 Hz )、单片磁导计、全自动测量软件组成。使用该装置可在能耗、效率、材料均匀性/一致性、可靠性、整个生命…

CSS的选择器(一篇文章齐全)

目录 Day26&#xff1a;CSS的选择器 1、CSS的引入方式 2、CSS的选择器 2.1 基本选择器​编辑 2.2 组合选择器 2.3 属性选择器 2.4 伪类选择器 2.5 样式继承 2.6 选择器优先级 3、CSS的属性操作 3.1 文本属性 3.2 背景属性 3.3 边框属性 3.4 列表属性 3.5 dispal…

【10套模拟】【7】

关键字&#xff1a; 二叉排序树插入一定是叶子、单链表简单选择排序、子串匹配、层次遍历

力扣刷题-二叉树-二叉树的高度与深度

二叉树最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 递归法 本题可以使用前序&#xff08;中左…

Sql Server 2017主从配置之:事务日志传送

使用事务日志传送模式搭建Sql Server 2017主从同步&#xff0c;该模式有一定的延迟&#xff0c;是通过3个不同的定时任务&#xff0c;将主库的日志同步到从库进行恢复来实现数据库同步操作。 该模式在同步时候&#xff0c;从库不可以被使用&#xff0c;否则同步就会失败。 环…

现货白银MACD实战分析例子

MACD这个技术指标的全称是平滑异同移动平均线&#xff0c;主要表示经过平滑处理后均线的差异程度&#xff0c;一般用来研判现货白银价格变化的方向、强度和趋势。MT4中的MACD指标&#xff0c;主要是由信号线、&#xff08;上升/下跌&#xff09;动能柱、0轴这三部分组成。 MACD…

【开源】基于Vue.js的衣物搭配系统的设计和实现

项目编号&#xff1a; S 016 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S016&#xff0c;文末获取源码。} 项目编号&#xff1a;S016&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 衣物档案模块2.2 衣物搭配模块2.3 衣…

MyBatis查询数据库(全是精髓)

1. 什么是MyBatis&#xff1f; 简单说&#xff0c;MyBatis就是一个完成程序与数据库交互的工具&#xff0c;也就是更简单的操作和读取数据库的工具。 2. 怎么学习Mybatis Mybatis学习只分为两部分&#xff1a; 配置MyBatis开发环境使用MyBatis模式和语法操作数据库 3. 第一…

2023年(第六届)电力机器人应用与创新发展论坛-核心PPT资料下载

一、峰会简介 大会以“聚焦电力机器人创新、助力行业数字化转型、促进产业链协同发展”为主题&#xff0c;展示电力机器人产业全景创新技术&#xff0c;探讨数字化战略下电力机器人应用前景和发展趋势。为加快推进电力机器人应用拓新&#xff0c;助力电网数字化转型升级&#…

彻底弄清Python软件包安装流程并解决安装错误

彻底弄清Python软件包安装流程并解决安装错误 前言&#xff1a;写这篇文章的初衷也是因为以前饱受Python环境配置和软件包安装的摧残&#xff0c;所以写下这篇文章希望帮助同样深陷泥潭的小伙伴们&#xff0c;该文会带你理解关于安装软件包的流程。&#xff08;tips&#xff1…

数据集笔记:NGSIM (next generation simulation)

1 数据集介绍 数据介绍s Next Generation Simulation (NGSIM) Open Data (transportation.gov) 数据地址&#xff1a;Next Generation Simulation (NGSIM) Vehicle Trajectories and Supporting Data | Department of Transportation - Data Portal 时间2005年到2006年间地…

七天.NET 8操作SQLite入门到实战 - SQLite 简介

什么是SQLite&#xff1f; SQLite是一个轻量级的嵌入式关系型数据库&#xff0c;它以一个小型的C语言库的形式存在。它的设计目标是嵌入式的&#xff0c;而且已经在很多嵌入式产品中使用了它&#xff0c;它占用资源非常的低&#xff0c;在嵌入式设备中&#xff0c;可能只需要几…

第四代智能井盖传感器,实时守护井盖位安全

城市管理中井盖的安全问题始终是一个不容忽视的方面。传统的巡检方式不仅效率低下&#xff0c;无法实现实时监测&#xff0c;而且很难准确掌握井盖的异动状态。因此智能井盖传感器的应用具有重要意义。这种智能传感器可以帮助政府实时掌握井盖的状态&#xff0c;一旦发现异常情…

企业计算机服务器中了mallox勒索病毒怎么解决,勒索病毒解密文件恢复

随着科技技术的不断发展&#xff0c;网络技术得到了快速提升&#xff0c;但网络安全威胁也不断增加&#xff0c;近期&#xff0c;云天数据恢复中心陆续接到很多企业的求助信息&#xff0c;企业的计算机服务器遭到了mallox勒索病毒攻击&#xff0c;导致企业的所有业务中断&#…

MatLab的下载、安装与使用(亲测有效)

1、概述 MatLab是由MathWorks公司开发并发布的&#xff0c;支持线性代数、矩阵运算、绘制函数和数据、信号处理、图像处理以及视频处理等功能。广泛用于算法开发、数据可视化、数据分析以及数值计算等。 Matlab 的主要特性包括&#xff1a; 简单易用的语法&#xff0c;使得程…

PC 477B西门子触摸屏维修6AV7853-0AE20-1AA0

西门子触摸屏维修故障有&#xff1a;上电黑屏, 花屏,暗屏,触摸失灵,按键损坏,电源板,高压板故障,液晶,主板坏等,内容错乱、进不了系统界面、无背光、背光暗、有背光无字符&#xff0c;上电无任何显示 &#xff0c;Power灯不亮但其他一切正常&#xff0c;双串口无法通讯 &#x…

车辆限迁查询API——查询您的车辆是否限制迁入迁出

随着城市的快速发展和人们生活水平的提高&#xff0c;车辆的使用量也不断增加。而随之而来的问题也愈发突出&#xff0c;其中之一就是车辆的限迁问题。 比如&#xff0c;在一些大城市&#xff0c;为了减少交通拥堵和空气污染&#xff0c;政府采取了限制车辆迁入迁出的措施&…

智能配电箱柜管理系统

智能配电箱柜管理系统是一个综合性的管理系统&#xff0c;专门设计用于监控和控制智能配电箱和柜的运行。这个系统集成了先进的技术和智能化功能&#xff0c;以确保配电系统的正常运行并提高其效率。依托电易云-智慧电力物联网&#xff0c;以下是智能配电箱柜管理系统的主要特点…