ARM-Linux驱动--MTD驱动分析(一)

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

从上图可以看出,原始设备是 MTD 字符设备和 MTD 块设备的抽象。
MTD 设备层、 MTD 原始设备层和 Flash 硬件驱动层之间的接口关系如下图:
下面首先分析下 MTD 原始层设备
1 mtd_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 }; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值