RK3568驱动指南|第十三篇 输入子系统-第150章 通用事件处理层event函数分析

本文主要是介绍RK3568驱动指南|第十三篇 输入子系统-第150章 通用事件处理层event函数分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第十三篇 输入子系统_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第150章 通用事件处理层event函数分析

接下来,我们将继续学习event和events函数,如下图所示:

evdev_events函数如下所示:

static void evdev_events(struct input_ handle *handle, const struct input_value *vals, unsigned int count)
{struct evdev *evdev = handle->private;  // 获取输入句柄的私有数据,这里假设是evdev结构体类型struct evdev_client *client;  // 定义evdev客户端指针ktime_t *ev_time = input_get_timestamp(handle->dev);  // 获取输入设备的时间戳rcu_read_lock();  // 开始读取RCU保护区域client = rcu_dereference(evdev->grab);  // RCU安全地获取当前的evdev客户端if (client)evdev_pass_values(client, vals, count, ev_time);  // 如果存在抢占的客户端,则将值传递给抢占的客户端elselist_for_each_entry_rcu(client, &evdev->client_list, node)evdev_pass_values(client, vals, count, ev_time);  // 否则,将值传递给所有注册的客户端rcu_read_unlock();  // 结束读取RCU保护区域
}

该函数用于处理输入设备的事件。它接受一个输入句柄、一个输入值数组以及值的数量作为参数。

首先,它从输入句柄的私有数据中获取一个指向evdev结构体的指针。

然后,它获取输入设备的时间戳。

接下来,它通过使用RCU(Read-Copy-Update)机制来保护数据访问。通过调用rcu_read_lock()函数,它开始读取RCU保护区域。

然后,它通过RCU安全地获取当前的evdev客户端。如果存在抢占的客户端(即非空),它将调用evdev_pass_values函数将值传递给抢占的客户端。否则,它使用list_for_each_entry_rcu宏遍历evdev->client_list链表中的每个客户端,并调用evdev_pass_values函数将值传递给每个注册的客户端。

最后,它通过调用rcu_read_unlock()函数结束对RCU保护区域的读取操作。

我们学习一下evdev_pass_values函数,如下所示:

static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t *ev_time)
{struct evdev *evdev = client->evdev;  // 获取evdev客户端所属的evdev结构体const struct input_value *v;  // 当前处理的输入值struct input_event event;  // 输入事件结构体struct timespec64 ts;  // 时间戳bool wakeup = false;  // 是否需要唤醒等待线程if (client->revoked)return;  // 如果客户端已被撤销,则直接返回ts = ktime_to_timespec64(ev_time[client->clk_type]);  // 将ev_time转换为struct timespec64类型的时间戳event.input_event_sec = ts.tv_sec;  // 输入事件的秒字段设置为时间戳的秒值event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;  // 输入事件的微秒字段设置为时间戳的纳秒值除以1000得到的值/* 关中断,只需获取锁即可。 */spin_lock(&client->buffer_lock);  // 获取客户端的缓冲区锁for (v = vals; v != vals + count; v++) {if (__evdev_is_filtered(client, v->type, v->code))continue;  // 如果输入值被过滤,则跳过当前值的处理if (v->type == EV_SYN && v->code == SYN_REPORT) {/* 丢弃空的SYN_REPORT */if (client->packet_head == client->head)continue;  // 如果客户端的数据包头和数据头相同,则跳过当前值的处理wakeup = true;  // 设置唤醒标志为真}event.type = v->type;  // 设置输入事件的类型字段为当前值的类型event.code = v->code;  // 设置输入事件的代码字段为当前值的代码event.value = v->value;  // 设置输入事件的值字段为当前值的值__pass_event(client, &event);  // 将输入事件传递给客户端的事件处理函数}spin_unlock(&client->buffer_lock);  // 释放客户端的缓冲区锁if (wakeup)wake_up_interruptible(&evdev->wait);  // 如果需要唤醒等待线程,则唤醒等待队列中的线程
}

该函数用于将输入值传递给evdev客户端进行处理。它接受一个evdev_client结构体指针,一个输入值数组以及值的数量作为参数。

首先,它从客户端结构体中获取所属的evdev结构体。

然后,它检查客户端是否已被撤销,如果是,则直接返回。接下来,它将ev_time转换为struct timespec64类型的时间戳,并将其赋值给ts变量。然后,它将时间戳的秒值赋给输入事件结构体的input_event_sec字段,将时间戳的纳秒值除以1000得到的值赋给输入事件结构体的input_event_usec字段。然后,它获取客户端的缓冲区锁,以确保在处理输入值时不会有竞争条件。

接下来,它遍历输入值数组中的每个值。对于每个值,它首先检查是否被客户端过滤。如果被过滤,则跳过当前值的处理。

