[PATCH] Add TI Stellaris bootloader DFU support

Tommi Keisala tommi.keisala at ray.fi
Fri Jun 29 13:54:06 CEST 2012


This patch adds suppport for TI Stellaris bootloader DFU mode with option -m.
File that is supposed to be flashed needs to be suffixed with dfu-suffix.
Option -m requires address that is used to construct prefix for Stellaris
bootloader use.
---
 src/Makefile.am |    4 +-
 src/dfu_file.c  |    2 -
 src/dfu_file.h  |    3 ++
 src/lmdfu.c     |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lmdfu.h     |   29 +++++++++++
 src/main.c      |   35 +++++++++++--
 6 files changed, 215 insertions(+), 7 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..4e38dac 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,9 @@ dfu_util_SOURCES = main.c \
 		dfu_file.c \
 		dfu_file.h \
 		quirks.c \
-		quirks.h
+		quirks.h \
+		lmdfu.c \
+		lmdfu. h
 
 dfu_suffix_SOURCES = suffix.c \
 		dfu_file.h \
diff --git a/src/dfu_file.c b/src/dfu_file.c
index 96def96..bde571f 100644
--- a/src/dfu_file.c
+++ b/src/dfu_file.c
@@ -27,8 +27,6 @@
 
 #include "dfu_file.h"
 
-#define DFU_SUFFIX_LENGTH 16
-
 unsigned long crc32_table[] = {
     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
diff --git a/src/dfu_file.h b/src/dfu_file.h
index c8b0c60..d0e9a40 100644
--- a/src/dfu_file.h
+++ b/src/dfu_file.h
@@ -5,6 +5,8 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#define DFU_SUFFIX_LENGTH 16
+
 struct dfu_file {
     const char *name;
     FILE *filep;
@@ -20,5 +22,6 @@ struct dfu_file {
 
 int parse_dfu_suffix(struct dfu_file *file);
 int generate_dfu_suffix(struct dfu_file *file);
+uint32_t crc32_byte(uint32_t accum, uint8_t delta);
 
 #endif /* DFU_FILE_H */
diff --git a/src/lmdfu.c b/src/lmdfu.c
new file mode 100644
index 0000000..1561c94
--- /dev/null
+++ b/src/lmdfu.c
@@ -0,0 +1,149 @@
+/* This implements the TI Stellaris DFU
+ * as per the Application Update Using the USB Device Firmware Upgrade Class
+ * (Document AN012373)
+ *
+ * (C) 2007-2008 by Harald Welte <laforge at gnumonks.org>
+ * 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"
+
+/* dfu_prefix payload length excludes prefix and suffix */
+unsigned char 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_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file file,
+		    unsigned int address)
+{
+	unsigned char *data;
+	int data_size;
+	struct dfu_status dst;
+	int bytes_sent = 0;
+	int ret;
+	uint32_t crc;
+	int i;
+	uint16_t addr;
+	uint32_t len;
+
+	data_size = file.size + sizeof(dfu_prefix);
+	data = malloc(data_size);
+	if (!data) {
+		fprintf(stderr, "Could not allocate data buffer\n");
+		return -ENOMEM;
+	}
+
+	/* fill Stellaris dfu_prefix with correct data */
+	addr = address / 1024;
+	len = file.size - DFU_SUFFIX_LENGTH;
+	dfu_prefix[2] = (unsigned char)addr & 0xff;
+	dfu_prefix[3] = (unsigned char)addr >> 8;
+	dfu_prefix[4] = (unsigned char)len & 0xff;
+	dfu_prefix[5] = (unsigned char)(len >> 8) & 0xff;
+	dfu_prefix[6] = (unsigned char)(len >> 16) & 0xff;
+	dfu_prefix[7] = (unsigned char)(len) >> 24;
+
+	memcpy(data, dfu_prefix, sizeof(dfu_prefix));
+
+	ret = fread(data + sizeof(dfu_prefix), 1, file.size, file.filep);
+	if (ret < file.size) {
+		fprintf(stderr, "Could not read data\n");
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	/* recalculate CRC */
+	crc = 0xffffffff;
+	for (i = 0; i < (data_size - 4); i++) {
+		crc = crc32_byte(crc, data[i]);
+	}
+
+	while (bytes_sent < data_size) {
+		int bytes_left;
+		int chunk_size;
+		bytes_left = data_size - bytes_sent;
+		if (bytes_left < xfer_size)
+			chunk_size = bytes_left;
+		else
+			chunk_size = xfer_size;
+
+		ret = dfu_download(dif->dev_handle, dif->interface, i
+				   chunk_size, data + bytes_sent);
+		if (ret < 0) {
+			fprintf(stderr, "Error during download\n");
+			goto out_free;
+		}
+		bytes_sent += ret;
+
+		do {
+			ret = dfu_get_status(dif->dev_handle, dif->interface,
+					     &dst);
+			if (ret < 0) {
+				fprintf(stderr,
+					"Error during download get_status\n");
+				goto out_free;
+			}
+
+			if (dst.bState == DFU_STATE_dfuDNLOAD_IDLE ||
+			    dst.bState == DFU_STATE_dfuERROR)
+				break;
+
+			/* Wait while device executes flashing */
+			if (quirks & QUIRK_POLLTIMEOUT)
+				milli_sleep(DEFAULT_POLLTIMEOUT);
+			else
+				milli_sleep(dst.bwPollTimeout);
+
+		} while (1);
+		if (dst.bStatus != DFU_STATUS_OK) {
+			printf(" failed!\n");
+			printf("state(%u) = %s, status(%u) = %s\n", dst.bState,
+			       dfu_state_to_string(dst.bState), dst.bStatus,
+			       dfu_status_to_string(dst.bStatus));
+			ret = -1;
+			goto out_free;
+		}
+
+	}
+	/* send one zero sized download request to signalize end */
+	ret = dfu_download(dif->dev_handle, dif->interface, 0, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "Error sending completion packet\n");
+		goto out_free;
+	}
+
+	printf("File downloaded succesfully\n");
+	ret = data_size;
+
+out_free:
+	free(data);
+	return ret;
+}
diff --git a/src/lmdfu.h b/src/lmdfu.h
new file mode 100644
index 0000000..aed232b
--- /dev/null
+++ b/src/lmdfu.h
@@ -0,0 +1,29 @@
+
+/* 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_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file file,
+		    unsigned int address);
+
+#endif /* LMDFU_H */
diff --git a/src/main.c b/src/main.c
index 4ac88d5..b282791 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,6 +34,7 @@
 #include "dfu_file.h"
 #include "dfu_load.h"
 #include "dfuse.h"
+#include "lmdfu.h"
 #include "quirks.h"
 
 #ifdef HAVE_USBPATH_H
@@ -549,6 +550,7 @@ static void help(void)
 		"  -s --dfuse-address address\tST DfuSe mode, specify target address for\n"
 		"\t\t\t\traw file download or upload. Not applicable for\n"
 		"\t\t\t\tDfuSe file (.dfu) downloads\n"
+		"  -m --lmdfu-address address\tTI Stellaris bootloader mode\n"
 		);
 }
 
