隨着愈來愈多的平臺支持從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請求。