Linux设备驱动开发 - 块设备驱动ramdisk实例

By: fulinux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!

在这里插入图片描述

理论来源

ramdisk驱动,区别在与使用最新的内核版本,比如linux-4.15。只做个简单记录,理论知识我就不贴了~
参考来源:韦东山二期驱动视频-块设备驱动1

源码

代码ramdisk.c:

#include <linux/major.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/hdreg.h>

#include <asm/setup.h>

#define DEVICE_NAME "myrb"
#define MYRAMBLOCK_SIZE (1024 * 1024)

static int major = 0;
static unsigned char *myrb_buf;

static DEFINE_SPINLOCK(myrb_lock);

static struct gendisk *myrb_gendisk;
static struct request_queue *myrb_queue;

static int myrb_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
    /* 容量=heads * cylinders * sectors * 512 */
    geo->heads = 2;
    geo->cylinders = 32;
    geo->sectors = MYRAMBLOCK_SIZE / geo->heads / geo->cylinders / 512;
    return 0;
}

static const struct block_device_operations myrb_fops = {
    .owner  = THIS_MODULE,
    .getgeo = myrb_getgeo,
};

static void do_myrb_request(struct request_queue *q)
{
    static int r_cnt = 0;
    static int w_cnt = 0;
    struct request *req;

    req = blk_fetch_request(q);
    while(req) {
        /* 数据传输三要素:源,目的,长度 */
        unsigned long offset = blk_rq_pos(req) << 9;
        /* 目的/源 */
        //req->buffer

        /* 长度 */
        unsigned long len = blk_rq_cur_bytes(req);
        void *buffer = bio_data(req->bio);
        blk_status_t err = BLK_STS_OK;

        if (offset + len > MYRAMBLOCK_SIZE) {
            pr_err(DEVICE_NAME ": bad access: block=%llu, "
                    "count=%u\n",
                    (unsigned long long)blk_rq_pos(req),
                    blk_rq_cur_sectors(req));
            err = BLK_STS_IOERR;
            goto done;
        }

        if (rq_data_dir(req) == READ) {
            printk("do_myrb_request read %d len = %d\n", ++r_cnt, len);
            memcpy(buffer, myrb_buf + offset, len);
        } else {
            printk("do_myrb_request write %d\n", ++w_cnt);
            memcpy(myrb_buf + offset, buffer, len);
        }
done:
        if (!__blk_end_request_cur(req, err))
            req = blk_fetch_request(q);
    }
}

static int __init myrb_init(void)
{
    int ret;

    printk("Hello World!\n");

    ret = -EBUSY;
    major = register_blkdev(0, DEVICE_NAME);
    if (major <= 0)
        goto err;

    /* 1. 分配一个gendisk结构体 */
    ret = -ENOMEM;
    myrb_gendisk = alloc_disk(1);
    if (!myrb_gendisk) {
        goto out_disk;
    }

    myrb_queue = blk_init_queue(do_myrb_request, &myrb_lock);
    if (!myrb_queue)
        goto out_queue;

    myrb_gendisk->major = major;
    myrb_gendisk->first_minor = 0;
    myrb_gendisk->fops = &myrb_fops;
    sprintf(myrb_gendisk->disk_name, DEVICE_NAME);

    myrb_gendisk->queue = myrb_queue;
    set_capacity(myrb_gendisk, MYRAMBLOCK_SIZE / 512);

    /* 硬件相关的操作 */
    myrb_buf = kzalloc(MYRAMBLOCK_SIZE, GFP_KERNEL);

    add_disk(myrb_gendisk);

        return 0;

out_queue:
    put_disk(myrb_gendisk);
out_disk:
    unregister_blkdev(major, DEVICE_NAME);
err:
    return ret;
}

static void __exit myrb_exit(void)
{
        printk("Goodbye Cruel World!\n");
    unregister_blkdev(major, DEVICE_NAME);
    del_gendisk(myrb_gendisk);
    put_disk(myrb_gendisk);
    blk_cleanup_queue(myrb_queue);
}

