
由上一篇中的字符设备可知我们需要定义设备号,设备号分为主设备号和次设备号,比如上篇中定义的主设备号为200,次设备号为:0。其中主设备号和次设备号必须未被其他设备使用。由ls /dev/ -l可以看到所有的设备号。 新字符设备就是想办法实现动态分配设备号,这样既可以简化操作也可以防止设备号冲突。 打开led.c,首先把设备号,改为设备个数 #define LED_MAJOR 200 改为#define LED_MAJOR 1 // 设备号个数 设备名称改为newled 然后需要定义一个字符设备结构体用于设备号的分配: struct newchrled_dev{ dev_t devid; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ }; struct newchrled_dev newchrled; /* led 设备 */ 在驱动程序的open中需要加入设备的动态分配结构: static int led_open(struct inode *inode,struct file *filp) { printk("led_open!\r\n"); /*在open文件中加入设备动态分配结构体*/ filp->private_data= &newchrled; return0; } 然后需要修改设备接口程序led_init,在加载设备的时候获取设备号: 原来的程序是 retvalue = register_chrdev(LED_MAJOR,LED_NAME, &led_fops); 直接注册了设备号和设备名称,在现在不知道设备号,所以需要获取设备号然后再创建设备,其步骤为: 获取设备号-》初始化设备-》加载设备号-》创建设备类-》创建设备 1、 获取设备号,新字符设备在结构体中也可以自己设置设备号,如果自己设置则把自己设置的设备号加载进去,如果未设置设备号则alloc_chrdev_region自动获取并且加载: if (newchrled.major) { // 如果定义了设备号 newchrled.devid =MKDEV(newchrled.major, 0); //获取定义的设备号 ret =register_chrdev_region(newchrled.devid, LED_MAJOR,LED_NAME); //注册已定义的设备号、设备个数、设备名 if(ret < 0) { pr_err("cannotregister %s char driver [ret=%d]\n",LED_NAME, LED_MAJOR); goto fail_map; } } else { // 如果没有定义设备号 ret =alloc_chrdev_region(&newchrled.devid, 0, LED_MAJOR,LED_NAME); //申请设备号并且注册设备号、设备个数、设备名 if(ret < 0) { pr_err("%sCouldn't alloc_chrdev_region, ret=%d\r\n", LED_NAME, ret); goto fail_map; } newchrled.major =MAJOR(newchrled.devid); // 获取主设备号 newchrled.minor =MINOR(newchrled.devid); // 获取次设备号 } 2、 设备号定义后需要把设备结构体和设备驱动关联起来,此处需要对newchrled进行初始化: newchrled.cdev.owner = THIS_MODULE; //定义设备结构体的owner 默认设置为THIS_MODULE cdev_init(&newchrled.cdev,&led_fops); //初始化设备结构体关联到led_fops驱动接口 3、 需要在初始化后的设备结构体中添加以获取的设备号: ret = cdev_add(&newchrled.cdev, newchrled.devid, LED_MAJOR); if(ret < 0) goto del_unregister; 4、 接下来把设备名写入设备结构体,创建为一个设备类: newchrled.class = class_create(THIS_MODULE, LED_NAME); if (IS_ERR(newchrled.class)) { goto del_cdev; } 5、 最后创建设备: newchrled.device = device_create(newchrled.class, NULL,newchrled.devid,NULL, LED_NAME); if (IS_ERR(newchrled.device)) { goto destroy_class; } 如果中间有错误,则清除对应的操纵并推出函数: , t! g- b9 Z0 X+ h/ S" T5 odestroy_class: class_destroy(newchrled.class);//删除类 del_cdev: cdev_del(&newchrled.cdev); //删除设备号 del_unregister: unregister_chrdev_region(newchrled.devid,LED_MAJOR);//删除设备关联 fail_map: /* 取消映射 */ iounmap(MPU_AHB4_PERIPH_RCC_PI); iounmap(GPIOI_MODER_PI); iounmap(GPIOI_OTYPER_PI); iounmap(GPIOI_OSPEEDR_PI); iounmap(GPIOI_PUPDR_PI); iounmap(GPIOI_BSRR_PI); return -EIO; 在卸载驱动接口中也需要加入设备号、设备类、设备关联状态的清除: //卸载驱动 static void __exit led_exit(void) { printk("led_exit!\r\n"); /* 取消映射 */ iounmap(MPU_AHB4_PERIPH_RCC_PI); iounmap(GPIOI_MODER_PI); iounmap(GPIOI_OTYPER_PI); iounmap(GPIOI_OSPEEDR_PI); iounmap(GPIOI_PUPDR_PI); iounmap(GPIOI_BSRR_PI); ) X: _% h6 w7 c6 Z' o( e, _0 D cdev_del(&newchrled.cdev); //删除设备号 unregister_chrdev(LED_MAJOR,LED_NAME);/* 注销字符设备驱动 */ ; X2 d5 b. |& l6 y( J/ F unregister_chrdev_region(newchrled.devid,LED_MAJOR);//删除设备关联 class_destroy(newchrled.class);//删除类 } 到此程序编写完毕,开始测试: ![]() |
基于STM32MP1和STM32MP2在嵌入式Linux平台上部署有效的安全保护机制
利用STM32MP1和STM32MP2为嵌入式Linux提供有效的安全措施:供当今决策者参考的3条宝贵经验
STM32MP1 WiFi连接
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【STM32MPU 安全启动】 TF-A BL2 TrustedBoot原理学习
《STM32MPU安全启动》学**结
《STM32MPU安全启动》学习笔记之optee 如何加载CORTEX-M核和使能校验
《STM32MPU安全启动》学习笔记之TF-A BL2校验optee和uboot的流程以及如何使能
《STM32MPU 安全启动》课程学习心得+开启一扇通往嵌入式系统安全领域深处的大门。
《STM32MPU安全启动》 课程学习心得