[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