<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux內(nèi)核的Nand驅(qū)動(dòng)流程分析

          Linux內(nèi)核的Nand驅(qū)動(dòng)流程分析

          作者: 時(shí)間:2016-11-28 來源:網(wǎng)絡(luò) 收藏
          最近在做Linux內(nèi)核移植,總體的感覺是這樣的,想要徹底的閱讀Linux內(nèi)核代碼幾乎是不可能的,至少這還不是嵌入式學(xué)期初期的重要任務(wù)。內(nèi)核代碼解壓后有250M左右,據(jù)統(tǒng)計(jì),有400多萬行,而且涉及到了軟件和硬件兩方面的諸多知識(shí),憑一人之力在短時(shí)間內(nèi)閱讀Linux內(nèi)核代碼是根本不可能的,強(qiáng)行閱讀可能會(huì)打消我們嵌入式學(xué)習(xí)的積極性,最后甚至可能放棄嵌入式學(xué)習(xí),如果真的想閱讀內(nèi)核代碼來提高自己水平的話可以等熟練掌握嵌入式以后再回過頭來閱讀,這樣理解也會(huì)更深刻,更透徹。

          我認(rèn)為Linux內(nèi)核移植的初期階段應(yīng)該將重點(diǎn)放在分析內(nèi)核設(shè)備驅(qū)動(dòng)上。實(shí)際上,Linux內(nèi)核的移植就是設(shè)備驅(qū)動(dòng)的移植,內(nèi)核本身不會(huì)直接訪問硬件,是通過驅(qū)動(dòng)程序來間接控制硬件的,而其他的高級(jí)功能如內(nèi)存管理,進(jìn)程管理等是通用的,無需做其他配置,所以我們只需要配置相關(guān)的驅(qū)動(dòng)即可實(shí)現(xiàn)Linux內(nèi)核移植。驅(qū)動(dòng)移植的關(guān)鍵在于了解在驅(qū)動(dòng)的結(jié)構(gòu),本文將以Nand驅(qū)動(dòng)為例,分析Linux內(nèi)核的驅(qū)動(dòng)結(jié)構(gòu)。

          本文引用地址:http://www.ex-cimer.com/article/201611/322799.htm

          在分析驅(qū)動(dòng)結(jié)構(gòu)之前,還需要了解下內(nèi)核識(shí)別設(shè)備的方式,內(nèi)核通過驅(qū)動(dòng)程序識(shí)別設(shè)備的方法有兩種,一種是驅(qū)動(dòng)程序本身帶有設(shè)備信息,比如開始地址、中斷號(hào)等,加載驅(qū)動(dòng)時(shí)就可以根據(jù)驅(qū)動(dòng)中的信息來識(shí)別設(shè)備;另一種是驅(qū)動(dòng)程序本身沒有設(shè)備信息,但是內(nèi)核中已經(jīng)根據(jù)其他方式確定了很多設(shè)備信息,加載驅(qū)動(dòng)時(shí)將驅(qū)動(dòng)程序與這些設(shè)備逐個(gè)比較,確定兩者是否匹配,如果匹配就可以使用該驅(qū)動(dòng)來識(shí)別設(shè)備了。內(nèi)核常采用的是第二種方式,這樣方式可將各種設(shè)備集中在一個(gè)文件中管理,當(dāng)開發(fā)板的配置改變時(shí)便于修改代碼。對(duì)應(yīng)的,內(nèi)核文件include/linux/platform_device.h中定義了兩個(gè)結(jié)構(gòu),一個(gè)是platform_device,用來描述設(shè)備信息,一個(gè)是platform_driver,用來描述驅(qū)動(dòng)信息,內(nèi)核啟動(dòng)后首先構(gòu)造鏈表將plartfrom_device結(jié)構(gòu)組織起來得到一個(gè)設(shè)備鏈表,當(dāng)加載某個(gè)驅(qū)動(dòng)時(shí)根據(jù)platform_driver提供的信息與設(shè)備鏈表一一進(jìn)行匹配,這就是內(nèi)核設(shè)備識(shí)別的大體過程,具體的過程比這復(fù)雜很多,這里不做過多研究。下面我們開始分析Linux內(nèi)核的Nand驅(qū)動(dòng)。

          這里以Linux內(nèi)核的3.5.3中默認(rèn)的mini2440開發(fā)板為例,首先定位到arm/arm/mach-s3c24xx/mach-mini2440.c,然后找到如下結(jié)構(gòu):

          1. staticstructplatform_device*mini2440_devices[]__initdata={
          2. &s3c_device_ohci,
          3. &s3c_device_wdt,
          4. &s3c_device_i2c0,
          5. &s3c_device_rtc,
          6. &s3c_device_usbgadget,
          7. &mini2440_device_eth,
          8. &mini2440_led1,
          9. &mini2440_led2,
          10. &mini2440_led3,
          11. &mini2440_led4,
          12. &mini2440_button_device,
          13. &s3c_device_nand,
          14. &s3c_device_sdi,
          15. &s3c_device_iis,
          16. &uda1340_codec,
          17. &mini2440_audio,
          18. &samsung_asoc_dma,
          19. };
          顯然,這里就是內(nèi)核需要的設(shè)備列表,通過后面的mini2440_init函數(shù)中的
          1. platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));
          注冊(cè)到內(nèi)核,然后由內(nèi)核進(jìn)行管理,顯然,跟我們分析的Nand相關(guān)的就是s3c_device_nand,這就代表我們開發(fā)版上的Nand flash,我們先定位到它的定義,在arch/arm/plat-samsung/devs.c中有如下代碼
          1. staticstructresources3c_nand_resource[]={
          2. [0]=DEFINE_RES_MEM(S3C_PA_NAND,SZ_1M),
          3. };
          4. structplatform_devices3c_device_nand={
          5. .name="s3c2410-nand",
          6. .id=-1,
          7. .num_resources=ARRAY_SIZE(s3c_nand_resource),
          8. .resource=s3c_nand_resource,
          9. };
          第二個(gè) 結(jié)構(gòu)就是s3c_device_nand的定義,之所以帶上第一個(gè)結(jié)構(gòu)是因?yàn)槎xs3c_device_nand時(shí)用到了s3c_nand_resource,我們先看一下s3c_device_nand的定義,s3c_device_nand只明確定義了Nand設(shè)備的名稱和設(shè)備ID,并沒有給出具體的寄存器信息,加上s3c_nand_resource的名字帶有資源的意思,因此我們斷定,寄存器信息應(yīng)該在s3c_nand_resource中,從s3c_nand_resource的定義中我們只能看到很少的信息,要想了解具體信息需要看一下struct resource和宏DEFINE_RES_MEM的定義及
          1. structresource{
          2. resource_size_tstart;
          3. resource_size_tend;
          4. constchar*name;
          5. unsignedlongflags;
          6. structresource*parent,*sibling,*child;
          7. };
          這里 可以看到,struct resource中定義了起始,結(jié)束,名字等信息,我們?cè)賮砜匆幌翫EFINE_RES_MEM的定義
          1. #defineDEFINE_RES_NAMED(_start,_size,_name,_flags)
          2. {
          3. .start=(_start),
          4. .end=(_start)+(_size)-1,
          5. .name=(_name),
          6. .flags=(_flags),
          7. }
          8. #defineDEFINE_RES_MEM_NAMED(_start,_size,_name)
          9. DEFINE_RES_NAMED((_start),(_size),(_name),IORESOURCE_MEM)
          10. #defineDEFINE_RES_MEM(_start,_size)
          11. DEFINE_RES_MEM_NAMED((_start),(_size),NULL)
          我這里整合了一下上面的信息,將相關(guān)的宏都做了一下追蹤,因此,s3c_nand_resource的實(shí)際定義為
          1. {
          2. .start=(S3C_PA_NAND),
          3. .end=(S3C_PA_NAND)+(SZ_1M)-1,
          4. .name=(NULL),
          5. .flags=(IORESOURCE_MEM),
          6. }
          追蹤可知,S3C_PA_NAND定義如下
          1. #defineS3C2410_PA_NAND(0x4E000000)
          2. #defineS3C24XX_PA_NANDS3C2410_PA_NAND
          3. #defineS3C_PA_NANDS3C24XX_PA_NAND

          也就是說,S3C_PA_NAND是Nand flash寄存器首地址,而SZ_1M明顯是個(gè)長度,因此,這里的resource實(shí)際上是Nand flash寄存器首地址跟接下來的1M空間,可是,Nand的寄存器并沒有那么多,這又是為什么呢?這些信息有什么用又在哪里用到了呢?答案很簡單,這肯定是給驅(qū)動(dòng)程序使用的了,帶著這個(gè)疑問我們繼續(xù)分析代碼。定位到/drivers/mtd/nand/s3c2410.c,瀏覽代碼可以看到驅(qū)動(dòng)結(jié)構(gòu)定義

          1. staticstructplatform_drivers3c24xx_nand_driver={
          2. .probe=s3c24xx_nand_probe,
          3. .remove=s3c24xx_nand_remove,
          4. .suspend=s3c24xx_nand_suspend,
          5. .resume=s3c24xx_nand_resume,
          6. .id_table=s3c24xx_driver_ids,
          7. .driver={
          8. .name="s3c24xx-nand",
          9. .owner=THIS_MODULE,
          10. },
          11. };
          可以看到,這里指定了結(jié)構(gòu)中的各種操作的函數(shù)指針,從名字上可以看出probe是加載驅(qū)動(dòng)程序后執(zhí)行的第一個(gè)函數(shù),remove是移除驅(qū)動(dòng)前最后執(zhí)行的函數(shù),suspend是掛起操作,等等。先不著急分析這些函數(shù),先來看看內(nèi)核是如何加載驅(qū)動(dòng)的,s3c24xx_nand_driver又是如何注冊(cè)到內(nèi)核的。往下瀏覽代碼可以看到
          1. staticint__inits3c2410_nand_init(void)
          2. {
          3. printk("S3C24XXNANDDriver,(c)2004SimtecElectronics");
          4. returnplatform_driver_register(&s3c24xx_nand_driver);
          5. }
          6. staticvoid__exits3c2410_nand_exit(void)
          7. {
          8. platform_driver_unregister(&s3c24xx_nand_driver);
          9. }
          10. module_init(s3c2410_nand_init);
          11. module_exit(s3c2410_nand_exit);
          12. MODULE_LICENSE("GPL");
          13. MODULE_AUTHOR("BenDooks");
          14. MODULE_DESCRIPTION("S3C24XXMTDNANDdriver");
          顯然,加載該驅(qū)動(dòng)時(shí)s3c2410_nand_init函數(shù)將s3c24xx_nand_driver注冊(cè)到了內(nèi)核,卸載該驅(qū)動(dòng)時(shí)s3c2410_nand_exit將s3c24xx_nand_driver注銷,但是這兩個(gè)函數(shù)也不過是兩個(gè)普通函數(shù),內(nèi)核如何知道加載驅(qū)動(dòng)時(shí)運(yùn)行s3c2410_nand_init,卸載驅(qū)動(dòng)時(shí)運(yùn)行s3c2410_nand_exit呢?下面的module_init和module_exit解決了這個(gè)問題,它們分別告訴內(nèi)核驅(qū)動(dòng)程序的入口和出口。至于下面的MODULE_LICENSE指定了內(nèi)核的權(quán)限協(xié)議,這里指定內(nèi)核為GPL協(xié)議的,只有符合這個(gè)協(xié)議才能調(diào)用這個(gè)協(xié)議內(nèi)的函數(shù),因此是驅(qū)動(dòng)程序必須的部分,剩下的兩行是驅(qū)動(dòng)的作者和描述,無關(guān)緊要,可以沒有。現(xiàn)在我們明白了內(nèi)核如何加載驅(qū)動(dòng)了,我們?cè)偃シ治鰌robe函數(shù),往上瀏覽代碼可以找到

          上一頁 1 2 3 下一頁

          評(píng)論


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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();