Linux MTD层的研究(Nandflash)

来源:互联网 发布:王者荣耀女娲攻略知乎 编辑:程序博客网 时间:2024/06/06 10:39

花了点时间学习Linux MTD层,下面简单总结一下!

以下是MTD层的结构图


      MTD层实现了文件系统与Flash之间的桥梁,下面就粗略说明字符型MTD驱动与下层驱动的关系。

分析对象:/drivers/mtdchar.c 字符型mtd设备

字符设备中定义了mtd_fops字符类的文件指针操作函数,完成字符设备读写与打开等功能。

1. static int mtd_open(struct inode *inode, struct file *file)
{
    int minor = iminor(inode);
    int devnum = minor >> 1;
    int ret = 0;
    struct mtd_info *mtd;
    struct mtd_file_info *mfi;
   ........
    mtd = get_mtd_device(NULL, devnum);    //在原始设备层实现, mtd/mtdcore.c文件中被EXPORTS_SYMBOL
    ........
} /* mtd_open */

/*====================

get_mtd_device在原始设备层中被实现,原始设备层中维护了一个struct mtd_info *mtd_table[MAX_MTD_DEVICES],用来存储注册mtd的设备列表。该文件中(该层)实现了如下的函数对外Export_Symbol:

EXPORT_SYMBOL_GPL(add_mtd_device);      //用于硬件驱动层调用,注册到原始设备层,调用路径为:s3c24xx_nand_probe()(/drivers/mtd/nand/s3c2410.c) --> add_one_partition(mtdpart.c) --> add_mtd_device()(mtdcore.c)
EXPORT_SYMBOL_GPL(del_mtd_device);    //用法与上面差不多
EXPORT_SYMBOL_GPL(get_mtd_device);    //得到table里面的具体mtd设备(mtd_info),该结构里有read等函数;该函数主要为mtd字符设备层调用
EXPORT_SYMBOL_GPL(get_mtd_device_nm);   //通过名字得到mtd设备(mtd_info)
EXPORT_SYMBOL_GPL(put_mtd_device);           //释放
EXPORT_SYMBOL_GPL(register_mtd_user);    //注册mtd_user;mtd原始层维护了一个mtd_notifiers链表,用于提供上层向下层注册 struct mtd_notifier {void (*add)(struct mtd_info *mtd); void (*remove)(struct mtd_info *mtd);struct list_head list; }
EXPORT_SYMBOL_GPL(unregister_mtd_user);
EXPORT_SYMBOL_GPL(default_mtd_writev);


2. 字符设备mtdchar.c中的


static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{
   

。。。。。

           ret = mtd->read(mtd, *ppos, len, &retlen, kbuf);
。。。。。
    return total_retlen;
} /* mtd_read */


 通过调用mtd原始层struct mtd_info *mtd_table[MAX_MTD_DEVICES]对应的mtd_info中的封装的read方法实现读写。

那么该read方法是怎么实现的呢?在/drivers/mtd/nand下有个nand_base.c中,公开了一些函数,在s3c2440.c中被调用

EXPORT_SYMBOL_GPL(nand_scan);
EXPORT_SYMBOL_GPL(nand_scan_ident);
EXPORT_SYMBOL_GPL(nand_scan_tail);
EXPORT_SYMBOL_GPL(nand_release);

其中nand_scan函数中完成了Mtd_info的read等函数的赋值:

    /* Fill in remaining MTD driver data */
    mtd->type = MTD_NANDFLASH;
    mtd->flags = MTD_CAP_NANDFLASH;
    mtd->erase = nand_erase;
    mtd->point = NULL;
    mtd->unpoint = NULL;
    mtd->read = nand_read;
    mtd->write = nand_write;
    mtd->read_oob = nand_read_oob;
    mtd->write_oob = nand_write_oob;
    mtd->sync = nand_sync;
    mtd->lock = NULL;
    mtd->unlock = NULL;
    mtd->suspend = nand_suspend;
    mtd->resume = nand_resume;
    mtd->block_isbad = nand_block_isbad;
    mtd->block_markbad = nand_block_markbad;

这些函数的功能,使得硬件驱动层struct nand_chip中的相关read函数与之关联起来。

3. /driver/mtd/nand/s3c2410.c实现了与硬件相关的驱动程序:

