内核实验(六):使用misc框架,实现简单字符设备驱动

简介: 本文介绍了如何使用Linux的misc框架来实现一个简单的字符设备驱动程序,包括编写驱动源码、编译、部署以及在Qemu虚拟机中测试驱动程序,展示了如何动态分配次设备号并手动创建设备文件以进行测试。

一、篇头

使用自行组建的Qemu Linux虚拟机,提升效率,继续内核实验。本文将学习使用misc框架来创建设备驱动。

在linux系统中,主设备号,在历史的长河里,都是固定分配好的(见内核文档 Documentation/admin-guide/devices.txt)。对于其他研究内核驱动,或编写驱动的开发人员来说,必须保证自己所使用的主设备号不与现有设备号发生冲突。方法一,自然是使用内核实验(五)中所使用的动态分配接口。其次,就是使用MISC设备驱动框架,它为这些小设备提供了一个公用的主设备号,此设备号则依据申请分配。

二、系列文章

略……

三、实验环境

  • 编译服务器+NFS:ubuntu 22.04
  • Qemu 虚拟机:Linux version 5.15.102 + Buysbox 1.3.36 + ARM_32bit
  • Qemu 启动命令:qemu-system-arm -nographic -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -initrd …/busybox/rootfs.ext4.img.gz -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb

四、源码解析

4.1 app源码

  • 文件名:linux-stable\my_kmodules\app_test.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define MY_DEV_NAME "/dev/my_dev"

int main()
{
   
   
    char buffer[64];
    int fd;
    fd = open(MY_DEV_NAME, O_RDONLY);
    if (fd < 0) {
   
   
        printf("open device %s failded\n", MY_DEV_NAME);
        return -1;
    }
    read(fd, buffer, 64);
    close(fd);
    return 0;
}

4.2 驱动源码

  • 文件名:linux-stable\my_kmodules\test_4.c
4.2.1 关键部分
/*
* (1)使用MISC_DYNAMIC_MINOR动态分配次设备号;而主设备号则自动使用MISC框架的主设备号10;
* (2)创建MISC设备结构体 struct miscdevice test_4_misc_device; 
* (3)使用misc_register() 注册MISC框架设备驱动;使用 misc_deregister()注销。
*/
static struct miscdevice test_4_misc_device ={
   
   

    .minor = MISC_DYNAMIC_MINOR,
    .name = MY_DEV_NAME,
    .fops = &test_fops,
};
4.2.2 完整源码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/miscdevice.h>

#define MY_DEV_NAME "my_dev"

static int test_4_open(struct inode *inode, struct file *file)
{
   
   
    int major = MAJOR(inode->i_rdev);
    int minor = MINOR(inode->i_rdev);

    pr_info("%s: major=%d, minor=%d\n", __func__, major, minor);
    return 0;
}

static int test_4_release(struct inode *inode, struct file *file)
{
   
   
    pr_info("%s \n", __func__);

    return 0;
}

static ssize_t test_4_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos)
{
   
   
    pr_info("%s \n", __func__);
    return 0;
}

static ssize_t test_4_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
   
   
    pr_info("%s \n", __func__);
    return 0;

}

static const struct file_operations test_fops = {
   
   
    .owner = THIS_MODULE,
    .open = test_4_open,
    .release = test_4_release,
    .read = test_4_read,
    .write = test_4_write
};

static struct miscdevice test_4_misc_device ={
   
   

    .minor = MISC_DYNAMIC_MINOR,
    .name = MY_DEV_NAME,
    .fops = &test_fops,
};


static int __init test_4_init(void)
{
   
   
    int ret;

    pr_info("test_4_init\n");

    ret = misc_register(&test_4_misc_device);
    if (ret != 0 ) {
   
   
        pr_err("failed to misc_register");
        return ret;
    }

    pr_err("Minor number = %d\n", test_4_misc_device.minor);

    return 0;
}

static void __exit test_4_exit(void)
{
   
   
    pr_info("test_4_exit\n");
    misc_deregister(&test_4_misc_device);
}

module_init(test_4_init);
module_exit(test_4_exit);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("szhou <66176468@qq.com>");
MODULE_DESCRIPTION("test_4, 使用misc框架开发设备驱动");

4.3 Makefile

  • 文件名:linux-stable\my_kmodules\Makefile
  • 本实验,继承之前的做法,只单独添加test_4.o即可
KDIR := /home/szhou/works/qemu_linux/linux-stable

