Linux內(nèi)核的Nand驅(qū)動流程分析
我認為Linux內(nèi)核移植的初期階段應(yīng)該將重點放在分析內(nèi)核設(shè)備驅(qū)動上。實際上,Linux內(nèi)核的移植就是設(shè)備驅(qū)動的移植,內(nèi)核本身不會直接訪問硬件,是通過驅(qū)動程序來間接控制硬件的,而其他的高級功能如內(nèi)存管理,進程管理等是通用的,無需做其他配置,所以我們只需要配置相關(guān)的驅(qū)動即可實現(xiàn)Linux內(nèi)核移植。驅(qū)動移植的關(guān)鍵在于了解在驅(qū)動的結(jié)構(gòu),本文將以Nand驅(qū)動為例,分析Linux內(nèi)核的驅(qū)動結(jié)構(gòu)。
本文引用地址:http://m.butianyuan.cn/article/201611/322799.htm在分析驅(qū)動結(jié)構(gòu)之前,還需要了解下內(nèi)核識別設(shè)備的方式,內(nèi)核通過驅(qū)動程序識別設(shè)備的方法有兩種,一種是驅(qū)動程序本身帶有設(shè)備信息,比如開始地址、中斷號等,加載驅(qū)動時就可以根據(jù)驅(qū)動中的信息來識別設(shè)備;另一種是驅(qū)動程序本身沒有設(shè)備信息,但是內(nèi)核中已經(jīng)根據(jù)其他方式確定了很多設(shè)備信息,加載驅(qū)動時將驅(qū)動程序與這些設(shè)備逐個比較,確定兩者是否匹配,如果匹配就可以使用該驅(qū)動來識別設(shè)備了。內(nèi)核常采用的是第二種方式,這樣方式可將各種設(shè)備集中在一個文件中管理,當開發(fā)板的配置改變時便于修改代碼。對應(yīng)的,內(nèi)核文件include/linux/platform_device.h中定義了兩個結(jié)構(gòu),一個是platform_device,用來描述設(shè)備信息,一個是platform_driver,用來描述驅(qū)動信息,內(nèi)核啟動后首先構(gòu)造鏈表將plartfrom_device結(jié)構(gòu)組織起來得到一個設(shè)備鏈表,當加載某個驅(qū)動時根據(jù)platform_driver提供的信息與設(shè)備鏈表一一進行匹配,這就是內(nèi)核設(shè)備識別的大體過程,具體的過程比這復(fù)雜很多,這里不做過多研究。下面我們開始分析Linux內(nèi)核的Nand驅(qū)動。
這里以Linux內(nèi)核的3.5.3中默認的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明顯是個長度,因此,這里的resource實際上是Nand flash寄存器首地址跟接下來的1M空間,可是,Nand的寄存器并沒有那么多,這又是為什么呢?這些信息有什么用又在哪里用到了呢?答案很簡單,這肯定是給驅(qū)動程序使用的了,帶著這個疑問我們繼續(xù)分析代碼。定位到/drivers/mtd/nand/s3c2410.c,瀏覽代碼可以看到驅(qū)動結(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");
評論