字符设备驱动(随笔)

    科技2026-08-31  2

    文章目录

    模块代码(1)register_chrdev字符注册函数的作用是什么?(2)怎么查看已经注册好的驱动?(3)驱动的设备号本质的作用是什么?(4)有了驱动,那怎么调用它的函数?(5)字符设备文件怎么与注册了的驱动关联上? 应用程序代码Makefile编写 实验现象 先奉上代码

    模块代码

    #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #define MYMAJOR 0 #define NAME "MyModule" int major; static int module_open(struct inode *inode, struct file *file) { printk("module_open\n"); return 0; } static ssize_t module_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { printk("module_write\n"); return 0; } static ssize_t module_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { printk("module_read\n"); return 0; } static int module_release(struct inode *inode, struct file *file) { printk("module_release\n"); return 0; } static const struct file_operations fops = { .open = module_open, .write = module_write, .read = module_read, .release = module_release, .owner = THIS_MODULE, }; static int __init module_test(void) { printk(KERN_DEBUG "install module_test"); major = register_chrdev(MYMAJOR, NAME, &fops); if (major < 0) { printk(KERN_ERR "register_chrdev failed\n"); return -EINVAL; } printk("module_test major: %d\n",major); } static void __exit module_ex(void) { unregister_chrdev(major, NAME); printk(KERN_DEBUG "uninstall module_test"); } module_init(module_test); module_exit(module_ex); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Zhou");

    (1)register_chrdev字符注册函数的作用是什么?

    首先,我们来看看它需要什么参数。第一个参数输入的主设备号,第二参数传入你的驱动名字,第三个参数传入对应的file_operations结构体。

    reguster_chrdev成功调用后,驱动就被注册到内核的驱动表当中,本质上是将驱动的file_operations结构体注册到内核的驱动表中。

    register_chrdev默认的次设备号是 0. cd = __register_chrdev_region(major, 0, 256, name);这个是内部其中的一行代码。第一个传入注射比号,第二个传入次设备号。

    register_chrdev_region函数,可以区分设备的主次设备号。

    有了注册,应当也有注销驱动。unregister_chrdev

    (2)怎么查看已经注册好的驱动?

    输入命令 cat /proc/devices 可以查看。

    (3)驱动的设备号本质的作用是什么?

    从上图我们可以看到,最左边的一列就是主设备号,从低到高往下排列。主设备号这相当于这一列表的一个索引,最多能存放256个。在调用register_chrdev时,我传入了MYMAJOR,即输入 0,表示内核自动分配一个设备号,它采取的策略是从后往前寻找一个空闲的位置。

    有了驱动的设备号,那么,字符设备就能很轻易地找到它对应的驱动,只要设备号对上了。

    (4)有了驱动,那怎么调用它的函数?

    首先,我们要明确一条的路线: 在应用程序中,操作字符设备文件(open、read、write) --> 字符设备文件的操作已经被重映射到对应的驱动,最终调用的file_operations结构体中的open、read、write。

    (5)字符设备文件怎么与注册了的驱动关联上?

    在 /dev 的文件夹中,mknod MyModule c 248 0新建字符类型的文件,248是主设备号,0是次设备号。这样,就跟驱动关联上。设备号与次设备号必须跟驱动的对应上。

    应用程序代码

    #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #define DEV_DIR "/dev/MyModule" int main(void) { int fd; char buf[10]; //打开字符设备文件 fd = open(DEV_DIR, O_RDWR); if (fd < 0) { perror("open failed!\n"); } //测试是否能打开对应驱动的write和read函数,即file_operations中的函数 write(fd, "12345", 5); //读写的内容可以随意,此处用不上 read(fd, (char*)buf, 10); close(fd); return 0; }

    Makefile编写

    obj-m = module_test.o KER_DIR = /home/iTOP4421/iTop4412_Kernel_3.0 # 开发板Linux内核的位置 PWD = $(shell pwd) all: make -C $(KER_DIR) M=$(PWD) modules arm-linux-gnueabi-gcc -o app app.c .PHONY:clean clean: make -C $(KER_DIR) M=$(PWD) clean

    实验现象

    Processed: 0.010, SQL: 10