在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            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://www.biyoush.com/article/201611/319013.htm

            1、mtd_notifier結(jié)構(gòu)體

            1. //MTD設(shè)備通知結(jié)構(gòu)體
            2. structmtd_notifier{
            3. void(*add)(structmtd_info*mtd);//加入MTD原始/字符/塊設(shè)備時執(zhí)行
            4. void(*remove)(structmtd_info*mtd);//移除MTD原始/字符/塊設(shè)備時執(zhí)行
            5. structlist_headlist;//list是雙向鏈表,定義在include/linux/list.h
            6. };
            而struct list_head定義在/include/linux/list.h中,內(nèi)核中其宏定義和函數(shù)如下

            INIT_LIST_HEAD(ptr) 初始化ptr節(jié)點為表頭,將前趨與后繼都指向自己。
            LIST_HEAD(name) 聲明并初始化雙向循環(huán)鏈表name。

            static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
            向鏈表中在prev與next之間插入元素new
            static inline void list_add(struct list_head *new, struct list_head *head)
            在鏈表中頭節(jié)點后插入元素new,調(diào)用__list_add()實現(xiàn)。
            static inline void list_add_tail(struct list_head *new, struct list_head *head)
            在鏈表末尾插入元素new,調(diào)用__list_add()實現(xiàn)。

            static inline void __list_del(struct list_head * prev, struct list_head * next)
            刪除鏈表中prev與next之間的元素。
            static inline void list_del(struct list_head *entry)
            刪除鏈表中的元素entry。

            static inline void list_del_init(struct list_head *entry)
            從鏈表中刪除元素entry,并將其初始化為新的鏈表。
            static inline void list_move(struct list_head *list, struct list_head *head)
            從鏈表中刪除list元素,并將其加入head鏈表。
            static inline void list_move_tail(struct list_head *list, struct list_head *head)
            把list移動到鏈表末尾。

            static inline int list_empty(const struct list_head *head)
            測試鏈表是否為空。

            static inline void __list_splice(struct list_head *list, struct list_head *head)
            將鏈表list與head合并。
            static inline void list_splice(struct list_head *list, struct list_head *head)
            在list不為空的情況下,調(diào)用__list_splice()實現(xiàn)list與head的合并。
            static inline void list_splice_init(struct list_head *list, struct list_head *head)
            將兩鏈表合并,并將list初始化。

            list_entry(ptr, type, member)
            list_entry的定義是怎么回事?
            a. list_entry的定義在內(nèi)核源文件include/linux/list.h中:
            #define list_entry(ptr, type, member)
            ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
            b. 其功能是根據(jù)list_head型指針ptr換算成其宿主結(jié)構(gòu)的起始地址,該宿主結(jié)構(gòu)是type型的,而ptr在其宿主結(jié)構(gòu)中定義為member成員。

            2、add_mtd_device函數(shù)

            1. /**
            2. *add_mtd_device-registeranMTDdevice
            3. *@mtd:pointertonewMTDdeviceinfostructure
            4. *
            5. *AddadevicetothelistofMTDdevicespresentinthesystem,and
            6. *notifyeachcurrentlyactiveMTDuserofitsarrival.Returns
            7. *zeroonsuccessor1onfailure,whichcurrentlywillonlyhappen
            8. *ifthereisinsufficientmemoryorasysfserror.
            9. */
            10. //添加MTD設(shè)備函數(shù),將MTD設(shè)備加入MTD設(shè)備鏈表,并通知所有的MTDuser該MTD設(shè)備。返回0表示成功,返回1表示出錯(內(nèi)存不足或文件系統(tǒng)錯誤)
            11. intadd_mtd_device(structmtd_info*mtd)
            12. {
            13. structmtd_notifier*not;//定義一個MTD設(shè)備通知器
            14. inti,error;
            15. //下面是設(shè)置mtd_info結(jié)構(gòu)體信息
            16. if(!mtd->backing_dev_info){
            17. switch(mtd->type){
            18. caseMTD_RAM://MTD_RAM定義在include/mtd/mtd-abi.h
            19. mtd->backing_dev_info=&mtd_bdi_rw_mappable;
            20. break;
            21. caseMTD_ROM:
            22. mtd->backing_dev_info=&mtd_bdi_ro_mappable;
            23. break;
            24. default:
            25. mtd->backing_dev_info=&mtd_bdi_unmappable;
            26. break;
            27. }
            28. }
            29. BUG_ON(mtd->writesize==0);
            30. mutex_lock(&mtd_table_mutex);//給操作mtd_table加鎖
            31. do{
            32. if(!idr_pre_get(&mtd_idr,GFP_KERNEL))//為mtd_idr分配內(nèi)存
            33. gotofail_locked;
            34. error=idr_get_new(&mtd_idr,mtd,&i);//將id號和mtd_idr關(guān)聯(lián)
            35. }while(error==-EAGAIN);
            36. if(error)
            37. gotofail_locked;
            38. mtd->index=i;
            39. mtd->usecount=0;
            40. if(is_power_of_2(mtd->erasesize))
            41. mtd->erasesize_shift=ffs(mtd->erasesize)-1;
            42. else
            43. mtd->erasesize_shift=0;
            44. if(is_power_of_2(mtd->writesize))
            45. mtd->writesize_shift=ffs(mtd->writesize)-1;
            46. else
            47. mtd->writesize_shift=0;
            48. mtd->erasesize_mask=(1<erasesize_shift)-1;
            49. mtd->writesize_mask=(1<writesize_shift)-1;
            50. /*Somechipsalwayspoweruplocked.Unlockthemnow*/
            51. if((mtd->flags&MTD_WRITEABLE)
            52. &&(mtd->flags&MTD_POWERUP_LOCK)&&mtd->unlock){
            53. if(mtd->unlock(mtd,0,mtd->size))
            54. printk(KERN_WARNING
            55. "%s:unlockfailed,writesmaynotworkn",
            56. mtd->name);
            57. }
            58. /*Callershouldhavesetdev.parenttomatchthe
            59. *physicaldevice.
            60. */
            61. mtd->dev.type=&mtd_devtype;
            62. mtd->dev.class=&mtd_class;
            63. mtd->dev.devt=MTD_DEVT(i);
            64. //設(shè)置mtd設(shè)備名
            65. dev_set_name(&mtd->dev,"mtd%d",i);
            66. //設(shè)置mtd設(shè)備信息mtd_info
            67. dev_set_drvdata(&mtd->dev,mtd);
            68. //注冊設(shè)備
            69. if(device_register(&mtd->dev)!=0)
            70. gotofail_added;
            71. //創(chuàng)建設(shè)備
            72. if(MTD_DEVT(i))
            73. device_create(&mtd_class,mtd->dev.parent,
            74. MTD_DEVT(i)+1,
            75. NULL,"mtd%dro",i);
            76. DEBUG(0,"mtd:Givingoutdevice%dto%sn",i,mtd->name);
            77. /*Noneedtogetarefcountonthemodulecontaining
            78. thenotifier,sinceweholdthemtd_table_mutex*/
            79. //遍歷list鏈表將每個mtd_notifier執(zhí)行add()函數(shù),對新加入的mtd設(shè)備操作,通知所有的MTDuser新的MTD設(shè)備的到來
            80. list_for_each_entry(not,&mtd_notifiers,list)
            81. not->add(mtd);
            82. //解鎖信號量
            83. mutex_unlock(&mtd_table_mutex);
            84. /*We_know_wearentbeingremoved,because
            85. ourcallerisstillholdingushere.Sonone
            86. ofthistry_nonsense,andnobitchingaboutit
            87. either.:)*/
            88. __module_get(THIS_MODULE);
            89. return0;
            90. fail_added:
            91. idr_remove(&mtd_idr,i);
            92. fail_locked:
            93. mutex_unlock(&mtd_table_mutex);
            94. return1;
            95. }

            其中用到的IDR機制如下:

            (1)獲得idr
            要在代碼中使用idr,首先要包括。接下來,我們要在代碼中分配idr結(jié)構(gòu)體,并初始化:
            void idr_init(struct idr *idp);
            其中idr定義如下:
            struct idr {
            struct idr_layer *top;
            struct idr_layer *id_free;
            int layers;
            int id_free_cnt;
            spinlock_t lock;
            };
            /* idr是idr機制的核心結(jié)構(gòu)體 */
            (2)為idr分配內(nèi)存
            int idr_pre_get(struct idr *idp, unsigned int gfp_mask);
            每次通過idr獲得ID號之前,需要先分配內(nèi)存。
            返回0表示錯誤,非零值代表正常
            (3)分配ID號并將ID號和指針關(guān)聯(lián)
            int idr_get_new(struct idr *idp, void *ptr, int *id);
            int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);
            idp: 之前通過idr_init初始化的idr指針
            id: 由內(nèi)核自動分配的ID號
            ptr: 和ID號相關(guān)聯(lián)的指針
            start_id: 起始ID號。內(nèi)核在分配ID號時,會從start_id開始。如果為I2C節(jié)點分配ID號,可以將設(shè)備地址作為start_id
            函數(shù)調(diào)用正常返回0,如果沒有ID可以分配,則返回-ENOSPC
            在實際中,上述函數(shù)常常采用如下方式使用:
            again:
            if (idr_pre_get(&my_idr, GFP_KERNEL) == 0) {
            /* No memory, give up entirely */
            }
            spin_lock(&my_lock);
            result = idr_get_new(&my_idr, &target, &id);
            if (result == -EAGAIN) {
            sigh();
            spin_unlock(&my_lock);
            goto again;
            }
            (4)通過ID號搜索對應(yīng)的指針
            void *idr_find(struct idr *idp, int id);
            返回值是和給定id相關(guān)聯(lián)的指針,如果沒有,則返回NULL
            (5)刪除ID
            要刪除一個ID,使用:
            void idr_remove(struct idr *idp, int id);
            通過上面這些方法,內(nèi)核代碼可以為子設(shè)備,inode生成對應(yīng)的ID號。這些函數(shù)都定義在lib/idr.c中

            3、del_mtd_device函數(shù)

            1. /**
            2. *del_mtd_device-unregisteranMTDdevice
            3. *@mtd:pointertoMTDdeviceinfostructure
            4. *
            5. *RemoveadevicefromthelistofMTDdevicespresentinthesystem,
            6. *andnotifyeachcurrentlyactiveMTDuserofitsdeparture.
            7. *Returnszeroonsuccessor1onfailure,whichcurrentlywillhappen
            8. *iftherequesteddevicedoesnotappeartobepresentinthelist.
            9. */
            10. //刪除mtd設(shè)備函數(shù)。
            11. //從MTD設(shè)備的鏈表中移除該MTD設(shè)備信息,并通知系統(tǒng)中所有的MTDuser該MTD設(shè)備的移除。
            12. //返回0表示成功,返回1表示出錯(該設(shè)備信息不存在設(shè)備鏈表中)
            13. intdel_mtd_device(structmtd_info*mtd)
            14. {
            15. intret;
            16. structmtd_notifier*not;//定義一個mtd_notifier指針
            17. mutex_lock(&mtd_table_mutex);
            18. if(idr_find(&mtd_idr,mtd->index)!=mtd){
            19. ret=-ENODEV;
            20. gotoout_error;
            21. }
            22. /*Noneedtogetarefcountonthemodulecontaining
            23. thenotifier,sinceweholdthemtd_table_mutex*/
            24. //遍歷list鏈表,并使每個mtd_notifier執(zhí)行remove函數(shù),通知每個MTDuser該設(shè)備的移除
            25. list_for_each_entry(not,&mtd_notifiers,list)
            26. not->remove(mtd);
            27. if(mtd->usecount){
            28. printk(KERN_NOTICE"RemovingMTDdevice#%d(%s)withusecount%dn",
            29. mtd->index,mtd->name,mtd->usecount);
            30. ret=-EBUSY;
            31. }else{
            32. device_unregister(&mtd->dev);//移除MTD設(shè)備
            33. idr_remove(&mtd_idr,mtd->index);//移除mtd的id號并釋放已分配的內(nèi)存
            34. module_put(THIS_MODULE);
            35. ret=0;
            36. }
            37. out_error:
            38. mutex_unlock(&mtd_table_mutex);
            39. returnret;
            40. }

            4、register_mtd_user函數(shù)

            1. /**
            2. *register_mtd_user-registerauserofMTDdevices.
            3. *@new:pointertonotifierinfostructure
            4. *
            5. *Registersapairofcallbacksfunctiontobecalleduponaddition
            6. *orremovalofMTDdevices.Causestheaddcallbacktobeimmediately
            7. *invokedforeachMTDdevicecurrentlypresentinthesystem.
            8. */
            9. //MTD原始設(shè)備使用者注冊MTD設(shè)備(具體的字符設(shè)備或塊設(shè)備)
            10. //參數(shù)是新的mtd通知器,將其加入mtd_notifiers隊列,然后
            11. voidregister_mtd_user(structmtd_notifier*new)
            12. {
            13. structmtd_info*mtd;
            14. mutex_lock(&mtd_table_mutex);
            15. //將new->list頭插mtd_notifiers入鏈表
            16. list_add(&new->list,&mtd_notifiers);
            17. __module_get(THIS_MODULE);
            18. //對每個MTD原始設(shè)備執(zhí)行add函數(shù)
            19. mtd_for_each_device(mtd)
            20. new->add(mtd);
            21. mutex_unlock(&mtd_table_mutex);
            22. }

            5、unregister_mtd_user函數(shù)

            1. /**
            2. *unregister_mtd_user-unregisterauserofMTDdevices.
            3. *@old:pointertonotifierinfostructure
            4. *
            5. *Removesacallbackfunctionpairfromthelistofuserstobe
            6. *notifieduponadditionorremovalofMTDdevices.Causesthe
            7. *removecallbacktobeimmediatelyinvokedforeachMTDdevice
            8. *currentlypresentinthesystem.
            9. */
            10. //刪除MTD設(shè)備。
            11. //通知所有該MTD原始設(shè)備的MTD設(shè)備執(zhí)行remove()函數(shù),將被刪除的MTD設(shè)備的通知器從mtd_notifier隊列中刪除
            12. intunregister_mtd_user(structmtd_notifier*old)
            13. {
            14. structmtd_info*mtd;
            15. mutex_lock(&mtd_table_mutex);
            16. module_put(THIS_MODULE);
            17. //通知所有該MTD原始設(shè)備的MTD設(shè)備執(zhí)行remove()函數(shù)
            18. mtd_for_each_device(mtd)
            19. old->remove(mtd);
            20. //將被刪除的MTD設(shè)備的通知器從mtd_notifier隊列中刪除
            21. list_del(&old->list);
            22. mutex_unlock(&mtd_table_mutex);
            23. return0;
            24. }

            6、獲取MTD設(shè)備的操作指針,只是參數(shù)不同,一個是按照設(shè)備地址,另一個是安裝設(shè)備的名稱來獲取MTD設(shè)備的操作地址

            struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)

            struct mtd_info *get_mtd_device_nm(const char *name)

            下面現(xiàn)分析第一個函數(shù)

            1. /**
            2. *get_mtd_device-obtainavalidatedhandleforanMTDdevice
            3. *@mtd:lastknownaddressoftherequiredMTDdevice
            4. *@num:internaldevicenumberoftherequiredMTDdevice
            5. *
            6. *GivenanumberandNULLaddress,returnthenumthentryinthedevice
            7. *table,ifany.Givenanaddressandnum==-1,searchthedevicetable
            8. *foradevicewiththataddressandreturnifitsstillpresent.Given
            9. *both,returnthenumthdriveronlyifitsaddressmatches.Return
            10. *errorcodeifnot.
            11. */
            12. //根據(jù)設(shè)備地址來獲取MTD設(shè)備的操作地址
            13. structmtd_info*get_mtd_device(structmtd_info*mtd,intnum)
            14. {
            15. structmtd_info*ret=NULL,*other;
            16. interr=-ENODEV;
            17. //給mtd_table加鎖,以便互斥訪問
            18. mutex_lock(&mtd_table_mutex);
            19. if(num==-1){//num=-1&&鏈表不空,則返回mtd的地址
            20. mtd_for_each_device(other){
            21. if(other==mtd){
            22. ret=mtd;
            23. break;
            24. }
            25. }
            26. }elseif(num>=0){//num>=0,查找第num個設(shè)備,若不空,返回地址,若為空,返回NULL
            27. ret=idr_find(&mtd_idr,num);
            28. if(mtd&&mtd!=ret)
            29. ret=NULL;
            30. }
            31. if(!ret){
            32. ret=ERR_PTR(err);
            33. gotoout;
            34. }
            35. err=__get_mtd_device(ret);
            36. //錯誤處理
            37. if(err)
            38. ret=ERR_PTR(err);
            39. out:
            40. mutex_unlock(&mtd_table_mutex);//解鎖互斥信號量
            41. returnret;
            42. }
            43. int__get_mtd_device(structmtd_info*mtd)
            44. {
            45. interr;
            46. if(!try_module_get(mtd->owner))
            47. return-ENODEV;
            48. if(mtd->get_device){
            49. err=mtd->get_device(mtd);
            50. if(err){
            51. module_put(mtd->owner);
            52. returnerr;
            53. }
            54. }
            55. mtd->usecount++;//增加該MTD原始設(shè)備的使用者計數(shù)器
            56. return0;
            57. }

            第二個函數(shù)
            1. /**
            2. *get_mtd_device_nm-obtainavalidatedhandleforanMTDdeviceby
            3. *devicename
            4. *@name:MTDdevicenametoopen
            5. *
            6. *ThisfunctionreturnsMTDdevicedescriptionstructureincaseof
            7. *successandanerrorcodeincaseoffailure.
            8. */
            9. //通過設(shè)備名來獲得相應(yīng)的MTD原始設(shè)備的操作地址
            10. //該函數(shù)和上面的函數(shù)類似,不過就是通過循環(huán)比較MTD設(shè)備的name字段來返回
            11. structmtd_info*get_mtd_device_nm(constchar*name)
            12. {
            13. interr=-ENODEV;
            14. structmtd_info*mtd=NULL,*other;
            15. mutex_lock(&mtd_table_mutex);
            16. mtd_for_each_device(other){
            17. if(!strcmp(name,other->name)){
            18. mtd=other;
            19. break;
            20. }
            21. }
            22. if(!mtd)
            23. gotoout_unlock;
            24. if(!try_module_get(mtd->owner))
            25. gotoout_unlock;
            26. if(mtd->get_device){
            27. err=mtd->get_device(mtd);
            28. if(err)
            29. gotoout_put;
            30. }
            31. mtd->usecount++;
            32. mutex_unlock(&mtd_table_mutex);
            33. returnmtd;
            34. out_put:
            35. module_put(mtd->owner);
            36. out_unlock:
            37. mutex_unlock(&mtd_table_mutex);
            38. returnERR_PTR(err);
            39. }



            評論


            相關(guān)推薦

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

            關(guān)閉