Nand flash(二)Linux MTD系统剖析

                
<p><span style="font-size:14px;"><span style="white-space:pre;">MTD,Memory Technology Device即内存技术设备</span>,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。</span></p>
<p><span style="font-size:14px;"><img src="https://img-blog.csdn.net/20140319173537937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHdqMTAzODYyMDk1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt=""><br></span></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span>如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。</span></p>
<p><span style="font-size:14px;"><span style="color:#ff0000;"><strong>Flash硬件驱动层</strong></span>:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。</span></p>
<p><span style="font-size:14px;"><span style="color:#ff0000;"><strong>MTD原始设备层:</strong></span>用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。</span><span style="font-size:14px;">其中<span style="color:#ff0000;"><strong>mtdcore.c</strong></span>:  MTD原始设备接口相关实现<span style="color:#ff0000;"><strong>,mtdpart.c</strong></span>
 :  MTD分区接口相关实现。</span></p>
<p><span style="font-size:14px;"><strong><span style="color:#ff0000;">MTD设备层:</span></strong>基于MTD原始设备,linux系统可以定义出MTD的<strong><span style="color:#cc33cc;">块设备(主设备号31)</span></strong>和<strong><span style="color:#cc33cc;">字符设备(设备号90)</span></strong>。其中<span style="color:#ff0000;"><strong>mtdchar.c</strong></span>
 :  MTD字符设备接口相关实现,<span style="color:#ff0000;"><strong>mtdblock.c</strong></span> : MTD块设备接口相关实现。</span></p>
