查看: 1785|回复: 0

[Linux技术] ARM-Linux驱动--MTD驱动分析(一)

[复制链接]
  • TA的每日心情

    2014-4-10 13:56
  • 签到天数: 5 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2014-1-23 08:57:14 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 forlinx2013 于 2014-1-24 09:21 编辑

    欢迎大家来到飞凌爱板网专区,对嵌入式技术感兴趣的朋友不妨多多关注一下,我们提供了公司所有开发板的所有资料,也会更新大量技术文章,欢迎大家一块学习提高!!!

    主机:Gentoo Linux 11.2 with linux kernel 3.0.6
    硬件平台:FL2440(S3C2440)with linux kernel 2.6.35

    MTD(memory technology device内存技术设备) 在硬件和文件系统层之间的提供了一个抽象的接口,MTD是用来访问内存设备(如:ROMflash)的中间层,它将内存设备的共有特性抽取出来,从而使增加新的内存设备驱动程序变得更简单。MTD的源代码都在/drivers/mtd目录中。
    MTD中间层细分为四层,按从上到下依次为:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。MTD中间层层次结构图如下:

    从上图可以看出,原始设备是MTD字符设备和MTD块设备的抽象。
    MTD设备层、MTD原始设备层和Flash硬件驱动层之间的接口关系如下图:
    下面首先分析下MTD原始层设备
    1mtd_info数据结构
    1 struct mtd_info {  
    2     u_char type;//内存技术类型,例如MTD_RAM,MTD_ROM,MTD_NORFLASH,MTD_NAND_FLASH,MTD_PEROM等   
    3     uint32_t flags;//标志位   
    4     uint64_t size;   // Total size of the MTD//MTD设备的大小   
    5   
    6     /* "Major" erase size for the device. Naïve users may take this
    7      * to be the only erase size available, or may use the more detailed
    8      * information below if they desire
    9      */  
    10     uint32_t erasesize;//最小的擦除块大小   
    11     /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
    12      * though individual bits can be cleared), in case of NAND flash it is
    13      * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
    14      * it is of ECC block size, etc. It is illegal to have writesize = 0.
    15      * Any driver registering a struct mtd_info must ensure a writesize of
    16      * 1 or larger.
    17      */  
    18     uint32_t writesize;//编程块大小   
    19   
    20     uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)//oob(Out of band)块大小   
    21     uint32_t oobavail;  // Available OOB bytes per block//每块的可用的oob字节   
    22   
    23     /*
    24      * If erasesize is a power of 2 then the shift is stored in
    25      * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
    26      */  
    27     unsigned int erasesize_shift;  
    28     unsigned int writesize_shift;  
    29     /* Masks based on erasesize_shift and writesize_shift */  
    30     unsigned int erasesize_mask;  
    31     unsigned int writesize_mask;  
    32   
    33     // Kernel-only stuff starts here.   
    34     const char *name;  
    35     int index;  
    36   
    37     /* ecc layout structure pointer - read only ! */  
    38     struct nand_ecclayout *ecclayout;//eec布局结构   
    39   
    40     /* Data for variable erase regions. If numeraseregions is zero,
    41      * it means that the whole device has erasesize as given above.
    42      */  
    43     int numeraseregions;//擦除区域个数,通常为1   
    44     struct mtd_erase_region_info *eraseregions;//擦除区域的区域信息地址   
    45   
    46     /*
    47      * Erase is an asynchronous operation.  Device drivers are supposed
    48      * to call instr->callback() whenever the operation completes, even
    49      * if it completes with a failure.
    50      * Callers are supposed to pass a callback function and wait for it
    51      * to be called before writing to the block.
    52      */  
    53     int (*erase) (struct mtd_info *mtd, struct erase_info *instr);//函数指针,erase函数的功能是将一个erase_info加入擦除队列   
    54   
    55     /* This stuff for eXecute-In-Place */  
    56     /* phys is optional and may be set to NULL */  
    57     int (*point) (struct mtd_info *mtd, loff_t from, size_t len,  
    58             size_t *retlen, void **virt, resource_size_t *phys);//point函数功能是允许片内执行(XIP)   
    59   
    60     /* We probably shouldn't allow XIP if the unpoint isn't a NULL */  
    61     void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);//unpoint函数与point函数相反,是禁止片内执行(XIP)   
    62   
    63     /* Allow NOMMU mmap() to directly map the device (if not NULL)
    64      * - return the address to which the offset maps
    65      * - return -ENOSYS to indicate refusal to do the mapping
    66      */  
    67     //如果不是NULL,则允许无MMU单元的地址映射,返回偏移地址   
    68     unsigned long (*get_unmapped_area) (struct mtd_info *mtd,  
    69                         unsigned long len,  
    70                         unsigned long offset,  
    71                         unsigned long flags);  
    72   
    73     /* Backing device capabilities for this device
    74      * - provides mmap capabilities
    75      */  
    76     struct backing_dev_info *backing_dev_info;  
    77   
    78     //MTD设备的读写函数   
    79     int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    80     int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
    81   
    82     /* In blackbox flight recorder like scenarios we want to make successful
    83        writes in interrupt context. panic_write() is only intended to be
    84        called when its known the kernel is about to panic and we need the
    85        write to succeed. Since the kernel is not going to be running for much
    86        longer, this function can break locks and delay to ensure the write
    87        succeeds (but not sleep). */  
    88   
    89     int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
    90      
    91     //用于MTD设备的OBB数据读写   
    92     int (*read_oob) (struct mtd_info *mtd, loff_t from,  
    93              struct mtd_oob_ops *ops);  
    94     int (*write_oob) (struct mtd_info *mtd, loff_t to,  
    95              struct mtd_oob_ops *ops);  
    96   
    97     /*
    98      * Methods to access the protection register area, present in some
    99      * flash devices. The user data is one time programmable but the
    100      * factory data is read only.
    101      */  
    102     int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
    103     int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    104     int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
    105     int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    106     int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    107     int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
    108   
    109     /* kvec-based read/write methods.
    110        NB: The 'count' parameter is the number of _vectors_, each of
    111        which contains an (ofs, len) tuple.
    112     */  
    113     int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
    114   
    115     /* Sync */  
    116     //MTD设备的同步函数   
    117     void (*sync) (struct mtd_info *mtd);  
    118   
    119     /* Chip-supported device locking */  
    120     //芯片的加锁和解锁   
    121     int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
    122     int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
    123   
    124     /* Power Management functions */  
    125     //支持电源管理函数   
    126     int (*suspend) (struct mtd_info *mtd);  
    127     void (*resume) (struct mtd_info *mtd);  
    128   
    129     /* Bad block management functions */  
    130     //坏块管理函数   
    131     int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  
    132     int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);  
    133   
    134     struct notifier_block reboot_notifier;  /* default mode before reboot */  
    135   
    136     /* ECC status information */  
    137     struct mtd_ecc_stats ecc_stats;//ECC状态信息   
    138     /* Subpage shift (NAND) */  
    139     int subpage_sft;  
    140   
    141     void *priv;//私有数据指针   
    142   
    143     struct module *owner;  
    144     struct device dev;  
    145     int usecount;//记录用户的个数   
    146   
    147     /* If the driver is something smart, like UBI, it may need to maintain
    148      * its own reference counting. The below functions are only for driver.
    149      * The driver may register its callbacks. These callbacks are not
    150      * supposed to be called by MTD users */  
    151     //驱动回调函数   
    152     int (*get_device) (struct mtd_info *mtd);  
    153     void (*put_device) (struct mtd_info *mtd);  
    154 };  
    struct mtd_info {
        u_char type;//内存技术类型,例如MTD_RAM,MTD_ROM,MTD_NORFLASH,MTD_NAND_FLASH,MTD_PEROM
        uint32_t flags;//标志位
        uint64_t size;   // Total size of the MTD//MTD设备的大小

        /* "Major" erase size for the device. Naïve users may take this
         * to be the only erase size available, or may use the more detailed
         * information below if they desire
         */
        uint32_t erasesize;//最小的擦除块大小
        /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
         * though individual bits can be cleared), in case of NAND flash it is
         * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
         * it is of ECC block size, etc. It is illegal to have writesize = 0.
         * Any driver registering a struct mtd_info must ensure a writesize of
         * 1 or larger.
         */
        uint32_t writesize;//编程块大小

        uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)//oob(Out of band)块大小
        uint32_t oobavail;  // Available OOB bytes per block//每块的可用的oob字节

        /*
         * If erasesize is a power of 2 then the shift is stored in
         * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
         */
        unsigned int erasesize_shift;
        unsigned int writesize_shift;
        /* Masks based on erasesize_shift and writesize_shift */
        unsigned int erasesize_mask;
        unsigned int writesize_mask;

        // Kernel-only stuff starts here.
        const char *name;
        int index;

        /* ecc layout structure pointer - read only ! */
        struct nand_ecclayout *ecclayout;//eec布局结构

        /* Data for variable erase regions. If numeraseregions is zero,
         * it means that the whole device has erasesize as given above.
         */
        int numeraseregions;//擦除区域个数,通常为1
        struct mtd_erase_region_info *eraseregions;//擦除区域的区域信息地址

        /*
         * Erase is an asynchronous operation.  Device drivers are supposed
         * to call instr->callback() whenever the operation completes, even
         * if it completes with a failure.
         * Callers are supposed to pass a callback function and wait for it
         * to be called before writing to the block.
         */
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);//函数指针,erase函数的功能是将一个erase_info加入擦除队列

        /* This stuff for eXecute-In-Place */
        /* phys is optional and may be set to NULL */
        int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, void **virt, resource_size_t *phys);//point函数功能是允许片内执行(XIP

        /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
        void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);//unpoint函数与point函数相反,是禁止片内执行(XIP

        /* Allow NOMMU mmap() to directly map the device (if not NULL)
         * - return the address to which the offset maps
         * - return -ENOSYS to indicate refusal to do the mapping
         */
        //如果不是NULL,则允许无MMU单元的地址映射,返回偏移地址
        unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
                            unsigned long len,
                            unsigned long offset,
                            unsigned long flags);

        /* Backing device capabilities for this device
         * - provides mmap capabilities
         */
        struct backing_dev_info *backing_dev_info;

        //MTD设备的读写函数
        int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

        /* In blackbox flight recorder like scenarios we want to make successful
           writes in interrupt context. panic_write() is only intended to be
           called when its known the kernel is about to panic and we need the
           write to succeed. Since the kernel is not going to be running for much
           longer, this function can break locks and delay to ensure the write
           succeeds (but not sleep). */

        int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

        //用于MTD设备的OBB数据读写
        int (*read_oob) (struct mtd_info *mtd, loff_t from,
                 struct mtd_oob_ops *ops);
        int (*write_oob) (struct mtd_info *mtd, loff_t to,
                 struct mtd_oob_ops *ops);

        /*
         * Methods to access the protection register area, present in some
         * flash devices. The user data is one time programmable but the
         * factory data is read only.
         */
        int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
        int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
        int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);

        /* kvec-based read/write methods.
           NB: The 'count' parameter is the number of _vectors_, each of
           which contains an (ofs, len) tuple.
        */
        int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);

        /* Sync */
        //MTD设备的同步函数
        void (*sync) (struct mtd_info *mtd);

        /* Chip-supported device locking */
        //芯片的加锁和解锁
        int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
        int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);

        /* Power Management functions */
        //支持电源管理函数
        int (*suspend) (struct mtd_info *mtd);
        void (*resume) (struct mtd_info *mtd);

        /* Bad block management functions */
        //坏块管理函数
        int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
        int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);

        struct notifier_block reboot_notifier;  /* default mode before reboot */

        /* ECC status information */
        struct mtd_ecc_stats ecc_stats;//ECC状态信息
        /* Subpage shift (NAND) */
        int subpage_sft;

        void *priv;//私有数据指针

        struct module *owner;
        struct device dev;
        int usecount;//记录用户的个数

        /* If the driver is something smart, like UBI, it may need to maintain
         * its own reference counting. The below functions are only for driver.
         * The driver may register its callbacks. These callbacks are not
         * supposed to be called by MTD users */
        //驱动回调函数
        int (*get_device) (struct mtd_info *mtd);
        void (*put_device) (struct mtd_info *mtd);
    };


    2、mtd_part结构体信息
    155 /* Our partition linked list */  
    156 static LIST_HEAD(mtd_partitions);//分区链表  
    /* Our partition linked list */
    static LIST_HEAD(mtd_partitions);//分区链表

    157 /* Our partition node structure */  
    158 //分区结构信息   
    159 struct mtd_part {  
    160     struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table中   
    161     struct mtd_info *master;//该分区的主分区   
    162     uint64_t offset;//该分区的偏移地址   
    163     struct list_head list;//分区链表   
    164 };  
    /* Our partition node structure */
    //分区结构信息
    struct mtd_part {
        struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table
        struct mtd_info *master;//该分区的主分区
        uint64_t offset;//该分区的偏移地址
        struct list_head list;//分区链表
    };


    3、mtd_partition描述mtd具体分区结构
    165 /*
    166  * Partition definition structure:
    167  *
    168  * An array of struct partition is passed along with a MTD object to
    169  * add_mtd_partitions() to create them.
    170  *
    171  * For each partition, these fields are available:
    172  * name: string that will be used to label the partition's MTD device.
    173  * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
    174  *  will extend to the end of the master MTD device.
    175  * offset: absolute starting position within the master MTD device; if
    176  *  defined as MTDPART_OFS_APPEND, the partition will start where the
    177  *  previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.
    178  * mask_flags: contains flags that have to be masked (removed) from the
    179  *  master MTD flag set for the corresponding MTD partition.
    180  *  For example, to force a read-only partition, simply adding
    181  *  MTD_WRITEABLE to the mask_flags will do the trick.
    182  *
    183  * Note: writeable partitions require their size and offset be
    184  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
    185  */  
    186   
    187 struct mtd_partition {  
    188     char *name;         /* identifier string 分区名*/  
    189     uint64_t size;          /* partition size 分区大小*/  
    190     uint64_t offset;        /* offset within the master MTD space 偏移地址*/  
    191     uint32_t mask_flags;        /* master MTD flags to mask out for this partition */  
    192     struct nand_ecclayout *ecclayout;   /* out of band layout for this partition (NAND only)*/  
    193 };  


    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-5-16 19:37 , Processed in 0.113601 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.