// 参考:
// 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
#include
#include
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;
// 目的/源: (写的时候buffer是源,读的时候buffer是目的,从扇区里读出来放在buffer里)
// 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 ,表示有15个分区
// 2. 设置
// 2.1 分配/设置队列: 提供读写能力
ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);//do_ramblock_request队列处理函数
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); //在内核里面对于文件系统那一层,认为 //扇区永远是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");
==============================================================
框架:
app: open,read,write "1.txt"
--------------------------------------------- 文件的读写
文件系统: vfat, ext2, ext3, yaffs2, jffs2 (把文件的读写转换为扇区的读写)
-----------------ll_rw_block----------------- 扇区的读写
1. 不像字符设备那样提供读写函数,而是把"读写"放入队列