This lesson mainly according to the initialization block and the operation flow analysis device out of a lesson, write their own device driver function block. So this blog is mainly to talk about the use and function of the other frameworks used.
- 1, the preparation of a module frame
- 2, register a block device major = register_blkdev (major, "blk "); It has two parameters, the master device number and device name, generally use core automatically assigned, so here the parameter is 0, the automatic dispensing device number will return as a value obtained. If the return value is less than or equal to 0, indicating the major number allocation fails, an error message and returns -EBUSY (the macro <linux / errno.h> in). The second parameter is the name of the device.
- 3, complete other initialization, the definition of a setup_device function to achieve.
- 3.1 computing device block size
-
3.2 initiates a request queue, using the dev-> Queue = blk_init_queue (blk_request, NULL); , the first parameter is a function in response to the request, this is defined as blk_request, the second parameter is the spinlock is generally empty. The return value is the address of the queue, where we own define a structure to hold the queue./计算设备大小 dev->size = nsectors*sect_size; dev->data = vmalloc(dev->size);
-
After the definition of good should blk_init apply a spatial structure for the function dev = kmalloc (sizeof (struct blk_dev ), GFP_KERNEL);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 */ };
- 3.3 blk_queue_logical_block_size specified equipment sector size, the size parameters are block and request queue
- 3.4 gendisk assigned structure assigned, each device has a block structure gendisk specified in the kernel, using the dev-> Gd = alloc_disk (1); , parameter indicates how many blocks of the device may support the device, where one can fill the sake of simplicity. The saved return gendisk pointer.
- 3.5 complete the initialization of gendisk structure:
-
4, a block write function device requests static void blk_request (struct request_queue Q *) , the parameter is a request queue// 初始化gendisk结构 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, "simp_blk%d", 0); //磁盘名字 set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数
- 4.1 out of the request queue a request, REQ = blk_fetch_request (Q) ; if you do not get empty described, processes the request, and then determines whether the queue is empty, if not empty then process the second request. Here handler by blk_transfer achieved.
- 5, a block write device handler blk_transfer , which parameters include dev interfaces , the operation starting sector , number of sectors operation , store data buffer structure , then the read-write status
- blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
- 6, the preparation of block device to exit the program
- 6.1 cancellation gendiskdel_gendisk (dev-> gd);
- 6.2 Clear Queue blk_cleanup_queue (dev-> queue);
- 6.3 release the allocated space vfree (dev-> data);
- 6.4 cancellation block device unregister_blkdev (major, "blk") ;
- Dev 6.5 release structure kfree (dev);
- The complete code
#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; // 扇区大小
static int nsectors = 1024; // 扇区数
struct blk_dev
{
int size;
u8 *data;
struct request_queue *queue;
struct gendisk *gd;
};
struct blk_dev *dev;
static struct block_device_operations blk_ops =
{
.owner = THIS_MODULE,
};
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 (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_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_device()
{
// 计算块设备的大小
dev->size = nsectors * sect_size;
dev->data = vmalloc(dev->size);
// 初始化一个请求队列
dev->queue = blk_init_queue(blk_request, NULL);
// 指明设备的扇区大小,参数分别为请求队列和块的大小
blk_queue_logical_block_size(dev->queue, sect_size);
// 分配gendisk结构
dev->gd = alloc_disk(1);
// 初始化gendisk结构
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, "simp_blk%d", 0); //磁盘名字
set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数
// 注册gendisk
add_disk(dev->gd);
}
int blk_init()
{
// 注册一个块设备
major = register_blkdev(0, "blk");
if (major <= 0)
{
printk("register blk dev fail!\n");
return -EBUSY;
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
setup_device();
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);