change indent style..

This commit is contained in:
Olaf Rempel 2017-03-07 20:09:48 +01:00
parent 84b8ddd1f5
commit 5ab1e36fc7
8 changed files with 1384 additions and 524 deletions

View File

@ -27,26 +27,35 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
struct chipinfo { struct chipinfo
{
uint8_t sig[3]; uint8_t sig[3];
const char name[16]; const char name[16];
}; };
static struct chipinfo chips[] = { static struct chipinfo chips[] =
{
{ { 0x1E, 0x93, 0x07 }, "AVR Mega 8" }, { { 0x1E, 0x93, 0x07 }, "AVR Mega 8" },
{ { 0x1E, 0x93, 0x0A }, "AVR Mega 88" }, { { 0x1E, 0x93, 0x0A }, "AVR Mega 88" },
{ { 0x1E, 0x94, 0x06 }, "AVR Mega 168" }, { { 0x1E, 0x94, 0x06 }, "AVR Mega 168" },
{ { 0x1E, 0x95, 0x02 }, "AVR Mega 32" }, { { 0x1E, 0x95, 0x02 }, "AVR Mega 32" },
}; };
/* *************************************************************************
* chipinfo_get_avr_name
* ************************************************************************* */
const char * chipinfo_get_avr_name(const uint8_t *sig) const char * chipinfo_get_avr_name(const uint8_t *sig)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(chips); i++) {
for (i = 0; i < ARRAY_SIZE(chips); i++)
{
struct chipinfo *chip = &chips[i]; struct chipinfo *chip = &chips[i];
if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2]) if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2])
{
return chip->name; return chip->name;
}
} }
return "unknown"; return "unknown";
} } /* chipinfo_get_avr_name */

View File

