zl程序教程

您现在的位置是:首页 >  其他

当前栏目

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

2023-04-18 16:49:16 时间

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

一、篇头

使用自行组建的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-stablemy_kmodulesapp_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
", MY_DEV_NAME);
		return -1;
	}
	read(fd, buffer, 64);
	close(fd);
	return 0;
}

4.2 驱动源码

  • 文件名:linux-stablemy_kmodules est_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
", __func__, major, minor);
	return 0;
}

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

	return 0;
}

static ssize_t test_4_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos)
{
	pr_info("%s 
", __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 
", __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
");

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

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

	return 0;
}

static void __exit test_4_exit(void)
{
	pr_info("test_4_exit
");
    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-stablemy_kmodulesMakefile
  • 本实验,继承之前的做法,只单独添加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 # 

效果图示:

在这里插入图片描述

七、篇尾

略……