块设备驱动系统架构和简单设计
2017-08-15 09:08
288 查看
1.块设备概念
块设备是指只能以块(512Byte)为单位进行访问的设备,块大小一般是512个字节的整数倍。常见的块设备包括硬件,SD卡,光盘等。
2.快速体验
insmod simple-blk.ko
ls /dev/simp_blkdev0
mkfs.ext3 /dev/simp_blk0
mkdir –p /mnt/blk
mount /dev/simp_blk0 /mnt/blk
cp /etc/init.d/* /mnt/blk
ls /mnt/blk
umount /mnt/blk
ls /mnt/blk
3.块设备驱动系统架构
VFS是对各种具体文件系统的一种封装 ,为用户程序访问文件提供统一的接口。
4.系统架构-Cache
当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存了,如果在cache中,则直接从cache中读取。
如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。
5.Mapping Layer(映射层、FS文件系统)
1. 首先确定文件系统的block size,然后计算所请求的数据包含多少个block。
2. 调用具体文件系统的函数来访问文件的inode结构,确定所请求的数据在磁盘上的地址。
6. Generic Block Layer
Linux内核把把块设备看作是由若干个扇区组成的数据空间。上层的读写请求在通用块层被构造成一个或多个bio结构。
7. I/O Scheduler Layer
I/O调度层负责采用某种算法(如:电梯调度算法)将I/O操作进行排序。
8. I/O Scheduler Layer
电梯调度算法的基本原则:如果电梯现在朝上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。
9.块设备驱动
在块系统架构的最底层,由块设备驱动根据排序好的请求,对硬件进行数据访问。
10.块设备驱动实例分析
#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>
MODULE_LICENSE("Dual BSD/GPL");
static int major = 0;
static int sect_size = 512;
static int nsectors = 1024;
/*
* The internal representation of our device.
*/
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 */
};
struct blk_dev *dev;
/*
* Handle an I/O request, in sectors.
*/
static 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 ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes); //对内存读写
else
memcpy(buffer, dev->data + offset, nbytes);
}
/*
* The simple form of the request function.
*/
static void blk_request(struct request_queue *q) //实现读写请求处理函数
{
struct request *req;
req = blk_fetch_request(q); //从队列中取出一个请求
while (req != NULL) {
struct blk_dev *dev = req->rq_disk->private_data;
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); //嵌套处理
}
}
}
/*
* The device operations structure.
*/
static struct block_device_operations blk_ops = {
.owner = THIS_MODULE,
};
/*
* Set up our internal device.
*/
static void setup_device()
{
/*
* Get some memory.
*/
dev->size = nsectors*sect_size; //获取设备大小
dev->data = vmalloc(dev->size); //获取数据指针
if (dev->data == NULL) {
printk (KERN_NOTICE "vmalloc failure.\n");
return;
}
dev->queue = blk_init_queue(blk_request, NULL); //请求队列初始化,blk_request是处理上层传下来的请求的
if (dev->queue == NULL)
goto out_vfree;
blk_queue_logical_block_size(dev->queue, sect_size); //指明扇区大小
dev->queue->queuedata = dev;
/*
* And the gendisk structure.
*/
dev->gd = alloc_disk(1); //为块设备分配gendisk结构,并初始化
if (! dev->gd) {
printk (KERN_NOTICE "alloc_disk failure\n");
goto out_vfree;
}
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));
add_disk(dev->gd); //注册块设备
return;
out_vfree:
if (dev->data)
vfree(dev->data);
}
static int __init blk_init(void)
{
/*
* Get registered.
*/
major = register_blkdev(major, "blk"); //注册块设备驱动,major若为0会自动分配
if (major <= 0) {
printk(KERN_WARNING "blk: unable to get major number\n");
return -EBUSY;
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL); //分配一个blk_dev空间
if (dev == NULL)
goto out_unregister;
setup_device(); //调用函数
return 0;
out_unregister:
unregister_blkdev(major, "sbd");
return -ENOMEM;
}
static void blk_exit(void)
{
if (dev->gd) {
del_gendisk(dev->gd);
put_disk(dev->gd);
}
if (dev->queue)
blk_cleanup_queue(dev->queue);
if (dev->data)
vfree(dev->data);
unregister_blkdev(major, "blk");
kfree(dev);
}
module_init(blk_init);
module_exit(blk_exit);
11、简单块设备驱动设计
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/genhd.h>
MODULE_LICENSE("GPL");
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 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 nbyte = nsect * sect_size;
if((offset + nbyte) > dev->size)
{
printk(KERN_NOTICE"Beyond-end write (%ld %ld)\n", offset, nbyte);
return;
}
if(write)
{
memcpy(dev->data + offset, buffer, nbyte);
}
else
{
memcpy(buffer, dev->data + offset, nbyte);
}
}
void blk_request(struct request_queue *q)
{
struct request *req;
req = blk_fetch_request(q);
while(req != NULL)
{
struct blk_dev *dev = req->rq_disk->private_data;
//处理该请求
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);
}
}
static struct block_device_operations blk_ops = {
.owner = THIS_MODULE,
};
static void setup_device(void)
{
dev->size = nsectors * sect_size;
dev->data = vmalloc(dev->size);
if(dev->data == NULL) {
printk(KERN_NOTICE "vmalloc failure.\n");
return;
}
dev->queue = blk_init_queue(blk_request, NULL);
if(dev->queue == NULL)
{
goto out_vfree;
}
blk_queue_logical_block_size(dev->queue, sect_size);
dev->queue->queuedata = dev;
dev->gd = alloc_disk(1);
if(!dev->gd)
{
printk(KERN_NOTICE "alloc_disk failure\n");
goto out_vfree;
}
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);
add_disk(dev->gd);
return;
out_vfree:
if(dev->data)
vfree(dev->data);
}
static int __init blk_init(void)
{
major = register_blkdev(0, "blk");
if(major <= 0)
{
printk(KERN_WARNING "register blk dev fail!\n");
return -EBUSY;
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
if(dev == NULL)
goto out_unregister;
setup_device();
return 0;
out_unregister:
unregister_blkdev(major, "sbd");
return -ENOMEM;
}
static void blk_exit(void)
{
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);
错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。
第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(68) | 评论(0) | 转发(0) |
0
上一篇:LCD驱动程序架构和分析
下一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计
相关热门文章
SHTML是什么_SSI有什么用...
查看linux中某个端口(port)...
卡尔曼滤波的原理说明...
shell中字符串操作
关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
块设备是指只能以块(512Byte)为单位进行访问的设备,块大小一般是512个字节的整数倍。常见的块设备包括硬件,SD卡,光盘等。
2.快速体验
insmod simple-blk.ko
ls /dev/simp_blkdev0
mkfs.ext3 /dev/simp_blk0
mkdir –p /mnt/blk
mount /dev/simp_blk0 /mnt/blk
cp /etc/init.d/* /mnt/blk
ls /mnt/blk
umount /mnt/blk
ls /mnt/blk
3.块设备驱动系统架构
VFS是对各种具体文件系统的一种封装 ,为用户程序访问文件提供统一的接口。
4.系统架构-Cache
当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存了,如果在cache中,则直接从cache中读取。
如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。
5.Mapping Layer(映射层、FS文件系统)
1. 首先确定文件系统的block size,然后计算所请求的数据包含多少个block。
2. 调用具体文件系统的函数来访问文件的inode结构,确定所请求的数据在磁盘上的地址。
6. Generic Block Layer
Linux内核把把块设备看作是由若干个扇区组成的数据空间。上层的读写请求在通用块层被构造成一个或多个bio结构。
7. I/O Scheduler Layer
I/O调度层负责采用某种算法(如:电梯调度算法)将I/O操作进行排序。
8. I/O Scheduler Layer
电梯调度算法的基本原则:如果电梯现在朝上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。
9.块设备驱动
在块系统架构的最底层,由块设备驱动根据排序好的请求,对硬件进行数据访问。
10.块设备驱动实例分析
#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>
MODULE_LICENSE("Dual BSD/GPL");
static int major = 0;
static int sect_size = 512;
static int nsectors = 1024;
/*
* The internal representation of our device.
*/
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 */
};
struct blk_dev *dev;
/*
* Handle an I/O request, in sectors.
*/
static 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 ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes); //对内存读写
else
memcpy(buffer, dev->data + offset, nbytes);
}
/*
* The simple form of the request function.
*/
static void blk_request(struct request_queue *q) //实现读写请求处理函数
{
struct request *req;
req = blk_fetch_request(q); //从队列中取出一个请求
while (req != NULL) {
struct blk_dev *dev = req->rq_disk->private_data;
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); //嵌套处理
}
}
}
/*
* The device operations structure.
*/
static struct block_device_operations blk_ops = {
.owner = THIS_MODULE,
};
/*
* Set up our internal device.
*/
static void setup_device()
{
/*
* Get some memory.
*/
dev->size = nsectors*sect_size; //获取设备大小
dev->data = vmalloc(dev->size); //获取数据指针
if (dev->data == NULL) {
printk (KERN_NOTICE "vmalloc failure.\n");
return;
}
dev->queue = blk_init_queue(blk_request, NULL); //请求队列初始化,blk_request是处理上层传下来的请求的
if (dev->queue == NULL)
goto out_vfree;
blk_queue_logical_block_size(dev->queue, sect_size); //指明扇区大小
dev->queue->queuedata = dev;
/*
* And the gendisk structure.
*/
dev->gd = alloc_disk(1); //为块设备分配gendisk结构,并初始化
if (! dev->gd) {
printk (KERN_NOTICE "alloc_disk failure\n");
goto out_vfree;
}
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));
add_disk(dev->gd); //注册块设备
return;
out_vfree:
if (dev->data)
vfree(dev->data);
}
static int __init blk_init(void)
{
/*
* Get registered.
*/
major = register_blkdev(major, "blk"); //注册块设备驱动,major若为0会自动分配
if (major <= 0) {
printk(KERN_WARNING "blk: unable to get major number\n");
return -EBUSY;
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL); //分配一个blk_dev空间
if (dev == NULL)
goto out_unregister;
setup_device(); //调用函数
return 0;
out_unregister:
unregister_blkdev(major, "sbd");
return -ENOMEM;
}
static void blk_exit(void)
{
if (dev->gd) {
del_gendisk(dev->gd);
put_disk(dev->gd);
}
if (dev->queue)
blk_cleanup_queue(dev->queue);
if (dev->data)
vfree(dev->data);
unregister_blkdev(major, "blk");
kfree(dev);
}
module_init(blk_init);
module_exit(blk_exit);
11、简单块设备驱动设计
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/genhd.h>
MODULE_LICENSE("GPL");
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 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 nbyte = nsect * sect_size;
if((offset + nbyte) > dev->size)
{
printk(KERN_NOTICE"Beyond-end write (%ld %ld)\n", offset, nbyte);
return;
}
if(write)
{
memcpy(dev->data + offset, buffer, nbyte);
}
else
{
memcpy(buffer, dev->data + offset, nbyte);
}
}
void blk_request(struct request_queue *q)
{
struct request *req;
req = blk_fetch_request(q);
while(req != NULL)
{
struct blk_dev *dev = req->rq_disk->private_data;
//处理该请求
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);
}
}
static struct block_device_operations blk_ops = {
.owner = THIS_MODULE,
};
static void setup_device(void)
{
dev->size = nsectors * sect_size;
dev->data = vmalloc(dev->size);
if(dev->data == NULL) {
printk(KERN_NOTICE "vmalloc failure.\n");
return;
}
dev->queue = blk_init_queue(blk_request, NULL);
if(dev->queue == NULL)
{
goto out_vfree;
}
blk_queue_logical_block_size(dev->queue, sect_size);
dev->queue->queuedata = dev;
dev->gd = alloc_disk(1);
if(!dev->gd)
{
printk(KERN_NOTICE "alloc_disk failure\n");
goto out_vfree;
}
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);
add_disk(dev->gd);
return;
out_vfree:
if(dev->data)
vfree(dev->data);
}
static int __init blk_init(void)
{
major = register_blkdev(0, "blk");
if(major <= 0)
{
printk(KERN_WARNING "register blk dev fail!\n");
return -EBUSY;
}
dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
if(dev == NULL)
goto out_unregister;
setup_device();
return 0;
out_unregister:
unregister_blkdev(major, "sbd");
return -ENOMEM;
}
static void blk_exit(void)
{
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);
错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。
第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(68) | 评论(0) | 转发(0) |
0
上一篇:LCD驱动程序架构和分析
下一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计
相关热门文章
SHTML是什么_SSI有什么用...
查看linux中某个端口(port)...
卡尔曼滤波的原理说明...
shell中字符串操作
关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
相关文章推荐
- 《Linux4.0设备驱动开发详解》笔记--第十九章:Linux电源管理的系统架构和驱动
- USB鼠标设备简单驱动设计
- Linux SPI总线和设备驱动架构之一:系统概述
- Linux SPI总线和设备驱动架构之一:系统概述
- MTD系统架构和yaffs2使用、Nandflash驱动设计
- Linux SPI总线和设备驱动架构之一:系统概述
- Linux SPI总线和设备驱动架构之一:系统概述
- 20155309南皓芯《信息安全系统设计基础》实验四:外设驱动设备设计 实验报告
- Linux SPI总线和设备驱动架构之一:系统概述
- 基于视窗系统 CE的USB设备驱动程式设计
- Linux SPI总线和设备驱动架构之一:系统概述
- 基于嵌入式wince平台的GPS手持终端设备系统及驱动设计
- 浅谈自己去设计的一套简单的系统架构
- [国嵌攻略][147][简单块设备驱动设计]
- 嵌入式Linux系统中I2C总线设备的驱动设计
- 架构设计:系统存储(10)——MySQL简单主从方案及暴露的问题
- 简单聊一聊系统架构设计的七个要素
- Linux SPI总线和设备驱动架构之一:系统概述
- 架构设计:系统存储(10)——MySQL简单主从方案及暴露的问题
- Linux SPI总线和设备驱动架构之一:系统概述