6.块设备驱动程序--二:块设备驱动编写

如何写块设备驱动程序
1., 使用register_blkdev()创建一个块设备
2,以面向对象的思想分配 gendisk 结构体。用 alloc_disk 函数。
3,设置 gendisk 结构体。
①,分配/设置一个队列:request_queue_t. (提供读写能力)用 blk_init_queue 函
数。
②,设置 gendisk 其他信息。(提供磁盘属性:磁盘容量,扇区大小等)
4,注册 gendisk 结构体。用 add_disk 函数

/*13.块驱动程序:分配一段内存,用内存来模拟硬盘:*/

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
#include <linux/io.h>

#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/dma.h>

#define RAMBLOCK_SIZE (1024*1024)           //定义块设备的容量为1M字节

static struct gendisk *ramblock_disk;   //定义gendisk通用磁盘结构体
static struct request_queue *ramblock_queue; //定义请求队列结构体

static int major;                    //定义主设备号
static DEFINE_SPINLOCK(ramblock_lock);      //定义一个自旋锁,用于分配/设置队列

static struct block_device_operations ramblock_fops = {
	.owner	= THIS_MODULE,
};
	

static void do_ramblock_request (request_queue_t * q)
{

}


static int ramblock_init(void)
{
	/*1.分配一个gendisk(通用磁盘)结构体*/
	ramblock_disk = alloc_disk(16);  //次设备号个数:分区个数+1
	
	/*2.设置*/
	/*2.1 分配/设置一个队列request_queue_t. (提供读写能力)*/	
	ramblock_queue=blk_init_queue(do_ramblock_request, &ramblock_lock);      //分配队列
	ramblock_disk->queue = ramblock_queue;         //设置队列
	
	/*2.2设置gendisk其他属性:容量等*/
		major = register_blkdev(0, "ramblock"); //创建一个块设备,当major==0时,表示动态创建,创建成功会返回一个主设备号,可通过 cat 、proc/device查看到
		
		ramblock_disk->major = major;               //主设备号
		ramblock_disk->first_minor = 0;             ///第一个次设备号写为0,则从0~16都对应这个块设备。
		sprintf(ramblock_disk->disk_name, "ramblock");   //块设备的名字
		ramblock_disk->fops = &ramblock_fops;            //必要的操作函数,即使为空也要提供该结构体
//	ramblock_disk->private_data = p;        私有数据不需要

		set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);           //设置容量,单位为扇区个数,扇区=512字节
		
	/*3.注册gendisk结构体,用add_disk函数*/
		add_disk(ramblock_disk);
	
	return 0;
}

static void rmablock_exit(void)
{
	unregister_blkdev(major, "ramblock");   //卸载块设备
	//使用put_disk()和del_gendisk()来注销,释放gendisk结构体
	put_disk(ramblock_disk);
	del_gendisk(ramblock_disk);
	blk_cleanup_queue(ramblock_queue);  //清除内存中的申请队列
		

}

module_init(ramblock_init);
module_exit(rmablock_exit);
MODULE_LICENSE("GPL");




二:入口函数相关API

1.分配一个 gendisk 结构体:allock_disk()

ramblock_disk= allock_disk(16);

alloc_disk (int minors)需要参数“minor+s”是指次设备号个数。即“分区个数
+1”。minors为 1 时,就是把整个磁盘当成一个分区,则在上面不能再创建分
区了。如写成 16,则最多可以创建 15 个分区。
若是说,这个主设备号之下,从哪个次设备号开始都是对应这个块设备。
1
对于一个块设备,次设备号为“0”时,表示整个磁盘。如“/dev/sda”。次设备号“1,
2,、”表示是磁盘的第几个 主 分区。次设备号从 5 开始是“扩展分区”。

2.,分配队列:blk_init_queue()

ramblock_queue = blk_init_queue (do_rambloc_request, &ramblock_lock);

blk_init_queue (request_fn_proc * rfn, spinlock_t * lock) 分配一个队列。
参 1 rfn,执行处理队列的函数。
参 2 lock,一个“自旋锁”。 需提前定义:DEFINE_SPINLOCK (beep_lock)
函数功能:分配一个请求队列,分配成功则返回一个队列结构体
提供读写能力:之前分析把“文件读写”转成“扇区读写”,对“扇区的读写”会放入个队列里面

