块设备驱动程序设计(3)—简单块设备驱动设计
这节课的内容主要根据上一节课分析出来的块设备的初始化和操作流程,编写出自己的块设备驱动函数。因此这篇博文主要讲一下所用到函数的用法及其他框架。
- 1、编写一个模块框架
- 2、注册一个块设备major = register_blkdev(major, "blk");它有2个参数,主设备号和设备名字,一般采用内核自动分配,所以这里参数为0,自动分配的设备号会以返回值的形式得到。如果返回值小于等于0,说明主设备号分配失败,应提示错误信息,并返回-EBUSY(这个宏在<linux/errno.h> 中)。第二个参数是设备的名字。
- 3、完成其他初始化工作,定义一个setup_device函数来实现。
- 3.1 计算块设备的大小
/计算设备大小 dev->size = nsectors*sect_size; dev->data = vmalloc(dev->size);
3.2 初始化一个请求队列,使用dev->queue = blk_init_queue(blk_request, NULL);,第一个参数是对请求的响应函数,这个定义为blk_request,第二个参数是自旋锁一般为空。返回值是这个队列的地址,这里我们自己定义一个结构来保存这个队列。
struct blk_dev{int size; /* Device size in sectors */u8 *data; /* The data array */struct request_queue *queue; /* The device request queue */struct gendisk *gd; /* The gendisk structure */ };
定义好之后应该在blk_init函数中为这个结构申请一个空间dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
- 3.3 使用blk_queue_logical_block_size指明设备的扇区大小,参数分别为请求队列和块的大小
- 3.4 分配分配gendisk结构,每一个块设备在内核中都有gendisk结构来指定,使用dev->gd = alloc_disk(1);,参数表示这个设备可以支持多少种块设备,这里为了简单可以填1。把返回的gendisk指针保存起来。
- 3.5 对gendisk结构完成初始化:
// 初始化gendisk结构 dev->gd->major = major; //主设备号 dev->gd->first_minor = 0; //次设备号 dev->gd->fops = &blk_ops; //操作函数集 dev->gd->queue = dev->queue; //请求队列 dev->gd->private_data = dev; //私有数据 sprintf(dev->gd->disk_name, "simp_blk%d", 0); //磁盘名字 set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数
4、编写块设备请求函数static void blk_request(struct request_queue *q),参数是请求队列
- 4.1 从请求队列中拿出一个请求,req = blk_fetch_request(q);如果不为空说明拿到了,处理这个请求,再判断队列是否为空,如果不为空接着处理第二个请求。这里的处理函数通过blk_transfer来实现。
- 5、编写块设备处理函数blk_transfer,它的参数包括dev接口,操作起始扇区,操作扇区数,存放数据缓存的结构,然后是读写状态
- blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
- 6、编写块设备退出程序
- 6.1 注销gendiskdel_gendisk(dev->gd);
- 6.2 清除队列blk_cleanup_queue(dev->queue);
- 6.3 释放分配的空间vfree(dev->data);
- 6.4 注销块设备unregister_blkdev(major, "blk");
- 6.5 释放dev结构kfree(dev);
- 完整代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/blkdev.h>
#include <linux/bio.h>static int major = 0;
static int sect_size = 512; // 扇区大小
static int nsectors = 1024; // 扇区数struct blk_dev
{int size;u8 *data;struct request_queue *queue;struct gendisk *gd;
};struct blk_dev *dev;static struct block_device_operations blk_ops =
{.owner = THIS_MODULE,
};void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)
{unsigned long offset = sector * sect_size; // 操作的起始地址unsigned long nbytes = nsect * sect_size; // 操作的数据量if (write)memcpy (dev->data + offset, buffer, nbytes);elsememcpy (buffer, dev->data + offset, nbytes);
}static void blk_request(struct request_queue *q)
{struct request *req;// 从队列中取出一个请求req = blk_fetch_request(q); while (req != NULL){// 处理该请求blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));if (!__blk_end_request_cur(req, 0))req = blk_fetch_request(q); }
}void setup_device()
{// 计算块设备的大小dev->size = nsectors * sect_size; dev->data = vmalloc(dev->size); // 初始化一个请求队列dev->queue = blk_init_queue(blk_request, NULL);// 指明设备的扇区大小,参数分别为请求队列和块的大小blk_queue_logical_block_size(dev->queue, sect_size);// 分配gendisk结构dev->gd = alloc_disk(1);// 初始化gendisk结构dev->gd->major = major; //主设备号dev->gd->first_minor = 0; //次设备号dev->gd->fops = &blk_ops; //操作函数集dev->gd->queue = dev->queue; //请求队列dev->gd->private_data = dev; //私有数据sprintf(dev->gd->disk_name, "simp_blk%d", 0); //磁盘名字set_capacity(dev->gd, nsectors*(sect_size / sect_size)); //分配扇区数// 注册gendiskadd_disk(dev->gd);
}int blk_init()
{// 注册一个块设备major = register_blkdev(0, "blk"); if (major <= 0){printk("register blk dev fail!\n"); return -EBUSY; }dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);setup_device();return 0;
}void blk_exit()
{del_gendisk(dev->gd);blk_cleanup_queue(dev->queue);vfree(dev->data);unregister_blkdev(major, "blk");kfree(dev);
}module_init(blk_init);
module_exit(blk_exit);
块设备驱动程序设计(3)—简单块设备驱动设计相关推荐
- Linux USB设备驱动程序设计 和 USB下载线驱动设计
Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...
- linux下spi flash驱动程序,关于spi flash芯片m25p80驱动以及其简单的mtd驱动分析
项目中用到了spi flash芯片MX25L25635E,之前在uboot下简单分析了驱动代码,调试该flash擦除的bug,一直没有时间分 析内核中关于该芯片的驱动,以下是对该芯片驱动的一个简单分析 ...
- 驱动开发之六 --- 一个简单的显示驱动之一 [译文]
这个系列的文章在网上到处都是 这里也不清楚谁才是原文作者 我这里做个整理,标注一下希望大家能看的更加舒服一点 目录 (一)驱动开发一个简单的显示驱动 (二)驱动开发一个简单的显示驱动 (三)驱动开发一 ...
- Linux驱动开发--写一个块设备驱动
原文地址:[原创] 写一个块设备驱动 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2017377&fromuid=288 ...
- 基于块的linux驱动程序,基于块的Linux驱动程序 块设备驱动 centos内核编译过程 操作系统课程设计...
操作系统的课程设计,本人也是一头雾水地做完了课程设计,在这里贴下操作过程,放下当时参考的一篇CSDN文章链接:https://blog.csdn.net/cxy_chen/article/detail ...
- Linux块设备驱动(二)————块设备的体系架构
块设备的体系架构从上到下依次为VFS虚拟文件系统.磁盘缓冲.各种类型的磁盘系统.通用块设备层.I/O调度层(优化访问上层的请求(读写请求)).块设备驱动层.块设备硬件层. 1.虚拟文件系统(VFS) ...
- linux块设备驱动(一)——块设备概念介绍
linux块设备驱动(一)--块设备概念介绍 本文来源于: 1. http://blog.csdn.net/jianchi88/article/details/7212370 2. http://bl ...
- linux 块设备驱动(二)——块设备数据结构
linux 块设备驱动(二)--块设备数据结构 本文来源于: 1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html 块 ...
- linux 块设备驱动 (三)块设备驱动开发
linux 块设备驱动 (三)块设备驱动开发 一: 块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为: int ...
最新文章
- 自然语言处理(NLP)之pyltp的介绍与使用(中文分词、词性标注、命名实体识别、依存句法分析、语义角色标注)
- crm创建和编辑全局选项集
- Redis 的缓存异常处理 —— 缓存雪崩、缓存击穿、缓存穿透
- Spring在bean配置文件中定义电子邮件模板
- shell排序_Python排序算法(五)希尔排序
- 138. 复制带随机指针的链表 golang
- 【算法分析与设计】寻找假币问题
- 程序员不满薪资拒绝offer,HR怒称:估计你一辈子就是个程序员了!
- 信签纸有虚线怎么写_edm邮件营销,专注解决你的开发信难题
- SQLServer数据库处于恢复挂起状态的解决办法
- 网络收藏夹--用来收藏我经常访问的网站
- Python——轮盘抽奖游戏
- 查看主板型号 两种方法
- 固态硬盘是什么接口_选对接口很重要:固态硬盘接错位置可能损失可达42%
- COCI 2016/2017 Round 4 C dp
- CSS动画,风车案例
- php mysql 性能_php插入mysql方式性能分析
- C C++混合编译问题,gcc可以编译过,但是g++编译不过(restrict引起的问题)
- Dev C++ 运行出现:源文件未编译
- 成功解决:Updates were rejected because the tip of your current branch is behind its remote...【解决方法】
热门文章
- 世界互联网大会还是那个大会,互联网的江湖却变了半边天
- Visio画图形状默认填充是蓝色,如何修改成黑白?如何修改Visio样式?毕业设计流程图,功能结构图!
- el-table懒加载刷新
- Linux 自定义网桥配置静态 IP
- EasyPoi实现Excel数据导入
- deepin20系统选择手动安装盘_Mac USB启动安装盘制作 (U盘安装 Mac 系统) / 兼10.14 Mojave降级办法...
- 《js中原型和原型链的深入理解》的笔记
- nohup忽略SIGHUP信号
- 网站移动端性能优化方法
- LeetCode-Python-1275. 找出井字棋的获胜者(模拟法)