Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332627
  • 博文数量: 125
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-06 15:18
文章分类

全部博文(125)

文章存档

2014年(29)

2013年(93)

2012年(3)

分类: LINUX

2013-03-21 23:58:48

Arm-linux东东nand9: nand_scan_tail:

static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,

                        loff_t offs, uint8_t *buf, int len)

{

       struct mtd_oob_ops ops;

       int j, ret;

 

       ops.ooblen = mtd->oobsize;

       ops.oobbuf = buf;

       ops.ooboffs = 0;

       ops.datbuf = NULL;

       ops.mode = MTD_OOB_PLACE;

 

       for (j = 0; j < len; j++) {

              /*

               * Read the full oob until read_oob is fixed to

               * handle single byte reads for 16 bit

               * buswidth

               */

              ret = mtd->read_oob(mtd, offs, &ops);

              if (ret)

                     return ret;

 

              if (check_short_pattern(buf, bd))

                     return 1;

 

              offs += mtd->writesize;

       }

       return 0;

}

Len是为2.也就只要扫描头二页就行了.红色的那一句就是加一页了.

 

/**

 * struct mtd_oob_ops - oob operation operands

 * @mode:     operation mode

 *

 * @len:  number of data bytes to write/read

 *

 * @retlen:     number of data bytes written/read

 *

 * @ooblen:   number of oob bytes to write/read

 * @oobretlen:       number of oob bytes written/read

 * @ooboffs:  offset of oob data in the oob area (only relevant when

 *           mode = MTD_OOB_PLACE)

 * @datbuf:    data buffer - if NULL only oob data are read/written

 * @oobbuf:   oob data buffer

 *

 * Note, it is allowed to read more then one OOB area at one go, but not write.

 * The interface assumes that the OOB write requests program only one page's

 * OOB area.

 */

struct mtd_oob_ops {

       mtd_oob_mode_t   mode;

       size_t             len;

       size_t             retlen;

       size_t             ooblen;

       size_t             oobretlen;

       uint32_t   ooboffs;

       uint8_t           *datbuf;

       uint8_t           *oobbuf;

};

mtd_oob_ops 可以表示真的数据,也可以表示OOB数据.上面的解释很清楚了.再说你可能要骂我了.

check_short_pattern很简单.只要会C的就能看懂了.

我们看这个mtd->read_oob

记得不在nand_scan_tail:

       mtd->read_oob = nand_read_oob;

…………………………………………………

static int nand_read_oob(struct mtd_info *mtd, loff_t from,

                      struct mtd_oob_ops *ops)

{

       struct nand_chip *chip = mtd->priv;

       int ret = -ENOTSUPP;

 

       ops->retlen = 0;

 

       /* Do not allow reads past end of device */

       if (ops->datbuf && (from + ops->len) > mtd->size) {

              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "

                    "Attempt read beyond end of device\n");

              return -EINVAL;

       }

 

       nand_get_device(chip, mtd, FL_READING);

 

       switch(ops->mode) {

       case MTD_OOB_PLACE:

       case MTD_OOB_AUTO:

       case MTD_OOB_RAW:

              break;

 

       default:

              goto out;

       }

 

       if (!ops->datbuf)

              ret = nand_do_read_oob(mtd, from, ops);

       else

              ret = nand_do_read_ops(mtd, from, ops);

 

 out:

       nand_release_device(mtd);

       return ret;

}

……………………………………..

我们来说下主要的函数:

关于nand_get_devicenand_release_device这里不表

红色的那段是成立的.于是:

…………………………

static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,

                         struct mtd_oob_ops *ops)

{

       int page, realpage, chipnr, sndcmd = 1;

       struct nand_chip *chip = mtd->priv;

       int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;

       int readlen = ops->ooblen;

       int len;

       uint8_t *buf = ops->oobbuf;

 

       DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",

             (unsigned long long)from, readlen);

 

       if (ops->mode == MTD_OOB_AUTO)

              len = chip->ecc.layout->oobavail;

       else

              len = mtd->oobsize;

 

       if (unlikely(ops->ooboffs >= len)) {

              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "

                     "Attempt to start read outside oob\n");

              return -EINVAL;

       }

 

       /* Do not allow reads past end of device */

       if (unlikely(from >= mtd->size ||

                   ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -

                                   (from >> chip->page_shift)) * len)) {

              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "

                     "Attempt read beyond end of device\n");

              return -EINVAL;

       }

 

       chipnr = (int)(from >> chip->chip_shift);

       chip->select_chip(mtd, chipnr);

 

       /* Shift to get page */

       realpage = (int)(from >> chip->page_shift);

       page = realpage & chip->pagemask;