3.设置gendisk结构体的其他成员

使用register_blkdev()创建一个块设备*/

major = register_blkdev(0, "ramblock"); //创建一个块设备,当major=0时,表示动态创建,创建成功会返回一个主设备号,可通过 cat 、proc/device查看到
	1.	ramblock_disk->major = major;               //主设备号
	2   ramblock_disk->first_minor = 0;             ///第一个次设备号,写为0则从0~16都对应这个块设备。
	3.	sprintf(ramblock_disk->disk_name, "ramblock");   //块设备的名字
	4.	ramblock_disk->fops = &ramblock_fops;            //必要的操作函数,即使为空也要提供该结构体
	5.	set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);           //容量,单位为扇区个数,扇区=512字节
		

1.主设备号:
static int major;
major = register_blkdev(0, “ramblock”); //自动分配主设备号
ramblock_disk->major = major; //属性:主设备号
主设备号可以自已定义,也可以让系统自动分配。

2.,第一个次设备号 和 块设备的名字。
ramblock_disk->first_minor = 0; //第一个次设备号写为0,则从0~16都对应这个块设备。
printf(ramblock_disk->disk_name, “ramblock”); //块设备的名字

3.fops :操作函数。即使是空的操作函数,这个 fops 也要提供。
static struct block_device_operations ramblock_fops = {
.owner = THIS_MODULE,
.ioctl = ramblock_ioctl,
.getgeo = ramblock_getgeo,
};
经过实验,即使这个函数里什么也没有(如没有".ioctl"和".getgeo"),也要提供这个结构体。不然会出错。
ramblock_disk->fops = &ramblock_fops; //必要的操作函数

4.设置队列:
把设置队列放在“分配队列”那一步骤代码紧跟的之下。就是把队列使用起来,即放到
request_queue_t 结构变量 ramblock_queue 里中去。
//2.1,分配/设置队列:提供读写能力
ramblock_queue = blk_init_queue (do_rambloc_request, &ramblock_lock);
ramblock_disk->queue = ramblock_queue; //设置队列

5.容量:设置容量时,是以扇区为单位。
块设备容量 1M 字节
#define RAMBLOCK_SIZE (1024*1024)
set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);
单位是“扇区”,在内核里,对于文件系统那一层,永远认为扇区是 512 字节。

6.处理请求函数:
在“分配/设置队列 blk_init_queue()”函数中,形参 1“request_fn_proc *rfn”是用
来“处理”队列中的请求的函数。
//定义"处理队列请求"的函数
static void do_rambloc_request (request_queue_t * q)
{

}
这里什么也没做,以后慢慢完善。以上一个驱动程序基本上写完了。

4.注册gendisk结构体:add_disk().

add_disk(ramblock_disk);

三:出口函数
1.卸载块设备
unregister_blkdev(major, “ramblock”); //卸载块设备
2.使用put_disk()和del_gendisk()来注销,释放gendisk结构体
put_disk(ramblock_disk);
del_gendisk(ramblock_disk);
3./清除内存中的申请队列
blk_cleanup_queue(ramblock_queue); //清除内存中的申请队列

二:总结步骤过程

步骤如下:

1在入口函数中:

1)使用register_blkdev()创建一个块设备
2) blk_init_queue()使用分配一个申请队列,并赋申请队列处理函数
3)使用alloc_disk()分配一个gendisk结构体
4)设置gendisk结构体的成员
->4.1)设置成员参数(major、first_minor、disk_name、fops)
->4.2)设置queue成员,等于之前分配的申请队列
->4.3)通过set_capacity()设置capacity成员,等于扇区数
5)使用kzalloc()来获取缓存地址,用做扇区
6)使用add_disk()注册gendisk结构体

2在申请队列的处理函数中

  1. while循环使用elv_next_request()获取申请队列中每个未处理的申请
    2)使用rq_data_dir()来获取每个申请的读写命令标志,为 0(READ)表示读, 为1(WRITE)表示写
    3)使用memcp()来读或者写扇区(缓存)
    4)使用end_request()来结束获取的每个申请

3在出口函数中

1)使用put_disk()和del_gendisk()来注销,释放gendisk结构体
2)使用kfree()释放磁盘扇区缓存
3)使用blk_cleanup_queue()清除内存中的申请队列
4)使用unregister_blkdev()卸载块设备

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值