<p><span style="font-size:14px;"><strong><span style="color:#ff0000;">设备节点:</span></strong>通过mknod在/dev子目录下建立<span style="color:#cc33cc;"><strong>MTD块设备节点(主设备号为31)</strong></span>和<span style="color:#cc33cc;"><strong>MTD字符设备节点(主设备号为90)</strong></span>。通过访问此设备节点即可访问MTD字符设备和块设备 </span></p>
<p><span style="font-size:18px;"><span style="background-color:rgb(51,255,51);">MTD数据结构:</span></span></p>
<p><span style="font-size:14px;">1.Linux内核使用<span style="color:#ff0000;"><strong>mtd_info</strong></span>结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数(后面将会看到),所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:</span></p>
<p><span style="font-size:14px;"></span></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 1219px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_1" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 1219px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_8" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_8" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=8&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="keyword">struct</span><span> mtd_info *mtd_table[MAX_MTD_DEVICES];  </span></span></li></ol></div><pre class="cpp" name="code" style="display: none;">struct mtd_info *mtd_table[MAX_MTD_DEVICES];</pre>2.Linux内核使用<span style="color:#ff0000;"><strong>mtd_part</strong></span>结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。
<p></p>
<p><span style="font-size:14px;"></span></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 1348px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_2" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 1348px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_9" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_9" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=9&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="keyword">struct</span><span> mtd_part {  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> mtd_info mtd;        </span><span class="comment">/* 分区信息, 大部分由master决定 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> mtd_info *master;    </span><span class="comment">/* 分区的主分区 */</span><span>  </span></span></li><li class=""><span>    uint64_t offset;            <span class="comment">/* 分区的偏移地址 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> index;                  </span><span class="comment">/* 分区号 (Linux3.0后不存在该字段) */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> list_head list;      </span><span class="comment">/* 将mtd_part链成一个链表mtd_partitons */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> registered;  </span></span></li><li class=""><span>};  </span></li></ol></div><pre class="cpp" name="code" style="display: none;">struct mtd_part {
	struct mtd_info mtd;	    /* 分区信息, 大部分由master决定 */
	struct mtd_info *master;	/* 分区的主分区 */
	uint64_t offset;			/* 分区的偏移地址 */
	int index;					/* 分区号 (Linux3.0后不存在该字段) */
	struct list_head list;		/* 将mtd_part链成一个链表mtd_partitons */
	int registered;
};</pre>mtd_info结构体主要成员,为了便于观察,将重要的数据放在前面,不大重要的编写在后面。
<p></p>
<p><span style="font-size:14px;"></span></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 1581px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_3" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 1581px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_10" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_10" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=10&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="keyword">struct</span><span> mtd_info {  </span></span></li><li class=""><span>    u_char type;         <span class="comment">/* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */</span><span>  </span></span></li><li class="alt"><span>    uint32_t flags;      <span class="comment">/* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */</span><span>  </span></span></li><li class=""><span>    uint64_t size;       <span class="comment">/* mtd设备的大小 */</span><span>  </span></span></li><li class="alt"><span>    uint32_t erasesize;  <span class="comment">/* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */</span><span>  </span></span></li><li class=""><span>    uint32_t writesize;  <span class="comment">/* 写大小, 对于norFlash是字节,对nandFlash为一页 */</span><span>  </span></span></li><li class="alt"><span>    uint32_t oobsize;    <span class="comment">/* OOB字节数 */</span><span>  </span></span></li><li class=""><span>    uint32_t oobavail;   <span class="comment">/* 可用的OOB字节数 */</span><span>  </span></span></li><li class="alt"><span>    unsigned <span class="datatypes">int</span><span> erasesize_shift;   </span><span class="comment">/* 默认为0,不重要 */</span><span>  </span></span></li><li class=""><span>    unsigned <span class="datatypes">int</span><span> writesize_shift;   </span><span class="comment">/* 默认为0,不重要 */</span><span>  </span></span></li><li class="alt"><span>    unsigned <span class="datatypes">int</span><span> erasesize_mask;    </span><span class="comment">/* 默认为1,不重要 */</span><span>  </span></span></li><li class=""><span>    unsigned <span class="datatypes">int</span><span> writesize_mask;    </span><span class="comment">/* 默认为1,不重要 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">const</span><span> </span><span class="datatypes">char</span><span> *name;               </span><span class="comment">/* 名字,   不重要*/</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> index;                      </span><span class="comment">/* 索引号,不重要 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> numeraseregions;            </span><span class="comment">/* 通常为1 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> mtd_erase_region_info *eraseregions; </span><span class="comment">/* 可变擦除区域 */</span><span>  </span></span></li><li class="alt"><span>      </span></li><li class=""><span>    <span class="keyword">void</span><span> *priv;     </span><span class="comment">/* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> module *owner;   </span><span class="comment">/* 一般设置为THIS_MODULE */</span><span>  </span></span></li><li class=""><span>      </span></li><li class="alt"><span>    <span class="comment">/* 擦除函数 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*erase) (</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> erase_info *instr);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* 读写flash函数 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*read) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, u_char *buf);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*write) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t to, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, </span><span class="keyword">const</span><span> u_char *buf);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* 带oob读写Flash函数 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*read_oob) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from,  </span></span></li><li class=""><span>             <span class="keyword">struct</span><span> mtd_oob_ops *ops);  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*write_oob) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t to,  </span></span></li><li class=""><span>             <span class="keyword">struct</span><span> mtd_oob_ops *ops);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="datatypes">int</span><span> (*get_fact_prot_info) (</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> otp_info *buf, </span><span class="datatypes">size_t</span><span> len);  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*read_fact_prot_reg) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, u_char *buf);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*get_user_prot_info) (</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> otp_info *buf, </span><span class="datatypes">size_t</span><span> len);  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*read_user_prot_reg) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, u_char *buf);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*write_user_prot_reg) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, u_char *buf);  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*lock_user_prot_reg) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len);  </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*writev) (</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">const</span><span> </span><span class="keyword">struct</span><span> kvec *vecs, unsigned </span><span class="datatypes">long</span><span> count, loff_t to, </span><span class="datatypes">size_t</span><span> *retlen);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*panic_write) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t to, </span><span class="datatypes">size_t</span><span> len, </span><span class="datatypes">size_t</span><span> *retlen, </span><span class="keyword">const</span><span> u_char *buf);  </span></span></li><li class="alt"><span>    <span class="comment">/* Sync */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span> (*sync) (</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* Chip-supported device locking */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*lock) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs, uint64_t len);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*unlock) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs, uint64_t len);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* 电源管理函数 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*suspend) (</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class=""><span>    <span class="keyword">void</span><span> (*resume) (</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* 坏块管理函数 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*block_isbad) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> (*block_markbad) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs);  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="keyword">void</span><span> (*unpoint) (</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t from, </span><span class="datatypes">size_t</span><span> len);  </span></span></li><li class="alt"><span>    unsigned <span class="datatypes">long</span><span> (*get_unmapped_area) (</span><span class="keyword">struct</span><span> mtd_info *mtd,  </span></span></li><li class=""><span>                        unsigned <span class="datatypes">long</span><span> len,  </span></span></li><li class="alt"><span>                        unsigned <span class="datatypes">long</span><span> offset,  </span></span></li><li class=""><span>                        unsigned <span class="datatypes">long</span><span> flags);  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> backing_dev_info *backing_dev_info;  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> notifier_block reboot_notifier;  </span><span class="comment">/* default mode before reboot */</span><span>  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">/* ECC status information */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> mtd_ecc_stats ecc_stats;  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> subpage_sft;  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> device dev;  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span> usecount;  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span> (*get_device) (</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class=""><span>    <span class="keyword">void</span><span> (*put_device) (</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class="alt"><span>};  </span></li></ol></div><pre class="cpp" name="code" style="display: none;">struct mtd_info {
	u_char type;	     /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */
	uint32_t flags;	     /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */
	uint64_t size;	     /* mtd设备的大小 */
	uint32_t erasesize;	 /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */
	uint32_t writesize;	 /* 写大小, 对于norFlash是字节,对nandFlash为一页 */
	uint32_t oobsize;    /* OOB字节数 */
	uint32_t oobavail;   /* 可用的OOB字节数 */
	unsigned int erasesize_shift;	/* 默认为0,不重要 */
	unsigned int writesize_shift;	/* 默认为0,不重要 */
	unsigned int erasesize_mask;	/* 默认为1,不重要 */
	unsigned int writesize_mask;	/* 默认为1,不重要 */
	const char *name;				/* 名字,   不重要*/
	int index;						/* 索引号,不重要 */
	int numeraseregions;			/* 通常为1 */
	struct mtd_erase_region_info *eraseregions;	/* 可变擦除区域 */
	
	void *priv;		/* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */
	struct module *owner;	/* 一般设置为THIS_MODULE */
	
	/* 擦除函数 */
	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);

	/* 读写flash函数 */
	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);

	/* 带oob读写Flash函数 */
	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);

	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);

	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
	int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
	/* Sync */
	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);

	/* 电源管理函数 */
	int (*suspend) (struct mtd_info *mtd);
	void (*resume) (struct mtd_info *mtd);

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

	void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
	unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
					    unsigned long len,
					    unsigned long offset,
					    unsigned long flags);
	struct backing_dev_info *backing_dev_info;
	struct notifier_block reboot_notifier;  /* default mode before reboot */

	/* ECC status information */
	struct mtd_ecc_stats ecc_stats;
	int subpage_sft;
	struct device dev;
	int usecount;
	int (*get_device) (struct mtd_info *mtd);
	void (*put_device) (struct mtd_info *mtd);
};</pre><span style="white-space:pre;"></span>mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。
<p></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span>如果MTD设备<span style="color:#ff0000;"><strong>只有一个分区</strong></span>,那么使用下面两个函数注册和注销MTD设备。</span></p>
<p><span style="font-size:14px;"></span></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 3048px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_4" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 3048px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_11" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_11" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=11&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="datatypes">int</span><span> add_mtd_device(</span><span class="keyword">struct</span><span> mtd_info *mtd)  </span></span></li><li class=""><span><span class="datatypes">int</span><span> del_mtd_device (</span><span class="keyword">struct</span><span> mtd_info *mtd)  </span></span></li></ol></div><pre class="cpp" name="code" style="display: none;">int add_mtd_device(struct mtd_info *mtd)
int del_mtd_device (struct mtd_info *mtd)</pre><span style="white-space:pre;"></span>如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。<br><div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 3173px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_5" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_5" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=5&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 3173px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_12" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_12" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=12&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="datatypes">int</span><span> add_mtd_partitions(</span><span class="keyword">struct</span><span> mtd_info *master,</span><span class="keyword">const</span><span> </span><span class="keyword">struct</span><span> mtd_partition *parts,</span><span class="datatypes">int</span><span> nbparts)  </span></span></li><li class=""><span><span class="datatypes">int</span><span> del_mtd_partitions(</span><span class="keyword">struct</span><span> mtd_info *master)  </span></span></li></ol></div><pre class="cpp" name="code" style="display: none;">int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts)
int del_mtd_partitions(struct mtd_info *master)</pre>其中<span style="color:#ff0000;"><strong>mtd_partition</strong></span>结构体表示分区的信息
<p></p>
<p></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 3298px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_6" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_6" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=6&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 3298px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_13" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_13" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=13&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="keyword">struct</span><span> mtd_partition {  </span></span></li><li class=""><span>    <span class="datatypes">char</span><span> *name;             </span><span class="comment">/* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */</span><span>  </span></span></li><li class="alt"><span>    uint64_t size;          <span class="comment">/* 分区大小 */</span><span>  </span></span></li><li class=""><span>    uint64_t offset;        <span class="comment">/* 分区偏移值 */</span><span>  </span></span></li><li class="alt"><span>    uint32_t mask_flags;    <span class="comment">/* 掩码标识,不重要 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> nand_ecclayout *ecclayout;   </span><span class="comment">/* OOB布局 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> mtd_info **mtdp;     </span><span class="comment">/* pointer to store the MTD object */</span><span>  </span></span></li><li class=""><span>};  </span></li><li class="alt"><span>其中nand_ecclayout结构体:  </span></li><li class=""><span><span class="keyword">struct</span><span> nand_ecclayout {  </span></span></li><li class="alt"><span>    __u32 eccbytes;     <span class="comment">/* ECC字节数 */</span><span>  </span></span></li><li class=""><span>    __u32 eccpos[64];   <span class="comment">/* ECC校验码在OOB区域存放位置 */</span><span>  </span></span></li><li class="alt"><span>    __u32 oobavail;       </span></li><li class=""><span>    <span class="comment">/* 除了ECC校验码之外可用的OOB字节数 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  </span></span></li><li class=""><span>};  </span></li></ol></div><pre class="cpp" style="font-size: 14px; display: none;" name="code">struct mtd_partition {
	char *name;				/* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */
	uint64_t size;			/* 分区大小 */
	uint64_t offset;		/* 分区偏移值 */
	uint32_t mask_flags;	/* 掩码标识,不重要 */
	struct nand_ecclayout *ecclayout;	/* OOB布局 */
	struct mtd_info **mtdp;		/* pointer to store the MTD object */
};
其中nand_ecclayout结构体:
struct nand_ecclayout {
	__u32 eccbytes;		/* ECC字节数 */
	__u32 eccpos[64];	/* ECC校验码在OOB区域存放位置 */
	__u32 oobavail;		
	/* 除了ECC校验码之外可用的OOB字节数 */
	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};</pre><span style="font-size:14px;white-space:pre;"> </span><span style="font-size:14px;">关于nand_ecclayout结构体实例,更多可参考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64实例。</span><br><span style="font-size:18px;background-color:rgb(51,255,51);"><strong>MTD设备层:</strong></span>