…………………………

MTD_OOB_AUTO没有设的于是.len就等于mtd->oobsize. 那个realpage行吧.记得我以前说过page_shitf不记得回头看下.

……………………

 

while(1) {

              sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);

 

              len = min(len, readlen);

              buf = nand_transfer_oob(chip, buf, ops, len);

 

              if (!(chip->options & NAND_NO_READRDY)) {

                     /*

                      * Apply delay or wait for ready/busy pin. Do this

                      * before the AUTOINCR check, so no problems arise if a

                      * chip which does auto increment is marked as

                      * NOAUTOINCR by the board driver.

                      */

                     if (!chip->dev_ready)

                            udelay(chip->chip_delay);

                     else

                            nand_wait_ready(mtd);

              }

 

              readlen -= len;

              if (!readlen)

                     break;

 

              /* Increment page address */

              realpage++;

 

              page = realpage & chip->pagemask;

              /* Check, if we cross a chip boundary */

              if (!page) {

                     chipnr++;

                     chip->select_chip(mtd, -1);

                     chip->select_chip(mtd, chipnr);

              }

 

              /* Check, if the chip supports auto page increment

               * or if we have hit a block boundary.

               */

              if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))

                     sndcmd = 1;

       }

………………………………………………………

进入这个while不过只会一次.执行到红色那里就退出了.

因为readlen就等于len;

ops.ooblen = mtd->oobsize;

       ops.oobbuf = buf;

       ops.ooboffs = 0;

       ops.datbuf = NULL;

       ops.mode = MTD_OOB_PLACE;

这一句: sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);

对于硬件算ECC的来说就是

…………………

static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,

                          int page, int sndcmd)

{

       if (sndcmd) {

              chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);

              sndcmd = 0;

       }

       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);

       return sndcmd;

}

Sndcmd是为1.发送命令.然后就读.命令如何分发上面已经讲过了.

回到nand_do_read_oob还有一个函数nand_transfer_oob

static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,

                              struct mtd_oob_ops *ops, size_t len)

{

       switch(ops->mode) {

 

       case MTD_OOB_PLACE:

       case MTD_OOB_RAW:

              memcpy(oob, chip->oob_poi + ops->ooboffs, len);

              return oob + len;

 

       case MTD_OOB_AUTO: {

              struct nand_oobfree *free = chip->ecc.layout->oobfree;

              uint32_t boffs = 0, roffs = ops->ooboffs;

              size_t bytes = 0;

 

              for(; free->length && len; free++, len -= bytes) {

                     /* Read request not from offset 0 ? */

                     if (unlikely(roffs)) {

                            if (roffs >= free->length) {

                                   roffs -= free->length;

                                   continue;

                            }

                            boffs = free->offset + roffs;

                            bytes = min_t(size_t, len,

                                         (free->length - roffs));

                            roffs = 0;

                     } else {

                            bytes = min_t(size_t, len, free->length);

                            boffs = free->offset;

                     }

                     memcpy(oob, chip->oob_poi + boffs, bytes);

                     oob += bytes;

              }

              return oob;

       }

       default:

              BUG();

       }

       return NULL;

}

MTD_OOB_PLACE是设了的.于是只有一个潇潇洒洒的一个函数memcpy

回了,一直返回.这样一次扫描就完了.于在nand_chip中就有一个表来表示那些是坏块了

还有一个函数就是:

int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)

{

       struct nand_chip *this = mtd->priv;

       int block;

       uint8_t res;

 

       /* Get block number * 2 */

       block = (int)(offs >> (this->bbt_erase_shift - 1));

       res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;

 

       DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",

             (unsigned int)offs, block >> 1, res);

 

       switch ((int)res) {

       case 0x00:

              return 0;

       case 0x01:

              return 1;

       case 0x02:

              return allowbbt ? 0 : 1;

       }

       return 1;

}

没有了.就这样了.

万物归宗又回到了s3c24xx_nand_probe

还有一个函数就是s3c2410_nand_add_partition

 

阅读(1072) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~