块设备驱动程序

一、概念:
Linux操作系统有两类主要的设备文件:
1.字符设备:以字节为单位进行顺序I/O操作的设备,无需缓冲区且被直接读写。

2.块设备:只能以块单位接收输入返回,对于I/O请求有对应的缓冲区,可以随机访问,块设备的访问位置必须能够在介质的不同区间前后移动。在块设备中,最小的可寻址单元是扇区,扇区的大小一般是2的整数倍,常见的大小为512个字节。

二、驱动分析
由于硬件的限制,我们用JZ2440开发板的虚拟内存模拟硬盘进行操作。

2.1 驱动程序的编写框架

 1. 分配gendisk结构体
 2. 设置
    2.1 分配/设置队列,并将它放入结构体中,用来提供读写能力
    2.2 设置gendisk其他信息(主设备号、次设备号、名字、操作函数、容量)
              操作函数:这里面主要调用了ramblock_getgeo函数用来设置硬盘的属性(虽然是RAM模拟的,为了使用 老的工具还是要假装设置一下)
3.硬件相关的操作(就是分配一块内存,比较简单)          
4. 注册: add_disk
5. 请求处理函数(块设备驱动的核心)

当内核需要驱动程序处理读取、写入以及其他的操作时,就会调用该函数





//参考 drivers\block\xd.c
//参考 drivers\block\z2ram.c


#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>


static struct gendisk *ramblock_disk;
static request_queue_t *ramblock_queue;
static int major;
#define RAMBLOCK_SIZE (1024*1024)    /*定义1M的内存作为虚拟块设备 */
static unsigned char *ramblock_buf;


static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
    /* 容量=heads*cylinders*sectors*512 */
    geo->heads     = 2;                         /*多少面 */
    geo->cylinders = 32;                        /*多少环 */
    geo->sectors   = RAMBLOCK_SIZE/2/32/512;    /*一环有多少扇区*/
    return 0;
}

static DEFINE_SPINLOCK(ramblock_lock);

static struct block_device_operations ramblock_fops = {
    .owner  = THIS_MODULE,   /*一个指向拥有该结构的模块指针,通常设为THIS_MODULE  */
    .getgeo = ramblock_getgeo,  /*8几何属性*/
};



static void do_ramblock_request (request_queue_t * q)
{
    static int cnt = 0;
    struct request *req;

    while ((req = elv_next_request(q)) != NULL) {
        /* 数据传输三要素: 源,目的,长度 */
        /* 源/目的: */
        unsigned long offset = req->sector * 512;  /*从哪开始(偏移值)*/

        /* 目的/源: */
        // req->buffer

        /* 长度: */       
        unsigned long len = req->current_nr_sectors * 512; /*需要传送长度*/

        if (rq_data_dir(req) == READ)  //读
        {
            memcpy(req->buffer, ramblock_buf+offset, len); /*将内存中数据拷贝到buffer中*/
        }
        else                           //写
        {
            memcpy(ramblock_buf+offset, req->buffer, len); /*将buffer中的数据拷到内存中  */
        }       

        end_request(req, 1);
    }
}

static int ramblock_init(void)
{
    /*1. 分配一个gendisk结构体*/
    ramblock_disk = alloc_disk(16);   /*次设备号个数 : 分区个数+1*/

    /*2. 设置*/
        /*2.1 分配/设置队列:它提供读写能力/  分配请求队列,绑定请求队列和请求函数*/
    ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);
    ramblock_disk->queue = ramblock_queue;

        /*2.2 设置其他属性:比如说容量*/
    major = register_blkdev(0,"ramblock");   /*写0,由系统分配主设备号*/

    ramblock_disk->major = major;
    ramblock_disk->first_minor = 0;  /*第一个次设备号 */
    sprintf(ramblock_disk->disk_name, "ramblock");
    ramblock_disk->fops         = &ramblock_fops;
    set_capacity(ramblock_disk, RAMBLOCK_SIZE/512);  /*扇区是512字节*/

    /*3. 硬件相关*/
    ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);

    /*4. 注册*/
    add_disk(ramblock_disk);

    return 0;

}

static void ramblock_exit(void)
{
    unregister_blkdev(major,"ramblock");
    del_gendisk(ramblock_disk);
    put_disk(ramblock_disk);
    blk_cleanup_queue(ramblock_queue);
    kfree(ramblock_buf);
}

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

三、测试

  1. insmod ramblock.ko
  2. 格式化: mkdosfs /dev/ramblock
  3. 挂接: mount /dev/ramblock /tmp/
  4. 读写文件: cd /tmp, 在里面vi文件
  5. cd /; umount /tmp/
  6. cat /dev/ramblock > /mnt/ramblock.bin
  7. 在PC上查看ramblock.bin
    sudo mount -o loop ramblock.bin /mnt

也可以 . fdisk /dev/ramblock进行分区测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值