[ARM筆記]驅動對設備的識別過程及實例——NAND Flash
驅動程序識別設備時,有以下兩種方法:
(1)驅動程序本身帶有設備信息,比如開始地址、中斷號等;加載驅動程序時,就可以根據這些信息來識別設備。
(2)驅動程序本身沒有設備信息,但是內核中已經(或以后)根據其他方式確定了很多設備的信息;加載驅動程序時,將驅動程序與這些設備逐個比較,確定兩者是否匹配(math)。如果驅動程序與某個設備匹配,就可以通過該驅動程序來操作這個設備了。
內核常使用第二種方法來識別設備,這可以將各種設備集中在一個文件中管理,當開發(fā)板的配置改變時,便于修改代碼。在內核文件include/linux/platform_device.h中,定義了兩個數據結構來表示這些設備和驅動程序:platform_device結構用來描述設備的名稱、ID、所占用的資源(比如內存地址/大小、中斷號)等;platform_driver結構用來描述各種操作函數,比如枚舉函數、移除設備函數、驅動名稱等。
內核啟動后,首先構造鏈表將描述設備的platform_device結構組織起來,得到一個設備的列表;當加載某個驅動程序的platform_driver結構時,使用一些匹配函數來檢查驅動程序能否支持這些設備,常用的檢查方法很簡單:比較驅動程序和設備的名稱。
以S3C2410開發(fā)板為例,在include/arch/arm/mach-s3c2410/mach-smdk2410.c中定義了如下設備:
89 static struct platform_device *smdk2410_devices[] __initdata = {
90&s3c_device_usb,
91&s3c_device_lcd,
92&s3c_device_wdt,
93&s3c_device_i2c,
94&s3c_device_iis,
95 };
104 static void __init smdk2410_init(void)
105 {
106platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
107smdk_machine_init();
108 }
在include/arch/arm/plat-s3c24xx/common-smdk.c中定義了如下設備:
175 static struct platform_device __initdata *smdk_devs[] = {
176&s3c_device_nand,
177&smdk_led4,
178&smdk_led5,
179&smdk_led6,
180&smdk_led7,
181 };
183 void __initsmdk_machine_init(void)
184 {
185/* Configure the LEDs (even if we have no LED support)*/
186
187s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
188s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
189s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
190s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
191
192s3c2410_gpio_setpin(S3C2410_GPF4, 1);
193s3c2410_gpio_setpin(S3C2410_GPF5, 1);
194s3c2410_gpio_setpin(S3C2410_GPF6, 1);
195s3c2410_gpio_setpin(S3C2410_GPF7, 1);
196
197if (machine_is_smdk2443())
198smdk_nand_info.twrph0 = 50;
199
200s3c_device_nand.dev.platform_data = &smdk_nand_info;
201
202platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
203
204s3c2410_pm_init();
205 }
627 int __init s3c2410_pm_init(void)
628 {
629printk("S3C2410 Power Management, (c) 2004 Simtec Electronicsn");
630
631suspend_set_ops(&s3c2410_pm_ops);
632return 0;
633 }
這些設備在smdk2410_init函數(對應S3C2410)或smdk2440_machine_init函數(對應S3C2440)中,通過plat_add_devices函數注冊進內核中。
NAND Flash設備s3c2410_device_nand在include/arch/arm/plat-s3c24xx/devs.c中的定義如下:
201 struct platform_devices3c_device_nand= {
202.name= "s3c2410-nand",
203.id= -1,
204.num_resources= ARRAY_SIZE(s3c_nand_resource),
205.resource= s3c_nand_resource,
206 };
207
208 EXPORT_SYMBOL(s3c_device_nand); /*導出符號,以便外部文件引用*/
對于S3C2440開發(fā)板,s3c_device_nand結構的名字會在s3c244x_map_io函數中修改為“s3c2440-nand”,這個函數在include/arch/arm/plat-s3c24xx/s3c244x.c中定義如下:
59 void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
...
68s3c_device_i2c.name= "s3c2440-i2c";
69s3c_device_nand.name = "s3c2440-nand";
70s3c_device_usbgadget.name = "s3c2440-usbgadget";
71 }
有了NAND Flash設備,還要有NAND Flash驅動程序,內核針對S3C2410、S3C2412、S3C2440定義了3個驅動。它們在include/drivers/mtd/nand/s3c2410.c中的s3c2410_nand_init函數中注冊進內核,如下所示:
890 static int __init s3c2410_nand_init(void)
891 {
892printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronicsn");
893
894platform_driver_register(&s3c2412_nand_driver);
895platform_driver_register(&s3c2440_nand_driver);
896return platform_driver_register(&s3c2410_nand_driver);
897 }
其中的S3C2410_nand_driver結構是在include/drivers/mtd/nand/s3c2410.c中定義,如下所示:
857 static struct platform_drivers3c2410_nand_driver= {
858.probe= s3c2410_nand_probe,
859.remove= s3c2410_nand_remove,
860.suspend= s3c24xx_nand_suspend,
861.resume= s3c24xx_nand_resume,
862.driver= {
863.name= "s3c2410-nand",
864.owner= THIS_MODULE,
865},
866 };
可見,s3c_device_nand結構和s3c2410_nand_driver結構中的name成員相同,都是“s3c2410-nand”。platform_driver_register函數就是根據這點確定它們是匹配的,所以調用s3c2410_nand_probe函數枚舉NAND Flash設備s3c2410_device_nand。