非常简单的一个块设备驱动,simp_blkdev,2.6.31之后的变化
以下代码亲测在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之后的变化相关推荐
- [转]写一个块设备驱动(第八章)
第8章 +---------------------------------------------------+ | 写一个块设备驱动 ...
- [转]写一个块设备驱动(第一章)
写一个块设备驱动1,2(转) 2009/09/03 15:42 第1章 +---------------------------------------------------+ | ...
- 转:写一个块设备驱动
----------------------- Page 1----------------------- 第 1章 +---------------------------------------- ...
- 写一个块设备驱动5,6
http://blogold.chinaunix.net/u3/108239/showart.php?id=2144628 第5章 +--------------------------------- ...
- Linux驱动开发--写一个块设备驱动
原文地址:[原创] 写一个块设备驱动 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2017377&fromuid=288 ...
- 写一个块设备驱动1,2
http://blogold.chinaunix.net/u3/108239/showart.php?id=2144624 第1章 +--------------------------------- ...
- 写一个块设备驱动1,2(转)
第1章 +---------------------------------------------------+ |???????????????? 写一个块设备驱动???????????????? ...
- 写一个块设备驱动5,6(转)
第5章 +---------------------------------------------------+ |???????????????? 写一个块设备驱动???????????????? ...
- 第6章 写一个块设备驱动
第6章 +---------------------------------------------------+ | 写一个块设备驱动 ...
最新文章
- Python 进阶 — 面向对象设计原则
- php in循环与for循环,详谈js中标准for循环与foreach(for in)的区别
- 深入浅出,Spring 框架和 Spring Boot 的故事
- oracle数据库的导入导出
- opencv轮廓周长原理_OpenCV3 - 轮廓特征
- Java面试 - HashMap的底层实现,之后会问ConcurrentHashMap的底层实现
- Opencore-黑苹果:外接4K显示器却只能选择2K或以下分辨率
- 5. 直接三角形分解法
- java学习日记-基础-列出2~100内的素数
- VMThread占CPU高基本上是JVM在频繁GC导致,原因基本上是冰法下短时间内创建了大量对象堆积造成频繁GC。...
- Overleaf 中文硕博论文LaTex模板
- (附源码)ssm教培管理系统 毕业设计 230932
- 前端开发工具Axure——Axure原型图查看
- 如何把拼音放在文字的右侧,干货到,在WORD中怎么把拼音和汉字同排
- 物联网:GPRS和NB-IOT
- R2S设置openWrt软路由
- WPF之布局属性HorizontalAlignment、HorizontalContentAlignment、VertialAlignment、VerticalContentAlignment
- TYPEC 接口芯片CC逻辑原理与必要性
- 设置iPhone的呼叫转移来电等待
- cx_Oracle使用方法
热门文章
- 【EasyRL学习笔记】第二章 Markov Decision Process 马尔可夫决策过程
- DQN(基本概念和进阶技巧)
- 按excel表格顺序批量改变图片名字:
- LS-DYNA中射流冲击模型的技术难点及案例模型
- TCP通信基础(一发一收)
- C++:按位异或运算符:^
- 浅谈UML中的聚合与组合
- 今年全系 iPhone 都是 4G 运存——11 突然变香了!
- 施工员是做什么的?施工员证书怎么考?
- 图片头顶距离顶部百分比怎么修改_迷你世界:爱吃糖葫芦怎么办?学会模型制作,美食甜品自己做!...