Linux內(nèi)核的Nand驅(qū)動流程分析
- s3c_nand_set_platdata(&mini2440_nand_info);
- /*NANDFlashonMINI2440board*/
- staticstructmtd_partitionmini2440_default_nand_part[]__initdata={
- [0]={
- .name="u-boot",
- .size=SZ_256K,
- .offset=0,
- },
- [1]={
- .name="u-boot-env",
- .size=SZ_128K,
- .offset=SZ_256K,
- },
- [2]={
- .name="kernel",
- /*5megabytes,forakernelwithnomodules
- *orauImagewitharamdiskattached*/
- .size=0x00500000,
- .offset=SZ_256K+SZ_128K,
- },
- [3]={
- .name="root",
- .offset=SZ_256K+SZ_128K+0x00500000,
- .size=MTDPART_SIZ_FULL,
- },
- };
- staticstructs3c2410_nand_setmini2440_nand_sets[]__initdata={
- [0]={
- .name="nand",
- .nr_chips=1,
- .nr_partitions=ARRAY_SIZE(mini2440_default_nand_part),
- .partitions=mini2440_default_nand_part,
- .flash_bbt=1,/*weuseu-boottocreateaBBT*/
- },
- };
- staticstructs3c2410_platform_nandmini2440_nand_info__initdata={
- .tacls=0,
- .twrph0=25,
- .twrph1=15,
- .nr_sets=ARRAY_SIZE(mini2440_nand_sets),
- .sets=mini2440_nand_sets,
- .ignore_unset_ecc=1,
- };
(1)初始化了chip中的各種操作函數(shù)指針并賦值給了nmtd->mtd.priv。
(2)初始化了info的sel_*成員,顯然是Nand片選所用
(3)初始化了nmtd的幾個成員
nmtd,info,set是該函數(shù)的三個參數(shù),理解了這幾個參數(shù)也就理解了這個函數(shù)的作用。info顯然就是s3c24xx_nand_init中的s3c2410_nand_info,nmtd是info->mtds,而info->mtds是kzmalloc開辟的大小為size的內(nèi)核空間,kzmalloc是kernel zero malloc,也就是開辟了size大小的空間清全部設(shè)置為0,也就是nmtds就是空的mtd數(shù)組,sets來就前面我定義的mini2440_nand_sets,這樣三個參數(shù)都知道什么意思了,再去看代碼就很簡單了。(剛才去打了半小時電話,思路有點亂,不過大體上看了下,這個函數(shù)里面沒有復(fù)雜的操作,相信大家很容易看懂)。
執(zhí)行完s3c2410_nand_init之后就執(zhí)行了nand_scan_ident,這是內(nèi)核函數(shù)我就不做分析了,大家自己跟一下就可以知道,這個函數(shù)完成了nand_chip其他未指定函數(shù)指針的初始化,并獲取了Nand的ID信息等,接下來又s3c2410_nand_update_chip,nand_scan_tail,s3c2410_nand_add_partitions,其中nand_scan_tail是通用的內(nèi)核函數(shù),而s3c2410_nand_update_chip是ecc相關(guān)的操作,我們只分析s3c2410_nand_add_partitions,從名字上講,s3c2410開頭的函數(shù)肯定不是內(nèi)核通用函數(shù),也就是說,這實際上是我們需要自行完成的函數(shù),當(dāng)然,也是可以借鑒的函數(shù),追蹤進入s3c2410_nand_add_partitions,看看內(nèi)核是如何知道分區(qū)信息的。
- staticints3c2410_nand_add_partition(structs3c2410_nand_info*info,
- structs3c2410_nand_mtd*mtd,
- structs3c2410_nand_set*set)
- {
- if(set)
- mtd->mtd.name=set->name;
- returnmtd_device_parse_register(&mtd->mtd,NULL,NULL,
- set->partitions,set->nr_partitions);
- }
這個函數(shù)也很簡單,僅設(shè)置了下mtd的nand然后就調(diào)用和mtd_core.c中的mtd_device_parse_register函數(shù),從參數(shù)可以知道,該函數(shù)向內(nèi)核注冊了Nand分區(qū)信息。這樣我們就基本上看完了Linux內(nèi)核Nand驅(qū)動部分的結(jié)構(gòu)。
在結(jié)尾之前我還要提到一個問題,就是內(nèi)核驅(qū)動的匹配問題,在platform_device定義時內(nèi)核指定的名稱是s3c2410-nand
- structplatform_devices3c_device_nand={
- .name="s3c2410-nand",
- .id=-1,
- .num_resources=ARRAY_SIZE(s3c_nand_resource),
- .resource=s3c_nand_resource,
- };
- void__inits3c244x_map_io(void)
- {
- /*registerourio-tables*/
- iotable_init(s3c244x_iodesc,ARRAY_SIZE(s3c244x_iodesc));
- /*renameanyperipheralsuseddifferingfromthes3c2410*/
- s3c_device_sdi.name="s3c2440-sdi";
- s3c_device_i2c0.name="s3c2440-i2c";
- s3c_nand_setname("s3c2440-nand");
- s3c_device_ts.name="s3c2440-ts";
- s3c_device_usbgadget.name="s3c2440-usbgadget";
- }
- staticstructplatform_device_ids3c24xx_driver_ids[]={
- {
- .name="s3c2410-nand",
- .driver_data=TYPE_S3C2410,
- },{
- .name="s3c2440-nand",
- .driver_data=TYPE_S3C2440,
- },{
- .name="s3c2412-nand",
- .driver_data=TYPE_S3C2412,
- },{
- .name="s3c6400-nand",
- .driver_data=TYPE_S3C2412,/*compatiblewith2412*/
- },
- {}
- };
- structbus_typeplatform_bus_type={
- .name="platform",
- .dev_attrs=platform_dev_attrs,
- .match=platform_match,
- .uevent=platform_uevent,
- .pm=&platform_dev_pm_ops,
- };
- intplatform_driver_register(structplatform_driver*drv)
- {
- drv->driver.bus=&platform_bus_type;
- if(drv->probe)
- drv->driver.probe=platform_drv_probe;
- if(drv->remove)
- drv->driver.remove=platform_drv_remove;
- if(drv->shutdown)
- drv->driver.shutdown=platform_drv_shutdown;
- returndriver_register(&drv->driver);
- }
- staticintplatform_match(structdevice*dev,structdevice_driver*drv)
- {
- structplatform_device*pdev=to_platform_device(dev);
- structplatform_driver*pdrv=to_platform_driver(drv);
- /*AttemptanOFstylematchfirst*/
- if(of_driver_match_device(dev,drv))
- return1;
- /*Thentrytomatchagainsttheidtable*/
- if(pdrv->id_table)
- returnplatform_match_id(pdrv->id_table,pdev)!=NULL;
- /*fall-backtodrivernamematch*/
- return(strcmp(pdev->name,drv->name)==0);
- }
- staticconststructplatform_device_id*platform_match_id(
- conststructplatform_device_id*id,
- structplatform_device*pdev)
- {
- while(id->name[0]){
- if(strcmp(pdev->name,id->name)==0){
- pdev->id_entry=id;
- returnid;
- }
- id++;
- }
- returnNULL;
- }
- (1)定義resource,保證可以以物理地址方式正確訪問Nand寄存器。(默認有)
- (2)定義platform_device,這是內(nèi)核記錄的硬件信息,要注冊到內(nèi)核設(shè)備列表。
- (3)定義mtd_partition,設(shè)置Nand分區(qū)。
- (4)定義s3c2410_nand_set,枚舉所有Nand芯片信息。
- (5)定義s3c2410_platform_nand,這是驅(qū)動程序初始化Nand是需要的數(shù)據(jù),包括分區(qū)信息的和芯片時序等必要信息。
- (6)將s3c2410_platform_nand賦值給mtd_device->dev.platform_data。
- (7)將Nand設(shè)備結(jié)構(gòu)注冊到設(shè)備列表。
評論