• 嵌入式Linux 开发经验:编写用户态应用程序打开 misc 设备


    参考文章

    VSCode SSH 连接远程ubuntu Linux 主机

    ubuntu 20.04 qemu linux6.0.1 开发环境搭建

    ubuntu 20.04 qemu linux6.0.1 制作ext4根文件系统

    嵌入式Linux 开发经验:platform_driver_register 的使用方法

    嵌入式Linux 开发经验:注册一个 misc 设备

    • 通过以上的文章,应该可以搭建一个 基于 qemu 的 Linux 设备驱动开发验证平台,开发方法是 VS Code 远程连接 ubuntu 20.04,Linux 内核 在 ubuntu 主机上。

    测试环境搭建

    • ubuntu 20.04

    • VMware Workstation Pro 16

    • 基于qemu(模拟器),vexpress-a9 平台

    • Linux 6.0.10 (当前最新版本)

    • 编写一个简单的用户态应用程序,打开与关闭 Linux 内核注册的misc 驱动设备,掌握misc 设备使用方法:打开与关闭的方法

    用户态应用程序

    • Linux 系统分为内核态与用户态,驱动一般写在内核态,用户态想访问内核态注册的驱动设备,需要通过 文件操作 API,如 open、close、read、write、ioctl 等

    • Linux misc 设备,一般不提供 read 与 write,而是提供 open 、close、 ioctl 等接口,open 用于打开设备, close 用于关闭设备, 而 ioctl 虽然是一个 API,但是可以通过 命令,实现多个操作

    • 假如 内核态的驱动设备 是个【空调】,开机后内核注册了这个设备,就像是安装在了家里,如果不【上电】,空调就无法工作,用户需要【遥控器】去操作这个【空调】,用户程序的操作就类似于【遥控器】的操作,不是直接打开【空调】盖子上电,通过【遥控器】的命令就可以实现多个操作

    编写用户程序

    • 用户程序不需要放在 Linux 内核目录下编译,可以单独放在其他的目录,上篇注册了一个 misc 的设备,本篇写个简单的 用户态程序,打开或者关闭这个 misc 设备

    • 编写 led_control.c,位置可以随便放,我放在 /home/zhangsz/linux/apps/led_control 目下

    • 当前只有打开与关闭的操作,后续再实现 ioctl 控制操作

    #include 
    #include 
    #include 
    #include 
    
    #define LED_CONTROL_DEVICE_NAME		"/dev/led_misc"
    
    int led_dev_fd = -1;
    
    /* 打开操作 API,这个 API其实比较的底层,也就是用户高层的应用,可以调用这个 API */
    int led_dev_init(void)
    {
    	int fd;
    	fd = open(LED_CONTROL_DEVICE_NAME, O_RDWR);
    	if (fd < 0)
    	{
    		printf("%s : open device error\n", __func__);
    		return -1;
    	}
    	led_dev_fd = fd;
    	
    	printf("%s : ok\n", __func__);
    	return 0;
    }
    
    /* 关闭操作 API,这个 API其实比较的底层,也就是用户高层的应用,可以调用这个 API */
    int led_dev_deinit(void)
    {
    	if (close(led_dev_fd) != 0)
    	{
    		printf("%s : error\n", __func__);
    		return -1;
    	}
    		
    	printf("%s : ok\n", __func__);
    	return 0;
    }
    
    /* API 调用的测试,实际用户程序当然不只是这么简单 */
    int main(int argc, char **argv)
    {
    	printf("%s : enter\n", __func__);
    	led_dev_init();
    	led_dev_deinit();
    	printf("%s : exit\n", __func__);
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    编译方法

    • 可以直接使用命令行编译,也可以编写Makefile,因为当前的用户程序就是一个文件,所以写个简单的Makefile编译,后面就不用一直输入较长的gcc 命令来编译了

    • 新建 Maekfile 文件,放在 /home/zhangsz/linux/apps/led_control 目下

    all:
    	arm-linux-gnueabihf-gcc led_control.c -o led_control
    clean:
    	rm -rf *.o led_control
    
    • 1
    • 2
    • 3
    • 4
    • Makefile 注意缩进使用的 TAB(制表符),而不是空格

    • 然后在Linux shell 中 输入 make 就可以编译了

    zhangsz@zhangsz:~/linux/apps/led_control$ make
    arm-linux-gnueabihf-gcc led_control.c -o led_control
    
    • 1
    • 2
    • 这里生成了可执行的文件 led_control,这个文件需要放在 Linux 根文件系统中,在 shell 手动执行这个文件才能工作,当然后期可以写个自动调用的shell 脚步放在板子上自动调用执行

    运行用户程序

    • 这里是 基于 qemu 的 ext4 的 镜像,只要把 镜像文件挂载到某个目录下,然后把 led_control 复制进去,然后 umount 后,这个文件就加入到根文件系统镜像里面了

    • 相关操作

    /* apps led_control 路径 */
    zhangsz@zhangsz:~/linux/apps/led_control$ ls
    led_control  led_control.c  Makefile
    
    
    zhangsz@zhangsz:~/linux/apps/led_control$ cd ../../rootfs/
    zhangsz@zhangsz:~/linux/rootfs$ ls
    1130  boot_qemu.sh  ext4_rootfs  make_rootfs.sh  rootfs.ext4.img  rootfs_mnt  vexpress-v2p-ca9.dtb  zImage
    
    /* ext4 根文件系统镜像文件,使用 mount 挂载到一个目录 */
    zhangsz@zhangsz:~/linux/rootfs$ sudo mount rootfs.ext4.img rootfs_mnt/
    [sudo] password for zhangsz: 
    
    /* led_control 复制到 根文件系统镜像文件挂载的目录内 */
    zhangsz@zhangsz:~/linux/rootfs$ sudo cp ../apps/led_control/led_control rootfs_mnt/home/root/
    
    /* umount 后,文件就复制进根文件系统镜像文件中了 */
    zhangsz@zhangsz:~/linux/rootfs$ sudo umount rootfs_mnt 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 运行qemu : ./boot_qemu.sh rootfs.ext4.img ,这里使用的 shell 脚本,具体命令行为
    qemu-system-arm -M vexpress-a9 -m 512M -dtb vexpress-v2p-ca9.dtb -kernel zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.ext4.img
    
    • 1
    • 注意启动 qemu 前, 设备树 dbt 文件 vexpress-v2p-ca9.dtb 与内核文件 zImage 都在同一个目录下
    zhangsz@zhangsz:~/linux/rootfs$ ls
    1130  boot_qemu.sh  ext4_rootfs  make_rootfs.sh  rootfs.ext4.img  rootfs_mnt  vexpress-v2p-ca9.dtb  zImage
    
    • 1
    • 2
    • 进入qemu Linux shell,通过 ls sys/class/misc/ -la 可以查看当前注册的 misc 设备,这里是 led_misc

    • 进入 /home/root/ ,运行 ./led_control,可以看到 设备 打开 与关闭的信息,说明 用户应用程序成功的打开与关闭了 内核驱动 注册的 led_misc 设备

    在这里插入图片描述

    小结

    • 本篇记录Linux 用户态 应用程序的编写编译方法,通过标准文件接口 open close 对 内核注册的 misc 设备进行 打开与关闭。

    • misc 设备最有用的一般是 ioctl 命令,用户可以通过自定义实现多个 基于ioctl 的 cmd 命令,实现各种各样的操作。

  • 相关阅读:
    WIN11+OPENCV4.8 编译及下载失败处理方法
    汽车网络安全方案产品交付形态的思考
    Qt | 信号和槽之间的连接与使用、重新信号和槽的连接
    字符串ipv4和ipv6地址转换成整形
    1-VSCode搭建GD32开发环境
    python让女友照片飞来飞去
    关于看病报销额度
    图扑软件助力企业数字化转型
    java后端web前端10套项目开发案例源码,毕设,期末作业
    设计模式-单例
  • 原文地址:https://blog.csdn.net/tcjy1000/article/details/128165100