From f2f5fd2fa13f74560bb2cfd88417ad6c1e230988 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 18 Jan 2012 20:45:18 +1300 Subject: Added unfinished, untested upgrade tool. --- upgrade/Makefile | 22 ++++++++ upgrade/bindata.S | 28 ++++++++++ upgrade/bindata.h | 32 +++++++++++ upgrade/dfu.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ upgrade/dfu.h | 86 ++++++++++++++++++++++++++++ upgrade/main.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++ upgrade/stm32mem.c | 97 ++++++++++++++++++++++++++++++++ upgrade/stm32mem.h | 30 ++++++++++ 8 files changed, 605 insertions(+) create mode 100644 upgrade/Makefile create mode 100644 upgrade/bindata.S create mode 100644 upgrade/bindata.h create mode 100644 upgrade/dfu.c create mode 100644 upgrade/dfu.h create mode 100644 upgrade/main.c create mode 100644 upgrade/stm32mem.c create mode 100644 upgrade/stm32mem.h (limited to 'upgrade') diff --git a/upgrade/Makefile b/upgrade/Makefile new file mode 100644 index 0000000..65d88e5 --- /dev/null +++ b/upgrade/Makefile @@ -0,0 +1,22 @@ + +CC = $(CROSS_COMPILE)gcc + +CFLAGS = -Wall -Wextra -std=gnu99 -O0 -g -MD +LDFLAGS = -lusb + +OBJ = bindata.o \ + dfu.o \ + stm32mem.o \ + main.o + +all: bmp_upgrade + +bmp_upgrade: $(OBJ) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +.PHONY: clean +clean: + -rm -rf bmp_upgrade *.d *.o + +-include *.d + diff --git a/upgrade/bindata.S b/upgrade/bindata.S new file mode 100644 index 0000000..1d94da5 --- /dev/null +++ b/upgrade/bindata.S @@ -0,0 +1,28 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +.section .rodata +.global _bindata, _bindatalen + +_bindata: + .incbin "../src/blackmagic.bin" + +_bindatalen: + .word . - _bindata + diff --git a/upgrade/bindata.h b/upgrade/bindata.h new file mode 100644 index 0000000..3679692 --- /dev/null +++ b/upgrade/bindata.h @@ -0,0 +1,32 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +#ifndef __BINDATA_H +#define __BINDATA_H + +#ifndef WIN32 +#define bindatalen _bindatalen +#define bindata _bindata +#endif + +extern const uint32_t bindatalen; +extern const uint8_t bindata[]; + +#endif + diff --git a/upgrade/dfu.c b/upgrade/dfu.c new file mode 100644 index 0000000..2ab16ed --- /dev/null +++ b/upgrade/dfu.c @@ -0,0 +1,150 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ + +#include + +#include "dfu.h" + +/* DFU Requests: Refer to Table 3.2 */ +#define DFU_DETACH 0x00 +#define DFU_DNLOAD 0x01 +#define DFU_UPLOAD 0x02 +#define DFU_GETSTATUS 0x03 +#define DFU_CLRSTATUS 0x04 +#define DFU_GETSTATE 0x05 +#define DFU_ABORT 0x06 + +#define USB_DEFAULT_TIMEOUT 1000 +#define DFU_DETACH_TIMEOUT 1000 + +int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout) +{ + return usb_control_msg(dev, + USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_DETACH, wTimeout, iface, NULL, 0, + USB_DEFAULT_TIMEOUT); +} + +int dfu_dnload(usb_dev_handle *dev, uint16_t iface, + uint16_t wBlockNum, void *data, uint16_t size) +{ + return usb_control_msg(dev, + USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_DNLOAD, wBlockNum, iface, data, size, + USB_DEFAULT_TIMEOUT); +} + +int dfu_upload(usb_dev_handle *dev, uint16_t iface, + uint16_t wBlockNum, void *data, uint16_t size) +{ + return usb_control_msg(dev, + USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_DNLOAD, wBlockNum, iface, data, size, + USB_DEFAULT_TIMEOUT); +} + +int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status) +{ + return usb_control_msg(dev, + USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_GETSTATUS, 0, iface, (void*)status, sizeof(dfu_status), + USB_DEFAULT_TIMEOUT); +} + +int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface) +{ + return usb_control_msg(dev, + USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_CLRSTATUS, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT); +} + +int dfu_getstate(usb_dev_handle *dev, uint16_t iface) +{ + int i; + uint8_t state; + do { + i = usb_control_msg(dev, + USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_GETSTATE, 0, iface, &state, 1, USB_DEFAULT_TIMEOUT); + } while(i == 0); + + if(i > 0) + return state; + else + return i; +} + +int dfu_abort(usb_dev_handle *dev, uint16_t iface) +{ + return usb_control_msg(dev, + USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + DFU_ABORT, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT); +} + + +int dfu_makeidle(usb_dev_handle *dev, uint16_t iface) +{ + int i; + dfu_status status; + + for(i = 0; i < 3; i++) { + if(dfu_getstatus(dev, iface, &status) < 0) { + dfu_clrstatus(dev, iface); + continue; + } + + i--; + + switch(status.bState) { + case STATE_DFU_IDLE: + return 0; + + case STATE_DFU_DOWNLOAD_SYNC: + case STATE_DFU_DOWNLOAD_IDLE: + case STATE_DFU_MANIFEST_SYNC: + case STATE_DFU_UPLOAD_IDLE: + case STATE_DFU_DOWNLOAD_BUSY: + case STATE_DFU_MANIFEST: + dfu_abort(dev, iface); + continue; + + case STATE_DFU_ERROR: + dfu_clrstatus(dev, iface); + continue; + + case STATE_APP_IDLE: + dfu_detach(dev, iface, DFU_DETACH_TIMEOUT); + continue; + + case STATE_APP_DETACH: + case STATE_DFU_MANIFEST_WAIT_RESET: + usb_reset(dev); + return -1; + + default: + return -1; + } + + } + + return -1; +} + + diff --git a/upgrade/dfu.h b/upgrade/dfu.h new file mode 100644 index 0000000..1594962 --- /dev/null +++ b/upgrade/dfu.h @@ -0,0 +1,86 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +#ifndef __DFU_H +#define __DFU_H + +#include + +#include + +/* DFU states as returned by DFU_GETSTATE and DFU_GETSTATUS request in bState field. + * Refer to Section 6.1.2 + * Refer to Figure A.1 for state diagram + */ +#define STATE_APP_IDLE 0x00 +#define STATE_APP_DETACH 0x01 +#define STATE_DFU_IDLE 0x02 +#define STATE_DFU_DOWNLOAD_SYNC 0x03 +#define STATE_DFU_DOWNLOAD_BUSY 0x04 +define STATE_DFU_DOWNLOAD_IDLE 0x05 +#define STATE_DFU_MANIFEST_SYNC 0x06 +#define STATE_DFU_MANIFEST 0x07 +#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 +#define STATE_DFU_UPLOAD_IDLE 0x09 +#define STATE_DFU_ERROR 0x0a + +/* DFU status codes as returned by DFU_GETSTATUS request in bStatus field. + * Refer to Section 6.1.2 */ +#define DFU_STATUS_OK 0x00 +#define DFU_STATUS_ERROR_TARGET 0x01 +#define DFU_STATUS_ERROR_FILE 0x02 +#define DFU_STATUS_ERROR_WRITE 0x03 +#define DFU_STATUS_ERROR_ERASE 0x04 +#define DFU_STATUS_ERROR_CHECK_ERASED 0x05 +#define DFU_STATUS_ERROR_PROG 0x06 +#define DFU_STATUS_ERROR_VERIFY 0x07 +#define DFU_STATUS_ERROR_ADDRESS 0x08 +#define DFU_STATUS_ERROR_NOTDONE 0x09 +#define DFU_STATUS_ERROR_FIRMWARE 0x0a +#define DFU_STATUS_ERROR_VENDOR 0x0b +#define DFU_STATUS_ERROR_USBR 0x0c +#define DFU_STATUS_ERROR_POR 0x0d +#define DFU_STATUS_ERROR_UNKNOWN 0x0e +#define DFU_STATUS_ERROR_STALLEDPKT 0x0f + +/* Device status structure returned by DFU_GETSTATUS request. + * Refer to Section 6.1.2 */ +typedef struct dfu_status { + uint8_t bStatus; + uint32_t bwPollTimeout:24; + uint8_t bState; + uint8_t iString; +} __attribute__((packed)) dfu_status; + + +int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout); +int dfu_dnload(usb_dev_handle *dev, uint16_t iface, + uint16_t wBlockNum, void *data, uint16_t size); +int dfu_upload(usb_dev_handle *dev, uint16_t iface, + uint16_t wBlockNum, void *data, uint16_t size); +int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status); +int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface); +int dfu_getstate(usb_dev_handle *dev, uint16_t iface); +int dfu_abort(usb_dev_handle *dev, uint16_t iface); + +int dfu_makeidle(usb_dev_handle *dev, uint16_t iface); + + +#endif + diff --git a/upgrade/main.c b/upgrade/main.c new file mode 100644 index 0000000..bdb1b6b --- /dev/null +++ b/upgrade/main.c @@ -0,0 +1,160 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +#include +#include +#include + +#include "dfu.h" +#include "stm32mem.h" +#include "bindata.h" + +#define VERSION "1.0" + +#define LOAD_ADDRESS 0x8002000 + +void banner(void) +{ + puts("\nBlack Magic Probe -- Firmware Upgrade Utility -- Version " VERSION); + puts("Copyright (C) 2011 Black Sphere Technologies Ltd."); + puts("License GPLv3+: GNU GPL version 3 or later \n"); +} + + +struct usb_device * find_dev(void) +{ + struct usb_bus *bus; + struct usb_device *dev; + struct usb_dev_handle *handle; + char man[40]; + char prod[40]; + + usb_find_busses(); + usb_find_devices(); + + for(bus = usb_get_busses(); bus; bus = bus->next) { + for(dev = bus->devices; dev; dev = dev->next) { + /* Check for ST Microelectronics vendor ID */ + if(dev->descriptor.idVendor != 0x483) continue; + + handle = usb_open(dev); + usb_get_string_simple(handle, dev->descriptor.iManufacturer, man, + sizeof(man)); + usb_get_string_simple(handle, dev->descriptor.iProduct, prod, + sizeof(prod)); +#if 0 + printf("%s:%s [%04X:%04X] %s : %s\n", bus->dirname, dev->filename, + dev->descriptor.idVendor, dev->descriptor.idProduct, man, prod); +#endif + usb_close(handle); + + if((dev->descriptor.idProduct == 0x5740) && + !strcmp(man, "Black Sphere Technologies") && + !strcmp(prod, "Black Magic Probe")) + return dev; + + if((dev->descriptor.idProduct == 0xDF11) && + !strcmp(man, "Black Sphere Technologies") && + !strcmp(prod, "Black Magic Probe (Upgrade)")) + return dev; + } + } + return NULL; +} + +usb_dev_handle * get_dfu_interface(struct usb_device *dev, uint16_t *interface) +{ + int i, j, k; + struct usb_config_descriptor *config; + struct usb_interface_descriptor *iface; + + usb_dev_handle *handle; + + for(i = 0; i < dev->descriptor.bNumConfigurations; i++) { + config = &dev->config[i]; + + for(j = 0; j < config->bNumInterfaces; j++) { + for(k = 0; k < config->interface[j].num_altsetting; k++) { + iface = &config->interface[j].altsetting[k]; + if((iface->bInterfaceClass == 0xFE) && + (iface->bInterfaceSubClass = 0x01)) { + handle = usb_open(dev); + //usb_set_configuration(handle, i); + usb_claim_interface(handle, j); + //usb_set_altinterface(handle, k); + *interface = j; + return handle; + } + } + + } + } + return NULL; +} + +int main(void) +{ + struct usb_device *dev; + usb_dev_handle *handle; + uint16_t iface; + int state; + uint32_t offset; + + banner(); + usb_init(); + +retry: + if(!(dev = find_dev()) || !(handle = get_dfu_interface(dev, &iface))) { + puts("FATAL: No compatible device found!\n"); + return -1; + } + + state = dfu_getstate(handle, iface); + if((state < 0) || (state == STATE_APP_IDLE)) { + puts("Resetting device in firmware upgrade mode..."); + dfu_detach(handle, iface, 1000); + usb_release_interface(handle, iface); + usb_close(handle); +#ifdef WIN32 + Sleep(3000); +#else + sleep(1); +#endif + goto retry; + } + printf("Found device at %s:%s\n", dev->bus->dirname, dev->filename); + + dfu_makeidle(handle, iface); + + for(offset = 0; offset < bindatalen; offset += 1024) { + printf("Progress: %d%%\r", (offset*100)/bindatalen); + fflush(stdout); + stm32_mem_erase(handle, iface, LOAD_ADDRESS + offset); + stm32_mem_write(handle, iface, (void*)&bindata[offset], 1024); + } + stm32_mem_manifest(handle, iface); + + usb_release_interface(handle, iface); + usb_close(handle); + + puts("All operations complete!\n"); + + return 0; +} + diff --git a/upgrade/stm32mem.c b/upgrade/stm32mem.c new file mode 100644 index 0000000..10dd744 --- /dev/null +++ b/upgrade/stm32mem.c @@ -0,0 +1,97 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +#include +#include + +#ifdef WIN32 +# include +#else +# include +#endif + +#include "dfu.h" +#include "stm32mem.h" + +#define STM32_CMD_GETCOMMANDS 0x00 +#define STM32_CMD_SETADDRESSPOINTER 0x21 +#define STM32_CMD_ERASE 0x41 + +static int stm32_download(usb_dev_handle *dev, uint16_t iface, + uint16_t wBlockNum, void *data, int size) +{ + dfu_status status; + int i; + + if((i = dfu_dnload(dev, iface, wBlockNum, data, size)) < 0) return i; + while(1) { + if((i = dfu_getstatus(dev, iface, &status)) < 0) return i; + switch(status.bState) { + case STATE_DFU_DOWNLOAD_BUSY: +#ifdef WIN32 + Sleep(status.bwPollTimeout); +#else + usleep(status.bwPollTimeout * 1000); +#endif + break; + case STATE_DFU_DOWNLOAD_IDLE: + return 0; + default: + return -1; + } + } +} + +int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr) +{ + uint8_t request[5]; + + request[0] = STM32_CMD_ERASE; + memcpy(request+1, &addr, sizeof(addr)); + + return stm32_download(dev, iface, 0, request, sizeof(request)); +} + +int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size) +{ + return stm32_download(dev, iface, 2, data, size); +} + +int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface) +{ + dfu_status status; + int i; + + if((i = dfu_dnload(dev, iface, 0, NULL, 0)) < 0) return i; + while(1) { + if((i = dfu_getstatus(dev, iface, &status)) < 0) return 0; +#ifdef WIN32 + Sleep(status.bwPollTimeout); +#else + usleep(status.bwPollTimeout * 1000); +#endif + switch(status.bState) { + case STATE_DFU_MANIFEST: + return 0; + default: + return -1; + } + } +} + diff --git a/upgrade/stm32mem.h b/upgrade/stm32mem.h new file mode 100644 index 0000000..34cdfb1 --- /dev/null +++ b/upgrade/stm32mem.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * 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 3 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, see . + */ +#ifndef __STM32MEM_H +#define __STM32MEM_H + +#include + +int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr); +int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size); +int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface); + +#endif + -- cgit v1.2.3