http://blog.chinaunix.net/uid-28236237-id-3989135.html
分析uboot中的nand flash。查找了一些资料,看了韦东山移植。也不是很懂,nand flash设计一些框架,框架的调用需要长时间的分析。暂不分析,引用他人的资料,做个小结。
MTD是linux内核为了简化对Flash设备的编程而建立的一种驱动框架。当各种Flash设备需要加入到linux的内核中时,不需要编写复杂的驱动程序来在内核中建立块设备等等。而只需要遵循MTD驱动的架构,实现相应的驱动接口,就能将各种Flash设备加入到内核中去。并在内核中形成块设备,字符设备等等。
总而言之MTD就是将各种Flash设备的一些共有特性抽象出来,在文件系统和设备之间形成一种联系和框架。所有的Flash设备可以利用这个框架来加入内核中,而设备之需要实现框架没有的特性,就能完成开发。
MTD可以分为设备节点层,MTD块设备层,MTD原始设备层和硬件设备层。本节首先介绍一下硬件设备层和MTD原始设备层。
首先我们要介绍一下MTD中几个重量级的数据结构,一个是mtd_info,这个这数据结构主要记录Flash设备的一些关键信息和对Flash物理设备进行操作的函数。关键信息有
Flash的大小、Flash的擦除块大小、Flash的写块大小、Flash的oob大小等等。
而对Flash硬件设备操作函数的指针有
Flash擦除操作、Flash写操作、Flash读取操作
一般来说,设备驱动程序需要给mtd_info结构安装硬件操作的指针,这样上层块层的操作可以调用这些函数完成具体的读写操作。但是,MTD越来越完善给开发者考虑得很全面,就是mtd_info中的操作函数都提供了NAND抽象、NOR Flash的抽象。硬件驱动只需要去关心更加底层的一些操作了。
然后另外一个很重要的结构体就是mtd_part,这个结构体表示一个MTD设备的一个分区,其中包含了一个mtd_info结构体(表示这个分区结构),还有一个mtd_info的指针。Mtd_info指针指向了表示整个MTD设备的数据结构。然后还有一个表示分区在整个mtd设备上偏移的数据。
对于硬件驱动的工作就是,初始化好mtd_info和mtd_part两个结构体,然后调用mtd层的相关函数向mtd层进行注册。仅此而已。最后在mtd层中需要形成如下的数据结构联系,如下图所示。下面我们首先分析这个过程。
size = nr_sets * sizeof(*info->mtds);
/*分配mtd_info结构体*/
info->mtds = kmalloc(size, GFP_KERNEL);
if (info->mtds == NULL)
{
dev_err(&pdev->dev, "failed to allocate mtd storage\n");
err = -ENOMEM;
goto exit_error;
}
memset(info->mtds, 0, size);
/* initialise all possible chips */
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++)
{
pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
/*准备使用内核中的nand mtd框架,首先初始化一些底层的操作*/
s3c2410_nand_init_chip(info, nmtd, sets);
/*读写chip id 并初始化一些mtd_info的域*/
nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
(sets) ? sets->nr_chips : 1);
if (nmtd->scan_res == 0)
{
s3c2410_nand_update_chip(info, nmtd);
/*将mtd_info中的函数指针初始化*/
nand_scan_tail(&nmtd->mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
if (sets != NULL)
sets++;
}
|
上面这段代码主要完成对mtd_info的初始化操作,其中还涉及到了一个数据结构nand_chip,这个数据结构中也是各种操作函数指针,上面我们说到内核中mtd越来越完善。驱动可以自己去实现mtd_info中的read、write函数,但是也可以选择使用mtd框架中的已经实现的nand_read、nand_write函数去初始化mtd_info,mtd又抽象了一层,而把驱动中需要自己实现的操作包含在了nand_chip结构体中。
实际上上面的初始化代码中,真正硬件驱动自己的代码只有s3c2410_nand_init_chip函数,这个函数将nand_chip中一些重要的必须的函数实现并初始化一下。接下来就是调用mtd nand层来进行程序化的初始化操作。
/* s3c2410_nand_init_chip
*
* init a single instance of an chip
*/
static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd,
struct s3c2410_nand_set *set)
{
struct nand_chip *chip = &nmtd->chip;
void __iomem *regs = info->regs;
/*初始化必须实现的几个函数*/
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
chip->chip_delay = 50;
chip->priv = nmtd;
chip->options = 0;
chip->controller = &info->controller;
switch (info->cpu_type)
{
case TYPE_S3C2410:
break;
case TYPE_S3C2440:
chip->IO_ADDR_W = regs + S3C2440_NFDATA;
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2440_NFCONT_nFCE;
/*初始化必须实现的几个函数*/
chip->cmd_ctrl = s3c2440_nand_hwcontrol;
chip->dev_ready = s3c2440_nand_devready;
chip->read_buf = s3c2440_nand_read_buf;
chip->write_buf = s3c2440_nand_write_buf;
break;
case TYPE_S3C2412:
break;
}
chip->IO_ADDR_R = chip->IO_ADDR_W;
nmtd->info = info;
/*mtd 层调用mtd nand层的函数时将nand_chip数据传入*/
nmtd->mtd.priv = chip;
nmtd->mtd.owner = THIS_MODULE;
nmtd->set = set;
if (hardware_ecc)
{
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
.....
}
else
{
chip->ecc.mode = NAND_ECC_SOFT;
}
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;
if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE;
}
|
在初始化Flash 设备时,一件最重要的事情就是确认系统中flash的类型,并初始化mtd_info
结构中Flash大小、擦写块大小、写page大小等等。这个工作在
int nand_scan_ident(struct mtd_info *mtd, int maxchips)函数中完成。这个函数已经是mtd nand模块提供的内核实现了。
读出了Flash相关的参数,会继续调用nand_scan_tail函数完成mtd_info结构中操作函数指针的挂接,这个过程也写非常非常重要的一个过程。
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
mtd->read = nand_read;
mtd->write = nand_write;
mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
mtd->suspend = nand_suspend;
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
|
完成上上面的初始化后,调用下面函数将mtd_info注册到mtd层中,硬件驱动的工作就基本完成。而这个注册过程如下图函数调用关系所示
static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *mtd,
struct s3c2410_nand_set *set)
{
if (set == NULL)
return add_mtd_device(&mtd->mtd);
if (set->nr_partitions > 0 && set->partitions != NULL)
{
return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions);
}
return add_mtd_device(&mtd->mtd);
}
|
mtd驱动分析-硬件驱动层相关推荐
- CMOS摄像头驱动分析-i2c驱动
CMOS摄像头驱动分析-i2c驱动 文章目录 CMOS摄像头驱动分析-i2c驱动 设备树内容 module_i2c_driver宏分析 ov2640_i2c_driver ov2640_probe 设 ...
- Linux USB 3.0驱动分析—UAC驱动分析
转自 https://www.cnblogs.com/wen123456/p/14281917.html 因为项目里面有USB音频外设,所以需要分析一下UAC驱动. USB Audio Class,U ...
- python硬件驱动_硬件驱动python
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! linux获取linux硬件信息的方式,有很多. 1.使用puppet或者sal ...
- Linux查看网卡加载驱动,linux网卡驱动分析之驱动加载
通过insmod或者modprobe命令加载驱动,这两个命令为应用程序,在应用程序里调用了一个系统调用: extern long init_module(void *, unsigned long, ...
- 全志t3linux驱动_全志A20GPIO驱动分析|Android驱动及系统开发交流区|研发交流|雨滴科技技术论坛 - Powered by Discuz!...
虽然成功控制了PH17脚输出高低电平,但是我感觉什么都没有获取到(关于Linux的字符设备驱动). 打算把驱动直接编译进内核,首先看看怎样把自己的驱动添加到内核配置界面上.打开内核配置界面,在lich ...
- 20150311 NandFlash驱动分析
20150311 NandFlash驱动分析 2015-03-11 李海沿 一.结构体详解 MTD体系结构: 在linux中提供了MTD(Memory Technology Device,内存技术设备 ...
- rt-thread SDIO驱动框架分析(SD卡驱动\SD Nand驱动)
rt-thread SDIO驱动框架分析之SD卡驱动 文章目录 rt-thread SDIO驱动框架分析之SD卡驱动 1. 前言 2. SDIO通用驱动框架介绍 3. 文件架构分析 4. SDIO设备 ...
- USB转串口驱动分析(一)
之前追踪代码用的grep命令效率太低了,所以这次下载C代码阅读跳转利器ctags.cscope用于分析代码 因为用的是Centos6.7所以需要用到yum install安装软件 [wuyujun@w ...
- RK3399平台开发系列讲解(内核驱动外设篇)6.21、RK LCD显示驱动分析(fb和screen 部分程序)
平台 内核版本 安卓版本 px3 Linux3.0 Android7.1 查看设备: ls /sys/devices/platform display驱动分析: RK LCD这块首先分为四大块相互依赖 ...
最新文章
- oschina添加ssh公钥一记
- C语言关于signal()函数
- ICCV 2017 CREST:《CREST: Convolutional Residual Learning for Visual Tracking》论文笔记
- boost::throw_exception的测试程序
- MySQL模糊查询—in关键字
- 调用WindowsAPI显示帮助提示
- Redis 7.0 Multi Part AOF的设计和实现
- CRS磁盘force dismount引起的RAC节点宕机故障
- matlab size
- notification 是同步的
- iOS -- MBProgressHUB
- Windows下 Nginx创建文件服务器
- java计算机毕业设计考试编排管理系统源码+mysql数据库+系统+lw文档+部署
- Python 矩形积分法推荐采样点设置个数
- [BZOJ2286] [Sdoi2011]消耗战
- 趣味记忆5大经典的软件架构风格
- 【Microsoft Azure 的1024种玩法】九. Microsoft Azure云端轻松构建部署PostgreSQL数据库...
- GPRS模块发送短信
- 几分钟搞定,文件名称中文转英文
- 用Java模拟斗地主游戏
热门文章
- 专升本第四讲(计算机的“灵魂”)
- 《操作系统之哲学原理(第2版)》——— 操作系统的发展历史
- 浅谈DC-IRIS的PID控制方法
- windows 2003 删除一键恢复EISA
- google play直接下载apk安装包文件教程(blynk)
- linux 板卡驱动开源项目Comedi使用编译流程
- 太阳能路灯的根本结构及作业原理
- MATLAB常用命令及函数大全(字母顺序)
- springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod
- Qt编写可视化大屏电子看板系统30-模块8物料管理