From 71cdf0043740361416df97a432dc4f0da225a099 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sat, 20 Oct 2007 09:11:34 +0000 Subject: Initial version of tcctool - a utility for talking to Telechips TCC77x-based devices in USB boot mode, allowing code to be uploaded to RAM and run via USB, without any danger of bricking. When your uploaded code crashes, just power-cycle the device and it is back to normal. Requires libusb. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15217 a1c6a512-1295-4272-9138-f99709370657 --- utils/tcctool/Makefile | 43 +++++++ utils/tcctool/README | 29 +++++ utils/tcctool/tcctool.c | 316 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 388 insertions(+) create mode 100644 utils/tcctool/Makefile create mode 100644 utils/tcctool/README create mode 100644 utils/tcctool/tcctool.c (limited to 'utils') diff --git a/utils/tcctool/Makefile b/utils/tcctool/Makefile new file mode 100644 index 0000000000..4e1ec476ab --- /dev/null +++ b/utils/tcctool/Makefile @@ -0,0 +1,43 @@ +# This contains the file to upload +ROMFILE=player.rom + +CFLAGS=-Wall -W -I/usr/local/include + +ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) +OUTPUT=tcctool.exe +CROSS= +CFLAGS+=-mno-cygwin +else +OUTPUT=tcctool +CROSS=i586-mingw32msvc- +endif + +LIBS = -lusb +WINLIBS = -I libusb-win32-device-bin-0.1.12.1/include libusb-win32-device-bin-0.1.12.1/lib/dynamic/libusb_dyn.c + +NATIVECC = gcc +CC = $(CROSS)gcc + +all: $(OUTPUT) + +tcctool: tcctool.c + gcc $(CFLAGS) $(LIBS) -o tcctool tcctool.c + strip tcctool + +tcctool.exe: tcctool.c + $(CC) $(CFLAGS) $(WINLIBS) -o tcctool.exe tcctool.c + $(CROSS)strip tcctool.exe + +tcctool-mac: tcctool-i386 tcctool-ppc + lipo -create tcctool-ppc tcctool-i386 -output tcctool-mac + +tcctool-i386: tcctool.c usb.h libusb-i386.a + gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -framework iokit -framework coreservices -arch i386 $(CFLAGS) -o tcctool-i386 tcctool.c -I. libusb-i386.a + strip tcctool-i386 + +tcctool-ppc: tcctool.c usb.h libusb-ppc.a + gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -framework iokit -framework coreservices -arch ppc $(CFLAGS) -o tcctool-ppc tcctool.c -I. libusb-ppc.a + strip tcctool-ppc + +clean: + rm -f tcctool.exe tcctool-mac tcctool-i386 tcctool-ppc tcctool *~ diff --git a/utils/tcctool/README b/utils/tcctool/README new file mode 100644 index 0000000000..c2fa8a0fb9 --- /dev/null +++ b/utils/tcctool/README @@ -0,0 +1,29 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + ****************************************************************************/ + +tcctool +------- + +tcctool is a utility for uploading code to Telechips TCC77x based +devices in USB boot mode. + +It has been tested on the iaudio 7 and Logik DAX DAB/MP3 Player, but +should work on other devices if the appropriate magic value is +identified from existing "firmware recovery" programs - see the +"devices" array in tcctool.c + +It can be used for safely testing firmware images before performing a +firmware upgade. + +A first test when using tcctool on a new device can be to upload the +original firmware. If you do this, make sure you upload the same +version that is installed on your player - otherwise you may find +yourself with corrupted config files and music database. diff --git a/utils/tcctool/tcctool.c b/utils/tcctool/tcctool.c new file mode 100644 index 0000000000..22e6f1066d --- /dev/null +++ b/utils/tcctool/tcctool.c @@ -0,0 +1,316 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 Dave Chapman + * + * USB code based on ifp-line - http://ifp-driver.sourceforge.net + * + * ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and + * licensed under the GPL (v2) + * + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.1" + +#define MAX_FIRMWARESIZE (2*1024*1024) /* Arbitrary limit (for safety) */ + +struct device_t +{ + char* name; + char* label; + uint32_t loadaddr; + uint32_t magic; +}; + +static struct device_t devices[] = +{ + {"logikdax", "Logik DAX 1GB DAB/MP3 player", 0x20000000, 0x52e97410 }, + {"iaudio6", "iAudio 6", 0x20000000, 0x62e97010 }, + {"iaudio7", "iAudio 7", 0x20000000, 0x62e97010 } +}; + +#define NUM_DEVICES ((sizeof(devices) / sizeof(struct device_t))) + +int find_device(char* devname) +{ + unsigned int i = 0; + + while ((i < NUM_DEVICES) && (strcmp(devices[i].name,devname))) + i++; + + if (i==NUM_DEVICES) + return -1; + else + return i; +} + +void print_devices(void) +{ + unsigned int i; + + printf("Valid devices are:\n"); + for (i=0; i(b))?(a):(b)) +#endif + +static void put_int32le(uint32_t x, char* p) +{ + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +int upload_app(usb_dev_handle* dh, int device, char* p, int len) +{ + char buf[PACKET_SIZE]; + int err; + int i; + + /* Send the header - Destination address, length and magic value */ + memset(buf, 0, PACKET_SIZE); + + put_int32le(0xf0000000, buf); /* Unknown - always the same */ + put_int32le(len / PACKET_SIZE, buf + 4); + put_int32le(devices[device].loadaddr, buf + 8); + put_int32le(devices[device].magic, buf + 12); + + err = usb_bulk_write(dh, TCC_BULK_TO, buf, PACKET_SIZE, TOUT); + + if (err < 0) + { + fprintf(stderr,"[ERR] Error writing header\n"); + fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); + return -1; + } + + /* Now send the data, PACKET_SIZE bytes at a time. */ + + for (i=0 ; i < (len / PACKET_SIZE) ; i++) + { + err = usb_bulk_write(dh, TCC_BULK_TO, p, PACKET_SIZE, TOUT); + + if (err < 0) + { + fprintf(stderr,"[ERR] Error writing data\n"); + fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); + return -1; + } + + p += PACKET_SIZE; + } + + return 0; +} + + +/* The main function */ + +void do_patching(int device, char* buf, int len) +{ + struct usb_bus *busses; + struct usb_bus *bus; + struct usb_device *tmp_dev; + struct usb_device *dev = NULL; + usb_dev_handle *dh; + int err; + + fprintf(stderr,"[INFO] Searching for TCC device...\n"); + + usb_init(); + if(usb_find_busses() < 0) { + fprintf(stderr, "[ERR] Could not find any USB busses.\n"); + return; + } + + if (usb_find_devices() < 0) { + fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n"); + return; + } + + /* C calling convention, it's not nice to use global stuff */ + busses = usb_get_busses(); + + for (bus = busses; bus; bus = bus->next) { + for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) { + //printf("Found Vendor %04x Product %04x\n",tmp_dev->descriptor.idVendor, tmp_dev->descriptor.idProduct); + if (tmp_dev->descriptor.idVendor == TCC_VENDORID && + tmp_dev->descriptor.idProduct == TCC_PRODUCTID ) { + + dev = tmp_dev; + goto found; + + } + } + } + + if (dev == NULL) { + fprintf(stderr, "[ERR] TCC device not found.\n"); + fprintf(stderr, "[ERR] Ensure your TCC device is in USB boot mode and run tcctool again.\n"); + return; + } + +found: + if ( (dh = usb_open(dev)) == NULL) { + fprintf(stderr,"[ERR] Unable to open TCC device.\n"); + return; + } + + err = usb_set_configuration(dh, 1); + + if (err < 0) { + fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err); + usb_close(dh); + return; + } + + /* "must be called" written in the libusb documentation */ + err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber); + if (err < 0) { + fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err); + usb_close(dh); + return; + } + + fprintf(stderr,"[INFO] Found TCC device, uploading application.\n"); + + /* Now we can transfer the application to the device. */ + + if (upload_app(dh, device, buf, len) < 0) + { + fprintf(stderr,"[ERR] Upload of application failed.\n"); + } + else + { + fprintf(stderr,"[INFO] Patching application uploaded successfully!\n"); + } + + /* release claimed interface */ + usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber); + + usb_close(dh); +} + +off_t filesize(int fd) { + struct stat buf; + + if (fstat(fd,&buf) < 0) { + perror("[ERR] Checking filesize of input file"); + return -1; + } else { + return(buf.st_size); + } +} + +void print_usage(void) +{ + printf("Usage: tcctool -d devicename firmware.bin\n"); +} + +int main(int argc, char* argv[]) +{ + char* buf; + int n,len; + int fd; + int device; + + printf("tcctool v" VERSION " - (C) 2007 Dave Chapman\n"); + printf("This is free software; see the source for copying conditions. There is NO\n"); + printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); + + if (argc != 4) + { + print_usage(); + return 1; + } + + if (strcmp(argv[1],"-d")) + { + print_usage(); + return 2; + } + + device = find_device(argv[2]); + + if (device < 0) + { + printf("[ERR] Unknown device \"%s\"\n",argv[2]); + print_devices(); + return 3; + } + + printf("[INFO] Using device \"%s\"\n",devices[device].label); + fd = open(argv[3], O_RDONLY); + if (fd < 0) + { + printf("[ERR] Could not open %s\n", argv[3]); + return 4; + } + + len = filesize(fd); + + if (len > MAX_FIRMWARESIZE) + { + printf("[ERR] Firmware file too big\n"); + close(fd); + return 5; + } + + buf = malloc(len); + if (buf == NULL) + { + printf("[ERR] Could not allocate memory.\n"); + close(fd); + return 6; + } + + n = read(fd, buf, len); + if (n != len) + { + printf("[ERR] Short read.\n"); + close(fd); + return 7; + } + close(fd); + + do_patching(device, buf, len); + + return 0; +} -- cgit v1.2.3