11-S3C2440驱动学习(八)嵌入式linux-块设备驱动程序
来源:互联网 发布:ios 跳转到淘宝客户端 编辑:程序博客网 时间:2024/06/05 09:23
一、回顾字符设备驱动
1、简单字符设备驱动
对于简单的字符设备驱动,不需要采用分离分层的思想,主要包括以下几个部分。
2、复杂字符设备驱动
对于复杂的字符设备驱动,采用分离分层的思想,内核中已经实现好了核心层部分,我们只需要实现与硬件相关的部分就可以,最后形成一个总体。这样就是一个通用的字符驱动框架。如LCD驱动、V4L2驱动,当然有时候我们可以选择不采用分离分层的思想,按简单驱动程序的框架来实现一个驱动。
3、字符设备驱动常用技巧
(1) 查询方式
(2) 休眠唤醒,APP-read drv_read
(3) poll机制
(4) 异步通知发信号
(5) 通用驱动程序:输入子系统、融入内核代码
二、块设备驱动
1、一些概念
硬盘里面有很多磁头,每个磁头有很多环,类似跑道。称为柱面:0柱面 1柱面;跑道里面有很多块称为扇区:扇区0 扇区1。硬盘操作的耗时主要在磁盘转换的时候,如果我们一会读1磁头,一会写2磁头,然后又读1磁头,如果来回这么跳转,会导致效率十分低。
.
(2)Flash
Flash有很多块,每个块里面有很多扇区。
Flash以块为单位进行操作。操作扇区时也需要读取整个块到内存中。如果读1块中的1扇区,又去写2块的1扇区,然后又读1块的2扇区,如果不优化效率将很低。
因此,基于以上硬件的特点,及效率问题,内核采用了电梯调度算法进行命令的优化。也就是收到一个命令时不会立刻执行,而是放入队列,当存在多个命令时,经过电梯调度算法来进行优化后执行,这样就提升了读写的效率,这个是块设备驱动程序要考虑的问题。
2、块设备驱动程序的框架
应用程序文件读写—》扇区读写,文件系统来做转换之后调用ll_rw_block函数操作块设备。
那么扇区读写函数是?
ll_rw_block:low_level read write block
ll_rw_block作用:把读写放入队列并优化,之后调用队列的处理函数。即优化后执行。
分析ll_rw_block for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; submit_bh(rw, bh); struct bio *bio; // 使用bh来构造bio (block input/output) submit_bio(rw, bio); // 通用的构造请求: 使用bio来构造请求(request) generic_make_request(bio); __generic_make_request(bio); request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列 // 调用队列的"构造请求函数" ret = q->make_request_fn(q, bio); // 默认的函数是__make_request __make_request // 先尝试合并 elv_merge(q, &req, bio); // 如果合并不成,使用bio构造请求 init_request_from_bio(req, bio); // 把请求放入队列 add_request(q, req); // 执行队列 __generic_unplug_device(q); // 调用队列的"处理函数" q->request_fn(q);
int submit_bh(int rw, struct buffer_head *bh)
函数作用:用buffer_head来构造bio,最后提交bio--》submit_bio
void submit_bio(int rw, struct bio *bio)
--generic_make_request
函数作用:使用bio来构造请求,把请求放入队列。
elv_merge(q, &req, bio); 电梯调度算法,来尝试把bio合并到队列里面去。如果合并不成,使用bio构造请求init_request_from_bio(req, bio); 把请求放入队列add_request(q,req); 执行队列__generic_unplug_device(q); 调用队列的"处理函数" q->request_fn(q);
这里强调:块设备的读写并不会立刻执行,而是先放入队列进行优化。
3、怎么写块设备驱动程序呢?
常规思路,分配结构体,设置结构体,注册到某个地方。
(1)分配gendisk:alloc_disk
(2)设置
分配/设置队列: request_queue_t // 它提供读写能力
blk_init_queue //设备队列
设置gendisk其他信息 // 它提供属性: 比如容量
(3) 注册: add_disk
4、内存模拟块设备
参考:drivers\block\xd.c
drivers\block\z2ram.c
(1)拷贝头文件,搭出框架
(2)明确需要做的任务
/*1. 分配一个gendisk结构体 */
/*2. 设置 */
/*2.1 分配/设置队列: 提供读写能力 */
/*2.2 设置其他属性: 比如容量 */
/*3. 注册 */
(3)实现ramblock_disk = alloc_disk(16); /* 次设备号个数: 分区个数+1 */
ramblock_buf= kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);//分配内存模拟
while ((req = elv_next_request(q)) != NULL)//电梯调度算法
/* 参考: * drivers\block\xd.c * drivers\block\z2ram.c */#include <linux/module.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/genhd.h>#include <linux/hdreg.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/delay.h>#include <linux/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/dma.h>static struct gendisk *ramblock_disk;static request_queue_t *ramblock_queue;static int major;static DEFINE_SPINLOCK(ramblock_lock);#define RAMBLOCK_SIZE (1024*1024)static unsigned char *ramblock_buf;static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo){/* 容量=heads*cylinders*sectors*512 */geo->heads = 2;geo->cylinders = 32;geo->sectors = RAMBLOCK_SIZE/2/32/512;return 0;}static struct block_device_operations ramblock_fops = {.owner= THIS_MODULE,.getgeo= ramblock_getgeo,};static void do_ramblock_request(request_queue_t * q){static int r_cnt = 0;static int w_cnt = 0;struct request *req;//printk("do_ramblock_request %d\n", ++cnt);while ((req = elv_next_request(q)) != NULL) {/* 数据传输三要素: 源,目的,长度 *//* 源/目的: */unsigned long offset = req->sector * 512;/* 目的/源: */// req->buffer/* 长度: */unsigned long len = req->current_nr_sectors * 512;if (rq_data_dir(req) == READ){//printk("do_ramblock_request read %d\n", ++r_cnt);memcpy(req->buffer, ramblock_buf+offset, len);}else{//printk("do_ramblock_request write %d\n", ++w_cnt);memcpy(ramblock_buf+offset, req->buffer, len);}end_request(req, 1);}}static int ramblock_init(void){/* 1. 分配一个gendisk结构体 */ramblock_disk = alloc_disk(16); /* 次设备号个数: 分区个数+1 *//* 2. 设置 *//* 2.1 分配/设置队列: 提供读写能力 */ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);ramblock_disk->queue = ramblock_queue;/* 2.2 设置其他属性: 比如容量 */major = register_blkdev(0, "ramblock"); /* cat /proc/devices */ramblock_disk->major = major;ramblock_disk->first_minor = 0;sprintf(ramblock_disk->disk_name, "ramblock");ramblock_disk->fops = &ramblock_fops;set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);/* 3. 硬件相关操作 */ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);/* 4. 注册 */add_disk(ramblock_disk);return 0;}static void ramblock_exit(void){unregister_blkdev(major, "ramblock");del_gendisk(ramblock_disk);put_disk(ramblock_disk);blk_cleanup_queue(ramblock_queue);kfree(ramblock_buf);}module_init(ramblock_init);module_exit(ramblock_exit);MODULE_LICENSE("GPL");
(4)实验
没有立刻写,等一会才出现write
要么都是读要么都是写 不会一读一写。效率高
分区试试
柱面数不知道
static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo){/* 容量=heads*cylinders*sectors*512 */geo->heads = 2; // 多少磁头 多少面 2面geo->cylinders = 32; // 多少个柱面 多少环 32环 geo->sectors = RAMBLOCK_SIZE/2/32/512;//一环里面多少扇区return 0;}
测试5th:
1. insmod ramblock.ko
2. ls /dev/ramblock*
3. fdisk /dev/ramblock
分别操作分区。
- 11-S3C2440驱动学习(八)嵌入式linux-块设备驱动程序
- 11-S3C2440驱动学习(八)嵌入式linux-块设备驱动(2)之Nand Flash驱动
- 10-S3C2440驱动学习(四)嵌入式linux-LCD驱动程序
- 11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 11-S3C2440驱动学习(五)嵌入式linux-网络设备驱动(一)虚拟网卡驱动程序
- 11-S3C2440驱动学习(五)嵌入式linux-网络设备驱动(二)移植DM9000C网卡驱动程序
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-LED字符设备驱动
- 12-S3C2440驱动学习(九)嵌入式linux-USB驱动程序(未完待续)
- 10-S3C2440驱动学习(六)嵌入式linux-触摸屏设备驱动
- 09-S3C2440驱动学习(三)嵌入式linux-platform平台总线驱动程序及分离分层构建驱动框架
- 块设备驱动程序(Linux设备驱动程序)
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- Linux块设备驱动(三)————块设备驱动程序的框架
- linux块设备驱动学习(一)
- 嵌入式linux驱动-块设备笔记
- linux 块设备驱动程序
- 嵌入式linux之块设备驱动程序概念,框架
- C语言实现简易通讯录
- 正则表达式介绍
- 51nod--1113 矩阵快速幂
- 悟空传电影悟空传百度云资源
- 优先队列的 java 代码实现
- 11-S3C2440驱动学习(八)嵌入式linux-块设备驱动程序
- windows 下进程池的操作
- 19、多线程
- 已知一个字符串都是由左括号(和右括号)组成,判断该字符串是否是有效的括号组合。
- MVG读书笔记——齐次坐标与射影几何
- Android图形显示系统——概述
- 文件权限
- 8款实用HTML5开发框架
- 推荐算法——基于图模型