linux块设备驱动与其测试

1 驱动程序

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/timer.h>
#include <linux/types.h>	/* size_t */
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/hdreg.h>	/* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>	/* invalidate_bdev */
#include <linux/bio.h>


//块设备文件主设备号  72
#define BLOCK_DEVICEMAJOR        COMPAQ_SMART2_MAJOR
// 块设备名字
#define BLOCK_DISKNAME           "queue_block" 
//块设备容量
#define BLOCK_DEV_BYTES        (1*1024*1024)   // 1M
//请求队列指针
static struct request_queue *block_request_queue;
// gendisk结构体指针变量
static struct gendisk *block_dev_disk;
//模拟磁盘空间
unsigned char block_dev_data[BLOCK_DEV_BYTES];

//该函数不能由驱动自己调用   由系统调用   系统认为是时候调用的时候调用
static void block_dev_do_request(struct request_queue *q)
{      //获取请求队列第一个IO请求
        struct request *req =blk_fetch_request(q);
   
       while ( req  != NULL) {
               sector_t sector = blk_rq_pos(req);  //获取扇区第一个位置
               unsigned long nsector = blk_rq_cur_sectors(req);//获取扇区数目
 //判断是否大于总容量
                if ((sector + nsector)<<9 > BLOCK_DEV_BYTES) 
                  {
                        printk(KERN_ERR BLOCK_DISKNAME
                                ": bad request: block=%llu, count=%llu\n",
                                (unsigned long long)sector,
                                 (unsigned long long)nsector);
                        __blk_end_request_all(req, -EIO);
                        continue;
                }  
 //判断数据传输方向
                switch (rq_data_dir(req)) {
                case READ:
                        memcpy(req->buffer,
                                block_dev_data + (sector<<9),
                                nsector<<9);
                       
                        break;
                case WRITE:
                        memcpy(block_dev_data + (sector<<9),
                                req->buffer,  nsector<<9);
                       
                        break;
                default:
                      
                        break;
                }
              //通知请求队列当前IO已经处理完毕
             if ( ! __blk_end_request_cur(req, 0) ) {
			req = blk_fetch_request(q); //继续读取下一个IO请求
		}
        }
}
static int block_dev_open (struct block_device *device, fmode_t mode)
{


    printk("open %s\n", device->bd_disk->disk_name);
    return 0;
}
//  释放块设备
static int block_dev_release(struct gendisk *gendisk, fmode_t mode)
{   
    printk("release %s\n", gendisk->disk_name);
    return 0;
}


//类似字符设备
struct block_device_operations block_dev_fops = {
        .owner                = THIS_MODULE,.open=block_dev_open, .release=block_dev_release
};


static int __init block_dev_init(void)
{
        int ret;
        //初始化请求队列
        block_request_queue = blk_init_queue(block_dev_do_request, NULL);
        if (!block_request_queue) {
                ret = -ENOMEM;
                goto err_init_queue;
        }
      //分配磁盘
        block_dev_disk = alloc_disk(1);
        if (!block_dev_disk) {
                ret = -ENOMEM;
                goto err_alloc_disk;
        }


        strcpy(block_dev_disk->disk_name, BLOCK_DISKNAME);//设备文件名
        block_dev_disk->major = BLOCK_DEVICEMAJOR;
        block_dev_disk->first_minor = 0;
        block_dev_disk->fops = &block_dev_fops;
        block_dev_disk->queue = block_request_queue;//指定请求队列
        set_capacity(block_dev_disk, BLOCK_DEV_BYTES>>9);//设置磁盘容量
        add_disk(block_dev_disk);//添加磁盘


        return 0;


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


static void __exit block_dev_exit(void)
{
        del_gendisk(block_dev_disk);//删除磁盘
        put_disk(block_dev_disk);//gendisk引用次数减一
        blk_cleanup_queue(block_request_queue);//清除请求队列
}


module_init(block_dev_init);
module_exit(block_dev_exit);


测试:

第一步:编译安装驱动程序
makefile;
ifneq ($(KERNELRELEASE),)  
    obj-m :=queue_block.o  
else  
    KERNELDIR :=/home/litingting/gec2440/linux-2.6.30.4
all:  
    make -C $(KERNELDIR) M=$(PWD)  modules  ARCH=arm  CROSS_COMPILE=arm-linux-  
clean:  
    rm -f *.o *.ko *.mod.o *.mod.c *.symvers modul* *.*~  
 
endif  

接下来  insmod   queue_block.ko 
 
第二步:格式化块设备   
例如将设备格式化为Ext2文件系统格式  mkfs.ext2  /dev/queue_block

第三步:挂载

mount  /dev/queue_block  /mnt/queue_block 
关于挂载解释如下:
A  
我把U盘插到USB口上了,下一步我该如何做才能查看U盘里的内容? 

我不能确定你的Linux系统会不会自动加载。所以,你应该先去/media目录下查看一下,看看是不是已经自动加载上了。如果是的话,应该在/media里有一个目录,
名字类似于disk,你进入目录就等于进入你的U盘了。 

如果/media没有你想要的东西,那就要自己mount了! 

$mkdir /mnt/usb 

$mount -t vfat /dev/sda /mnt/usb 

这样就可以了,你去/mnt/usb目录看看,应该有你想要的了。如果mount命令不管用,那么你可以将/dev/sda改成/dev/sdb或者/dev/sdc试试! 

-t选项用于设定文件系统类型,我假设你的U盘是fat32的。(因为大部分U盘都是这样的)如果是其他文件系统,你可以man mount来查看一下,方法类似。 

B  
我把光盘放到光驱里了,下一步咋办? 

如果系统没有自动加载光驱的话,那么用下面命令一般有效: 

$mkdir /mnt/cdrom 

$mount -t iso9660 /dev/cdrom /mnt/cdrom 


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。