ARM Linux 驱动开发篇----字符设备驱动开发(5)--- 编写测试chrdevbase 字符设备驱动开发APP程序--- Ubuntu20.04

🎬 渡水无言 :个人主页渡水无言

❄专栏传送门 :linux专栏

⭐️流水不争先,争的是滔滔不绝

目录

前言

[一、C 库文件操作基本函数](#一、C 库文件操作基本函数)

[1.1、open 函数](#1.1、open 函数)

[1.2read 函数](#1.2read 函数)

[1.3write 函数](#1.3write 函数)

[1.4、close 函数](#1.4、close 函数)

[二、编写测试 APP 程序](#二、编写测试 APP 程序)

[三、编译驱动程序和测试 APP](#三、编译驱动程序和测试 APP)

1、编译驱动程序

[2、编译测试 APP](#2、编译测试 APP)

总结


前言

上一期博客我们编写完成了chrdevbase 字符设备驱动开发实验的代码,这一期博客,我们开始编写测试 APP的代码。


一、C库文件操作基本函数

编写测试 APP 就是编写 Linux 应用,需要用到 C 库里面和文件操作有关的一些函数,比如open、read、write 和 close 这四个函数。

1.1、open函数

open 函数原型如下:

复制代码
int open(const char *pathname, int flags)

open 函数参数含义如下:

pathname:要打开的设备或者文件名。

flags**:**文件打开模式,以下三种模式必选其一:

O_RDONLY 只读模式

O_WRONLY 只写模式

O_RDWR 读写模式

因为我们要对 chrdevbase 这个设备进行读写操作,所以选择 O_RDWR。除了上述三种模式以外还有其他的可选模式,通过逻辑或来选择多种模式

返回值:如果文件打开成功的话返回文件的文件描述符。
在 Ubuntu 中输入" man 2 open "即可查看 open 函数的详细内容,如下图 所示:

1.2read****函数

read 函数原型如下:

复制代码
ssize_t read(int fd, void *buf, size_t count)

read 函数参数含义如下:

fd:要读取的文件描述符,读取文件之前要先用 open 函数打开文件,open 函数打开文件成

功以后会得到文件描述符。

buf**:**数据读取到此 buf 中。

count**:**要读取的数据长度,也就是字节数。

**返回值:**读取成功的话返回读取到的字节数;如果返回 0 表示读取到了文件末尾;如果返回负值,表示读取失败。在 Ubuntu 中输入"man 2 read"命令即可查看 read 函数的详细内容。

1.3write****函数

write 函数原型如下:

复制代码
ssize_t write(int fd, const void *buf, size_t count);

write 函数参数含义如下:

fd:要进行写操作的文件描述符,写文件之前要先用 open 函数打开文件,open 函数打开文

件成功以后会得到文件描述符。

buf**:**要写入的数据。

count**:**要写入的数据长度,也就是字节数。

**返回值:**写入成功的话返回写入的字节数;如果返回 0 表示没有写入任何数据;如果返回

负值,表示写入失败。在 Ubuntu 中输入"man 2 write"命令即可查看 write 函数的详细内容。

1.4、close****函数

close 函数原型如下:

int close(int fd);

close 函数参数含义如下:

fd:要关闭的文件描述符。

**返回值:**0 表示关闭成功,负值表示关闭失败。在 Ubuntu 中输入"man 2 close"命令即可

查看 close 函数的详细内容。

二、编写测试APP程序

驱动编写好以后是需要测试的,一般编写一个简单的测试 APP,测试 APP 运行在用户空

间。测试 APP 很简单通过输入相应的指令来对 chrdevbase 设备执行读或者写操作。在 1_chrdevbase 目录中新建 chrdevbaseApp.c 文件,在此文件中输入如下内容:

复制代码
1  #include "stdio.h"
2  #include "unistd.h"
3  #include "sys/types.h"
4  #include "sys/stat.h"
5  #include "fcntl.h"
6  #include "stdlib.h"
7  #include "string.h"
8  
9  /********************************************
11 文件名     : chrdevbaseApp.c
13 版本       : V1.0
14 描述       : chrdevbase 驱动测试APP。
15 其他       : 使用方法: ./chrdevbaseApp /dev/chrdevbase <1>|<2>
16 ********************************************/
17  
18 static char usrdata[] = {"usr data!"};
19  
20 /*
21  * @description : main 主程序
22  * @param - argc : argv 数组元素个数
23  * @param - argv : 具体参数
24  * @return      : 0 成功;其他 失败
25  */
26 int main(int argc, char *argv[])
27 {
28     int fd, retval;
29     char readbuf[100], writebuf[100];
30     static char usrdata[] = {"usr data!"};
31  
32     if(argc != 3){
33         printf("Error Usage!\r\n");
34         return -1;
35     }
36  
37     char *filename = argv[1];
38  
39     /* 打开驱动文件 */
40     fd = open(filename, O_RDWR);
41     if(fd < 0){
42         printf("Can't open file %s\r\n", filename);
43         return -1;
44     }
45  
46     if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */
47         retval = read(fd, readbuf, 50);
48         if(retval < 0){
49             printf("read file %s failed!\r\n", filename);
50         }else{
51             /* 读取成功,打印出读取成功的数据 */
52             printf("read data:%s\r\n",readbuf);
53         }
54     }
55  
56     if(atoi(argv[2]) == 2){ /* 向设备驱动写数据 */
57         memcpy(writebuf, usrdata, sizeof(usrdata));
58         retval = write(fd, writebuf, 50);
59         if(retval < 0){
60             printf("write file %s failed!\r\n", filename);
61         }
62     }
63  
64     /* 关闭设备 */
65     retval = close(fd);
66     if(retval < 0){
67         printf("Can't close file %s\r\n", filename);
68         return -1;
69     }
70  
71     return 0;
72 }

第 18 行,数组 usrdata 是测试 APP 要向 chrdevbase 设备写入的数据。

第 32行,判断运行测试 APP 的时候输入的参数是不是为 3 个,main 函数的 argc 参数表示参数数量,argv\[\]保存着具体的参数,如果参数不为 3 个的话就表示测试 APP 用法错误。比如,现在要从 chrdevbase 设备中读取数据,需要输入如下命令:

复制代码
./chrdevbaseApp /dev/chrdevbase 1

上述命令一共有三个参数"./chrdevbaseApp"、"/dev/chrdevbase"和"1",这三个参数分别

对应 argv0、argv1和 argv2。第一个参数表示运行 chrdevbaseAPP 这个软件,第二个参数表

示测试APP要打开/dev/chrdevbase这个设备。第三个参数就是要执行的操作,1表示从chrdevbase

中读取数据,2 表示向 chrdevbase 写数据。

第 37行,获取要打开的设备文件名字,argv1保存着设备名字。

第 40行,调用 C 库中的 open 函数打开设备文件:/dev/chrdevbase。

第 46行,判断 argv2参数的值是 1 还是 2,因为输入命令的时候其参数都是字符串格式的,因此需要借助 atoi 函数将字符串格式的数字转换为真实的数字。

第 47 行,当 argv2为 1 的时候表示要从 chrdevbase 设备中读取数据,一共读取 50 字节的数据,读取到的数据保存在 readbuf 中,读取成功以后就在终端上打印出读取到的数据。

第 56 行,当 argv2为 2 的时候表示要向 chrdevbase 设备写数据。

第 65 行,对 chrdevbase 设备操作完成以后就关闭设备。

chrdevbaseApp.c 内容还是很简单的,就是最普通的文件打开、关闭和读写操作。

三、编译驱动程序和测试****APP

1**、编译驱动程序**

首先编译驱动程序,也就是 chrdevbase.c 这个文件,我们需要将其编译为.ko 模块,创建 Makefile 文件,然后在其中输入如下内容:

复制代码
1 KERNELDIR := /home/duan/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
2 CURRENT_PATH := $(shell pwd)
3 obj-m := chrdevbase.o
4 
5 build: kernel_modules
6 
7 kernel_modules:
8 	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
9 clean:
10 	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

第 1 行,KERNELDIR 表示开发板所使用的 Linux 内核源码目录,使用绝对路径(需要自己修改)。

第 2 行,CURRENT_PATH 表示当前路径,直接通过运行"pwd"命令来获取当前所处路径。

第 3 行,obj-m 表示将 chrdevbase.c 这个文件编译为 chrdevbase.ko 模块。

第 8 行,具体的编译命令,后面的 modules 表示编译模块,-C 表示将当前的工作目录切

换到指定目录中,也就是 KERNERLDIR 目录。M 表示模块源码目录,"make modules"命令

中加入 M=dir 以后程序会自动到指定的 dir 目录中读取模块的源码并将其编译为.ko 文件。

Makefile 编写好以后输入"make"命令编译驱动模块,编译过程如图 所示:

编译成功以后就会生成一个叫做 chrdevbaes.ko 的文件,此文件就是 chrdevbase 设备的驱动

模块。至此,chrdevbase 设备的驱动就编译成功。

2**、编译测试****APP**

测试 APP 比较简单,只有一个文件,因此就不需要编写 Makefile 了,直接输入命令编译。

因为测试 APP 是要在 ARM 开发板上运行的,所以需要使用 arm-linux-gnueabihf-gcc 来编译,

输入如下命令:

复制代码
arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseApp

编译完成以后会生成一个叫做 chrdevbaseApp 的可执行程序,输入如下命令查看

复制代码
chrdevbaseAPP 

结果如下图所示:


总结

相关推荐
律宏阔3 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔3 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴3 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千4 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei374 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei374 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei374 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
judezh4 小时前
api 容器一直 unhealthy?我把一个 Agent 运行时的健康检查逐条拆了,查出四个问题
运维·docker
GeW4 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
GeW4 小时前
工业场景中的Linux与数据库选型:高端化转型的技术底座
linux