然后,它检查当前值是否为EV_SYN类型且代码为SYN_REPORT。如果是,它进一步检查客户端的数据包头和数据头是否相同。如果相同,则说明是一个空的SYN_REPORT,可以丢弃。否则,将唤醒标志设置为真。

接下来,它设置输入事件的类型字段为当前值的类型,代码字段为当前值的代码,值字段为当前值的值,并调用__pass_event函数将输入事件传递给客户端的事件处理函数。

完成对所有输入值的处理后,它释放客户端的缓冲区锁,解除对缓冲区的访问限制。

最后,如果需要唤醒等待线程(即唤醒标志为真),则调用wake_up_interruptible函数唤醒等待队列中的线程,以通知它们有新的事件可用。

   __pass_event函数将输入事件传递给客户端的事件处理函数,我们来学习一下。

static void __pass_event(struct evdev_client *client, const struct input_event *event)
{client->buffer[client->head++] = *event;  // 将事件复制到客户端的缓冲区中,然后将缓冲区头指针递增client->head &= client->bufsize - 1;  // 将缓冲区头指针掩码处理,确保其在缓冲区范围内if (unlikely(client->head == client->tail)) {/** 这实际上"丢弃"了所有未消耗的事件,只保留了EV_SYN/SYN_DROPPED加上最新的事件。*/client->tail = (client->head - 2) & (client->bufsize - 1);  // 更新缓冲区尾指针,使其指向倒数第二个事件client->buffer[client->tail] = (struct input_event) {.input_event_sec = event->input_event_sec,.input_event_usec = event->input_event_usec,.type = EV_SYN,.code = SYN_DROPPED,.value = 0,};  // 在缓冲区尾指针位置插入一个EV_SYN/SYN_DROPPED事件,表示丢弃了事件client->packet_head = client->tail;  // 更新数据包头指针为缓冲区尾指针}if (event->type == EV_SYN && event->code == SYN_REPORT) {client->packet_head = client->head;  // 更新数据包头指针为缓冲区头指针kill_fasync(&client->fasync, SIGIO, POLL_IN);  // 向注册的异步通知处理函数发送SIGIO信号,通知有新的事件可读取}
}

该函数用于将输入事件传递给evdev客户端的缓冲区进行存储。它接受一个evdev_client结构体指针和一个输入事件指针作为参数。

首先,它将输入事件复制到客户端的缓冲区中,并递增缓冲区头指针。

然后,它对缓冲区头指针进行掩码处理,以确保其在缓冲区范围内。

接下来,它检查缓冲区头指针是否等于缓冲区尾指针。如果相等,表示缓冲区已满,需要丢弃一些事件。

在这种情况下,它将缓冲区尾指针更新为缓冲区头指针减去2,并进行掩码处理,以确保其在缓冲区范围内。这样做是为了给丢弃的事件留出空间。

然后,它在缓冲区尾指针的位置插入一个EV_SYN/SYN_DROPPED事件,表示丢弃了事件。该事件具有与最新事件相同的时间戳。

接下来,它将数据包头指针更新为缓冲区尾指针,以确保数据包头始终指向最新的事件。

最后,如果输入事件的类型为EV_SYN且代码为SYN_REPORT,表示一个数据包的结束,它将数据包头指针更新为缓冲区头指针,并向注册的异步通知处理函数发送SIGIO信号,通知有新的事件可读取。

至此,通用事件处理层event函数分析完毕。

这篇关于RK3568驱动指南|第十三篇 输入子系统-第150章 通用事件处理层event函数分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/845636

相关文章

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Python实现精确小数计算的完全指南

《Python实现精确小数计算的完全指南》在金融计算、科学实验和工程领域,浮点数精度问题一直是开发者面临的重大挑战,本文将深入解析Python精确小数计算技术体系,感兴趣的小伙伴可以了解一下... 目录引言:小数精度问题的核心挑战一、浮点数精度问题分析1.1 浮点数精度陷阱1.2 浮点数误差来源二、基础解决

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

从入门到精通详解Python虚拟环境完全指南

《从入门到精通详解Python虚拟环境完全指南》Python虚拟环境是一个独立的Python运行环境,它允许你为不同的项目创建隔离的Python环境,下面小编就来和大家详细介绍一下吧... 目录什么是python虚拟环境一、使用venv创建和管理虚拟环境1.1 创建虚拟环境1.2 激活虚拟环境1.3 验证虚

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

Python ORM神器之SQLAlchemy基本使用完全指南

《PythonORM神器之SQLAlchemy基本使用完全指南》SQLAlchemy是Python主流ORM框架,通过对象化方式简化数据库操作,支持多数据库,提供引擎、会话、模型等核心组件,实现事务... 目录一、什么是SQLAlchemy?二、安装SQLAlchemy三、核心概念1. Engine(引擎)