例程代码路径:ELF 1开发板资料包\03-例程源码\03-2 驱动例程源码\02_字符驱动\mydevice-auto 上一节写的驱动加载后,需要手动使用mknod命令在/dev下创建设备节点,本节讲解如何让驱动自动在/dev目录下生成设备节点。 想要实现自动创建节点,首先需要创建设备类,然后创建设备节点并关联到设备类。 在mydevice.c源码的基础上进行添加,重命名为mydevice-auto.c (一)添加头文件 #include (二)声明变量 static struct class *my_class; static struct device *my_device; (三)在mydevice_init(void)函数中创建类和设备节点 static int __init mydevice_init(void) { int ret; // 在这里执行驱动程序的初始化操作 // 注册字符设备驱动程序 ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME); if (ret < 0) { printk(KERN_ALERT "Failed to allocate device number: %d\n", ret); return ret; } major=MAJOR(dev_num); //获取主设备号 minor=MINOR(dev_num); //获取次设备号 printk(KERN_INFO "major number: %d\n",major); printk(KERN_INFO "minor number: %d\n",minor); my_cdev.owner = THIS_MODULE; cdev_init(&my_cdev,&fops); //初始化字符设备结构体 cdev_add(&my_cdev,dev_num,1); //将字符设备添加到内核中 // 创建设备类 my_class = class_create(THIS_MODULE, "my_class"); if (IS_ERR(my_class)) { pr_err("Failed to create class\n"); return PTR_ERR(my_class); } // 创建设备节点并关联到设备类 my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME); if (IS_ERR(my_device)) { pr_err("Failed to create device\n"); class_destroy(my_class); return PTR_ERR(my_device); } printk(KERN_INFO "Device registered successfully.\n"); return 0; } class_create()函数的原型: struct class *class_create(struct module *owner, const char *name); owner:指向拥有该设备类的内核模块的指针。通常使用THIS_MODULE来指定当前驱动模块作为拥有者; name:指定设备类的名称。该名称将用于在sysfs文件系统中创建对应的类目录; class_create()函数返回一个指向新创建的设备类的struct class指针。如果创建失败,它将返回一个指向NULL的指针; 设备类的创建是设备驱动程序中重要的一步,它为设备提供了一个统一的命名空间和属性集合,并将相关设备节点组织在一起。创建设备类后,驱动程序可以使用device_create()函数创建设备节点,并将其关联到该设备类下。 device_create()函数的原型: struct device *device_create(struct class *class, struct device *parent, dev_t dev, void *drvdata, const char *fmt, ...); class:指向设备节点所属的设备类的struct class指针; parent:指向设备节点的父设备的struct device指针,如果没有父设备,则可以设置为NULL; dev:指定设备节点的设备号,使用MKDEV(major, minor)来创建; drvdata:指向与设备节点相关的私有数据的指针,可以将驱动程序的特定数据与设备节点关联起来; fmt:设备节点名称的格式字符串,用于在sysfs文件系统中创建设备节点。可以使用类似"mydevice%d"的格式,并使用可变参数来指定设备节点名称的后缀; device_create()函数返回一个指向新创建的设备节点的struct device指针。如果创建失败,它将返回一个指向NULL的指针; 设备节点的创建需要先创建一个设备类(使用class_create()函数),然后使用device_create()函数创建设备节点并将其关联到设备类下; (四)mydevice_exit(void)函数中添加销毁设备节点和设备类 static void __exit mydevice_exit(void) { // 在这里执行驱动程序的清理操作 // 销毁设备节点 device_destroy(my_class, MKDEV(major, minor)); // 销毁设备类 class_destroy(my_class); // 删除字符设备 cdev_del(&my_cdev); // 注销字符设备驱动程序 unregister_chrdev(0, DEVICE_NAME); printk(KERN_INFO "Device unregistered.\n"); } mydevice-auto.c完整示例源码 #include // 包含模块相关函数的头文件 #include // 包含文件系统相关函数的头文件 #include // 包含用户空间数据访问函数的头文件 #include //包含字符设备头文件 #include #define DEVICE_NAME "mydevice" // 设备名称 static dev_t dev_num; //分配的设备号 struct cdev my_cdev; //字符设备指针 int major; //主设备号 int minor; //次设备号 static struct class *my_class; static struct device *my_device; static int device_open(struct inode *inode, struct file *file) { // 在这里处理设备打开的操作 printk(KERN_INFO "This is device_open.\n"); return 0; } static int device_release(struct inode *inode, struct file *file) { // 在这里处理设备关闭的操作 printk(KERN_INFO "This is device_release.\n"); return 0; } static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { // 在这里处理设备读取的操作 printk(KERN_INFO "This is device_read.\n"); return 0; } static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { // 在这里处理设备写入的操作 printk(KERN_INFO "This is device_write.\n"); return 0; } static struct file_operations fops = { .owner = THIS_MODULE, .open = device_open, .release = device_release, .read = device_read, .write = device_write, }; static int __init mydevice_init(void) { int ret; // 在这里执行驱动程序的初始化操作 // 注册字符设备驱动程序 ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME); if (ret < 0) { printk(KERN_ALERT "Failed to allocate device number: %d\n", ret); return ret; } major=MAJOR(dev_num); //获取主设备号 minor=MINOR(dev_num); //获取次设备号 printk(KERN_INFO "major number: %d\n",major); printk(KERN_INFO "minor number: %d\n",minor); my_cdev.owner = THIS_MODULE; cdev_init(&my_cdev,&fops); //初始化字符设备结构体 cdev_add(&my_cdev,dev_num,1); //将字符设备添加到内核中 // 创建设备类 my_class = class_create(THIS_MODULE, "my_class"); if (IS_ERR(my_class)) { pr_err("Failed to create class\n"); return PTR_ERR(my_class); } // 创建设备节点并关联到设备类 my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME); if (IS_ERR(my_device)) { pr_err("Failed to create device\n"); class_destroy(my_class); return PTR_ERR(my_device); } printk(KERN_INFO "Device registered successfully.\n"); return 0; } static void __exit mydevice_exit(void) { // 在这里执行驱动程序的清理操作 // 销毁设备节点 device_destroy(my_class, MKDEV(major, minor)); // 销毁设备类 class_destroy(my_class); // 删除字符设备 cdev_del(&my_cdev); // 注销字符设备驱动程序 unregister_chrdev(0, DEVICE_NAME); printk(KERN_INFO "Device unregistered.\n"); } module_init(mydevice_init); module_exit(mydevice_exit); MODULE_LICENSE("GPL"); // 指定模块的许可证信息 MODULE_AUTHOR("Your Name"); // 指定模块的作者信息 MODULE_DESCRIPTION("A simple character device driver"); // 指定模块的描述信息 编译 Makefile文件如下: ![]() . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi elf@ubuntu:~/work/test/02_字符驱动/mydevice-auto$ make 将生成的mydevice.ko文件拷贝到开发板中。 编写测试应用源码device-auto_app.c 驱动中已经给应用层提供了open、read、write的接口,接下来应用层就可以进行相应的系统调用。 #include #include #include #include #include #include #define DEV_NAME "/dev/my_device" int main(int argc, char *argv[]) { int reg; int fd = 0; int dat = 0; fd = open (DEV_NAME, O_RDWR); if (fd < 0) { perror("Open "DEV_NAME" Failed!\n"); exit(1); } reg = read(fd, &dat, 1); if (reg<0) { perror("read "DEV_NAME" Failed!\n"); exit(1); } dat = 0; reg = write(fd, &dat, 1); if (reg<0) { perror("write "DEV_NAME" Failed!\n"); exit(1); } close(fd); return 0; } 设置环境变量: . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi 编译,将生成的device-auto_app文件拷贝到开发板中: elf@ubuntu:~/work/test/02_字符驱动/device-auto_app$ $CC device-auto_app.c -o d\evice-auto_app 测试 root@ELF1:~# insmod mydevice-auto.ko major number: 245 minor number: 0 Device registered successfully. root@ELF1:~# ls /dev/my_device /dev/my_device root@ELF1:~# ./device-auto_app This is device_open. This is device_read. This is device_write. This is device_release. root@ELF1:~# rmmod mydevice-auto.ko Device unregistered. 可以看出在使用insmod加载驱动后,在/dev下就生成了my_device节点,使用device_app测试正常。 |
234 浏览 0 评论
迅为RK3568开发板helloworld 驱动实验-驱动编写
484 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-platform总线驱动简单示例
635 浏览 0 评论
智能配电新纪元:基于飞凌嵌入式T536核心板的DTU解决方案
819 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中的中断之按键中断驱动
1582 浏览 0 评论