mini2440 linux块设备驱动开发源代码(宋宝华框架)

/*************************************************************************************************

mini2440 linux块设备驱动开发源代码:

**************************************************************************************************/
/*
insmod b_dev_tangjx.ko //动态挂载驱动模块
lsmod  //查看是否多了个b_dev_tangjx 模块
ls /dev  //查看一下/dev目录下是否多了个block_dev节点(节点会自动创建)
mkfs.ext3 /dev/block_dev  //在虚拟磁盘上建立ext3文件系统
mount /dev/block_dev /mnt/test   //挂载到/mnt/test目录下,然后去看看mnt/test下面是不是多了lost+found文件夹

终端敲入mount,看一下mount的记录,是不是ext3格式

对它进行读写:
#cp *.c /mnt/test 
#ls /mnt/test  看内容是否写过去了
#cp su.c /
#ls /su.c 看是否读OK


玩够了之后就清除掉
umount /mnt/test
rmmod b_dev_tangjx.ko 
(注意:要关闭这个终端新开一个终端,不然系统会认为该模块正被使用而不能卸载)

*/

// 上面步骤已经在pc机上测试OK ,但是在ARM平台运行时,ARM平台没有mkfs.ext3命令,所以没往下执行---SU

//使用了SBH-P289 无请求队列请求时使用的模板

#include <linux/string.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/genhd.h>
#include <linux/buffer_head.h>  /* for invalidate_bdev() */
#include <linux/backing-dev.h>
#include <linux/blkpg.h>
#include <linux/writeback.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include<linux/fs.h>

#include <linux/bio.h>
#include<linux/fs.h>
#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/compiler.h>


/*宏定义*/
#define  BLOCK_DEVICEMAJOR  0 //主设备号
#define  BLOCK_DISKNAME   "block_dev"  //设备名称
#define  BLOCK_BYTES  (16*1024*1024)  //存取块的大小
#define  BLOCK_BLKDEV_MAXPARTITIONS   1  //(64)    //总共最多的分区数

unsigned char block_data[BLOCK_BYTES];  //16m的大小,从内存中划分出来当前硬盘使用

static int block_devicemajor = BLOCK_DEVICEMAJOR; //主设备号
module_param( block_devicemajor, int, 0 );

struct block_driver
{
 struct request_queue *block_queue; //块驱动的请求队列
 struct gendisk *block_disk;

};/*自定义结构体*/

static struct block_driver *block_dev=NULL; //赋值NULL防止野指针

//这个函数会自动调用
static int block_blkdev_make_request(struct request_queue *q, struct bio *bio)
{
 struct bio_vec *bvec;
 int i;
 void *dsk_mem;
 // 检测访问请求是否超越了块设备限制  //bio是经过合并的数据块
 if ((bio->bi_sector << 9) + bio->bi_size > BLOCK_BYTES)//  bi_sector要传输的第一个扇区.bi_size要传输的字节数SBH_P285
 { //bi_sector << 9相当于当前扇区*512
  printk(KERN_ERR  "SIMP_BLKDEV_DISKNAME: bad request: block=%llu, count=%u\n", (unsigned long long)bio->bi_sector, bio->bi_size);

  #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) )  //LINUX_VERSION_CODE记录着内核的版本
  //bio_endio用于返回这个对bio请求的处理结果,在2.6.24之后的内核中,第一个参数是被处理的
  //bio指针,第二个参数成功时为0,失败时为-ERRNO。
   bio_endio(bio, 0, -EIO);  //-EIO代表IO操作有出错
  #else
   bio_endio(bio, -EIO);
  #endif

  return 0;
 }
 //数组名block_data代表内存的首地址 + 扇区数*512
 dsk_mem = block_data + (bio->bi_sector << 9);  //指针指向要读写的第一个扇区首地址(挂载点)
 bio_for_each_segment(bvec, bio, i) //遍历bio中的每个bvec ,把bio一个一个放到bvec中,i从0开始
 { //bio中的每个扇区
  void *iovec_mem;
  switch (bio_rw(bio)) {
  case READ:  //#define READ   0
  case READA: //#define READA 2  /* read-ahead  - don't block if no resources */
   iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset; // 映射一个物理页面,kmap定位下就知道它映射的位置(就知道挂载到哪个目录)
   memcpy(iovec_mem, dsk_mem, bvec->bv_len);  //把数据读出//把硬盘的东西dsk_mem读到iovec_mem目录挂载点
   kunmap(bvec->bv_page); //数据已经复制过去,可以断开映射寻找挂载到哪个目录
   break;
  case WRITE: //  #define WRITE 1 //数据从挂载点拷贝到硬盘中
   iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
   memcpy(dsk_mem, iovec_mem, bvec->bv_len);  //把数据写入
   kunmap(bvec->bv_page);
   break;
  default:
   /*
    // return READ, READA, or WRITE
                 #define bio_rw(bio)  ((bio)->bi_rw & (RW_MASK | RWA_MASK))
   */
   printk(KERN_ERR  "SIMP_BLKDEV_DISKNAME: unknown value of bio_rw: %lu\n", bio_rw(bio));
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
     //bio_endio:设置块设备i/o停止
   bio_endio(bio, 0, -EIO);//#define EIO   5 /* I/O error */
  #else
   bio_endio(bio, -EIO);     //通知应用程出错
  #endif
   return 0;
  }
  dsk_mem += bvec->bv_len;
 }
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
  bio_endio(bio, bio->bi_size, 0);
 #else
  bio_endio(bio, 0);    //通知应用程已经完成

 #endif

 return 0;
}

//这就是我们的硬盘提供的操作接口

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

static int __init block_init(void)
{
 int ret;
 
 //动态申请块设备号, 返回值就是主设备号,注册失败则返回负值。
 block_devicemajor = register_blkdev( block_devicemajor, BLOCK_DISKNAME );//
 
 if( block_devicemajor <= 0 )
 {
  printk( KERN_WARNING "GKDD-disk: unable to get major number\n" );
  return -EBUSY;
 }
 
 printk("<0>"  "block_devicemajor==>>%d\n" ,block_devicemajor); //打印出主设备号

 //封装好的结构体指针 block_dev 分配内存
 block_dev= kmalloc( sizeof( struct block_driver ), GFP_KERNEL );
 if(block_dev == NULL)
 {
  goto err_kmalloc;
 }
 /*
 * # define GFP_KERNEL 0
 */
 /*分配一个请求队列*/
 block_dev->block_queue = blk_alloc_queue(GFP_KERNEL);
 if (!block_dev->block_queue)
 {
  ret = -ENOMEM;
  printk("<0>" "block_queue::");
  goto err_init_queue;
 }

 /*在队列中添加中断函数,把请求队列和请求函数绑定*/
 blk_queue_make_request(block_dev->block_queue, block_blkdev_make_request);//请求合并好后会自动调用这个函数,请求函数相当于真正的读写函数
 
 if (!block_dev->block_queue)
 {
  ret = -ENOMEM;
  goto err_init_queue;
 }
 
 
 //安装对应的 block_dev 结构
 
 block_dev->block_disk = alloc_disk(BLOCK_BLKDEV_MAXPARTITIONS);
 if (!block_dev->block_disk)
 {
  ret = -ENOMEM;
  goto err_alloc_disk;
 }
//初始化gendisk
 strcpy(block_dev->block_disk->disk_name, BLOCK_DISKNAME);
 block_dev->block_disk->major = block_devicemajor;//注册块设备主设备号
 block_dev->block_disk->first_minor = 0;//注册次设备号
 block_dev->block_disk->fops = &block_fops; //内核提供给驱动层的函数接口
 block_dev->block_disk->queue = block_dev->block_queue; //请求队列
 block_dev->block_disk->private_data = block_dev; //保存我们的设备结构

 /*
 *容量,以扇区为单位
 *以512-字节扇区来计.  传递扇区数目给
 */
 set_capacity(block_dev->block_disk, BLOCK_BYTES>>9);  //BLOCK_BYTES>>9 扇区的个数(BLOCK_BYTES/512,每个扇区大小512)
 //做这一步前要确保一切准备工作都做好,一般放在最后一步
 add_disk(block_dev->block_disk); //添加块设备加入到内核
 
 printk( "<0>" "Module block init finish\n" );
 
 return 0;
 
err_alloc_disk:
 blk_cleanup_queue(block_dev->block_queue); //清除队列
 //return ret;
 
err_init_queue:
    kfree(block_dev);
 //return ret;
 
err_kmalloc:
 unregister_blkdev( block_devicemajor, BLOCK_DISKNAME );
 return -ENOMEM;
 
}


static void __exit block_exit(void)
{
    /*删除磁盘设备*/
 del_gendisk(block_dev->block_disk); //删除分区,从内核中删除
 put_disk(block_dev->block_disk);    //释放扇区资源
 blk_cleanup_queue(block_dev->block_queue);//清除块设备队列
 
 unregister_blkdev( block_devicemajor, BLOCK_DISKNAME );//取消注册
 kfree(block_dev);//释放块设备结构体内存空间
 printk( "<0>" "Module block exit\n" );
}


module_init(block_init);
module_exit(block_exit);

 

 

//=====================================================================================

应用程序测试代码

//=====================================================================================

 

#include <linux/string.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/buffer_head>
#include <linux/backing-dev.h>
#include <linux/blkpg.h>
#include <writeback.h>
#include <version.h>
#include <asm/uaccess.h>
#include <linux/fs.h>

#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/dlevator.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/compiler.h>

#define BLOCK_DEVICEMAJOR 0
#define BLOCK_DISKNAME "block_dev"
#define BLOCK_BYTES (16*1024*1024)
#define BLOCK_BLKDEV_MAXPARTITIONS 1

