块设备驱动分析及编写

. 框架

 

app:      open,read,write "1.txt"

---------------------------------------------  文件的读写

文件系统: vfat, ext2, ext3, yaffs2, jffs2     (把文件的读写转换为扇区的读写)

-----------------ll_rw_block()-----------------  (这个函数是块设备操作的入口,提供扇区的读写功能,详细请参阅<LINUX内核源代码情景分析>设备驱动一章

                       1. "读写"放入队列

                       2. 调用队列的处理函数(优化/调顺序/合并)

           块设备驱动程序    

---------------------------------------------

硬件:        硬盘,flash

 

 

. ll_rw_block()分析

 

<LINUX内核源代码情景分析>

 

分析ll_rw_block

        for (i = 0; i < nr; i++) {

            struct buffer_head *bh = bhs[i];

            submit_bh(rw, bh);

                struct bio *bio; // 使用bh来构造bio (block input/output)

                submit_bio(rw, bio);

                    // 通用的构造请求: 使用bio来构造请求(request)

                    generic_make_request(bio);

                       __generic_make_request(bio);

                            request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列 

                           

                            // 调用队列的"构造请求函数"

                            ret =q->make_request_fn(q, bio);

                                    // 默认的函数是__make_request

                                   __make_request

                                        // 先尝试合并

                                       elv_merge(q, &req, bio);

                                       

                                        // 如果合并不成,使用bio构造请求

                                       init_request_from_bio(req, bio);

                                       

                                        // 把请求放入队列

                                        add_request(q, req);

                                       

                                        // 执行队列

                                       __generic_unplug_device(q);

                                               // 调用队列的"处理函数"

                                               q->request_fn(q);

           

先构造一个make_request(bio),在构造一个请求队列,将请求加入队列

 

 

. 块设备驱动程序编写

 

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

 

1.      Xd.c分析

register_blkdev(XT_DISK_MAJOR,"xd")

struct request_queue*xd_queue = blk_init_queue(do_xd_request, &xd_lock);// //为设备准备请求队列

xd_drives = xd_initdrives(xd_sigs[controller].init_drive);

 

for (i = 0; i < xd_drives; i++) {

              XD_INFO*p = &xd_info[i];

              structgendisk *disk = alloc_disk(64);

              disk->major= XT_DISK_MAJOR;

              disk->first_minor= i<<6;

                     disk->fops = &xd_fops;

              disk->private_data= p;

              disk->queue= xd_queue;

}

 

z2ram.c分析

register_blkdev(Z2RAM_MAJOR,DEVICE_NAME)

struct  gendisk *z2ram_gendisk = alloc_disk(1);

struct request_queue *z2_queue = blk_init_queue(do_z2_request, &z2ram_lock);//为设备准备请求队列

                           static DEFINE_SPINLOCK(z2ram_lock);

static void do_z2_request(struct request_queue *q)//请求处理函数

{

              structrequest *req;

              req= blk_fetch_request(q);//从队列中取出请求

              memcpy(req->buffer,(char *)addr, size);

}

z2ram_gendisk->major = Z2RAM_MAJOR;

z2ram_gendisk->first_minor = 0;

z2ram_gendisk->fops = &z2_fops;

                           static const struct block_device_operations z2_fops =

{

.owner          =THIS_MODULE,

.open            =z2_open,

.release =z2_release,

};

 z2ram_gendisk->queue = z2_queue;

add_disk(z2ram_gendisk);

 

2.      自己编写

2.1   具体步骤:

内容:从内存中划出一部分内存,当做磁盘来操作。

1. 注册设备register_blkdev()

2. 为设备初始化一个请求队列struct request_queue : blk_init_queue()(blk_cleanup_queue())

3. 分配gendisk: alloc_disk

4. 设置gendisk

     设备号,名字,操作函数,容量,所属队列等等属性

5. 注册: add_disk

 

2.2 代码:

#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 structgendisk *ramblock_disk;

staticrequest_queue_t *ramblock_queue;

 

static intmajor;

 

staticDEFINE_SPINLOCK(ramblock_lock);

 

#defineRAMBLOCK_SIZE (1024*1024)

static unsignedchar *ramblock_buf;

 

static intramblock_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 structblock_device_operations ramblock_fops = {

       .owner   =THIS_MODULE,

       .getgeo  =ramblock_getgeo,

};

 

static voiddo_ramblock_request(request_queue_t * q)

{

       static int r_cnt = 0;

       static int w_cnt = 0;

       struct request *req;

      

       //printk("do_ramblock_request%d\n", ++cnt);

 

       while ((req = elv_next_request(q)) !=NULL) {

              /* 数据传输三要素: ,目的,长度 */

              /* /目的: */

              unsigned long offset =req->sector * 512;

 

              /* 长度: */        

              unsigned long len =req->current_nr_sectors * 512;

 

              if (rq_data_dir(req) == READ)

              {

                     //printk("do_ramblock_requestread %d\n", ++r_cnt);

                     memcpy(req->buffer,ramblock_buf+offset, len);

              }

              else

              {

                     //printk("do_ramblock_requestwrite %d\n", ++w_cnt);

                     memcpy(ramblock_buf+offset,req->buffer, len);

              }            

             

              end_request(req, 1);//1--succes0--error

       }

}

 

static intramblock_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;

      

       major = register_blkdev(0,"ramblock");  /* cat/proc/devices */     

       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);//设置容量

 

       /* 3. 硬件相关操作 */

       ramblock_buf = kzalloc(RAMBLOCK_SIZE,GFP_KERNEL);

 

       /* 4. 注册 */

       add_disk(ramblock_disk);

 

       return 0;

}

 

static voidramblock_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");

 

 

测试3th,4th:

在开发板上:

1. insmodramblock.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

 

测试5th:

1. insmodramblock.ko

2. ls/dev/ramblock*

3. fdisk/dev/ramblock

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值