Linux下Nand Flash 驱动代码分析

半腔热情 提交于 2019-12-04 04:59:26
  随着越来越多的平台支持从Nand Flash 中启动,掌握Nand Flash 的驱动编写有着重要的现实意义,由于内核已经完成了大部分的工作,实际工作中大部分工程师对Nand Flash 驱动只是简单的修改。
   下面分析一下Nand Flash 的代码流程:
   学习Nand Flash 之前,需要对块设备中下面2点有个认识:
   1, gendisk: 描述块设备实体(一整个Nand Flash 芯片)的结构体,整个块设备的注册过程都是围绕gendisk 来开展的;
   2, add_disk(): 将一个分区信息(如:/dev/mtdblock3)注册到内核列表中
 
   下面分析具体的驱动:
   1, s3c2410 nandflash 控制器初始化步骤
   s3c2410_nand_init(&s3c2410_nand_driver)
   ->driver_register->bus_add_driver()->driver_attach->bus_for_each_dev(_driver_attach)->driver_probe_device()->dev->probe()  /*最后这个函数实质是 s3c2410_nand_probe() */
 
   ->s3c2410_nand_probe()
   ->s3c24xx_nand_probe()
   ->s3c2410_nand_inithw()   /* 初始化nandflash 控制器 */
     ->s3c2410_nand_init_chip()  /* 初始化s3c2410 nandflash 驱动最底层的访问控制函数 */
       ->chip->write_buf = s3c2410_nand_write_buf;
       ->chip->read_buf = s3c2410_nand_read_buf;
       ->chip->select_chip = s3c2410_nand_select_chip;
       ->chip->cmd_ctrl = s3c2410_nand_hwcontrol()
     ->nand_scan()
     ->s3c2410_nand_add_partition()
   ->add_mtd_device()
  
   将nandflash 的一个分区注册成一个块设备,并通过IO请求来访问的步骤: /*块设备驱动程序的注册过程*/
   module_init(init_mtdblock)
   ->init_mtdblock()
   ->register_mtd_blktrans(&mtdblock_tr)
     ->register_blkdev()  /* 注册为块设备 */
     ->blk_init_queue()   /* IO请求队列初始化 */
     ->kernel_thread(mtd_blktrans_thread) /* 块设备(nandflash)读写访问io请求处理线程 */
     ->tr->add_mtd()
       mtdblock_add_mtd()
       ->add_mtd_blktrans_dev()
       ->alloc_disk()
       ->add_disk()   /* 初始化一个gendisk 结构体并注册成一个disk */
         ->blk_register_region()
         ->register_disk()
         ->blk_register_queue()
 
   1, nandflash io 请求处理线程mtd_blktrans_thread()等在一个等待队列上
   mtd_blktrans_thread()
   ->DECLARE_WAITQUEUE(wait,current);
   ->elv_next_request()  /* 检查有没有IO请求 */
   ->add_wait_queue(&tr->blkcore_priv->thread_wq)  /* 等在等待队列上 */
   ->set_current_state(TASK_INTERRUPTIBLE)
   ->schedule();   /* 让出cpu使用权 */
   ->    /* 等待,直到有IO请求到来被唤醒 */
   ->do_blktrans_request()
     ->blk_fs_request();
     ->   /* 检查访问的偏移量不能大于整个nandflash 的容量 */
     ->   /* 假设为读访问: */
       ->tr->readsect()
         mtdblock_readsect()   /* mtd_block.c */
         ->do_cached_read()    /* mtd_block.c */
           ->mtd->read()
             nand_read()   /* nand_base.c */
             ->nand_do_read_ops()
               ->nand_read_page_raw()
                 ->s3c2410_nand_read_buf()  /* 通过s3c2410 nandflash控制器发命令读取nandflash 内容*/  //s3c2410.c
 
     ->  /* 假设为写访问 */
       ->tr->writesect()
         mtdblock_writesect()
   ->end_request()
 
   2, 当IO请求来时,唤醒线程 mtd_blktrans_thread()
   mtd_blktrans_request()
   ->wake_up(&tr->blkcore_priv->thread_wq)
 
   3, nandflash IO请求处理线程mtd_blktrans_thread()开始处理IO请求
   ->do_blktrans_request()
   ->/* 见上 */
 
从上面的代码流程可见,Nand Flash 驱动作为一个块设备的典型案例,为位于MTD的下层,其数据的读写通过mtd_blktrans_thread内核线程来处理IO请求。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!