实现原理:
1. 把"读写"放入队列,先不执行;
2. 优化后再执行(优化/调顺序/合并)。
块设备驱动程序实现:
- 分配gendisk: alloc_disk
- 设置
2.1 分配/设置队列: request_queue// 它提供读写能力
blk_init_queue
2.2 设置gendisk其他信息 // 它提供属性: 比如容量 - 注册: add_disk
使用内存(SDRAM)来构造一个块设备:
源码
#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>
#define RAMBLOCK_SIZE (1024*1024)//1M
static struct gendisk *ramblock_disk;
static struct request_queue *ramblock_queue;
static int major;
static u8 *ramblock_buf;
static DEFINE_SPINLOCK(ramblock_lock);//自旋锁
/*虚拟的*/
static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{ /*容量=面x环x扇区x512*/
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(struct request_queue * q )
{
static int w_cnt=0;
static int r_cnt=0;
struct request *req;
/*获得列队中第一个未完成的请求,没有请求处理时,返回NULL*/
req=blk_fetch_request(q);
while(req!=NULL)//获得列队中第一个未完成的请求
{
/*数据传输三要素:源,目的,长度*/
u32 offset=blk_rq_pos(req) << 9;//源/目的:下一个要提交的扇区*512
u32 len=blk_rq_cur_bytes(req);//长度:当前处理的扇区个数*512
if(rq_data_dir(req)==READ)//读
{
printk("do_ramblock_request read %d\n",++r_cnt);
/*从源读到buff*/
memcpy(req->buffer,ramblock_buf+offset,len);
}
else//rq_data_dir(req)==WRITE
{
printk("do_ramblock_request write %d\n",++w_cnt);
/*从buff写到目的*/
memcpy(ramblock_buf+offset,req->buffer,len);
}
/*结束请求,获取下一个请求*/
if (!__blk_end_request_cur(req, 0))/* 1 = success */
{
req = blk_fetch_request(q);
}
else
{
printk("__blk_end_request_cur error!\n");
}
}
}
static int ramblock_init(void)
{
/*分配一个gendisk结构体-》设置-》注册*/
ramblock_disk=alloc_disk(16);//次设备号个数:分区个数+1
/*分配/设置列队:提供读写能力*/
ramblock_queue=blk_init_queue(do_ramblock_request, &ramblock_lock);
ramblock_disk->queue = ramblock_queue;
major=register_blkdev(0,"ramblock");//注册 得到主设备号
/*设置其他属性*/
ramblock_disk->major = major;
ramblock_disk->first_minor = 0;//第一个次设备号
sprintf(ramblock_disk->disk_name, "ramblock");
ramblock_disk->fops = &ramblock_fops;
/*设置容量 磁盘扇区的个数 扇区(512B)为单位*/
set_capacity(ramblock_disk, RAMBLOCK_SIZE/512);
/*硬件相关操作 分配一块内存*/
ramblock_buf=kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
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");
格式化
挂载、分区