RK3568驱动指南|第十三篇 输入子系统-第141章 编写最简单的设备驱动层代码

本文主要是介绍RK3568驱动指南|第十三篇 输入子系统-第141章 编写最简单的设备驱动层代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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


第141章 编写最简单的设备驱动层代码

从上面的学习中可以了解到,输入子系统可以分为三层,分别为中间的核心层,靠近上层应用的事件处理层,以及靠近硬件设备的设备驱动层,事件处理层的代码一般情况下也不需要编写,所以需要我们来编写的就只有设备驱动层的代码。本小节将编写一个最简单的设备驱动层代码。

141.1 设备驱动层代码编写步骤

步骤一:创建输入设备结构体变量 在设备驱动的开发中,首先需要创建一个输入设备的结构体变量,该结构体变量将用于表示和管理设备的属性和状态。可以使用 input_allocate_device 函数来分配输入设备结构体的内存。

步骤二:初始化输入设备结构体变量 在创建输入设备结构体变量后,需要对其进行初始化。这包括设置设备的名称、支持的事件类型、事件处理函数等。可以使用结构体提供的成员变量和函数来完成初始化过程。

步骤三:注册输入设备结构体变量 在初始化输入设备结构体变量后,需要将其注册到系统中,以便系统能够正确地识别和使用该设备。可以使用 input_register_device 函数来注册输入设备结构体变量。在注册过程中,系统将完成设备的匹配和初始化工作。

步骤四:上报事件 一旦设备注册成功,就可以通过输入设备结构体变量上报事件。这可以通过调用输入设备结构体提供的函数来完成,例如 input_event 函数。根据设备类型和事件类型,可以生成相应的输入事件,并通过调用该函数将事件发送给系统。

注:本章节只是为了编写最简单的设备驱动层代码,所以本章节不会涉及到事件上报这一步骤相关的代码,会在后面的章节再进行填充。

步骤五:注销和释放输入设备结构体变量 当设备不再需要使用时,应该进行注销和释放操作,以确保资源的正确释放。可以使用 input_unregister_device 函数来注销输入设备结构体变量,并使用 input_free_device 函数来释放相关资源和内存。

141.2 input_allocate_device 函数讲解

input_allocate_device 函数定义在drivers/input/input.c文件中,具体内容如下所示:

struct input_dev *input_allocate_device(void)
{static atomic_t input_no = ATOMIC_INIT(-1);struct input_dev *dev;// 分配输入设备结构体的内存dev = kzalloc(sizeof(*dev), GFP_KERNEL);if (dev) {// 设置设备类型和设备类dev->dev.type = &input_dev_type;dev->dev.class = &input_class;// 初始化设备device_initialize(&dev->dev);// 初始化互斥锁和事件自旋锁mutex_init(&dev->mutex);spin_lock_init(&dev->event_lock);// 初始化定时器timer_setup(&dev->timer, NULL, 0);// 初始化链表头INIT_LIST_HEAD(&dev->h_list);INIT_LIST_HEAD(&dev->node);// 设置设备名称,使用原子变量递增来保证唯一性dev_set_name(&dev->dev, "input%lu", (unsigned long)atomic_inc_return(&input_no));// 增加模块引用计数__module_get(THIS_MODULE);}return dev;
}

这个函数的作用是为输入设备分配内存并进行必要的初始化,为后续的输入事件处理和设备注册做准备。

141.3 初始化input_dev 结构体

在使用input_allocate_device函数创建了一个input_dev结构体之后,接下来就要初始化input_dev结构体内容了,在该步骤中又有两个内容,分别为设置事件类型和设置具体类型。

141.3.1 设置事件类型

在头文件include/uapi/linux/input-event-codes.h中,Linux内核已经为我们定义了一些输入事件类型,它们的含义如下:

(1)EV_SYN (0x00): 用于同步事件,表示一组输入事件的结束。

(2)EV_KEY (0x01): 用于按键事件,表示按下、释放或重复一个键。

(3)EV_REL (0x02): 用于相对位移事件,表示设备的相对位置变化,例如鼠标的移动。

(4)EV_ABS (0x03): 用于绝对位移事件,表示设备的绝对位置变化,例如触摸屏的坐标。

(5)EV_MSC (0x04): 用于杂项事件,包含一些特殊目的的事件类型,例如设备状态变化等。

(6)EV_SW (0x05): 用于开关事件,表示开关的状态变化,例如电源按钮、开合盖等。

(7)EV_LED (0x11): 用于 LED 事件,表示 LED 灯的状态变化。

(8)EV_SND (0x12): 用于声音事件,表示声音的播放相关事件。

(9)EV_REP (0x14): 用于重复事件,表示键盘重复发送事件。

(10)EV_FF (0x15): 用于力反馈事件,表示力反馈设备的输出事件。

(11)EV_PWR (0x16): 用于电源事件,表示电源状态变化。

(12)EV_FF_STATUS (0x17): 用于力反馈状态事件,表示力反馈设备的状态变化。

(13)EV_MAX (0x1f): 输入事件类型的最大值。

(14)EV_CNT: 输入事件类型的数量。

而在input_dev结构体中定义了一系列的位图,在输入子系统中用于表示输入设备的能力和支持的功能,具体定义如下所示:

unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];     // 设备的属性位图
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)];             // 设备支持的LED位图
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];             // 设备支持的声音位图
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];               // 设备支持的力反馈位图
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];               // 设备支持的开关位图

