Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1912565
  • 博文数量: 376
  • 博客积分: 2147
  • 博客等级: 大尉
  • 技术积分: 3642
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-06 10:47
文章分类

全部博文(376)

文章存档

2019年(3)

2017年(28)

2016年(15)

2015年(17)

2014年(182)

2013年(16)

2012年(115)

我的朋友

分类: LINUX

2012-06-04 16:32:52

//mtd为待擦除的原始MTD设备,例如flash有两个分区1和2,它们分别都有MTD从设备,当擦除它们中的某个时候,传给cfi_amdstd_erase_varsize都是分区所属的主设备
static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
    unsigned long ofs, len;
    int ret;

    ofs = instr->addr;//原始设备的擦除地址
    len = instr->len;

    ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
    if (ret)
        return ret;

    instr->state = MTD_ERASE_DONE;//设置擦除完成标志
    mtd_erase_callback(instr);//擦除回调,一般是唤醒等待擦除完成的进程

    return 0;
}

int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
                     loff_t ofs, size_t len, void *thunk)
{
    struct map_info *map = mtd->priv;
    struct cfi_private *cfi = map->fldrv_priv;
    unsigned long adr;
    int chipnum, ret = 0;
    int i, first;
    struct mtd_erase_region_info *regions = mtd->eraseregions;

    if (ofs > mtd->size)//待擦除的偏移大于设备大小
        return -EINVAL;

    if ((len + ofs) > mtd->size)//待擦除的末尾偏移大于设备大小
        return -EINVAL;

    /* Check that both start and end of the requested erase are
     * aligned with the erasesize at the appropriate addresses.
     */

    i = 0;

    /* Skip all erase regions which are ended before the start of
       the requested erase. Actually, to save on the calculations,
       we skip to the first erase region which starts after the
       start of the requested erase, and then go back one.
    */
//计算待擦除区域的起始区域
    while (i < mtd->numeraseregions && ofs >= regions[i].offset)
           i++;
    i--;

    /* OK, now i is pointing at the erase region in which this
       erase request starts. Check the start of the requested
       erase range is aligned with the erase size which is in
       effect here.
    */

    if (ofs & (regions[i].erasesize-1))//偏移不是块的整数倍地址
        return -EINVAL;

    /* Remember the erase region we start on */
    first = i;

    /* Next, check that the end of the requested erase is aligned
     * with the erase region at that address.
     */
//计算待擦除区域的结束区域
    while (inumeraseregions && (ofs + len) >= regions[i].offset)
        i++;

    /* As before, drop back one to point at the region in which
       the address actually falls
    */
    i--;

    if ((ofs + len) & (regions[i].erasesize-1))
        return -EINVAL;

    chipnum = ofs >> cfi->chipshift;//计算待擦除区域起始第几个芯片
    adr = ofs - (chipnum << cfi->chipshift);//相对于起始芯片的片内偏移

    i=first;

    while(len) {
        int size = regions[i].erasesize;//获取擦除块大小
//调用擦除回调函数对adr地址块进行擦除
        ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);

        if (ret)
            return ret;

        adr += size;
        ofs += size;
        len -= size;
//偏移达到一个擦除区域的末尾,则对下一区域操作
        if (ofs == regions[i].offset + size * regions[i].numblocks)
            i++;
//地址偏移达到一组芯片的末尾,则对下一组芯片操作
        if (adr >> cfi->chipshift) {
            adr = 0;
            chipnum++;

            if (chipnum >= cfi->numchips)
            break;
        }
    }

    return 0;
}

static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                  size_t *retlen, const u_char *buf)
{
    struct map_info *map = mtd->priv;
    struct cfi_private *cfi = map->fldrv_priv;
    int ret = 0;
    int chipnum;
    unsigned long ofs, chipstart;
    DECLARE_WAITQUEUE(wait, current);

    *retlen = 0;
    if (!len)
        return 0;

    chipnum = to >> cfi->chipshift;//计算擦除的待芯片
    ofs = to  - (chipnum << cfi->chipshift);//计算相对待擦除芯片的片内地址
    chipstart = cfi->chips[chipnum].start;;//待擦除芯片的起始地址

    /* If it's not bus-aligned, do the first byte write */
    if (ofs & (map_bankwidth(map)-1)) {//待擦除起始偏移不是map_bankwidth(map)整数倍
        unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
        int i = ofs - bus_ofs;
        int n = 0;
        map_word tmp_buf;

 retry:
        spin_lock(cfi->chips[chipnum].mutex);

        if (cfi->chips[chipnum].state != FL_READY) {
#if 0
            printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
#endif
            set_current_state(TASK_UNINTERRUPTIBLE);
            add_wait_queue(&cfi->chips[chipnum].wq, &wait);

            spin_unlock(cfi->chips[chipnum].mutex);

            schedule();
            remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
#if 0
            if(signal_pending(current))
                return -EINTR;
#endif
            goto retry;
        }

        /* Load 'tmp_buf' with old contents of flash */
        tmp_buf = map_read(map, bus_ofs+chipstart);

        spin_unlock(cfi->chips[chipnum].mutex);

        /* Number of bytes to copy from buffer */
        n = min_t(int, len, map_bankwidth(map)-i);

        tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);

        ret = do_write_oneword(map, &cfi->chips[chipnum],
                       bus_ofs, tmp_buf);
        if (ret)
            return ret;

        ofs += n;
        buf += n;
        (*retlen) += n;
        len -= n;

        if (ofs >> cfi->chipshift) {
            chipnum ++;
            ofs = 0;
            if (chipnum == cfi->numchips)
                return 0;
        }
    }

    /* We are now aligned, write as much as possible */
    while(len >= map_bankwidth(map)) {
        map_word datum;

        datum = map_word_load(map, buf);

        ret = do_write_oneword(map, &cfi->chips[chipnum],
                       ofs, datum);
        if (ret)
            return ret;

        ofs += map_bankwidth(map);
        buf += map_bankwidth(map);
        (*retlen) += map_bankwidth(map);
        len -= map_bankwidth(map);

        if (ofs >> cfi->chipshift) {
            chipnum ++;
            ofs = 0;
            if (chipnum == cfi->numchips)
                return 0;
            chipstart = cfi->chips[chipnum].start;
        }
    }

    /* Write the trailing bytes if any */
    if (len & (map_bankwidth(map)-1)) {
        map_word tmp_buf;

 retry1:
        spin_lock(cfi->chips[chipnum].mutex);

        if (cfi->chips[chipnum].state != FL_READY) {
#if 0
            printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
#endif
            set_current_state(TASK_UNINTERRUPTIBLE);
            add_wait_queue(&cfi->chips[chipnum].wq, &wait);

            spin_unlock(cfi->chips[chipnum].mutex);

            schedule();
            remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
#if 0
            if(signal_pending(current))
                return -EINTR;
#endif
            goto retry1;
        }

        tmp_buf = map_read(map, ofs + chipstart);

        spin_unlock(cfi->chips[chipnum].mutex);

        tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);

        ret = do_write_oneword(map, &cfi->chips[chipnum],
                ofs, tmp_buf);
        if (ret)
            return ret;

        (*retlen) += len;
    }

    return 0;
}

阅读(949) | 评论(0) | 转发(0) |
0

上一篇:MTD源代码分析(三)

下一篇:mtdblock分析

给主人留下些什么吧!~~