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

相关文章

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

使用JavaScript将PDF页面中的标注扁平化的操作指南

《使用JavaScript将PDF页面中的标注扁平化的操作指南》扁平化(flatten)操作可以将标注作为矢量图形包含在PDF页面的内容中,使其不可编辑,DynamsoftDocumentViewer... 目录使用Dynamsoft Document Viewer打开一个PDF文件并启用标注添加功能扁平化

轻松掌握python的dataclass让你的代码更简洁优雅

《轻松掌握python的dataclass让你的代码更简洁优雅》本文总结了几个我在使用Python的dataclass时常用的技巧,dataclass装饰器可以帮助我们简化数据类的定义过程,包括设置默... 目录1. 传统的类定义方式2. dataclass装饰器定义类2.1. 默认值2.2. 隐藏敏感信息

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

电脑显示hdmi无信号怎么办? 电脑显示器无信号的终极解决指南

《电脑显示hdmi无信号怎么办?电脑显示器无信号的终极解决指南》HDMI无信号的问题却让人头疼不已,遇到这种情况该怎么办?针对这种情况,我们可以采取一系列步骤来逐一排查并解决问题,以下是详细的方法... 无论你是试图为笔记本电脑设置多个显示器还是使用外部显示器,都可能会弹出“无HDMI信号”错误。此消息可能