nandflash学习经历

来源:互联网 发布:锵锵三人行 德国公知 编辑:程序博客网 时间:2024/06/06 14:14

经过一段时间的奋斗,  终于对nandflash的框架有点了解!

首先nandflash的框架:
 
                  APP: open  read  write
 
 ----------------------------------------------------------------------
 
 vfs:  sys_open  sys_read    sys_write
 
 ------------------------------------------------------------------
 
 字符设备                       |FS:  VFAT  EXT2   YAFFS2
 
                                   | --------------------------------------
 
                                   | 块设备(优化)
 
 -----------------------------------------------------------------------------
 
              nandflash协议层(知道 读写、扫描nandflsh...)
 
 --------------------------------------------------------------------------------
 
                   nandflash硬件层  (实现nandchip 结构
 
                                        |
 
                                        |__(1)  分配nandchip结构
 
                                             (2)设置nandchip 
 
                                             (3) 硬件相关设置
 
                                             (4)使用nandchip结构   nand_scan   add_parition....

 

首先从/drivers/mtd/nand/AT91_nand.c开始分析

 

at91_nand_probe
 //获得nandflash 的类型
 //drivers/mtd/nand/Nand_base.c
 nand_scan
  //获得真正nandflash   的类型
  nand_scan_ident
   nand_get_flash_type
   
   
  //初始化nandflash使用的函数
  nand_scan_tail
   mtd->read = nand_read;
   mtd->write = nand_write;
  
 
 //添加分区信息
 //drivers/mtd/nand/Mtdpart.c
 add_mtd_partitions
  //drivers/mtd/Mtdcore.c
  add_mtd_device
   list_for_each(this, &mtd_notifiers) {//mtd_notifiers在哪初始化此链表?
            // 在register_mtd_user   中添加链表,那此函数哪个中被调用呢?
            //被drivers\mtd\Mtdchar.c  和  drivers\mtd\Mtd_blkdevs.c 调用
   struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
   not->add(mtd);
   }
   
   //drivers\mtd\Mtdchar.c
   //初始化时调用register_mtd_user 函数对 mtd_notifiers进行注册
   init_mtdchar
    register_mtd_user(&notifier);
     //注册链表的时候,  上面的not->add(mtd); 实际上就是调用下面结构mtd_notify_add的函数
     //static struct mtd_notifier notifier = {
     //.add = mtd_notify_add,
     //.remove = mtd_notify_remove,
     //};

   mtd_notify_add
    //创建两个设备节点  mtd*   mtd*ro
    class_device_create
    class_device_create
    
   
   
   //drivers\mtd\Mtd_blkdevs.c
   //调用 register_mtd_blktrans对mtd_notifiers进行注册
   register_mtd_blktrans 
    register_mtd_user(&blktrans_notifier);
    //注册链表的时候, 上面的not->add(mtd);实际就是调用blktrans_notify_add此函数
    // static struct mtd_notifier blktrans_notifier = {
    // .add = blktrans_notify_add,
    // .remove = blktrans_notify_remove,
    // };
   //添加函数中又出现个链表blktrans_majors      
   blktrans_notify_add  
    //list_for_each(this, &blktrans_majors) {//这个链表blktrans_majors又是被谁初始化和添加呢?
         //(1)初始化还是被register_mtd_blktrans
         //  list_add(&tr->list, &blktrans_majors);
         
    // struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); 
    // tr->add_mtd(tr, mtd);
    //}
    
   register_mtd_blktrans   被谁调用呢?
   //drivers\mtd\Mtdblock.c   和  drivers\mtd\Mtdblock_ro.c
   //这两个文件初始化的时候,调用register_mtd_blktrans此函数对链表进行初始化
   init_mtdblock(void)
     register_mtd_blktrans(&mtdblock_tr);
     //但是上面链表的.add调用谁呢?
     //答:会调用mtdblock_tr 结构中mtdblock_add_mtd    drivers\mtd\Mtdblock.c
     static struct mtd_blktrans_ops mtdblock_tr = {
     .name  = "mtdblock",
     .major  = 31,
     .part_bits = 0,
     .blksize  = 512,
     .open  = mtdblock_open,
     .flush  = mtdblock_flush,
     .release = mtdblock_release,
     .readsect = mtdblock_readsect,
     .writesect = mtdblock_writesect,
     .add_mtd = mtdblock_add_mtd,
     .remove_dev = mtdblock_remove_dev,
     .owner  = THIS_MODULE,
    };
    
    //上面的.add_mtd会调用此函数
    mtdblock_add_mtd
     //那这个函数中会做写什么呢?
     //drivers/mtd/Mtd_blkdev.c
     add_mtd_blktrans_dev
     //分配一个struct gendisk  结构,又回到用内存模仿nandflsh那一套
     alloc_disk
     //设置容量
     set_capacity
     //初始化一个默认的队列
     gd->queue = tr->blkcore_priv->rq;//blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
     add_disk(gd);
     
    
     //那队列mtd_blktrans_request  唤醒函数做些什么呢?
       //唤醒队列,那运行等待队列在哪实现的呢?
       wake_up_process(tr->blkcore_priv->thread);
       
       register_mtd_blktrans
        //在register_mtd_blktrans注册函数中,有个线程mtd_blktrans_thread
        tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread,
        tr,"%sd", tr->name);
        
        mtd_blktrans_thread
         //电梯调度算法
         req = elv_next_request(rq);
         //唤醒后执行do_blktrans_request,没有一直在这休眠
         do_blktrans_request
          //最终还是调用读、写块函数    
         
           struct mtd_blktrans_ops *tr
           tr->readsect(dev, block, buf)
           //实际上就是调用
           .readsect = mtdblock_readsect,
           
           //而mtdblock_readsect  实际上内部就是调用
           //mtd->read(mtd, pos, size, &retlen, buf);
    

原创粉丝点击