From c06071e2e705095e49207f92b941edd3b5ada46c Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sun, 22 Feb 2009 13:54:46 +0000 Subject: Initial version of a BSD-licensed beastpatcher utility for Gigabeat S installation. Currently only compiles on Linux, but Windows and OS X support are planned. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20083 a1c6a512-1295-4272-9138-f99709370657 --- utils/MTP/beastpatcher/Makefile | 52 ++++++++ utils/MTP/beastpatcher/README | 61 ++++++++++ utils/MTP/beastpatcher/TODO | 17 +++ utils/MTP/beastpatcher/beastpatcher.c | 221 ++++++++++++++++++++++++++++++++++ utils/MTP/beastpatcher/mtp_common.h | 71 +++++++++++ utils/MTP/beastpatcher/mtp_libmtp.c | 174 ++++++++++++++++++++++++++ 6 files changed, 596 insertions(+) create mode 100644 utils/MTP/beastpatcher/Makefile create mode 100644 utils/MTP/beastpatcher/README create mode 100644 utils/MTP/beastpatcher/TODO create mode 100644 utils/MTP/beastpatcher/beastpatcher.c create mode 100644 utils/MTP/beastpatcher/mtp_common.h create mode 100644 utils/MTP/beastpatcher/mtp_libmtp.c (limited to 'utils') diff --git a/utils/MTP/beastpatcher/Makefile b/utils/MTP/beastpatcher/Makefile new file mode 100644 index 0000000000..edd08b1248 --- /dev/null +++ b/utils/MTP/beastpatcher/Makefile @@ -0,0 +1,52 @@ +CFLAGS=-Wall -W + +ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) +OUTPUT=beastpatcher.exe +CROSS= +else +OUTPUT=beastpatcher +CROSS=i586-mingw32msvc- +endif + +ifeq ($(OUTPUT),beastpatcher) +LIBS = /usr/lib/libmtp.a /usr/lib/libusb.a +CFLAGS += $(shell printf \ + '\#include \nlibmtp version: LIBMTP_VERSION\n' | \ + gcc -E -P - -o - | grep -q '^libmtp version: 0\.2' && echo '-DOLDMTP') +else +CFLAGS+=-mno-cygwin +LIBS = ../MTP_DLL.dll +endif + +NATIVECC = gcc +CC = $(CROSS)gcc + +all: $(OUTPUT) + +beastpatcher: beastpatcher.c bootimg.c mtp_common.h mtp_libmtp.c + gcc $(CFLAGS) -o beastpatcher beastpatcher.c bootimg.c mtp_libmtp.c $(LIBS) + strip beastpatcher + +beastpatcher.exe: beastpatcher.c bootimg.c mtp_common.h mtp_win32.c $(LIBS) + $(CROSS)$(CC) $(CFLAGS) $(LIBS) -o beastpatcher.exe beastpatcher.c bootimg.c + $(CROSS)strip beastpatcher.exe + +beastpatcher-mac: beastpatcher-i386 beastpatcher-ppc + lipo -create beastpatcher-ppc beastpatcher-i386 -output beastpatcher-mac + +beastpatcher-i386: beastpatcher.c bootimg.c usb.h libusb-i386.a + $(CC) -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch i386 $(CFLAGS) -o beastpatcher-i386 beastpatcher.c bootimg.c -I. libusb-i386.a + strip beastpatcher-i386 + +beastpatcher-ppc: beastpatcher.c bootimg.c usb.h libusb-ppc.a + $(CC) -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch ppc $(CFLAGS) -o beastpatcher-ppc beastpatcher.c bootimg.c -I. libusb-ppc.a + strip beastpatcher-ppc + +bin2c: ../../../rbutil/sansapatcher/bin2c.c + $(NATIVECC) $(CFLAGS) -o bin2c ../../../rbutil/sansapatcher/bin2c.c + +bootimg.c: bootloader.bin bin2c + ./bin2c bootloader.bin bootimg + +clean: + rm -f beastpatcher.exe beastpatcher-mac beastpatcher-i386 beastpatcher-ppc beastpatcher bin2c bootimg.c bootimg.h *~ diff --git a/utils/MTP/beastpatcher/README b/utils/MTP/beastpatcher/README new file mode 100644 index 0000000000..85a039268a --- /dev/null +++ b/utils/MTP/beastpatcher/README @@ -0,0 +1,61 @@ +beastpatcher - a tool for installing the Rockbox bootloader on the Gigabeat S + +Unlike most other parts of the Rockbox project, this tool is +distributed under the BSD license. This is due to the fact that the +Windows version links with the Microsoft MTP library. + + + +Building instructions - All OSes +-------------------------------- + +For all versions, you need to copy a "bootloader.bin" file (containing +the Rockbox bootloader) into this directory. + +This can be built from the Rockbox source by selecting "41" and then +"B" when running tools/configure. + +You need the Rockbox toolchain to build any Rockbox target binaries - +this can be downloaded and built with the tools/rockboxdev.sh script. + +The latest officially released bootloader can always be downloaded from: + +http://download.rockbox.org/bootloader/gigabeat-s/ + + + +Linux +----- + +The Unix versions requires libmtp, which in turn requires libusb. + +beastpatcher is built to statically link to these libraries and +expects them to exist as /usr/lib/libmtp.a and /usr/lib/libusb.a +respectively. Change the definition of LIBS in the Makefile if this +is not the case for your system. + +After this, just type "make" to get a + + + +OS X +---- + +[Not yet implemented] + +The OS X build is a universal binary statically linked with libusb and libmtp. + + + +Windows +------- + +[Not yet implemented] + +The MTP_DLL.dll requires VC2005 to compile - see instructions in +MTP_DLL/README + +To compile beastpatcher itself, you can either cross-compile from +Linux using the mingw32 package, or compile in Cygwin. Just type +"make beastpatcher.exe" (in Linux) or "make" (in Cygwin). + diff --git a/utils/MTP/beastpatcher/TODO b/utils/MTP/beastpatcher/TODO new file mode 100644 index 0000000000..717a77e7c8 --- /dev/null +++ b/utils/MTP/beastpatcher/TODO @@ -0,0 +1,17 @@ +Basic implementation: + +* Windows support - need to expand API provided by MTP_DLL.dll +* OS X support - need to statically link against libusb and libmtp +* Load bootloader.bin from a file + +Ideas for future features: + +* Dual-boot. Look for nk.bin in current directory, and check its + md5sum to confirm it's an original firmware. Possibly include + override for user-modified OFs, and option for user to specify an + alternate location. + + This will give the user three options - rockbox only, OF only + (i.e. uninstall) or dual-boot. It would be easy to give the choice + of two boot orders (RB on hold or OF on hold) if that was desired. + diff --git a/utils/MTP/beastpatcher/beastpatcher.c b/utils/MTP/beastpatcher/beastpatcher.c new file mode 100644 index 0000000000..8043ebadc2 --- /dev/null +++ b/utils/MTP/beastpatcher/beastpatcher.c @@ -0,0 +1,221 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * $Id:$ + * + * Copyright (c) 2009, Dave Chapman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtp_common.h" +#include "bootimg.h" + +#define VERSION "1.0 with v1 bootloader" + +void print_usage(void) +{ + fprintf(stderr,"Usage: beastpatcher [action]\n"); + fprintf(stderr,"\n"); + fprintf(stderr,"Where [action] is one of the following options:\n"); + fprintf(stderr," --install (default)\n"); + fprintf(stderr," -?, --help\n"); + fprintf(stderr,"\n"); +} + +/* Code to create a single-boot bootloader. + Based on tools/gigabeats.c by Will Robertson. +*/ + +/* Entry point (and load address) for the main Rockbox bootloader */ +#define BL_ENTRY_POINT 0x8a000000 + +static void put_uint32le(uint32_t x, unsigned char* p) +{ + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static uint32_t calc_csum(const unsigned char* pb, int cb) +{ + uint32_t l = 0; + while (cb--) + l += *pb++; + return l; +} + +static void create_single_boot(unsigned char* boot, int bootlen, + unsigned char** fwbuf, int* fwsize) +{ + unsigned char* buf; + + /* 15 bytes for header, 16 for signature bypass, + * 12 for record header, size of bootloader, 12 for footer */ + *fwsize = 15 + 16 + 12 + bootlen + 12; + *fwbuf = malloc(*fwsize); + + if(buf == NULL) { + fprintf(stderr, "[ERR] Cannot allocate memory.\n" ); + *fwbuf = NULL; + *fwsize = 0; + return; + } + + buf = *fwbuf; + + /* Copy bootloader image. */ + memcpy(buf + 43, boot, bootlen); + + /* Step 2: Create the file header */ + sprintf((char *)buf, "B000FF\n"); + put_uint32le(0x88200000, buf+7); + + /* If the value below is too small, the update will attempt to flash. + * Be careful when changing this (leaving it as is won't cause issues) */ + put_uint32le(0xCC0CD8, buf+11); + + /* Step 3: Add the signature bypass record */ + put_uint32le(0x88065A10, buf+15); + put_uint32le(4, buf+19); + put_uint32le(0xE3A00001, buf+27); + put_uint32le(calc_csum(buf+27,4), buf+23); + + /* Step 4: Create a record for the actual code */ + put_uint32le(BL_ENTRY_POINT, buf+31); + put_uint32le(bootlen, buf+35); + put_uint32le(calc_csum(buf + 43, bootlen), buf+39); + + /* Step 5: Write the footer */ + put_uint32le(0, buf+*fwsize-12); + put_uint32le(BL_ENTRY_POINT, buf+*fwsize-8); + put_uint32le(0, buf+*fwsize-4); + + return; +} + +int beastpatcher(int argc, char* argv[]) +{ + char yesno[4]; + unsigned char* fwbuf; + int fwsize; + struct mtp_info_t mtp_info; + + (void)argv; + + fprintf(stderr,"beastpatcher v" VERSION " - (C) 2009 by the Rockbox developers\n"); + fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); + fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); + + /* No options are currently implemented, so just display help if any are + provided. */ + + if (argc > 1) { + print_usage(); + return 1; + } + + if (mtp_init(&mtp_info) < 0) { + fprintf(stderr,"[ERR] Can not init MTP\n"); + return 1; + } + + /* Scan for attached MTP devices. */ + if (mtp_scan(&mtp_info) < 0) + { + fprintf(stderr,"[ERR] No devices found\n"); + return 1; + } + + printf("[INFO] Found device \"%s - %s\"\n", mtp_info.manufacturer, + mtp_info.modelname); + printf("[INFO] Device version: \"%s\"\n",mtp_info.version); + + + printf("\nEnter i to install the Rockbox bootloader or c to cancel and do nothing (i/c): "); + + if (fgets(yesno,4,stdin)) + { + if (yesno[0]=='i') + { + /* Create a single-boot bootloader from the embedded bootloader */ + create_single_boot(bootimg, LEN_bootimg, &fwbuf, &fwsize); + + if (fwbuf == NULL) + return 1; + + if (mtp_send_firmware(&mtp_info, fwbuf, fwsize) == 0) + { + fprintf(stderr,"[INFO] Bootloader installed successfully.\n"); + } + else + { + fprintf(stderr,"[ERR] Bootloader install failed.\n"); + } + + /* We are now done with the firmware image */ + free(fwbuf); + } + else + { + fprintf(stderr,"[INFO] Installation cancelled.\n"); + } + } + + mtp_finished(&mtp_info); + + return 0; +} + + +int main(int argc, char* argv[]) +{ + int res; + char yesno[4]; + + res = beastpatcher(argc, argv); + + printf("\nPress ENTER to exit beastpatcher: "); + fgets(yesno,4,stdin); + + return res; +} diff --git a/utils/MTP/beastpatcher/mtp_common.h b/utils/MTP/beastpatcher/mtp_common.h new file mode 100644 index 0000000000..2fb52a9e81 --- /dev/null +++ b/utils/MTP/beastpatcher/mtp_common.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * $Id:$ + * + * Copyright (c) 2009, Dave Chapman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef _MTP_COMMON_H +#define _MTP_COMMON_H + +#ifdef __WIN32__ +#error Windows support not yet implemented +#else +#include "libmtp.h" +#endif + +struct mtp_info_t +{ + /* Generic data */ + char manufacturer[200]; + char modelname[200]; + char version[200]; + + /* OS-Specific data */ +#ifdef __WIN32__ +#else + LIBMTP_mtpdevice_t *device; +#endif +}; + +/* Common functions for both libMTP and win32 */ + +int mtp_init(struct mtp_info_t* mtp_info); +int mtp_finished(struct mtp_info_t* mtp_info); +int mtp_scan(struct mtp_info_t* mtp_info); +int mtp_send_firmware(struct mtp_info_t* mtp_info, unsigned char* fwbuf, + int fwsize); + +#endif /* !_MTP_COMMON_H */ diff --git a/utils/MTP/beastpatcher/mtp_libmtp.c b/utils/MTP/beastpatcher/mtp_libmtp.c new file mode 100644 index 0000000000..7e8579ac99 --- /dev/null +++ b/utils/MTP/beastpatcher/mtp_libmtp.c @@ -0,0 +1,174 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * $Id:$ + * + * Copyright (c) 2009, Dave Chapman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "libmtp.h" +#include "mtp_common.h" + +int mtp_init(struct mtp_info_t* mtp_info) +{ + /* Fill the info struct with zeros - mainly for the strings */ + memset(mtp_info, 0, sizeof(struct mtp_info_t)); + + LIBMTP_Init(); + + return 0; + +} + +int mtp_finished(struct mtp_info_t* mtp_info) +{ + LIBMTP_Release_Device(mtp_info->device); + + return 0; +} + +int mtp_scan(struct mtp_info_t* mtp_info) +{ + char* str; + + mtp_info->device = LIBMTP_Get_First_Device(); + + if (mtp_info->device == NULL) + { + return -1; + } + else + { + /* NOTE: These strings are filled with zeros in mtp_init() */ + + if ((str = LIBMTP_Get_Manufacturername(mtp_info->device))) + { + strncpy(mtp_info->manufacturer, str, sizeof(mtp_info->manufacturer)-1); + } + + if ((str = LIBMTP_Get_Modelname(mtp_info->device))) + { + strncpy(mtp_info->modelname, str, sizeof(mtp_info->modelname)-1); + } + + if ((str = LIBMTP_Get_Deviceversion(mtp_info->device))) + { + strncpy(mtp_info->version, str, sizeof(mtp_info->version)-1); + } + + return 0; + } +} + +static int progress(uint64_t const sent, uint64_t const total, + void const *const data) +{ + (void)data; + + int percent = (sent * 100) / total; +#ifdef __WIN32__ + printf("Progress: %I64u of %I64u (%d%%)\r", sent, total, percent); +#else + printf("Progress: %"PRIu64" of %"PRIu64" (%d%%)\r", sent, total, percent); +#endif + fflush(stdout); + return 0; +} + + +int mtp_send_firmware(struct mtp_info_t* mtp_info, unsigned char* fwbuf, + int fwsize) +{ + LIBMTP_file_t *genfile; + int ret; + size_t n; + FILE* fwfile; + + /* Open a temporary file - this will be automatically deleted when closed */ + fwfile = tmpfile(); + + if (fwfile == NULL) + { + fprintf(stderr,"[ERR] Could not create temporary file.\n"); + return -1; + } + + n = fwrite(fwbuf, 1, fwsize, fwfile); + if ((int)n < fwsize) + { + fprintf(stderr,"[ERR] Could not write to temporary file - n = %d.\n",(int)n); + fclose(fwfile); + return -1; + } + + /* Reset file pointer */ + fseek(fwfile, SEEK_SET, 0); + + /* Prepare for uploading firmware */ + genfile = LIBMTP_new_file_t(); + genfile->filetype = LIBMTP_FILETYPE_FIRMWARE; + genfile->filename = strdup("nk.bin"); + genfile->filesize = fwsize; + +#ifdef OLDMTP + ret = LIBMTP_Send_File_From_File_Descriptor(mtp_info->device, + fileno(fwfile), genfile, progress, NULL, 0); +#else + ret = LIBMTP_Send_File_From_File_Descriptor(mtp_info->device, + fileno(fwfile), genfile, progress, NULL); +#endif + + /* Keep the progress line onscreen */ + printf("\n"); + + /* NOTE: According to the docs, a value of ret != 0 means error, but libMTP + seems to return that even when successful. So we can't check the return + code. + */ + + /* Cleanup */ + LIBMTP_destroy_file_t(genfile); + + /* Close the temporary file - this also deletes it. */ + fclose(fwfile); + + return 0; +} -- cgit v1.2.3