Chinaunix首页 | 论坛 | 博客
  • 博客访问: 27779
  • 博文数量: 22
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 125
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-24 12:40
文章分类

全部博文(22)

文章存档

2012年(22)

我的朋友
最近访客

分类:

2012-09-24 12:46:49

上面二章整体分析了mtd_dev_init()函数,现在就来具体分析struct mtd_info中函数的具体实现,至于mtd_info结构中的数据可以参考第一章中的说明。
在mtd_info结构体中一共包含了14个函数,他们分别是:
int (*erase)(struct mtd_info *mtd, struct erase_info *instr);

int (*point)(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);

int(*unpoint)(struct mtd_info *mtd, u_char *addr);

int (*read)(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

int(*write)(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);

int(*read_ecc)(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);

int(*write)(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);

int (*read_oob)(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen ,u_char *buf);

int(*write_oob)(struct mtd_info *mtd, loff_t to ,size_t len, size_t *retlen, const u_char *buf);

下面的函数是在一些特别的flash设备中提供去访问保护区域的方法
int (*read_user_prot_reg)(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

int (*read_fact_prot_reg)(struct mtd_info *mtd, loff_t from, size_t len , size_t *retlen, u_char *buf);

下面这个函数在vivi中没有实现:
int (*write_user_prot_reg)(struct mtd_info *mtd, loff_t from, size_t len ,size_t *retlen, u_char *buf);

设备支持锁:
int (*lock)(struct mtd_info *mtd, loff_t ofs, size_t len);

int (*unlock)(struct mtd_info *mtd, loff_t ofs, size_t len);
以上的就是strust mtd_info中的14个函数,从名字我们也可以看出他们的作用,现在我们来看看每个函数具体的实现:
首先我们反过来看smc_scan(struct mtd_info *mtd),我们知道在找到设备匹配的flash设备以后要对struct mtd_info结构变量赋值,函数方面的赋值如下:
    mtd->erase = nand_erase;
    mtd->point = NULL;
    mtd->unpoint = NULL;
    mtd->read = nand_read;
    mtd->write = nand_write;
    mtd->read_ecc = nand_read_ecc;
    mtd->write_ecc = nand_write_ecc;
    mtd->read_oob = nand_read_oob;
    mtd->write_oob = nand_write_oob;
    mtd->lock = NULL;
    mtd->unlock = NULL;
从mtd_info结构中数据的填充来看,有的函数在vivi中并没有实现,只是实现了部分,下面的分析也就根据实现的函数来说明,其中包括:
1,nand_erase
2, nand_read
3, nand_write
4, nand_read_ecc
5, nand_write_ecc
6, nand_read_oob
7, nand_write_oob
这么看来减少了一半的工作量,如果对所有的都感兴趣可以去查看linux的源代码:)
一:先来看mtd_info中的erase函数,他的函数原型则是nand_erase(),首先我们得了解nand flash的擦除是以块(block)为单位的,关于nand flash的资料我会另取一章来介绍,nand的知识也有待加强
在nand_erase函数有一个结构struct erase_info在上面介绍,现在我们先来看看改结构体的定义:

struct erase_info {
    struct mtd_info *mtd;
    u_int32_t addr;
    u_int32_t len;
    u_long time;
    u_long retries;
    u_int dev;
    u_int cell;
    void (*callback)(struct erase_info *self);
    u_long priv;
    u_char state;
    struct erase_info *next;
}



在函数中有一个DEBUG函数,查看原型:
#define DEBUG(n, args...) \
      if (n <= CONFIG_MTD_DEBUG_VERBOSE){ \
            printk(##args);   \
      }
__FUNCTION__ 在C语言中以编程的方式获取函数名
因此函数EEBUG(LEVEL, __FUNCTION__():....);则是输出nand_erase():



/*
 * NAND erase a block
 */

static int 
nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
    int i, page, len, status, pages_per_block;
    struct nand_chip *this = mtd->priv;

    DEBUG(MTD_DEBUG_LEVEL3,
        __FUNCTION__"(): start = 0x%08x, len = %i\n",
        (unsigned int)instr->addr, (unsigned int)instr->len);

/*
*
*因为nand flash的擦除是以块为单位的,而instr->addr指向要擦除的地址的起始
*因此需要块对齐。下面则是保证地址开始以块对齐
*
*/


    /* Start address must aligned on block boundary */
    if (instr->addr & (mtd->erasesize - 1)) {
        DEBUG(MTD_DEBUG_LEVEL0,
            __FUNCTION__"(): Unaligned address\n");
        return -EINVAL;
    }
/*
*
*擦除的长度也需要以块对齐,
*
*/

    /* Length must align on block boundary */
    if (instr->len & (mtd->erasesize - 1)) {
        DEBUG(MTD_DEBUG_LEVEL0,
            __FUNCTION__"(): Length not block aligned\n");
        return -EINVAL;
    }
/*
*不能超过nand flash的边界
*/

    /* Do not allow erase past end of device */
    if ((instr->len + instr->addr) > mtd->size) {
        DEBUG(MTD_DEBUG_LEVEL0,
            __FUNCTION__"(): Erase past end of device\n");
        return -EINVAL;
    }
/*
* 找到要擦除的第一页的位置
* this->page_shift = 9,每页为512个字节
*/

    /* Shift to get first page */
    page = (int)(instr->addr >> this->page_shift);

    /* Calculate pages in each block */
    pages_per_block = mtd->erasesize / mtd->oobblock;

    /* Select the NAND device */
    nand_select();
/*
*在vivi中已经定了一个宏#define NAND_CMD_STATUS 0X70,命令0x70是读取flash的状态
*然后等待读取完成
*/

    /* Check the WP bit */
    nand_command(mtd, NAND_CMD_STATUS, -1, -1);
    this->wait_for_ready();
/*
* 在这里的读数据,我没弄懂,读的是哪的数据,可能在nand flash手册里面有介绍,还没
* 看,改天看看,意思就是读数据,看这些数据是不是被保护,是保护则退出??????
*(已经解决,看本章最后说明!)
*/

    if (!(this->read_data() & SMC_STAT_NOT_WP)) {
        DEBUG(MTD_DEBUG_LEVEL0,
            __FUNCTION__"(): Device is write protected!!!\n");
        nand_deselect();
        return -EIO;
    }
/**
* 下面的循环则是开始擦除数据(以页为单位)
*
**/

    /* Loop through the pages */
    len = instr->len;
    while (len) {
        /* Send commands to erase a page */
        nand_command(mtd, NAND_CMD_ERASE1, -1, page);
        nand_command(mtd, NAND_CMD_ERASE2, -1, -1);

        this->wait_for_ready();

        /*
         * Wait for program operation to complete. This could
         * take up to 4000us (4ms) on some devices, so we try
         * and exit as quickly as possible.
         */

        status = 0;
        for (= 0; i < 32; i++) {
            /* Delay for 125us */
            udelay(125);

            /* Check the status */
            nand_command(mtd, NAND_CMD_STATUS, -1, -1);
/**
*擦除以后检查数据位!不同的情况不同的处理
**/

            this->wait_for_ready();

            status = (int)this->read_data();
            if (status & SMC_STAT_READY)
                break;
        }

        /* See if block erase succeeded */
        if (status & SMC_STAT_WRITE_ERR) {
            DEBUG(MTD_DEBUG_LEVEL0,
                __FUNCTION__"(): Failed erase, page 0x%08x\n", page);
            nand_deselect();
#if 0
            instr->state = MTD_ERASE_FAILED;
            if (instr->callback)
                instr->callback(instr);
#endif
            return -EIO;
        }

        /* Increment page address and decrement length */
        len -= mtd->erasesize;
        page += pages_per_block;
    }

    /* De-select the NAND device */
    nand_deselect();

#if 0
    /* Do call back function */
    instr->state = MTD_ERASE_DONE;
    if (instr->callback)
        instr->callback(instr);
#endif

    /* Return happy */
    return 0;
}



如果成功则返回0
于硬件连接的软件一定要去读硬件的数据手册,下面这段文字是我所使用的nand flash的手册
由于上面程序的需要我只是看了关于状态寄存器的部分,该寄存器反应了写入或擦除操作是否完成,或写入和擦除操作是否无错
READ STATUS
The device contains a Status Register which may be read to find out whether program or erase operation is completed, and whether
the program or erase operation is completed successfully. After writing 70h command to the command register, a read cycle outputs
the content of the Status Register to the I/O pins on the falling edge of CE or RE, whichever occurs last. This two line control allows
the system to poll the progress of each device in multiple memory connections even when R/B pins are common-wired. RE or CE
does not need to be toggled for updated status. Refer to table 4 for specific Status Register definitions. The command register
remains in Status Read mode until further commands are issued to it. Therefore, if the status register is read during a random read
cycle, a read command(00h or 50h) should be given before sequential page read cycle.
For Read Status of Multi Plane Program/Erase, the Read Multi-Plane Status command(71h) should be used to find out whether multi-
plane program or erase operation is completed, and whether the program or erase operation is completed successfully. The pass/fail
status data must be checked only in the Ready condition after the completion of Multi-Plane program or erase operation.
Table4. Read Staus Register Definition
    I/O No.                Status                    Definition by 70h Command                   Definition by 71h Command
      I/O 0          Total Pass/Fail           Pass : "0"               Fail : "1"         Pass : "0"(1)              Fail : "1"
      I/O 1         Plane 0 Pass/Fail          Must be don’t -cared                        Pass : "0"(2)                 Fail : "1"
      I/O 2         Plane 1 Pass/Fail          Must be don’t -cared                                   (2)
                                                                                           Pass : "0"                    Fail : "1"
      I/O 3         Plane 2 Pass/Fail          Must be don’t -cared                        Pass : "0"(2)                 Fail : "1"
      I/O 4         Plane 3 Pass/Fail          Must be don’t -cared                                   (2)
                                                                                           Pass : "0"                    Fail : "1"
      I/O 5              Reserved              Must be don’t -cared                        Must be don’t-cared
      I/O 6         Device Operation           Busy : "0"                 Ready : "1"      Busy : "0"                   Ready : "1"
      I/O 7           Write Protect            Protected : "0"       Not Protected : "1"   Protected : "0"        Not Protected : "1"
NOTE : 1. I/O 0 describes combined Pass/Fail condition for all planes. If any of the selected multiple pages/blocks fails in Program/
            Erase operation, it sets "Fail" flag.
         2. The pass/fail status applies only to the corresponding plane.

看完这个我上午的那个不理解的部分也就清晰了,其实就是首先读NAND的状态,然后检查NAND的数据是不是保护的,是保护则退出!!!
在擦除数据的循环中,检查擦除是否成功,通过查看vivi中的宏定义更能说明。
查看vivi中的宏定义:
#define SMC_STAT_READY    0X40      //0: BUSY   1:READY
#define SMC_STAT_WRITE_ERR     0X01 //1: Error in Program/Erase

好了到这里为止,第一个函数nand_erase全部解释完,可能还有遗漏的地方!
下面插入一个nand flash擦除的流程图,看完这个流程图则会很清晰
阅读(560) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~