#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <asm/uaccess.h>
#define BLK_NAME "ram_blk"
#define BLK_MAJOR 222
#define DISK_SECTOR_SIZE 512 //每扇區大小
#define DISK_SECTOR 1024 //總扇區數,
#define DISK_SIZE (DISK_SECTOR_SIZE*DISK_SECTOR)//總大小,共0.5M
typedef struct//裝置結構體
{
unsigned char *data;
struct request_queue *queue;
struct gendisk *gd;
} disk_dev;
disk_dev device;//定義裝置結構體
//--------------------------------------------------------------------------
//在硬碟等帶柱面扇區等的裝置上使用request,可以整理隊列。但是ramdisk等可以
//使用make_request
static int disk_make_request(struct request_queue *q,struct bio *bio)
{
int i;
char *mem_pbuf;
char *disk_pbuf;
disk_dev *pdevice;
struct bio_vec *pbvec;
/*在周遊段之前先判斷要傳輸資料的總長度大小是否超過範圍*/
i=bio->bi_sector*DISK_SECTOR_SIZE+bio->bi_size;
if(i>DISK_SIZE)//判斷是否超出範圍
goto fail;
pdevice=(disk_dev*)bio->bi_bdev->bd_disk->private_data;//得到裝置結構體
disk_pbuf=pdevice->data+bio->bi_sector*DISK_SECTOR_SIZE;//得到要讀寫的起始位置
/*開始周遊這個bio中的每個bio_vec*/
bio_for_each_segment(pbvec,bio,i)//循環分散的記憶體segment
{
mem_pbuf=kmap(pbvec->bv_page)+pbvec->bv_offset;//獲得實際記憶體位址
switch(bio_data_dir(bio))
{//讀寫
case READA:
case READ:
memcpy(mem_pbuf,disk_pbuf,pbvec->bv_len);
break;
case WRITE:
memcpy(disk_pbuf,mem_pbuf,pbvec->bv_len);
break;
default:
kunmap(pbvec->bv_page);
goto fail;
}
kunmap(pbvec->bv_page);//清除映射
disk_pbuf+=pbvec->bv_len;
}
bio_endio(bio,0);//這個函數2.6.25和2.6.4是不一樣的,
return 0;
fail:
bio_io_error(bio);//這個函數2.6.25和2.6.4是不一樣的,
return 0;
}
int blk_open(struct block_device *dev, fmode_t no)
{
return 0;
}
int blk_release(struct gendisk *gd, fmode_t no)
{
return 0;
}
int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)
{
return -ENOTTY;
}
static struct block_device_operations blk_fops=
{
.owner=THIS_MODULE,
.open=blk_open,//
.release=blk_release,//
.ioctl=blk_ioctl,//
};
int disk_init(void)
{
if(!register_blkdev(BLK_MAJOR,BLK_NAME));//注冊驅動
{
printk("register blk_dev succeed\n");
}
device.data=vmalloc(DISK_SIZE);
device.queue=blk_alloc_queue(GFP_KERNEL);//生成隊列
blk_queue_make_request(device.queue,disk_make_request);/*注冊make_request 綁定請求制造函數*/
printk("make_request succeed\n");
device.gd=alloc_disk(1);//生成gendisk
device.gd->major=BLK_MAJOR;//主裝置号
device.gd->first_minor=0;//此裝置号
device.gd->fops=&blk_fops;//塊檔案結構體變量
device.gd->queue=device.queue;//請求隊列
device.gd->private_data=&device;
sprintf(device.gd->disk_name,"disk%c",'a');//名字
set_capacity(device.gd,DISK_SECTOR);//設定大小
add_disk(device.gd);//注冊塊裝置資訊
printk("gendisk succeed\n");
return 0;
}
void disk_exit(void)
{
del_gendisk(device.gd);
put_disk(device.gd);
unregister_blkdev(BLK_MAJOR,BLK_NAME);
vfree(device.data);
printk("free succeed\n");
}
module_init(disk_init);
module_exit(disk_exit);
MODULE_LICENSE("Dual BSD/GPL");