obj-m := test_1.o test_2.o test_3.o test_4.o
all :
    $(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
    rm -f *.ko

五、编译及部署

1)执行驱动KO编译
shou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ make 
make -C /home/szhou/works/qemu_linux/linux-stable M=/home/szhou/works/qemu_linux/linux-stable/my_kmodules modules
make[1]: Entering directory '/home/szhou/works/qemu_linux/linux-stable'
  CC [M]  /home/szhou/works/qemu_linux/linux-stable/my_kmodules/test_4.o
  MODPOST /home/szhou/works/qemu_linux/linux-stable/my_kmodules/Module.symvers
  LD [M]  /home/szhou/works/qemu_linux/linux-stable/my_kmodules/test_4.ko
make[1]: Leaving directory '/home/szhou/works/qemu_linux/linux-stable'
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$

(2)编译APP,采用 --staitc 静态链接
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ arm-linux-gnueabi-gcc app_test.c -o app_test --static3)将KO和APP存放到NFS共享目录
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ cp test_4.ko ~/works/nfs_share/
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$ cp app_test ~/works/nfs_share/
szhou@bc01:~/works/qemu_linux/linux-stable/my_kmodules$

六、运行及测试

1)启动之前编译组建的QEMU虚拟机
Please press Enter to activate this console.2)挂载NFS共享目录
~ #  mount -t nfs -o nolock 192.168.3.67:/home/szhou/works/nfs_share /mnt

(3)查看设备文件,这时候还没加载驱动,也没创建节点,所以肯定是没有的
~ # ls /dev | grep my
~ # ls /sys/class/misc | grep my

(4) 加载ko
~ # cd /mnt/
/mnt # insmod  test_4.ko 
test_4: loading out-of-tree module taints kernel.
test_4_init
Minor number = 1254)查看设备文件,可见/dev/my_dev 依旧是不存在的(这是因为/dev下的设备并非由驱动创建,而是由/sbin/mdev -s,此处我们就手动创建就行)
/mnt # ls /dev | grep my

(5)查看misc设备,可见已创建 /sys/class/misc/my_dev, 但这是设备目录文件,非设备的用户接口
/mnt # ls /sys/class/misc | grep my
my_dev

(6)手动创建设备文件,主设备号为MISC框架的设备号:10 (日常开发misc,会自动调用 /sbin/mdev -s创建设备,此处虽然已经配置,但我的hotplug还是有问题,暂时用手动创建了)
/mnt # mdev -s (会检查/sys/class下所有dev文件,并创建/dev/xxx),效果等同于下面这个命令
(# mknod /dev/my_dev c 10 125 )

(7)运行测试程序,将执行 fd = open("/dev/my_dev", O_RDONLY);
/mnt # ./app_test 
test_4_open: major=10, minor=125
test_4_read 
test_4_release 
/mnt #

效果图示:

在这里插入图片描述

七、篇尾

略……

相关文章
|
6月前
|
Linux
嵌入式linux系统设备树实例分析
嵌入式linux系统设备树实例分析
107 0
|
3月前
|
Linux
内核实验(五):传统简单字符设备驱动
本文通过一个简单的字符设备驱动程序实验,演示了如何在Linux内核中编写、编译和测试驱动代码,并使用Qemu虚拟机和NFS环境进行部署和验证,同时检验了NFS环境对于提高开发效率的作用。
42 0
内核实验(五):传统简单字符设备驱动
|
5月前
|
Linux
【Linux驱动学习(1)】USB与input子系统,linux统一设备模型,枚举,USB描述符深入剖析
【Linux驱动学习(1)】USB与input子系统,linux统一设备模型,枚举,USB描述符深入剖析
|
6月前
|
存储 缓存 安全
掌握Linux字符设备驱动程序的核心要点
掌握Linux字符设备驱动程序的核心要点
110 0
|
6月前
|
Linux 芯片 开发者
Linux 驱动开发基础知识——内核对设备树的处理与使用(十)
Linux 驱动开发基础知识——内核对设备树的处理与使用(十)
855 0
Linux 驱动开发基础知识——内核对设备树的处理与使用(十)
|
6月前
|
Linux
Linux 驱动开发基础知识——总线设备驱动模型(七)
Linux 驱动开发基础知识——总线设备驱动模型(七)
103 0
Linux 驱动开发基础知识——总线设备驱动模型(七)
|
6月前
|
Linux
Linux 驱动开发基础知识——总线设备驱动模型(八)
Linux 驱动开发基础知识——总线设备驱动模型(八)
97 0
Linux 驱动开发基础知识——总线设备驱动模型(八)
|
6月前
|
Linux API
字符设备驱动(1):Linux字符设备驱动结构
字符设备驱动(1):Linux字符设备驱动结构
92 1
|
6月前
|
Linux API 芯片
Linux 系统的中断子系统基本框架(一)
Linux 系统的中断子系统基本框架(一)
108 0
|
Linux Android开发
Linux misc子系统框架驱动4412蜂鸣器
Linux misc子系统框架驱动4412蜂鸣器
93 0
Linux misc子系统框架驱动4412蜂鸣器