📄 cfi_cmdset_0001.c
字号:
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long ofs; int chipnum; int ret = 0; if (!map->virt || (from + len > mtd->size)) return -EINVAL; *mtdbuf = (void *)map->virt + from; *retlen = 0; /* Now lock the chip(s) to POINT state */ /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); while (len) { unsigned long thislen; if (chipnum >= cfi->numchips) break; if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else thislen = len; ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen); if (ret) break; *retlen += thislen; len -= thislen; ofs = 0; chipnum++; } return 0;}static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long ofs; int chipnum; /* Now unlock the chip(s) POINT state */ /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); while (len) { unsigned long thislen; struct flchip *chip; chip = &cfi->chips[chipnum]; if (chipnum >= cfi->numchips) break; if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else thislen = len; spin_lock(chip->mutex); if (chip->state == FL_POINT) { chip->ref_point_counter--; if(chip->ref_point_counter == 0) chip->state = FL_READY; } else printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ put_chip(map, chip, chip->start); spin_unlock(chip->mutex); len -= thislen; ofs = 0; chipnum++; }}static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){ unsigned long cmd_addr; struct cfi_private *cfi = map->fldrv_priv; int ret; adr += chip->start; /* Ensure cmd read/writes are aligned. */ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); if (ret) { spin_unlock(chip->mutex); return ret; } if (chip->state != FL_POINT && chip->state != FL_READY) { cfi_write(map, CMD(0xff), cmd_addr); chip->state = FL_READY; } map_copy_from(map, buf, adr, len); put_chip(map, chip, cmd_addr); spin_unlock(chip->mutex); return 0;}static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long ofs; int chipnum; int ret = 0; /* ofs: offset within the first chip that the first read should start */ chipnum = (from >> cfi->chipshift); ofs = from - (chipnum << cfi->chipshift); *retlen = 0; while (len) { unsigned long thislen; if (chipnum >= cfi->numchips) break; if ((len + ofs -1) >> cfi->chipshift) thislen = (1<<cfi->chipshift) - ofs; else thislen = len; ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); if (ret) break; *retlen += thislen; len -= thislen; buf += thislen; ofs = 0; chipnum++; } return ret;}static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; struct flchip *chip; int ofs_factor = cfi->interleave * cfi->device_type; int count = len; int chip_num, offst; int ret; chip_num = ((unsigned int)from/reg_sz); offst = from - (reg_sz*chip_num)+base_offst; while (count) { /* Calculate which chip & protection register offset we need */ if (chip_num >= cfi->numchips) goto out; chip = &cfi->chips[chip_num]; spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); if (ret) { spin_unlock(chip->mutex); return (len-count)?:ret; } if (chip->state != FL_JEDEC_QUERY) { cfi_write(map, CMD(0x90), chip->start); chip->state = FL_JEDEC_QUERY; } while (count && ((offst-base_offst) < reg_sz)) { *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); buf++; offst++; count--; } put_chip(map, chip, chip->start); spin_unlock(chip->mutex); /* Move on to the next chip */ chip_num++; offst = base_offst; } out: return len-count;} static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp=cfi->cmdset_priv; int base_offst,reg_sz; /* Check that we actually have some protection registers */ if(!(extp->FeatureSupport&64)){ printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); return 0; } base_offst=(1<<extp->FactProtRegSize); reg_sz=(1<<extp->UserProtRegSize); return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp=cfi->cmdset_priv; int base_offst,reg_sz; /* Check that we actually have some protection registers */ if(!(extp->FeatureSupport&64)){ printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); return 0; } base_offst=0; reg_sz=(1<<extp->FactProtRegSize); return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);}static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum){ struct cfi_private *cfi = map->fldrv_priv; cfi_word status, status_OK; unsigned long timeo; int z, ret=0; adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { spin_unlock(chip->mutex); return ret; } ENABLE_VPP(map); cfi_write(map, CMD(0x40), adr); cfi_write(map, datum, adr); chip->state = FL_WRITING; spin_unlock(chip->mutex); cfi_udelay(chip->word_write_time); spin_lock(chip->mutex); timeo = jiffies + (HZ/2); z = 0; for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ spin_lock(chip->mutex); continue; } status = cfi_read(map, adr); if ((status & status_OK) == status_OK) break; /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); ret = -EIO; goto out; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock(chip->mutex); z++; cfi_udelay(1); spin_lock(chip->mutex); } if (!z) { chip->word_write_time--; if (!chip->word_write_time) chip->word_write_time++; } if (z > 1) chip->word_write_time++; /* Done and happy. */ chip->state = FL_STATUS; /* check for lock bit */ if (status & CMD(0x02)) { /* clear status */ cfi_write(map, CMD(0x50), adr); /* put back into read status register mode */ cfi_write(map, CMD(0x70), adr); ret = -EROFS; } out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_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; *retlen = 0; if (!len) return 0; chipnum = to >> cfi->chipshift; ofs = to - (chipnum << cfi->chipshift); /* If it's not bus-aligned, do the first byte write */ if (ofs & (CFIDEV_BUSWIDTH-1)) { unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); int gap = ofs - bus_ofs; int i = 0, n = 0; u_char tmp_buf[8]; cfi_word datum; while (gap--) tmp_buf[i++] = 0xff; while (len && i < CFIDEV_BUSWIDTH) tmp_buf[i++] = buf[n++], len--; while (i < CFIDEV_BUSWIDTH) tmp_buf[i++] = 0xff; if (cfi_buswidth_is_2()) { datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; } else if (cfi_buswidth_is_8()) { datum = *(__u64*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, datum); if (ret) return ret; ofs += n; buf += n; (*retlen) += n; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } while(len >= CFIDEV_BUSWIDTH) { cfi_word datum; if (cfi_buswidth_is_1()) { datum = *(__u8*)buf; } else if (cfi_buswidth_is_2()) { datum = *(__u16*)buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)buf; } else if (cfi_buswidth_is_8()) { datum = *(__u64*)buf; } else { return -EINVAL; } ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum); if (ret) return ret; ofs += CFIDEV_BUSWIDTH; buf += CFIDEV_BUSWIDTH; (*retlen) += CFIDEV_BUSWIDTH; len -= CFIDEV_BUSWIDTH; if (ofs >> cfi->chipshift) { chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } if (len & (CFIDEV_BUSWIDTH-1)) { int i = 0, n = 0; u_char tmp_buf[8]; cfi_word datum; while (len--) tmp_buf[i++] = buf[n++]; while (i < CFIDEV_BUSWIDTH) tmp_buf[i++] = 0xff; if (cfi_buswidth_is_2()) { datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; } else if (cfi_buswidth_is_8()) { datum = *(__u64*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum); if (ret) return ret; (*retlen) += n; } return 0;}static inline int do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const u_char *buf, int len){ struct cfi_private *cfi = map->fldrv_priv; cfi_word status, status_OK; unsigned long cmd_adr, timeo; int wbufsize, z, ret=0, bytes, words; wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; adr += chip->start; cmd_adr = adr & ~(wbufsize-1); /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_adr, FL_WRITING); if (ret) { spin_unlock(chip->mutex); return ret; } if (chip->state != FL_STATUS) cfi_write(map, CMD(0x70), cmd_adr); status = cfi_read(map, cmd_adr); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -