嵌入式开发记录-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

 

posted @ 2020-07-19 23:57  笑不出花的旦旦  阅读(95)  评论(0)    收藏  举报