您的位置 首页 电路

ARM-Linux驱动–MTD驱动剖析(三)

主机:GentooLinux112withlinuxkernel306硬件平台:FL2440(S3C2440)withlinuxkernel2635原创作品,转载请标明出

主机:Gentoo Linux 11.2 with linux kernel 3.0.6

硬件渠道:FL2440(S3C2440)with linux kernel 2.6.35

本文剖析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%012llx\n”,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–disabled\n”,
  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%#llx\n”,
  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-only\n”,
  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-only\n”,
  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设备,字符设备和块设备,待续……..

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/dianlu/264551.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部