#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
static int major = 0;
static int sect_size = 512; //指明每个扇区大小为512
static int nsectors = 1024;
struct blk_dev
{
int size; /* Device size in sectors */
u8 *data; /* The data array */
struct request_queue *queue; /* The device request queue */
struct gendisk *gd; /* The gendisk structure,每一个块设备都有一个gendisk向与之对应 */
};
struct blk_dev *dev;
static struct block_device_operations blk_ops =
{
.ower = THIS_MODULE,
};
/*
* Handle an I/O request, in sectors.
*/
static void blk_transfer(struct blk_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*sect_size; //计算操作起始地址
unsigned long nbytes = nsect*sect_size; //计算操作数据量
if ((offset + nbytes) > dev->size)
{
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else
memcpy(buffer, dev->data + offset, nbytes);
}
/*处理请求队列函数*/
static void blk_request(struct request_queue *q)
{
struct request *req;
/*取出请求队列中的一个请求*/
req = blk_fetch_request(q);
/*判断请求是否为空*/
while (req != NULL)
{
/*
blk_rq_pos():取出起始扇区
blk_rq_cur_sectors():计算操作多少个扇区
req->buffer:磁盘数据读写缓存
rq_data_dir():确定是写还是读
*/
blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
//判断是否为最后一个请求
if(!__blk_end_request_cur(req, 0))
{
//继续取出请求队列中的请求
req = blk_fetch_request(q);
}
}
}
void setup_devce()
{
/*初始化请求队列,第一个参数请求队列处理函数
第二个函数自旋锁,返回值为request_queue请求队列*/
dev->queue = blk_init_queue(blk_request, NULL);
/*设置扇区尺寸,第一个参数为请求队列,第二个参数为扇区大小*/
blk_queue_logical_block_size(dev->queue, sect_size);
/*分配块设备结构,参数表示支持多少个设备*/
dev->gd = alloc_disk(1);
/*初始化dev->gd*/
dev->gd->major = major;
dev->gd->first_minor = 0;
dev->gd->fops = &blk_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
sprintf (dev->gd->disk_name, "Flash_blk%d", 0);
/*设置扇区数个数,第一个参数为需要设备的设备,第二个参数为扇区个数*/
set_capacity(dev->gd, nsectors);
/*向内核注册块设备*/
add_disk(dev->gd);
}
int blk_init()
{
register_blkdev(major, "blk"); //使用动态分配主设备号,使用静态分配可能会造成冲突
if (major <= 0)
{
printk("register blk dev fail.\n");
return -EBUSY; //需要添加<linux/errno.h>
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL); //GFP_KERNEL常规分配
setup_devce();
return 0;
}
void blk_exit()
{
del_gendisk(dev->gd);
blk_cleanup_queue(dev->queue);
vfree(dev->data);
unregister_blkdev(major, "blk");
kfree(dev);
}
module_init(blk_init);
module_exit(blk_exit);
Linux-FLASH驱动设计三
最新推荐文章于 2023-11-30 17:11:23 发布