<p></p>
<p><span style="font-size:14px;color:#ff0000;"><strong>mtd字符设备接口:</strong></span></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span>/drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout
 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL) </span></p>
<p><span style="font-size:14px;color:#ff0000;"><strong>mtd块设备接口:</strong></span></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span><span style="font-size:14px;">/drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block
 块的数据。</span><br>
MTD硬件驱动层:</span></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span>Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。</span></p>
<p><span style="font-size:14px;"><span style="white-space:pre;"></span>MTD使用<span style="color:#ff0000;"><strong>nand_chip</strong></span>来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。</span></p>
<p><span style="font-size:14px;"></span></p>
<div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><b>[cpp]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><div style="position: absolute; left: 167px; top: 4192px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_7" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_7" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=7&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div><div style="position: absolute; left: 167px; top: 4192px; width: 16px; height: 16px; z-index: 99;"><embed id="ZeroClipboardMovie_14" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" name="ZeroClipboardMovie_14" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=14&width=16&height=16" wmode="transparent" width="16" height="16" align="middle"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a></div></div><ol start="1" class="dp-cpp"><li class="alt"><span><span class="keyword">struct</span><span> nand_chip {  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>  __iomem   *IO_ADDR_R;     </span><span class="comment">/* 读8位I/O线地址 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">void</span><span>  __iomem   *IO_ADDR_W;     </span><span class="comment">/* 写8位I/O线地址 */</span><span>  </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="comment">/* 从芯片中读一个字节 */</span><span>  </span></span></li><li class=""><span>    uint8_t (*read_byte)(<span class="keyword">struct</span><span> mtd_info *mtd);       </span></span></li><li class="alt"><span>    <span class="comment">/* 从芯片中读一个字 */</span><span>  </span></span></li><li class=""><span>    u16     (*read_word)(<span class="keyword">struct</span><span> mtd_info *mtd);       </span></span></li><li class="alt"><span>    <span class="comment">/* 将缓冲区内容写入芯片 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>    (*write_buf)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">const</span><span> uint8_t *buf, </span><span class="datatypes">int</span><span> len);      </span></span></li><li class="alt"><span>    <span class="comment">/* 读芯片读取内容至缓冲区/ */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>    (*read_buf)(</span><span class="keyword">struct</span><span> mtd_info *mtd, uint8_t *buf, </span><span class="datatypes">int</span><span> len);  </span></span></li><li class="alt"><span>    <span class="comment">/* 验证芯片和写入缓冲区中的数据 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*verify_buf)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">const</span><span> uint8_t *buf, </span><span class="datatypes">int</span><span> len);  </span></span></li><li class="alt"><span>    <span class="comment">/* 选中芯片 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>    (*select_chip)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="datatypes">int</span><span> chip);  </span></span></li><li class="alt"><span>    <span class="comment">/* 检测是否有坏块 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*block_bad)(</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs, </span><span class="datatypes">int</span><span> getchip);  </span></span></li><li class="alt"><span>    <span class="comment">/* 标记坏块 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*block_markbad)(</span><span class="keyword">struct</span><span> mtd_info *mtd, loff_t ofs);  </span></span></li><li class="alt"><span>    <span class="comment">/* 命令、地址、数据控制函数 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>    (*cmd_ctrl)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="datatypes">int</span><span> dat,unsigned </span><span class="datatypes">int</span><span> ctrl);  </span></span></li><li class="alt"><span>    <span class="comment">/* 设备是否就绪 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*dev_ready)(</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class="alt"><span>    <span class="comment">/* 实现命令发送 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">void</span><span>    (*cmdfunc)(</span><span class="keyword">struct</span><span> mtd_info *mtd, unsigned command, </span><span class="datatypes">int</span><span> column, </span><span class="datatypes">int</span><span> page_addr);  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span>     (*waitfunc)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> nand_chip *</span><span class="keyword">this</span><span>);  </span></span></li><li class=""><span>    <span class="comment">/* 擦除命令的处理 */</span><span>  </span></span></li><li class="alt"><span>    <span class="keyword">void</span><span>    (*erase_cmd)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="datatypes">int</span><span> page);  </span></span></li><li class=""><span>    <span class="comment">/* 扫描坏块 */</span><span>  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span>     (*scan_bbt)(</span><span class="keyword">struct</span><span> mtd_info *mtd);  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*errstat)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> nand_chip *</span><span class="keyword">this</span><span>, </span><span class="datatypes">int</span><span> state, </span><span class="datatypes">int</span><span> status, </span><span class="datatypes">int</span><span> page);  </span></span></li><li class="alt"><span>    <span class="comment">/* 写一页 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>     (*write_page)(</span><span class="keyword">struct</span><span> mtd_info *mtd, </span><span class="keyword">struct</span><span> nand_chip *chip,  </span></span></li><li class="alt"><span>                      <span class="keyword">const</span><span> uint8_t *buf, </span><span class="datatypes">int</span><span> page, </span><span class="datatypes">int</span><span> cached, </span><span class="datatypes">int</span><span> raw);  </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="datatypes">int</span><span>     chip_delay;         </span><span class="comment">/* 由板决定的延迟时间 */</span><span>  </span></span></li><li class=""><span>    <span class="comment">/* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */</span><span>  </span></span></li><li class="alt"><span>    unsigned <span class="datatypes">int</span><span>    options;      </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="comment">/* 用位表示的NAND芯片的page大小,如某片NAND芯片</span> </span></li><li class=""><span><span class="comment">     * 的一个page有512个字节,那么page_shift就是9 </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      page_shift;  </span></span></li><li class="alt"><span>    <span class="comment">/* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可</span> </span></li><li class=""><span><span class="comment">     * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14</span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      phys_erase_shift;  </span></span></li><li class="alt"><span>    <span class="comment">/* 用位表示的bad block table的大小,通常一个bbt占用一个block,</span> </span></li><li class=""><span><span class="comment">     * 所以bbt_erase_shift通常与phys_erase_shift相等</span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      bbt_erase_shift;  </span></span></li><li class="alt"><span>    <span class="comment">/* 用位表示的NAND芯片的容量 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      chip_shift;  </span></span></li><li class="alt"><span>    <span class="comment">/* NADN FLASH芯片的数量 */</span><span>  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      numchips;  </span></span></li><li class="alt"><span>    <span class="comment">/* NAND芯片的大小 */</span><span>  </span></span></li><li class=""><span>    uint64_t chipsize;  </span></li><li class="alt"><span>    <span class="datatypes">int</span><span>      pagemask;  </span></span></li><li class=""><span>    <span class="datatypes">int</span><span>      pagebuf;  </span></span></li><li class="alt"><span>    <span class="datatypes">int</span><span>      subpagesize;  </span></span></li><li class=""><span>    uint8_t  cellinfo;  </span></li><li class="alt"><span>    <span class="datatypes">int</span><span>      badblockpos;  </span></span></li><li class=""><span>    nand_state_t    state;  </span></li><li class="alt"><span>    uint8_t     *oob_poi;  </span></li><li class=""><span>    <span class="keyword">struct</span><span> nand_hw_control  *controller;  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> nand_ecclayout   *ecclayout; </span><span class="comment">/* ECC布局 */</span><span>  </span></span></li><li class=""><span>      </span></li><li class="alt"><span>    <span class="keyword">struct</span><span> nand_ecc_ctrl ecc;   </span><span class="comment">/* ECC校验结构体,里面有大量的函数进行ECC校验 */</span><span>  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> nand_buffers *buffers;  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> nand_hw_control hwcontrol;  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> mtd_oob_ops ops;  </span></span></li><li class="alt"><span>    uint8_t     *bbt;  </span></li><li class=""><span>    <span class="keyword">struct</span><span> nand_bbt_descr   *bbt_td;  </span></span></li><li class="alt"><span>    <span class="keyword">struct</span><span> nand_bbt_descr   *bbt_md;  </span></span></li><li class=""><span>    <span class="keyword">struct</span><span> nand_bbt_descr   *badblock_pattern;  </span></span></li><li class="alt"><span>    <span class="keyword">void</span><span>        *priv;  </span></span></li><li class=""><span>};  </span></li></ol></div><pre class="cpp" name="code" style="display: none;">struct nand_chip {
	void  __iomem	*IO_ADDR_R;		/* 读8位I/O线地址 */
	void  __iomem	*IO_ADDR_W;		/* 写8位I/O线地址 */

	/* 从芯片中读一个字节 */
	uint8_t	(*read_byte)(struct mtd_info *mtd);		
	/* 从芯片中读一个字 */
	u16		(*read_word)(struct mtd_info *mtd);		
	/* 将缓冲区内容写入芯片 */
	void	(*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);	
	/* 读芯片读取内容至缓冲区/ */
	void	(*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
	/* 验证芯片和写入缓冲区中的数据 */
	int		(*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
	/* 选中芯片 */
	void	(*select_chip)(struct mtd_info *mtd, int chip);
	/* 检测是否有坏块 */
	int		(*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
	/* 标记坏块 */
	int		(*block_markbad)(struct mtd_info *mtd, loff_t ofs);
	/* 命令、地址、数据控制函数 */
	void	(*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);
	/* 设备是否就绪 */
	int		(*dev_ready)(struct mtd_info *mtd);
	/* 实现命令发送 */
	void	(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
	/* 擦除命令的处理 */
	void	(*erase_cmd)(struct mtd_info *mtd, int page);
	/* 扫描坏块 */
	int		(*scan_bbt)(struct mtd_info *mtd);
	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
	/* 写一页 */
	int		(*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
				      const uint8_t *buf, int page, int cached, int raw);

	int		chip_delay;			/* 由板决定的延迟时间 */
	/* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */
	unsigned int	options;	

	/* 用位表示的NAND芯片的page大小,如某片NAND芯片
	 * 的一个page有512个字节,那么page_shift就是9 
	 */
	int		 page_shift;
	/* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可
	 * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14
	 */
	int		 phys_erase_shift;
	/* 用位表示的bad block table的大小,通常一个bbt占用一个block,
	 * 所以bbt_erase_shift通常与phys_erase_shift相等
 	 */
	int		 bbt_erase_shift;
	/* 用位表示的NAND芯片的容量 */
	int		 chip_shift;
	/* NADN FLASH芯片的数量 */
	int		 numchips;
	/* NAND芯片的大小 */
	uint64_t chipsize;
	int		 pagemask;
	int		 pagebuf;
	int		 subpagesize;
	uint8_t	 cellinfo;
	int		 badblockpos;
	nand_state_t	state;
	uint8_t		*oob_poi;
	struct nand_hw_control  *controller;
	struct nand_ecclayout	*ecclayout;	/* ECC布局 */
	
	struct nand_ecc_ctrl ecc;	/* ECC校验结构体,里面有大量的函数进行ECC校验 */
	struct nand_buffers *buffers;
	struct nand_hw_control hwcontrol;
	struct mtd_oob_ops ops;
	uint8_t		*bbt;
	struct nand_bbt_descr	*bbt_td;
	struct nand_bbt_descr	*bbt_md;
	struct nand_bbt_descr	*badblock_pattern;
	void		*priv;
};</pre><span style="white-space:pre;"></span>最后,我们来用图表的形式来总结一下,MTD设备层、MTD原始设备层、FLASH硬件驱动层之间的联系。
<p></p>
<p><span style="font-size:14px;"><img src="https://img-blog.csdn.net/20140319203528000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHdqMTAzODYyMDk1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt=""><br></span></p>
<p><span style="font-size:14px;"><br></span></p>
            

猜你喜欢

转载自blog.csdn.net/jerrygou/article/details/80348182
今日推荐