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

2021-01-08 電子產品世界

主機:Gentoo Linux 11.2 with linux kernel 3.0.6

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

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

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

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

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

/*Ourpartitionnodestructure*///分區結構信息structmtd_part{structmtd_infomtd;//mtd_info數據結構,會被加入mtd_table中structmtd_info*master;//該分區的主分區uint64_toffset;//該分區的偏移地址structlist_headlist;};

2、分區鍊表mtd_partitions

/*Ourpartitionlinkedlist*///聲明mtd_partitions鍊表staticLIST_HEAD(mtd_partitions);

3、add_mtd_partitions函數
/**Thisfunction,givenamasterMTDobjectandapartitiontable,creates*andregistersslaveMTDobjectswhichareboundtothemasteraccordingto*thepartitiondefinitions.**Wedontregisterthemaster,orexpectthecallertohavedoneso,*forreasonsofdataintegrity.*///根據一個MTD主設備和分區表,創建新的主設備下的副設備並記錄到分區表中//這裡我們不將注射被註冊到分區表中,只註冊副設備到到分區表中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;islave=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函數實現如下:
//創建一個分區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);//分配內存if(!slave){printk(KERN_ERR"memoryallocationerrorwhilecreatingpartitionsfor\"%s\"\n",master->name);del_mtd_partitions(master);returnNULL;}list_add(&slave->list,&mtd_partitions);//將原始設備表添加到分區表中/*setuptheMTDobjectforthispartition*///大部分根據master相應的信息設置MTD分區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%012llx\n",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--disabled\n",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%#llx\n",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;ioffset;i++);/*Theloopsearchedfortheregion_behind_thefirstone*/if(i>0)i--;/*Pickbiggesterasesize*/for(;iif(slave->mtd.erasesizeslave->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-only\n",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-only\n",part->name);}slave->mtd.ecclayout=master->ecclayout;if(master->block_isbad){uint64_toffs=0;while(offsmtd.size){if(master->block_isbad(master,offs+slave->offset))slave->mtd.ecc_stats.badblocks++;offs+=slave->mtd.erasesize;}}out_register:/*registerourpartition*///最後調用add_mtd_device根據該設備的mtd_info信息添加設備鍊表,將其作為一個獨立的MTD原始設備add_mtd_device(&slave->mtd);returnslave;}

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

5、其他的分區管理函數
/**MTDmethodswhichsimplytranslatetheeffectiveaddressandpassthrough*tothe_real_device.*///讀取某個分區的指定數據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);}//獲取空閒的內存驅動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);}//分區寫函數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);}//分區同步函數staticvoidpart_sync(structmtd_info*mtd){structmtd_part*part=PART(mtd);part->master->sync(part->master);}//支持電源管理的功能函數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);}//標記設備地址壞塊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設備,字符設備和塊設備,待續........

