框架: app: open,read,write "1.txt" --------------------------------------------- 文件的读写 文件系统: vfat, ext2, ext3, yaffs2, jffs2 (把文件的读写转换为扇区的读写) -----------------ll_rw_block----------------- 扇区的读写 1. 把"读写"放入队列 2. 调用队列的处理函数(优化/调顺序/合并) 块设备驱动程序 --------------------------------------------- 硬件: 硬盘,flash <LINUX内核源代码情景分析> 分析ll_rw_block for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; submit_bh(rw, bh); struct bio *bio; // 使用bh来构造bio (block input/output) submit_bio(rw, bio); // 通用的构造请求: 使用bio来构造请求(request) generic_make_request(bio); __generic_make_request(bio); request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列 // 调用队列的"构造请求函数" ret = q->make_request_fn(q, bio); // 默认的函数是__make_request __make_request // 先尝试合并 elv_merge(q, &req, bio); // 如果合并不成,使用bio构造请求 init_request_from_bio(req, bio); // 把请求放入队列 add_request(q, req); // 执行队列 __generic_unplug_device(q); // 调用队列的"处理函数" q->request_fn(q); 怎么写块设备驱动程序呢? 1. 分配gendisk: alloc_disk 2. 设置 2.1 分配/设置队列: request_queue_t // 它提供读写能力 blk_init_queue 2.2 设置gendisk其他信息 // 它提供属性: 比如容量 3. 注册: add_disk 参考: drivers\block\xd.c drivers\block\z2ram.c 测试3th,4th: 在开发板上: 1. insmod ramblock.ko 2. 格式化: mkdosfs /dev/ramblock 3. 挂接: mount /dev/ramblock /tmp/ 4. 读写文件: cd /tmp, 在里面vi文件 5. cd /; umount /tmp/ 6. cat /dev/ramblock > /mnt/ramblock.bin 7. 在PC上查看ramblock.bin sudo mount -o loop ramblock.bin /mnt 测试5th: 1. insmod ramblock.ko 2. ls /dev/ramblock* 3. fdisk /dev/ramblock
驱动程序源代码:
/* 参考: * drivers\block\xd.c * drivers\block\z2ram.c */ #include <linux/module.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/timer.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/wait.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/delay.h> #include <linux/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/dma.h> static struct gendisk *ramblock_disk; static request_queue_t *ramblock_queue; static int major; static DEFINE_SPINLOCK(ramblock_lock); #define RAMBLOCK_SIZE (1024*1024) static unsigned char *ramblock_buf; static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo) { /* 容量=heads*cylinders*sectors*512 */ geo->heads = 2; geo->cylinders = 32; geo->sectors = RAMBLOCK_SIZE/2/32/512; return 0; } static struct block_device_operations ramblock_fops = { .owner = THIS_MODULE, .getgeo = ramblock_getgeo, }; static void do_ramblock_request(request_queue_t * q) { static int r_cnt = 0; static int w_cnt = 0; struct request *req; //printk("do_ramblock_request %d\n", ++cnt); while ((req = elv_next_request(q)) != NULL) { /* 数据传输三要素: 源,目的,长度 */ /* 源/目的: */ unsigned long offset = req->sector * 512; /* 目的/源: */ // req->buffer /* 长度: */ unsigned long len = req->current_nr_sectors * 512; if (rq_data_dir(req) == READ) { //printk("do_ramblock_request read %d\n", ++r_cnt); memcpy(req->buffer, ramblock_buf+offset, len); } else { //printk("do_ramblock_request write %d\n", ++w_cnt); memcpy(ramblock_buf+offset, req->buffer, len); } end_request(req, 1); } } static int ramblock_init(void) { /* 1. 分配一个gendisk结构体 */ ramblock_disk = alloc_disk(16); /* 次设备号个数: 分区个数+1 */ /* 2. 设置 */ /* 2.1 分配/设置队列: 提供读写能力 */ ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); ramblock_disk->queue = ramblock_queue; /* 2.2 设置其他属性: 比如容量 */ major = register_blkdev(0, "ramblock"); /* cat /proc/devices */ ramblock_disk->major = major; ramblock_disk->first_minor = 0; sprintf(ramblock_disk->disk_name, "ramblock"); ramblock_disk->fops = &ramblock_fops; set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512); /* 3. 硬件相关操作 */ ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); /* 4. 注册 */ add_disk(ramblock_disk); return 0; } static void ramblock_exit(void) { unregister_blkdev(major, "ramblock"); del_gendisk(ramblock_disk); put_disk(ramblock_disk); blk_cleanup_queue(ramblock_queue); kfree(ramblock_buf); } module_init(ramblock_init); module_exit(ramblock_exit); MODULE_LICENSE("GPL");