以下代码亲测在2.6.38上测试通过,在3的内核上不行,因为3的内核有许多API已经变了(见上篇),而且3的struct request没有buffer这个成员

simp_blkdev.c:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/string.h>
#include<linux/blkdev.h>
#include<linux/hdreg.h>

#define SIMP_BLKDEV_MAJOR 180 
#define SIMP_BLKDEV_DISKNAME "simp_blkdev"
#define SIMP_BLKDEV_BYTES (2*1024*1024) //块设备的大小 2M

static struct request_queue *simp_blkdev_queue = NULL;   //良好的习惯
static struct gendisk *simp_blkdev_disk = NULL;
static unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];

//负责处理块设备请求的函数
static void simp_blkdev_do_request(struct request_queue *q)
{
    struct request *req;

req = blk_fetch_request(q);
    //从请求队列中不断的提取下一条请求,然后对请求进行处理
    while(req){
        //如果传送的扇区超出块设备大小。
        //扇区->字节,blk_rq_pos当前要传送的扇区,blk_rq_cur_sectors当前要传送的扇区数量
        if((blk_rq_pos(req) + blk_rq_cur_sectors(req)) << 9 > SIMP_BLKDEV_BYTES){
            printk(KERN_ERR "bad request:block=%llu,count=%u\n",(unsigned long long)blk_rq_pos(req),blk_rq_cur_sectors(req));
            if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
        continue;
        }

switch (rq_data_dir(req)){
            case READ:
                memcpy(req->buffer,simp_blkdev_data+(blk_rq_pos(req) << 9),blk_rq_cur_sectors(req) << 9); //从第二个参数的地址拷贝第三个参数的字节数到第一个参数的地址
        if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
                break;
            case WRITE:
                memcpy(simp_blkdev_data+(blk_rq_pos(req) << 9),req->buffer,blk_rq_cur_sectors(req) << 9);
        if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
                break;
            default:
                break;
        }
    }
}

struct block_device_operations simp_blkdev_fops = {
    .owner = THIS_MODULE,
};

static int __init simp_blkdev_init(void)
{
    int ret;
    //请求队列初始化,绑定函数
    simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request,NULL);
    if(!simp_blkdev_queue){ //初始化失败
        ret = - ENOMEM;
        goto err_init_queue;
    }
    register_blkdev(SIMP_BLKDEV_MAJOR,SIMP_BLKDEV_DISKNAME);//注册主设备
    simp_blkdev_disk = alloc_disk(1); //申请gendisk
    if(!simp_blkdev_disk){
        ret = - ENOMEM;
        goto err_alloc_disk;
    }
    //gendisk初始化
    strcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);
    simp_blkdev_disk->major = SIMP_BLKDEV_MAJOR;
    simp_blkdev_disk->first_minor = 0;  //第一次设备号
    simp_blkdev_disk->fops = &simp_blkdev_fops;
    simp_blkdev_disk->queue = simp_blkdev_queue;
    //设置块设备的大小,块设备使用扇区作为单位设置,而扇区的大小默认是512字节。
    //在把字节为单位的大小转换为以扇区为单位时,我们需要除以512,或者右移9位可能更快一些。
    set_capacity(simp_blkdev_disk,SIMP_BLKDEV_BYTES>>9);
    add_disk(simp_blkdev_disk); //向系统添加这个块设备

return 0;

err_alloc_disk:
        blk_cleanup_queue(simp_blkdev_queue);
    err_init_queue:
        return ret;
}

static void __exit simp_blkdev_exit(void)
{
    unregister_blkdev(SIMP_BLKDEV_MAJOR,SIMP_BLKDEV_DISKNAME);//注销设备驱动
    del_gendisk(simp_blkdev_disk); //从系统中删除这个块设备
    put_disk(simp_blkdev_disk); //释放申请的空间
    blk_cleanup_queue(simp_blkdev_queue);
}

module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);

MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("simp_blkdev");

Makefile:

obj-m := simp_blkdev.o
KDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38/
PWD := $(shell pwd)
default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
    rm -rf *.ko *.o *.mod.* *.symvers *.order

测试(我是在tiny6410(2.6.38)上测试的,因为我的电脑是3.16的,虽然我又编译了2.6.38的内核但就是跑不起来,无奈就用板子试了)没有板子也没关系,只要电脑内核是2的也能成功:

1.insmod simp_blkdev.ko

2.mkfs.ext2 /dev/simp_blkdev

板子上只有ext2和vfat两种文件系统,没有ext3更没有ext4,所以我这边用ext2,查看支持的文件系统用ls /sbin/mkfs.*

3.mkdir -p /mnt/blk

4.mount /dev/simp_blkdev /mnt/blk

未mount前lsmod和mount后是这样的