该驱动是platform类型的驱动,其设备的注册在/arch/arm/plat-s3c24xx/common-smdk.c中:

static struct mtd_partition smdk_default_nand_part[]
将源结构体删除,或者注释掉,修改为以下形式
static struct mtd_partition smdk_default_nand_part[] = {
                [0] = {
                                .name                = "Boot",
                                .size                = 0x00100000,
                                .offset = 0
                },
                [1] = {
                                .name                = "MyApp",
                                .size                = 0x003c0000,
                                .offset = 0x00140000,
                },
                [2] = {
                                .name                = "Kernel",
                                .size                = 0x00300000,
                                .offset = 0x00500000,
                },
                [3] = {
                                .name                = "fs_yaffs",
                                .size                = 0x03c00000,                  //30M
                                .offset = 0x00800000,
                },                
                [4] = {
                                .name                = "WINCE",
                                .size                = 0x03c00000,
                                .offset = 0x04400000,
                }
};    //该配置针对的是 FL2440中的nandflash分区划分。common-smdk中smdk_machine_init调用了platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));函数,实现了平台设备的注册,这些设备还包括看门狗,LCD等等。。。根据Platform的特点,在/drivers/mtd/nand/s3c2410.c中实现驱动的注册就行了,下面这个函数会在platform类型的驱动被内核自动调用。该函数取出上面结构的信息,分配给驱动存储空间,nand_chip 初始化,以及调用mtd原始驱动提供的函数完成Mtd设备的增加(s3c24xx_nand_probe()(/drivers/mtd/nand/s3c2410.c) --> add_one_partition(mtdpart.c) --> add_mtd_device()(mtdcore.c))。

static int s3c24xx_nand_probe(struct platform_device *pdev,
                  enum s3c_cpu_type cpu_type)
{
    struct s3c2410_platform_nand *plat = to_nand_plat(pdev);

   。。。。。。


4. 对于一个Soc芯片来说,之需要实现与硬件相关的驱动层的结构体(nand_chip),mtd原始设备层与mtd字符设备,快设备系统内核已经实现了,

nand_chip结构体为:

struct nand_chip {
 

   void __iomem* IO_ADDR_R;
 
   void __iomem* IO_ADDR_W;

    uint8_t (* read_byte) ( struct mtd_info * mtd) ;
 
   u16 ( *read_word) ( struct mtd_info * mtd) ;
 
   void ( *write_buf) ( struct mtd_info * mtd, const uint8_t * buf, int len);
 
   void ( *read_buf) ( struct mtd_info * mtd, uint8_t * buf, int len) ;
 
   int ( *verify_buf) ( struct mtd_info * mtd, const uint8_t * buf, int len);
 
   void ( *select_chip) ( struct mtd_info * mtd, int chip) ;
 
   int ( *block_bad) ( struct mtd_info * mtd, loff_t ofs, int getchip);
 
   int ( *block_markbad) ( struct mtd_info * mtd, loff_t ofs) ;
 
   void ( *cmd_ctrl) ( struct mtd_info * mtd, int dat, unsigned int ctrl);
 
   int ( *dev_ready) ( struct mtd_info * mtd) ;
 
   void ( *cmdfunc) ( struct mtd_info * mtd, unsigned command, int column, intpage_addr) ;
 
   int ( *waitfunc) ( struct mtd_info * mtd, struct nand_chip * this );
 
   void ( *erase_cmd) ( struct mtd_info * mtd, int page) ;
 
   int ( *scan_bbt) ( struct mtd_info * mtd) ;
 
   int ( *errstat) ( struct mtd_info * mtd, struct nand_chip * this , intstate, int status, int page) ;
 
   int ( *write_page) ( struct mtd_info * mtd, struct nand_chip * chip, constuint8_t * buf, int page, int cached, int raw) ;

    ……

    structnand_ecc_ctrl ecc;

    ……
}

    要想些SOC类型的Nandflash驱动可以重点研究/drivers/mtd/nand/s3c2410.c,仿造其来实现。注意:这里可以调用的函数常常有/drivers/mtd/mtdcore.c,/dirvers/mtd/mtdpart.c , /driver/mtd/nand/nand_base.c中导出的供下层使用的函数(kernel 2.6.28),另外,/drivers/mtd/chips中主要为Norflash驱动的实现,还没来得及研究,后续在写。

原创粉丝点击