Linux MTD (Memory Technology Device) subsystem analysis

For Atheros char device

读了Linux MTD 源代码分析 对这部分有了整体的认识,结合现有代码,分析一下Atheros的MTD是如何使用的。

Linux kernel: 2.6.31.

Atheros platform: QCA9890???

参考Linux MTD 源代码分析,这里把MTD分为4层,从上到下依次是:字符设备节点、字符设备、MTD 核心、FLASH 硬件驱动。

字符设备节点:/dev/mtd0 /dev/mtd1 等节点,可以通过fopen()等直接使用。这些节点是MTD子系统创建的,用户通过访问这些节点操作MTD。

字符设备:MTD子系统把MTD封装为字符设备。

MTD核心:管理所有的MTD设备,提供get/add/del MTD功能;同时,一个MTD设备可能逻辑上会被划分为多个区,每个区被当成一个MTD设备,所以还提供了通过分区信息批量加入、删除MTD设备的功能。为了从kernel启动参数获取分区信息,MTD核心提供了分析启动参数中分区信息的功能。

FLASH硬件驱动:提供FLASH的read/write/erase等功能。因为Atheros的分区信息是在kernel的启动参数里面取得,所以这里还有分析启动参数分区信息的功能;根据分区信息把MTD设备加到MTD核心中。

系统启动时,MTD核心层可以直接编译到kernel中,FLASH驱动层在系统启动时解析分区信息,把MTD加入到MTD核心层,MTD核心层完成设备节点的创建,MTD字符设备注册MTD字符设备信息,这样访问设备节点的时候就可以找到具体的执行函数。

图1 Atheros MTD Subsystem Architecture

图1显示了各层的主要信息。

MTD设备的使用是通过访问设备节点/dev/mtd0 /dev/mtd1,一般用法是

File *f = fopen(“/dev/mtd0”, “r”);

 

fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

/dev/mtd0 等设备是由MTD核心创建的,由add_mtd_device()->device_register()创建。fread/fwrite是由MTD字符设备层实现具体的读写,至于是如何找到MTD字符设备层的函数的,以及设备节点如何和这些函数关联的,需要看下fread以及Linux的驱动模型(device_register/register_chrdev),以后再总结吧。

MTD字符设备层是通过register_chrdev()来实现的,需要提供struct file_operations中的函数,这些函数完成对指定MTD的read/write/erase等。register_chrdev()之后,当用fread等访问MTD的时候,就会找到这里注册的函数。

static const struct file_operations mtd_fops = {

            .owner                     = THIS_MODULE,

            .llseek                       = mtd_lseek,

            .read             = mtd_read,

            .write                       = mtd_write,

            .ioctl              = mtd_ioctl,

#ifdef CONFIG_COMPAT

            .compat_ioctl       = mtd_compat_ioctl,

#endif

            .open                       = mtd_open,

            .release        = mtd_close,

            .mmap                    = mtd_mmap,

#ifndef CONFIG_MMU

            .get_unmapped_area = mtd_get_unmapped_area,

#endif

};

 

static int __init init_mtdchar(void)

{

            int status;

 

            status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);

            if (status < 0) {

                       printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",

                              MTD_CHAR_MAJOR);

            }

 

            return status;

}

具体看下open/read/close是如何使用MTD的,get/put_mtd_device有MTD核心层提供,下面会具体看到。mtd_open 通过inode取得设备号,进一步通过get_mtd_device取得MTD的struct mtd_info信息,也就获得了具体操作MTD的函数;以后的mtd_read/write等函数就可以直接使用mtd->read/mtd->write完成具体的操作。

static int mtd_open(struct inode *inode, struct file *file)

{

            int minor = iminor(inode);

            int devnum = minor >> 1;

            …

            mtd = get_mtd_device(NULL, devnum);

    ….

            mfi = kzalloc(sizeof(*mfi), GFP_KERNEL);

            mfi->mtd = mtd;

            file->private_data = mfi;

out:

            unlock_kernel();

            return ret;

} /* mtd_open */

 

static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)

{

            struct mtd_file_info *mfi = file->private_data;

            struct mtd_info *mtd = mfi->mtd;

            …

            while (count) {

                       switch (mfi->mode) {

                       default:

                                   ret = mtd->read(mtd, *ppos, len, &retlen, kbuf);

                       }

            }

    …

            return total_retlen;

} /* mtd_read */

 

static int mtd_close(struct inode *inode, struct file *file)

{

            struct mtd_file_info *mfi = file->private_data;

            struct mtd_info *mtd = mfi->mtd;

            put_mtd_device(mtd);

            file->private_data = NULL;

            kfree(mfi);

            return 0;

} /* mtd_close */

MTD核心层提供的功能可以分为两部分:面向上层用户的API和面向底层用户的API。上层用户主要是指MTD字符设备层,字符设备层可以通过get_mtd_device获得MTD的struct mtd_info 信息,然后通过mtd->read、mtd->write等操作MTD。使用方法可以参考字符设备层中函数的实现。下层用户是FLASH驱动层,FLASH驱动层通过parse_mtd_partitions获得kernel启动参数中的分区信息,然后通过add_mtd_partitions把各个分区当做单独的MTD设备加入到MTD核心层;为了分析kernel启动参数,需要注册parser函数,通过register_mtd_parser实现,这个函数的注册可以由FLASH驱动层完成,也可以编译到kernel中(make menuconfig->Device drivers->MTD support->Command line partition table parsing)。

至于注册的parser是如何得到kernel启动参数的,大概的过程是,bootloader通过bootargs的mtdparts传入分区信息,这个分区信息会被当成kernel的启动参数;kernel通过__setup("mtdparts=", mtdpart_setup) 注册函数mtdpart_setup,mtdpart_setup保存分区信息,parser解析保存的信息,参考(cmdlinepart.c)。

MTD核心层的实现原理是:

每个MTD用一个struct mtd_info描述,所有的mtd_info保存在struct mtd_info *mtd_table[]中,get/add/del_mtd_device都是操作mtd_table。

一个MTD FLASH可以逻辑上分为多个区,每个区当成一个MTD,分区信息用struct mtd_partition描述,通过分区信息加入MTD时,需要知道master MTD的信息,每个分区的信息多数来源于master MTD,master MTD不会加入MTD核心层,只有里面的各个分区会加入核心层,当成单独的MTD。

MTD核心层还有notifier的功能,保存在struct mtd_notifier,所有的notifier保存在一个链表中。

具体可以参考Linux MTD 源代码分析。

FLASH驱动层提供mtd_info中read/write等的具体实现,如果有逻辑分区的话,这个mtd_info就是master MTD。然后调用parser_mtd_partitions 和add_mtd_partitions把逻辑分区加入到MTD核心层。

Linux MTD (Memory Technology Device) subsystem analysis -For Atheros char device的更多相关文章

  1. Linux MTD子系统 _从模型分析到Flash驱动模板

    MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...

  2. Understanding Memory Technology Devices in Embedded Linux

    转: NAND Chip Drivers NAND technology users such as USB pen drives, DOMs, Compact Flash memory, and S ...

  3. Is an MTD device a block device or a char device?

    转:http://www.linux-mtd.infradead.org/faq/general.html#L_mtd_what Note, you can find Ukranian transla ...

  4. Linux MTD系统剖析【转】

    转自:http://blog.csdn.net/lwj103862095/article/details/21545791 版权声明:本文为博主原创文章,未经博主允许不得转载. MTD,Memory ...

  5. linux MTD系统解析(转)

    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口.MTD将文件系统与底层FLASH存储 ...

  6. Linux MTD系统剖析

    MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口.MTD将文件系统与底层FLASH存储 ...

  7. Linux MTD 子系统

    一.MTD子系统概述 MTD(Memory Technology Device, 内存技术设备)是用于访问memory 设备 (ROM.FLASH)的Linux子系统. 主要目的是为了使新的memor ...

  8. linux输入子系统(input subsystem)之evdev.c事件处理过程

    1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...

  9. Linux high memory 学习总结

    在free命令中有个参数l,它表示 show detailed low and high memory statistics.其实最先是对High Memory总是为零有些不解(Linux是64为). ...

随机推荐

  1. hdu4003/蓝桥杯 金属采集

    思路: 树形dp + 分组背包dp. 参考https://www.cnblogs.com/kuangbin/archive/2012/08/29/2661928.html 实现: #include & ...

  2. Android Studio Terminal 不是内部或外部命令,也不是可运行程序或批处理文件

    1.Android Studio Terminal 命令行无效的问题 在Android Studio中自带了命令行终端Terminal,但是我们在输入命令时经常会发现:“XXX”不是内部或外部命令,也 ...

  3. Linux常用终端快捷键

    UNIX程序员对键盘以及快捷键的设置都遵循一个标准:"手移动最少的距离,作更多的操作." 所有的类UNIX的终端上都有一些快捷键Ctrl+n = 下,Ctrl+b = 左,Ctrl ...

  4. OCP 11g 第四章练习

    练习 4-1 配置Oracle Net 在本练习中, 将使用图形化工具和命令行工具来建立一个完整的Oracle Net 环境. 由此, 读者可看出在Windows 和 Linux 系统中的区别. 1. ...

  5. 浅析HashSet add() 方法存储自定义类型对象的过程

    一.自定义一个Student类 package date0504; public class Student { private String id; Student(String id){ this ...

  6. @click.native 会触发原生 click事件 vue

    @click.native 会触发原生 click事件 vue

  7. windows10家庭版 远程桌面报错

    windows10家庭版 远程桌面报错“要求的函数不受支持 ...”,Windows没有编辑组策略选项(gpedit.msc),所以无法按照微软提供的方法来修改组策略.所以我们需要修改注册表的方法来修 ...

  8. hdu 6441 Find Integer(费马大定理+勾股数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6441(本题来源于2018年中国大学生程序设计竞赛网络选拔赛) 题意:输入n和a,求满足等式a^n+b^ ...

  9. OVOO

    题目描述: $zhx$有一个棵$n$个点的树,每条边有个权值. 定义一个连通块为一个点集与使这些点连通的所有边(这些点必须连通). 定义一个连通块的权值为这个连通块的边权和(如果一个连通块只包含一个点 ...

  10. InnoDB 事务隔离级别

    InnoDB是一种平衡高可靠性和高性能的通用存储引擎.在MySQL数据库5.5.8版本开始,InnoDB是默认的MySQL存储引擎. InnoDB的主要优势 - 其DML操作遵循ACID,具有提交,回 ...