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 ",(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