相關焦點

  • NAND FLASH驅動程序
    // 參考* drivers\mtd\nand\s3c2410.c* drivers\mtd\nand\at91_nand.c//#include "linux/module.h"#include "linux/types.h
  • 淺談分析Arm linux 內核移植及系統初始化的過程二
    調用驅動初始化函數初始化子系統。以此為入口,可以查詢所有的設備驅動。(void) linux/arch/arm/kernel/dma.cstatic int __init s3c2410_core_init(void) linux/arch/arm/mach-s3c2410/s3c2410.cpostcore_initcall(fn)static int ecard_bus_init(void) linux/arch/arm/kernel
  • [ARM筆記]驅動對設備的識別過程及實例——NAND Flash
    驅動程序識別設備時,有以下兩種方法:本文引用地址:http://www.eepw.com.cn/article/201612/341049.htm  (1)驅動程序本身帶有設備信息,比如開始地址、中斷號等;加載驅動程序時,就可以根據這些信息來識別設備。
  • ARM在嵌入式linux內核裁剪與移植的應用
    交叉編譯器完整的安裝涉及到多個軟體安裝,最重要的有binutils、gcc、glibc三個。其中,binutils主要用於生成一些輔助工具;gcc則用來生成交叉編譯器,主要生成arm-linux-gcc交叉編譯工具;glibc主要是提供用戶程序所使用的一些基本的函數庫。自行搭建交叉編譯環境通常比較複雜,而且很容易出錯。
  • ARM-Linux驅動--DM9000網卡驅動分析(一)
    轉載請標明出處http://blog.csdn.net/yming0221/article/details/66097421、下圖是DM9000的引腳圖2、這裡我們結合具體的開發板FL2440下面是FL2440和DM9000的引腳連結圖本人移植DM9000的時候將設備的資源定義放在了arch/arm
  • ARM-Linux驅動--DM9000網卡驅動分析(二)
    硬體平臺:FL2440(s3c2440)內核版本:2.6.35主機平臺:Ubuntu 11.04內核版本:2.6.39原創作品,轉載請標明出處http://blog.csdn.net/yming0221/article/details/6612623下面開始分析具體的代碼,這裡由於使
  • NOR FLASH驅動程序
    //// 參考 drivers\mtd\maps\physmap.c//#include "linux/module.h"#include "linux/types.h"#include "linux/kernel.h"#include "linux/init.h"#include "linux
  • arm驅動Linux內核開發之阻塞非阻塞IO輪詢操作
    《[arm驅動]Linux內核開發之阻塞非阻塞IO----輪詢操作》涉及內核驅動函數二個,內核結構體零個,分析了內核驅動函數二個;可參考的相關應用程式模板或內核驅動模板二個,可參考的相關應用程式模板或內核驅動一個一、概念:Poll是非阻塞IO----
  • 內核不斷升級 如何學習linux設備驅動
    【IT168技術】面對不斷升級的linux內核、GNU開發工具、linux環境下的各種圖形庫,很多linux應用程式開發人員和linux設備驅動開發人員即興奮,又煩躁。興奮的是新的軟體軟體、工具給我提供了更強大的功能,煩躁的是適應新軟體的特性、搭建新環境是一項非常繁瑣的事情。
  • ARM-Linux驅動移植--RTC(實時時鐘)移植
    硬體平臺:FL2440本文引用地址:http://www.eepw.com.cn/article/201611/318866.htm內核版本:2.6.28主機平臺:Ubuntu 11.04內核版本:2.6.39首先修改內核源碼/arch/arm/mach-s3c2410/mach-smdk2410
  • linux內核移植-移植2.6.35.4內核到s3c2440
    ,有人說是新的內核對arm平臺的支持不好,所以就降低了一下版本,這裡移植2.6.35.4內核一、準備工作1、下載 解壓內核從官網上下載linux-2.6.35的內核, ftp://ftp.kernel.org/pub/linux/kernel/v2.6/ ,文件不大,約85M。
  • 嵌入式Linux之我行——LED驅動在2440上的實例開發
    一、開發環境主機:VMWare--Fedora 9開發板:Mini2440--64MB Nand編譯器:arm-linux-gcc-4.3.2二、實現步驟
  • 「正點原子FPGA連載」第二十八章Linux蜂鳴器驅動實驗
    本章我們就驅動開發板上的有源蜂鳴器,使其周期性的「滴、滴、滴…..」鳴叫。本節我們來看一下如果在Linux下編寫蜂鳴器驅動需要做哪些工作:①在設備樹中創建蜂鳴器節點beeper;②在蜂鳴器節點beeper中指定gpio;③編寫驅動程序和測試APP,和第二十七章的LED驅動程序和測試APP基本一樣。接下來我們就根據上面這三步來編寫蜂鳴器Linux驅動程序。
  • USB無線網卡的Linux驅動移植
    也就是說,整個移植過程要求USB無線網卡驅動必須是Realtek 8188SU,且工作環境是Linux2.6.12.7。Realtek公司對8188SU主晶片驅動提供的建議是PC機Fedora Linux 2.6.24測試通過。經測試,若直接將驅動使用Linux 2.6.12.7內核編譯,將出現大量錯誤。如何將驅動移植到Linux 2.6.12.7還需要進一步研究。
  • 「正點原子Linux連載」第七十章Linux WIFI驅動實驗
    ,命令如下:cp arch/arm/boot/zImage /home/zuozhongkai/linux/tftpboot/ -f然後重啟開發板!!!進入到iwlist_for_visteon-master文件夾裡面,打開Makefile文件,修改Makefile中的CC、AR和RANLIB這三個變量,修改後的值如圖70.2.1.1所示:圖70.2.1.1修改後的CC、AR和RANLIB值圖70.2.1.1中CC、AR和RANLIB這三個變量為所使用的編譯器工具,將其改為我們所使用的
  • PWM在ARM Linux中的原理和蜂鳴器驅動實例開發
    三、蜂鳴器驅動實例1. 蜂鳴器的種類和工作原理 蜂鳴器主要分為壓電式蜂鳴器和電磁式蜂鳴器兩種類型。 壓電式蜂鳴器主要由多諧振蕩器、壓電蜂鳴片、阻抗匹配器及共鳴箱、外殼等組成。有的壓電式蜂鳴器外殼上還裝有發光二極體。多諧振蕩器由電晶體或集成電路構成。
  • Linux USB總線驅動框架分析
    首先來看一個現象,插入USB設備後linux系統列印如下日誌:1.2 USB接入識別大致過程當識別出有USB設備插入後,linux內的USB總線驅動程序發出命令至該設備,與設備對話,並詢問設備信息(描述符),設備收到請求後,回復設備描述符給總線驅動程序。且總線驅動程序會為該設備分配一個地址,如上地址為2,當後期訪問某個USB設備時,均會通過這個地址編號,當新接入的USB設備被第一次訪問時,以地址0來訪問。
  • ARM-Linux驅動--DM9000網卡驅動分析(四)
    硬體平臺:FL2440 (S3C2440)內核版本:2.6.35主機平臺:Ubuntu 11.04內核版本:2.6.39交叉編譯器:arm-linux-gcc 4.3.2原創作品,轉載請標明出處本文接上文ARM-Linux
  • Linux SD/MMC/SDIO驅動分析
    MMC核心層由三個部分組成:MMC,SD和SDIO,分別為三類設備驅動提供接口函數;  Host 驅動層:針對不同主機端的SDHC、MMC控制器的驅動;  Client 驅動層:針對不同客戶端的設備驅動程序。如SD卡、T-flash卡、SDIO接口的GPS和wi-fi等設備驅動。
  • WiFi驅動程序調試過程
    經過漫長的代碼閱讀及分析,發現LTIB軟體包中自帶的ath9k驅動程序目錄下的hw.h中不存在0033這樣的devid,而AR9382的devid 0030則存在其中,如下圖。 那麼問題應該就出在這裡,LTIB軟體包中自帶的ath9k驅動程序版本過低,無法識別較新的WiFi晶片。 6. Google一下,發現compat-wireless是普遍使用的WiFi驅動程序。compat-wireless是一個Linux的無線驅動兼容性解決方案,提供Linux內核2.6.25及以上版本的最新無線驅動支持的改進。