mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 10:07:38 -04:00
rknanoutils: add dfu tool
This tool can upload a firmware to the device in DFU mode. The protocol is the same as the rk27xx devices except that it can load a bigger (unlimited ?) firmware. Change-Id: Ic9d4c5087629a9156f9d5d5cdc80767e6359c431
This commit is contained in:
parent
aa898d65fe
commit
6ea48cf92b
2 changed files with 239 additions and 0 deletions
20
utils/rknanoutils/rkload/Makefile
Normal file
20
utils/rknanoutils/rkload/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
DEFINES=
|
||||
CC=gcc
|
||||
LD=gcc
|
||||
CFLAGS=-O3 -g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
||||
LDFLAGS=`pkg-config --libs libusb-1.0`
|
||||
BINS=rkloader
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
sbtoelf: rkloader.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -fr *.o
|
||||
|
||||
veryclean:
|
||||
rm -rf $(BINS)
|
219
utils/rknanoutils/rkload/rkloader.c
Normal file
219
utils/rknanoutils/rkload/rkloader.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2013 Amaury Pouly
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libusb.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <getopt.h>
|
||||
|
||||
bool g_debug = false;
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* shamelessly copied from rk27xx utils */
|
||||
static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size)
|
||||
{
|
||||
uint8_t key[] =
|
||||
{
|
||||
0x7C, 0x4E, 0x03, 0x04,
|
||||
0x55, 0x05, 0x09, 0x07,
|
||||
0x2D, 0x2C, 0x7B, 0x38,
|
||||
0x17, 0x0D, 0x17, 0x11
|
||||
};
|
||||
int i, i3, x, val, idx;
|
||||
|
||||
uint8_t key1[0x100];
|
||||
uint8_t key2[0x100];
|
||||
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
key1[i] = i;
|
||||
key2[i] = key[i & 0xf];
|
||||
}
|
||||
|
||||
i3 = 0;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
x = key1[i];
|
||||
i3 = key1[i] + i3;
|
||||
i3 += key2[i];
|
||||
i3 &= 0xff;
|
||||
key1[i] = key1[i3];
|
||||
key1[i3] = x;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
for (i=0; i < size; i++)
|
||||
{
|
||||
x = key1[(i + 1) & 0xff];
|
||||
val = x;
|
||||
idx = (x + idx) & 0xff;
|
||||
key1[(i + 1) & 0xff] = key1[idx];
|
||||
key1[idx] = (x & 0xff);
|
||||
val = (key1[(i + 1)&0xff] + x) & 0xff;
|
||||
val = key1[val];
|
||||
outpg[i] = val ^ inpg[i];
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t compute_crc(uint8_t *buf, int size)
|
||||
{
|
||||
uint16_t result = 65535;
|
||||
for(; size; buf++, size--)
|
||||
{
|
||||
for(int bit = 128; bit; bit >>= 1)
|
||||
{
|
||||
if(result & 0x8000)
|
||||
result = (2 * result) ^ 0x1021;
|
||||
else
|
||||
result *= 2;
|
||||
if(*buf & bit)
|
||||
result ^= 0x1021;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int send_dfu(libusb_device_handle *dev, void *buffer, long size)
|
||||
{
|
||||
/* FIXME I never tried but if the image size is a multiple of 4096 we
|
||||
* probably need to send a last zero length packet for the DFU to boot */
|
||||
while(size >= 0)
|
||||
{
|
||||
int xfer = MIN(size, 4096);
|
||||
if(g_debug)
|
||||
printf("[rkloader] send %d bytes\n", xfer);
|
||||
int ret = libusb_control_transfer(dev,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 12, 0, 1137,
|
||||
buffer, xfer, 1000);
|
||||
if(ret < 0)
|
||||
{
|
||||
fprintf(stderr, "transfer error: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
buffer += xfer;
|
||||
size -= xfer;
|
||||
if(xfer != 4096)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("usage: rkload [options] <file>\n");
|
||||
printf("options:\n");
|
||||
printf(" --help/-? Display this help\n");
|
||||
printf(" --debug/-d Enable debug output\n");
|
||||
printf(" --encode/-e Encode file before sending it\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool encode = false;
|
||||
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"encode", no_argument, 0, 'e'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "?de", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case -1:
|
||||
break;
|
||||
case 'd':
|
||||
g_debug = true;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
case 'e':
|
||||
encode = true;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(argc - optind != 1)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
libusb_init(NULL);
|
||||
libusb_set_debug(NULL, 3);
|
||||
if(g_debug)
|
||||
printf("[rkloader] opening device...\n");
|
||||
libusb_device_handle *dev = libusb_open_device_with_vid_pid(NULL, 0x071b, 0x3226);
|
||||
if(dev == NULL)
|
||||
return fprintf(stderr, "No device found\n");
|
||||
|
||||
if(g_debug)
|
||||
printf("[rkloader] loading file...\n");
|
||||
FILE *f = fopen(argv[optind], "rb");
|
||||
if(f == NULL)
|
||||
return fprintf(stderr, "Cannot open file for reading: %m\n");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
/* allocate two more bytes for the crc */
|
||||
void *buffer = malloc(size + 2);
|
||||
fread(buffer, size, 1, f);
|
||||
fclose(f);
|
||||
/* encode buffer if needed */
|
||||
if(encode)
|
||||
{
|
||||
if(g_debug)
|
||||
printf("[rkloader] encoding buffer...\n");
|
||||
encode_page(buffer, buffer, size);
|
||||
}
|
||||
/* compute crc */
|
||||
if(g_debug)
|
||||
printf("[rkloader] computing crc...\n");
|
||||
uint16_t crc = compute_crc(buffer, size);
|
||||
*(uint8_t *)(buffer + size) = crc >> 8;
|
||||
*(uint8_t *)(buffer + size + 1) = crc & 0xff;
|
||||
|
||||
/* send buffer */
|
||||
if(g_debug)
|
||||
printf("[rkloader] sending buffer...\n");
|
||||
int ret = send_dfu(dev, buffer, size + 2);
|
||||
|
||||
free(buffer);
|
||||
libusb_close(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue