blob: e76c0388875c448cda36b40c3c823e78f79f5fd2 [file] [log] [blame]
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Maurus Cuelenaere
*
* based on tcctool.c by 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)
*
*
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <inttypes.h>
#include <usb.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdbool.h>
#include <unistd.h>
#include "jz4740.h"
#include "jz_xloader.h"
#define VERSION "0.4"
#define MAX_FIRMWARESIZE (64*1024*1024) /* Arbitrary limit (for safety) */
/* For win32 compatibility: */
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* USB IDs for USB Boot Mode */
#define VID 0x601A
#define PID 0x4740
#define EP_BULK_TO 0x01
#define TOUT 5000
enum USB_JZ4740_REQUEST
{
VR_GET_CPU_INFO = 0,
VR_SET_DATA_ADDRESS,
VR_SET_DATA_LENGTH,
VR_FLUSH_CACHES,
VR_PROGRAM_START1,
VR_PROGRAM_START2,
VR_NOR_OPS,
VR_NAND_OPS,
VR_SDRAM_OPS,
VR_CONFIGURATION
};
enum NOR_OPS_TYPE
{
NOR_INIT = 0,
NOR_QUERY,
NOR_WRITE,
NOR_ERASE_CHIP,
NOR_ERASE_SECTOR
};
enum NOR_FLASH_TYPE
{
NOR_AM29 = 0,
NOR_SST28,
NOR_SST39x16,
NOR_SST39x8
};
enum NAND_OPS_TYPE
{
NAND_QUERY = 0,
NAND_INIT,
NAND_MARK_BAD,
NAND_READ_OOB,
NAND_READ_RAW,
NAND_ERASE,
NAND_READ,
NAND_PROGRAM,
NAND_READ_TO_RAM
};
enum SDRAM_OPS_TYPE
{
SDRAM_LOAD,
};
enum DATA_STRUCTURE_OB
{
DS_flash_info,
DS_hand
};
enum OPTION
{
OOB_ECC,
OOB_NO_ECC,
NO_OOB,
};
int filesize(FILE* fd)
{
int ret;
fseek(fd, 0, SEEK_END);
ret = ftell(fd);
fseek(fd, 0, SEEK_SET);
return ret;
}
bool file_exists(const char* filename)
{
FILE* fp = fopen(filename, "r");
if(fp)
{
fclose(fp);
return true;
}
else
return false;
}
#define SEND_COMMAND(cmd, arg) err = usb_control_msg(dh, USB_ENDPOINT_OUT | USB_TYPE_VENDOR, (cmd), (arg)>>16, (arg)&0xFFFF, NULL, 0, TOUT);\
if (err < 0) \
{ \
fprintf(stderr,"\n[ERR] Error sending control message (%d, %s)\n", err, usb_strerror()); \
return -1; \
}
#define GET_CPU_INFO(s) err = usb_control_msg(dh, USB_ENDPOINT_IN | USB_TYPE_VENDOR, VR_GET_CPU_INFO, 0, 0, (s), 8, TOUT); \
if (err < 0) \
{ \
fprintf(stderr,"\n[ERR] Error sending control message (%d, %s)\n", err, usb_strerror()); \
return -1; \
}
#define SEND_DATA(ptr, size) err = usb_bulk_write(dh, USB_ENDPOINT_OUT | EP_BULK_TO, ((char*)(ptr)), (size), TOUT); \
if (err != (size)) \
{ \
fprintf(stderr,"\n[ERR] Error writing data\n"); \
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); \
return -1; \
}
#define GET_DATA(ptr, size) err = usb_bulk_read(dh, USB_ENDPOINT_IN | EP_BULK_TO, ((char*)(ptr)), (size), TOUT); \
if (err != (size)) \
{ \
fprintf(stderr,"\n[ERR] Error writing data\n"); \
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err)); \
return -1; \
}
int upload_data(usb_dev_handle* dh, int address, unsigned char* p, int len)
{
int err;
char buf[9];
unsigned char* tmp_buf;
fprintf(stderr, "[INFO] GET_CPU_INFO: ");
GET_CPU_INFO(buf);
buf[8] = 0;
fprintf(stderr, "%s\n", buf);
fprintf(stderr, "[INFO] SET_DATA_ADDRESS to 0x%x...", address);
SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
fprintf(stderr, " Done!\n");
fprintf(stderr, "[INFO] Sending data...");
/* Must not split the file in several packages! */
SEND_DATA(p, len);
fprintf(stderr, " Done!\n");
fprintf(stderr, "[INFO] Verifying data...");
SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
SEND_COMMAND(VR_SET_DATA_LENGTH, len);
tmp_buf = malloc(len);
if (tmp_buf == NULL)
{
fprintf(stderr, "\n[ERR] Could not allocate memory.\n");
return -1;
}
GET_DATA(tmp_buf, len);
if (memcmp(tmp_buf, p, len) != 0)
fprintf(stderr, "\n[WARN] Sent data isn't the same as received data...\n");
else
fprintf(stderr, " Done!\n");
free(tmp_buf);
return 0;
}
int boot(usb_dev_handle* dh, int address, bool stage2)
{
int err;
fprintf(stderr, "[INFO] Booting device STAGE%d...", (stage2 ? 2 : 1));
SEND_COMMAND((stage2 ? VR_PROGRAM_START2 : VR_PROGRAM_START1), address );
fprintf(stderr, " Done!\n");
return err;
}
int upload_app(usb_dev_handle* dh, int address, unsigned char* p, int len, bool stage2)
{
int err = upload_data(dh, address, p, len);
if(err == 0)
{
err = boot(dh, address, stage2);
if(err == 0)
fprintf(stderr, "[INFO] Done!\n");
}
return err;
}
int read_data(usb_dev_handle* dh, int address, unsigned char *p, int len)
{
int err;
char buf[9];
fprintf(stderr, "[INFO] GET_CPU_INFO: ");
GET_CPU_INFO(buf);
buf[8] = 0;
fprintf(stderr, "%s\n", buf);
fprintf(stderr, "[INFO] Reading data...");
SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
SEND_COMMAND(VR_SET_DATA_LENGTH, len);
GET_DATA(p, len);
fprintf(stderr, " Done!\n");
return 0;
}
unsigned int read_reg(usb_dev_handle* dh, int address, int size)
{
int err; /* set by SEND_COMMAND macro */
unsigned char buf[4];
SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
SEND_COMMAND(VR_SET_DATA_LENGTH, size);
GET_DATA(buf, size);
if(size == 1)
return buf[0];
else if(size == 2)
return (buf[1] << 8) | buf[0];
else if(size == 4)
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
else
return 0;
}
int set_reg(usb_dev_handle* dh, int address, unsigned int val, int size)
{
int err; /* set by SEND_COMMAND macro */
unsigned char buf[4];
buf[0] = val & 0xff;
if(size > 1)
{
buf[1] = (val >> 8) & 0xff;
if(size > 2)
{
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24) & 0xff;
}
}
SEND_COMMAND(VR_SET_DATA_ADDRESS, address);
SEND_DATA(buf, size);
return 0;
}
#define or_reg(dh, adr, val, size) set_reg(dh, adr, (read_reg(dh, adr, size) | (val)), size);
#define and_reg(dh, adr, val, size) set_reg(dh, adr, (read_reg(dh, adr, size) & (val)), size);
#define bc_reg(dh, adr, val, size) set_reg(dh, adr, (read_reg(dh, adr, size) & ~(val)), size);
#define xor_reg(dh, adr, val, size) set_reg(dh, adr, (read_reg(dh, adr, size) ^ (val)), size);
#define TEST(m, size) fprintf(stderr, "%s -> %x\n", #m, read_reg(dh, m, size));
int test_device(usb_dev_handle* dh)
{
TEST(INTC_ISR, 4);
TEST(INTC_IMR, 4);
TEST(INTC_IMSR, 4);
TEST(INTC_IMCR, 4);
TEST(INTC_IPR, 4);
fprintf(stderr, "\n");
TEST(RTC_RCR, 4);
TEST(RTC_RSR, 4);
TEST(RTC_RSAR, 4);
TEST(RTC_RGR, 4);
TEST(RTC_HCR, 4);
TEST(RTC_RCR, 4);
TEST(RTC_HWFCR, 4);
TEST(RTC_HRCR, 4);
TEST(RTC_HWCR, 4);
TEST(RTC_HWSR, 4);
fprintf(stderr, "\n");
TEST(GPIO_PXPIN(0), 4);
TEST(GPIO_PXPIN(1), 4);
TEST(GPIO_PXPIN(2), 4);
TEST(GPIO_PXPIN(3), 4);
fprintf(stderr, "\n");
TEST(CPM_CLKGR, 4);
fprintf(stderr, "\n");
TEST(SADC_ENA, 1);
TEST(SADC_CTRL, 1);
TEST(SADC_TSDAT, 4);
TEST(SADC_BATDAT, 2);
TEST(SADC_STATE, 1);
fprintf(stderr, "\n");
TEST(SLCD_CFG, 4);
TEST(SLCD_CTRL, 1);
TEST(SLCD_STATE, 1);
return 0;
}
unsigned int read_file(const char *name, unsigned char **buffer)
{
FILE *fd;
int len, n;
fd = fopen(name, "rb");
if (fd == NULL)
{
fprintf(stderr, "[ERR] Could not open %s\n", name);
return 0;
}
len = filesize(fd);
*buffer = (unsigned char*)malloc(len);
if (*buffer == NULL)
{
fprintf(stderr, "[ERR] Could not allocate memory.\n");
fclose(fd);
return 0;
}
n = fread(*buffer, 1, len, fd);
if (n != len)
{
fprintf(stderr, "[ERR] Short read.\n");
fclose(fd);
return 0;
}
fclose(fd);
return len;
}
#define _GET_CPU fprintf(stderr, "[INFO] GET_CPU_INFO:"); \
GET_CPU_INFO(cpu); \
cpu[8] = 0; \
fprintf(stderr, " %s\n", cpu);
#define _SET_ADDR(a) fprintf(stderr, "[INFO] Set address to 0x%x...", a); \
SEND_COMMAND(VR_SET_DATA_ADDRESS, a); \
fprintf(stderr, " Done!\n");
#define _SEND_FILE(a) fsize = read_file(a, &buffer); \
if(fsize == 0) \
return -1; \
fprintf(stderr, "[INFO] Sending file %s: %d bytes...", a, fsize); \
SEND_DATA(buffer, fsize); \
free(buffer); \
fprintf(stderr, " Done!\n");
#define _VERIFY_DATA(a,c) fprintf(stderr, "[INFO] Verifying data (%s)...", a); \
fsize = read_file(a, &buffer); \
if(fsize == 0) \
return -1; \
buffer2 = (unsigned char*)malloc(fsize); \
SEND_COMMAND(VR_SET_DATA_ADDRESS, c); \
SEND_COMMAND(VR_SET_DATA_LENGTH, fsize); \
GET_DATA(buffer2, fsize); \
if(memcmp(buffer, buffer2, fsize) != 0) \
fprintf(stderr, "\n[WARN] Sent data isn't the same as received data...\n"); \
else \
fprintf(stderr, " Done!\n"); \
free(buffer); \
free(buffer2);
#define _STAGE1(a) fprintf(stderr, "[INFO] Stage 1 at 0x%x\n", a); \
SEND_COMMAND(VR_PROGRAM_START1, a);
#define _STAGE2(a) fprintf(stderr, "[INFO] Stage 2 at 0x%x\n", a); \
SEND_COMMAND(VR_PROGRAM_START2, a);
#define _FLUSH fprintf(stderr, "[INFO] Flushing caches...\n"); \
SEND_COMMAND(VR_FLUSH_CACHES, 0);
#ifdef _WIN32
#define _SLEEP(x) Sleep(x*1000);
#else
#define _SLEEP(x) sleep(x);
#endif
int mimic_of(usb_dev_handle *dh, bool vx767)
{
int err, fsize;
unsigned char *buffer, *buffer2;
char cpu[9];
fprintf(stderr, "[INFO] Start!\n");
_GET_CPU;
_SET_ADDR(0x8000 << 16);
_SEND_FILE("1.bin");
_GET_CPU;
_VERIFY_DATA("1.bin", 0x8000 << 16);
_STAGE1(0x8000 << 16);
_SLEEP(3);
_VERIFY_DATA("2.bin", 0xB3020060);
_GET_CPU;
_GET_CPU;
_FLUSH;
_GET_CPU;
_GET_CPU;
_SET_ADDR(0x8000 << 16);
_SEND_FILE("3.bin");
_GET_CPU;
_VERIFY_DATA("3.bin", 0x8000 << 16);
_GET_CPU;
_FLUSH;
_GET_CPU;
_GET_CPU;
_SET_ADDR(0x80D0 << 16);
_SEND_FILE("4.bin");
_GET_CPU;
_VERIFY_DATA("4.bin", 0x80D0 << 16);
_GET_CPU;
_FLUSH;
_GET_CPU;
_GET_CPU;
_SET_ADDR(0x80E0 << 16);
_SEND_FILE("5.bin");
_GET_CPU;
_VERIFY_DATA("5.bin", 0x80E0 << 16);
_GET_CPU;
_FLUSH;
_GET_CPU;
_GET_CPU;
_SET_ADDR(0x80004000);
_SEND_FILE("6.bin");
_GET_CPU;
_VERIFY_DATA("6.bin", 0x80004000);
_GET_CPU;
_FLUSH;
_GET_CPU;
_GET_CPU;
_SET_ADDR(0x80FD << 16);
_SEND_FILE("7.bin");
_GET_CPU;
_VERIFY_DATA("7.bin", 0x80FD << 16);
_GET_CPU;
_FLUSH;
_GET_CPU;
_STAGE2(0x80FD0004);
_VERIFY_DATA("8.bin", 0x80004004);
_VERIFY_DATA("9.bin", 0x80004008);
_SLEEP(2);
_GET_CPU;
_SET_ADDR(0x80E0 << 16);
_SEND_FILE("10.bin");
_GET_CPU;
_VERIFY_DATA("10.bin", 0x80E0 << 16);
_GET_CPU;
_FLUSH;
_GET_CPU;
if(vx767)
{
_STAGE2(0x80E10008);
}
else
{
_STAGE2(0x80E00008);
}
fprintf(stderr, "[INFO] Done!\n");
return 0;
}
int send_rockbox(usb_dev_handle *dh, const char* filename)
{
int fsize;
unsigned char *buffer;
fprintf(stderr, "[INFO] Start!\n");
if(file_exists("jz_xloader.bin"))
{
fprintf(stderr, "[INFO] Using jz_xloader.bin\n");
fsize = read_file("jz_xloader.bin", &buffer);
upload_data(dh, 0x080000000, buffer, fsize);
free(buffer);
}
else
{
fprintf(stderr, "[INFO] Using built-in jz_xloader.bin\n");
upload_data(dh, 0x080000000, jz_xloader, LEN_jz_xloader);
}
boot(dh, 0x080000000, false);
_SLEEP(1);
fsize = read_file(filename, &buffer);
upload_data(dh, 0x080004000, buffer, fsize);
free(buffer);
boot(dh, 0x080004000, true);
fprintf(stderr, "[INFO] Done!\n");
return 0;
}
#define SEND_NAND_COMMAND(cs, cmd, option) SEND_COMMAND(VR_NAND_OPS, ((cmd&0xF)|((cs&0xFF)<<4)|((option&0xFF)<<12)) );
#define LENGTH 1024*1024*5
int nand_dump(usb_dev_handle *dh)
{
int err;
unsigned int n;
FILE *fd;
unsigned char* buffer;
fd = fopen("nand_dump.bin", "wb");
if (fd == NULL)
{
fprintf(stderr, "[ERR] Could not open nand_dump.bin\n");
return 0;
}
buffer = (unsigned char*)malloc(LENGTH);
if (buffer == NULL)
{
fprintf(stderr, "[ERR] Could not allocate memory.\n");
fclose(fd);
return 0;
}
SEND_NAND_COMMAND(0, NAND_INIT, 0);
/*
fprintf(stderr, "[INFO] Querying NAND...\n");
SEND_NAND_COMMAND(0, NAND_QUERY, 0);
GET_DATA(buffer, 4);
printf("[INFO] %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
*/
SEND_COMMAND(VR_SET_DATA_ADDRESS, 0);
SEND_COMMAND(VR_SET_DATA_LENGTH, LENGTH);
SEND_NAND_COMMAND(0, NAND_READ, NO_OOB);
fprintf(stderr, "[INFO] Reading data...\n");
err = usb_bulk_read(dh, USB_ENDPOINT_IN | EP_BULK_TO, (char*)buffer, LENGTH, TOUT);
if (err != LENGTH)
{
fprintf(stderr,"\n[ERR] Error writing data\n");
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
fclose(fd);
free(buffer);
return -1;
}
n = fwrite(buffer, 1, LENGTH, fd);
if (n != LENGTH)
{
fprintf(stderr, "[ERR] Short write.\n");
fclose(fd);
free(buffer);
return 0;
}
fclose(fd);
free(buffer);
return n;
}
#define ROM_LENGTH 0x1000*16
int rom_dump(usb_dev_handle *dh)
{
int err;
unsigned int n;
FILE *fd;
unsigned char* buffer;
fd = fopen("rom_dump.bin", "wb");
if (fd == NULL)
{
fprintf(stderr, "[ERR] Could not open rom_dump.bin\n");
return 0;
}
buffer = (unsigned char*)malloc(ROM_LENGTH);
if (buffer == NULL)
{
fprintf(stderr, "[ERR] Could not allocate memory.\n");
fclose(fd);
return 0;
}
SEND_COMMAND(VR_SET_DATA_ADDRESS, 0x1FC00000);
SEND_COMMAND(VR_SET_DATA_LENGTH, ROM_LENGTH);
fprintf(stderr, "[INFO] Reading data...\n");
err = usb_bulk_read(dh, USB_ENDPOINT_IN | EP_BULK_TO, (char*)buffer, ROM_LENGTH, TOUT);
if (err != ROM_LENGTH)
{
fprintf(stderr,"\n[ERR] Error writing data\n");
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
fclose(fd);
free(buffer);
return -1;
}
n = fwrite(buffer, 1, ROM_LENGTH, fd);
if (n != ROM_LENGTH)
{
fprintf(stderr, "[ERR] Short write.\n");
fclose(fd);
free(buffer);
return 0;
}
fclose(fd);
free(buffer);
return n;
}
int jzconnect(int address, unsigned char* buf, int len, int func)
{
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 device...\n");
usb_init();
if(usb_find_busses() < 0)
{
fprintf(stderr, "[ERR] Could not find any USB busses.\n");
return -2;
}
if (usb_find_devices() < 0)
{
fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
return -3;
}
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next)
{
if (tmp_dev->descriptor.idVendor == VID &&
tmp_dev->descriptor.idProduct == PID)
{
dev = tmp_dev;
goto found;
}
}
}
fprintf(stderr, "[ERR] Device not found.\n");
fprintf(stderr, "[ERR] Ensure your device is in USB boot mode and run usbtool again.\n");
return -4;
found:
if ( (dh = usb_open(dev)) == NULL)
{
fprintf(stderr,"[ERR] Unable to open device.\n");
return -5;
}
/* usb_set_configuration() calls are already done in Linux */
#ifdef _WIN32
err = usb_set_configuration(dh, 1);
if (err < 0)
{
fprintf(stderr, "[ERR] usb_set_configuration failed (%d, %s)\n", err, usb_strerror());
usb_close(dh);
return -6;
}
#endif
/* "must be called" written in the libusb documentation */
err = usb_claim_interface(dh, 0);
if (err < 0)
{
fprintf(stderr, "[ERR] Unable to claim interface (%d, %s)\n", err, usb_strerror());
usb_close(dh);
return -7;
}
fprintf(stderr,"[INFO] Found device, uploading application.\n");
/* Now we can transfer the application to the device. */
switch(func)
{
case 1:
case 5:
err = upload_app(dh, address, buf, len, (func == 5));
break;
case 2:
err = read_data(dh, address, buf, len);
break;
case 3:
err = test_device(dh);
break;
case 6:
case 7:
err = mimic_of(dh, (func == 7));
break;
case 8:
err = nand_dump(dh);
break;
case 9:
err = rom_dump(dh);
break;
case 10:
err = send_rockbox(dh, (char*)buf);
break;
}
/* release claimed interface */
usb_release_interface(dh, 0);
usb_close(dh);
return err;
}
void print_usage(void)
{
#ifdef _WIN32
fprintf(stderr, "Usage: usbtool.exe <CMD> [FILE] [ADDRESS] [LEN]\n");
#else
fprintf(stderr, "Usage: usbtool <CMD> [FILE] [ADDRESS] [LEN]\n");
#endif
fprintf(stderr, "\t[ADDRESS] has to be in 0xHEXADECIMAL format\n");
fprintf(stderr, "\tCMD:\n");
fprintf(stderr, "\t\t 1 -> upload file to specified address and boot from it\n");
fprintf(stderr, "\t\t 2 -> read data from [ADDRESS] with length [LEN] to [FILE]\n");
fprintf(stderr, "\t\t 3 -> read device status\n");
fprintf(stderr, "\t\t 5 -> same as 1 but do a stage 2 boot\n");
fprintf(stderr, "\t\t 6 -> mimic VX747 OF fw recovery\n");
fprintf(stderr, "\t\t 7 -> mimic VX767 OF fw recovery\n");
fprintf(stderr, "\t\t 8 -> do a NAND dump\n");
fprintf(stderr, "\t\t 9 -> do a ROM dump\n");
fprintf(stderr, "\t\t10 -> send Rockbox bootloader at [FILE] to SDRAM\n");
#ifdef _WIN32
fprintf(stderr, "\nExample:\n\t usbtool.exe 1 fw.bin 0x80000000\n");
fprintf(stderr, "\t usbtool.exe 2 save.bin 0x81000000 1024\n");
#else
fprintf(stderr, "\nExample:\n\t usbtool 1 fw.bin 0x80000000\n");
fprintf(stderr, "\t usbtool 2 save.bin 0x81000000 1024\n");
#endif
}
int main(int argc, char* argv[])
{
unsigned char* buf;
int n, len, address, cmd=0;
FILE* fd;
fprintf(stderr, "USBtool v" VERSION " - (C) 2008 Maurus Cuelenaere\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");
if(argc > 1)
sscanf(argv[1], "%d", &cmd);
switch(cmd)
{
case 5:
case 1:
if (strcmp(argv[3], "-1") == 0)
address = 0x80000000;
else
{
if (sscanf(argv[3], "0x%x", &address) <= 0)
{
print_usage();
return -1;
}
}
fd = fopen(argv[2], "rb");
if (fd < 0)
{
fprintf(stderr, "[ERR] Could not open %s\n", argv[2]);
return 4;
}
len = filesize(fd);
if (len > MAX_FIRMWARESIZE)
{
fprintf(stderr, "[ERR] Firmware file too big\n");
fclose(fd);
return 5;
}
buf = malloc(len);
if (buf == NULL)
{
fprintf(stderr, "[ERR] Could not allocate memory.\n");
fclose(fd);
return 6;
}
n = fread(buf, 1, len, fd);
if (n != len)
{
fprintf(stderr, "[ERR] Short read.\n");
fclose(fd);
return 7;
}
fclose(fd);
fprintf(stderr, "[INFO] File size: %d bytes\n", n);
return jzconnect(address, buf, len, cmd);
case 2:
if (sscanf(argv[3], "0x%x", &address) <= 0)
{
print_usage();
return -1;
}
fd = fopen(argv[2], "wb");
if (fd < 0)
{
fprintf(stderr, "[ERR] Could not open %s\n", argv[2]);
return 4;
}
sscanf(argv[4], "%d", &len);
buf = malloc(len);
if (buf == NULL)
{
fprintf(stderr, "[ERR] Could not allocate memory.\n");
fclose(fd);
return 6;
}
int err = jzconnect(address, buf, len, 2);
n = fwrite(buf, 1, len, fd);
if (n != len)
{
fprintf(stderr, "[ERR] Short write.\n");
fclose(fd);
return 7;
}
fclose(fd);
return err;
case 10:
if(argc < 3)
{
print_usage();
return 1;
}
if(!file_exists(argv[2]))
{
print_usage();
return 1;
}
return jzconnect(address, (unsigned char*)argv[2], 0, 10);
case 3:
case 6:
case 7:
case 8:
case 9:
return jzconnect(address, NULL, 0, cmd);
default:
print_usage();
return 1;
}
return 0;
}