新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM-Linux驅(qū)動--MTD驅(qū)動分析(三)

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

作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
主機:Gentoo Linux 11.2 with linux kernel 3.0.6

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

本文引用地址:http://butianyuan.cn/article/201611/319014.htm

本文分析MTD設(shè)備的分區(qū)管理機制

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

1、分區(qū)的結(jié)構(gòu)體描述結(jié)構(gòu)體mtd_part

  1. /*Ourpartitionnodestructure*/
  2. //分區(qū)結(jié)構(gòu)信息
  3. structmtd_part{
  4. structmtd_infomtd;//mtd_info數(shù)據(jù)結(jié)構(gòu),會被加入mtd_table中
  5. structmtd_info*master;//該分區(qū)的主分區(qū)
  6. uint64_toffset;//該分區(qū)的偏移地址
  7. structlist_headlist;
  8. };

2、分區(qū)鏈表mtd_partitions

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

3、add_mtd_partitions函數(shù)
  1. /*
  2. *Thisfunction,givenamasterMTDobjectandapartitiontable,creates
  3. *andregistersslaveMTDobjectswhichareboundtothemasteraccordingto
  4. *thepartitiondefinitions.
  5. *
  6. *Wedontregisterthemaster,orexpectthecallertohavedoneso,
  7. *forreasonsofdataintegrity.
  8. */
  9. //根據(jù)一個MTD主設(shè)備和分區(qū)表,創(chuàng)建新的主設(shè)備下的副設(shè)備并記錄到分區(qū)表中
  10. //這里我們不將注射被注冊到分區(qū)表中,只注冊副設(shè)備到到分區(qū)表中
  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函數(shù)實現(xiàn)如下:
  1. //創(chuàng)建一個分區(qū)
  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);//分配內(nèi)存
  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);//將原始設(shè)備表添加到分區(qū)表中
  16. /*setuptheMTDobjectforthispartition*/
  17. //大部分根據(jù)master相應(yīng)的信息設(shè)置MTD分區(qū)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. //最后調(diào)用add_mtd_device根據(jù)該設(shè)備的mtd_info信息添加設(shè)備鏈表,將其作為一個獨立的MTD原始設(shè)備
  158. add_mtd_device(&slave->mtd);
  159. returnslave;
  160. }

4、del_mtd_partition函數(shù)
  1. /*
  2. *ThisfunctionunregistersanddestroyallslaveMTDobjectswhichare
  3. *attachedtothegivenmasterMTDobject.
  4. */
  5. //將一個主設(shè)備下的所有副設(shè)備刪除
  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鏈表,查找到指定的主設(shè)備
  10. if(slave->master==master){
  11. list_del(&slave->list);//將主設(shè)備下的附屬設(shè)備刪除
  12. del_mtd_device(&slave->mtd);//調(diào)用del_mtd_device函數(shù)將每個設(shè)備從MTD原始設(shè)備表中刪除
  13. kfree(slave);//釋放內(nèi)存
  14. }
  15. return0;
  16. }
  17. EXPORT_SYMBOL(del_mtd_partitions);

5、其他的分區(qū)管理函數(shù)
  1. /*
  2. *MTDmethodswhichsimplytranslatetheeffectiveaddressandpassthrough
  3. *tothe_real_device.
  4. */
  5. //讀取某個分區(qū)的指定數(shù)據(jù)
  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. //獲取空閑的內(nèi)存驅(qū)動
  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. //分區(qū)寫函數(shù)
  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. //分區(qū)同步函數(shù)
  203. staticvoidpart_sync(structmtd_info*mtd)
  204. {
  205. structmtd_part*part=PART(mtd);
  206. part->master->sync(part->master);
  207. }
  208. //支持電源管理的功能函數(shù)
  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. //標記設(shè)備地址壞塊
  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設(shè)備,字符設(shè)備和塊設(shè)備,待續(xù)........


評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