(1)evbit(事件类型位图)是一个长度为 EV_CNT 的数组,每个元素对应一个事件类型。通过设置相应的位,可以指示设备支持的事件类型,如按键事件、相对位移事件、绝对位移事件、杂项事件等。

(2)keybit(按键类型位图)表示输入设备支持的按键类型,通常与 EV_KEY 事件类型相关。通过设置相应的位,可以指示设备支持的按键。

(3)relbit(相对位移类型位图)表示输入设备支持的相对位移类型,通常与 EV_REL 事件类型相关。通过设置相应的位,可以指示设备支持的相对位移,例如鼠标的移动。

(4)absbit(绝对位移类型位图)表示输入设备支持的绝对位移类型,通常与 EV_ABS 事件类型相关。通过设置相应的位,可以指示设备支持的绝对位移,例如触摸屏的坐标。

(5)mscbit(杂项类型位图)表示输入设备支持的杂项类型,通常与 EV_MSC 事件类型相关。通过设置相应的位,可以指示设备支持的杂项事件,例如设备状态变化等。

(6)ledbit(LED 类型位图)表示输入设备支持的 LED 类型,通常与 EV_LED 事件类型相关。通过设置相应的位,可以指示设备支持的 LED 灯控制。

(7)sndbit(声音类型位图)表示输入设备支持的声音类型,通常与 EV_SND 事件类型相关。通过设置相应的位,可以指示设备支持的声音事件。

(8)ffbit(力反馈类型位图)表示输入设备支持的力反馈类型,通常与 EV_FF 事件类型相关。通过设置相应的位,可以指示设备支持的力反馈事件。

(9)swbit(开关类型位图)表示输入设备支持的开关类型,通常与 EV_SW 事件类型相关。通过设置相应的位,可以指示设备支持的开关状态变化。

这些位图用于向输入子系统提供关于输入设备的能力和功能的信息,以便在注册和处理输入设备时进行相应的配置和过滤。通过设置相应的位,可以告知输入子系统设备所支持的事件类型和功能,使得输入子系统能够正确识别和处理来自设备的输入数据。

__set_bit是一个位操作函数,用于设置一个位图中的特定位,例如可以通过下面的代码将输入设备设置为支持按键事件:

__set_bit(EV_KEY,myinput_dev->evbit)

141.3.2 设置具体类型

设置完事件类型之后,还需要设置具体类型,宏定义仍旧定义在头文件include/uapi/linux/input-event-codes.h中,部分内容如下所示:

#define KEY_RESERVED		0
#define KEY_ESC			1
#define KEY_1			2
#define KEY_2			3
#define KEY_3			4
#define KEY_4			5
#define KEY_5			6
#define KEY_6			7
#define KEY_7			8
#define KEY_8			9
#define KEY_9			10

上一小节只是将输入设备设置为了按键事件,但具体要表示什么呢,是按键1还是按键2亦或者其他按键,都无法确定,所以仍旧需要使用__set_bit函数来确定具体类型,例如使用以下程序将该输入设备设置为按键1

__set_bit(KEY_1,myinput_dev->keybit)

141.4 驱动程序的编写

本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\91_myinput_dev。编写完成的myinput_dev.c代码如下所示:

#include <linux/input.h>
#include <linux/module.h>struct input_dev *myinput_dev;static int myinput_dev_init(void)
{int ret;// 分配输入设备结构体myinput_dev = input_allocate_device();if (myinput_dev == NULL) {printk("input_allocate_device error\n");return -1;}// 设置输入设备的名称myinput_dev->name = "myinput_dev";// 设置输入设备支持的事件类型__set_bit(EV_KEY, myinput_dev->evbit);    // 设置支持按键事件__set_bit(KEY_1, myinput_dev->keybit);    // 设置支持按键1// 注册输入设备ret = input_register_device(myinput_dev);if (ret < 0) {printk("input_register_device error\n");goto error;}return 0;error:// 注册失败,释放输入设备结构体input_free_device(myinput_dev);return ret;
}
static void myinput_dev_exit(void)
{// 注销输入设备input_unregister_device(myinput_dev);
}module_init(myinput_dev_init);
module_exit(myinput_dev_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");

141.5 运行测试

141.5.1 编译驱动程序

在上一小节中的myinput_dev.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += myinput_dev.o    #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            
PWD ?= $(shell pwd)
all:make -C $(KDIR) M=$(PWD) modules    #make操作
clean:make -C $(KDIR) M=$(PWD) clean    #make clean操作    

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放myinput_dev.c和Makefile文件目录下,如下图所示:

然后使用命令“make”进行驱动的编译,编译完成如下图所示:

编译完生成myinput_dev.ko目标文件,如下图所示:

至此驱动模块就编译成功了。

141.5.2 运行测试

首先启动开发板,进入系统之后如下所示:

然后将上一小节编译完成的myinput_dev.ko驱动文件拷贝到开发板上,拷贝完成如下所示:

在加载驱动之前首先使用以下命令查看当前的输入设备,如下所示:

ls /dev/input

可以看到目前有4个输入设备的设备节点,然后使用以下命令进行驱动的加载,如下图所示:

insmod myinput_dev.ko

然后重新查看设备节点,可以看到多出来了一个event4节点,如下图所示:

然后使用以下命令查看设备节点信息,可以根据名字确定event4正是加载驱动所创建的,如下图所示:

cat /proc/bus/input/devices

至此,关于最简单的设备驱动程序就测试完成了。 

这篇关于RK3568驱动指南|第十三篇 输入子系统-第141章 编写最简单的设备驱动层代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN