分类: LINUX
2011-12-12 17:18:25
block.rar 写一个块设备驱动--没看过的可以看看(完整).doc
实验源文件
/******************************************************
*author:tingkman
*time :2011.12.9
*ver :v1
*******************************************************/
一、试验环境:
虚拟机:vmware
系统:red hat enterprise 6
版本:2.6.32
交叉编译链:内核自带gcc 版本 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC)
/********************************************************
模块文件:Mod.c
********************************************************
#include
#include
#include
#include
#include
#include
#define SIMP_BLKDEV_DISKNAME "simp_blkdev"
#define SIMP_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR
#define SIMP_BLKDEV_BYTES (16*1024*1024)
unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];
static struct gendisk *simp_blkdev_disk;
static struct request_queue *simp_blkdev_queue;//定义一个request_queue结构体指针
int ret;
static void simp_blkdev_do_request(struct request_queue *q)
{
struct request *req;
/*电梯调度算法实现*/
while ((req = elv_next_request(q)) != NULL) {
if ((req->sector + req->current_nr_sectors) << 9
> SIMP_BLKDEV_BYTES) {
printk(KERN_ERR SIMP_BLKDEV_DISKNAME
": bad request: block=%llu, count=%u\n",
(unsigned long long)req->sector,
req->current_nr_sectors);
end_request(req, 0);
continue;
}
/*判断是读还是写数据*/
switch (rq_data_dir(req)) {
case READ:
/*因为是在内存李的块设备,数据操作知识memcpy,实际设备合作和这不一样*/
memcpy(req->buffer,
simp_blkdev_data + (req->sector << 9),
req->current_nr_sectors << 9);
end_request(req, 1);
break;
case WRITE:
memcpy(simp_blkdev_data + (req->sector << 9),
req->buffer, req->current_nr_sectors << 9);
end_request(req, 1);
break;
default:
/* No default because rq_data_dir(req) is 1 bit */
break;
}
}
}
struct block_device_operations simp_blkdev_fops={
.owner =THIS_MODULE,//此处为逗号,结尾为分号
};
static int __init simp_blkdev_init(void)
{
int ret;
/*初始化话请求队列这里I/O调度算法是默认的blk_init_queue()即楼梯调度算法*/
simp_blkdev_queue=blk_init_queue(simp_blkdev_do_request,NULL);
if(!simp_blkdev_queue){
ret=-ENOMEM;
goto err_init_queue;
}
/*申请这个设备的资源*/
simp_blkdev_disk=alloc_disk(1);
if(!simp_blkdev_disk)//申请成功返回1否则返回0
{
ret=-ENOMEM;
goto err_alloc_disk;
}
/*设置设备相关属性主要是 主次设备号、设备名,设备操作接口、设备的等待队列、容量*/
strcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);
simp_blkdev_disk->major= SIMP_BLKDEV_DEVICEMAJOR;
simp_blkdev_disk->first_minor=0;
//simp_blkdev_disk->fops=simp_blkdev_fops;
simp_blkdev_disk->queue= simp_blkdev_queue;
set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES>>9);//设置块容量,以扇区为单位一个扇区512byte
/*添加设备*/
add_disk(simp_blkdev_disk);//入口处添加设备
return 0;
err_alloc_disk:
return ret;
err_init_queue:
return ret;
}
static void __exit simp_blkdev_exit(void)
{
/*注意次序,先申请请求队列,然后申请资源,然后添加设备*/
del_gendisk(simp_blkdev_disk);//这个地方为什么不是邋del_disk查看内核就是这么定义的、出口处删除设备,添加-删除成对出现
put_disk(simp_blkdev_disk);//出口处释放资源,申请和释放成对出现
blk_cleanup_queue(simp_blkdev_queue);//
}
module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR("tingkman");
MODULE_DESCRIPTION("For test");
*******************************************************************************Makefile
obj-m :=mod.o
#KDIR :=/home/yao/driver/block/linux-2.6.32
#KDIR :=/home/yao/kernel_apollo_pro_hdnp
KDIR := /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
rm -rf Module.markers modules.order Module.symvers
注意到KDIR 指向内核目录,因为编译模块依赖内核
执行Make命令
[root@localhost block]# make
make -C /lib/modules/2.6.32-71.el6.i686/build SUBDIRS=/home/yao/driver/block modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-71.el6.i686'
CC [M] /home/yao/driver/block/mod.o
/home/yao/driver/block/mod.c: 在函数‘simp_blkdev_do_request’中:
/home/yao/driver/block/mod.c:18: 错误:隐式声明函数‘elv_next_request’
/home/yao/driver/block/mod.c:18: 警告:赋值时将整数赋给指针,未作类型转换
/home/yao/driver/block/mod.c:19: 错误:‘struct request’没有名为‘sector’的成员
/home/yao/driver/block/mod.c:19: 错误:‘struct request’没有名为‘current_nr_sectors’的成员
/home/yao/driver/block/mod.c:23: 错误:‘struct request’没有名为‘sector’的成员
/home/yao/driver/block/mod.c:24: 错误:‘struct request’没有名为‘current_nr_sectors’的成员
/home/yao/driver/block/mod.c:25: 错误:隐式声明函数‘end_request’
/home/yao/driver/block/mod.c:32: 错误:‘struct request’没有名为‘sector’的成员
/home/yao/driver/block/mod.c:32: 错误:‘struct request’没有名为‘current_nr_sectors’的成员
/home/yao/driver/block/mod.c:38: 错误:‘struct request’没有名为‘sector’的成员
/home/yao/driver/block/mod.c:38: 错误:‘struct request’没有名为‘current_nr_sectors’的成员
make[2]: *** [/home/yao/driver/block/mod.o] 错误 1
make[1]: *** [_module_/home/yao/driver/block] 错误 2
make[1]: Leaving directory `/usr/src/kernels/2.6.32-71.el6.i686'
make: *** [default] 错误 2
[root@localhost block]#
出错,出错原因理解为函数elv_next_request和sector和current_nr_sectors等找不到,刚开始以为头文件没找到,因为elv_next_request函数在#include
make -C /home/yao/kernel_apollo_pro_hdnp SUBDIRS=/home/yao/driver/block modules
make[1]: Entering directory `/home/yao/kernel_apollo_pro_hdnp'
CC [M] /home/yao/driver/block/mod.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/yao/driver/block/mod.mod.o
LD [M] /home/yao/driver/block/mod.ko
make[1]: Leaving directory `/home/yao/kernel_apollo_pro_hdnp'
编译通过,首先声明一下,该内核版本是2.6.27,,为什么会这样,我也不知道,于是将mod.ko下到开发板加载,insmod有出错了,说没有足够的内存,郁闷了,可能是开发板的内存太小,不适合这个基于内存的驱动,想一下还是在虚拟机里面做,于是有google一下,有人说内核版本问题新的内核没有elv_next_request这个函数了,,这是后我想起来,是不是我的内核版本太高了,于是,我吧编译环境改成red hat enterprise 5 该内核是2.6.18,编译通过,看来是内核版本问题,这也是为什么我要在前面写开发环境的原因。
该编译虽然通过,但是格式化时有些问题,以后研究