line source
/*
* This module implements the flash program-bin command:
* programming flash using a binary file as the data source.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include "flash.h"
extern struct flash_bank_info flash_bank_info[2];
extern uint32_t crc32_table[];
flashcmd_progbin(argc, argv, bank)
char **argv;
{
struct flash_bank_info *bi;
u_long flashoff, fileoff, len, origlen, bytesdone;
u_long crc_base_addr, crc_from_target;
uint32_t crcaccum;
char *strtoul_endp;
FILE *binf;
struct stat filestat;
char *targv[4], shortarg[10], longarg[513];
u_char databuf[256];
int reclen, cc, i;
time_t curtime, last_time;
if (argc < 4 || argc > 6) {
inv: fprintf(stderr,
"usage: %s %s flash-offset binfile [file-offset [length]]\n",
argv[0], argv[1]);
return(-1);
}
flashoff = strtoul(argv[2], &strtoul_endp, 16);
if (*strtoul_endp)
goto inv;
if (flash_get_cfi(bank) < 0)
return(-1);
bi = flash_bank_info + bank;
if (flashoff >= bi->geom->total_size) {
fprintf(stderr,
"error: specified flash offset exceeds bank size (0x%lx)\n",
(u_long) bi->geom->total_size);
return(-1);
}
if (flashoff & 1) {
fprintf(stderr, "error: flash offset must be even\n");
return(-1);
}
binf = fopen(argv[3], "r");
if (!binf) {
perror(argv[3]);
return(-1);
}
fstat(fileno(binf), &filestat);
if (!S_ISREG(filestat.st_mode)) {
fprintf(stderr, "%s is not a regular file\n", argv[3]);
fclose(binf);
return(-1);
}
if (argc > 4) {
fileoff = strtoul(argv[4], &strtoul_endp, 16);
if (*strtoul_endp) {
fclose(binf);
goto inv;
}
if (fileoff > filestat.st_size) {
fprintf(stderr,
"error: specified file offset exceeds file length\n");
fclose(binf);
return(-1);
}
} else
fileoff = 0;
if (argc > 5) {
len = strtoul(argv[5], &strtoul_endp, 16);
if (*strtoul_endp) {
fclose(binf);
goto inv;
}
if (len > filestat.st_size - fileoff) {
fprintf(stderr,
"error: specified file offset+length exceed file length\n");
fclose(binf);
return(-1);
}
} else
len = filestat.st_size - fileoff;
if (!len) {
printf("Length is zero - nothing to do!\n");
fclose(binf);
return(0);
}
if (len > bi->geom->total_size - flashoff) {
fprintf(stderr,
"error: specified flash offset+length exceed bank size (0x%lx)\n",
(u_long) bi->geom->total_size);
fclose(binf);
return(-1);
}
if (len & 1) {
fprintf(stderr, "error: program length must be even\n");
fclose(binf);
return(-1);
}
/* finally done with the arg parsing etc, can get to work now */
if (flash_id_check(bank, 0) < 0) {
fclose(binf);
return(-1);
}
crc_base_addr = bi->base_addr + flashoff;
sprintf(shortarg, "%lx", (u_long) bi->base_addr);
targv[0] = bi->ops->loadagent_setbase_cmd;
targv[1] = shortarg;
targv[2] = 0;
printf("Setting flash base address: %s %s\n", targv[0], targv[1]);
tpinterf_make_cmd(targv);
if (tpinterf_send_cmd() < 0) {
fclose(binf);
return(-1);
}
cc = tpinterf_pass_output(1);
if (cc) {
fclose(binf);
return(cc);
}
if (bi->ops->prep_for_program(bi) < 0) {
fclose(binf);
return(-1);
}
fseek(binf, fileoff, SEEK_SET);
targv[0] = bi->ops->loadagent_program_cmd;
targv[1] = shortarg;
targv[2] = longarg;
targv[3] = 0;
printf("Programming flash: %lu (0x%lx) bytes\n", len, len);
origlen = len;
bytesdone = 0;
last_time = 0;
crcaccum = 0xFFFFFFFF;
while (len) {
if (len >= 256)
reclen = 256;
else
reclen = len;
cc = fread(databuf, 1, reclen, binf);
if (cc != reclen) {
fclose(binf);
fprintf(stderr, "error reading from %s\n", argv[3]);
return(-1);
}
for (i = 0; i < reclen; i++) /* update running CRC */
crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i]]
^ (crcaccum >> 8);
sprintf(shortarg, "%lx", flashoff);
build_flashw_hex_string(databuf, longarg, reclen >> 1, 0);
tpinterf_make_cmd(targv);
if (tpinterf_send_cmd() < 0) {
fclose(binf);
return(-1);
}
i = tpinterf_pass_output(8); /* 8 s timeout */
if (i) {
fclose(binf);
return(i);
}
flashoff += reclen;
len -= reclen;
bytesdone += reclen;
cc = bytesdone * 100 / origlen;
time(&curtime);
if (curtime != last_time || cc == 100) {
printf("\r0x%lx bytes programmed (%i%%)",
bytesdone, cc);
fflush(stdout);
}
last_time = curtime;
}
putchar('\n');
fclose(binf);
/* reset flash to read mode */
if (bi->ops->reset_cmd(bi) < 0)
return(-1);
printf("Verifying CRC-32 of programmed flash area\n");
if (crc32_on_target(crc_base_addr, origlen, &crc_from_target) < 0)
return(-1);
if (crc_from_target == crcaccum) {
printf("match (%08lX)\n", crc_from_target);
return(0);
} else {
fprintf(stderr, "error: CRC mismatch!\n");
return(-1);
}
}