注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之七  

2012-01-17 19:47:16|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之七

这篇文章争取把这个PROBE系列结束,其实这个结束了,重点基本也就差不多了,其它的就是一些在PROBE里配置过的函数的读写,前面其实在讲一些准备知识中也进行了一些具体的了解,这一篇完成后,春节也就要到了,就不会再进行如此大规模成系列的写博客了,余下的就是一些修补和简短的小文章了。

回到正题:接着上文说:

/*

 * Scan a given block partially

 */

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;

}

这里面用到了一个数据结构体如下:

/**

 * 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 than 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->read_oob木有,还记得不记得在nand_scan_tail中:

       mtd->read_oob = nand_read_oob;

 

/**

 * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band

 * @mtd:    MTD device structure

 * @from:   offset to read from

 * @ops:    oob operation description structure

 *

 * NAND read data and/or out-of-band data

 */

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, "%s: Attempt read "

                "beyond end of device\n", __func__);

        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;

}

按ARM-LINUX东东上说,红色的部分是成立的,也就是说数据是NULL,结构体的英文注释,这里不细说。

/**

 * nand_do_read_oob - [Intern] NAND read out-of-band

 * @mtd:    MTD device structure

 * @from:   offset to read from

 * @ops:    oob operations description structure

 *

 * NAND read out-of-band data from the spare area

 */

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, "%s: from = 0x%08Lx, len = %i\n",

            __func__, (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, "%s: Attempt to start read "

                    "outside oob\n", __func__);

        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, "%s: Attempt read beyond end "

                    "of device\n", __func__);

        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;

 

    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;

    }

 

    ops->oobretlen = ops->ooblen;

    return 0;

}

同样还是在nand_scan_tail函数中,已经设置:

chip->ecc.read_oob = nand_read_oob_std;

/**

 * nand_read_oob_std - [REPLACABLE] the most common OOB data read function

 * @mtd:    mtd info structure

 * @chip:   nand chip info structure

 * @page:   page number to read

 * @sndcmd: flag whether to issue read command or not

 */

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;

}

看到chip->cmdfunc这代码没,熟悉吧,不熟悉的回头看去,呵呵,不过是发送一些命令罢了,对着命令宏定义和实际的DATASHEET来想吧。没什么技术含量。

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

/**

 * nand_transfer_oob - [Internal] Transfer oob to client buffer

 * @chip:   nand chip structure

 * @oob:    oob destination address

 * @ops:    oob ops structure

 * @len:    size of oob to transfer

 */

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中就有一个表来表示那些是坏块了

Return,return,return回到了probe函数中,呵呵,这就算讲完了这个probe函数,可能讲得还是很清楚,因为我自己对这个也不是清楚的如丝发一样,有不对的地方请童鞋们提出来,我改,我改。

核心和主干基本就这样了,一开始也说了,余下的主要是一些非主流了。

春节快到,祝大家和各位童鞋新春快乐,万事如意,心享事成,龙年吉祥。给大家提前先拜个早年。

  评论这张
 
阅读(1072)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017