@@ -578,7 +580,8 @@ static struct option opts[] = {
 	{ "upload", 1, 0, 'U' },
 	{ "download", 1, 0, 'D' },
 	{ "reset", 0, 0, 'R' },
-	{ "dfuse-address", 1, 0, 's' }
+	{ "dfuse-address", 1, 0, 's' },
+	{ "lmdfu-address", 1, 0, 'm' }
 };
 
 enum mode {
@@ -610,13 +613,15 @@ int main(int argc, char **argv)
 	int ret;
 	int dfuse = 0;
 	unsigned int dfuse_address = 0; /* FIXME allow address to be zero? */
+	int lmdfu = 0;
+	unsigned int lmdfu_address = 0;
 
 	memset(dif, 0, sizeof(*dif));
 	file.name = NULL;
 
 	while (1) {
 		int c, option_index = 0;
-		c = getopt_long(argc, argv, "hVvled:p:c:i:a:t:U:D:Rs:", opts,
+		c = getopt_long(argc, argv, "hVvled:p:c:i:a:t:U:D:Rs:m:", opts,
 				&option_index);
 		if (c == -1)
 			break;
@@ -698,6 +703,17 @@ int main(int argc, char **argv)
 			    }
 			}
 			break;
+		case 'm':
+			lmdfu =1;
+			if (strcmp(optarg, "default")) {
+                            lmdfu_address = strtoul(optarg, &end, 0);
+                            if (!lmdfu_address || (*end)) {
+                                fprintf(stderr, "Error: Invalid lmdfu address: "
+                                        "%s\n", optarg);
+                                exit(2);
+                            }
+                        }
+			break;
 		default:
 			help();
 			exit(2);
@@ -1132,7 +1148,13 @@ status_again:
 		if (ret < 0)
 			exit(1);
 		if (ret == 0) {
-			fprintf(stderr, "Warning: File has no DFU suffix\n");
+			if(lmdfu) {
+				fprintf(stderr, "Error: File has no DFU suffix\n");
+				fprintf(stderr, "       DFU suffix is required for Stellaris download\n");
+				exit(1);
+			} else {
+				fprintf(stderr, "Warning: File has no DFU suffix\n");
+			}
 		} else if (file.bcdDFU != 0x0100 && file.bcdDFU != 0x11a) {
 			fprintf(stderr, "Unsupported DFU file revision "
 				"%04x\n", file.bcdDFU);
@@ -1152,10 +1174,15 @@ status_again:
 		        if (dfuse_do_dnload(dif, transfer_size, file,
 							dfuse_address) < 0)
 				exit(1);
+		}
+		if (lmdfu) {
+			if (lmdfu_do_dnload(dif, transfer_size, file,
+							lmdfu_address) < 0)
+				exit(1);
 		} else {
 			if (dfuload_do_dnload(dif, transfer_size, file) < 0)
 				exit(1);
-	 	}
+		}
 		fclose(file.filep);
 		break;
 	default:
-- 
1.7.10


--------------050603010604090907010007--



More information about the devel mailing list