unsigned char block_data[BLOCK_BYTES];
static int block_devicemajor = BLOCK_DEVICEMAJOR;
module_param(block_devicemajor,int,0);
struct block_driver
{
 struct request_queue *block_queue;
 struct gendisk *block_disk;
};
static int block_blkdev_make_request(struct request_queue *q, struct bio *bio)
{
 struct bio_vec *bvec;
 int i;
 void *dsk_mem;

 if((bio->bi_sector <<9)+ bio->bi_size >BLOCK_BYTES)
 {
  printk(KERN_ERR "ERROR");
  #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
   bio_endio(bio,0,-EIO);
  #else
   bio_endio(bio,-EIO);
  #endif
  
 }

 dsk_mem=block_data+(bio->bi_sector<<9);
 bio_for_each_segment(bvec,bio,i)
 {
  void *iovec_mem;
  switch(bio_rw(bio))
  {
   case READ:
   case READA:
    iovec_mem = kmap(bvec->bv_page)+bvec->bv_offset;
    memcpy(iovec_mem,dsk_mem,bvec->bv_len);
    kunmap(bvec->bv_page);
    break;
   case WRITE:
    iovec_mem=kmap(bvec->bv_page)+bvec->bv_offset;
    memcpy(dsk_mem,iovec_mem,bvec->bv_len);
    kunmap(bvec->bv_page);
    break;
   default:
    printk(KERN_ERR "%lu\n",bio_rw(bio));
    #if LINUX_VERSION_CODE <KERNEL_VERSION(25,6,24)
     bio_endio(bio,0,-EIO);
    #else
     bio_endio(bio,0,-EIO);
    #endif
     return 0;
  }
  dsk_mem+=bvec->bv_len;
 }
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
  bio_endio(bio,bio->bi_size,0);
 #else
  bio_endio(bio,0);
 #endif
 return 0;
 
}


struct block_device_operations block_fops={

 .owner = THIS_MODULE,
};

static struct block_driver *block_dev = NULL;

static int __init block_init(void)
{
 int ret;
 block_devicemajor = register_blkdev(block_devicemajor,BLOCK_DISKNAME);
 if(block_devicemajor<0)
 {
  printk(KERN_WARNING "unable to get major number\n");
  return -EBUSY;
 }
 printk("<0>" "block_devicemajor==>>%d\n",block_devicemajor);

 block_dev=kmalloc(sizeof(struct block_driver),GFP_KERNEL);
 if(block_dev == NULL)
 {
  goto err_kmalloc;
 }

 block_dev->block_queue = blk_alloc_queue(GFP_KERNEL);
 if(!block_dev->block_queue)
 {
  ret = -ENOMEM;
  printk("<0>" "block_queue::");
  goto err_init_queue;
 }
 blk_queue_make_request(block_dev->block_queue,block_blkdev_make_request);

 if(!block_dev->block_queue)
 {
  ret= -ENOMEM;
  goto err_init_queue;
 }
 block_dev->block_disk= alloc_disk(BLOCK_BLKDEV_MAXPARTITIONS);
 if(!block_dev->block_disk)
 {
  ret =- ENOMEM;
  goto err_alloc_disk;
 }
 strcpy(block_dev->block_disk->disk_name,BLOCK_DISKNAME);
 block_dev->block_disk->major= block_devicemajor;
 block_dev->block_disk->first_minor = 0;
 block_dev->block_disk->fops=&block_fops;
 block_dev->block_disk->queue= block_dev->block_queue;
 block_dev->block_disk->private_data= block_dev;

 set_capacity(block_dev->block_disk,BLOCK_BYTES>>9);
 add_disk(block_dev->block_disk);
 printk("<0>" "MOdule block init finish\n");
 return 0;

 err_alloc_disk:
  blk_cleanup_queue(block_dev->block_queue);
 err_init_queue:
  kfree(block_dev);
 err_kmalloc:
  unregister_blkdev(block_devicemajor,BLOCK_DISKNAME);
  return -ENOMEM;
}
static void __exit block_exit(void)
{
 del_gendisk(block_dev->block_disk);
 put_disk(block_dev->block_disk);
 blk_cleanup_queue(block_dev->block_queue);

 unregister_blkdev(block_devicemajor,BLOCK_DISKNAME);
 kfree(block_dev);
 printk("<0>" "Module block exit\n");
}
module_init(block_init);
module_exit(block_exit);

 

//=====================================================================================

Makefile

//=====================================================================================

#如果是PC机运行,则#make #如果是arm平台运行,则#make arch=arm
ifneq ($(arch),arm)

#CROSS=
#CC=$(CROSS)gcc
#LD=$(CROSS)ld
#AR=$(CROSS)ar  #函数库打包,可创建静态库.a文档
#AS=$(CROSS)as  #汇编程序

obj-m:=block.o
all:
 make -C /usr/src/kernels/2.6.18-1.2798.fc6-i686 M=$(PWD) modules

else

CROSS=/usr/local/arm/4.3.2/bin/arm-linux-
CC=$(CROSS)gcc
LD=$(CROSS)ld
AR=$(CROSS)ar
AS=$(CROSS)as

obj-m:=block.o
globalmem_arm-objs:=block.o  //同类型的多个设备
all:
 #make -C /et10/linux-2.6.12 M=$(PWD) modules
 make -C /mini2440/linux-2.6.32.2 M=$(PWD) modules
endif
clean:
 @rm -rf *.o *.ko *.symvers *.mod.c


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值