可以看到模块引用计数从0变为1了,等会umount掉又会变成0

5.ls /mnt/blk

6.umount /mnt/blk

7.rmmod simp_blkdev

我的这份代码跟网上其他类似的代码不同的地方有这些:

1.最坑爹的一点!!!!blk_end_request_cur(req,0)    0是表示成功的!不是网上代码看到的0是失败,害我整整搞了一天啊!!!!!!!一直在mkfs.ext2那句整个板子卡死

2.网上其他代码的主设备号是抢其他的设备的,我这边是单独自己选个没用到的设备自己进行注册,所以才有init中才有register_blkdev这句,insmod成功之后你能在cat /proc/device中看到它

3.其他的一些变化详见上篇

4.__blk_end_request_cur或者__blk_end_request_all都可以用,效果是一样的,我还不知道具体区别是什么。

ps:

blk_alloc_queue分配的请求队列中make_request_fn是没有被赋值的,所以要实现无请求队列的simp_blkdev要自己写个simp_blkdev_make_request并绑定到request_quque的make_request_fn,而blk_init_quque则把make_request_fn与simp_blkdev_do_request绑定在一起。

非常简单的一个块设备驱动,simp_blkdev,2.6.31之后的变化相关推荐

  1. [转]写一个块设备驱动(第八章)

    第8章 +---------------------------------------------------+ |                 写一个块设备驱动                 ...

  2. [转]写一个块设备驱动(第一章)

    写一个块设备驱动1,2(转) 2009/09/03 15:42 第1章 +---------------------------------------------------+ |          ...

  3. 转:写一个块设备驱动

    ----------------------- Page 1----------------------- 第 1章 +---------------------------------------- ...

  4. 写一个块设备驱动5,6

    http://blogold.chinaunix.net/u3/108239/showart.php?id=2144628 第5章 +--------------------------------- ...

  5. Linux驱动开发--写一个块设备驱动

    原文地址:[原创] 写一个块设备驱动 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2017377&fromuid=288 ...

  6. 写一个块设备驱动1,2

    http://blogold.chinaunix.net/u3/108239/showart.php?id=2144624 第1章 +--------------------------------- ...

  7. 写一个块设备驱动1,2(转)

    第1章 +---------------------------------------------------+ |???????????????? 写一个块设备驱动???????????????? ...

  8. 写一个块设备驱动5,6(转)

    第5章 +---------------------------------------------------+ |???????????????? 写一个块设备驱动???????????????? ...

  9. 第6章 写一个块设备驱动

    第6章 +---------------------------------------------------+ |                 写一个块设备驱动                 ...

最新文章

  1. Python 进阶 — 面向对象设计原则
  2. php in循环与for循环,详谈js中标准for循环与foreach(for in)的区别
  3. 深入浅出,Spring 框架和 Spring Boot 的故事
  4. oracle数据库的导入导出
  5. opencv轮廓周长原理_OpenCV3 - 轮廓特征
  6. Java面试 - HashMap的底层实现,之后会问ConcurrentHashMap的底层实现
  7. Opencore-黑苹果:外接4K显示器却只能选择2K或以下分辨率
  8. 5. 直接三角形分解法
  9. java学习日记-基础-列出2~100内的素数
  10. VMThread占CPU高基本上是JVM在频繁GC导致,原因基本上是冰法下短时间内创建了大量对象堆积造成频繁GC。...
  11. Overleaf 中文硕博论文LaTex模板
  12. (附源码)ssm教培管理系统 毕业设计 230932
  13. 前端开发工具Axure——Axure原型图查看
  14. 如何把拼音放在文字的右侧,干货到,在WORD中怎么把拼音和汉字同排
  15. 物联网:GPRS和NB-IOT
  16. R2S设置openWrt软路由
  17. WPF之布局属性HorizontalAlignment、HorizontalContentAlignment、VertialAlignment、VerticalContentAlignment
  18. TYPEC 接口芯片CC逻辑原理与必要性
  19. 设置iPhone的呼叫转移来电等待
  20. cx_Oracle使用方法

热门文章

  1. 【EasyRL学习笔记】第二章 Markov Decision Process 马尔可夫决策过程
  2. DQN(基本概念和进阶技巧)
  3. 按excel表格顺序批量改变图片名字:
  4. LS-DYNA中射流冲击模型的技术难点及案例模型
  5. TCP通信基础(一发一收)
  6. C++:按位异或运算符:^
  7. 浅谈UML中的聚合与组合
  8. 今年全系 iPhone 都是 4G 运存——11 突然变香了!
  9. 施工员是做什么的?施工员证书怎么考?
  10. 图片头顶距离顶部百分比怎么修改_迷你世界:爱吃糖葫芦怎么办?学会模型制作,美食甜品自己做!...