[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