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