linux驱动内存申请,Linux驱动开发----块设备驱动(内存模拟)Tiny6410

写了好久的字符设备驱动,是时候看下块设备驱动程序设计方法了,块设备驱动和字符设备不同,字符设备是直接和虚拟文件系统进行交互,而块设备驱动则是通过块缓冲/调度层间接和虚拟文件系统交互;块设备驱动数据访问都是以块为单位;多个块I/O需要组成一个请求队列,这个功能是块缓冲/调度层提供的,它出于硬件特性和读写性能的考虑,将块I/O进行重新排序,并组成一个请求队列,交给内核,内核则调用请求队列处理函数来逐个处理请求队列。

大致框架:

1.分配gendisk结构,使用alloc_disk函数

2.分配设置请求队列,提供读写能力

3.设置其他信息,例如容量、名称等

4.硬件相关操作

5.注册(add_disk)

在测试块设备驱动的过程中,刚开始使用的是函数kzmalloc申请1M大小的内存来进行测试,可是驱动加载的时候没有问题,可是当使用mkdosfs格式化的时候报错"short write".,并且在导出到文件上时也提示错误,内核直接崩溃掉。后来改成vmalloc函数就可以了。额。。这是为什么??还没弄明白。。

下面是代码:

#include //module_init/exit

#include //MODULE_AUTHOR,MODULE_LICENSE等

#include //alloc_disk

#include //blk_init_queue

#include //register_blkdev,unregister_blkdev

#include //u_char,u_short

#include

#include

//1MB大小空间

#define RAMBLK_SIZE (1024*1024*2)

/*

//定义驱动私有数据结构

struct ramblk_info{

u_char heads;//磁头数

u_short cylinders;//柱面数

u_char sectors;//扇区数

u_char control;

int unit;

};

*/

static struct gendisk * ramblk_disk = NULL;

static struct request_queue * ramblk_request_queue = NULL;

static int major = 0;//块设备的主设备号

//static struct ramblk_info *pinfo = NULL;

static DEFINE_SPINLOCK(ramblk_spinlock);//定义并初始化一个自旋锁

static char * ramblk_buf = NULL;//申请的内存起始地址

//ramdisk_info初始化函数

/*

static int ramblk_info_init(struct ramblk_info *p)

{

if(!p){

printk("ramblk_info_init p==NULL.\n");

return -1;

}

p->heads = 4;//4个磁头

p->cylinders = 4;//4个柱面

p->sectors = 128;//128个扇区

return 0;

}

*/

int ramblk_getgeo(struct block_device * blk_Dev, struct hd_geometry * hg)

{

hg->cylinders = 64;

hg->heads = 8;

hg->sectors = (RAMBLK_SIZE/8/64/512);

return 0;

}

static const struct block_device_operations ramblk_fops = {

.owner = THIS_MODULE,

.getgeo = ramblk_getgeo,

};

static void do_ramblk_request(struct request_queue *q )

{

struct request *req;

// static volatile int r_cnt = 0;

// static volatile int w_cnt = 0;

//printk("ramblk_request_fn %d.\n",cnt++);

req = blk_fetch_request(q);

while (req) {

unsigned long start = blk_rq_pos(req) << 9;

unsigned long len  = blk_rq_cur_bytes(req);

//   printk("len=%d.\n",len);

if (start + len > RAMBLK_SIZE) {

printk("RAMBLK_SIZE< start+len");

goto done;

}

if (rq_data_dir(req) == READ)

memcpy(req->buffer, (char *)(start+ramblk_buf), len);

else

memcpy((char *)(start+ramblk_buf), req->buffer, len);

done:

if (!__blk_end_request_cur(req, 0))

req = blk_fetch_request(q);

}

}

static int ramblk_init(void)

{

// 1.分配gendisk结构体,使用alloc_disk函数

ramblk_disk = alloc_disk(16);//minors=分区+1

// 2.设置

// 2.1 分配/设置队列,提供读写能力.使用函数blk_init_queue(request_fn_proc *rfn,spin_lock_t *lock)

ramblk_request_queue = blk_init_queue(do_ramblk_request,&ramblk_spinlock);

// 2.2 设置disk的其他信息,比如容量、主设备号等

major = register_blkdev(0,"ramblk");//注册主设备

if(major < 0){//检查是否成功分配一个有效的主设备号

printk(KERN_ALERT "register_blkdev err.\n");

return -1;

}

//设置主设备号

ramblk_disk->major = major;

ramblk_disk->first_minor = 0;//设置第一个次设备号

sprintf(ramblk_disk->disk_name, "ramblk%c", 'a');//设置设备名

ramblk_disk->fops = &ramblk_fops;//设置fops

/*

//分配一个ramdisk_info结构体,并初始化

pinfo =(struct ramblk_info*)kmalloc(sizeof(struct ramblk_info),GFP_KERNEL);

if(!pinfo){

printk("kmalloc pinfo err.\n");

return -1;

}

ramblk_info_init(pinfo);

ramlk_disk->private_data = pinfo;*/

ramblk_disk->queue = ramblk_request_queue;//设置请求队列

set_capacity(ramblk_disk, RAMBLK_SIZE/512);//设置容量

// 3.硬件相关的操作

ramblk_buf = (char*)vmalloc(RAMBLK_SIZE);//申请RAMBLK_SIZE内存

// 4.注册

add_disk(ramblk_disk);//add partitioning information to kernel list

printk("ramblk_init.\n");

return 0;

}

static void ramblk_exit(void)

{

unregister_blkdev(major,"ramblk");//注销设备驱动

blk_cleanup_queue(ramblk_request_queue);//清除队列

del_gendisk(ramblk_disk);

put_disk(ramblk_disk);

vfree(ramblk_buf);//释放申请的内存

printk("ramblk_exit.\n");

}

module_init(ramblk_init);//入口

module_exit(ramblk_exit);//出口

MODULE_AUTHOR("jefby");

MODULE_LICENSE("Dual BSD/GPL");

编译完成后,使用mkdosfs格式化,并挂载到目录test下,读写文件,重新挂载查看文件是否存在,另外,可以导出到文件上,在PC机上测试文件是否正确。

cca5b2ac72ea572ab4386bce4ccf9e55.png

67f17ea9e199a8b4496b9cac8f26aa18.png0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值