Block Device Driver (3) - a simple design block device driver

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
    • /计算设备大小
      dev->size = nsectors*sect_size;
      dev->data = vmalloc(dev->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.
    • 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 */
      };
      
      After the definition of good should blk_init apply a spatial structure for the function dev = kmalloc (sizeof (struct blk_dev ), GFP_KERNEL);
    • 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:
  • // 初始化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, a block write function device requests static void blk_request (struct request_queue Q *) , the parameter is a request queue
    • 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);

 

Guess you like

Origin blog.csdn.net/qq_22847457/article/details/93975105