【驱动】第7课、块设备驱动之学习笔记
主 机:VMWare--Ubuntu-16.04.2-x64-100ask
开发板:Mini2440--256M NandFlash, 2M NorFlash, 64M SDRAM, LCD-TD35;
bootlorder:u-boot1.16, Kernel:2.6.22.6;
编译器:arm-linux-gcc-3.4.5
目录
【课堂笔记】
框架:
app: open,read,write "1.txt"
--------------------------------------------- 文件的读写
文件系统: vfat, ext2, ext3, yaffs2, jffs2 (把文件的读写转换为扇区的读写)
-----------------ll_rw_block----------------- 扇区的读写
1. 把"读写"放入队列
2. 调用队列的处理函数(优化/调顺序/合并)
块设备驱动程序
---------------------------------------------
硬件: 硬盘,flash
【编程】
参考:
drivers\block\xd.c
drivers\block\z2ram.c
目的:分配一块内存,用这块内存作为块设备模拟硬盘;
一、驱动框架
1、分配一个gendisk结构体;
2、设置
2.1分配/设置一个队列:request_queue_t, 提供(块设备的)读写能力;
blk_init_queue();
2.2设置gendisk其他信息/属性(6项),比如:主设备号,次设备首号,名字,操作函数,容量,队列;
3、硬件操作:为块设备读写操作分配内存;
4、注册gendisk结构体;
add_disk(ramblock_disk);
5、操作函数所在fops结构体;
函数分配与回滚:
ramblock_disk = alloc_disk(16); 对应 put_disk(ramblock_disk); del_gendisk(ramblock_disk);
q = blk_init_queue(); 对应 blk_cleanup_queue(q);
register_blkdev(0, "ramblock"); 对应unregister_blkdev(major, "ramblock");
二、硬件相关的操作
1、硬件操作:为块设备读写操作分配内存;
2、在读写操作队列处理函数:do_xx_request()中,对读/写队列进行处理,然后结束队列;
fops = {... .getgeo = ramblock_getgeo,}
【测试】
1、块设备驱动,实验找不到mkdosfs命令?
答:开发板的文件系统缺少mkdosfs可执行文件!
2、硬件操作分配的内存 ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL),是为块设备读写操作分配的数据缓冲区,
还是为块设备本身分配的内存?
答:是为块设备本身分配的内存,为队列里读/写操作分配的数据缓冲区是struct request *req->buffer;该数据缓冲区貌
似是内核自己分配的,没有让驱动开发者手动分配!
3、网络文件系统上的ramblock9.ko没有删除直接用新文件上传覆盖时,测试(不正常):
Device Boot Start End Blocks Id System
/dev/ramblock1 1 5 288 83 Linux
Partition 1 has different physical/logical endings:
phys=(260, 1, 0) logical=(4, 1, 64)
Partition 1 does not end on cylinder boundary
Command (m for help): n
用rm命令手动删除该ramblock9.ko文件,然后再从服务器cp该文件到单板网络文件系统测试(正常):
Device Boot Start End Blocks Id System
/dev/ramblock1 1 5 144 83 Linux
Command (m for help):
总结:已经是第二次遇到这个问题了,文件并没有随着最新时间的相同文件的上传而被覆盖,相反旧文件覆盖了新文件或者没更新旧文件!
这是为什么呢?
ramblock9.c
1 /* 2 * 2019-01-10 3 * 目的: 分配一块内存,用这块内存做块设备模拟硬盘; 4 */ 5 #include <linux/module.h> 6 #include <linux/errno.h> 7 #include <linux/interrupt.h> 8 #include <linux/mm.h> 9 #include <linux/fs.h> 10 #include <linux/kernel.h> 11 #include <linux/timer.h> 12 #include <linux/genhd.h> 13 #include <linux/hdreg.h> 14 #include <linux/ioport.h> 15 #include <linux/init.h> 16 #include <linux/wait.h> 17 #include <linux/blkdev.h> 18 #include <linux/blkpg.h> 19 #include <linux/delay.h> 20 #include <linux/io.h> 21 22 #include <asm/system.h> 23 #include <asm/uaccess.h> 24 #include <asm/dma.h> 25 26 #define RAMBLOCK_SIZE (1024*1024) 27 MODULE_LICENSE("GPL"); 28 29 static struct gendisk *ramblock_disk; 30 static request_queue_t *ramblock_queue; 31 static DEFINE_SPINLOCK(ramblock_lock); 32 static int major; 33 static unsigned char *ramblock_buf; 34 35 /* 读写操作请求队列处理函数 */ 36 static void do_ramblock_request(request_queue_t *q) 37 { 38 struct request *req; 39 while((req = elv_next_request(q)) != NULL) 40 { 41 /* 数据传输三要素: 源,长度,目的地 */ 42 unsigned long offset = req->sector*512; /* 写入为目的地,读出为源 */ 43 unsigned long len = req->current_nr_sectors*512; 44 if(rq_data_dir(req) == READ) 45 { 46 memcpy(req->buffer, ramblock_buf + offset, len); 47 } 48 else 49 { 50 memcpy(ramblock_buf + offset, req->buffer, len); 51 } 52 53 end_request(req, 1); 54 } 55 } 56 57 static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo) 58 { 59 geo->heads = 2; 60 geo->cylinders = 32; 61 geo->sectors = RAMBLOCK_SIZE/2/32/512; 62 return 0; 63 } 64 65 static struct block_device_operations ramblock_fops = { 66 .owner = THIS_MODULE, 67 .getgeo = ramblock_getgeo, 68 }; 69 70 static int ramblock_init(void) 71 { 72 int err; 73 /* 1.分配一个gendisk结构体 */ 74 ramblock_disk = alloc_disk(16); 75 if(!ramblock_disk) 76 { 77 printk(KERN_ERR "Unable to allocate ramblock_disk gendisk!\n"); 78 err = -ENOMEM; 79 goto err_fail1; 80 } 81 /* 2.配置该结构体 */ 82 /* 2.1分配/设置一个队列: 提供读写能力 */ 83 ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); 84 if(!ramblock_queue) 85 { 86 printk(KERN_ERR "Unable to prepare ramblock_queue request queue!\n"); 87 err = -ENOMEM; 88 goto err_fail2; 89 } 90 /* 2.2其他属性: 主设备号,次设备首号,操作函数,队列,名字,容量等 */ 91 major = register_blkdev(0, "ramblock"); 92 if(!major) 93 { 94 printk(KERN_ERR "Unable to register ramblock block device!\n"); 95 err = -EBUSY; 96 goto err_fail3; 97 } 98 ramblock_disk->major = major; 99 ramblock_disk->first_minor = 0; 100 sprintf(ramblock_disk->disk_name, "ramblock"); 101 ramblock_disk->fops = &ramblock_fops; 102 ramblock_disk->queue = ramblock_queue; 103 set_capacity(ramblock_disk, RAMBLOCK_SIZE/512); //容量: 扇区数目; 104 /* 3.硬件相关的配置 */ 105 ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); 106 if(!ramblock_buf) 107 { 108 printk(KERN_ERR "Unable to allocate ramblock_buf buffer!\n"); 109 err = -ENOMEM; 110 goto err_fail4; 111 } 112 /* 4.注册该结构体 */ 113 add_disk(ramblock_disk); 114 return 0; 115 err_fail4: 116 kfree(ramblock_buf); 117 err_fail3: 118 unregister_blkdev(major, "ramblock"); 119 err_fail2: 120 blk_cleanup_queue(ramblock_queue); 121 err_fail1: 122 put_disk(ramblock_disk); 123 del_gendisk(ramblock_disk); 124 return err; 125 } 126 127 static void ramblock_exit(void) 128 { 129 unregister_blkdev(major, "ramblock"); 130 blk_cleanup_queue(ramblock_queue); 131 put_disk(ramblock_disk); 132 del_gendisk(ramblock_disk); 133 kfree(ramblock_buf); 134 } 135 136 module_init(ramblock_init); 137 module_exit(ramblock_exit);
Makefile:
1 ifneq ($(KERNELRELEASE),) 2 obj-m := ramblock9.o 3 else 4 KERN_DIR ?= /home/book/workbook/mini2440/systems/linux-2.6.22.6 5 6 PWD = $(shell pwd) 7 all: 8 $(MAKE) -C $(KERN_DIR) M=$(PWD) modules 9 clean: 10 $(MAKE) -C $(KERN_DIR) M=$(PWD) modules clean 11 rm -rf modules.order 12 13 endif