1 #include <linux/module.h>
  2 #include <linux/blkdev.h>
  3 
  4 #define SIMP_BLKDEV_DISKNAME "simp_blkdev"          //块设备名
  5 #define SIMP_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR //主设备号
  6 #define SIMP_BLKDEV_BYTES (1*1024*1024)            // 块设备大小为50MB
  7 #define SECTOR_SIZE_SHIFT 9
  8 
  9 static struct gendisk *simp_blkdev_disk;// gendisk结构表示一个简单的磁盘设备
 10 static struct block_device_operations simp_blkdev_fops = { //块设备操作,gendisk的一个属性
 11     .owner = THIS_MODULE,
 12 };
 13 static struct request_queue *simp_blkdev_queue;//指向块设备请求队列的指针
 14 unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];// 虚拟磁盘块设备的存储空间
 15 
 16 
 17 /******************************************************
 18 *
 19 *   磁盘块设备数据请求的处理函数
 20 *
 21 ******************************************************/
 22 static void simp_blkdev_do_request(struct request_queue *q){
 23     struct request *req;// 正在处理的请求队列中的请求
 24     struct bio *req_bio;// 当前请求的bio
 25     struct bio_vec *bvec;// 当前请求的bio的段(segment)链表
 26     char *disk_mem;      // 需要读/写的磁盘区域
 27     char *buffer;        // 磁盘块设备的请求在内存中的缓冲区
 28     int i = 0;
 29 
 30     while((req = blk_fetch_request(q)) != NULL){
 31         // 判断当前req是否合法
 32         if((blk_rq_pos(req)<<SECTOR_SIZE_SHIFT) + blk_rq_bytes(req) > SIMP_BLKDEV_BYTES){
 33             printk(KERN_ERR SIMP_BLKDEV_DISKNAME":bad request:block=%llu, count=%u\n",(unsigned long long)blk_rq_pos(req),blk_rq_sectors(req));
 34             blk_end_request_all(req, -EIO);
 35             continue;
 36         }
 37         //获取需要操作的内存位置
 38         disk_mem = simp_blkdev_data + (blk_rq_pos(req) << SECTOR_SIZE_SHIFT);
 39         req_bio = req->bio;// 获取当前请求的bio
 40 
 41         switch (rq_data_dir(req)) {  //判断请求的类型
 42         case READ:
 43             // 遍历req请求的bio链表
 44             while(req_bio != NULL){
 45                 // for循环处理bio结构中的bio_vec结构体数组(bio_vec结构体数组代表一个完整的缓冲区)
 46                 for(i=0; i<req_bio->bi_vcnt; i++){
 47                     bvec = &(req_bio->bi_io_vec[i]);
 48                     buffer = kmap(bvec->bv_page) + bvec->bv_offset;
 49                     memcpy(buffer, disk_mem, bvec->bv_len);
 50                     kunmap(bvec->bv_page);
 51                     disk_mem += bvec->bv_len;
 52                 }
 53                 req_bio = req_bio->bi_next;
 54             }
 55             __blk_end_request_all(req, 0);
 56             break;
 57         case WRITE:
 58             while(req_bio != NULL){
 59                 for(i=0; i<req_bio->bi_vcnt; i++){
 60                     bvec = &(req_bio->bi_io_vec[i]);
 61                     buffer = kmap(bvec->bv_page) + bvec->bv_offset;
 62                     memcpy(disk_mem, buffer, bvec->bv_len);
 63                     kunmap(bvec->bv_page);
 64                     disk_mem += bvec->bv_len;
 65                 }
 66                 req_bio = req_bio->bi_next;
 67             }
 68             __blk_end_request_all(req, 0);
 69             break;
 70         default:
 71             /* No default because rq_data_dir(req) is 1 bit */
 72             break;
 73         }
 74     }
 75 }
 76 
 77 
 78 /******************************************************
 79 *
 80 *   模块的入口函数
 81 *
 82 ******************************************************/
 83 static int __init simp_blkdev_init(void){
 84     int ret;
 85 
 86     //1.添加设备之前,先申请设备的资源
 87     simp_blkdev_disk = alloc_disk(1);
 88     if(!simp_blkdev_disk){
 89         ret = -ENOMEM;
 90         goto err_alloc_disk;
 91     }
 92 
 93     //2.设置设备的有关属性(设备名,设备号,fops指针,请求队列,512B的扇区数)
 94     strcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);
 95     simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
 96     simp_blkdev_disk->first_minor = 0;
 97     simp_blkdev_disk->fops = &simp_blkdev_fops;
 98     // 将块设备请求处理函数的地址传入blk_init_queue函数,初始化一个请求队列
 99     simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
100     if(!simp_blkdev_queue){
101         ret = -ENOMEM;
102         goto err_init_queue;
103     }
104     simp_blkdev_disk->queue = simp_blkdev_queue;
105     set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES>>9);
106 
107     //3.入口处添加磁盘块设备
108     add_disk(simp_blkdev_disk);
109     return 0;
110 
111     err_alloc_disk:
112         return ret;
113     err_init_queue:
114         return ret;
115 }
116 
117 
118 /******************************************************
119 *
120 *   模块的出口函数
121 *
122 ******************************************************/
123 static void __exit simp_blkdev_exit(void){
124     del_gendisk(simp_blkdev_disk);// 释放磁盘块设备
125     put_disk(simp_blkdev_disk);   // 释放申请的设备资源
126     blk_cleanup_queue(simp_blkdev_queue);// 清除请求队列
127 }
128 
129 
130 module_init(simp_blkdev_init);// 声明模块的入口
131 module_exit(simp_blkdev_exit);// 声明模块的出口

Makefile文件:

 1 ifneq ($(KERNELRELEASE),) 
 2 MODULE_NAME := blk_ko
 3 OBJGMAC := simp_blkdev.o
 4 
 5 $(MODULE_NAME)-objs := $(OBJGMAC)
 6 obj-m := $(MODULE_NAME).o 
 7 
 8 else
 9 
10 DRIVERDIR := $(shell pwd)
11 KERNELDIR = /home/rayhe/share/rk3288_sdk/rk3288_rt
12 
13 all: 
14     $(MAKE) -C $(KERNELDIR) M=$(DRIVERDIR) modules
15 
16 clean:
17     rm -rf *.o  ./build/*.ko ./gmac/*.o  ./gmac/*.ko *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
18 endif

参考网址:https://blog.csdn.net/cxy_chen/article/details/80998510

posted on 2018-08-07 15:09  Garnett21  阅读(292)  评论(0编辑  收藏  举报