Linux内核的Nand驱动流程分析
我认为Linux内核移植的初期阶段应该将重点放在分析内核设备驱动上。实际上,Linux内核的移植就是设备驱动的移植,内核本身不会直接访问硬件,是通过驱动程序来间接控制硬件的,而其他的高级功能如内存管理,进程管理等是通用的,无需做其他配置,所以我们只需要配置相关的驱动即可实现Linux内核移植。驱动移植的关键在于了解在驱动的结构,本文将以Nand驱动为例,分析Linux内核的驱动结构。
本文引用地址:https://www.eepw.com.cn/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");
评论