轉(zhuǎn)自:http://blog.csdn.net/lwj103862095/article/details/21545791
?
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
MTD,Memory Technology Device即內(nèi)存技術(shù)設(shè)備,在Linux內(nèi)核中,引入MTD層為NOR FLASH和NAND FLASH設(shè)備提供統(tǒng)一接口。MTD將文件系統(tǒng)與底層FLASH存儲(chǔ)器進(jìn)行了隔離。
如上圖所示,MTD設(shè)備通常可分為四層,從上到下依次是:設(shè)備節(jié)點(diǎn)、MTD設(shè)備層、MTD原始設(shè)備層、硬件驅(qū)動(dòng)層。
Flash硬件驅(qū)動(dòng)層:Flash硬件驅(qū)動(dòng)層負(fù)責(zé)對(duì)Flash硬件的讀、寫(xiě)和擦除操作。MTD設(shè)備的Nand Flash芯片的驅(qū)動(dòng)則drivers/mtd/nand/子目錄下,Nor Flash芯片驅(qū)動(dòng)位于drivers/mtd/chips/子目錄下。
MTD原始設(shè)備層:用于描述MTD原始設(shè)備的數(shù)據(jù)結(jié)構(gòu)是mtd_info,它定義了大量的關(guān)于MTD的數(shù)據(jù)和操作函數(shù)。其中mtdcore.c: ?MTD原始設(shè)備接口相關(guān)實(shí)現(xiàn),mtdpart.c?: ?MTD分區(qū)接口相關(guān)實(shí)現(xiàn)。
MTD設(shè)備層:基于MTD原始設(shè)備,linux系統(tǒng)可以定義出MTD的塊設(shè)備(主設(shè)備號(hào)31)和字符設(shè)備(設(shè)備號(hào)90)。其中mtdchar.c?: ?MTD字符設(shè)備接口相關(guān)實(shí)現(xiàn),mtdblock.c?: MTD塊設(shè)備接口相關(guān)實(shí)現(xiàn)。
設(shè)備節(jié)點(diǎn):通過(guò)mknod在/dev子目錄下建立MTD塊設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為31)和MTD字符設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為90)。通過(guò)訪(fǎng)問(wèn)此設(shè)備節(jié)點(diǎn)即可訪(fǎng)問(wèn)MTD字符設(shè)備和塊設(shè)備?
MTD數(shù)據(jù)結(jié)構(gòu):
1.Linux內(nèi)核使用mtd_info結(jié)構(gòu)體表示MTD原始設(shè)備,這其中定義了大量關(guān)于MTD的數(shù)據(jù)和操作函數(shù)(后面將會(huì)看到),所有的mtd_info結(jié)構(gòu)體存放在mtd_table結(jié)構(gòu)體數(shù)據(jù)里。在/drivers/mtd/mtdcore.c里:
?
[cpp]?view plaincopy? print?
struct?mtd_info?*mtd_table[MAX_MTD_DEVICES];?? 2.Linux內(nèi)核使用mtd_part結(jié)構(gòu)體表示分區(qū),其中mtd_info結(jié)構(gòu)體成員用于描述該分區(qū),大部分成員由其主分區(qū)mtd_part->master決定,各種函數(shù)也指向主分區(qū)的相應(yīng)函數(shù)。 ?
?
[cpp]?view plaincopy? print?
struct?mtd_part?{??????struct?mtd_info?mtd;??????????????struct?mtd_info?*master;??????????uint64_t?offset;??????????????????int?index;????????????????????????struct?list_head?list;????????????int?registered;??};?? mtd_info結(jié)構(gòu)體主要成員,為了便于觀察,將重要的數(shù)據(jù)放在前面,不大重要的編寫(xiě)在后面。 ?
?
[cpp]?view plaincopy? print?
struct?mtd_info?{??????u_char?type;???????????????uint32_t?flags;????????????uint64_t?size;?????????????uint32_t?erasesize;????????uint32_t?writesize;????????uint32_t?oobsize;??????????uint32_t?oobavail;?????????unsigned?int?erasesize_shift;?????????unsigned?int?writesize_shift;?????????unsigned?int?erasesize_mask;??????????unsigned?int?writesize_mask;??????????const?char?*name;?????????????????????int?index;????????????????????????????int?numeraseregions;??????????????????struct?mtd_erase_region_info?*eraseregions;?????????????void?*priv;???????????struct?module?*owner;?????????????????????int?(*erase)?(struct?mtd_info?*mtd,?struct?erase_info?*instr);??????????????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);??????????????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);????????????void?(*sync)?(struct?mtd_info?*mtd);??????????????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;????????????????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);??};?? mtd_info結(jié)構(gòu)體中的read()、write()、read_oob()、write_oob()、erase()是MTD設(shè)備驅(qū)動(dòng)要實(shí)現(xiàn)的主要函數(shù),幸運(yùn)的是Linux大牛已經(jīng)幫我們實(shí)現(xiàn)了一套適合大部分FLASH設(shè)備的mtd_info成員函數(shù)。 ?
如果MTD設(shè)備只有一個(gè)分區(qū),那么使用下面兩個(gè)函數(shù)注冊(cè)和注銷(xiāo)MTD設(shè)備。
?
[cpp]?view plaincopy? print?
int?add_mtd_device(struct?mtd_info?*mtd)??int?del_mtd_device?(struct?mtd_info?*mtd)?? 如果MTD設(shè)備存在其他分區(qū),那么使用下面兩個(gè)函數(shù)注冊(cè)和注銷(xiāo)MTD設(shè)備。 [cpp]?view plaincopy? print?
int?add_mtd_partitions(struct?mtd_info?*master,const?struct?mtd_partition?*parts,int?nbparts)??int?del_mtd_partitions(struct?mtd_info?*master)?? 其中mtd_partition結(jié)構(gòu)體表示分區(qū)的信息 ?
?
[cpp]?view plaincopy? print?
struct?mtd_partition?{??????char?*name;???????????????????uint64_t?size;????????????????uint64_t?offset;??????????????uint32_t?mask_flags;??????????struct?nand_ecclayout?*ecclayout;?????????struct?mtd_info?**mtdp;???????};??其中nand_ecclayout結(jié)構(gòu)體:??struct?nand_ecclayout?{??????__u32?eccbytes;???????????__u32?eccpos[64];?????????__u32?oobavail;?????????????????struct?nand_oobfree?oobfree[MTD_MAX_OOBFREE_ENTRIES];??};?? 關(guān)于nand_ecclayout結(jié)構(gòu)體實(shí)例,更多可參考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64實(shí)例。MTD設(shè)備層: ?
mtd字符設(shè)備接口:
/drivers/mtd/mtdchar.c文件實(shí)現(xiàn)了MTD字符設(shè)備接口,通過(guò)它,可以直接訪(fǎng)問(wèn)Flash設(shè)備,與前面的字符驅(qū)動(dòng)一樣,通過(guò)file_operations結(jié)構(gòu)體里面的open()、read()、write()、ioctl()可以讀寫(xiě)Flash,通過(guò)一系列IOCTL 命令可以獲取Flash 設(shè)備信息、擦除Flash、讀寫(xiě)NAND 的OOB、獲取OOB layout 及檢查NAND 壞塊等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)?
mtd塊設(shè)備接口:
/drivers/mtd/mtdblock.c文件實(shí)現(xiàn)了MTD塊設(shè)備接口,主要原理是將Flash的erase block 中的數(shù)據(jù)在內(nèi)存中建立映射,然后對(duì)其進(jìn)行修改,最后擦除Flash 上的block,將內(nèi)存中的映射塊寫(xiě)入Flash 塊。整個(gè)過(guò)程被稱(chēng)為read/modify/erase/rewrite 周期。?但是,這樣做是不安全的,當(dāng)下列操作序列發(fā)生時(shí),read/modify/erase/poweroff,就會(huì)丟失這個(gè)block 塊的數(shù)據(jù)。
MTD硬件驅(qū)動(dòng)層:
Linux內(nèi)核再M(fèi)TD層下實(shí)現(xiàn)了通用的NAND驅(qū)動(dòng)(/driver/mtd/nand/nand_base.c),因此芯片級(jí)的NAND驅(qū)動(dòng)不再需要實(shí)現(xiàn)mtd_info結(jié)構(gòu)體中的read()、write()、read_oob()、write_oob()等成員函數(shù)。
MTD使用nand_chip來(lái)表示一個(gè)NAND FLASH芯片, 該結(jié)構(gòu)體包含了關(guān)于Nand Flash的地址信息,讀寫(xiě)方法,ECC模式,硬件控制等一系列底層機(jī)制。
?
[cpp]?view plaincopy? print?
struct?nand_chip?{??????void??__iomem???*IO_ADDR_R;???????????void??__iomem???*IO_ADDR_W;???????????????????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;?????????????????????unsigned?int????options;????????????????????int??????page_shift;??????????????int??????phys_erase_shift;??????????????int??????bbt_erase_shift;????????????int??????chip_shift;????????????int??????numchips;????????????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;?????????????struct?nand_ecc_ctrl?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;??};?? 最后,我們來(lái)用圖表的形式來(lái)總結(jié)一下,MTD設(shè)備層、MTD原始設(shè)備層、FLASH硬件驅(qū)動(dòng)層之間的聯(lián)系。 ?
?
?
?
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
MTD,Memory Technology Device即內(nèi)存技術(shù)設(shè)備,在Linux內(nèi)核中,引入MTD層為NOR FLASH和NAND FLASH設(shè)備提供統(tǒng)一接口。MTD將文件系統(tǒng)與底層FLASH存儲(chǔ)器進(jìn)行了隔離。
如上圖所示,MTD設(shè)備通常可分為四層,從上到下依次是:設(shè)備節(jié)點(diǎn)、MTD設(shè)備層、MTD原始設(shè)備層、硬件驅(qū)動(dòng)層。
Flash硬件驅(qū)動(dòng)層:Flash硬件驅(qū)動(dòng)層負(fù)責(zé)對(duì)Flash硬件的讀、寫(xiě)和擦除操作。MTD設(shè)備的Nand Flash芯片的驅(qū)動(dòng)則drivers/mtd/nand/子目錄下,Nor Flash芯片驅(qū)動(dòng)位于drivers/mtd/chips/子目錄下。
MTD原始設(shè)備層:用于描述MTD原始設(shè)備的數(shù)據(jù)結(jié)構(gòu)是mtd_info,它定義了大量的關(guān)于MTD的數(shù)據(jù)和操作函數(shù)。其中mtdcore.c: ?MTD原始設(shè)備接口相關(guān)實(shí)現(xiàn),mtdpart.c?: ?MTD分區(qū)接口相關(guān)實(shí)現(xiàn)。
MTD設(shè)備層:基于MTD原始設(shè)備,linux系統(tǒng)可以定義出MTD的塊設(shè)備(主設(shè)備號(hào)31)和字符設(shè)備(設(shè)備號(hào)90)。其中mtdchar.c?: ?MTD字符設(shè)備接口相關(guān)實(shí)現(xiàn),mtdblock.c?: MTD塊設(shè)備接口相關(guān)實(shí)現(xiàn)。
設(shè)備節(jié)點(diǎn):通過(guò)mknod在/dev子目錄下建立MTD塊設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為31)和MTD字符設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為90)。通過(guò)訪(fǎng)問(wèn)此設(shè)備節(jié)點(diǎn)即可訪(fǎng)問(wèn)MTD字符設(shè)備和塊設(shè)備?
MTD數(shù)據(jù)結(jié)構(gòu):
1.Linux內(nèi)核使用mtd_info結(jié)構(gòu)體表示MTD原始設(shè)備,這其中定義了大量關(guān)于MTD的數(shù)據(jù)和操作函數(shù)(后面將會(huì)看到),所有的mtd_info結(jié)構(gòu)體存放在mtd_table結(jié)構(gòu)體數(shù)據(jù)里。在/drivers/mtd/mtdcore.c里:
?
[cpp]?view plaincopy? print?
struct?mtd_info?*mtd_table[MAX_MTD_DEVICES];?? 2.Linux內(nèi)核使用mtd_part結(jié)構(gòu)體表示分區(qū),其中mtd_info結(jié)構(gòu)體成員用于描述該分區(qū),大部分成員由其主分區(qū)mtd_part->master決定,各種函數(shù)也指向主分區(qū)的相應(yīng)函數(shù)。 ?
?
[cpp]?view plaincopy? print?
struct?mtd_part?{??????struct?mtd_info?mtd;??????????????struct?mtd_info?*master;??????????uint64_t?offset;??????????????????int?index;????????????????????????struct?list_head?list;????????????int?registered;??};?? mtd_info結(jié)構(gòu)體主要成員,為了便于觀察,將重要的數(shù)據(jù)放在前面,不大重要的編寫(xiě)在后面。 ?
?
[cpp]?view plaincopy? print?
struct?mtd_info?{??????u_char?type;???????????????uint32_t?flags;????????????uint64_t?size;?????????????uint32_t?erasesize;????????uint32_t?writesize;????????uint32_t?oobsize;??????????uint32_t?oobavail;?????????unsigned?int?erasesize_shift;?????????unsigned?int?writesize_shift;?????????unsigned?int?erasesize_mask;??????????unsigned?int?writesize_mask;??????????const?char?*name;?????????????????????int?index;????????????????????????????int?numeraseregions;??????????????????struct?mtd_erase_region_info?*eraseregions;?????????????void?*priv;???????????struct?module?*owner;?????????????????????int?(*erase)?(struct?mtd_info?*mtd,?struct?erase_info?*instr);??????????????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);??????????????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);????????????void?(*sync)?(struct?mtd_info?*mtd);??????????????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;????????????????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);??};?? mtd_info結(jié)構(gòu)體中的read()、write()、read_oob()、write_oob()、erase()是MTD設(shè)備驅(qū)動(dòng)要實(shí)現(xiàn)的主要函數(shù),幸運(yùn)的是Linux大牛已經(jīng)幫我們實(shí)現(xiàn)了一套適合大部分FLASH設(shè)備的mtd_info成員函數(shù)。 ?
如果MTD設(shè)備只有一個(gè)分區(qū),那么使用下面兩個(gè)函數(shù)注冊(cè)和注銷(xiāo)MTD設(shè)備。
?
[cpp]?view plaincopy? print?
int?add_mtd_device(struct?mtd_info?*mtd)??int?del_mtd_device?(struct?mtd_info?*mtd)?? 如果MTD設(shè)備存在其他分區(qū),那么使用下面兩個(gè)函數(shù)注冊(cè)和注銷(xiāo)MTD設(shè)備。 [cpp]?view plaincopy? print?
int?add_mtd_partitions(struct?mtd_info?*master,const?struct?mtd_partition?*parts,int?nbparts)??int?del_mtd_partitions(struct?mtd_info?*master)?? 其中mtd_partition結(jié)構(gòu)體表示分區(qū)的信息 ?
?
[cpp]?view plaincopy? print?
struct?mtd_partition?{??????char?*name;???????????????????uint64_t?size;????????????????uint64_t?offset;??????????????uint32_t?mask_flags;??????????struct?nand_ecclayout?*ecclayout;?????????struct?mtd_info?**mtdp;???????};??其中nand_ecclayout結(jié)構(gòu)體:??struct?nand_ecclayout?{??????__u32?eccbytes;???????????__u32?eccpos[64];?????????__u32?oobavail;?????????????????struct?nand_oobfree?oobfree[MTD_MAX_OOBFREE_ENTRIES];??};?? 關(guān)于nand_ecclayout結(jié)構(gòu)體實(shí)例,更多可參考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64實(shí)例。MTD設(shè)備層: ?
mtd字符設(shè)備接口:
/drivers/mtd/mtdchar.c文件實(shí)現(xiàn)了MTD字符設(shè)備接口,通過(guò)它,可以直接訪(fǎng)問(wèn)Flash設(shè)備,與前面的字符驅(qū)動(dòng)一樣,通過(guò)file_operations結(jié)構(gòu)體里面的open()、read()、write()、ioctl()可以讀寫(xiě)Flash,通過(guò)一系列IOCTL 命令可以獲取Flash 設(shè)備信息、擦除Flash、讀寫(xiě)NAND 的OOB、獲取OOB layout 及檢查NAND 壞塊等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)?
mtd塊設(shè)備接口:
/drivers/mtd/mtdblock.c文件實(shí)現(xiàn)了MTD塊設(shè)備接口,主要原理是將Flash的erase block 中的數(shù)據(jù)在內(nèi)存中建立映射,然后對(duì)其進(jìn)行修改,最后擦除Flash 上的block,將內(nèi)存中的映射塊寫(xiě)入Flash 塊。整個(gè)過(guò)程被稱(chēng)為read/modify/erase/rewrite 周期。?但是,這樣做是不安全的,當(dāng)下列操作序列發(fā)生時(shí),read/modify/erase/poweroff,就會(huì)丟失這個(gè)block 塊的數(shù)據(jù)。
MTD硬件驅(qū)動(dòng)層:
Linux內(nèi)核再M(fèi)TD層下實(shí)現(xiàn)了通用的NAND驅(qū)動(dòng)(/driver/mtd/nand/nand_base.c),因此芯片級(jí)的NAND驅(qū)動(dòng)不再需要實(shí)現(xiàn)mtd_info結(jié)構(gòu)體中的read()、write()、read_oob()、write_oob()等成員函數(shù)。
MTD使用nand_chip來(lái)表示一個(gè)NAND FLASH芯片, 該結(jié)構(gòu)體包含了關(guān)于Nand Flash的地址信息,讀寫(xiě)方法,ECC模式,硬件控制等一系列底層機(jī)制。
?
[cpp]?view plaincopy? print?
struct?nand_chip?{??????void??__iomem???*IO_ADDR_R;???????????void??__iomem???*IO_ADDR_W;???????????????????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;?????????????????????unsigned?int????options;????????????????????int??????page_shift;??????????????int??????phys_erase_shift;??????????????int??????bbt_erase_shift;????????????int??????chip_shift;????????????int??????numchips;????????????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;?????????????struct?nand_ecc_ctrl?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;??};?? 最后,我們來(lái)用圖表的形式來(lái)總結(jié)一下,MTD設(shè)備層、MTD原始設(shè)備層、FLASH硬件驅(qū)動(dòng)層之間的聯(lián)系。 ?
?
本文轉(zhuǎn)自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/5825580.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的Linux MTD系统剖析【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。