嵌入式开发记录-day21 字符驱动--2 注册字符类设备

1、在前面几节里也有注册设备,但是都是注册杂项设备,并且杂项设备的设备号都是固定的10;

2、应用的函数

// 函数在include/linux/slab.h
// 分配内存空间
void *kmalloc(size_t s, gfp_t gfp)  
// 其中,gfp是枚举类,GFP_KERNEL取值表示内存不够可延迟分配

// 函数路径include/linux/cdev.h
//字符设备初始化
void cdev_init(struct cdev *, const struct file_operations *);
// 添加到内核中
int cdev_add(struct cdev *, dev_t, unsigned);
//卸载设备
void cdev_del(struct cdev *);

//cdev结构体
struct cdev {
        struct kobject kobj;
        struct module *owner;
        const struct file_operations *ops;
        struct list_head list;
        dev_t dev; // 应用这个类型的参数
        unsigned int count;
};

3、实现registercdev.c

  1 #include <linux/init.h>
  2 /*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
  3 #include <linux/module.h>
  4 #include <linux/fs.h>  // 申请设备号函数
  5 #include <linux/kdev_t.h>  // MKDEV宏定义的相关处理
  6 #include <linux/cdev.h>
  7 #include <linux/slab.h>
  8 
  9 MODULE_LICENSE("Dual BSD/GPL");
 10 /*声明是开源的,没有内核版本限制*/
 11 MODULE_AUTHOR("iTOPEET_dz");
 12 /*声明作者*/
 13 
 14 #define DEVICE_NAME "ascdev"  // 注册设备的名称
 15 #define DEVICE_MINOR_NUM 2    // 次设备的个数
 16 #define DEV_MAJOR 0           // 预定以主设备号为0,加载的时候在查询  静态设置设备号
 17 #define DEV_MINOR 0              // 预设次设备号为0 cat /proc/devices
 18 #define REGDEV_SIZE 3000      // 定义注册设备存储数据的大小 相当于读写操作时的缓冲大小
 19 
 20 int numdev_major = DEV_MAJOR;
 21 int numdev_minor = DEV_MINOR;
 22 
 23 struct reg_dev
 24 {
 25     char *data;         // 存放数据 用于读写设备时的缓冲
 26     unsigned long size; // 定义数据长度
 27     struct cdev cdev;    // 包含的操作fops
 28 };
 29 
 30 struct reg_dev *my_devices;
 31 // 简单初始化结构体file_operations
 32 struct file_operations my_fops = {
 33     .owner = THIS_MODULE,
 34 };
 35 
 36 /*输入主设备号*/
 37 module_param(numdev_major,int,S_IRUSR);
 38 /*输入次设备号*/
 39 module_param(numdev_minor,int,S_IRUSR);
 40 
 41 /// 单个设备初始化
 42 static void reg_init_cdev(struct reg_dev* dev,int index)
 43 {
 44     int ret;
 45     int devnum = MKDEV(numdev_major,numdev_minor+index);
 46     
 47     // 设备单个结点初始化
 48     cdev_init(&dev->cdev,&my_fops);
 49     dev->cdev.owner = THIS_MODULE,
 50     dev->cdev.ops = &my_fops,
 51     // 将设备结点加载到内核中
 52     ret = cdev_add(&dev->cdev,devnum,1);
 53     if(ret){
 54         printk(KERN_EMERG "cdev_add %d is fail! %d\n",index,ret);
 55     }
 56     else{
 57         printk(KERN_EMERG "cdev_add %d is success!\n",index);
 58     }
 59 }
 60 
 61 static int scdev_init(void)
 62 {    
 63     int ret = 0,i;
 64     dev_t num_dev;
 65     
 66     printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);
 67     printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);
 68     
 69     if(numdev_major){
 70         // 将设备号转换成可以注册的格式
 71         num_dev = MKDEV(numdev_major,numdev_minor);  
 72         // 将主次设备号注册到linux内核中
 73         ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);  
 74     }
 75     else{ // 动态申请设备号 
 76         // 设备号地址、次设备号、设备号数量、设备号名称
 77         ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM,DEVICE_NAME);
 78         if(ret < 0){
 79             printk(KERN_EMERG "func alloc_chrdev_region was failed!\n");
 80         }
 81         printk(KERN_EMERG "adev_region numdev_major req %d !\n",MAJOR(num_dev));
 82         printk(KERN_EMERG "adev_region numdev_minor req %d !\n",MINOR(num_dev));
 83     }
 84     if(ret<0){
 85         printk(KERN_EMERG "register_chrdev_region req %d is failed!\n",numdev_major);        
 86     }
 87     
 88     // 成功申请设备号,开始分配内存;
 89     // 分配内存是在获取主设备号以后
 90     my_devices = kmalloc(DEVICE_MINOR_NUM* sizeof(struct reg_dev), GFP_KERNEL);
 91     if(!my_devices){
 92         ret = -ENOMEM;
 93         goto fail;
 94     }
 95     // 分配内存完成后,清空内存
 96     memset(my_devices,0,DEVICE_MINOR_NUM* sizeof(struct reg_dev));
 97     for(i=0;i<DEVICE_MINOR_NUM;i++){
 98         // 给缓冲区申请内存
 99         my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);
100         memset(my_devices[i].data,0,REGDEV_SIZE); // 清0
101         // 初始化单个设备
102         reg_init_cdev(&my_devices[i],i);
103     }
104     
105     printk(KERN_EMERG "scdev_init!\n");
106     /*打印信息,KERN_EMERG表示紧急信息*/
107     return 0;
108 
109 fail:
110     unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM); 
111     printk(KERN_EMERG "kmalloc is fail!\n");
112     return ret;
113 }
114 
115 static void scdev_exit(void)
116 {
117     int i=0;
118     printk(KERN_EMERG "hello exit...\n");
119     // 注销注册好的设备号
120     unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);  
121 }
122 
123 // 模块的入口函数
124 module_init(scdev_init);
125 module_exit(scdev_exit);

4、加载结果

[root@iTOP-4412]# insmod /mnt/disk/registercdev.ko                                                 
[   52.639464] numdev_major is 0!
[   52.641156] numdev_minor is 0!
[   52.644130] adev_region numdev_major req 248 !
[   52.648666] adev_region numdev_minor req 0 !
[   52.652869] cdev_add 0 is success!
[   52.656259] cdev_add 1 is success!
[   52.659641] scdev_init!

 

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