Linux內(nèi)核的Nand驅(qū)動(dòng)流程分析
我認(rèn)為L(zhǎng)inux內(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)程序來(lái)間接控制硬件的,而其他的高級(jí)功能如內(nèi)存管理,進(jìn)程管理等是通用的,無(wú)需做其他配置,所以我們只需要配置相關(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://cafeforensic.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)中的信息來(lái)識(shí)別設(shè)備;另一種是驅(qū)動(dòng)程序本身沒有設(shè)備信息,但是內(nèi)核中已經(jīng)根據(jù)其他方式確定了很多設(shè)備信息,加載驅(qū)動(dòng)時(shí)將驅(qū)動(dòng)程序與這些設(shè)備逐個(gè)比較,確定兩者是否匹配,如果匹配就可以使用該驅(qū)動(dòng)來(lái)識(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,用來(lái)描述設(shè)備信息,一個(gè)是platform_driver,用來(lái)描述驅(qū)動(dòng)信息,內(nèi)核啟動(dòng)后首先構(gòu)造鏈表將plartfrom_device結(jié)構(gòu)組織起來(lái)得到一個(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):
- staticstructplatform_device*mini2440_devices[]__initdata={
- &s3c_device_ohci,
- &s3c_device_wdt,
- &s3c_device_i2c0,
- &s3c_device_rtc,
- &s3c_device_usbgadget,
- &mini2440_device_eth,
- &mini2440_led1,
- &mini2440_led2,
- &mini2440_led3,
- &mini2440_led4,
- &mini2440_button_device,
- &s3c_device_nand,
- &s3c_device_sdi,
- &s3c_device_iis,
- &uda1340_codec,
- &mini2440_audio,
- &samsung_asoc_dma,
- };
- platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));
- staticstructresources3c_nand_resource[]={
- [0]=DEFINE_RES_MEM(S3C_PA_NAND,SZ_1M),
- };
- structplatform_devices3c_device_nand={
- .name="s3c2410-nand",
- .id=-1,
- .num_resources=ARRAY_SIZE(s3c_nand_resource),
- .resource=s3c_nand_resource,
- };
- structresource{
- resource_size_tstart;
- resource_size_tend;
- constchar*name;
- unsignedlongflags;
- structresource*parent,*sibling,*child;
- };
- #defineDEFINE_RES_NAMED(_start,_size,_name,_flags)
- {
- .start=(_start),
- .end=(_start)+(_size)-1,
- .name=(_name),
- .flags=(_flags),
- }
- #defineDEFINE_RES_MEM_NAMED(_start,_size,_name)
- DEFINE_RES_NAMED((_start),(_size),(_name),IORESOURCE_MEM)
- #defineDEFINE_RES_MEM(_start,_size)
- DEFINE_RES_MEM_NAMED((_start),(_size),NULL)
- {
- .start=(S3C_PA_NAND),
- .end=(S3C_PA_NAND)+(SZ_1M)-1,
- .name=(NULL),
- .flags=(IORESOURCE_MEM),
- }
- #defineS3C2410_PA_NAND(0x4E000000)
- #defineS3C24XX_PA_NANDS3C2410_PA_NAND
- #defineS3C_PA_NANDS3C24XX_PA_NAND
也就是說,S3C_PA_NAND是Nand flash寄存器首地址,而SZ_1M明顯是個(gè)長(zhǎng)度,因此,這里的resource實(shí)際上是Nand flash寄存器首地址跟接下來(lái)的1M空間,可是,Nand的寄存器并沒有那么多,這又是為什么呢?這些信息有什么用又在哪里用到了呢?答案很簡(jiǎn)單,這肯定是給驅(qū)動(dòng)程序使用的了,帶著這個(gè)疑問我們繼續(xù)分析代碼。定位到/drivers/mtd/nand/s3c2410.c,瀏覽代碼可以看到驅(qū)動(dòng)結(jié)構(gòu)定義
- staticstructplatform_drivers3c24xx_nand_driver={
- .probe=s3c24xx_nand_probe,
- .remove=s3c24xx_nand_remove,
- .suspend=s3c24xx_nand_suspend,
- .resume=s3c24xx_nand_resume,
- .id_table=s3c24xx_driver_ids,
- .driver={
- .name="s3c24xx-nand",
- .owner=THIS_MODULE,
- },
- };
- staticint__inits3c2410_nand_init(void)
- {
- printk("S3C24XXNANDDriver,(c)2004SimtecElectronics");
- returnplatform_driver_register(&s3c24xx_nand_driver);
- }
- staticvoid__exits3c2410_nand_exit(void)
- {
- platform_driver_unregister(&s3c24xx_nand_driver);
- }
- module_init(s3c2410_nand_init);
- module_exit(s3c2410_nand_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("BenDooks
"); - MODULE_DESCRIPTION("S3C24XXMTDNANDdriver");
評(píng)論