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

瑞芯微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主板


  1. 第151章  通用事件处理层read和write函数分析

本章节我们继续分析通用事件处理层evdev.c文件中的read和write函数。

151.1 read函数分析

接下来我们继续分析read函数,如下图所示:

evdev_read函数如下所示

static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
    struct evdev_client *client = file->private_data;  // 获取文件私有数据中的evdev客户端结构体指针
    struct evdev *evdev = client->evdev;  // 获取客户端结构体中的evdev结构体指针
    struct input_event event;  // 定义一个输入事件结构体
    size_t read = 0;  // 已读取的字节数
    int error;

    if (count != 0 && count < input_event_size())
        return -EINVAL;  // 如果count不为0且小于输入事件大小,返回无效参数错误

    for (;;) {
        if (!evdev->exist || client->revoked)
            return -ENODEV;  // 如果evdev设备不存在或客户端已撤销,则返回设备不存在错误码

        if (client->packet_head == client->tail &&
            (file->f_flags & O_NONBLOCK))
            return -EAGAIN;  // 如果数据包头等于尾且文件标志中设置了非阻塞标志,返回暂无数据可读错误码

        /*
         * count == 0 is special - no IO is done but we check
         * for error conditions (see above).
         */
        if (count == 0)
            break;  // 如果count为0,退出循环,不执行IO操作,但仍检查错误条件

        while (read + input_event_size() <= count &&
               evdev_fetch_next_event(client, &event)) {

            if (input_event_to_user(buffer + read, &event))
                return -EFAULT;  // 将输入事件数据复制到用户空间缓冲区中,如果复制失败,返回错误码

            read += input_event_size();  // 更新已读取的字节数
        }

        if (read)
            break;  // 如果已读取的字节数大于0,退出循环

        if (!(file->f_flags & O_NONBLOCK)) {
            error = wait_event_interruptible(evdev->wait,
                    client->packet_head != client->tail ||
                    !evdev->exist || client->revoked);  // 等待事件的发生,阻塞当前线程
            if (error)
                return error;  // 如果等待被中断,返回错误码
        }
    }

    return read;  // 返回已读取的字节数
}

此函数的目的是从evdev设备中读取输入事件。下面是逐行解释:

1 struct evdev_client *client = file->private_data; 从文件的私有数据中获取evdev客户端的指针。

2 struct evdev *evdev = client->evdev; 从evdev客户端结构体中获取evdev设备的指针。

3 struct input_event event; 创建一个输入事件结构体。

4 size_t read = 0; 用于记录已读取的字节数。

5 int error; 用于保存错误码。

接下来是一些错误检查和条件判断:

6 if (count != 0 && count < input_event_size()) return -EINVAL; 检查count是否为0且小于输入事件的大小,如果是,则返回无效参数错误码。

7 (!evdev->exist || client->revoked) return -ENODEV; 检查evdev设备是否存在或客户端是否已撤销,如果是,则返回设备不存在错误码。

