static int write_block(MtdWriteContext *ctx, const char *data) { const MtdPartition *partition = ctx->partition; int fd = ctx->fd; off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) return 1; ssize_t size = partition->erase_size; char *verify = malloc(size); if (verify == NULL) return 1; while (pos + size <= (int) partition->size) { loff_t bpos = pos; int ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) { add_bad_block_offset(ctx, pos); fprintf(stderr, "mtd: not writing bad block at 0x%08lx (ret %d errno %d)\n", pos, ret, errno); pos += partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { #ifdef RK3066 if (rk30_zero_out(fd, pos, size) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #else if (ioctl(fd, MEMERASE, &erase_info) < 0) { printf("mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #endif if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { printf("mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; if (lseek(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { printf("mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (memcmp(data, verify, size) != 0) { printf("mtd: verification error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { printf("mtd: wrote block after %d retries\n", retry); } printf("mtd: successfully wrote block at %lx\n", pos); free(verify); return 0; // Success! } // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); printf("mtd: skipping write block at 0x%08lx\n", pos); #ifdef RK3066 rk30_zero_out(fd, pos, size); #else ioctl(fd, MEMERASE, &erase_info); #endif pos += partition->erase_size; } free(verify); // Ran out of space on the device errno = ENOSPC; return -1; }
int mtd_write_block_ex(MtdWriteContext *ctx, const char *data, off64_t addr) { const MtdPartition *partition = ctx->partition; int fd = ctx->fd; off64_t pos = lseek64(fd, addr, SEEK_SET); if (pos == (off64_t) -1) return 1; fprintf(stdout, "[%s] addr=0x%X, pos=0x%X, erase=0x%X\n", __func__, (int) addr, (int) pos, partition->erase_size); ssize_t size = partition->erase_size; while (pos + size <= (int) partition->size) { off64_t bpos = pos; if (ioctl(fd, MEMGETBADBLOCK, &bpos) > 0) { add_bad_block_offset(ctx, pos); fprintf(stderr, "mtd: not writing bad block at 0x%08llx\n", pos); pos += partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { fprintf(stdout, "[%s] erase\n", __func__); if (ioctl(fd, MEMERASE, &erase_info) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08llx (%s)\n", pos, strerror(errno)); continue; } fprintf(stdout, "[%s] write\n", __func__); if (lseek64(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { fprintf(stderr, "mtd: write error at 0x%08llx (%s)\n", pos, strerror(errno)); } char verify[size]; fprintf(stdout, "[%s] read back\n", __func__); if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { fprintf(stderr, "mtd: re-read error at 0x%08llx (%s)\n", pos, strerror(errno)); continue; } fprintf(stdout, "[%s] compare : %X %X %X %X %X %X %X %X\n", __func__, verify[0], verify[1], verify[2], verify[3], verify[4], verify[5], verify[6], verify[7]); if (memcmp(data, verify, size) != 0) { fprintf(stderr, "mtd: verification error at 0x%08llx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { fprintf(stderr, "mtd: wrote block after %d retries\n", retry); } return 0; // Success! } fprintf(stdout, "[%s] write next\n", __func__); // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); fprintf(stderr, "mtd: skipping write block at 0x%08llx\n", pos); ioctl(fd, MEMERASE, &erase_info); pos += partition->erase_size; } // Ran out of space on the device errno = ENOSPC; return -1; }