linux NAND驱动之三:6410平台上的NAND驱动加载

1,platform_driver 的定义和注册

      在s3c_nand.c中,

static struct platform_driver s3c6410_nand_driver = {
                .probe  = s3c6410_nand_probe,
                .remove  = s3c_nand_remove,
                .suspend = s3c_nand_suspend,
                .resume  = s3c_nand_resume,
                .driver  = {
                       .name = "s3c6410-nand",
                       .owner = THIS_MODULE,
                 },
      };

      static int __init s3c_nand_init(void)
     {
             printk("S3C NAND Driver, (c) 2008 Samsung Electronics/n");
             return platform_driver_register(&s3c6410_nand_driver);
      }

     module_init(s3c_nand_init);
     module_exit(s3c_nand_exit);

与大多数嵌入式Linux 驱动一样,NAND 驱动也是从module_init 宏开始。s3c_nand_init 是驱动初始化函数,在此函数中注册platform driver 结构体,platform driver 结构体中自然需要定义probe 和remove 函数。其实在大多数嵌入式Linux 驱动中,这样的套路基本已经成了一个定式。
      至于module_init 有什么作用,s3c_nand_init 又是何时调用的,以及这个driver 是怎么和NAND 设备联系起来的,就不再多说了,这里只提三点:
A)以上代码只是向内核注册了NAND 的platform_driver ,即s3c_nand_init ,我们当然还需要一个NAND 的platform_device ,要不然s3c_nand_init的probe 函数就永远不会被执行,因为没有device 需要这个driver 。

B)向Linux 内核注册NAND 的platform_device 有两种方式:其一是直接定义一个NAND 的platform_device 结构体,然后调用platform_device_register 函数注册。其二是用platform_device_alloc 函数动态分配一个platform_device ,然后再用platform_device_add 函数把这个platform_device 加入到内核中去。相对来说,第一种方式更加方便和直观一点,而第二种方式则更加灵活一点。

C)在加载NAND 驱动时,我们还需要向MTD Core 提供一个信息,那就是NAND 的分区信息。

2,platform_device 的定义和注册

     在本地代码上,platform_device是这样注册的:
     A)定义了分区表:

struct mtd_partition s3c_partition_info[] = {
       {
                .name  = "misc",
                .offset  = (768*SZ_1K),  /* for bootloader */
                .size  = (256*SZ_1K),
                .mask_flags = MTD_CAP_NANDFLASH,
        },
        {
                .name  = "recovery",
                .offset  = MTDPART_OFS_APPEND,
                .size  = (5*SZ_1M),
//                .mask_flags = MTD_CAP_NANDFLASH,
        },
        {
                .name  = "kernel",
                .offset  = MTDPART_OFS_APPEND,
                .size  = (3*SZ_1M),
        },
        {
                .name  = "ramdisk",
                .offset  = MTDPART_OFS_APPEND,
                .size  = (1*SZ_1M),
        },
        {
                .name  = "system",
                .offset  = MTDPART_OFS_APPEND,
                .size  = (67*SZ_1M),
        },
        {
                .name  = "cache",
                .offset  = MTDPART_OFS_APPEND,
                .size  = (67*SZ_1M),
        },
        {
                .name  = "userdata",
                .offset  = MTDPART_OFS_APPEND,
                .size  = MTDPART_SIZ_FULL,
        }

};

      其中offset是分区开始的偏移地址,MTDPART_OFS_APPEND,表示紧接着上一个分区,MTD Core会自动计算和处理分区地址;size是分区的大小,在最后一个分区我们设为MTDPART_SIZ_FULL,表示这个NAND剩下的所有部分。这样配置NAND的分区并不是唯一的,需要视具体的系统而定,我们可以在kernel中这样显式的指定,也可以使用bootloader传给内核的参数进行配置。
     B)struct s3c_nand_mtd_info s3c_nand_mtd_part_info = {
             .chip_nr = 1,
             .mtd_part_nr = ARRAY_SIZE(s3c_partition_info),
             .partition = s3c_partition_info,
          };
     C)填充s3c_device_nand.dev.platform_data = &s3c_nand_mtd_part_info;
     D)s3c_device_nand是struct platform_device *smdk6410_devices[]的一个成员,然后platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));一起加载全部的platform_device(与platform_device_add相比前者的好处是可以一次加载多个device)

3,对分区的加载应用
      一个MTD原始设备可以通过mtd_part分割成数个MTD原始设备注册进mtd_table,mtd_table中的每个MTD原始设备都可以被注册成一个MTD设备,有两个函数可以完成这个工作,即 add_mtd_device函数和add_mtd_partitions函数。其中add_mtd_device函数是把整个NAND FLASH注册进MTD Core,而add_mtd_partitions函数则是把NAND FLASH的各个分区分别注册进MTD Core。其中master就是这个MTD原始设备,parts即NAND的分区信息,nbparts指有几个分区。
      这个可以从s3c_nand_probe中的add_mtd_partitions(s3c_mtd, partition_info, plat_info->mtd_part_nr);获得,其中的partition_info就是3c_partition_info,第三个参数就是ARRAY_SIZE(s3c_partition_info)。
 

 

参考原文:http://blog.csdn.net/leibniz_zsu/archive/2009/12/10/4977650.aspx

 

你可能感兴趣的:(linux NAND驱动之三:6410平台上的NAND驱动加载)