rockbox/rbutil/e200rpatcher/e200rpatcher.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

241 lines
6.6 KiB
C

/***************************************************************************
* __________ __ ___.
* 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)
*
*
* 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 "stdbool.h"
#include "bootimg.h"
#define VERSION "0.2"
/* USB IDs for Manufacturing Mode */
#define E200R_VENDORID 0x0781
#define E200R_PRODUCTID 0x0720
#define E200R_BULK_TO 1
#define TOUT 5000
#define MAX_TRANSFER 64 /* Number of bytes to send in one write */
#ifndef MAX
#define MAX(a,b) (((a)>(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)
{
char buf[4];
int err;
int tosend;
char* p = (char*)bootimg;
int bytesleft = LEN_bootimg;
/* Write the data length */
put_int32le(LEN_bootimg, buf);
err = usb_bulk_write(dh, E200R_BULK_TO, buf, 4, TOUT);
if (err < 0)
{
fprintf(stderr,"[ERR] Error writing data length\n");
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
return -1;
}
/* Now send the data, MAX_TRANSFER bytes at a time. */
while (bytesleft > 0)
{
tosend = MAX(MAX_TRANSFER, bytesleft);
err = usb_bulk_write(dh, E200R_BULK_TO, p, tosend, 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 += tosend;
bytesleft -= tosend;
}
return 0;
}
/* The main function */
void do_patching(void)
{
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 E200R\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) {
if (tmp_dev->descriptor.idVendor == E200R_VENDORID &&
tmp_dev->descriptor.idProduct == E200R_PRODUCTID ) {
dev = tmp_dev;
goto found;
}
}
}
if (dev == NULL) {
fprintf(stderr, "[ERR] E200R device not found.\n");
fprintf(stderr, "[ERR] Ensure your E200R is in manufacturing mode and run e200rpatcher again.\n");
return;
}
found:
if ( (dh = usb_open(dev)) == NULL) {
fprintf(stderr,"[ERR] Unable to open E200R 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 E200R, uploading patching application.\n");
/* Now we can transfer the application to the device. */
if (upload_app(dh) < 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);
}
void print_usage(void)
{
fprintf(stderr,"Usage: e200rpatcher [options]\n");
fprintf(stderr,"Options:\n");
fprintf(stderr," -s, --silent\t\tDont display instructions\n");
}
int main(int argc, char* argv[])
{
char input[4];
int silent = 0;
int i;
/* check args */
if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
print_usage();
return 1;
}
for (i=1;i<argc;i++)
{
if (!strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s"))
silent = 1;
}
printf("e200rpatcher v" VERSION " - (C) 2007 Jonathan Gordon & 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 (!silent)
{
printf("Attach your E200R in \"manufacturing mode\" as follows:\n");
printf(" 1) Power-off your E200R\n");
printf(" 2) Turn ON the lock/hold switch\n");
printf(" 3) Press and hold the SELECT button and whilst it is held down,\n");
printf(" attach your E200R to your computer via USB\n");
printf(" 4) After attaching to USB, keep the SELECT button held for 10 seconds.\n");
printf("\n");
printf("NOTE: If your E200R starts in the normal Sansa firmware, you have\n");
printf(" failed to enter manufacturing mode and should try again at step 1).\n\n");
printf("[INFO] Press Enter to continue:");
fgets(input, 4, stdin);
}
do_patching();
if (!silent)
{
printf("[INFO] Press ENTER to exit: ");
fgets(input, 4, stdin);
}
return 0;
}