[PATCH] add, remove and check TI Stellaris DFU prefix
Tommi Keisala
tommi.keisala at ray.fi
Tue Jul 10 11:42:04 CEST 2012
Patch adds functionality to add, remove and check TI Stellaris DFU prefix with
dfu-suffix tool. TI Stellaris bootloader expects to have 8 byte prefix in the
beginning of binary image. Patch adds option -s --stellaris to dfu-suffix to
add that prefix (with -a).
When adding (-a) prefix (and suffix) option -s requires address as an argument.
To delete prefix use -D and -T option.
If -D is used to Stellaris prefixed file only suffix gets removed. Use -D again
with -T option to delete prefix.
To check for TI Stellaris prefix use -c with -T option.
To add DFU suffix and prefix use:
dfu-suffix -s 0x2000 -v 0x1cbe -p 0x00ff -d 0x0000 -a image.bin
To remove DFU suffix and prefix use:
dfu-suffix -T -D image.bin
To check DFU suffix use:
dfu-suffix -T -c image.bin
Signed-off-by: Tommi Keisala <tommi.keisala at ray.fi>
---
src/Makefile.am | 4 +-
src/lmdfu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/lmdfu.h | 30 +++++++++
src/suffix.c | 93 ++++++++++++++++++++++------
4 files changed, 293 insertions(+), 19 deletions(-)
create mode 100644 src/lmdfu.c
create mode 100644 src/lmdfu.h
diff --git a/src/Makefile.am b/src/Makefile.am
index df2ef36..99df307 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,4 +19,6 @@ dfu_util_SOURCES = main.c \
dfu_suffix_SOURCES = suffix.c \
dfu_file.h \
- dfu_file.c
+ dfu_file.c \
+ lmdfu.c \
+ lmdfu.h
diff --git a/src/lmdfu.c b/src/lmdfu.c
new file mode 100644
index 0000000..0989056
--- /dev/null
+++ b/src/lmdfu.c
@@ -0,0 +1,185 @@
+/* This implements the TI Stellaris DFU
+ * as per the Application Update Using the USB Device Firmware Upgrade Class
+ * (Document AN012373)
+ * http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=spma003&fileType=pdf
+ *
+ * Copyright 2012 Tommi Keisala <tommi.keisala at ray.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "portable.h"
+#include "dfu.h"
+#include "dfu_file.h"
+#include "quirks.h"
+
+/* lmdfu_dfu_prefix payload length excludes prefix and suffix */
+unsigned char lmdfu_dfu_prefix[] = {
+ 0x01, /* STELLARIS_DFU_PROG */
+ 0x00, /* Reserved */
+ 0x00, /* LSB start address / 1024 */
+ 0x20, /* MSB start address / 1024 */
+ 0x00, /* LSB file payload length */
+ 0x00, /* Byte 2 file payload length */
+ 0x00, /* Byte 3 file payload length */
+ 0x00, /* MSB file payload length */
+};
+
+int lmdfu_add_prefix(struct dfu_file file, unsigned int address)
+{
+ int ret;
+ uint16_t addr;
+ uint32_t len;
+
+ unsigned char *data = NULL;
+
+ fseek(file.filep, 0, SEEK_END);
+ len = ftell(file.filep);
+ rewind(file.filep);
+
+ data = (unsigned char *)malloc(len);
+ if (!data) {
+ fprintf(stderr, "Unable to allocate buffer.\n");
+ exit(1);
+ }
+
+ ret = fread(data, 1, len, file.filep);
+ if (ret < 0) {
+ fprintf(stderr, "Could not read file\n");
+ perror(file.name);
+ free(data);
+ return ret;
+ } else if (ret < len) {
+ fprintf(stderr, "Could not read whole file\n");
+ free(data);
+ return -EIO;
+ }
+
+ /* fill Stellaris lmdfu_dfu_prefix with correct data */
+ addr = address / 1024;
+ lmdfu_dfu_prefix[2] = (unsigned char)addr & 0xff;
+ lmdfu_dfu_prefix[3] = (unsigned char)addr >> 8;
+ lmdfu_dfu_prefix[4] = (unsigned char)len & 0xff;
+ lmdfu_dfu_prefix[5] = (unsigned char)(len >> 8) & 0xff;
+ lmdfu_dfu_prefix[6] = (unsigned char)(len >> 16) & 0xff;
+ lmdfu_dfu_prefix[7] = (unsigned char)(len) >> 24;
+
+ rewind(file.filep);
+ ret = fwrite(lmdfu_dfu_prefix, 1, sizeof(lmdfu_dfu_prefix), file.filep);
+ if (ret < 0) {
+ fprintf(stderr, "Could not write TI Stellaris DFU prefix\n");
+ perror(file.name);
+ } else if (ret < sizeof(lmdfu_dfu_prefix)) {
+ fprintf(stderr, "Could not write while file\n");
+ ret = -EIO;
+ }
+
+ ret = fwrite(data, 1, len, file.filep);
+ if (ret < 0) {
+ fprintf(stderr, "Could not write data after TI Stellaris DFU "
+ "prefix\n");
+ perror(file.name);
+ } else if (ret < sizeof(lmdfu_dfu_prefix)) {
+ fprintf(stderr, "Could not write whole file\n");
+ ret = -EIO;
+ }
+
+ rewind(file.filep);
+ printf("TI Stellaris DFU prefix added.\n");
+ return 0;
+}
+
+int lmdfu_remove_prefix(struct dfu_file *file)
+{
+ long len;
+ unsigned char *data;
+ int ret;
+
+#ifdef HAVE_FTRUNCATE
+ printf("Remove TI Stellaris prefix\n");
+
+ fseek(file->filep, 0, SEEK_END);
+ len = ftell(file->filep);
+ rewind(file->filep);
+
+ data = (unsigned char *)malloc(len);
+ if (!data) {
+ fprintf(stderr, "Unable to allocate buffer.\n");
+ exit(1);
+ }
+
+ ret = fread(data, 1, len, file->filep);
+ if (ret < 0) {
+ fprintf(stderr, "Could not read file\n");
+ perror(file->name);
+ free(data);
+ return ret;
+ } else if (ret < len) {
+ fprintf(stderr, "Could not read whole file\n");
+ free(data);
+ return -EIO;
+ }
+
+ ret = ftruncate(fileno(file->filep), 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error truncating\n");
+ }
+ rewind(file->filep);
+
+ fwrite(data + sizeof(lmdfu_dfu_prefix), 1, len - sizeof(lmdfu_dfu_prefix),
+ file->filep);
+
+ printf("TI Stellaris prefix removed\n");
+#else
+ printf("Prefix removal not implemented on this platform\n");
+#endif /* HAVE_FTRUNCATE */
+
+ return ret;
+}
+
+int lmdfu_check_prefix(struct dfu_file *file)
+{
+ unsigned char *data;
+ int ret;
+
+ data = malloc(sizeof(lmdfu_dfu_prefix));
+
+ ret = fread(data, 1, sizeof(lmdfu_dfu_prefix), file->filep);
+ if (ret < sizeof(lmdfu_dfu_prefix)) {
+ fprintf(stderr, "Could not read prefix\n");
+ perror(file->name);
+ }
+
+ if ((data[0] != 0x01) && (data[1] != 0x00)) {
+ printf("Not valid TI Stellaris DFU prefix\n");
+ ret = 0;
+ goto out_rewind;
+ } else {
+ printf
+ ("Possible TI Stellaris DFU prefix with the following properties\n");
+ printf("Address: 0x%08x\n",
+ 1024 * (data[3] << 8 | data[2]));
+ printf("Payload length: %d\n",
+ data[4] | data[5] << 8 | data[6] << 16 | data[7] << 14);
+ }
+
+out_rewind:
+ rewind(file->filep);
+ return ret;
+}
diff --git a/src/lmdfu.h b/src/lmdfu.h
new file mode 100644
index 0000000..8af689f
--- /dev/null
+++ b/src/lmdfu.h
@@ -0,0 +1,30 @@
+
+/* This implements the TI Stellaris DFU
+ * as per the Application Update Using the USB Device Firmware Upgrade Class
+ * (Document AN012373)
+ *
+ * Copyright 2012 Tommi Keisala <tommi.keisala at ray.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LMDFU_H
+#define LMDFU_H
+
+int lmdfu_add_prefix(struct dfu_file file, unsigned int address);
+int lmdfu_remove_prefix(struct dfu_file *file);
+int lmdfu_check_prefix(struct dfu_file *file);
+
+#endif /* LMDFU_H */
diff --git a/src/suffix.c b/src/suffix.c
index fe19194..12d99cb 100644
--- a/src/suffix.c
+++ b/src/suffix.c
@@ -20,8 +20,10 @@
#include <stdio.h>
#include <stdint.h>
#include <getopt.h>
+#include <string.h>
#include "dfu_file.h"
+#include "lmdfu.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -36,17 +38,28 @@ enum mode {
MODE_CHECK
};
+enum lmdfu_mode {
+ LMDFU_NONE,
+ LMDFU_ADD,
+ LMDFU_DEL,
+ LMDFU_CHECK
+};
+
static void help(void)
{
printf("Usage: dfu-suffix [options] <file>\n"
- " -h --help\tPrint this help message\n"
- " -V --version\tPrint the version number\n"
- " -D --delete\tDelete DFU suffix from <file>\n"
- " -p --pid\tAdd product ID into DFU suffix in <file>\n"
- " -v --vid\tAdd vendor ID into DFU suffix in <file>\n"
- " -d --did\tAdd device ID into DFU suffix in <file>\n"
- " -c --check\tCheck DFU suffix of <file>\n"
- " -a --add\tAdd DFU suffix to <file>\n"
+ " -h --help\t\t\tPrint this help message\n"
+ " -V --version\t\t\tPrint the version number\n"
+ " -D --delete\t\t\tDelete DFU suffix from <file>\n"
+ " -p --pid\t\t\tAdd product ID into DFU suffix in <file>\n"
+ " -v --vid\t\t\tAdd vendor ID into DFU suffix in <file>\n"
+ " -d --did\t\t\tAdd device ID into DFU suffix in <file>\n"
+ " -c --check\t\t\tCheck DFU suffix of <file>\n"
+ " -a --add\t\t\tAdd DFU suffix to <file>\n"
+ " -s --stellaris-address address \tAdd TI Stellaris address "
+ "prefix to <file>.\n\t\t\t\tUse with -a\n"
+ " -T --stellaris\t\tTI Stellaris prefix extension from "
+ "<file>.\n\t\t\t\tUse with -D or -c\n"
);
}
@@ -67,6 +80,8 @@ static struct option opts[] = {
{ "did", 1, 0, 'd' },
{ "check", 1, 0, 'c' },
{ "add", 1, 0, 'a' },
+ { "stellaris-address", 1, 0, 's' },
+ { "stellaris", 0, 0, 'T' },
};
static int check_suffix(struct dfu_file *file) {
@@ -86,13 +101,13 @@ static int check_suffix(struct dfu_file *file) {
return ret;
}
-static void remove_suffix(struct dfu_file *file)
+static int remove_suffix(struct dfu_file *file)
{
int ret;
ret = parse_dfu_suffix(file);
if (ret <= 0)
- exit(1);
+ return 0;
#ifdef HAVE_FTRUNCATE
/* There is no easy way to truncate to a size with stdio */
@@ -106,17 +121,12 @@ static void remove_suffix(struct dfu_file *file)
#else
printf("Suffix removal not implemented on this platform\n");
#endif /* HAVE_FTRUNCATE */
+ return 1;
}
static void add_suffix(struct dfu_file *file, int pid, int vid, int did) {
int ret;
- ret = check_suffix(file);
- if (ret > 0) {
- printf("Please remove existing DFU suffix before adding a new one.\n");
- exit(1);
- }
-
file->idProduct = pid;
file->idVendor = vid;
file->bcdDevice = did;
@@ -134,6 +144,10 @@ int main(int argc, char **argv)
struct dfu_file file;
int pid, vid, did;
enum mode mode = MODE_NONE;
+ enum lmdfu_mode lmdfu_mode = LMDFU_NONE;
+ unsigned int lmdfu_flash_address=0;
+ int lmdfu_prefix=0;
+ char *end;
print_version();
@@ -142,7 +156,7 @@ int main(int argc, char **argv)
while (1) {
int c, option_index = 0;
- c = getopt_long(argc, argv, "hVD:p:v:d:c:a:", opts,
+ c = getopt_long(argc, argv, "hVD:p:v:d:c:a:s:T", opts,
&option_index);
if (c == -1)
break;
@@ -176,12 +190,27 @@ int main(int argc, char **argv)
file.name = optarg;
mode = MODE_ADD;
break;
+ case 's':
+ lmdfu_mode = LMDFU_ADD;
+ lmdfu_flash_address = strtoul(optarg, &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error: Invalid lmdfu "
+ "address: %s\n", optarg);
+ exit(2);
+ }
+ break;
+ case 'T':
+ lmdfu_mode = LMDFU_CHECK;
+ break;
default:
help();
exit(2);
}
}
+ if(mode == MODE_DEL && lmdfu_mode == LMDFU_CHECK)
+ lmdfu_mode = LMDFU_DEL;
+
if (!file.name) {
fprintf(stderr, "You need to specify a filename\n");
help();
@@ -198,20 +227,48 @@ int main(int argc, char **argv)
switch(mode) {
case MODE_ADD:
+ if (check_suffix(&file)) {
+ if(lmdfu_prefix) lmdfu_check_prefix(&file);
+ printf("Please remove existing DFU suffix before adding a new one.\n");
+ exit(1);
+ }
+ if(lmdfu_mode == LMDFU_ADD) {
+ if(lmdfu_check_prefix(&file)) {
+ fprintf(stderr, "Adding new anyway\n");
+ }
+ lmdfu_add_prefix(file, lmdfu_flash_address);
+ }
add_suffix(&file, pid, vid, did);
break;
case MODE_CHECK:
/* FIXME: could open read-only here */
check_suffix(&file);
+ if(lmdfu_mode == LMDFU_CHECK)
+ lmdfu_check_prefix(&file);
break;
case MODE_DEL:
- remove_suffix(&file);
+ if(!remove_suffix(&file)) {
+ if(lmdfu_mode == LMDFU_DEL)
+ if (lmdfu_check_prefix(&file))
+ lmdfu_remove_prefix(&file);
+ exit(1);
+ }
break;
default:
help();
exit(2);
}
+ if(lmdfu_mode == LMDFU_DEL) {
+ if (check_suffix(&file)) {
+ fprintf(stderr, "DFU suffix exist. Remove suffix before using -T or use it with -D to delete suffix\n");
+ exit(1);
+ } else {
+ if(lmdfu_check_prefix(&file))
+ lmdfu_remove_prefix(&file);
+ }
+ }
+
fclose(file.filep);
exit(0);
}
--
1.7.10.4
--------------030106080504020802080608--
More information about the devel
mailing list