@ -31,10 +31,14 @@
#define FILETYPE_BINARY 1 #define FILETYPE_BINARY 1
#define FILETYPE_INTELHEX 2 #define FILETYPE_INTELHEX 2
/* *************************************************************************
* dbuf_alloc
* ************************************************************************* */
struct databuf * dbuf_alloc(uint32_t size) struct databuf * dbuf_alloc(uint32_t size)
{ {
struct databuf *dbuf = malloc(sizeof(struct databuf) + size); struct databuf *dbuf = malloc(sizeof(struct databuf) + size);
if (dbuf == NULL) { if (dbuf == NULL)
{
perror("dbuf_alloc"); perror("dbuf_alloc");
return NULL; return NULL;
} }
@ -43,71 +47,108 @@ struct databuf * dbuf_alloc(uint32_t size)
dbuf->size = size; dbuf->size = size;
dbuf->length = 0; dbuf->length = 0;
return dbuf; return dbuf;
} } /* dbuf_alloc */
/* *************************************************************************
* dbuf_free
* ************************************************************************* */
void dbuf_free(struct databuf *dbuf) void dbuf_free(struct databuf *dbuf)
{ {
free(dbuf); free(dbuf);
} } /* dbuf_free */
/* *************************************************************************
* dbuf_dump
* ************************************************************************* */
static void dbuf_dump(struct databuf *dbuf) static void dbuf_dump(struct databuf *dbuf)
{ {
int pos = 0, oldskip = 0; int pos = 0, oldskip = 0;
while (pos < dbuf->length) { while (pos < dbuf->length)
{
char buf[128]; char buf[128];
int j, i = 0; int j, i = 0;
int skip = 1; int skip = 1;
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++)
{
if (pos + j < dbuf->length) if (pos + j < dbuf->length)
{
i += sprintf(buf + i, "%02X", dbuf->data[pos + j]); i += sprintf(buf + i, "%02X", dbuf->data[pos + j]);
else } else {
i += sprintf(buf + i, " "); i += sprintf(buf + i, " ");
}
if (j % 2) if (j % 2)
buf[i++] = ' '; {
}
for (j = 0; j < 16; j++) {
if (pos + j < dbuf->length) {
unsigned char val = dbuf->data[pos + j];
if (val >= 0x20 && val < 0x7F)
buf[i++] = val;
else
buf[i++] = '.';
if (val != 0xFF)
skip = 0;
} else {
buf[i++] = ' '; buf[i++] = ' ';
} }
} }
if (pos == 0 || (pos + 16) >= dbuf->length || skip == 0) { for (j = 0; j < 16; j++)
{
if (pos + j < dbuf->length)
{
unsigned char val = dbuf->data[pos + j];
if (val >= 0x20 && val < 0x7F)
{
buf[i++] = val;
} else {
buf[i++] = '.';
}
if (val != 0xFF)
{
skip = 0;
}
}
else
{
buf[i++] = ' ';
}
}
if ((pos == 0) ||
((pos + 16) >= dbuf->length) ||
(skip == 0)
)
{
buf[i++] = '\0'; buf[i++] = '\0';
printf("%04X: %s\r\n", pos, buf); printf("%04X: %s\r\n", pos, buf);
oldskip = 0; oldskip = 0;
} else if (skip == 1 && oldskip == 0) { }
else if ((skip == 1) &&
(oldskip == 0)
)
{
printf("****\n"); printf("****\n");
oldskip = 1; oldskip = 1;
} }
pos += 16; pos += 16;
} }
} } /* dbuf_dump */
/* *************************************************************************
* binfile_getsize
* ************************************************************************* */
static int binfile_getsize(const char *filename, uint32_t *size) static int binfile_getsize(const char *filename, uint32_t *size)
{ {
int fd = open(filename, O_RDONLY); int fd = open(filename, O_RDONLY);
if (fd < 0) { if (fd < 0)
{
perror("binfile_getsize(): open()"); perror("binfile_getsize(): open()");
return -1; return -1;
} }
struct stat filestat; struct stat filestat;
if (fstat(fd, &filestat) < 0) { if (fstat(fd, &filestat) < 0)
{
perror("binfile_getsize(): fstat()"); perror("binfile_getsize(): fstat()");
close(fd); close(fd);
return -1; return -1;
@ -117,18 +158,24 @@ static int binfile_getsize(const char *filename, uint32_t *size)
close(fd); close(fd);
return 0; return 0;
} } /* binfile_getsize */
/* *************************************************************************
* binfile_read
* ************************************************************************* */
static int binfile_read(const char *filename, struct databuf *dbuf) static int binfile_read(const char *filename, struct databuf *dbuf)
{ {
int fd = open(filename, O_RDONLY); int fd = open(filename, O_RDONLY);
if (fd < 0) { if (fd < 0)
{
perror("binfile_read(): open()"); perror("binfile_read(): open()");
return -1; return -1;
} }
ssize_t readsize = read(fd, dbuf->data, dbuf->size); ssize_t readsize = read(fd, dbuf->data, dbuf->size);
if (readsize <= 0) { if (readsize <= 0)
{
perror("binfile_read(): read()"); perror("binfile_read(): read()");
close(fd); close(fd);
return -1; return -1;
@ -138,18 +185,24 @@ static int binfile_read(const char *filename, struct databuf *dbuf)
close(fd); close(fd);
return 0; return 0;
} } /* binfile_read */
/* *************************************************************************
* binfile_write
* ************************************************************************* */
static int binfile_write(const char *filename, struct databuf *dbuf) static int binfile_write(const char *filename, struct databuf *dbuf)
{ {
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) { if (fd < 0)
{
perror("binfile_write(): open()"); perror("binfile_write(): open()");
return -1; return -1;
} }
ssize_t writesize = write(fd, dbuf->data, dbuf->length); ssize_t writesize = write(fd, dbuf->data, dbuf->length);
if (writesize != dbuf->length) { if (writesize != dbuf->length)
{
perror("binfile_write(): write()"); perror("binfile_write(): write()");
close(fd); close(fd);
return -1; return -1;
@ -157,9 +210,11 @@ static int binfile_write(const char *filename, struct databuf *dbuf)
close(fd); close(fd);
return 0; return 0;
} } /* binfile_write */
struct ihex_record {
struct ihex_record
{
uint8_t byte_count; uint8_t byte_count;
uint16_t address; uint16_t address;
uint8_t type; uint8_t type;
@ -168,46 +223,61 @@ struct ihex_record {
uint8_t chksum; uint8_t chksum;
}; };
/* *************************************************************************
* hex2byte
* ************************************************************************* */
static uint8_t hex2byte(const char *ptr) static uint8_t hex2byte(const char *ptr)
{ {
int i; int i;
uint8_t result = 0; uint8_t result = 0;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++)
{
result <<= 4; result <<= 4;
result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0') : result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0')
(((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A) : : (((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A)
0x00); : 0x00);
} }
return result; return result;
} } /* hex2byte */
/* *************************************************************************
* hexfile_getrecord
* ************************************************************************* */
static int hexfile_getrecord(FILE *stream, struct ihex_record *record) static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
{ {
char *hexline = NULL; char *hexline = NULL;
size_t size; size_t size;
ssize_t length = getline(&hexline, &size, stream); ssize_t length = getline(&hexline, &size, stream);
if (length == -1) { if (length == -1)
if (!feof(stream)) { {
if (!feof(stream))
{
perror("hexfile_getrecord(): getline()"); perror("hexfile_getrecord(): getline()");
} }
return -1; return -1;
} }
if (length < 12) { if (length < 12)
fprintf(stderr, "record too short (%d)\n", length); {
fprintf(stderr, "record too short (%ld)\n", length);
free(hexline); free(hexline);
return -1; return -1;
} }
int pos = 0; int pos = 0;
if (hexline[pos] != ':') { if (hexline[pos] != ':')
{
fprintf(stderr, "invalid startcode\n"); fprintf(stderr, "invalid startcode\n");
free(hexline); free(hexline);
return -1; return -1;
} }
pos++; pos++;
uint8_t chksum = 0x00; uint8_t chksum = 0x00;
@ -216,9 +286,11 @@ static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
chksum += record->byte_count; chksum += record->byte_count;
pos += 2; pos += 2;
if (record->byte_count > 0) { if (record->byte_count > 0)
{
record->data = malloc(record->byte_count); record->data = malloc(record->byte_count);
if (record->data == NULL) { if (record->data == NULL)
{
perror("hexfile_getrecord(): malloc()"); perror("hexfile_getrecord(): malloc()");
free(hexline); free(hexline);
return -1; return -1;
@ -236,7 +308,8 @@ static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
pos += 2; pos += 2;
int i; int i;
for (i = 0; i < record->byte_count; i++) { for (i = 0; i < record->byte_count; i++)
{
record->data[i] = hex2byte(&hexline[pos]); record->data[i] = hex2byte(&hexline[pos]);
chksum += record->data[i]; chksum += record->data[i];
pos += 2; pos += 2;
@ -246,18 +319,26 @@ static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
chksum += record->chksum; chksum += record->chksum;
pos += 2; pos += 2;
if (chksum != 0x00) { if (chksum != 0x00)
{
fprintf(stderr, "invalid checksum (0x%02X)\n", chksum); fprintf(stderr, "invalid checksum (0x%02X)\n", chksum);
if (record->byte_count > 0) if (record->byte_count > 0)
{
free(record->data); free(record->data);
}
free(hexline); free(hexline);
return -1; return -1;
} }
free(hexline); free(hexline);
return 0; return 0;
} } /* hexfile_getrecord */
/* *************************************************************************
* hexfile_putrecord
* ************************************************************************* */
static int hexfile_putrecord(FILE *stream, struct ihex_record *record) static int hexfile_putrecord(FILE *stream, struct ihex_record *record)
{ {
uint8_t chksum = record->byte_count; uint8_t chksum = record->byte_count;
@ -269,39 +350,62 @@ static int hexfile_putrecord(FILE *stream, struct ihex_record *record)
char buf[64]; char buf[64];
buf[0] = '\0'; buf[0] = '\0';
for (i = 0; i < record->byte_count; i++) { for (i = 0; i < record->byte_count; i++)
{
len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]); len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]);
chksum += record->data[i]; chksum += record->data[i];
} }
fprintf(stream, ":%02X%04X%02X%s%02X\n", record->byte_count, record->address, record->type, buf, (uint8_t)(0x100 - chksum)); fprintf(stream, ":%02X%04X%02X%s%02X\n",
return -1; record->byte_count,
} record->address,
record->type,
buf,
(uint8_t)(0x100 - chksum));
return -1;
} /* hexfile_putrecord */
/* *************************************************************************
* hexfile_getsize
* ************************************************************************* */
static int hexfile_getsize(const char *filename, uint32_t *size) static int hexfile_getsize(const char *filename, uint32_t *size)
{ {
*size = 0x10000; *size = 0x10000;
return 0; return 0;
} } /* hexfile_getsize */
/* *************************************************************************
* hexfile_read
* ************************************************************************* */
static int hexfile_read(const char *filename, struct databuf *dbuf) static int hexfile_read(const char *filename, struct databuf *dbuf)
{ {
FILE *stream = fopen(filename, "r"); FILE *stream = fopen(filename, "r");
if (stream == NULL) { if (stream == NULL)
{
perror("hexfile_read(): fopen()"); perror("hexfile_read(): fopen()");
return -1; return -1;
} }
while (1) { while (1)
{
struct ihex_record record; struct ihex_record record;
memset(&record, 0x00, sizeof(struct ihex_record)); memset(&record, 0x00, sizeof(struct ihex_record));
int result = hexfile_getrecord(stream, &record); int result = hexfile_getrecord(stream, &record);
if (result == -1) if (result == -1)
{
break; break;
}
if (record.type == 0x00) { if (record.type == 0x00)
if (record.address > dbuf->size || record.address + record.byte_count > dbuf->size) { {
if ((record.address > dbuf->size) ||
(record.address + record.byte_count > dbuf->size)
)
{
fprintf(stderr, "hexfile_read(): data out of bounds\n"); fprintf(stderr, "hexfile_read(): data out of bounds\n");
break; break;
} }
@ -313,12 +417,17 @@ static int hexfile_read(const char *filename, struct databuf *dbuf)
fclose(stream); fclose(stream);
return 0; return 0;
} } /* hexfile_read */
/* *************************************************************************
* hexfile_write
* ************************************************************************* */
static int hexfile_write(const char *filename, struct databuf *dbuf) static int hexfile_write(const char *filename, struct databuf *dbuf)
{ {
FILE *stream = fopen(filename, "w"); FILE *stream = fopen(filename, "w");
if (stream == NULL) { if (stream == NULL)
{
perror("hexfile_write(): fopen()"); perror("hexfile_write(): fopen()");
return -1; return -1;
} }
@ -326,21 +435,30 @@ static int hexfile_write(const char *filename, struct databuf *dbuf)
int i; int i;
int addr_min = dbuf->length; int addr_min = dbuf->length;
int addr_max = 0; int addr_max = 0;
for (i = 0; i < dbuf->length; i++) { for (i = 0; i < dbuf->length; i++)
{
if (dbuf->data[i] == 0xFF) if (dbuf->data[i] == 0xFF)
{
continue; continue;
}
if (addr_min > i) if (addr_min > i)
{
addr_min = i; addr_min = i;
}
if (addr_max < i) if (addr_max < i)
{
addr_max = i; addr_max = i;
}
} }
addr_min = addr_min & ~0x0F; addr_min = addr_min & ~0x0F;
addr_max = (addr_max + 0x0F) & ~0x0F; addr_max = (addr_max + 0x0F) & ~0x0F;
struct ihex_record record; struct ihex_record record;
for (i = addr_min; i < addr_max; i += 0x10) { for (i = addr_min; i < addr_max; i += 0x10)
{
record.byte_count = 0x10; record.byte_count = 0x10;
record.address = i; record.address = i;
record.type = 0x00; record.type = 0x00;
@ -357,67 +475,93 @@ static int hexfile_write(const char *filename, struct databuf *dbuf)
fclose(stream); fclose(stream);
return 0; return 0;
} } /* hexfile_write */
/* *************************************************************************
* get_filetype
* ************************************************************************* */
static int get_filetype(const char *filename) static int get_filetype(const char *filename)
{ {
const char *ext = filename + (strlen(filename) -4); const char *ext = filename + (strlen(filename) -4);
if (ext < filename) if (ext < filename)
{
return FILETYPE_UNKNOWN; return FILETYPE_UNKNOWN;
}
if (strncmp(ext, ".bin", 4) == 0) if (strncmp(ext, ".bin", 4) == 0)
{
return FILETYPE_BINARY; return FILETYPE_BINARY;
}
if (strncmp(ext, ".hex", 4) == 0) if (strncmp(ext, ".hex", 4) == 0)
{
return FILETYPE_INTELHEX; return FILETYPE_INTELHEX;
}
return FILETYPE_UNKNOWN; return FILETYPE_UNKNOWN;
} } /* get_filetype */
/* *************************************************************************
* file_getsize
* ************************************************************************* */
int file_getsize(const char *filename, uint32_t *size) int file_getsize(const char *filename, uint32_t *size)
{ {
switch (get_filetype(filename)) { switch (get_filetype(filename))
case FILETYPE_BINARY: {
return binfile_getsize(filename, size); case FILETYPE_BINARY:
return binfile_getsize(filename, size);
case FILETYPE_INTELHEX: case FILETYPE_INTELHEX:
return hexfile_getsize(filename, size); return hexfile_getsize(filename, size);
default: default:
return -1; return -1;
} }
} } /* file_getsize */
/* *************************************************************************
* file_read
* ************************************************************************* */
int file_read(const char *filename, struct databuf *dbuf) int file_read(const char *filename, struct databuf *dbuf)
{ {
switch (get_filetype(filename)) { switch (get_filetype(filename))
case FILETYPE_BINARY: {
return binfile_read(filename, dbuf); case FILETYPE_BINARY:
return binfile_read(filename, dbuf);
case FILETYPE_INTELHEX: case FILETYPE_INTELHEX:
return hexfile_read(filename, dbuf); return hexfile_read(filename, dbuf);
default: default:
return -1; return -1;
} }
} } /* file_read */
/* *************************************************************************
* file_write
* ************************************************************************* */
int file_write(const char *filename, struct databuf *dbuf) int file_write(const char *filename, struct databuf *dbuf)
{ {
if (strncmp(filename, "-", 1) == 0) { if (strncmp(filename, "-", 1) == 0)
{
dbuf_dump(dbuf); dbuf_dump(dbuf);
return 0; return 0;
} }
switch (get_filetype(filename)) { switch (get_filetype(filename))
case FILETYPE_BINARY: {
return binfile_write(filename, dbuf); case FILETYPE_BINARY:
return binfile_write(filename, dbuf);
case FILETYPE_INTELHEX: case FILETYPE_INTELHEX:
return hexfile_write(filename, dbuf); return hexfile_write(filename, dbuf);
default: default:
return -1; return -1;
} }
} } /* file_write */

444
funk.c
View File

@ -124,7 +124,8 @@ struct rfm12_pkt
struct multiboot_ops funk_ops; struct multiboot_ops funk_ops;
struct funk_privdata { struct funk_privdata
{
char *device; char *device;
int fd; int fd;
int connected; int connected;
@ -141,30 +142,35 @@ struct funk_privdata {
}; };
static struct option funk_optargs[] = { static struct option funk_optargs[] =
{"address", 1, 0, 'a'}, /* -a <addr> */ {
{"device", 1, 0, 'd'}, /* [ -d <device> ] */ { "address", 1, 0, 'a'}, /* -a <addr> */
{ "device", 1, 0, 'd'}, /* [ -d <device> ] */
}; };
/* *************************************************************************
* funk_optarg_cb
* ************************************************************************* */
static int funk_optarg_cb(int val, const char *arg, void *privdata) static int funk_optarg_cb(int val, const char *arg, void *privdata)
{ {
struct funk_privdata *funk = (struct funk_privdata *)privdata; struct funk_privdata *funk = (struct funk_privdata *)privdata;
switch (val) { switch (val)
case 'a': /* address */ {
{ case 'a': /* address */
char *endptr; {
funk->address = strtol(arg, &endptr, 16); char *endptr;
if (*endptr != '\0' || funk->address < 0x00 || funk->address > 0xFF) {
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */ funk->address = strtol(arg, &endptr, 16);
{ if (*endptr != '\0' || funk->address < 0x00 || funk->address > 0xFF) {
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */
if (funk->device != NULL) { if (funk->device != NULL) {
fprintf(stderr, "invalid device: '%s'\n", optarg); fprintf(stderr, "invalid device: '%s'\n", optarg);
return -1; return -1;
@ -175,11 +181,10 @@ static int funk_optarg_cb(int val, const char *arg, void *privdata)
perror("strdup()"); perror("strdup()");
return -1; return -1;
} }
} break;
break;
case 'h': case 'h':
case '?': /* error */ case '?': /* error */
fprintf(stderr, "Usage: funkboot [options]\n" fprintf(stderr, "Usage: funkboot [options]\n"
" -a <address> - selects rfm12 address (0x00 - 0xFF)\n" " -a <address> - selects rfm12 address (0x00 - 0xFF)\n"
" -d <device> - selects funkbridge device\n" " -d <device> - selects funkbridge device\n"
@ -192,25 +197,31 @@ static int funk_optarg_cb(int val, const char *arg, void *privdata)
"\n"); "\n");
return -1; return -1;
default: default:
return 1; return 1;
} }
return 0; return 0;
} /* funk_optarg_cb */ } /* funk_optarg_cb */
/* *************************************************************************
* funk_alloc
* ************************************************************************* */
static struct multiboot * funk_alloc(void) static struct multiboot * funk_alloc(void)
{ {
struct multiboot * mboot = malloc(sizeof(struct multiboot)); struct multiboot * mboot = malloc(sizeof(struct multiboot));
if (mboot == NULL) if (mboot == NULL)
{
return NULL; return NULL;
}
memset(mboot, 0x00, sizeof(struct multiboot)); memset(mboot, 0x00, sizeof(struct multiboot));
mboot->ops = &funk_ops; mboot->ops = &funk_ops;
struct funk_privdata *funk = malloc(sizeof(struct funk_privdata)); struct funk_privdata *funk = malloc(sizeof(struct funk_privdata));
if (funk == NULL) { if (funk == NULL)
{
free(mboot); free(mboot);
return NULL; return NULL;
} }
@ -226,55 +237,78 @@ static struct multiboot * funk_alloc(void)
} /* funk_alloc */ } /* funk_alloc */
/* *************************************************************************
* funk_free
* ************************************************************************* */
static void funk_free(struct multiboot *mboot) static void funk_free(struct multiboot *mboot)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
if (funk->device != NULL) if (funk->device != NULL)
{
free(funk->device); free(funk->device);
}
free(funk); free(funk);
free(mboot); free(mboot);
} /* funk_free */ } /* funk_free */
static int funk_get_memtype(struct multiboot *mboot, const char *memname) /* *************************************************************************
* optarg_copy
* ************************************************************************* */
static int funk_get_memtype(struct multiboot *mboot,
const char *memname)
{ {
if (strcmp(memname, "flash") == 0) if (strcmp(memname, "flash") == 0)
{
return MEMTYPE_FLASH; return MEMTYPE_FLASH;
}
else if (strcmp(memname, "eeprom") == 0) else if (strcmp(memname, "eeprom") == 0)
{
return MEMTYPE_EEPROM; return MEMTYPE_EEPROM;
}
return -1; return -1;
} /* funk_get_memtype */ } /* funk_get_memtype */
static int funk_get_memsize(struct multiboot *mboot, int memtype) /* *************************************************************************
* optarg_copy
* ************************************************************************* */
static int funk_get_memsize(struct multiboot *mboot,
int memtype)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
if (!funk->connected) if (!funk->connected)
{
return 0; return 0;
}
switch (memtype) { switch (memtype)
case MEMTYPE_FLASH: {
return funk->flashsize; case MEMTYPE_FLASH:
return funk->flashsize;
case MEMTYPE_EEPROM: case MEMTYPE_EEPROM:
return funk->eepromsize; return funk->eepromsize;
default: default:
return 0; return 0;
} }
} /* funk_get_memsize */ } /* funk_get_memsize */
/* *************************************************************************
* funk_serial_read
* ************************************************************************* */
static int funk_serial_read(int fd, void *data, int size) static int funk_serial_read(int fd, void *data, int size)
{ {
int pos = 0; int pos = 0;
while (1) { while (1)
{
fd_set fdset; fd_set fdset;
struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 }; struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
@ -282,21 +316,29 @@ static int funk_serial_read(int fd, void *data, int size)
FD_SET(fd, &fdset); FD_SET(fd, &fdset);
int ret = select(fd +1, &fdset, NULL, NULL, &timeout); int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
if (ret == -1) { if (ret == -1)
{
perror("select"); perror("select");
return -1; return -1;
} else if (ret == 0) { }
else if (ret == 0)
{
break; break;
}
} else if (FD_ISSET(fd, &fdset)) { else if (FD_ISSET(fd, &fdset))
{
int len = read(fd, data + pos, size - pos); int len = read(fd, data + pos, size - pos);
if (len < 0) { if (len < 0)
{
return -1; return -1;
} else { }
else
{
pos += len; pos += len;
if (pos == size) { if (pos == size)
{
break; break;
} }
} }
@ -308,31 +350,48 @@ static int funk_serial_read(int fd, void *data, int size)
#if (FUNK_BRIDGE_DEBUG == 1) || (FUNK_PACKET_DEBUG == 1) #if (FUNK_BRIDGE_DEBUG == 1) || (FUNK_PACKET_DEBUG == 1)
/* *************************************************************************
* funk_print_data
* ************************************************************************* */
static char * funk_print_data(uint8_t *data, uint16_t length) static char * funk_print_data(uint8_t *data, uint16_t length)
{ {
int pos = 0, i = 0, j; int pos = 0, i = 0, j;
char *buf = malloc(length * 4 + 64); char *buf = malloc(length * 4 + 64);
while (pos < length) { while (pos < length)
{
i += sprintf(buf + i, "%04X: ", pos); i += sprintf(buf + i, "%04X: ", pos);
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++)
{
if (pos + j < length) if (pos + j < length)
{
i += sprintf(buf + i, "%02X", data[pos + j]); i += sprintf(buf + i, "%02X", data[pos + j]);
}
else else
{
i += sprintf(buf + i, " "); i += sprintf(buf + i, " ");
if (j % 2)
{
buf[i++] = ' ';
}
}
if (j % 2) for (j = 0; j < 16; j++)
buf[i++] = ' '; {
} if (pos + j < length)
{
for (j = 0; j < 16; j++) {
if (pos + j < length) {
unsigned char val = data[pos + j]; unsigned char val = data[pos + j];
if (val >= 0x20 && val < 0x80) if (val >= 0x20 && val < 0x80)
{
buf[i++] = val; buf[i++] = val;
}
else else
{
buf[i++] = '.'; buf[i++] = '.';
} else { }
}
else
{
buf[i++] = ' '; buf[i++] = ' ';
} }
} }
@ -348,16 +407,27 @@ static char * funk_print_data(uint8_t *data, uint16_t length)
#endif #endif
static int funk_bridge_send(struct funk_privdata *funk, uint8_t *header, uint8_t headerlength, uint8_t *data, uint8_t datalength) /* *************************************************************************
* funk_bridge_send
* ************************************************************************* */
static int funk_bridge_send(struct funk_privdata *funk,
uint8_t *header,
uint8_t headerlength,
uint8_t *data,
uint8_t datalength)
{ {
if (headerlength > 0) { if (headerlength > 0)
if (write(funk->fd, header, headerlength) != headerlength) { {
if (write(funk->fd, header, headerlength) != headerlength)
{
return -1; return -1;
} }
} }
if (datalength > 0) { if (datalength > 0)
if (write(funk->fd, data, datalength) != datalength) { {
if (write(funk->fd, data, datalength) != datalength)
{
return -1; return -1;
} }
} }
@ -372,7 +442,14 @@ static int funk_bridge_send(struct funk_privdata *funk, uint8_t *header, uint8_t
} /* funk_bridge_send */ } /* funk_bridge_send */
static int funk_bridge_recv(struct funk_privdata *funk, uint8_t command, uint8_t *cause, uint8_t *buffer, int buffersize) /* *************************************************************************
* funk_bridge_recv
* ************************************************************************* */
static int funk_bridge_recv(struct funk_privdata *funk,
uint8_t command,
uint8_t *cause,
uint8_t *buffer,
int buffersize)
{ {
uint8_t response[3]; uint8_t response[3];
int len; int len;
@ -384,45 +461,63 @@ static int funk_bridge_recv(struct funk_privdata *funk, uint8_t command, uint8_t
return -1; return -1;
} }
if (response[0] != command) { if (response[0] != command)
fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n", response[0], command); {
fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n",
response[0], command);
return -1; return -1;
} }
*cause = response[1]; *cause = response[1];
uint16_t length = response[2]; uint16_t length = response[2];
uint16_t bufferpos = 0; uint16_t bufferpos = 0;
while (length > 0) {
while (length > 0)
{
/* free space in output buffer? */ /* free space in output buffer? */
if ((bufferpos < buffersize) && (buffer != NULL)) { if ((bufferpos < buffersize) && (buffer != NULL))
{
uint16_t size = MIN(buffersize - bufferpos, length); uint16_t size = MIN(buffersize - bufferpos, length);
len = funk_serial_read(funk->fd, buffer + bufferpos, size); len = funk_serial_read(funk->fd, buffer + bufferpos, size);
if (len <= 0) { if (len <= 0)
fprintf(stderr, "short read() from device (%d != %d)\n", len, size); {
fprintf(stderr, "short read() from device (%d != %d)\n",
len, size);
return -1; return -1;
} }
bufferpos += len; bufferpos += len;
length -= len; length -= len;
}
} else { else
{
uint8_t dummy[256]; uint8_t dummy[256];
/* no space in output buffer, but device still sends data -> do dummy read */ /* no space in output buffer, but device still sends data -> do dummy read */
uint16_t size = MIN(sizeof(dummy), length); uint16_t size = MIN(sizeof(dummy), length);
len = funk_serial_read(funk->fd, dummy, size); len = funk_serial_read(funk->fd, dummy, size);
if (len <= 0) { if (len <= 0)
fprintf(stderr, "short read() from device (%d != %d)\n", len, size); {
fprintf(stderr, "short read() from device (%d != %d)\n",
len, size);
return -1; return -1;
} }
length -= len; length -= len;
} }
} }
#if (FUNK_BRIDGE_DEBUG == 1) #if (FUNK_BRIDGE_DEBUG == 1)
char *dump = funk_print_data(buffer, bufferpos); char *dump = funk_print_data(buffer, bufferpos);
printf("funk_bridge_recv() cmd=0x%02x cause=0x%02x length=0x%02x\n%s\n", command, *cause, length, dump); printf("funk_bridge_recv() cmd=0x%02x cause=0x%02x length=0x%02x\n%s\n",
command, *cause, length, dump);
free(dump); free(dump);
#endif #endif
@ -430,22 +525,33 @@ static int funk_bridge_recv(struct funk_privdata *funk, uint8_t command, uint8_t
} /* funk_bridge_recv */ } /* funk_bridge_recv */
static int funk_send_packet(struct funk_privdata *funk, struct rfm12_pkt *pkt, int length) /* *************************************************************************
* funk_send_packet
* ************************************************************************* */
static int funk_send_packet(struct funk_privdata *funk,
struct rfm12_pkt *pkt,
int length)
{ {
uint8_t request[] = { BRIDGE_CMD_TRANSMIT, length }; uint8_t request[] = { BRIDGE_CMD_TRANSMIT, length };
int ret = funk_bridge_send(funk, request, sizeof(request), (uint8_t *)pkt, length); int ret = funk_bridge_send(funk, request, sizeof(request), (uint8_t *)pkt, length);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = BRIDGE_CAUSE_SUCCESS; uint8_t cause = BRIDGE_CAUSE_SUCCESS;
ret = funk_bridge_recv(funk, request[0], &cause, NULL, 0); ret = funk_bridge_recv(funk, request[0], &cause, NULL, 0);
if (ret != 0) if (ret != 0)
{
return -1; return -1;
}
#if (FUNK_PACKET_DEBUG == 1) #if (FUNK_PACKET_DEBUG == 1)
char *dump = funk_print_data((uint8_t *)pkt, length); char *dump = funk_print_data((uint8_t *)pkt, length);
printf("funk_send_packet() cause=0x%02x length=0x%02x\n%s\n", cause, length, dump); printf("funk_send_packet() cause=0x%02x length=0x%02x\n%s\n",
cause, length, dump);
free(dump); free(dump);
#endif #endif
@ -453,18 +559,27 @@ static int funk_send_packet(struct funk_privdata *funk, struct rfm12_pkt *pkt, i
} /* funk_send_packet */ } /* funk_send_packet */
static int funk_recv_packet(struct funk_privdata *funk, struct rfm12_pkt *pkt, int *length) /* *************************************************************************
* funk_recv_packet
* ************************************************************************* */
static int funk_recv_packet(struct funk_privdata *funk,
struct rfm12_pkt *pkt,
int *length)
{ {
uint8_t request[] = { BRIDGE_CMD_RECEIVE, 0 }; uint8_t request[] = { BRIDGE_CMD_RECEIVE, 0 };
int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0); int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = BRIDGE_CAUSE_SUCCESS; uint8_t cause = BRIDGE_CAUSE_SUCCESS;
ret = funk_bridge_recv(funk, request[0], &cause, (uint8_t *)pkt, *length); ret = funk_bridge_recv(funk, request[0], &cause, (uint8_t *)pkt, *length);
if (ret < 0) if (ret < 0)
{
return -1; return -1;
}
*length = ret; *length = ret;
@ -478,18 +593,27 @@ static int funk_recv_packet(struct funk_privdata *funk, struct rfm12_pkt *pkt, i
} /* funk_recv_packet */ } /* funk_recv_packet */
static int funk_bridge_version(struct funk_privdata *funk, uint8_t *version, int size) /* *************************************************************************
* funk_bridge_version
* ************************************************************************* */
static int funk_bridge_version(struct funk_privdata *funk,
uint8_t *version,
int size)
{ {
uint8_t request[] = { BRIDGE_CMD_VERSION, 0 }; uint8_t request[] = { BRIDGE_CMD_VERSION, 0 };
int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0); int ret = funk_bridge_send(funk, request, sizeof(request), NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = BRIDGE_CAUSE_SUCCESS; uint8_t cause = BRIDGE_CAUSE_SUCCESS;
ret = funk_bridge_recv(funk, request[0], &cause, version, size); ret = funk_bridge_recv(funk, request[0], &cause, version, size);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
version[ret] = '\0'; version[ret] = '\0';
@ -497,6 +621,9 @@ static int funk_bridge_version(struct funk_privdata *funk, uint8_t *version, int
} /* funk_bridge_version */ } /* funk_bridge_version */
/* *************************************************************************
* funk_close_device
* ************************************************************************* */
static void funk_close_device(struct funk_privdata *funk) static void funk_close_device(struct funk_privdata *funk)
{ {
/* delay close() / tcsetattr() */ /* delay close() / tcsetattr() */
@ -507,15 +634,20 @@ static void funk_close_device(struct funk_privdata *funk)
} /* funk_close_device */ } /* funk_close_device */
/* *************************************************************************
* funk_open_device
* ************************************************************************* */
static int funk_open_device(struct funk_privdata *funk) static int funk_open_device(struct funk_privdata *funk)
{ {
funk->fd = open(funk->device, O_RDWR | O_NOCTTY | O_CLOEXEC); funk->fd = open(funk->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
if (funk->fd < 0) { if (funk->fd < 0)
{
perror("open()"); perror("open()");
return -1; return -1;
} }
if (tcgetattr(funk->fd, &funk->oldtio) < 0) { if (tcgetattr(funk->fd, &funk->oldtio) < 0)
{
perror("tcgetattr(oldtio)"); perror("tcgetattr(oldtio)");
close(funk->fd); close(funk->fd);
return -1; return -1;
@ -531,7 +663,8 @@ static int funk_open_device(struct funk_privdata *funk)
newtio.c_cc[VTIME] = 0; newtio.c_cc[VTIME] = 0;
int err = tcsetattr(funk->fd, TCSANOW, &newtio); int err = tcsetattr(funk->fd, TCSANOW, &newtio);
if (err < 0) { if (err < 0)
{
perror("tcsetattr(newtio)"); perror("tcsetattr(newtio)");
close(funk->fd); close(funk->fd);
return -1; return -1;
@ -542,7 +675,11 @@ static int funk_open_device(struct funk_privdata *funk)
} /* funk_open_device */ } /* funk_open_device */
static int funk_switch_application(struct funk_privdata *funk, uint8_t application) /* *************************************************************************
* funk_switch_application
* ************************************************************************* */
static int funk_switch_application(struct funk_privdata *funk,
uint8_t application)
{ {
struct rfm12_pkt packet; struct rfm12_pkt packet;
@ -556,14 +693,16 @@ static int funk_switch_application(struct funk_privdata *funk, uint8_t applicati
packet.msg.p.switchapp.app = application; packet.msg.p.switchapp.app = application;
int ret = funk_send_packet(funk, &packet, 4 + packet.data_length); int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_switch_application(): funk_send_packet()\n"); fprintf(stderr, "funk_switch_application(): funk_send_packet()\n");
return ret; return ret;
} }
int response_size = sizeof(packet); int response_size = sizeof(packet);
ret = funk_recv_packet(funk, &packet, &response_size); ret = funk_recv_packet(funk, &packet, &response_size);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_switch_application(): funk_recv_packet()\n"); fprintf(stderr, "funk_switch_application(): funk_recv_packet()\n");
return ret; return ret;
} }
@ -579,7 +718,12 @@ static int funk_switch_application(struct funk_privdata *funk, uint8_t applicati
} /* funk_switch_application */ } /* funk_switch_application */
static int funk_read_version(struct funk_privdata *funk, uint8_t *version, uint16_t length) /* *************************************************************************
* funk_read_version
* ************************************************************************* */
static int funk_read_version(struct funk_privdata *funk,
uint8_t *version,
uint16_t length)
{ {
struct rfm12_pkt packet; struct rfm12_pkt packet;
@ -592,14 +736,16 @@ static int funk_read_version(struct funk_privdata *funk, uint8_t *version, uint1
packet.msg.cause = CAUSE_SUCCESS; packet.msg.cause = CAUSE_SUCCESS;
int ret = funk_send_packet(funk, &packet, 4 + packet.data_length); int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_read_version(): funk_send_packet()\n"); fprintf(stderr, "funk_read_version(): funk_send_packet()\n");
return ret; return ret;
} }
int response_size = sizeof(packet); int response_size = sizeof(packet);
ret = funk_recv_packet(funk, &packet, &response_size); ret = funk_recv_packet(funk, &packet, &response_size);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_read_version(): funk_recv_packet()\n"); fprintf(stderr, "funk_read_version(): funk_recv_packet()\n");
return ret; return ret;
} }
@ -613,7 +759,9 @@ static int funk_read_version(struct funk_privdata *funk, uint8_t *version, uint1
int i; int i;
for (i = 0; i < packet.data_length -3; i++) for (i = 0; i < packet.data_length -3; i++)
{
version[i] = packet.msg.p.version.data[i] & 0x7F; version[i] = packet.msg.p.version.data[i] & 0x7F;
}
version[i] = '\0'; version[i] = '\0';
@ -621,7 +769,12 @@ static int funk_read_version(struct funk_privdata *funk, uint8_t *version, uint1
} /* funk_read_version */ } /* funk_read_version */
static int funk_read_chipinfo(struct funk_privdata *funk, uint8_t *chipinfo, uint16_t length) /* *************************************************************************
* funk_read_chipinfo
* ************************************************************************* */
static int funk_read_chipinfo(struct funk_privdata *funk,
uint8_t *chipinfo,
uint16_t length)
{ {
struct rfm12_pkt packet; struct rfm12_pkt packet;
@ -634,7 +787,8 @@ static int funk_read_chipinfo(struct funk_privdata *funk, uint8_t *chipinfo, uin
packet.msg.cause = CAUSE_SUCCESS; packet.msg.cause = CAUSE_SUCCESS;
int ret = funk_send_packet(funk, &packet, 4 + packet.data_length); int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_read_chipinfo(): funk_send_packet()\n"); fprintf(stderr, "funk_read_chipinfo(): funk_send_packet()\n");
return ret; return ret;
} }
@ -659,7 +813,14 @@ static int funk_read_chipinfo(struct funk_privdata *funk, uint8_t *chipinfo, uin
} /* funk_read_chipinfo */ } /* funk_read_chipinfo */
static int funk_read_memory(struct funk_privdata *funk, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address) /* *************************************************************************
* funk_read_memory
* ************************************************************************* */
static int funk_read_memory(struct funk_privdata *funk,
uint8_t *buffer,
uint16_t size,
uint8_t memtype,
uint16_t address)
{ {
struct rfm12_pkt packet; struct rfm12_pkt packet;
@ -700,7 +861,14 @@ static int funk_read_memory(struct funk_privdata *funk, uint8_t *buffer, uint16_
} /* funk_read_memory */ } /* funk_read_memory */
static int __funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address) /* *************************************************************************
* __funk_write_memory
* ************************************************************************* */
static int __funk_write_memory(struct funk_privdata *funk,
uint8_t *buffer,
uint16_t size,
uint8_t memtype,
uint16_t address)
{ {
struct rfm12_pkt packet; struct rfm12_pkt packet;
@ -718,14 +886,16 @@ static int __funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint
memcpy(packet.msg.p.write_req.data, buffer, size); memcpy(packet.msg.p.write_req.data, buffer, size);
int ret = funk_send_packet(funk, &packet, 4 + packet.data_length); int ret = funk_send_packet(funk, &packet, 4 + packet.data_length);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_write_memory(): funk_send_packet()\n"); fprintf(stderr, "funk_write_memory(): funk_send_packet()\n");
return ret; return ret;
} }
int response_size = sizeof(packet); int response_size = sizeof(packet);
ret = funk_recv_packet(funk, &packet, &response_size); ret = funk_recv_packet(funk, &packet, &response_size);
if (ret < 0) { if (ret < 0)
{
fprintf(stderr, "funk_write_memory(): funk_recv_packet()\n"); fprintf(stderr, "funk_write_memory(): funk_recv_packet()\n");
return ret; return ret;
} }
@ -741,7 +911,14 @@ static int __funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint
} /* __funk_write_memory */ } /* __funk_write_memory */
static int funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address) /* *************************************************************************
* funk_write_memory
* ************************************************************************* */
static int funk_write_memory(struct funk_privdata *funk,
uint8_t *buffer,
uint16_t size,
uint8_t memtype,
uint16_t address)
{ {
if (memtype == MEMTYPE_EEPROM) if (memtype == MEMTYPE_EEPROM)
{ {
@ -769,7 +946,9 @@ static int funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint16
{ {
ret = __funk_write_memory(funk, &pagebuf[pos], WRITE_BLOCK_SIZE, memtype, address + pos); ret = __funk_write_memory(funk, &pagebuf[pos], WRITE_BLOCK_SIZE, memtype, address + pos);
if (ret < 0) if (ret < 0)
{
break; break;
}
} }
free(pagebuf); free(pagebuf);
@ -777,39 +956,52 @@ static int funk_write_memory(struct funk_privdata *funk, uint8_t *buffer, uint16
} /* funk_write_memory */ } /* funk_write_memory */
/* *************************************************************************
* funk_close
* ************************************************************************* */
static int funk_close(struct multiboot *mboot) static int funk_close(struct multiboot *mboot)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
if (funk->connected) if (funk->connected)
{
funk_switch_application(funk, BOOTTYPE_APPLICATION); funk_switch_application(funk, BOOTTYPE_APPLICATION);
}
funk_close_device(funk); funk_close_device(funk);
return 0; return 0;
} /* funk_close */ } /* funk_close */
/* *************************************************************************
* funk_open
* ************************************************************************* */
static int funk_open(struct multiboot *mboot) static int funk_open(struct multiboot *mboot)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
if (funk->address == 0) { if (funk->address == 0)
{
fprintf(stderr, "abort: no address given\n"); fprintf(stderr, "abort: no address given\n");
return -1; return -1;
} }
if (funk->device == NULL) { if (funk->device == NULL)
{
fprintf(stderr, "abort: no device given\n"); fprintf(stderr, "abort: no device given\n");
return -1; return -1;
} }
if (funk_open_device(funk) < 0) if (funk_open_device(funk) < 0)
{
return -1; return -1;
}
printf("funkbridge dev : %-16s\n", funk->device); printf("funkbridge dev : %-16s\n", funk->device);
char bridge_version[20]; char bridge_version[20];
if (funk_bridge_version(funk, (uint8_t *)bridge_version, sizeof(bridge_version))) { if (funk_bridge_version(funk, (uint8_t *)bridge_version, sizeof(bridge_version)))
{
fprintf(stderr, "failed to get funkbridge version\n"); fprintf(stderr, "failed to get funkbridge version\n");
funk_close(mboot); funk_close(mboot);
return -1; return -1;
@ -817,7 +1009,8 @@ static int funk_open(struct multiboot *mboot)
printf("funkbridge ver : %-16s\n", bridge_version); printf("funkbridge ver : %-16s\n", bridge_version);
if (funk_switch_application(funk, BOOTTYPE_BOOTLOADER)) { if (funk_switch_application(funk, BOOTTYPE_BOOTLOADER))
{
fprintf(stderr, "failed to switch to bootloader (invalid address?)\n"); fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
funk_close(mboot); funk_close(mboot);
return -1; return -1;
@ -829,14 +1022,16 @@ static int funk_open(struct multiboot *mboot)
usleep(100000); usleep(100000);
char version[20]; char version[20];
if (funk_read_version(funk, (uint8_t *)version, sizeof(version))) { if (funk_read_version(funk, (uint8_t *)version, sizeof(version)))
{
fprintf(stderr, "failed to get bootloader version\n"); fprintf(stderr, "failed to get bootloader version\n");
funk_close(mboot); funk_close(mboot);
return -1; return -1;
} }
uint8_t chipinfo[8]; uint8_t chipinfo[8];
if (funk_read_chipinfo(funk, chipinfo, sizeof(chipinfo))) { if (funk_read_chipinfo(funk, chipinfo, sizeof(chipinfo)))
{
fprintf(stderr, "failed to get bootloader chipinfo\n"); fprintf(stderr, "failed to get bootloader chipinfo\n");
funk_close(mboot); funk_close(mboot);
return -1; return -1;
@ -848,26 +1043,39 @@ static int funk_open(struct multiboot *mboot)
funk->flashsize = (chipinfo[4] << 8) + chipinfo[5]; funk->flashsize = (chipinfo[4] << 8) + chipinfo[5];
funk->eepromsize = (chipinfo[6] << 8) + chipinfo[7]; funk->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n", version, chipinfo[0], chipinfo[1], chipinfo[2], chipname); printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n", funk->flashsize, funk->flashsize, funk->flashpage); version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
printf("eeprom size : 0x%04x / %5d\n", funk->eepromsize, funk->eepromsize);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
funk->flashsize, funk->flashsize, funk->flashpage);
printf("eeprom size : 0x%04x / %5d\n",
funk->eepromsize, funk->eepromsize);
return 0; return 0;
} /* funk_open */ } /* funk_open */
static int funk_read(struct multiboot *mboot, struct databuf *dbuf, int memtype) /* *************************************************************************
* funk_read
* ************************************************************************* */
static int funk_read(struct multiboot *mboot,
struct databuf *dbuf,
int memtype)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
int pos = 0; int pos = 0;
int size = (memtype == MEMTYPE_FLASH) ? funk->flashsize : funk->eepromsize; int size = (memtype == MEMTYPE_FLASH) ? funk->flashsize : funk->eepromsize;
while (pos < size) {
while (pos < size)
{
mboot->progress_cb(progress_msg, pos, size); mboot->progress_cb(progress_msg, pos, size);
int len = MIN(READ_BLOCK_SIZE, size - pos); int len = MIN(READ_BLOCK_SIZE, size - pos);
if (funk_read_memory(funk, dbuf->data + pos, len, memtype, pos)) { if (funk_read_memory(funk, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -882,19 +1090,27 @@ static int funk_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
} /* funk_read */ } /* funk_read */
static int funk_write(struct multiboot *mboot, struct databuf *dbuf, int memtype) /* *************************************************************************
* funk_write
* ************************************************************************* */
static int funk_write(struct multiboot *mboot,
struct databuf *dbuf,
int memtype)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
int pos = 0; int pos = 0;
while (pos < dbuf->length) { while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = (memtype == MEMTYPE_FLASH) ? funk->flashpage : WRITE_BLOCK_SIZE; int len = (memtype == MEMTYPE_FLASH) ? funk->flashpage : WRITE_BLOCK_SIZE;
len = MIN(len, dbuf->length - pos); len = MIN(len, dbuf->length - pos);
if (funk_write_memory(funk, dbuf->data + pos, len, memtype, pos)) {
if (funk_write_memory(funk, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -907,23 +1123,32 @@ static int funk_write(struct multiboot *mboot, struct databuf *dbuf, int memtype
} /* funk_write */ } /* funk_write */
static int funk_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype) /* *************************************************************************
* funk_verify
* ************************************************************************* */
static int funk_verify(struct multiboot *mboot,
struct databuf *dbuf,
int memtype)
{ {
struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata; struct funk_privdata *funk = (struct funk_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
int pos = 0; int pos = 0;
uint8_t comp[READ_BLOCK_SIZE]; uint8_t comp[READ_BLOCK_SIZE];
while (pos < dbuf->length) {
while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos); int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
if (funk_read_memory(funk, comp, len, memtype, pos)) { if (funk_read_memory(funk, comp, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
if (memcmp(comp, dbuf->data + pos, len) != 0x00) { if (memcmp(comp, dbuf->data + pos, len) != 0x00)
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
fprintf(stderr, "verify failed at page 0x%04x!!\n", pos); fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
return -1; return -1;
@ -939,7 +1164,8 @@ static int funk_verify(struct multiboot *mboot, struct databuf *dbuf, int memtyp
} /* funk_verify */ } /* funk_verify */
struct multiboot_ops funk_ops = { struct multiboot_ops funk_ops =
{
.alloc = funk_alloc, .alloc = funk_alloc,
.free = funk_free, .free = funk_free,
.get_memtype = funk_get_memtype, .get_memtype = funk_get_memtype,

433
mpm.c
View File

@ -40,7 +40,8 @@
struct multiboot_ops mpm_ops; struct multiboot_ops mpm_ops;
struct mpm_privdata { struct mpm_privdata
{
char *device; char *device;
int fd; int fd;
int connected; int connected;
@ -54,44 +55,52 @@ struct mpm_privdata {
struct termios oldtio; struct termios oldtio;
}; };
static struct option mpm_optargs[] = { static struct option mpm_optargs[] =
{"address", 1, 0, 'a'}, /* -a <addr> */ {
{"device", 1, 0, 'd'}, /* [ -d <device> ] */ { "address", 1, 0, 'a'}, /* -a <addr> */
{ "device", 1, 0, 'd'}, /* [ -d <device> ] */
}; };
/* *************************************************************************
* mpm_optarg_cb
* ************************************************************************* */
static int mpm_optarg_cb(int val, const char *arg, void *privdata) static int mpm_optarg_cb(int val, const char *arg, void *privdata)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)privdata;
switch (val) { switch (val)
case 'a': /* address */ {
{ case 'a': /* address */
char *endptr; {
mpm->address = strtol(arg, &endptr, 16); char *endptr;
if (*endptr != '\0' || mpm->address < 0x01 || mpm->address > 0x7F) { mpm->address = strtol(arg, &endptr, 16);
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */ if (*endptr != '\0' || mpm->address < 0x01 || mpm->address > 0x7F)
{ {
if (mpm->device != NULL) { fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */
if (mpm->device != NULL)
{
fprintf(stderr, "invalid device: '%s'\n", optarg); fprintf(stderr, "invalid device: '%s'\n", optarg);
return -1; return -1;
} }
mpm->device = strdup(optarg); mpm->device = strdup(optarg);
if (mpm->device == NULL) { if (mpm->device == NULL)
{
perror("strdup()"); perror("strdup()");
return -1; return -1;
} }
} break;
break;
case 'h': case 'h':
case '?': /* error */ case '?': /* error */
fprintf(stderr, "Usage: mpmboot [options]\n" fprintf(stderr, "Usage: mpmboot [options]\n"
" -a <address> - selects mpm address (0x01 - 0xFF)\n" " -a <address> - selects mpm address (0x01 - 0xFF)\n"
" -d <device> - selects mpm device\n" " -d <device> - selects mpm device\n"
@ -102,26 +111,34 @@ static int mpm_optarg_cb(int val, const char *arg, void *privdata)
"\n" "\n"
"Example: mpmboot -d /dev/ttyUSB0 -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n" "Example: mpmboot -d /dev/ttyUSB0 -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
"\n"); "\n");
return -1; return -1;
default: default:
return 1; return 1;
} }
return 0; return 0;
} } /* mpm_optarg_cb */
/* *************************************************************************
* mpm_alloc
* ************************************************************************* */
static struct multiboot * mpm_alloc(void) static struct multiboot * mpm_alloc(void)
{ {
struct multiboot * mboot = malloc(sizeof(struct multiboot)); struct multiboot * mboot = malloc(sizeof(struct multiboot));
if (mboot == NULL) if (mboot == NULL)
{
return NULL; return NULL;
}
memset(mboot, 0x00, sizeof(struct multiboot)); memset(mboot, 0x00, sizeof(struct multiboot));
mboot->ops = &mpm_ops; mboot->ops = &mpm_ops;
struct mpm_privdata *mpm = malloc(sizeof(struct mpm_privdata)); struct mpm_privdata *mpm = malloc(sizeof(struct mpm_privdata));
if (mpm == NULL) { if (mpm == NULL)
{
free(mboot); free(mboot);
return NULL; return NULL;
} }
@ -130,65 +147,94 @@ static struct multiboot * mpm_alloc(void)
mpm->device = NULL; mpm->device = NULL;
mpm->address = 0; mpm->address = 0;
optarg_register(mpm_optargs, ARRAY_SIZE(mpm_optargs), mpm_optarg_cb, (void *)mpm); optarg_register(mpm_optargs, ARRAY_SIZE(mpm_optargs),
mpm_optarg_cb, (void *)mpm);
mboot->privdata = mpm; mboot->privdata = mpm;
return mboot; return mboot;
} } /* mpm_alloc */
/* *************************************************************************
* mpm_free
* ************************************************************************* */
static void mpm_free(struct multiboot *mboot) static void mpm_free(struct multiboot *mboot)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
if (mpm->device != NULL) if (mpm->device != NULL)
{
free(mpm->device); free(mpm->device);
}
free(mpm); free(mpm);
free(mboot); free(mboot);
} } /* mpm_free */
static int mpm_get_memtype(struct multiboot *mboot, const char *memname)
/* *************************************************************************
* mpm_get_memtype
* ************************************************************************* */
static int mpm_get_memtype(struct multiboot *mboot,
const char *memname)
{ {
if (strcmp(memname, "flash") == 0) if (strcmp(memname, "flash") == 0)
{
return MEMTYPE_FLASH; return MEMTYPE_FLASH;
}
else if (strcmp(memname, "eeprom") == 0) else if (strcmp(memname, "eeprom") == 0)
{
return MEMTYPE_EEPROM; return MEMTYPE_EEPROM;
}
return -1; return -1;
} } /* mpm_get_memtype */
/* *************************************************************************
* mpm_get_memsize
* ************************************************************************* */
static int mpm_get_memsize(struct multiboot *mboot, int memtype) static int mpm_get_memsize(struct multiboot *mboot, int memtype)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
if (!mpm->connected) if (!mpm->connected)
return 0; {
switch (memtype) {
case MEMTYPE_FLASH:
return mpm->flashsize;
case MEMTYPE_EEPROM:
return mpm->eepromsize;
default:
return 0; return 0;
} }
}
static int mpm_send(struct mpm_privdata *mpm, uint8_t command, uint8_t *data, int length) switch (memtype)
{
case MEMTYPE_FLASH:
return mpm->flashsize;
case MEMTYPE_EEPROM:
return mpm->eepromsize;
default:
return 0;
}
} /* mpm_get_memsize */
/* *************************************************************************
* mpm_send
* ************************************************************************* */
static int mpm_send(struct mpm_privdata *mpm, uint8_t command,
uint8_t *data, int length)
{ {
struct termios tio; struct termios tio;
if (tcgetattr(mpm->fd, &tio) < 0) { if (tcgetattr(mpm->fd, &tio) < 0)
{
perror("tcgetattr(tio)"); perror("tcgetattr(tio)");
return -1; return -1;
} }
tio.c_cflag |= PARODD; tio.c_cflag |= PARODD;
if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0) { if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0)
{
perror("tcsetattr(tio)"); perror("tcsetattr(tio)");
return -1; return -1;
} }
@ -196,7 +242,8 @@ static int mpm_send(struct mpm_privdata *mpm, uint8_t command, uint8_t *data, in
// usleep(5000); // usleep(5000);
uint8_t address = mpm->address; uint8_t address = mpm->address;
if (write(mpm->fd, &address, sizeof(address)) != sizeof(address)) { if (write(mpm->fd, &address, sizeof(address)) != sizeof(address))
{
perror("write(address)"); perror("write(address)");
return -1; return -1;
} }
@ -205,7 +252,8 @@ static int mpm_send(struct mpm_privdata *mpm, uint8_t command, uint8_t *data, in
tio.c_cflag &= ~(PARODD); tio.c_cflag &= ~(PARODD);
if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0) { if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0)
{
perror("tcsetattr(tio)"); perror("tcsetattr(tio)");
return -1; return -1;
} }
@ -215,26 +263,34 @@ static int mpm_send(struct mpm_privdata *mpm, uint8_t command, uint8_t *data, in
header[1] = (length >> 8) & 0xFF; header[1] = (length >> 8) & 0xFF;
header[2] = length & 0xFF; header[2] = length & 0xFF;
if (write(mpm->fd, header, sizeof(header)) != sizeof(header)) { if (write(mpm->fd, header, sizeof(header)) != sizeof(header))
{
perror("write(header)"); perror("write(header)");
return -1; return -1;
} }
if (data != NULL && length != 0) { if (data != NULL && length != 0)
if (write(mpm->fd, data, length) != length) { {
if (write(mpm->fd, data, length) != length)
{
perror("write(data)"); perror("write(data)");
return -1; return -1;
} }
} }
return 0; return 0;
} } /* mpm_send */
/* *************************************************************************
* myread
* ************************************************************************* */
static int myread(int fd, void *data, int size) static int myread(int fd, void *data, int size)
{ {
int pos = 0; int pos = 0;
while (1) { while (1)
{
fd_set fdset; fd_set fdset;
struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 }; struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
@ -242,21 +298,28 @@ static int myread(int fd, void *data, int size)
FD_SET(fd, &fdset); FD_SET(fd, &fdset);
int ret = select(fd +1, &fdset, NULL, NULL, &timeout); int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
if (ret == -1) { if (ret == -1)
{
perror("select"); perror("select");
return -1; return -1;
} else if (ret == 0) { }
else if (ret == 0)
{
break; break;
}
} else if (FD_ISSET(fd, &fdset)) { else if (FD_ISSET(fd, &fdset))
{
int len = read(fd, data + pos, size - pos); int len = read(fd, data + pos, size - pos);
if (len < 0) { if (len < 0)
{
return -1; return -1;
}
} else { else
{
pos += len; pos += len;
if (pos == size) { if (pos == size)
{
break; break;
} }
} }
@ -264,20 +327,30 @@ static int myread(int fd, void *data, int size)
} }
return pos; return pos;
} } /* myread */
static int mpm_recv(struct mpm_privdata *mpm, uint8_t command, uint8_t *cause, uint8_t *buffer, uint16_t buffersize)
/* *************************************************************************
* mpm_recv
* ************************************************************************* */
static int mpm_recv(struct mpm_privdata *mpm,
uint8_t command,
uint8_t *cause,
uint8_t *buffer,
uint16_t buffersize)
{ {
int len; int len;
uint8_t header[4]; uint8_t header[4];
len = myread(mpm->fd, header, sizeof(header)); len = myread(mpm->fd, header, sizeof(header));
if (len != sizeof(header)) { if (len != sizeof(header))
{
fprintf(stderr, "short read() from device (not addressed?)\n"); fprintf(stderr, "short read() from device (not addressed?)\n");
return -1; return -1;
} }
if (header[0] != command) { if (header[0] != command)
{
fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n", header[0], command); fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n", header[0], command);
return -1; return -1;
} }
@ -288,37 +361,51 @@ static int mpm_recv(struct mpm_privdata *mpm, uint8_t command, uint8_t *cause, u
// printf("mpm_recv() cmd=0x%02x cause=0x%02x length=0x%04x\n", command, *cause, length); // printf("mpm_recv() cmd=0x%02x cause=0x%02x length=0x%04x\n", command, *cause, length);
uint16_t bufferpos = 0; uint16_t bufferpos = 0;
while (length > 0) { while (length > 0)
{
/* free space in output buffer? */ /* free space in output buffer? */
if ((bufferpos < buffersize) && (buffer != NULL)) { if ((bufferpos < buffersize) && (buffer != NULL))
{
uint16_t size = MIN(buffersize - bufferpos, length); uint16_t size = MIN(buffersize - bufferpos, length);
len = myread(mpm->fd, buffer + bufferpos, size); len = myread(mpm->fd, buffer + bufferpos, size);
if (len <= 0) { if (len <= 0)
{
fprintf(stderr, "short read() from device (%d != %d)\n", len, size); fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
return -1; return -1;
} }
bufferpos += len; bufferpos += len;
length -= len; length -= len;
} else { }
else
{
uint8_t dummy[256]; uint8_t dummy[256];
/* no space in output buffer, but device still sends data -> do dummy read */ /* no space in output buffer, but device still sends data -> do dummy read */
uint16_t size = MIN(sizeof(dummy), length); uint16_t size = MIN(sizeof(dummy), length);
len = myread(mpm->fd, dummy, size); len = myread(mpm->fd, dummy, size);
if (len <= 0) { if (len <= 0)
{
fprintf(stderr, "short read() from device (%d != %d)\n", len, size); fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
return -1; return -1;
} }
length -= len; length -= len;
} }
} }
return bufferpos; return bufferpos;
} } /* mpm_recv */
/* *************************************************************************
* mpm_close_device
* ************************************************************************* */
static void mpm_close_device(struct mpm_privdata *mpm) static void mpm_close_device(struct mpm_privdata *mpm)
{ {
/* delay close() / tcsetattr() */ /* delay close() / tcsetattr() */
@ -326,17 +413,23 @@ static void mpm_close_device(struct mpm_privdata *mpm)
tcsetattr(mpm->fd, TCSANOW, &mpm->oldtio); tcsetattr(mpm->fd, TCSANOW, &mpm->oldtio);
close(mpm->fd); close(mpm->fd);
} } /* mpm_close_device */
/* *************************************************************************
* mpm_open_device
* ************************************************************************* */
static int mpm_open_device(struct mpm_privdata *mpm) static int mpm_open_device(struct mpm_privdata *mpm)
{ {
mpm->fd = open(mpm->device, O_RDWR | O_NOCTTY | O_CLOEXEC); mpm->fd = open(mpm->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
if (mpm->fd < 0) { if (mpm->fd < 0)
{
perror("open()"); perror("open()");
return -1; return -1;
} }
if (tcgetattr(mpm->fd, &mpm->oldtio) < 0) { if (tcgetattr(mpm->fd, &mpm->oldtio) < 0)
{
perror("tcgetattr(oldtio)"); perror("tcgetattr(oldtio)");
close(mpm->fd); close(mpm->fd);
return -1; return -1;
@ -352,7 +445,8 @@ static int mpm_open_device(struct mpm_privdata *mpm)
newtio.c_cc[VTIME] = 0; newtio.c_cc[VTIME] = 0;
int err = tcsetattr(mpm->fd, TCSANOW, &newtio); int err = tcsetattr(mpm->fd, TCSANOW, &newtio);
if (err < 0) { if (err < 0)
{
perror("tcsetattr(newtio)"); perror("tcsetattr(newtio)");
close(mpm->fd); close(mpm->fd);
return -1; return -1;
@ -360,58 +454,94 @@ static int mpm_open_device(struct mpm_privdata *mpm)
mpm->connected = 1; mpm->connected = 1;
return 0; return 0;
} } /* mpm_open_device */
static int mpm_switch_application(struct mpm_privdata *mpm, uint8_t application)
/* *************************************************************************
* mpm_switch_application
* ************************************************************************* */
static int mpm_switch_application(struct mpm_privdata *mpm,
uint8_t application)
{ {
uint8_t data[] = { application }; uint8_t data[] = { application };
int ret = mpm_send(mpm, CMD_SWITCH_APPLICATION, data, sizeof(data)); int ret = mpm_send(mpm, CMD_SWITCH_APPLICATION, data, sizeof(data));
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = CAUSE_SUCCESS; uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_SWITCH_APPLICATION, &cause, NULL, 0); ret = mpm_recv(mpm, CMD_SWITCH_APPLICATION, &cause, NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
return (cause != CAUSE_SUCCESS); return (cause != CAUSE_SUCCESS);
} } /* mpm_switch_application */
static int mpm_read_version(struct mpm_privdata *mpm, uint8_t *version, uint16_t length)
/* *************************************************************************
* mpm_read_version
* ************************************************************************* */
static int mpm_read_version(struct mpm_privdata *mpm,
uint8_t *version, uint16_t length)
{ {
memset(version, 0, length); memset(version, 0, length);
int ret = mpm_send(mpm, CMD_GET_BOOTLOADER_VERSION, NULL, 0); int ret = mpm_send(mpm, CMD_GET_BOOTLOADER_VERSION, NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = CAUSE_SUCCESS; uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_GET_BOOTLOADER_VERSION, &cause, version, length); ret = mpm_recv(mpm, CMD_GET_BOOTLOADER_VERSION, &cause, version, length);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
int i; int i;
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{
version[i] &= ~0x80; version[i] &= ~0x80;
}
return (cause != CAUSE_SUCCESS); return (cause != CAUSE_SUCCESS);
} }
static int mpm_read_chipinfo(struct mpm_privdata *mpm, uint8_t *chipinfo, uint16_t length)
/* *************************************************************************
* mpm_read_chipinfo
* ************************************************************************* */
static int mpm_read_chipinfo(struct mpm_privdata *mpm,
uint8_t *chipinfo, uint16_t length)
{ {
int ret = mpm_send(mpm, CMD_GET_CHIP_INFO, NULL, 0); int ret = mpm_send(mpm, CMD_GET_CHIP_INFO, NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = CAUSE_SUCCESS; uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_GET_CHIP_INFO, &cause, chipinfo, length); ret = mpm_recv(mpm, CMD_GET_CHIP_INFO, &cause, chipinfo, length);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
return (cause != CAUSE_SUCCESS); return (cause != CAUSE_SUCCESS);
} } /* mpm_read_chipinfo */
static int mpm_read_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address)
/* *************************************************************************
* mpm_read_memory
* ************************************************************************* */
static int mpm_read_memory(struct mpm_privdata *mpm,
uint8_t *buffer, uint16_t size,
uint8_t memtype, uint16_t address)
{ {
uint8_t param[5] = { uint8_t param[5] = {
memtype, memtype,
@ -423,33 +553,51 @@ static int mpm_read_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t s
int ret = mpm_send(mpm, CMD_READ_MEMORY, param, sizeof(param)); int ret = mpm_send(mpm, CMD_READ_MEMORY, param, sizeof(param));
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
uint8_t cause = CAUSE_SUCCESS; uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_READ_MEMORY, &cause, buffer, size); ret = mpm_recv(mpm, CMD_READ_MEMORY, &cause, buffer, size);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
return (cause != CAUSE_SUCCESS); return (cause != CAUSE_SUCCESS);
} } /* mpm_read_memory */
static int mpm_write_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address)
/* *************************************************************************
* mpm_write_memory
* ************************************************************************* */
static int mpm_write_memory(struct mpm_privdata *mpm,
uint8_t *buffer, uint16_t size,
uint8_t memtype, uint16_t address)
{ {
int bufsize; int bufsize;
if (memtype == MEMTYPE_FLASH) {
if ((address & (mpm->flashpage -1)) != 0x00) { if (memtype == MEMTYPE_FLASH)
{
if ((address & (mpm->flashpage -1)) != 0x00)
{
fprintf(stderr, "mpm_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, mpm->flashpage); fprintf(stderr, "mpm_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, mpm->flashpage);
return -1; return -1;
} }
bufsize = 5 + mpm->flashpage; bufsize = 5 + mpm->flashpage;
} else { }
else
{
bufsize = 5 + size; bufsize = 5 + size;
} }
uint8_t *cmd = malloc(bufsize); uint8_t *cmd = malloc(bufsize);
if (cmd == NULL) if (cmd == NULL)
{
return -1; return -1;
}
cmd[0] = memtype; cmd[0] = memtype;
cmd[1] = (address >> 8) & 0xFF; cmd[1] = (address >> 8) & 0xFF;
@ -458,53 +606,73 @@ static int mpm_write_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t
cmd[4] = ((bufsize -5) & 0xFF); cmd[4] = ((bufsize -5) & 0xFF);
memcpy(cmd +5, buffer, size); memcpy(cmd +5, buffer, size);
if (memtype == MEMTYPE_FLASH) { if (memtype == MEMTYPE_FLASH)
{
memset(cmd +5 +size, 0xFF, mpm->flashpage - size); memset(cmd +5 +size, 0xFF, mpm->flashpage - size);
} }
int ret = mpm_send(mpm, CMD_WRITE_MEMORY, cmd, bufsize); int ret = mpm_send(mpm, CMD_WRITE_MEMORY, cmd, bufsize);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
free(cmd); free(cmd);
uint8_t cause = CAUSE_SUCCESS; uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_WRITE_MEMORY, &cause, NULL, 0); ret = mpm_recv(mpm, CMD_WRITE_MEMORY, &cause, NULL, 0);
if (ret < 0) if (ret < 0)
{
return ret; return ret;
}
return (cause != CAUSE_SUCCESS); return (cause != CAUSE_SUCCESS);
} } /* mpm_write_memory */
/* *************************************************************************
* mpm_close
* ************************************************************************* */
static int mpm_close(struct multiboot *mboot) static int mpm_close(struct multiboot *mboot)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
if (mpm->connected) if (mpm->connected)
{
mpm_switch_application(mpm, BOOTTYPE_APPLICATION); mpm_switch_application(mpm, BOOTTYPE_APPLICATION);
}
mpm_close_device(mpm); mpm_close_device(mpm);
return 0; return 0;
} } /* mpm_close */
/* *************************************************************************
* mpm_open
* ************************************************************************* */
static int mpm_open(struct multiboot *mboot) static int mpm_open(struct multiboot *mboot)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
if (mpm->address == 0) { if (mpm->address == 0)
{
fprintf(stderr, "abort: no address given\n"); fprintf(stderr, "abort: no address given\n");
return -1; return -1;
} }
if (mpm->device == NULL) { if (mpm->device == NULL)
{
fprintf(stderr, "abort: no device given\n"); fprintf(stderr, "abort: no device given\n");
return -1; return -1;
} }
if (mpm_open_device(mpm) < 0) if (mpm_open_device(mpm) < 0)
{
return -1; return -1;
}
if (mpm_switch_application(mpm, BOOTTYPE_BOOTLOADER)) { if (mpm_switch_application(mpm, BOOTTYPE_BOOTLOADER))
{
fprintf(stderr, "failed to switch to bootloader (invalid address?)\n"); fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
mpm_close(mboot); mpm_close(mboot);
return -1; return -1;
@ -514,14 +682,16 @@ static int mpm_open(struct multiboot *mboot)
usleep(100000); usleep(100000);
char version[16]; char version[16];
if (mpm_read_version(mpm, (uint8_t *)version, sizeof(version))) { if (mpm_read_version(mpm, (uint8_t *)version, sizeof(version)))
{
fprintf(stderr, "failed to get bootloader version\n"); fprintf(stderr, "failed to get bootloader version\n");
mpm_close(mboot); mpm_close(mboot);
return -1; return -1;
} }
uint8_t chipinfo[8]; uint8_t chipinfo[8];
if (mpm_read_chipinfo(mpm, chipinfo, sizeof(chipinfo))) { if (mpm_read_chipinfo(mpm, chipinfo, sizeof(chipinfo)))
{
fprintf(stderr, "failed to get bootloader version\n"); fprintf(stderr, "failed to get bootloader version\n");
mpm_close(mboot); mpm_close(mboot);
return -1; return -1;
@ -533,26 +703,41 @@ static int mpm_open(struct multiboot *mboot)
mpm->flashsize = (chipinfo[4] << 8) + chipinfo[5]; mpm->flashsize = (chipinfo[4] << 8) + chipinfo[5];
mpm->eepromsize = (chipinfo[6] << 8) + chipinfo[7]; mpm->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
printf("device : %-16s (address: 0x%02X)\n", mpm->device, mpm->address); printf("device : %-16s (address: 0x%02X)\n",
printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n", version, chipinfo[0], chipinfo[1], chipinfo[2], chipname); mpm->device, mpm->address);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n", mpm->flashsize, mpm->flashsize, mpm->flashpage);
printf("eeprom size : 0x%04x / %5d\n", mpm->eepromsize, mpm->eepromsize); printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
mpm->flashsize, mpm->flashsize, mpm->flashpage);
printf("eeprom size : 0x%04x / %5d\n",
mpm->eepromsize, mpm->eepromsize);
return 0; return 0;
} } /* mpm_open */
static int mpm_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
/* *************************************************************************
* mpm_read
* ************************************************************************* */
static int mpm_read(struct multiboot *mboot,
struct databuf *dbuf, int memtype)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
int pos = 0; int pos = 0;
int size = (memtype == MEMTYPE_FLASH) ? mpm->flashsize : mpm->eepromsize; int size = (memtype == MEMTYPE_FLASH) ? mpm->flashsize : mpm->eepromsize;
while (pos < size) {
while (pos < size)
{
mboot->progress_cb(progress_msg, pos, size); mboot->progress_cb(progress_msg, pos, size);
int len = MIN(READ_BLOCK_SIZE, size - pos); int len = MIN(READ_BLOCK_SIZE, size - pos);
if (mpm_read_memory(mpm, dbuf->data + pos, len, memtype, pos)) { if (mpm_read_memory(mpm, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -564,21 +749,28 @@ static int mpm_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
mboot->progress_cb(progress_msg, pos, size); mboot->progress_cb(progress_msg, pos, size);
return 0; return 0;
} } /* mpm_read */
static int mpm_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
/* *************************************************************************
* mpm_write
* ************************************************************************* */
static int mpm_write(struct multiboot *mboot,
struct databuf *dbuf, int memtype)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
int pos = 0; int pos = 0;
while (pos < dbuf->length) { while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = (memtype == MEMTYPE_FLASH) ? mpm->flashpage : WRITE_BLOCK_SIZE; int len = (memtype == MEMTYPE_FLASH) ? mpm->flashpage : WRITE_BLOCK_SIZE;
len = MIN(len, dbuf->length - pos); len = MIN(len, dbuf->length - pos);
if (mpm_write_memory(mpm, dbuf->data + pos, len, memtype, pos)) { if (mpm_write_memory(mpm, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -588,25 +780,34 @@ static int mpm_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0; return 0;
} } /* mpm_write */
static int mpm_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
/* *************************************************************************
* mpm_verify
* ************************************************************************* */
static int mpm_verify(struct multiboot *mboot,
struct databuf *dbuf, int memtype)
{ {
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata; struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";
int pos = 0; int pos = 0;
uint8_t comp[READ_BLOCK_SIZE]; uint8_t comp[READ_BLOCK_SIZE];
while (pos < dbuf->length) {
while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos); int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
if (mpm_read_memory(mpm, comp, len, memtype, pos)) { if (mpm_read_memory(mpm, comp, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
if (memcmp(comp, dbuf->data + pos, len) != 0x00) { if (memcmp(comp, dbuf->data + pos, len) != 0x00)
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
fprintf(stderr, "verify failed at page 0x%04x!!\n", pos); fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
return -1; return -1;
@ -619,9 +820,11 @@ static int mpm_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0; return 0;
} } /* mpm_verify */
struct multiboot_ops mpm_ops = {
struct multiboot_ops mpm_ops =
{
.alloc = mpm_alloc, .alloc = mpm_alloc,
.free = mpm_free, .free = mpm_free,
.get_memtype = mpm_get_memtype, .get_memtype = mpm_get_memtype,

View File

@ -45,7 +45,8 @@ static struct prog_mode prog_modes[] =
{ "funkboot", &funk_ops }, { "funkboot", &funk_ops },
}; };
struct mboot_action { struct mboot_action
{
struct list_head list; struct list_head list;
char *filename; char *filename;
@ -55,78 +56,110 @@ struct mboot_action {
static LIST_HEAD(action_list); static LIST_HEAD(action_list);
static struct option main_optargs[] = { static struct option main_optargs[] =
{"help", 0, 0, 'h'}, /* [ -h ] */ {
{"progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */ { "help", 0, 0, 'h'}, /* [ -h ] */
{"read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */ { "progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */
{"write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */ { "read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */
{"no-verify", 0, 0, 'n'}, /* [ -n ] */ { "write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */
{0, 0, 0, 0} { "no-verify", 0, 0, 'n'}, /* [ -n ] */
{ 0, 0, 0, 0}
}; };
/* *************************************************************************
* progress_mode0_cb
* ************************************************************************* */
static void progress_mode0_cb(const char *msg, int pos, int size) static void progress_mode0_cb(const char *msg, int pos, int size)
{ {
/* no progress output */ /* no progress output */
} } /* progress_mode0_cb */
/* *************************************************************************
* progress_mode1_cb
* ************************************************************************* */
static void progress_mode1_cb(const char *msg, int pos, int size) static void progress_mode1_cb(const char *msg, int pos, int size)
{ {
if (pos != -1 && size != -1) { if (pos != -1 && size != -1)
{
char stars[50]; char stars[50];
int i; int i;
int count = (pos * sizeof(stars) / size); int count = (pos * sizeof(stars) / size);
for (i = 0; i < sizeof(stars); i++) for (i = 0; i < sizeof(stars); i++)
{
stars[i] = (i < count) ? '*' : ' '; stars[i] = (i < count) ? '*' : ' ';
}
printf("%-15s: [%s] (%d)\r", msg, stars, pos); printf("%-15s: [%s] (%d)\r", msg, stars, pos);
} }
if (pos == size) if (pos == size)
{
printf("\n"); printf("\n");
} }
} /* progress_mode1_cb */
/* *************************************************************************
* progress_mode2_cb
* ************************************************************************* */
static void progress_mode2_cb(const char *msg, int pos, int size) static void progress_mode2_cb(const char *msg, int pos, int size)
{ {
static int old_count; static int old_count;
if (pos != -1 && size != -1) { if (pos != -1 && size != -1)
if (pos == 0) { {
if (pos == 0)
{
old_count = 0; old_count = 0;
printf("%-15s: [", msg); printf("%-15s: [", msg);
} else if (pos <=size) { }
else if (pos <=size)
{
int i; int i;
int count = (pos * 50 / size); int count = (pos * 50 / size);
for (i = old_count; i < count; i++) for (i = old_count; i < count; i++)
{
printf("*"); printf("*");
}
old_count = count; old_count = count;
if (pos == size) { if (pos == size)
{
printf("] (%d)\n", pos); printf("] (%d)\n", pos);
} }
} }
} }
} } /* progress_mode2_cb */
/* *************************************************************************
* add_action
* ************************************************************************* */
static int add_action(struct multiboot *mboot, int mode, const char *arg) static int add_action(struct multiboot *mboot, int mode, const char *arg)
{ {
struct mboot_action *action = malloc(sizeof(struct mboot_action)); struct mboot_action *action = malloc(sizeof(struct mboot_action));
if (action == NULL) { if (action == NULL)
{
perror("malloc()"); perror("malloc()");
return -1; return -1;
} }
char *argcopy = strdup(arg); char *argcopy = strdup(arg);
if (argcopy == NULL) { if (argcopy == NULL)
{
perror("strdup()"); perror("strdup()");
free(action); free(action);
return -1; return -1;
} }
char *tok = strtok(argcopy, ":"); char *tok = strtok(argcopy, ":");
if (tok == NULL) { if (tok == NULL)
{
fprintf(stderr, "invalid argument: '%s'\n", arg); fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy); free(argcopy);
free(action); free(action);
@ -134,7 +167,8 @@ static int add_action(struct multiboot *mboot, int mode, const char *arg)
} }
action->memtype = mboot->ops->get_memtype(mboot, tok); action->memtype = mboot->ops->get_memtype(mboot, tok);
if (action->memtype == -1) { if (action->memtype == -1)
{
fprintf(stderr, "invalid memtype: '%s'\n", tok); fprintf(stderr, "invalid memtype: '%s'\n", tok);
free(argcopy); free(argcopy);
free(action); free(action);
@ -142,7 +176,8 @@ static int add_action(struct multiboot *mboot, int mode, const char *arg)
} }
tok = strtok(NULL, ":"); tok = strtok(NULL, ":");
if (tok == NULL) { if (tok == NULL)
{
fprintf(stderr, "invalid argument: '%s'\n", arg); fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy); free(argcopy);
free(action); free(action);
@ -150,7 +185,8 @@ static int add_action(struct multiboot *mboot, int mode, const char *arg)
} }
action->filename = strdup(tok); action->filename = strdup(tok);
if (action->filename == NULL) { if (action->filename == NULL)
{
perror("strdup()"); perror("strdup()");
free(argcopy); free(argcopy);
free(action); free(action);
@ -162,57 +198,64 @@ static int add_action(struct multiboot *mboot, int mode, const char *arg)
list_add_tail(&action->list, &action_list); list_add_tail(&action->list, &action_list);
free(argcopy); free(argcopy);
return 0; return 0;
} } /* add_action */
/* *************************************************************************
* main_optarg_cb
* ************************************************************************* */
static int main_optarg_cb(int val, const char *arg, void *privdata) static int main_optarg_cb(int val, const char *arg, void *privdata)
{ {
struct multiboot *mboot = (struct multiboot *)privdata; struct multiboot *mboot = (struct multiboot *)privdata;
switch (val) { switch (val)
case 'r': /* read */ {
{ case 'r': /* read */
if (add_action(mboot, ACTION_READ, arg) < 0) if (add_action(mboot, ACTION_READ, arg) < 0)
return -1; {
}
break;
case 'w': /* write */
{
if (add_action(mboot, ACTION_WRITE, arg) < 0)
return -1;
}
break;
case 'n': /* no verify after write */
mboot->verify = 0;
break;
case 'p':
{
switch (*arg) {
case '0':
mboot->progress_cb = progress_mode0_cb;
break;
case '1':
mboot->progress_cb = progress_mode1_cb;
break;
case '2':
mboot->progress_cb = progress_mode2_cb;
break;
default:
fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
return -1; return -1;
} }
} break;
break;
case 'w': /* write */
if (add_action(mboot, ACTION_WRITE, arg) < 0)
{
return -1;
}
break;
case 'n': /* no verify after write */
mboot->verify = 0;
break;
case 'p':
switch (*arg)
{
case '0':
mboot->progress_cb = progress_mode0_cb;
break;
case '1':
mboot->progress_cb = progress_mode1_cb;
break;
case '2':
mboot->progress_cb = progress_mode2_cb;
break;
default:
fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
return -1;
}
break;
} }
return 0; return 0;
} }
/* *************************************************************************
* main
* ************************************************************************* */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct multiboot *mboot = NULL; struct multiboot *mboot = NULL;
@ -221,19 +264,23 @@ int main(int argc, char *argv[])
progname = (progname != NULL) ? (progname +1) : argv[0]; progname = (progname != NULL) ? (progname +1) : argv[0];
int i; int i;
for (i = 0; i < ARRAY_SIZE(prog_modes); i++) { for (i = 0; i < ARRAY_SIZE(prog_modes); i++)
{
struct prog_mode *mode = &prog_modes[i]; struct prog_mode *mode = &prog_modes[i];
if (strcmp(progname, mode->progname) == 0) { if (strcmp(progname, mode->progname) == 0)
{
mboot = mode->ops->alloc(); mboot = mode->ops->alloc();
if (mboot == NULL) { if (mboot == NULL)
{
fprintf(stderr, "failed to allocate '%s'\n", progname); fprintf(stderr, "failed to allocate '%s'\n", progname);
return -1; return -1;
} }
} }
} }
if (mboot == NULL) { if (mboot == NULL)
{
fprintf(stderr, "invalid progname\n"); fprintf(stderr, "invalid progname\n");
return -1; return -1;
} }
@ -241,35 +288,49 @@ int main(int argc, char *argv[])
mboot->verify = 1; mboot->verify = 1;
mboot->progress_cb = progress_mode1_cb; mboot->progress_cb = progress_mode1_cb;
optarg_register(main_optargs, ARRAY_SIZE(main_optargs), main_optarg_cb, (void *)mboot); optarg_register(main_optargs, ARRAY_SIZE(main_optargs),
main_optarg_cb, (void *)mboot);
int abort = optarg_parse(argc, argv); int abort = optarg_parse(argc, argv);
if (abort == -1 || mboot->ops->open(mboot) != 0) if ((abort == -1) ||
(mboot->ops->open(mboot) != 0)
)
{
return -1; return -1;
}
setbuf(stdout, NULL); setbuf(stdout, NULL);
struct mboot_action *action, *tmp; struct mboot_action *action, *tmp;
list_for_each_entry(action, &action_list, list) { list_for_each_entry(action, &action_list, list)
{
abort = 1; abort = 1;
if (action->mode == ACTION_READ) { if (action->mode == ACTION_READ)
{
int memsize = mboot->ops->get_memsize(mboot, action->memtype); int memsize = mboot->ops->get_memsize(mboot, action->memtype);
if (memsize == 0) if (memsize == 0)
{
break; break;
}
struct databuf *dbuf = dbuf_alloc(memsize); struct databuf *dbuf = dbuf_alloc(memsize);
if (dbuf == NULL) if (dbuf == NULL)
{
break; break;
}
int result = mboot->ops->read(mboot, dbuf, action->memtype); int result = mboot->ops->read(mboot, dbuf, action->memtype);
if (result != 0) { if (result != 0)
{
fprintf(stderr, "failed to read from device\n"); fprintf(stderr, "failed to read from device\n");
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
} }
result = file_write(action->filename, dbuf); result = file_write(action->filename, dbuf);
if (result != 0) { if (result != 0)
{
fprintf(stderr, "failed to write file '%s'\n", action->filename); fprintf(stderr, "failed to write file '%s'\n", action->filename);
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
@ -278,42 +339,53 @@ int main(int argc, char *argv[])
dbuf_free(dbuf); dbuf_free(dbuf);
abort = 0; abort = 0;
} else if (action->mode == ACTION_WRITE) { }
else if (action->mode == ACTION_WRITE)
{
unsigned int size; unsigned int size;
int result; int result;
result = file_getsize(action->filename, &size); result = file_getsize(action->filename, &size);
if (result != 0) if (result != 0)
{
break; break;
}
struct databuf *dbuf = dbuf_alloc(size); struct databuf *dbuf = dbuf_alloc(size);
if (dbuf == NULL) if (dbuf == NULL)
{
break; break;
}
result = file_read(action->filename, dbuf); result = file_read(action->filename, dbuf);
if (result != 0) { if (result != 0)
{
fprintf(stderr, "failed to read file '%s'\n", action->filename); fprintf(stderr, "failed to read file '%s'\n", action->filename);
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
} }
int memsize = mboot->ops->get_memsize(mboot, action->memtype); int memsize = mboot->ops->get_memsize(mboot, action->memtype);
if (memsize == 0) { if (memsize == 0)
{
fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize); fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize);
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
} }
result = mboot->ops->write(mboot, dbuf, action->memtype); result = mboot->ops->write(mboot, dbuf, action->memtype);
if (result != 0) { if (result != 0)
{
fprintf(stderr, "failed to write to device\n"); fprintf(stderr, "failed to write to device\n");
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
} }
if (mboot->verify) { if (mboot->verify)
{
result = mboot->ops->verify(mboot, dbuf, action->memtype); result = mboot->ops->verify(mboot, dbuf, action->memtype);
if (result != 0) { if (result != 0)
{
fprintf(stderr, "failed to verify\n"); fprintf(stderr, "failed to verify\n");
dbuf_free(dbuf); dbuf_free(dbuf);
break; break;
@ -325,7 +397,8 @@ int main(int argc, char *argv[])
} }
} }
list_for_each_entry_safe(action, tmp, &action_list, list) { list_for_each_entry_safe(action, tmp, &action_list, list)
{
free(action->filename); free(action->filename);
free(action); free(action);
} }
@ -335,4 +408,4 @@ int main(int argc, char *argv[])
optarg_free(); optarg_free();
return abort; return abort;
} } /* main */

View File

@ -4,7 +4,8 @@
#include <stdint.h> #include <stdint.h>
#include "filedata.h" #include "filedata.h"
struct multiboot { struct multiboot
{
struct multiboot_ops *ops; struct multiboot_ops *ops;
void *privdata; void *privdata;
@ -12,7 +13,8 @@ struct multiboot {
void (* progress_cb)(const char *msg, int pos, int max); void (* progress_cb)(const char *msg, int pos, int max);
}; };
struct multiboot_ops { struct multiboot_ops
{
struct multiboot * (* alloc)(void); struct multiboot * (* alloc)(void);
void (* free)(struct multiboot *mboot); void (* free)(struct multiboot *mboot);

View File

@ -28,7 +28,8 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
struct optarg_entry { struct optarg_entry
{
struct list_head list; struct list_head list;
const struct option *opts; const struct option *opts;
int count; int count;
@ -39,6 +40,10 @@ struct optarg_entry {
static LIST_HEAD(option_list); static LIST_HEAD(option_list);
/* *************************************************************************
* optarg_register
* ************************************************************************* */
int optarg_register(const struct option *opts, int count, int optarg_register(const struct option *opts, int count,
int (* parser_cb)(int val, const char *arg, void *privdata), int (* parser_cb)(int val, const char *arg, void *privdata),
void *privdata) void *privdata)
@ -47,7 +52,9 @@ int optarg_register(const struct option *opts, int count,
entry = malloc(sizeof(struct optarg_entry)); entry = malloc(sizeof(struct optarg_entry));
if (entry == NULL) if (entry == NULL)
{
return -1; return -1;
}
entry->opts = opts; /* TODO: copy? */ entry->opts = opts; /* TODO: copy? */
entry->count = count; entry->count = count;
@ -56,18 +63,27 @@ int optarg_register(const struct option *opts, int count,
list_add_tail(&entry->list, &option_list); list_add_tail(&entry->list, &option_list);
return 0; return 0;
} } /* optarg_register */
/* *************************************************************************
* optarg_free
* ************************************************************************* */
void optarg_free(void) void optarg_free(void)
{ {
struct optarg_entry *entry, *entry_tmp; struct optarg_entry *entry, *entry_tmp;
list_for_each_entry_safe(entry, entry_tmp, &option_list, list) { list_for_each_entry_safe(entry, entry_tmp, &option_list, list)
{
list_del(&entry->list); list_del(&entry->list);
free(entry); free(entry);
} }
} } /* optarg_free */
/* *************************************************************************
* optarg_getsize
* ************************************************************************* */
static void optarg_getsize(int *opt_count, int *optstring_len) static void optarg_getsize(int *opt_count, int *optstring_len)
{ {
int count = 0; int count = 0;
@ -75,17 +91,21 @@ static void optarg_getsize(int *opt_count, int *optstring_len)
struct optarg_entry *entry; struct optarg_entry *entry;
list_for_each_entry(entry, &option_list, list) { list_for_each_entry(entry, &option_list, list)
{
count += entry->count; count += entry->count;
int i; int i;
for (i = 0; i < entry->count; i++) { for (i = 0; i < entry->count; i++)
switch (entry->opts[i].has_arg) { {
switch (entry->opts[i].has_arg)
{
case 0: /* no arguments */ case 0: /* no arguments */
case 1: /* has argument */ case 1: /* has argument */
case 2: /* optional argument */ case 2: /* optional argument */
length += entry->opts[i].has_arg +1; length += entry->opts[i].has_arg +1;
break; break;
default: default:
break; break;
} }
@ -94,19 +114,26 @@ static void optarg_getsize(int *opt_count, int *optstring_len)
*opt_count = count +1; *opt_count = count +1;
*optstring_len = length +1; *optstring_len = length +1;
} } /* optarg_getsize */
/* *************************************************************************
* optarg_copy
* ************************************************************************* */
static void optarg_copy(struct option *opts, char *optstring) static void optarg_copy(struct option *opts, char *optstring)
{ {
struct optarg_entry *entry; struct optarg_entry *entry;
list_for_each_entry(entry, &option_list, list) { list_for_each_entry(entry, &option_list, list)
{
memcpy(opts, entry->opts, sizeof(struct option) * entry->count); memcpy(opts, entry->opts, sizeof(struct option) * entry->count);
opts += entry->count; opts += entry->count;
int i; int i;
for (i = 0; i < entry->count; i++) { for (i = 0; i < entry->count; i++)
switch (entry->opts[i].has_arg) { {
switch (entry->opts[i].has_arg)
{
case 0: /* no arguments */ case 0: /* no arguments */
*optstring++ = (char)entry->opts[i].val; *optstring++ = (char)entry->opts[i].val;
break; break;
@ -130,8 +157,12 @@ static void optarg_copy(struct option *opts, char *optstring)
memset(opts++, 0x00, sizeof(struct option)); memset(opts++, 0x00, sizeof(struct option));
*optstring++ = '\0'; *optstring++ = '\0';
} } /* optarg_copy */
/* *************************************************************************
* optarg_parse
* ************************************************************************* */
int optarg_parse(int argc, char * const argv[]) int optarg_parse(int argc, char * const argv[])
{ {
struct option *longopts; struct option *longopts;
@ -143,10 +174,13 @@ int optarg_parse(int argc, char * const argv[])
longopts = malloc(sizeof(struct option) * opt_count); longopts = malloc(sizeof(struct option) * opt_count);
if (longopts == NULL) if (longopts == NULL)
{
return -1; return -1;
}
optstring = malloc(optstring_len); optstring = malloc(optstring_len);
if (optstring == NULL) { if (optstring == NULL)
{
free(longopts); free(longopts);
return -1; return -1;
} }
@ -155,32 +189,44 @@ int optarg_parse(int argc, char * const argv[])
int retval = 0; int retval = 0;
int val = 0; int val = 0;
while (val != -1 && retval == 0) { while (val != -1 && retval == 0)
{
opterr = 1; /* print error message to stderr */ opterr = 1; /* print error message to stderr */
val = getopt_long(argc, argv, optstring, longopts, NULL); val = getopt_long(argc, argv, optstring, longopts, NULL);
if (val == 0x00) /* variable assigned (not supported) */ /* variable assigned (not supported) */
if (val == 0x00)
{
continue; continue;
}
struct optarg_entry *entry; struct optarg_entry *entry;
list_for_each_entry(entry, &option_list, list) { list_for_each_entry(entry, &option_list, list)
{
int ret = entry->parser_cb(val, optarg, entry->privdata); int ret = entry->parser_cb(val, optarg, entry->privdata);
/* option recognized, with error */ /* option recognized, with error */
if (ret < 0) { if (ret < 0)
{
retval = ret; retval = ret;
break; break;
}
/* option recognized, no error */ /* option recognized, no error */
} else if (ret == 0) { else if (ret == 0)
{
break; break;
} }
} }
if (val == -1) /* parsing completed */ /* parsing completed */
if (val == -1)
{
break; break;
}
if (val == '?') { /* parsing error */ /* parsing error */
if (val == '?')
{
retval = 1; retval = 1;
break; break;
} }
@ -190,4 +236,4 @@ int optarg_parse(int argc, char * const argv[])
free(longopts); free(longopts);
return retval; return retval;
} } /* optarg_parse */

367
twi.c
View File

@ -66,7 +66,8 @@
struct multiboot_ops twi_ops; struct multiboot_ops twi_ops;
struct twi_privdata { struct twi_privdata
{
char *device; char *device;
uint8_t address; uint8_t address;
int fd; int fd;
@ -77,62 +78,103 @@ struct twi_privdata {
uint16_t eepromsize; uint16_t eepromsize;
}; };
static struct option twi_optargs[] = { static struct option twi_optargs[] =
{"address", 1, 0, 'a'}, /* -a <addr> */ {
{"device", 1, 0, 'd'}, /* [ -d <device> ] */ { "address", 1, 0, 'a'}, /* -a <addr> */
{ "device", 1, 0, 'd'}, /* [ -d <device> ] */
}; };
static int twi_switch_application(struct twi_privdata *twi, uint8_t application)
/* *************************************************************************
* twi_switch_application
* ************************************************************************* */
static int twi_switch_application(struct twi_privdata *twi,
uint8_t application)
{ {
uint8_t cmd[] = { CMD_SWITCH_APPLICATION, application }; uint8_t cmd[] = { CMD_SWITCH_APPLICATION, application };
return (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd)); return (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd));
} } /* twi_switch_application */
static int twi_read_version(struct twi_privdata *twi, char *version, int length)
/* *************************************************************************
* twi_switch_application
* ************************************************************************* */
static int twi_read_version(struct twi_privdata *twi,
char *version, int length)
{ {
uint8_t cmd[] = { CMD_READ_VERSION }; uint8_t cmd[] = { CMD_READ_VERSION };
if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd)) if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
{
return -1; return -1;
}
memset(version, 0, length); memset(version, 0, length);
if (read(twi->fd, version, length) != length) if (read(twi->fd, version, length) != length)
{
return -1; return -1;
}
int i; int i;
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{
version[i] &= ~0x80; version[i] &= ~0x80;
}
return 0; return 0;
} } /* twi_read_version */
static int twi_read_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t size, uint8_t memtype, uint16_t address)
/* *************************************************************************
* twi_read_memory
* ************************************************************************* */
static int twi_read_memory(struct twi_privdata *twi,
uint8_t *buffer, uint8_t size,
uint8_t memtype, uint16_t address)
{ {
uint8_t cmd[] = { CMD_READ_MEMORY, memtype, (address >> 8) & 0xFF, (address & 0xFF) }; uint8_t cmd[] = { CMD_READ_MEMORY, memtype, (address >> 8) & 0xFF, (address & 0xFF) };
if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd)) if (write(twi->fd, cmd, sizeof(cmd)) != sizeof(cmd))
{
return -1; return -1;
}
return (read(twi->fd, buffer, size) != size); return (read(twi->fd, buffer, size) != size);
} } /* twi_read_memory */
static int twi_write_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t size, uint8_t memtype, uint16_t address)
/* *************************************************************************
* twi_write_memory
* ************************************************************************* */
static int twi_write_memory(struct twi_privdata *twi,
uint8_t *buffer, uint8_t size,
uint8_t memtype, uint16_t address)
{ {
int bufsize; int bufsize;
if (memtype == MEMTYPE_FLASH) {
if ((address & (twi->pagesize -1)) != 0x00) { if (memtype == MEMTYPE_FLASH)
fprintf(stderr, "twi_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, twi->pagesize); {
if ((address & (twi->pagesize -1)) != 0x00)
{
fprintf(stderr, "twi_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n",
address, twi->pagesize);
return -1; return -1;
} }
bufsize = 4 + twi->pagesize;
} else { bufsize = 4 + twi->pagesize;
}
else
{
bufsize = 4 + size; bufsize = 4 + size;
} }
uint8_t *cmd = malloc(bufsize); uint8_t *cmd = malloc(bufsize);
if (cmd == NULL) if (cmd == NULL)
{
return -1; return -1;
}
cmd[0] = CMD_WRITE_MEMORY; cmd[0] = CMD_WRITE_MEMORY;
cmd[1] = memtype; cmd[1] = memtype;
@ -140,7 +182,8 @@ static int twi_write_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t s
cmd[3] = (address & 0xFF); cmd[3] = (address & 0xFF);
memcpy(cmd +4, buffer, size); memcpy(cmd +4, buffer, size);
if (memtype == MEMTYPE_FLASH) { if (memtype == MEMTYPE_FLASH)
{
memset(cmd +4 +size, 0xFF, twi->pagesize - size); memset(cmd +4 +size, 0xFF, twi->pagesize - size);
} }
@ -148,80 +191,118 @@ static int twi_write_memory(struct twi_privdata *twi, uint8_t *buffer, uint8_t s
free(cmd); free(cmd);
return (result != bufsize); return (result != bufsize);
} } /* twi_write_memory */
/* *************************************************************************
* twi_close_device
* ************************************************************************* */
static void twi_close_device(struct twi_privdata *twi) static void twi_close_device(struct twi_privdata *twi)
{ {
if (twi->connected) if (twi->connected)
{
close(twi->fd); close(twi->fd);
}
twi->connected = 0; twi->connected = 0;
} } /* twi_close_device */
/* *************************************************************************
* twi_open_device
* ************************************************************************* */
static int twi_open_device(struct twi_privdata *twi) static int twi_open_device(struct twi_privdata *twi)
{ {
twi->fd = open(twi->device, O_RDWR); twi->fd = open(twi->device, O_RDWR);
if (twi->fd < 0) { if (twi->fd < 0)
fprintf(stderr, "failed to open '%s': %s\n", twi->device, strerror(errno)); {
fprintf(stderr, "failed to open '%s': %s\n",
twi->device, strerror(errno));
return -1; return -1;
} }
unsigned long funcs; unsigned long funcs;
if (ioctl(twi->fd, I2C_FUNCS, &funcs)) { if (ioctl(twi->fd, I2C_FUNCS, &funcs))
{
perror("ioctl(I2C_FUNCS)"); perror("ioctl(I2C_FUNCS)");
close(twi->fd); close(twi->fd);
return -1; return -1;
} }
if (!(funcs & I2C_FUNC_I2C)) { if (!(funcs & I2C_FUNC_I2C))
fprintf(stderr, "I2C_FUNC_I2C not supported on '%s'!\n", twi->device); {
fprintf(stderr, "I2C_FUNC_I2C not supported on '%s'!\n",
twi->device);
close(twi->fd); close(twi->fd);
return -1; return -1;
} }
if (ioctl(twi->fd, I2C_SLAVE, twi->address) < 0) { if (ioctl(twi->fd, I2C_SLAVE, twi->address) < 0)
fprintf(stderr, "failed to select slave address '%d': %s\n", twi->address, strerror(errno)); {
fprintf(stderr, "failed to select slave address '%d': %s\n",
twi->address, strerror(errno));
close(twi->fd); close(twi->fd);
return -1; return -1;
} }
twi->connected = 1; twi->connected = 1;
return 0; return 0;
} } /* twi_open_device */
/* *************************************************************************
* twi_close
* ************************************************************************* */
static int twi_close(struct multiboot *mboot) static int twi_close(struct multiboot *mboot)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
if (twi->connected) if (twi->connected)
{
twi_switch_application(twi, BOOTTYPE_APPLICATION); twi_switch_application(twi, BOOTTYPE_APPLICATION);
}
twi_close_device(twi); twi_close_device(twi);
return 0; return 0;
} } /* twi_close */
/* *************************************************************************
* twi_open
* ************************************************************************* */
static int twi_open(struct multiboot *mboot) static int twi_open(struct multiboot *mboot)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
if (twi->address == 0) { if (twi->address == 0)
{
fprintf(stderr, "abort: no address given\n"); fprintf(stderr, "abort: no address given\n");
return -1; return -1;
} }
if (twi->device == NULL) { if (twi->device == NULL)
{
twi->device = strdup(TWI_DEFAULT_DEVICE); twi->device = strdup(TWI_DEFAULT_DEVICE);
if (twi->device == NULL) { if (twi->device == NULL)
{
perror("strdup()"); perror("strdup()");
return -1; return -1;
} }
} }
if (twi_open_device(twi) != 0) if (twi_open_device(twi) != 0)
{
return -1; return -1;
}
if (twi_switch_application(twi, BOOTTYPE_BOOTLOADER))
{
fprintf(stderr, "failed to switch to bootloader (invalid address?): %s\n",
strerror(errno));
if (twi_switch_application(twi, BOOTTYPE_BOOTLOADER)) {
fprintf(stderr, "failed to switch to bootloader (invalid address?): %s\n", strerror(errno));
twi_close(mboot); twi_close(mboot);
return -1; return -1;
} }
@ -230,14 +311,18 @@ static int twi_open(struct multiboot *mboot)
usleep(100000); usleep(100000);
char version[16]; char version[16];
if (twi_read_version(twi, version, sizeof(version))) { if (twi_read_version(twi, version, sizeof(version)))
fprintf(stderr, "failed to get bootloader version: %s\n", strerror(errno)); {
fprintf(stderr, "failed to get bootloader version: %s\n",
strerror(errno));
twi_close(mboot); twi_close(mboot);
return -1; return -1;
} }
uint8_t chipinfo[8]; uint8_t chipinfo[8];
if (twi_read_memory(twi, chipinfo, sizeof(chipinfo), MEMTYPE_CHIPINFO, 0x0000)) { if (twi_read_memory(twi, chipinfo, sizeof(chipinfo), MEMTYPE_CHIPINFO, 0x0000))
{
fprintf(stderr, "failed to get chipinfo: %s\n", strerror(errno)); fprintf(stderr, "failed to get chipinfo: %s\n", strerror(errno));
twi_close(mboot); twi_close(mboot);
return -1; return -1;
@ -249,26 +334,43 @@ static int twi_open(struct multiboot *mboot)
twi->flashsize = (chipinfo[4] << 8) + chipinfo[5]; twi->flashsize = (chipinfo[4] << 8) + chipinfo[5];
twi->eepromsize = (chipinfo[6] << 8) + chipinfo[7]; twi->eepromsize = (chipinfo[6] << 8) + chipinfo[7];
printf("device : %-16s (address: 0x%02X)\n", twi->device, twi->address); printf("device : %-16s (address: 0x%02X)\n",
printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n", version, chipinfo[0], chipinfo[1], chipinfo[2], chipname); twi->device, twi->address);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n", twi->flashsize, twi->flashsize, twi->pagesize);
printf("eeprom size : 0x%04x / %5d\n", twi->eepromsize, twi->eepromsize); printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n",
version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n",
twi->flashsize, twi->flashsize, twi->pagesize);
printf("eeprom size : 0x%04x / %5d\n",
twi->eepromsize, twi->eepromsize);
return 0; return 0;
} } /* twi_open */
static int twi_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
/* *************************************************************************
* twi_read
* ************************************************************************* */
static int twi_read(struct multiboot *mboot,
struct databuf *dbuf,
int memtype)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";
int pos = 0; int pos = 0;
int size = (memtype == MEMTYPE_FLASH) ? twi->flashsize : twi->eepromsize; int size = (memtype == MEMTYPE_FLASH) ? twi->flashsize : twi->eepromsize;
while (pos < size) {
while (pos < size)
{
mboot->progress_cb(progress_msg, pos, size); mboot->progress_cb(progress_msg, pos, size);
int len = MIN(READ_BLOCK_SIZE, size - pos); int len = MIN(READ_BLOCK_SIZE, size - pos);
if (twi_read_memory(twi, dbuf->data + pos, len, memtype, pos)) {
if (twi_read_memory(twi, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -280,21 +382,30 @@ static int twi_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
mboot->progress_cb(progress_msg, pos, size); mboot->progress_cb(progress_msg, pos, size);
return 0; return 0;
} } /* twi_read */
static int twi_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
/* *************************************************************************
* twi_write
* ************************************************************************* */
static int twi_write(struct multiboot *mboot,
struct databuf *dbuf,
int memtype)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom"; char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";
int pos = 0; int pos = 0;
while (pos < dbuf->length) { while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = (memtype == MEMTYPE_FLASH) ? twi->pagesize : WRITE_BLOCK_SIZE; int len = (memtype == MEMTYPE_FLASH) ? twi->pagesize : WRITE_BLOCK_SIZE;
len = MIN(len, dbuf->length - pos); len = MIN(len, dbuf->length - pos);
if (twi_write_memory(twi, dbuf->data + pos, len, memtype, pos)) {
if (twi_write_memory(twi, dbuf->data + pos, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
@ -304,8 +415,12 @@ static int twi_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0; return 0;
} } /* twi_write */
/* *************************************************************************
* twi_verify
* ************************************************************************* */
static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype) static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
@ -313,16 +428,20 @@ static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype
int pos = 0; int pos = 0;
uint8_t comp[READ_BLOCK_SIZE]; uint8_t comp[READ_BLOCK_SIZE];
while (pos < dbuf->length) {
while (pos < dbuf->length)
{
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos); int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
if (twi_read_memory(twi, comp, len, memtype, pos)) { if (twi_read_memory(twi, comp, len, memtype, pos))
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
return -1; return -1;
} }
if (memcmp(comp, dbuf->data + pos, len) != 0x00) { if (memcmp(comp, dbuf->data + pos, len) != 0x00)
{
mboot->progress_cb(progress_msg, -1, -1); mboot->progress_cb(progress_msg, -1, -1);
fprintf(stderr, "verify failed at page 0x%04x!!\n", pos); fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
return -1; return -1;
@ -335,71 +454,85 @@ static int twi_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype
mboot->progress_cb(progress_msg, pos, dbuf->length); mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0; return 0;
} } /* twi_verify */
/* *************************************************************************
* twi_optarg_cb
* ************************************************************************* */
static int twi_optarg_cb(int val, const char *arg, void *privdata) static int twi_optarg_cb(int val, const char *arg, void *privdata)
{ {
struct twi_privdata *twi = (struct twi_privdata *)privdata; struct twi_privdata *twi = (struct twi_privdata *)privdata;
switch (val) { switch (val)
case 'a': /* address */ {
{ case 'a': /* address */
char *endptr; {
twi->address = strtol(arg, &endptr, 16); char *endptr;
if (*endptr != '\0' || twi->address < 0x01 || twi->address > 0x7F) {
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */ twi->address = strtol(arg, &endptr, 16);
{ if (*endptr != '\0' || twi->address < 0x01 || twi->address > 0x7F)
if (twi->device != NULL) { {
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;
case 'd': /* device */
if (twi->device != NULL)
{
fprintf(stderr, "invalid device: '%s'\n", optarg); fprintf(stderr, "invalid device: '%s'\n", optarg);
return -1; return -1;
} }
twi->device = strdup(optarg); twi->device = strdup(optarg);
if (twi->device == NULL) { if (twi->device == NULL)
{
perror("strdup()"); perror("strdup()");
return -1; return -1;
} }
} break;
break;
case 'h': case 'h':
case '?': /* error */ case '?': /* error */
fprintf(stderr, "Usage: twiboot [options]\n" fprintf(stderr, "Usage: twiboot [options]\n"
" -a <address> - selects i2c address (0x01 - 0x7F)\n" " -a <address> - selects i2c address (0x01 - 0x7F)\n"
" -d <device> - selects i2c device (default: /dev/i2c-0)\n" " -d <device> - selects i2c device (default: /dev/i2c-0)\n"
" -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n" " -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
" -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n" " -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
" -n - disable verify after write\n" " -n - disable verify after write\n"
" -p <0|1|2> - progress bar mode\n" " -p <0|1|2> - progress bar mode\n"
"\n" "\n"
"Example: twiboot -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n" "Example: twiboot -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
"\n"); "\n");
return -1; return -1;
default: default:
return 1; return 1;
} }
return 0; return 0;
} } /* twi_optarg_cb */
/* *************************************************************************
* twi_alloc
* ************************************************************************* */
static struct multiboot * twi_alloc(void) static struct multiboot * twi_alloc(void)
{ {
struct multiboot * mboot = malloc(sizeof(struct multiboot)); struct multiboot * mboot = malloc(sizeof(struct multiboot));
if (mboot == NULL) if (mboot == NULL)
{
return NULL; return NULL;
}
memset(mboot, 0x00, sizeof(struct multiboot)); memset(mboot, 0x00, sizeof(struct multiboot));
mboot->ops = &twi_ops; mboot->ops = &twi_ops;
struct twi_privdata *twi = malloc(sizeof(struct twi_privdata)); struct twi_privdata *twi = malloc(sizeof(struct twi_privdata));
if (twi == NULL) { if (twi == NULL)
{
free(mboot); free(mboot);
return NULL; return NULL;
} }
@ -412,50 +545,74 @@ static struct multiboot * twi_alloc(void)
mboot->privdata = twi; mboot->privdata = twi;
return mboot; return mboot;
} } /* twi_alloc */
/* *************************************************************************
* twi_free
* ************************************************************************* */
static void twi_free(struct multiboot *mboot) static void twi_free(struct multiboot *mboot)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
if (twi->device != NULL) if (twi->device != NULL)
{
free(twi->device); free(twi->device);
}
free(twi); free(twi);
free(mboot); free(mboot);
} } /* twi_free */
static int twi_get_memtype(struct multiboot *mboot, const char *memname)
/* *************************************************************************
* twi_get_memtype
* ************************************************************************* */
static int twi_get_memtype(struct multiboot *mboot,
const char *memname)
{ {
if (strcmp(memname, "flash") == 0) if (strcmp(memname, "flash") == 0)
{
return MEMTYPE_FLASH; return MEMTYPE_FLASH;
}
else if (strcmp(memname, "eeprom") == 0) else if (strcmp(memname, "eeprom") == 0)
{
return MEMTYPE_EEPROM; return MEMTYPE_EEPROM;
}
return -1; return -1;
} } /* twi_get_memtype */
static int twi_get_memsize(struct multiboot *mboot, int memtype)
/* *************************************************************************
* twi_get_memsize
* ************************************************************************* */
static int twi_get_memsize(struct multiboot *mboot,
int memtype)
{ {
struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata; struct twi_privdata *twi = (struct twi_privdata *)mboot->privdata;
if (!twi->connected) if (!twi->connected)
return 0; {
switch (memtype) {
case MEMTYPE_FLASH:
return twi->flashsize;
case MEMTYPE_EEPROM:
return twi->eepromsize;
default:
return 0; return 0;
} }
}
struct multiboot_ops twi_ops = { switch (memtype)
{
case MEMTYPE_FLASH:
return twi->flashsize;
case MEMTYPE_EEPROM:
return twi->eepromsize;
default:
return 0;
}
} /* twi_get_memsize */
struct multiboot_ops twi_ops =
{
.alloc = twi_alloc, .alloc = twi_alloc,
.free = twi_free, .free = twi_free,
.get_memtype = twi_get_memtype, .get_memtype = twi_get_memtype,