新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM-Linux驅動--MTD驅動分析(三)

        ARM-Linux驅動--MTD驅動分析(三)

        作者: 時間:2016-11-20 來源:網絡 收藏
        主機:Gentoo Linux 11.2 with linux kernel 3.0.6

        硬件平臺:FL2440(S3C2440)with linux kernel 2.6.35

        本文引用地址:http://www.104case.com/article/201611/319014.htm

        本文分析MTD設備的分區管理機制

        分區管理實際上是將一個MTD設備分成幾個分區,將其作為單獨的MTD原始設備進行管理。

        1、分區的結構體描述結構體mtd_part

        1. /*Ourpartitionnodestructure*/
        2. //分區結構信息
        3. structmtd_part{
        4. structmtd_infomtd;//mtd_info數據結構,會被加入mtd_table中
        5. structmtd_info*master;//該分區的主分區
        6. uint64_toffset;//該分區的偏移地址
        7. structlist_headlist;
        8. };

        2、分區鏈表mtd_partitions

        1. /*Ourpartitionlinkedlist*/
        2. //聲明mtd_partitions鏈表
        3. staticLIST_HEAD(mtd_partitions);

        3、add_mtd_partitions函數
        1. /*
        2. *Thisfunction,givenamasterMTDobjectandapartitiontable,creates
        3. *andregistersslaveMTDobjectswhichareboundtothemasteraccordingto
        4. *thepartitiondefinitions.
        5. *
        6. *Wedontregisterthemaster,orexpectthecallertohavedoneso,
        7. *forreasonsofdataintegrity.
        8. */
        9. //根據一個MTD主設備和分區表,創建新的主設備下的副設備并記錄到分區表中
        10. //這里我們不將注射被注冊到分區表中,只注冊副設備到到分區表中
        11. intadd_mtd_partitions(structmtd_info*master,
        12. conststructmtd_partition*parts,
        13. intnbparts)
        14. {
        15. structmtd_part*slave;
        16. uint64_tcur_offset=0;
        17. inti;
        18. printk(KERN_NOTICE"Creating%dMTDpartitionson"%s":n",nbparts,master->name);
        19. for(i=0;i
        20. slave=add_one_partition(master,parts+i,i,cur_offset);
        21. if(!slave)
        22. return-ENOMEM;
        23. cur_offset=slave->offset+slave->mtd.size;
        24. }
        25. return0;
        26. }
        27. EXPORT_SYMBOL(add_mtd_partitions);

        而add_one_partition函數實現如下:
        1. //創建一個分區
        2. staticstructmtd_part*add_one_partition(structmtd_info*master,
        3. conststructmtd_partition*part,intpartno,
        4. uint64_tcur_offset)
        5. {
        6. structmtd_part*slave;
        7. /*allocatethepartitionstructure*/
        8. slave=kzalloc(sizeof(*slave),GFP_KERNEL);//分配內存
        9. if(!slave){
        10. printk(KERN_ERR"memoryallocationerrorwhilecreatingpartitionsfor"%s"n",
        11. master->name);
        12. del_mtd_partitions(master);
        13. returnNULL;
        14. }
        15. list_add(&slave->list,&mtd_partitions);//將原始設備表添加到分區表中
        16. /*setuptheMTDobjectforthispartition*/
        17. //大部分根據master相應的信息設置MTD分區slave的信息
        18. slave->mtd.type=master->type;
        19. slave->mtd.flags=master->flags&~part->mask_flags;
        20. slave->mtd.size=part->size;
        21. slave->mtd.writesize=master->writesize;
        22. slave->mtd.oobsize=master->oobsize;
        23. slave->mtd.oobavail=master->oobavail;
        24. slave->mtd.subpage_sft=master->subpage_sft;
        25. slave->mtd.name=part->name;
        26. slave->mtd.owner=master->owner;
        27. slave->mtd.backing_dev_info=master->backing_dev_info;
        28. /*NOTE:wedontarrangeMTDsasatree;itdbeerror-prone
        29. *tohavethesamedatabeintwodifferentpartitions.
        30. */
        31. slave->mtd.dev.parent=master->dev.parent;
        32. slave->mtd.read=part_read;
        33. slave->mtd.write=part_write;
        34. if(master->panic_write)
        35. slave->mtd.panic_write=part_panic_write;
        36. if(master->point&&master->unpoint){
        37. slave->mtd.point=part_point;
        38. slave->mtd.unpoint=part_unpoint;
        39. }
        40. if(master->get_unmapped_area)
        41. slave->mtd.get_unmapped_area=part_get_unmapped_area;
        42. if(master->read_oob)
        43. slave->mtd.read_oob=part_read_oob;
        44. if(master->write_oob)
        45. slave->mtd.write_oob=part_write_oob;
        46. if(master->read_user_prot_reg)
        47. slave->mtd.read_user_prot_reg=part_read_user_prot_reg;
        48. if(master->read_fact_prot_reg)
        49. slave->mtd.read_fact_prot_reg=part_read_fact_prot_reg;
        50. if(master->write_user_prot_reg)
        51. slave->mtd.write_user_prot_reg=part_write_user_prot_reg;
        52. if(master->lock_user_prot_reg)
        53. slave->mtd.lock_user_prot_reg=part_lock_user_prot_reg;
        54. if(master->get_user_prot_info)
        55. slave->mtd.get_user_prot_info=part_get_user_prot_info;
        56. if(master->get_fact_prot_info)
        57. slave->mtd.get_fact_prot_info=part_get_fact_prot_info;
        58. if(master->sync)
        59. slave->mtd.sync=part_sync;
        60. if(!partno&&!master->dev.class&&master->suspend&&master->resume){
        61. slave->mtd.suspend=part_suspend;
        62. slave->mtd.resume=part_resume;
        63. }
        64. if(master->writev)
        65. slave->mtd.writev=part_writev;
        66. if(master->lock)
        67. slave->mtd.lock=part_lock;
        68. if(master->unlock)
        69. slave->mtd.unlock=part_unlock;
        70. if(master->block_isbad)
        71. slave->mtd.block_isbad=part_block_isbad;
        72. if(master->block_markbad)
        73. slave->mtd.block_markbad=part_block_markbad;
        74. slave->mtd.erase=part_erase;
        75. slave->master=master;
        76. slave->offset=part->offset;
        77. if(slave->offset==MTDPART_OFS_APPEND)
        78. slave->offset=cur_offset;
        79. if(slave->offset==MTDPART_OFS_NXTBLK){
        80. slave->offset=cur_offset;
        81. if(mtd_mod_by_eb(cur_offset,master)!=0){
        82. /*Rounduptonexterasesize*/
        83. slave->offset=(mtd_div_by_eb(cur_offset,master)+1)*master->erasesize;
        84. printk(KERN_NOTICE"Movingpartition%d:"
        85. "0x%012llx->0x%012llxn",partno,
        86. (unsignedlonglong)cur_offset,(unsignedlonglong)slave->offset);
        87. }
        88. }
        89. if(slave->mtd.size==MTDPART_SIZ_FULL)
        90. slave->mtd.size=master->size-slave->offset;
        91. printk(KERN_NOTICE"0x%012llx-0x%012llx:"%s"n",(unsignedlonglong)slave->offset,
        92. (unsignedlonglong)(slave->offset+slave->mtd.size),slave->mtd.name);
        93. /*letsdosomesanitychecks*/
        94. if(slave->offset>=master->size){
        95. /*letsregisteritanywaytopreserveordering*/
        96. slave->offset=0;
        97. slave->mtd.size=0;
        98. printk(KERN_ERR"mtd:partition"%s"isoutofreach--disabledn",
        99. part->name);
        100. gotoout_register;
        101. }
        102. if(slave->offset+slave->mtd.size>master->size){
        103. slave->mtd.size=master->size-slave->offset;
        104. printk(KERN_WARNING"mtd:partition"%s"extendsbeyondtheendofdevice"%s"--sizetruncatedto%#llxn",
        105. part->name,master->name,(unsignedlonglong)slave->mtd.size);
        106. }
        107. if(master->numeraseregions>1){
        108. /*Dealwithvariableerasesizestuff*/
        109. inti,max=master->numeraseregions;
        110. u64end=slave->offset+slave->mtd.size;
        111. structmtd_erase_region_info*regions=master->eraseregions;
        112. /*Findthefirsteraseregionswhichispartofthis
        113. *partition.*/
        114. for(i=0;ioffset;i++)
        115. ;
        116. /*Theloopsearchedfortheregion_behind_thefirstone*/
        117. if(i>0)
        118. i--;
        119. /*Pickbiggesterasesize*/
        120. for(;i
        121. if(slave->mtd.erasesize
        122. slave->mtd.erasesize=regions[i].erasesize;
        123. }
        124. }
        125. BUG_ON(slave->mtd.erasesize==0);
        126. }else{
        127. /*Singleerasesize*/
        128. slave->mtd.erasesize=master->erasesize;
        129. }
        130. if((slave->mtd.flags&MTD_WRITEABLE)&&
        131. mtd_mod_by_eb(slave->offset,&slave->mtd)){
        132. /*Doesntstartonaboundaryofmajorerasesize*/
        133. /*FIXME:Letitbewritableifitisonaboundaryof
        134. *_minor_erasesizethough*/
        135. slave->mtd.flags&=~MTD_WRITEABLE;
        136. printk(KERN_WARNING"mtd:partition"%s"doesntstartonaneraseblockboundary--forceread-onlyn",
        137. part->name);
        138. }
        139. if((slave->mtd.flags&MTD_WRITEABLE)&&
        140. mtd_mod_by_eb(slave->mtd.size,&slave->mtd)){
        141. slave->mtd.flags&=~MTD_WRITEABLE;
        142. printk(KERN_WARNING"mtd:partition"%s"doesntendonaneraseblock--forceread-onlyn",
        143. part->name);
        144. }
        145. slave->mtd.ecclayout=master->ecclayout;
        146. if(master->block_isbad){
        147. uint64_toffs=0;
        148. while(offsmtd.size){
        149. if(master->block_isbad(master,
        150. offs+slave->offset))
        151. slave->mtd.ecc_stats.badblocks++;
        152. offs+=slave->mtd.erasesize;
        153. }
        154. }
        155. out_register:
        156. /*registerourpartition*/
        157. //最后調用add_mtd_device根據該設備的mtd_info信息添加設備鏈表,將其作為一個獨立的MTD原始設備
        158. add_mtd_device(&slave->mtd);
        159. returnslave;
        160. }

        4、del_mtd_partition函數
        1. /*
        2. *ThisfunctionunregistersanddestroyallslaveMTDobjectswhichare
        3. *attachedtothegivenmasterMTDobject.
        4. */
        5. //將一個主設備下的所有副設備刪除
        6. intdel_mtd_partitions(structmtd_info*master)
        7. {
        8. structmtd_part*slave,*next;
        9. list_for_each_entry_safe(slave,next,&mtd_partitions,list)//遍歷mtd_partitions鏈表,查找到指定的主設備
        10. if(slave->master==master){
        11. list_del(&slave->list);//將主設備下的附屬設備刪除
        12. del_mtd_device(&slave->mtd);//調用del_mtd_device函數將每個設備從MTD原始設備表中刪除
        13. kfree(slave);//釋放內存
        14. }
        15. return0;
        16. }
        17. EXPORT_SYMBOL(del_mtd_partitions);

        5、其他的分區管理函數
        1. /*
        2. *MTDmethodswhichsimplytranslatetheeffectiveaddressandpassthrough
        3. *tothe_real_device.
        4. */
        5. //讀取某個分區的指定數據
        6. staticintpart_read(structmtd_info*mtd,loff_tfrom,size_tlen,
        7. size_t*retlen,u_char*buf)
        8. {
        9. structmtd_part*part=PART(mtd);
        10. structmtd_ecc_statsstats;
        11. intres;
        12. stats=part->master->ecc_stats;
        13. if(from>=mtd->size)
        14. len=0;
        15. elseif(from+len>mtd->size)
        16. len=mtd->size-from;
        17. res=part->master->read(part->master,from+part->offset,
        18. len,retlen,buf);
        19. if(unlikely(res)){
        20. if(res==-EUCLEAN)
        21. mtd->ecc_stats.corrected+=part->master->ecc_stats.corrected-stats.corrected;
        22. if(res==-EBADMSG)
        23. mtd->ecc_stats.failed+=part->master->ecc_stats.failed-stats.failed;
        24. }
        25. returnres;
        26. }
        27. staticintpart_point(structmtd_info*mtd,loff_tfrom,size_tlen,
        28. size_t*retlen,void**virt,resource_size_t*phys)
        29. {
        30. structmtd_part*part=PART(mtd);
        31. if(from>=mtd->size)
        32. len=0;
        33. elseif(from+len>mtd->size)
        34. len=mtd->size-from;
        35. returnpart->master->point(part->master,from+part->offset,
        36. len,retlen,virt,phys);
        37. }
        38. staticvoidpart_unpoint(structmtd_info*mtd,loff_tfrom,size_tlen)
        39. {
        40. structmtd_part*part=PART(mtd);
        41. part->master->unpoint(part->master,from+part->offset,len);
        42. }
        43. //獲取空閑的內存驅動
        44. staticunsignedlongpart_get_unmapped_area(structmtd_info*mtd,
        45. unsignedlonglen,
        46. unsignedlongoffset,
        47. unsignedlongflags)
        48. {
        49. structmtd_part*part=PART(mtd);
        50. offset+=part->offset;
        51. returnpart->master->get_unmapped_area(part->master,len,offset,
        52. flags);
        53. }
        54. staticintpart_read_oob(structmtd_info*mtd,loff_tfrom,
        55. structmtd_oob_ops*ops)
        56. {
        57. structmtd_part*part=PART(mtd);
        58. intres;
        59. if(from>=mtd->size)
        60. return-EINVAL;
        61. if(ops->datbuf&&from+ops->len>mtd->size)
        62. return-EINVAL;
        63. res=part->master->read_oob(part->master,from+part->offset,ops);
        64. if(unlikely(res)){
        65. if(res==-EUCLEAN)
        66. mtd->ecc_stats.corrected++;
        67. if(res==-EBADMSG)
        68. mtd->ecc_stats.failed++;
        69. }
        70. returnres;
        71. }
        72. staticintpart_read_user_prot_reg(structmtd_info*mtd,loff_tfrom,
        73. size_tlen,size_t*retlen,u_char*buf)
        74. {
        75. structmtd_part*part=PART(mtd);
        76. returnpart->master->read_user_prot_reg(part->master,from,
        77. len,retlen,buf);
        78. }
        79. staticintpart_get_user_prot_info(structmtd_info*mtd,
        80. structotp_info*buf,size_tlen)
        81. {
        82. structmtd_part*part=PART(mtd);
        83. returnpart->master->get_user_prot_info(part->master,buf,len);
        84. }
        85. staticintpart_read_fact_prot_reg(structmtd_info*mtd,loff_tfrom,
        86. size_tlen,size_t*retlen,u_char*buf)
        87. {
        88. structmtd_part*part=PART(mtd);
        89. returnpart->master->read_fact_prot_reg(part->master,from,
        90. len,retlen,buf);
        91. }
        92. staticintpart_get_fact_prot_info(structmtd_info*mtd,structotp_info*buf,
        93. size_tlen)
        94. {
        95. structmtd_part*part=PART(mtd);
        96. returnpart->master->get_fact_prot_info(part->master,buf,len);
        97. }
        98. //分區寫函數
        99. staticintpart_write(structmtd_info*mtd,loff_tto,size_tlen,
        100. size_t*retlen,constu_char*buf)
        101. {
        102. structmtd_part*part=PART(mtd);
        103. if(!(mtd->flags&MTD_WRITEABLE))
        104. return-EROFS;
        105. if(to>=mtd->size)
        106. len=0;
        107. elseif(to+len>mtd->size)
        108. len=mtd->size-to;
        109. returnpart->master->write(part->master,to+part->offset,
        110. len,retlen,buf);
        111. }
        112. staticintpart_panic_write(structmtd_info*mtd,loff_tto,size_tlen,
        113. size_t*retlen,constu_char*buf)
        114. {
        115. structmtd_part*part=PART(mtd);
        116. if(!(mtd->flags&MTD_WRITEABLE))
        117. return-EROFS;
        118. if(to>=mtd->size)
        119. len=0;
        120. elseif(to+len>mtd->size)
        121. len=mtd->size-to;
        122. returnpart->master->panic_write(part->master,to+part->offset,
        123. len,retlen,buf);
        124. }
        125. staticintpart_write_oob(structmtd_info*mtd,loff_tto,
        126. structmtd_oob_ops*ops)
        127. {
        128. structmtd_part*part=PART(mtd);
        129. if(!(mtd->flags&MTD_WRITEABLE))
        130. return-EROFS;
        131. if(to>=mtd->size)
        132. return-EINVAL;
        133. if(ops->datbuf&&to+ops->len>mtd->size)
        134. return-EINVAL;
        135. returnpart->master->write_oob(part->master,to+part->offset,ops);
        136. }
        137. staticintpart_write_user_prot_reg(structmtd_info*mtd,loff_tfrom,
        138. size_tlen,size_t*retlen,u_char*buf)
        139. {
        140. structmtd_part*part=PART(mtd);
        141. returnpart->master->write_user_prot_reg(part->master,from,
        142. len,retlen,buf);
        143. }
        144. staticintpart_lock_user_prot_reg(structmtd_info*mtd,loff_tfrom,
        145. size_tlen)
        146. {
        147. structmtd_part*part=PART(mtd);
        148. returnpart->master->lock_user_prot_reg(part->master,from,len);
        149. }
        150. staticintpart_writev(structmtd_info*mtd,conststructkvec*vecs,
        151. unsignedlongcount,loff_tto,size_t*retlen)
        152. {
        153. structmtd_part*part=PART(mtd);
        154. if(!(mtd->flags&MTD_WRITEABLE))
        155. return-EROFS;
        156. returnpart->master->writev(part->master,vecs,count,
        157. to+part->offset,retlen);
        158. }
        159. staticintpart_erase(structmtd_info*mtd,structerase_info*instr)
        160. {
        161. structmtd_part*part=PART(mtd);
        162. intret;
        163. if(!(mtd->flags&MTD_WRITEABLE))
        164. return-EROFS;
        165. if(instr->addr>=mtd->size)
        166. return-EINVAL;
        167. instr->addr+=part->offset;
        168. ret=part->master->erase(part->master,instr);
        169. if(ret){
        170. if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
        171. instr->fail_addr-=part->offset;
        172. instr->addr-=part->offset;
        173. }
        174. returnret;
        175. }
        176. voidmtd_erase_callback(structerase_info*instr)
        177. {
        178. if(instr->mtd->erase==part_erase){
        179. structmtd_part*part=PART(instr->mtd);
        180. if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
        181. instr->fail_addr-=part->offset;
        182. instr->addr-=part->offset;
        183. }
        184. if(instr->callback)
        185. instr->callback(instr);
        186. }
        187. EXPORT_SYMBOL_GPL(mtd_erase_callback);
        188. staticintpart_lock(structmtd_info*mtd,loff_tofs,uint64_tlen)
        189. {
        190. structmtd_part*part=PART(mtd);
        191. if((len+ofs)>mtd->size)
        192. return-EINVAL;
        193. returnpart->master->lock(part->master,ofs+part->offset,len);
        194. }
        195. staticintpart_unlock(structmtd_info*mtd,loff_tofs,uint64_tlen)
        196. {
        197. structmtd_part*part=PART(mtd);
        198. if((len+ofs)>mtd->size)
        199. return-EINVAL;
        200. returnpart->master->unlock(part->master,ofs+part->offset,len);
        201. }
        202. //分區同步函數
        203. staticvoidpart_sync(structmtd_info*mtd)
        204. {
        205. structmtd_part*part=PART(mtd);
        206. part->master->sync(part->master);
        207. }
        208. //支持電源管理的功能函數
        209. staticintpart_suspend(structmtd_info*mtd)
        210. {
        211. structmtd_part*part=PART(mtd);
        212. returnpart->master->suspend(part->master);
        213. }
        214. staticvoidpart_resume(structmtd_info*mtd)
        215. {
        216. structmtd_part*part=PART(mtd);
        217. part->master->resume(part->master);
        218. }
        219. staticintpart_block_isbad(structmtd_info*mtd,loff_tofs)
        220. {
        221. structmtd_part*part=PART(mtd);
        222. if(ofs>=mtd->size)
        223. return-EINVAL;
        224. ofs+=part->offset;
        225. returnpart->master->block_isbad(part->master,ofs);
        226. }
        227. //標記設備地址壞塊
        228. staticintpart_block_markbad(structmtd_info*mtd,loff_tofs)
        229. {
        230. structmtd_part*part=PART(mtd);
        231. intres;
        232. if(!(mtd->flags&MTD_WRITEABLE))
        233. return-EROFS;
        234. if(ofs>=mtd->size)
        235. return-EINVAL;
        236. ofs+=part->offset;
        237. res=part->master->block_markbad(part->master,ofs);
        238. if(!res)
        239. mtd->ecc_stats.badblocks++;
        240. returnres;
        241. }

        下篇分析具體的MTD設備,字符設備和塊設備,待續........


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 淳安县| 儋州市| 罗源县| 军事| 临西县| 东乡县| 呼图壁县| 兴城市| 临沧市| 锦屏县| 桑植县| 崇信县| 新沂市| 教育| 吉林省| 辉南县| 集安市| 房产| 富源县| 平潭县| 阳原县| 永靖县| 赫章县| 睢宁县| 张家界市| 株洲县| 隆化县| 玉山县| 靖州| 虹口区| 谢通门县| 来安县| 那曲县| 浮山县| 高淳县| 济阳县| 阜阳市| 射阳县| 濮阳县| 开平市| 垣曲县|