ARM-Linux驅(qū)動--MTD驅(qū)動分析(三)
硬件平臺:FL2440(S3C2440)with linux kernel 2.6.35
本文引用地址:http://m.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
- /*Ourpartitionnodestructure*/
- //分區(qū)結(jié)構(gòu)信息
- structmtd_part{
- structmtd_infomtd;//mtd_info數(shù)據(jù)結(jié)構(gòu),會被加入mtd_table中
- structmtd_info*master;//該分區(qū)的主分區(qū)
- uint64_toffset;//該分區(qū)的偏移地址
- structlist_headlist;
- };
2、分區(qū)鏈表mtd_partitions
- /*Ourpartitionlinkedlist*/
- //聲明mtd_partitions鏈表
- staticLIST_HEAD(mtd_partitions);
3、add_mtd_partitions函數(shù)
- /*
- *Thisfunction,givenamasterMTDobjectandapartitiontable,creates
- *andregistersslaveMTDobjectswhichareboundtothemasteraccordingto
- *thepartitiondefinitions.
- *
- *Wedontregisterthemaster,orexpectthecallertohavedoneso,
- *forreasonsofdataintegrity.
- */
- //根據(jù)一個MTD主設(shè)備和分區(qū)表,創(chuàng)建新的主設(shè)備下的副設(shè)備并記錄到分區(qū)表中
- //這里我們不將注射被注冊到分區(qū)表中,只注冊副設(shè)備到到分區(qū)表中
- intadd_mtd_partitions(structmtd_info*master,
- conststructmtd_partition*parts,
- intnbparts)
- {
- structmtd_part*slave;
- uint64_tcur_offset=0;
- inti;
- printk(KERN_NOTICE"Creating%dMTDpartitionson"%s":n",nbparts,master->name);
- for(i=0;i
- slave=add_one_partition(master,parts+i,i,cur_offset);
- if(!slave)
- return-ENOMEM;
- cur_offset=slave->offset+slave->mtd.size;
- }
- return0;
- }
- EXPORT_SYMBOL(add_mtd_partitions);
而add_one_partition函數(shù)實現(xiàn)如下:
- //創(chuàng)建一個分區(qū)
- staticstructmtd_part*add_one_partition(structmtd_info*master,
- conststructmtd_partition*part,intpartno,
- uint64_tcur_offset)
- {
- structmtd_part*slave;
- /*allocatethepartitionstructure*/
- slave=kzalloc(sizeof(*slave),GFP_KERNEL);//分配內(nèi)存
- if(!slave){
- printk(KERN_ERR"memoryallocationerrorwhilecreatingpartitionsfor"%s"n",
- master->name);
- del_mtd_partitions(master);
- returnNULL;
- }
- list_add(&slave->list,&mtd_partitions);//將原始設(shè)備表添加到分區(qū)表中
- /*setuptheMTDobjectforthispartition*/
- //大部分根據(jù)master相應(yīng)的信息設(shè)置MTD分區(qū)slave的信息
- slave->mtd.type=master->type;
- slave->mtd.flags=master->flags&~part->mask_flags;
- slave->mtd.size=part->size;
- slave->mtd.writesize=master->writesize;
- slave->mtd.oobsize=master->oobsize;
- slave->mtd.oobavail=master->oobavail;
- slave->mtd.subpage_sft=master->subpage_sft;
- slave->mtd.name=part->name;
- slave->mtd.owner=master->owner;
- slave->mtd.backing_dev_info=master->backing_dev_info;
- /*NOTE:wedontarrangeMTDsasatree;itdbeerror-prone
- *tohavethesamedatabeintwodifferentpartitions.
- */
- slave->mtd.dev.parent=master->dev.parent;
- slave->mtd.read=part_read;
- slave->mtd.write=part_write;
- if(master->panic_write)
- slave->mtd.panic_write=part_panic_write;
- if(master->point&&master->unpoint){
- slave->mtd.point=part_point;
- slave->mtd.unpoint=part_unpoint;
- }
- if(master->get_unmapped_area)
- slave->mtd.get_unmapped_area=part_get_unmapped_area;
- if(master->read_oob)
- slave->mtd.read_oob=part_read_oob;
- if(master->write_oob)
- slave->mtd.write_oob=part_write_oob;
- if(master->read_user_prot_reg)
- slave->mtd.read_user_prot_reg=part_read_user_prot_reg;
- if(master->read_fact_prot_reg)
- slave->mtd.read_fact_prot_reg=part_read_fact_prot_reg;
- if(master->write_user_prot_reg)
- slave->mtd.write_user_prot_reg=part_write_user_prot_reg;
- if(master->lock_user_prot_reg)
- slave->mtd.lock_user_prot_reg=part_lock_user_prot_reg;
- if(master->get_user_prot_info)
- slave->mtd.get_user_prot_info=part_get_user_prot_info;
- if(master->get_fact_prot_info)
- slave->mtd.get_fact_prot_info=part_get_fact_prot_info;
- if(master->sync)
- slave->mtd.sync=part_sync;
- if(!partno&&!master->dev.class&&master->suspend&&master->resume){
- slave->mtd.suspend=part_suspend;
- slave->mtd.resume=part_resume;
- }
- if(master->writev)
- slave->mtd.writev=part_writev;
- if(master->lock)
- slave->mtd.lock=part_lock;
- if(master->unlock)
- slave->mtd.unlock=part_unlock;
- if(master->block_isbad)
- slave->mtd.block_isbad=part_block_isbad;
- if(master->block_markbad)
- slave->mtd.block_markbad=part_block_markbad;
- slave->mtd.erase=part_erase;
- slave->master=master;
- slave->offset=part->offset;
- if(slave->offset==MTDPART_OFS_APPEND)
- slave->offset=cur_offset;
- if(slave->offset==MTDPART_OFS_NXTBLK){
- slave->offset=cur_offset;
- if(mtd_mod_by_eb(cur_offset,master)!=0){
- /*Rounduptonexterasesize*/
- slave->offset=(mtd_div_by_eb(cur_offset,master)+1)*master->erasesize;
- printk(KERN_NOTICE"Movingpartition%d:"
- "0x%012llx->0x%012llxn",partno,
- (unsignedlonglong)cur_offset,(unsignedlonglong)slave->offset);
- }
- }
- if(slave->mtd.size==MTDPART_SIZ_FULL)
- slave->mtd.size=master->size-slave->offset;
- printk(KERN_NOTICE"0x%012llx-0x%012llx:"%s"n",(unsignedlonglong)slave->offset,
- (unsignedlonglong)(slave->offset+slave->mtd.size),slave->mtd.name);
- /*letsdosomesanitychecks*/
- if(slave->offset>=master->size){
- /*letsregisteritanywaytopreserveordering*/
- slave->offset=0;
- slave->mtd.size=0;
- printk(KERN_ERR"mtd:partition"%s"isoutofreach--disabledn",
- part->name);
- gotoout_register;
- }
- if(slave->offset+slave->mtd.size>master->size){
- slave->mtd.size=master->size-slave->offset;
- printk(KERN_WARNING"mtd:partition"%s"extendsbeyondtheendofdevice"%s"--sizetruncatedto%#llxn",
- part->name,master->name,(unsignedlonglong)slave->mtd.size);
- }
- if(master->numeraseregions>1){
- /*Dealwithvariableerasesizestuff*/
- inti,max=master->numeraseregions;
- u64end=slave->offset+slave->mtd.size;
- structmtd_erase_region_info*regions=master->eraseregions;
- /*Findthefirsteraseregionswhichispartofthis
- *partition.*/
- for(i=0;i
offset;i++) - ;
- /*Theloopsearchedfortheregion_behind_thefirstone*/
- if(i>0)
- i--;
- /*Pickbiggesterasesize*/
- for(;i
- if(slave->mtd.erasesize
- slave->mtd.erasesize=regions[i].erasesize;
- }
- }
- BUG_ON(slave->mtd.erasesize==0);
- }else{
- /*Singleerasesize*/
- slave->mtd.erasesize=master->erasesize;
- }
- if((slave->mtd.flags&MTD_WRITEABLE)&&
- mtd_mod_by_eb(slave->offset,&slave->mtd)){
- /*Doesntstartonaboundaryofmajorerasesize*/
- /*FIXME:Letitbewritableifitisonaboundaryof
- *_minor_erasesizethough*/
- slave->mtd.flags&=~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd:partition"%s"doesntstartonaneraseblockboundary--forceread-onlyn",
- part->name);
- }
- if((slave->mtd.flags&MTD_WRITEABLE)&&
- mtd_mod_by_eb(slave->mtd.size,&slave->mtd)){
- slave->mtd.flags&=~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd:partition"%s"doesntendonaneraseblock--forceread-onlyn",
- part->name);
- }
- slave->mtd.ecclayout=master->ecclayout;
- if(master->block_isbad){
- uint64_toffs=0;
- while(offs
mtd.size){ - if(master->block_isbad(master,
- offs+slave->offset))
- slave->mtd.ecc_stats.badblocks++;
- offs+=slave->mtd.erasesize;
- }
- }
- out_register:
- /*registerourpartition*/
- //最后調(diào)用add_mtd_device根據(jù)該設(shè)備的mtd_info信息添加設(shè)備鏈表,將其作為一個獨立的MTD原始設(shè)備
- add_mtd_device(&slave->mtd);
- returnslave;
- }
- if(slave->mtd.erasesize
4、del_mtd_partition函數(shù)
- /*
- *ThisfunctionunregistersanddestroyallslaveMTDobjectswhichare
- *attachedtothegivenmasterMTDobject.
- */
- //將一個主設(shè)備下的所有副設(shè)備刪除
- intdel_mtd_partitions(structmtd_info*master)
- {
- structmtd_part*slave,*next;
- list_for_each_entry_safe(slave,next,&mtd_partitions,list)//遍歷mtd_partitions鏈表,查找到指定的主設(shè)備
- if(slave->master==master){
- list_del(&slave->list);//將主設(shè)備下的附屬設(shè)備刪除
- del_mtd_device(&slave->mtd);//調(diào)用del_mtd_device函數(shù)將每個設(shè)備從MTD原始設(shè)備表中刪除
- kfree(slave);//釋放內(nèi)存
- }
- return0;
- }
- EXPORT_SYMBOL(del_mtd_partitions);
5、其他的分區(qū)管理函數(shù)
- /*
- *MTDmethodswhichsimplytranslatetheeffectiveaddressandpassthrough
- *tothe_real_device.
- */
- //讀取某個分區(qū)的指定數(shù)據(jù)
- staticintpart_read(structmtd_info*mtd,loff_tfrom,size_tlen,
- size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- structmtd_ecc_statsstats;
- intres;
- stats=part->master->ecc_stats;
- if(from>=mtd->size)
- len=0;
- elseif(from+len>mtd->size)
- len=mtd->size-from;
- res=part->master->read(part->master,from+part->offset,
- len,retlen,buf);
- if(unlikely(res)){
- if(res==-EUCLEAN)
- mtd->ecc_stats.corrected+=part->master->ecc_stats.corrected-stats.corrected;
- if(res==-EBADMSG)
- mtd->ecc_stats.failed+=part->master->ecc_stats.failed-stats.failed;
- }
- returnres;
- }
- staticintpart_point(structmtd_info*mtd,loff_tfrom,size_tlen,
- size_t*retlen,void**virt,resource_size_t*phys)
- {
- structmtd_part*part=PART(mtd);
- if(from>=mtd->size)
- len=0;
- elseif(from+len>mtd->size)
- len=mtd->size-from;
- returnpart->master->point(part->master,from+part->offset,
- len,retlen,virt,phys);
- }
- staticvoidpart_unpoint(structmtd_info*mtd,loff_tfrom,size_tlen)
- {
- structmtd_part*part=PART(mtd);
- part->master->unpoint(part->master,from+part->offset,len);
- }
- //獲取空閑的內(nèi)存驅(qū)動
- staticunsignedlongpart_get_unmapped_area(structmtd_info*mtd,
- unsignedlonglen,
- unsignedlongoffset,
- unsignedlongflags)
- {
- structmtd_part*part=PART(mtd);
- offset+=part->offset;
- returnpart->master->get_unmapped_area(part->master,len,offset,
- flags);
- }
- staticintpart_read_oob(structmtd_info*mtd,loff_tfrom,
- structmtd_oob_ops*ops)
- {
- structmtd_part*part=PART(mtd);
- intres;
- if(from>=mtd->size)
- return-EINVAL;
- if(ops->datbuf&&from+ops->len>mtd->size)
- return-EINVAL;
- res=part->master->read_oob(part->master,from+part->offset,ops);
- if(unlikely(res)){
- if(res==-EUCLEAN)
- mtd->ecc_stats.corrected++;
- if(res==-EBADMSG)
- mtd->ecc_stats.failed++;
- }
- returnres;
- }
- staticintpart_read_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->read_user_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_get_user_prot_info(structmtd_info*mtd,
- structotp_info*buf,size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->get_user_prot_info(part->master,buf,len);
- }
- staticintpart_read_fact_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->read_fact_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_get_fact_prot_info(structmtd_info*mtd,structotp_info*buf,
- size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->get_fact_prot_info(part->master,buf,len);
- }
- //分區(qū)寫函數(shù)
- staticintpart_write(structmtd_info*mtd,loff_tto,size_tlen,
- size_t*retlen,constu_char*buf)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- len=0;
- elseif(to+len>mtd->size)
- len=mtd->size-to;
- returnpart->master->write(part->master,to+part->offset,
- len,retlen,buf);
- }
- staticintpart_panic_write(structmtd_info*mtd,loff_tto,size_tlen,
- size_t*retlen,constu_char*buf)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- len=0;
- elseif(to+len>mtd->size)
- len=mtd->size-to;
- returnpart->master->panic_write(part->master,to+part->offset,
- len,retlen,buf);
- }
- staticintpart_write_oob(structmtd_info*mtd,loff_tto,
- structmtd_oob_ops*ops)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- return-EINVAL;
- if(ops->datbuf&&to+ops->len>mtd->size)
- return-EINVAL;
- returnpart->master->write_oob(part->master,to+part->offset,ops);
- }
- staticintpart_write_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->write_user_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_lock_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->lock_user_prot_reg(part->master,from,len);
- }
- staticintpart_writev(structmtd_info*mtd,conststructkvec*vecs,
- unsignedlongcount,loff_tto,size_t*retlen)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- returnpart->master->writev(part->master,vecs,count,
- to+part->offset,retlen);
- }
- staticintpart_erase(structmtd_info*mtd,structerase_info*instr)
- {
- structmtd_part*part=PART(mtd);
- intret;
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(instr->addr>=mtd->size)
- return-EINVAL;
- instr->addr+=part->offset;
- ret=part->master->erase(part->master,instr);
- if(ret){
- if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
- instr->fail_addr-=part->offset;
- instr->addr-=part->offset;
- }
- returnret;
- }
- voidmtd_erase_callback(structerase_info*instr)
- {
- if(instr->mtd->erase==part_erase){
- structmtd_part*part=PART(instr->mtd);
- if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
- instr->fail_addr-=part->offset;
- instr->addr-=part->offset;
- }
- if(instr->callback)
- instr->callback(instr);
- }
- EXPORT_SYMBOL_GPL(mtd_erase_callback);
- staticintpart_lock(structmtd_info*mtd,loff_tofs,uint64_tlen)
- {
- structmtd_part*part=PART(mtd);
- if((len+ofs)>mtd->size)
- return-EINVAL;
- returnpart->master->lock(part->master,ofs+part->offset,len);
- }
- staticintpart_unlock(structmtd_info*mtd,loff_tofs,uint64_tlen)
- {
- structmtd_part*part=PART(mtd);
- if((len+ofs)>mtd->size)
- return-EINVAL;
- returnpart->master->unlock(part->master,ofs+part->offset,len);
- }
- //分區(qū)同步函數(shù)
- staticvoidpart_sync(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- part->master->sync(part->master);
- }
- //支持電源管理的功能函數(shù)
- staticintpart_suspend(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->suspend(part->master);
- }
- staticvoidpart_resume(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- part->master->resume(part->master);
- }
- staticintpart_block_isbad(structmtd_info*mtd,loff_tofs)
- {
- structmtd_part*part=PART(mtd);
- if(ofs>=mtd->size)
- return-EINVAL;
- ofs+=part->offset;
- returnpart->master->block_isbad(part->master,ofs);
- }
- //標記設(shè)備地址壞塊
- staticintpart_block_markbad(structmtd_info*mtd,loff_tofs)
- {
- structmtd_part*part=PART(mtd);
- intres;
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(ofs>=mtd->size)
- return-EINVAL;
- ofs+=part->offset;
- res=part->master->block_markbad(part->master,ofs);
- if(!res)
- mtd->ecc_stats.badblocks++;
- returnres;
- }
下篇分析具體的MTD設(shè)備,字符設(shè)備和塊設(shè)備,待續(xù)........
評論