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驱动分析-硬件驱动层相关推荐

  1. CMOS摄像头驱动分析-i2c驱动

    CMOS摄像头驱动分析-i2c驱动 文章目录 CMOS摄像头驱动分析-i2c驱动 设备树内容 module_i2c_driver宏分析 ov2640_i2c_driver ov2640_probe 设 ...

  2. Linux USB 3.0驱动分析—UAC驱动分析

    转自 https://www.cnblogs.com/wen123456/p/14281917.html 因为项目里面有USB音频外设,所以需要分析一下UAC驱动. USB Audio Class,U ...

  3. python硬件驱动_硬件驱动python

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! linux获取linux硬件信息的方式,有很多. 1.使用puppet或者sal ...

  4. Linux查看网卡加载驱动,linux网卡驱动分析之驱动加载

    通过insmod或者modprobe命令加载驱动,这两个命令为应用程序,在应用程序里调用了一个系统调用: extern long init_module(void *, unsigned long, ...

  5. 全志t3linux驱动_全志A20GPIO驱动分析|Android驱动及系统开发交流区|研发交流|雨滴科技技术论坛 - Powered by Discuz!...

    虽然成功控制了PH17脚输出高低电平,但是我感觉什么都没有获取到(关于Linux的字符设备驱动). 打算把驱动直接编译进内核,首先看看怎样把自己的驱动添加到内核配置界面上.打开内核配置界面,在lich ...

  6. 20150311 NandFlash驱动分析

    20150311 NandFlash驱动分析 2015-03-11 李海沿 一.结构体详解 MTD体系结构: 在linux中提供了MTD(Memory Technology Device,内存技术设备 ...

  7. rt-thread SDIO驱动框架分析(SD卡驱动\SD Nand驱动)

    rt-thread SDIO驱动框架分析之SD卡驱动 文章目录 rt-thread SDIO驱动框架分析之SD卡驱动 1. 前言 2. SDIO通用驱动框架介绍 3. 文件架构分析 4. SDIO设备 ...

  8. USB转串口驱动分析(一)

    之前追踪代码用的grep命令效率太低了,所以这次下载C代码阅读跳转利器ctags.cscope用于分析代码 因为用的是Centos6.7所以需要用到yum install安装软件 [wuyujun@w ...

  9. RK3399平台开发系列讲解(内核驱动外设篇)6.21、RK LCD显示驱动分析(fb和screen 部分程序)

    平台 内核版本 安卓版本 px3 Linux3.0 Android7.1 查看设备: ls /sys/devices/platform display驱动分析: RK LCD这块首先分为四大块相互依赖 ...

最新文章

  1. oschina添加ssh公钥一记
  2. C语言关于signal()函数
  3. ICCV 2017 CREST:《CREST: Convolutional Residual Learning for Visual Tracking》论文笔记
  4. boost::throw_exception的测试程序
  5. MySQL模糊查询—in关键字
  6. 调用WindowsAPI显示帮助提示
  7. Redis 7.0 Multi Part AOF的设计和实现
  8. CRS磁盘force dismount引起的RAC节点宕机故障
  9. matlab size
  10. notification 是同步的
  11. iOS -- MBProgressHUB
  12. Windows下 Nginx创建文件服务器
  13. java计算机毕业设计考试编排管理系统源码+mysql数据库+系统+lw文档+部署
  14. Python 矩形积分法推荐采样点设置个数
  15. [BZOJ2286] [Sdoi2011]消耗战
  16. 趣味记忆5大经典的软件架构风格
  17. 【Microsoft Azure 的1024种玩法】九. Microsoft Azure云端轻松构建部署PostgreSQL数据库...
  18. GPRS模块发送短信
  19. 几分钟搞定,文件名称中文转英文
  20. 用Java模拟斗地主游戏

热门文章

  1. 专升本第四讲(计算机的“灵魂”)
  2. 《操作系统之哲学原理(第2版)》——— 操作系统的发展历史
  3. 浅谈DC-IRIS的PID控制方法
  4. windows 2003 删除一键恢复EISA
  5. google play直接下载apk安装包文件教程(blynk)
  6. linux 板卡驱动开源项目Comedi使用编译流程
  7. 太阳能路灯的根本结构及作业原理
  8. MATLAB常用命令及函数大全(字母顺序)
  9. springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod
  10. Qt编写可视化大屏电子看板系统30-模块8物料管理