随着越来越多的平台支持从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请求。
来源:oschina
链接:https://my.oschina.net/u/51715/blog/57930