module_init(myrb_init);
module_exit(myrb_exit);

MODULE_LICENSE("GPL");

Makefile文件:

obj-m := ramdisk.o

KERNEL_SRC := /lib/modules/`uname -r`/build
SRC := $(shell pwd)

all:
        $(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
        $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
        rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
        rm -f Module.markers Module.symvers modules.order
        rm -rf .tmp_versions Modules.symvers

将上述两个文件放入一个目录中,然后直接在Ubuntu上编译和加载测试:

编译

make

测试

sudo insmod ramdisk.ko
ls -l /dev/myrb

格式化和挂载:

sudo mkfs.fat /dev/myrb 
mkdir test
sudo mount -t vfat /dev/myrb test/
cp hello.c test/

内核打印信息dmesg:

[6244400.196037] Hello World!
[6244485.597221] do_myrb_request read 1 len = 4096
[6244485.597325] do_myrb_request read 2 len = 4096
[6244485.597552] do_myrb_request write 1
[6244485.597564] do_myrb_request write 2
[6244485.597568] do_myrb_request write 3
[6244485.597571] do_myrb_request write 4
[6244485.597574] do_myrb_request write 5
[6244532.059986] do_myrb_request read 3 len = 512
[6244532.060033] do_myrb_request read 4 len = 512
[6244532.060038] do_myrb_request read 5 len = 512
[6244532.060040] do_myrb_request read 6 len = 512
[6244532.060045] do_myrb_request read 7 len = 512
[6244532.060048] do_myrb_request read 8 len = 512
[6244532.060050] do_myrb_request read 9 len = 512
[6244532.060053] do_myrb_request read 10 len = 512
[6244532.060055] do_myrb_request read 11 len = 512
[6244532.060057] do_myrb_request read 12 len = 512
[6244532.060060] do_myrb_request read 13 len = 512
[6244532.060062] do_myrb_request read 14 len = 512
[6244532.060066] do_myrb_request read 15 len = 512
[6244532.060068] do_myrb_request read 16 len = 512
[6244532.060070] do_myrb_request read 17 len = 512
[6244532.060073] do_myrb_request read 18 len = 512
[6244532.060075] do_myrb_request read 19 len = 512
[6244532.060077] do_myrb_request read 20 len = 512
[6244532.060079] do_myrb_request read 21 len = 512
[6244532.060082] do_myrb_request read 22 len = 512
[6244532.060085] do_myrb_request read 23 len = 512
[6244532.060088] do_myrb_request read 24 len = 512
[6244532.060090] do_myrb_request read 25 len = 512
[6244532.060092] do_myrb_request read 26 len = 512
[6244532.060095] do_myrb_request read 27 len = 512
[6244532.060097] do_myrb_request read 28 len = 512
[6244532.060099] do_myrb_request read 29 len = 512
[6244532.060101] do_myrb_request read 30 len = 512
[6244532.060104] do_myrb_request read 31 len = 512
[6244532.060107] do_myrb_request read 32 len = 512
[6244532.060109] do_myrb_request read 33 len = 512
[6244532.060111] do_myrb_request read 34 len = 512
[6244532.060113] do_myrb_request read 35 len = 512
[6244532.060117] do_myrb_request write 6
[6244562.692167] do_myrb_request write 7
[6244608.777887] do_myrb_request write 8
[6244614.492541] do_myrb_request read 36 len = 512
[6244639.979392] do_myrb_request read 37 len = 512
[6244645.123077] do_myrb_request write 9
[6244645.123101] do_myrb_request write 10
[6244645.123108] do_myrb_request write 11
[6244645.123120] do_myrb_request write 12
[6244645.123125] do_myrb_request write 13
[6244675.835181] do_myrb_request write 14
[6246576.076089] do_myrb_request write 15

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fulinux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值