8 if (client->packet_head == client->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; 检查数据包头是否等于尾,并且文件标志中是否设置了非阻塞标志,如果是,则返回暂无数据可读错误码。

接下来是主要的读取逻辑:

9 if (count == 0) break; 如果count为0,表示不执行IO操作,但仍检查错误条件,此时跳出循环。

10 while (read + input_event_size()<= count && evdev_fetch_next_event(client, &event)) { 在已读取的字节数小于等于count且还能获取到下一个输入事件的情况下循环执行。

11 if (input_event_to_user(buffer + read, &event)) return -EFAULT; 将输入事件复制到用户空间缓冲区中,如果复制失败,返回错误码。

12 read += input_event_size(); 更新已读取的字节数。

接下来是处理没有读取到任何事件的情况:

13 if (read) break; 当已读取的字节数大于0时,跳出循环。

接下来是处理阻塞等待事件的情况:

14 if (!(file->f_flags & O_NONBLOCK)) { 如果文件标志中没有设置非阻塞标志,则执行以下操作。

15error = wait_event_interruptible(evdev->wait, client->packet_head != client->tail || !evdev->exist || client->revoked); 等待事件的发生,阻塞当前线程,直到数据包头不等于尾或evdev设备不存在或客户端已撤销。

16 if (error) return error; 如果等待被中断,返回错误码。

最后返回已读取的字节数。

这段代码是一个用于从evdev设备读取输入事件的函数。它首先进行一些错误检查和条件判断,然后通过循环读取输入事件并将其复制到用户空间缓冲区中,直到满足退出循环的条件。如果没有读取到任何事件,则根据阻塞标志执行相应操作。最后返回已读取的字节数。

151.2 write函数分析

接下来我们继续分析write函数,如下图所示:

evdev_write函数如下所示:

static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    struct evdev_client *client = file->private_data;  // 获取文件私有数据中的evdev客户端结构体指针
    struct evdev *evdev = client->evdev;  // 获取客户端结构体中的evdev结构体指针
    struct input_event event;  // 定义一个输入事件结构体
    int retval = 0;  // 返回值变量,默认为0

    if (count != 0 && count < input_event_size())
        return -EINVAL;  // 如果count不为0且小于输入事件大小,返回无效参数错误

    retval = mutex_lock_interruptible(&evdev->mutex);  // 对evdev的互斥锁进行上锁,可中断
    if (retval)
        return retval;  // 如果上锁失败,返回错误码

    if (!evdev->exist || client->revoked) {
        retval = -ENODEV;
        goto out;
    }  // 如果evdev设备不存在或客户端已撤销,则返回设备不存在错误码

    while (retval + input_event_size() <= count) {

        if (input_event_from_user(buffer + retval, &event)) {
            retval = -EFAULT;
            goto out;
        }  // 从用户空间复制输入事件到event结构体中,如果复制失败,返回错误码

        retval += input_event_size();  // 更新retval,增加一个输入事件的大小

        input_inject_event(&evdev->handle,
                           event.type, event.code, event.value);  // 将输入事件注入到evdev事件处理器中
        cond_resched();  // 条件调度,让出CPU给其他线程执行
    }

out:
    mutex_unlock(&evdev->mutex);  // 解锁evdev的互斥锁
    return retval;  // 返回retval作为写入的字节数或错误码
}

该函数用于将输入事件写入到evdev设备的缓冲区中。它接受一个文件结构体指针、一个指向用户空间缓冲区的指针、写入的字节数以及文件偏移量指针作为参数。

首先,它从文件的私有数据中获取evdev客户端结构体指针和evdev结构体指针。

然后,它检查count是否为0且小于输入事件的大小。如果是,则返回无效参数错误。

接下来,它对evdev的互斥锁进行上锁,可中断。如果上锁失败,返回错误码。

然后,它检查evdev设备是否存在且客户端是否已撤销。如果设备不存在或客户端已撤销,则返回设备不存在错误码。

接下来,它进入一个循环,直到写入的字节数达到count或超过count。

在循环中,它从用户空间复制输入事件数据到event结构体中。如果复制失败,返回错误码。

然后,它增加一个输入事件的大小到retval中,以跟踪已写入的字节数。

接下来,它将输入事件注入到evdev事件处理器中,使用event结构体中的type、code和value字段。

最后,它进行条件调度,让出CPU给其他线程执行。

循环结束后,它解锁evdev的互斥锁,并返回retval作为写入的字节数或错误码。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode第26题:删除有序数组中的重复项

代码实现 注意:该题要求原地删除&#xff0c;不能引入额外的连续内存空间 class Solution:def removeDuplicates(self, nums: List[int]) -> int:not_sorted_lengthlen(nums)while(not_sorted_length>0):numnums.pop(0)not_sorted_length-1if num not in nums:nums.appe…

【二十三】【算法分析与设计】三柱汉诺塔详解,计算子移动次数,正常递归计算,观察数据得出数学规律,递归图得出数学规律,将递归函数转化为递推式

目录 汉诺塔递归 汉诺塔子移动次数的计算 牛牛的汉诺塔 选择正常的递归模拟计算子移动次数 根据具体数据得出数学规律 根据递归图得出数学规律 将递归函数转化为递推式 结尾 汉诺塔递归 汉诺塔是一个经典问题&#xff0c;相传在古印度圣庙中&#xff0c;有一种被称为汉…

【框架】说一说 Fork/Join?

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习Java框架 个性签名&#xff1a;人生乏味啊&#xff0c;我欲令之光怪陆离 本文封面由 凯楠&#x1f4f7; 友情赞助 目录 前言 什么是 Fork&#xff1f; 什么是 Join&#xff1f; Fork/Join 的核心组件 F…

基于K-近邻的PLOSAR图像分类

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

网络原理(6)——IP协议

目录 一、网段划分 现在的网络划分&#xff1a; 1、一般情况下的家庭网络环境 2、IP地址 3、子网掩码 4、网关 以前的网络划分&#xff1a; 二、特殊IP 1、环回 IP 2、主机号为全 0 的IP 3、广播地址IP 三、路由选择&#xff08;路线规划&#xff09; 一、网段划分…

智慧城管综合执法办案系统,现场移动执法APP源码,占道经营AI智能识别分析系统

智慧城管执法平台源码 智慧城管综合执法办案系统&#xff0c;提供了案件在线办理、当事人信用管理、文书电子送达、沿街店铺分析等功能&#xff0c;全面赋能执法队员&#xff0c;提高执法队员办案效率。 智慧城管综合执法办案系统在业务上能够支持所有行政处罚权力项目的网上运…

systrace抓取

1. 抓取systrace日志 adb root adb shell atrace -z -b 8192 video gfx input view wm rs hal sched freq idle irq -t 10 > /sdcard/trace_output atrace: Android Trace命令&#xff0c;用于在Android系统上进行性能跟踪和分析。 -z: 压缩跟踪数据&#xff0c;减小输出文…

Excel中最常用的快捷健,每天都会用到

Hello&#xff0c;大家好&#xff0c;今天跟大家分享我们工作中经常使用的快捷键&#xff0c;快捷键能够在一定程度上提高我们的工作效率&#xff0c;快速达到我们想要的结果&#xff0c;善用快捷键也能让别人觉得你非常的厉害。 1快速求和 &#xff1a;Alt 使用方法非常的简…

Python编程异步爬虫实战案例

aiohttp异步爬取实战 案例介绍 链接为https://spa5.scrape.center&#xff0c;页面如下图所示&#xff1a; 这是一个图书网站&#xff0c;整个网站包含数千本图书信息&#xff0c;网站数据是JavaScript渲染而得的&#xff0c;数据可以通过Ajax接口获取&#xff0c;并且接口没…

深度学习 - PyTorch基本流程 (代码)

直接上代码 import torch import matplotlib.pyplot as plt from torch import nn# 创建data print("**** Create Data ****") weight 0.3 bias 0.9 X torch.arange(0,1,0.01).unsqueeze(dim 1) y weight * X bias print(f"Number of X samples: {len(…

ZYNQ学习之Ubuntu环境下的Shell与APT下载工具

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Ubuntu Shell操作 简单的说Shell 就是敲命令。国内把 Linux 下通过命令行输入命令叫…

代码随想录算法训练营第三十二天 | 122.买卖股票的最佳时机II ,55. 跳跃游戏 , 45.跳跃游戏II

贪心&#xff1a;只要把每一个上升区间都吃到手&#xff0c;就能一直赚 class Solution { public:int maxProfit(vector<int>& prices) {int res 0;for(int i 1;i< prices.size();i){int diff prices[i] - prices[i-1];if(prices[i] > prices[i-1]){res d…

WSL使用

WSL使用 WSL安装和使用 Termianl和Ubuntu的安装 打开Hype-V虚拟化配置Microsoft Store中搜索Window Terminal并安装Microsoft Store中搜索Ubuntu, 选择安装Ubuntu 22.04.3 LTS版本打开Window Terminal选择Ubuntu标签栏, 进入命令行 中文输入法安装 查看是否安装了fcitx框架…

【官方】操作指南,附代码!银河麒麟服务器迁移运维管理平台V2.1中间件及高可用服务部署(4)

1.RocketMQ集群模式 主机配置示例&#xff1a; IP 角色 架构模式 对应配置文件 1.1.1.1 nameserver1 master broker-n0.conf 2.2.2.2 nameserver2 salve1 broker-n1.conf 3.3.3.3 nameserver3 salve2 broker-n2.conf 1.1.安装rocketmq 在服务器上安装rocket…

第14篇:2线-4线译码器

Q&#xff1a;有编码器那对应的就会有译码器&#xff0c;本期我们来设计实现2线-4线二进制译码器 。 A&#xff1a;基本原理&#xff1a;译码器是编码器的逆过程&#xff0c;其功能是将具有特定含义的二进制码转换为对应的输出信号。2线-4线二进制译码器有2个输入共4种不同的组…

java目标和(力扣Leetcode106)

目标和 力扣原题 问题描述 给定一个正整数数组 nums 和一个整数 target&#xff0c;向数组中的每个整数前添加 ‘’ 或 ‘-’&#xff0c;然后串联起所有整数&#xff0c;可以构造一个表达式。返回可以通过上述方法构造的、运算结果等于 target 的不同表达式的数目。 示例 …

【MySQL】11. 复合查询(重点)

4. 子查询 子查询是指嵌入在其他sql语句中的select语句&#xff0c;也叫嵌套查询 4.1 单行子查询 返回一行记录的子查询 显示SMITH同一部门的员工 mysql> select * from emp where deptno (select deptno from emp where ename SMITH); -----------------------------…

小目标检测篇 | YOLOv8改进之添加BiFormer注意力机制

前言:Hello大家好,我是小哥谈。BiFormer是一种具有双层路由的动态稀疏注意力机制,它通过查询自适应的方式关注一小部分相关标记,从而提供了更灵活的计算分配和内容感知。它在多个计算机视觉任务中表现出了良好的性能和高计算效率。BiFormer注意力机制比较适合处理小尺度目标…

聚类算法之高斯混合模型聚类 (Gaussian Mixture Model, GMM)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 高斯混合模型&#xff08;GMM&#xff09;是统计模型中的一颗璀璨之星&#xff0c;它为数据提供了一种复杂而又强大的表示方法。在机器学习的许多…

大数据基础:Linux基础详解

课程介绍 本课程主要通过对linux基础课程的详细讲解&#xff0c;让大家熟练虚拟机的安装使用&#xff0c;Linux系统的安装配置&#xff0c;学习掌握linux系统常用命令的使用&#xff0c;常用的软件安装方法&#xff0c;制作快照&#xff0c;克隆&#xff0c;完成免密登录&…