嵌入式开发记录-day22 字符驱动 --3 生成字符类设备结点
1、在这里的设备结点类似于led,那么可能会有很多个led,为了更好的管理,一般创建每一个led的各个结点时,必须创建一个属于led的类;在这个led类中,可以、创建多个子结点,类似于led1,led2....,本节就生成设备结点chardevnode0和设备结点chardevnode1
2、用到的头文件include/linux/device.h
//1、 创建设备文件 define class_create(owner, name) 一般是THIS_MODULE,设备名称 //2、 销毁设备类文件 void class_destroy(struct class *cls); // class类在头文件include/linux/device.h的280行 //3、 创建设备结点 // class结构体变量 父设备 struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, // dev_t设备号,数据NULL const char *fmt, ...)// 设备结点名称 __attribute__((format(printf, 5, 6))); //4、 销毁设备结点 void device_destroy(struct class *cls, dev_t devt); //5、 kfree() 释放内存
3、实现creatcnode.c
1 #include <linux/init.h> 2 /*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/ 3 #include <linux/module.h> 4 /*定义module_param module_param_array的头文件*/ 5 #include <linux/moduleparam.h> 6 /*定义module_param module_param_array中perm的头文件*/ 7 #include <linux/stat.h> 8 9 /*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/ 10 11 #include <linux/fs.h> // 申请设备号函数 12 #include <linux/kdev_t.h> // MKDEV宏定义的相关处理 13 #include <linux/cdev.h> 14 #include <linux/slab.h> 15 #include <linux/device.h> // 创建字符设备类 16 17 #define DEVICE_NAME "chardevnode" // 注册的设备名称 18 #define DEVICE_MINOR_NUM 2 // 次设备的个数 19 #define DEV_MAJOR 0 // 预定以主设备号为0,加载的时候在查询 20 #define DEV_MINOR 0 // 预设次设备号为0 cat /proc/devices 21 #define REGDEV_SIZE 3000 // 定义注册设备存储数据的大小 22 23 MODULE_LICENSE("Dual BSD/GPL"); 24 /*声明是开源的,没有内核版本限制*/ 25 MODULE_AUTHOR("iTOPEET_dz"); 26 /*声明作者*/ 27 28 int numdev_major = DEV_MAJOR; 29 int numdev_minor = DEV_MINOR; 30 31 /*输入主设备号*/ 32 module_param(numdev_major,int,S_IRUSR); 33 /*输入次设备号*/ 34 module_param(numdev_minor,int,S_IRUSR); 35 36 static struct class* myclass; 37 38 struct reg_dev 39 { 40 char *data; // 存放数据 41 unsigned long size; // 定义数据长度 42 struct cdev cdev; 43 }; 44 45 struct reg_dev *my_devices; // 子设备类型 46 47 struct file_operations my_fops = { 48 .owner = THIS_MODULE, 49 }; 50 51 52 /// 单个设备初始化 53 static void reg_init_cdev(struct reg_dev* dev,int index) 54 { 55 int ret; 56 // 得到设备号 57 int devnum = MKDEV(numdev_major,numdev_minor+index); 58 59 // 初始化结构体数据 60 cdev_init(&dev->cdev,&my_fops); 61 dev->cdev.owner = THIS_MODULE; 62 dev->cdev.ops = &my_fops; 63 64 // 将设备添加到内核中 65 ret = cdev_add(&dev->cdev,devnum,1); 66 if(ret){ 67 printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,ret); 68 } 69 else{ 70 printk(KERN_EMERG "cdev_add %d is success!\n",numdev_minor+index); 71 } 72 } 73 74 static int scdev_init(void) 75 { 76 int ret = 0,i; 77 dev_t num_dev; 78 79 printk(KERN_EMERG "numdev_major is %d!\n",numdev_major); 80 printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor); 81 82 if(numdev_major){ 83 // 将设备号转换成可以注册的格式 84 num_dev = MKDEV(numdev_major,numdev_minor); 85 // 将主次设备号注册到linux内核中 86 ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME); 87 } 88 else{ // 动态申请设备号 89 // 设备号地址、次设备号、设备号数量、设备号名称 90 ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM,DEVICE_NAME); 91 92 numdev_major = MAJOR(num_dev); // 根据设备号获取主设备号 93 printk(KERN_EMERG "adev_region numdev_major req %d !\n",MAJOR(num_dev)); 94 printk(KERN_EMERG "adev_region numdev_minor req %d !\n",MINOR(num_dev)); 95 } 96 if(ret<0){ 97 printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major); 98 } 99 // 创建一个叫做chardevnode的设备类 100 myclass = class_create(THIS_MODULE,DEVICE_NAME); 101 102 // 成功申请设备号,开始分配内存; 103 // 分配内存是在获取主设备号以后 104 my_devices = kmalloc(DEVICE_MINOR_NUM* sizeof(struct reg_dev), GFP_KERNEL); 105 if(!my_devices){ 106 ret = -ENOMEM; 107 goto fail; 108 } 109 // 分配内存完成后,清空内存 110 memset(my_devices,0,DEVICE_MINOR_NUM* sizeof(struct reg_dev)); 111 // 初始化设备 112 for(i=0;i<DEVICE_MINOR_NUM;i++){ 113 my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL); 114 memset(my_devices[i].data,0,REGDEV_SIZE); 115 // 设备注册到系统中 116 reg_init_cdev(&my_devices[i],i); 117 118 // 创建设备结点 会在ls /dev/下创建结点 根据主设备号创建设备结点 119 device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL ,DEVICE_NAME"%d",i); 120 } 121 122 printk(KERN_EMERG "scdev_init!\n"); 123 /*打印信息,KERN_EMERG表示紧急信息*/ 124 return 0; 125 126 fail: 127 unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 128 printk(KERN_EMERG "kmalloc is fail!\n"); 129 return ret; 130 } 131 132 static void scdev_exit(void) 133 { 134 int i=0; 135 printk(KERN_EMERG "scdev exit...\n"); 136 // 注销注册好的设备号 137 //unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 138 for(i=0;i<DEVICE_MINOR_NUM;i++){ 139 cdev_del(&(my_devices[i].cdev)); 140 device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i)); 141 } 142 143 class_destroy(myclass); 144 kfree(my_devices); 145 146 unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 147 } 148 149 // 模块的入口函数 150 module_init(scdev_init); 151 module_exit(scdev_exit);
4、加载测试
[root@iTOP-4412]# mount /dev/sda1 /mnt/disk [root@iTOP-4412]# insmod /mnt/disk/creatcnode.ko [ 55.084594] numdev_major is 0! [ 55.086261] numdev_minor is 0! [ 55.089248] adev_region numdev_major req 248 ! [ 55.093731] adev_region numdev_minor req 0 ! [ 55.098998] cdev_add 0 is success! [ 55.102766] cdev_add 1 is success! [ 55.106063] scdev_init! // 并且可以查看到生成的设备结点 ls /dev // 可以看到chardevnode0 和chardevnode1

浙公网安备 33010602011771号