您的位置:首页 > 运维架构 > Linux

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

2012-12-10 13:45 459 查看
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)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: