1
0
Fork 0
forked from len0rd/rockbox

Rockchip rk27xx utils

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29936 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Marcin Bukat 2011-05-30 21:10:43 +00:00
parent 976a1699da
commit 8f4202db28
28 changed files with 1845 additions and 0 deletions

37
utils/rk27utils/README Normal file
View file

@ -0,0 +1,37 @@
This is the collection of small utilities needed to hack Rockchip rk27xx
series based DAPs. This tools were tested on linux only.
rk27load
This directory contains tool which can send arbitrary image(s) to the device
in rockchip recovery mode (VID:PID 0x071B:0x3201).
The first image can not exceed 510 bytes (+2 bytes checksum) and entry
point is 0x18020e00. Usually this code is used to configure SDRAM controller.
One can use first stage image extracted from Rock27Boot.bin file (a bit
more sofisticated) or the one provided in rk27load/stage1 directory.
The second image is loaded at the begining of the dram (0x60000000)
and executed. For some reason (which is still unclear) the size of
2nd stage image is limited to about 3-4 kB.
You can find example of custom 2nd stage image in rk27load/stage2 directory.
The purpose of this image is to configure bulk transfer and allow to
load usercode without size restriction mentioned above (the max size
is 8MB actually). The entry point of usercode is 0x60000000.
You need libusb 1.0 + header files in order to compile this utility.
You need working arm-eabi crosscompiler in order to compile stage1/stage2
bootloader binaries (but You should have one already if You tinker whith this)
rkboottool
This directory contains tool which allows to extract (and decrypt) images
stored in Rock27Boot.bin recovery file.
rkusbtool
This directory contains tool which sends custom scsi commands to the
rockchip player.
You need libusb-1.0 + header files in order to compile this utility.

View file

@ -0,0 +1,7 @@
all: rk27load
rk27load: main.c scramble.c checksum.c common.c stage1_upload.c stage2_upload.c stage3_upload.c
gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^
clean:
rm -fr *.o rk27load

View file

@ -0,0 +1,35 @@
#include <stdint.h>
#include "checksum.h"
uint16_t checksum(void *buff, uint32_t size)
{
uint32_t r2 = 0xffff;
uint32_t r3 = 0;
uint32_t i, j;
for (i=0; i<size; i++) {
r3 = 0x80;
for (j=0; j<8; j++) {
if ((r2 & 0x8000) != 0) {
r2 <<= 17;
r2 >>= 16;
r2 ^= 0x1000;
r2 ^= 0x21;
}
else {
r2 <<= 17;
r2 >>= 16;
}
if ((((uint8_t *)buff)[i] & r3) != 0) {
r2 ^= 0x1000;
r2 ^= 0x21;
}
r3 >>= 1;
}
}
return r2 & 0xffff;
}

View file

@ -0,0 +1 @@
uint16_t checksum(void *buff, uint32_t size);

View file

@ -0,0 +1,16 @@
#include <stdint.h>
#include <stdio.h>
#include "common.h"
uint32_t filesize(FILE * f)
{
uint32_t filesize;
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
return filesize;
}

View file

@ -0,0 +1 @@
uint32_t filesize(FILE * f);

View file

@ -0,0 +1,165 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <libusb.h>
#include "rk27load.h"
#include "common.h"
#include "stage1_upload.h"
#include "stage2_upload.h"
#include "stage3_upload.h"
#define VERSION "v0.2"
enum {
NONE = 0,
ENCODE_S1 = 1,
ENCODE_S2 = 2
};
static void usage(char *name)
{
printf("usage: (sudo) %s [-e1 -e2] -s1 stage1.bin -s2 stage2.bin -s3 usercode.bin\n", name);
printf("stage1.bin - binary of the stage1 (sdram init)\n");
printf("stage2.bin - binary of the stage2 bootloader\n");
printf("usercode.bin - binary of the custom usercode\n");
printf("\n");
printf("options:\n");
printf("-e1 - encode stage1 bootloader\n");
printf("-e2 - encode stage2 bootloader\n");
}
int main(int argc, char **argv)
{
libusb_device_handle *hdev;
char *filenames[3];
int i=1, action=0, ret=0;
while (i < argc)
{
if (strcmp(argv[i],"-e1") == 0)
{
action |= ENCODE_S1;
i++;
}
else if (strcmp(argv[i],"-e2") == 0)
{
action |= ENCODE_S2;
i++;
}
else if (strcmp(argv[i],"-s1") == 0)
{
i++;
if (i == argc)
{
usage(argv[0]);
return -1;
}
filenames[0] = argv[i];
printf("%s", argv[i]);
i++;
}
else if (strcmp(argv[i],"-s2") == 0)
{
i++;
if (i == argc)
{
usage(argv[0]);
return -2;
}
filenames[1] = argv[i];
i++;
}
else if (strcmp(argv[i],"-s3") == 0)
{
i++;
if (i == argc)
{
usage(argv[0]);
return -3;
}
filenames[2] = argv[i];
i++;
}
else
{
usage(argv[0]);
return -4;
}
}
fprintf(stderr,"rk27load " VERSION "\n");
fprintf(stderr,"(C) Marcin Bukat 2011\n");
fprintf(stderr,"Based on rk27load ver. 0.1 written by AleMaxx (alemaxx at hotmail.de)\n\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");
/* initialize libusb */
libusb_init(NULL);
/* configure device */
fprintf(stderr, "[info]: Initializing device... ");
hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID);
if (hdev == NULL)
{
fprintf(stderr, "\n[error]: Could not find rockchip device\n");
ret = -2;
goto finish;
}
ret = libusb_set_configuration(hdev, 1);
if (ret < 0)
{
fprintf(stderr, "\n[error]: Could not select configuration (1)\n");
ret = -3;
goto finish;
}
ret = libusb_claim_interface(hdev, 0);
if (ret < 0)
{
fprintf(stderr, "\n[error]: Could not claim interface #0\n");
ret = -4;
goto finish;
}
ret = libusb_set_interface_alt_setting(hdev, 0, 0);
if (ret < 0)
{
fprintf(stderr, "\n[error]: Could not set alternate interface #0\n");
ret = -5;
goto finish;
}
fprintf(stderr, "done\n");
ret = upload_stage1_code(hdev, filenames[0], (action & ENCODE_S1));
if (ret < 0)
goto finish;
ret = upload_stage2_code(hdev, filenames[1], (action & ENCODE_S2));
if (ret < 0)
goto finish;
ret = upload_stage3_code(hdev, filenames[2]);
if (ret < 0)
goto finish;
/* done */
ret = 0;
finish:
if (hdev != NULL)
libusb_close(hdev);
if (ret < 0)
fprintf(stderr, "[error]: Error %d\n", ret);
return ret;
}

View file

@ -0,0 +1,11 @@
#define USB_TIMEOUT 512
#define VENDORID 0x71b
#define PRODUCTID 0x3201
#define USB_EP0 0x41
#define VCMD_UPLOAD 0x0c
#define VCMD_INDEX_STAGE1 0x471
#define VCMD_INDEX_STAGE2 0x472

View file

@ -0,0 +1,46 @@
#include <stdint.h>
#include "scramble.h"
void scramble(uint8_t *in, uint8_t *out, const int size)
{
/* table extracted from bootrom */
static const 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];
out[i] = val ^ in[i];
}
}

View file

@ -0,0 +1 @@
void scramble(uint8_t *in, uint8_t *out, const int size);

View file

@ -0,0 +1,48 @@
TARGET = stage1
TOOLCHAIN = arm-elf-eabi-
CC = $(TOOLCHAIN)gcc
CPP = $(TOOLCHAIN)cpp
LD = $(TOOLCHAIN)gcc
AS = $(TOOLCHAIN)as
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
#ASFLAGS = -mcpu=arm926ej-s
OBJS = main.o
LDSCRIPT= stage1.lds
#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
#LIBS = -lgcc
LIBS =
LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
-mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
all : $(TARGET).bin
ls -ls $(TARGET).bin
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
%.o : %.S
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET).elf : $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
$(TARGET).bin : $(TARGET).elf
$(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
dasm : $(TARGET).bin
$(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
clean :
rm -f $(OBJS)
rm -f $(TARGET).elf
rm -f $(TARGET).bin
rm -f $(TARGET).asm
rm -f $(TARGET).map

View file

@ -0,0 +1,42 @@
.section .text,"ax",%progbits
.global start
start:
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
pll_setup:
mov r0, #0x18000000
add r0, r0, #0x1c000
/* setup ARM core freq = 200MHz */
/* AHB bus freq (HCLK) = 100MHz */
/* APB bus freq (PCLK) = 50MHz */
ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
orr r1, #9 /* ARM slow mode, HCLK:PCLK = 2:1 */
str r1, [r0,#0x14]
ldr r1,=0x01970c70 /* (1<<24) | (1<<23) | (23<<16) | (199<<4) */
str r1, [r0,#0x08]
ldr r2,=0x40000
1:
ldr r1, [r0,#0x2c] /* SCU_STATUS */
tst r1, #1 /* ARM pll lock */
bne 1f
subs r2, #1
bne 1b
1:
ldr r1, [r0,#0x14] /* SCU_DIVCON1 */
bic r1, #5 /* leave ARM slow mode, ARMclk:HCLK = 2:1 */
str r1, [r0,#0x14]
sdram_config:
add r0, r0, #0x94000 /* SDRAM base */
mov r1, #1
str r1, [r0,#0x10c] /* MCSDR_BASIC Round-robin, SDRAM width 16bits */
add r1, #0x10
str r1, [r0,#0x108] /* MCSDR_ADDCFG 12 bits row/9 bits col addr */
mov pc, lr /* we are done, return to bootrom code */

View file

@ -0,0 +1,23 @@
ENTRY(start)
OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
/* STARTUP(crt0.o) */
/* this is where bootrom loads sdram init code */
MEMORY
{
IRAM : ORIGIN = 0x18200E00, LENGTH = 0x00000200
}
SECTIONS
{
.text : {
*(.text*)
*(.glue_7*)
} > IRAM
.data : {
*(.rodata*)
*(.data*)
} > IRAM
}

View file

@ -0,0 +1,113 @@
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include "rk27load.h"
#include "common.h"
#include "scramble.h"
#include "checksum.h"
#include "stage1_upload.h"
/* ### upload sdram init code ### */
int upload_stage1_code(libusb_device_handle *hdev, char *fn_stage1,
bool do_scramble)
{
FILE *f;
int ret;
uint8_t *code;
uint32_t codesize;
uint16_t cks;
if ((f = fopen(fn_stage1, "rb")) == NULL)
{
fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage1);
return -10;
}
codesize = filesize(f);
if (codesize > 0x1fe)
{
fprintf(stderr, "[error]: Code too big for stage1\n");
return -11;
}
fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage1);
code = (uint8_t *)malloc(0x200);
if (code == NULL)
{
fprintf(stderr, "\n[error]: Out of memory\n");
fclose(f);
return -12;
}
memset(code, 0, 0x200);
if (fread(code, 1, codesize, f) != codesize)
{
fprintf(stderr, "\n[error]: I/O error\n");
fclose(f);
free(code);
return -13;
}
fprintf(stderr, "done\n");
fclose(f);
/* encode data if requested */
if (do_scramble)
{
fprintf(stderr, "[stage1]: Encoding %d bytes of data ... ", codesize);
scramble(code, code, codesize);
fprintf(stderr, "done\n");
}
fprintf(stderr, "[stage1]: codesize = %d (0x%x)\n", codesize, codesize);
fprintf(stderr, "[stage1]: Calculating checksum... ");
cks = checksum((void *)code, codesize);
fprintf(stderr, "0x%04x\n", cks);
code[0x1fe] = (cks >> 8) & 0xff;
code[0x1ff] = cks & 0xff;
codesize += 2;
fprintf(stderr, "[stage1]: Uploading code (%d bytes)... ", codesize);
ret = libusb_control_transfer(hdev, /* device handle */
USB_EP0, /* bmRequestType */
VCMD_UPLOAD, /* bRequest */
0, /* wValue */
VCMD_INDEX_STAGE1, /* wIndex */
code, /* data */
codesize, /* wLength */
USB_TIMEOUT /* timeout */
);
if (ret < 0)
{
fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
free(code);
return -14;
}
if (ret != (int)codesize)
{
fprintf(stderr, "\n[error]: Sent %d of %d total\n", ret, codesize);
free(code);
return -15;
}
sleep(1); /* wait for code to finish */
fprintf(stderr, "done\n");
/* free code */
free(code);
return 0;
}

View file

@ -0,0 +1,3 @@
int upload_stage1_code(libusb_device_handle * hdev, char *fn_stage1,
bool do_scramble);

View file

@ -0,0 +1,48 @@
TARGET = stage2
TOOLCHAIN = arm-elf-eabi-
CC = $(TOOLCHAIN)gcc
CPP = $(TOOLCHAIN)cpp
LD = $(TOOLCHAIN)gcc
AS = $(TOOLCHAIN)as
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
CFLAGS = -Wundef -marm -march=armv5te -nostdlib -mfpu=fpa -O0 -c
#ASFLAGS = -mcpu=arm926ej-s
OBJS = crt0.o main.o irq.o
LDSCRIPT= stage2.lds
#LIBDIRS = -L../arm/lib/gcc/arm-elf/4.1.0/ -L../lib
#LIBS = -lgcc
LIBS =
LDFLAGS = -Wundef -marm -march=armv5te -T$(LDSCRIPT) -nostartfiles \
-mfpu=fpa -nostdlib -Xlinker -Map=$(TARGET).map
all : $(TARGET).bin
ls -ls $(TARGET).bin
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(INCDIRS) $< -o $@
%.o : %.S
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET).elf : $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf
$(TARGET).bin : $(TARGET).elf
$(OBJCOPY) -O binary $(TARGET).elf $(TARGET).bin
dasm : $(TARGET).bin
$(OBJDUMP) -m arm -D $(TARGET).elf | cat > $(TARGET).asm
clean :
rm -f $(OBJS)
rm -f $(TARGET).elf
rm -f $(TARGET).bin
rm -f $(TARGET).asm
rm -f $(TARGET).map

View file

@ -0,0 +1,55 @@
//
// startup code
//
//
#define PSR_MODE 0x0000001f
#define PSR_USR_MODE 0x00000010
#define PSR_IRQ_MODE 0x00000012
#define PSR_SVC_MODE 0x00000013
#define PSR_INT_MASK 0x000000c0
#define PSR_FIQ_DIS 0x00000040
#define PSR_IRQ_DIS 0x00000080
.section .init.text,"ax",%progbits
.global start
.extern _interrupt_disable
// -----------------------------------------------------
// startup code (setup stacks, branch to main)
// -----------------------------------------------------
start:
// setup IRQ stack
mov r0, #(PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
msr cpsr, r0
ldr sp,=irqstackend
// setup SVC stack
mov r0, #(PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS)
msr cpsr, r0
ldr sp,=stackend
// disbale interrupts
mrs r0, cpsr
orr r0, r0, #0xc0
msr cpsr_c, r0
// remap
mov r0, #0x18000000
add r0, r0, #0x1C000
ldr r1,=0xdeadbeef
str r1, [r0, #4]
// relocate itself
ldr r0,=_relocstart
ldr r1,=_relocend
ldr r2,=0x0
1:
cmp r1,r0
ldrhi r3,[r0],#4
strhi r3,[r2],#4
bhi 1b
// continue running in SVC (supervisor mode)
ldr pc,=0x0

View file

@ -0,0 +1,103 @@
.section .text
.align 4
.global irq_handler
#define BUFF_ADDR 0x60800000
irq_handler:
stmfd sp!, {r0-r7, ip, lr}
// get interrupt number
mov r4, #0x18000000
add r4, r4, #0x80000
ldr r5, [r4, #0x104]
and r5, r5, #0x1f
cmp r5, #0x10 // UDC interrupt
bleq udc_irq
// clear pending interrupt
mov r3, #1
mov r2, r3, LSL r5
str r2, [r4, #0x118]
ldmfd sp!, {r0-r7, ip, lr}
subs pc, lr, #4
udc_irq:
stmfd sp!, {r4-r8, lr}
// handle usb interrupt
ldr r4,=0x180A0000
ldr r5, [r4, #0x18] // UDC_INTFLAG
// ep0 in intr
tst r5, #0x04
beq bulk_recv_intr
// write_reg32(UDC_TX0STAT, read_reg32(UDC_TX0STAT) & ~0x7FF);
ldr r5, [r4, #0x40]
mov r5, r5, lsr #10
mov r5, r5, lsl #10 // clear clower 10 bits
str r5, [r4, #0x40]
// write_reg32(UDC_DMA0LM_OADDR, (uint32_t)(state.ctrlep_data));
mov r5, #0x60000000
str r5, [r4, #0x3c]
// write_reg32(UDC_DMA0CTLO, read_reg32(UDC_DMA0CTLO) | ENP_DMA_START);
mov r5, #1
str r5, [r4, #0x38]
ldmfd sp!, {r4-r8, pc}
// bulk out interrupt
bulk_recv_intr:
tst r5, #0x100
ldmeqfd sp!, {r4-r8, pc}
// read UDC_RX1STAT
ldr r5, [r4, #0x54]
mov r5, r5, lsl #21
mov r5, r5, lsr #21 // r5 = length
ldr r6,=usb_sz
ldr r6, [r6]
ldr r7, [r6] // r7 = total_code_length expected
subs r7, r7, r5
bne usb_bulk_out1_recv
// copy from buff to the begining of the ram
ldr r0,=BUFF_ADDR
ldr r1,[r0,#-4] // size
ldr r1,=0x800000 // buffer size
add r1,r1,r0 // end address
ldr r2,=0x60000000 // destination
1:
cmp r1,r0
ldrhi r3,[r0],#4
strhi r3,[r2],#4
bhi 1b
// execute user code
ldr r0,=0x60000000
bx r0 // jump to 0x60000000
usb_bulk_out1_recv:
str r7, [r6] // size = size - received
ldr r6,=usb_write_addr
ldr r7, [r6]
add r7, r7, r5
str r7, [r6] // usb_write_addr += length
str r7, [r4, #0x60] // DMA1LM_OADDR = usb_write_addr
mov r5, #1
str r5, [r4, #0x5c] // DMA1_CTL0 = ENP_DMA_START
ldmfd sp!, {r4-r8, pc}

View file

@ -0,0 +1,89 @@
.section .text
.align 4
.arm
.global main
.global _interrupt_disable
.global _interrupt_enable
.global usb_write_addr
.global usb_sz
#define BUFF_ADDR 0x60800000
// -----------------------------------------------------
// vector table
// -----------------------------------------------------
ldr pc, =main
ldr pc, =main
ldr pc, =main
ldr pc, =main
ldr pc, =main
ldr pc, =main
ldr pc, =irq_handler
ldr pc, =main
// -----------------------------------------------------
// main
// -----------------------------------------------------
main:
// turn on usb interrupts
mov r0, #0x18000000
add r0, r0, #0x80000
ldr r1, [r0, #0x10c]
orr r1, r1, #0x10000
str r1, [r0, #0x10c]
// enable usb-bulk
add r0, r0, #0x20000 // R0 = 0x180A0000 (UDC_BASE)
// enable EP1, write_reg32(UDC_RX1CON, (0x1 << 8) | RxACKINTEN | RxEPEN);
mov r1, #0x190 // bits 8,7,4 -> 0x190
str r1, [r0, #0x58]
// setup receive buffer (must be aligned on dword boundary)
ldr r1,=usb_write_addr // write_reg32(UDC_DMA1LM_OADDR, (uint32_t)rx_buff);
ldr r1, [r1]
str r1, [r0, #0x60] // UDC_DMA1LM_OADDR = usb_write_addr
// write_reg32(UDC_DMA1CTRLO, read_reg32(UDC_DMA1CTRLO) | ENP_DMA_START);
ldr r1, [r0, #0x5c]
orr r1, r1, #2
str r1, [r0, #0x5c]
// enable bulk_out1 interrupt
ldr r1, [r0, #0x14] // UDC_ENINT
orr r1, r1, #0x100 // EN_BOUT1_INTR
str r1, [r0, #0x14]
bl _interrupt_enable
idle:
b idle
// -----------------------------------------------------
// _interrupt_enable - enables interrupts
// -----------------------------------------------------
_interrupt_enable:
mrs r0, cpsr
bic r0, r0, #0x80
msr cpsr_c, r0
mov pc, lr
// -----------------------------------------------------
// _interrupt_disable - disables interrupts
// -----------------------------------------------------
_interrupt_disable:
mrs r0, cpsr
orr r0, r0, #0xc0
msr cpsr_c, r0
mov pc, lr
.section .data
usb_write_addr:
.word (BUFF_ADDR-4)
usb_sz:
.word (BUFF_ADDR-4)

View file

@ -0,0 +1,40 @@
ENTRY(start)
OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
/* STARTUP(crt0.o) */
MEMORY
{
DRAM : ORIGIN = 0x60000000, LENGTH = 0x01000000
IRAM : ORIGIN = 0x00000000, LENGTH = 0x00002000
}
SECTIONS
{
.init.text : {
*(.init.text)
} > DRAM
.text : {
*(.text*)
*(.glue_7*)
} > IRAM AT > DRAM
.data : {
*(.data*)
} > IRAM AT > DRAM
_relocstart = LOADADDR(.text);
_relocend = LOADADDR(.data) + SIZEOF(.data);
.stack (NOLOAD) : {
. = ALIGN(0x100);
*(.stack)
stackbegin = .;
. += 0x200;
stackend = .;
irqstackbegin = .;
. += 0x200;
irqstackend = .;
} > IRAM
}

View file

@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include "rk27load.h"
#include "common.h"
#include "scramble.h"
#include "checksum.h"
#include "stage2_upload.h"
int upload_stage2_code(libusb_device_handle *hdev, char *fn_stage2,
bool do_scramble)
{
FILE *f;
uint32_t codesize;
uint8_t *code;
uint16_t cks;
int ret;
if ((f = fopen(fn_stage2, "rb")) == NULL)
{
fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage2);
return -21;
}
codesize = filesize(f);
fprintf(stderr, "[stage1]: Loading %d bytes (%s) of code... ", codesize, fn_stage2);
code = (uint8_t *) malloc(codesize + 0x400);
if (code == NULL)
{
fprintf(stderr, "\n[error]: Out of memory\n");
fclose(f);
return -22;
}
memset(code, 0, codesize + 0x400);
if (fread(code, 1, codesize, f) != codesize)
{
fprintf(stderr, "\n[error]: I/O error\n");
fclose(f);
free(code);
return -23;
}
fprintf(stderr, "done\n");
fclose(f);
codesize = ((codesize + 0x201) & 0xfffffe00) - 2;
if (do_scramble)
{
/* encode data if its user code */
fprintf(stderr, "[stage2]: Encoding %d bytes data... ", codesize);
scramble(code, code, codesize);
fprintf(stderr, "done\n");
}
fprintf(stderr, "[stage2]: Calculating checksum... ");
cks = checksum(code, codesize);
code[codesize + 0] = (cks >> 8) & 0xff;
code[codesize + 1] = cks & 0xff;
codesize += 2;
fprintf(stderr, "0x%04x\n", cks);
fprintf(stderr, "[stage2]: Uploading code (%d bytes)... ", codesize);
ret = libusb_control_transfer(hdev, /* device handle */
USB_EP0, /* bmRequestType */
VCMD_UPLOAD, /* bRequest */
0, /* wValue */
VCMD_INDEX_STAGE2, /* wIndex */
code, /* data */
codesize, /* wLength */
USB_TIMEOUT /* timeout */
);
if (ret < 0)
{
fprintf(stderr, "\n[error]: Code upload request failed (ret=%d)\n", ret);
free(code);
return -24;
}
if (ret != (int)codesize)
{
fprintf(stderr, "[error]: Sent %d of %d total\n", ret, codesize);
free(code);
return -25;
}
fprintf(stderr, "done\n");
free(code);
return 0;
}

View file

@ -0,0 +1,3 @@
int upload_stage2_code(libusb_device_handle * hdev, char *fn_stage2,
bool do_scramble);

View file

@ -0,0 +1,93 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include "rk27load.h"
#include "common.h"
#include "scramble.h"
#include "checksum.h"
#include "stage3_upload.h"
int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3)
{
FILE *f;
uint32_t codesize;
uint32_t remain;
uint8_t *code;
uint16_t send_size = 0x200;
uint32_t i = 0;
int ret, transfered;
if ((f = fopen(fn_stage3, "rb")) == NULL)
{
fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage3);
return -31;
}
codesize = filesize(f);
fprintf(stderr, "[stage3]: Loading user code (%d bytes)... ", codesize);
/* allocate buffer */
code = (uint8_t *) malloc(codesize + 0x204);
if (code == NULL)
{
fprintf(stderr, "\n[error]: Out of memory\n");
fclose(f);
return -32;
}
memset(code, 0, codesize + 0x204);
/* read usercode into buffer */
if (fread(&code[4], 1, codesize, f) != codesize)
{
fprintf(stderr, "\n[error]: I/O error\n");
fclose(f);
free(f);
return -33;
}
fprintf(stderr, "done\n");
fclose(f);
/* put code size at the first 4 bytes */
codesize += 4;
code[0] = codesize & 0xff;
code[1] = (codesize >> 8) & 0xff;
code[2] = (codesize >> 16) & 0xff;
code[3] = (codesize >> 24) & 0xff;
fprintf(stderr, "[stage3]: Uploading user code (%d bytes)... ", codesize);
remain = codesize;
while (remain > 0)
{
if (remain < 0x200)
send_size = remain;
ret = libusb_bulk_transfer(hdev, /* handle */
1, /* EP */
&code[i * 0x200], /* data */
send_size, /* length */
&transfered, /* xfered */
USB_TIMEOUT /* timeout */
);
if (ret != LIBUSB_SUCCESS)
{
fprintf(stderr, "\n[error]: Bulk transfer error (%d, %d)\n", ret, i);
free(code);
return -34;
}
remain -= send_size;
i++;
}
fprintf(stderr,"done (sent %d blocks)\n", i);
return 0;
}

View file

@ -0,0 +1 @@
int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3);

View file

@ -0,0 +1,7 @@
all: rkboottool
rkboottool: rkboottool.c
gcc -g -std=c99 -o $@ -W -Wall $^
clean:
rm -fr rkboottool

View file

@ -0,0 +1,360 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define VERSION "v0.3"
/* time field stucture */
struct rktime_t
{
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
};
/* Rock27Boot.bin header structure */
struct rkboot_info_t
{
char sign[32];
uint8_t check_values[16];
struct rktime_t time;
uint32_t ui_master_version;
uint32_t ui_slave_version;
uint32_t s1_offset;
int32_t s1_len;
uint32_t s2_offset;
int32_t s2_len;
uint32_t s3_offset;
int32_t s3_len;
uint32_t s4_offset;
int32_t s4_len;
uint32_t version_flag;
};
/* actions */
enum {
NONE = 0,
INFO = 1,
EXTRACT = 2,
SCRAMBLE = 4
};
/* scramble mode */
enum {
CONTINOUS_ENC, /* scramble whole block at once */
PAGE_ENC /* nand bootloader is scrambled in 0x200 chunks */
};
/* scrambling/descrambling reverse engineered by AleMaxx */
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 void *binary_extract(FILE *fp, uint32_t offset, uint32_t len, int descramble, int encode_mode)
{
void *buff, *buff_ptr;
uint32_t ret;
if ((fp == NULL) || len == 0)
return NULL;
/* allocate buff */
if ((buff = malloc(len)) == NULL)
return NULL;
/* seek to the begining of the data */
fseek(fp, offset, SEEK_SET);
/* read into the buffer */
ret = fread(buff, 1, len, fp);
if (ret != len)
{
free(buff);
return NULL;
}
/* descramble */
if ( descramble )
{
buff_ptr = buff;
if (encode_mode == PAGE_ENC)
{
while (len >= 0x200)
{
encode_page((uint8_t *)buff_ptr,
(uint8_t *)buff_ptr,
0x200);
buff_ptr += 0x200;
len -= 0x200;
}
}
encode_page((uint8_t *)buff_ptr, (uint8_t *)buff_ptr, len);
}
return buff;
}
static void usage(void)
{
printf("Usage: rkboottool [options] Rock27Boot.bin\n");
printf("-h|--help This help message\n");
printf("-e|--extract Extract binary images from Rock27Boot.bin file\n");
printf("-d|--descramble Descramble extracted binary images\n");
printf("-i|--info Print info about Rock27Boot.bin file\n");
printf("\n");
printf("Usually you would like to use -d -e together to obtain raw binary\n");
printf("(out files rkboot_s1.bin, rkboot_s2.bin, rkboot_s3.bin, rkboot_s4.bin)\n");
}
int main (int argc, char **argv)
{
struct rkboot_info_t rkboot_info;
FILE *fp_in, *fp_out;
int32_t i = 0, action = NONE;
int32_t ret;
void *buff;
char *in_filename = NULL;
if ( argc < 2 )
{
usage();
return -1;
}
/* print banner */
fprintf(stderr,"rkboottool " VERSION "\n");
fprintf(stderr,"(C) Marcin Bukat 2011\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");
/* arguments handling */
while (i < argc)
{
if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0))
{
action |= INFO;
}
else if ((strcmp(argv[i],"-e")==0) || (strcmp(argv[i],"--extract")==0))
{
action |= EXTRACT;
}
else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--descramble")==0))
{
action |= SCRAMBLE;
}
else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
{
usage();
return 0;
}
else if ( argv[i][0] != '-' )
{
/* file argument */
in_filename = argv[i];
}
i++;
}
if ( (fp_in = fopen(in_filename, "rb")) == NULL )
{
fprintf(stderr, "error: can't open %s file for reading\n", in_filename);
return -1;
}
ret = fread(&rkboot_info, 1, sizeof(rkboot_info), fp_in);
if (ret != sizeof(rkboot_info))
{
fclose(fp_in);
fprintf(stderr, "error: can't read %s file header\n", in_filename);
fprintf(stderr, "read %d, expected %d\n", ret, sizeof(rkboot_info));
return -2;
}
if (action & INFO)
{
printf("file: %s\n", in_filename);
printf("signature: %s\n", rkboot_info.sign);
printf("check bytes: ");
for (i = 0; i < 16; i++)
printf("0x%0x ", rkboot_info.check_values[i]);
printf("\n");
printf("timestamp %d.%d.%d %d:%d:%d\n", rkboot_info.time.day,
rkboot_info.time.month,
rkboot_info.time.year,
rkboot_info.time.hour,
rkboot_info.time.minute,
rkboot_info.time.second);
printf("UI master version: 0x%0x\n", rkboot_info.ui_master_version);
printf("UI slave version: 0x%0x\n", rkboot_info.ui_slave_version);
printf("s1 data offset: 0x%0x\n", rkboot_info.s1_offset);
printf("s1 data len: 0x%0x\n", rkboot_info.s1_len);
printf("s2 offset: 0x%0x\n", rkboot_info.s2_offset);
printf("s2 len: 0x%0x\n", rkboot_info.s2_len);
printf("s3 offset: 0x%0x\n", rkboot_info.s3_offset);
printf("s3 len: 0x%0x\n", rkboot_info.s3_len);
printf("s4 offset: 0x%0x\n", rkboot_info.s4_offset);
printf("s4 len: 0x%0x\n", rkboot_info.s4_len);
printf("UI version flag: 0x%0x\n", rkboot_info.version_flag);
}
if (action & EXTRACT)
{
/* first stage */
buff = binary_extract(fp_in, rkboot_info.s1_offset,
rkboot_info.s1_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "error: can't extract image\n");
return -2;
}
/* output */
if ((fp_out = fopen("rkboot_s1.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s1.bin for writing\n");
return -3;
}
fwrite(buff, 1, rkboot_info.s1_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s1.bin file\n");
free(buff);
fclose(fp_out);
/* second stage */
buff = binary_extract(fp_in, rkboot_info.s2_offset,
rkboot_info.s2_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "error: can't extract image\n");
return -2;
}
if ((fp_out = fopen("rkboot_s2.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s2.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s2_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s2.bin file\n");
free(buff);
fclose(fp_out);
/* third stage */
buff = binary_extract(fp_in, rkboot_info.s3_offset,
rkboot_info.s3_len,
action & SCRAMBLE,
PAGE_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "[error]: can't extract image.\n");
return -2;
}
if ((fp_out = fopen("rkboot_s3.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s3.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s3_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s3.bin file\n");
free(buff);
fclose(fp_out);
/* forth stage */
buff = binary_extract(fp_in, rkboot_info.s4_offset,
rkboot_info.s4_len,
action & SCRAMBLE,
CONTINOUS_ENC);
if ( buff == NULL )
{
fclose(fp_in);
fprintf(stderr, "[error]: can't extract image\n");
return -2;
}
if ((fp_out = fopen("rkboot_s4.bin", "wb")) == NULL)
{
free(buff);
fclose(fp_in);
fprintf(stderr, "[error]: can't open rkboot_s4.bin for writing\n");
return -4;
}
fwrite(buff, 1, rkboot_info.s4_len, fp_out);
fprintf(stderr, "[info]: extracted rkboot_s4.bin file\n");
free(buff);
fclose(fp_out);
}
fclose(fp_in);
return 0;
}

View file

@ -0,0 +1,7 @@
all: rkusbtool
rkusbtool: rkusbtool.c
gcc -g -std=c99 -o $@ -W -Wall -lusb-1.0 -I/usr/include/libusb-1.0/ $^
clean:
rm -fr rkusbtool

View file

@ -0,0 +1,388 @@
/* on ubuntu compile with gcc -W rkusbtool.c -o rkusbtool -lusb-1.0 -I/usr/include/libusb-1.0/ */
#include <libusb.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define VERSION "v0.1"
#define RETRY_MAX 5
#define USB_TIMEOUT 512
#define VENDORID 0x071b
#define PRODUCTID 0x3203
#define OUT_EP 0x01
#define IN_EP 0x82
#define CBW_SIGNATURE 0x43425355
#define CSW_SIGNATURE 0x53425355
#define SCSICMD_READ_12 0xa8
/* rockchip specific commands */
#define RK_CMD 0xe0
#define RK_GET_VERSION 0xffffffff
#define RK_SWITCH_ROCKUSB 0xfeffffff
#define RK_CHECK_USB 0xfdffffff
#define RK_OPEN_SYSDISK 0xfcffffff
enum {
NONE = 0,
INFO = 1,
RKUSB = 2,
SYSDISK = 4,
CHECKUSB = 8
};
enum {
COMMAND_PASSED = 0,
COMMAND_FAILED = 1,
PHASE_ERROR = 2
};
struct CBWCB_t
{
uint8_t cbCode;
uint8_t cbLun;
uint32_t LBA;
uint32_t cbLen;
uint8_t reseved;
uint8_t control;
} __attribute__((__packed__));
struct CBW_t
{
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCBLength;
uint8_t CBWCB[16];
} __attribute__((__packed__));
struct CSW_t
{
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
} __attribute__((__packed__));
static int send_msc_cmd(libusb_device_handle *hdev, struct CBWCB_t *cbwcb, uint32_t data_len, uint32_t *reftag)
{
struct CBW_t cbw;
int ret, repeat, transferred;
static uint32_t tag = 0xdaefbc01;
memset(&cbw, 0, sizeof(cbw));
cbw.dCBWSignature = CBW_SIGNATURE;
cbw.dCBWTag = tag++;
cbw.dCBWDataTransferLength = data_len;
cbw.bmCBWFlags = 0x80; /* device to host */
cbw.bCBWLUN = 0;
cbw.bCBWCBLength = sizeof(struct CBWCB_t);
memcpy(cbw.CBWCB, cbwcb, sizeof(struct CBWCB_t));
*reftag = cbw.dCBWTag;
do
{
/* transfer command to the device */
ret = libusb_bulk_transfer(hdev, OUT_EP, (unsigned char*)&cbw, 31, &transferred, USB_TIMEOUT);
if (ret == LIBUSB_ERROR_PIPE)
{
libusb_clear_halt(hdev, OUT_EP);
}
repeat++;
} while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX));
if (ret != LIBUSB_SUCCESS)
{
printf("error: command transfer error\n");
return -1;
}
return 0;
}
static int get_msc_csw(libusb_device_handle *hdev, uint32_t reftag)
{
struct CSW_t csw;
int ret, repeat, transferred;
/* get CSW response from device */
repeat = 0;
do
{
ret = libusb_bulk_transfer(hdev, IN_EP, (unsigned char *)&csw, 13, &transferred, USB_TIMEOUT);
if (ret == LIBUSB_ERROR_PIPE)
{
libusb_clear_halt(hdev, IN_EP);
}
repeat++;
} while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX));
if (ret != LIBUSB_SUCCESS)
{
printf("error reading CSW\n");
return -3;
}
if (transferred != 13)
{
printf("error wrong size of CSW packet\n");
return -4;
}
if (csw.dCSWSignature != CSW_SIGNATURE)
{
printf("error: wrong CSW signature.\n");
return -5;
}
if (csw.dCSWTag != reftag)
{
printf("error: CSW dCSWTag mismatch\n");
return -6;
}
if (csw.bCSWStatus)
{
/* In case of CSW indicating error dump the content of the packet */
printf ("dCSWSignature: 0x%0x\n", csw.dCSWSignature);
printf ("dCSWTag: 0x%0x\n", csw.dCSWTag);
printf ("dCSWDataResidue: 0x%0x\n", csw.dCSWDataResidue);
printf ("bCSWStatus: 0x%0x\n", csw.bCSWStatus);
}
return csw.bCSWStatus;
}
static int rk_cmd(libusb_device_handle *hdev, uint32_t command, uint8_t *buf, uint8_t len)
{
struct CBWCB_t cbwcb;
int ret, transferred;
uint32_t reftag;
/* enter command */
memset(&cbwcb, 0, sizeof(cbwcb));
cbwcb.cbCode = SCSICMD_READ_12;
cbwcb.cbLun = RK_CMD;
cbwcb.LBA = command; /* RK_GET_VERSION, RK_OPEN_SYSDISK, RK_SWITCH_ROCKUSB */
cbwcb.cbLen = len; /* size of transfer in response to this command */
ret = send_msc_cmd(hdev, &cbwcb, len, &reftag);
/* get the response */
if (len > 0)
{
ret = libusb_bulk_transfer(hdev, IN_EP, buf, len, &transferred, USB_TIMEOUT);
if (ret != LIBUSB_SUCCESS || transferred != len)
{
printf("error: reading response data failed\n");
return -2;
}
}
return get_msc_csw(hdev, reftag);
}
static int get_sense(libusb_device_handle *hdev)
{
struct CBWCB_t cbwcb;
unsigned char sense[0x12];
int size, ret;
uint32_t reftag;
memset(&cbwcb, 0, sizeof(cbwcb));
cbwcb.cbCode = 0x03;
cbwcb.cbLun = 0;
cbwcb.LBA = 0;
cbwcb.cbLen = 0x12;
ret = send_msc_cmd(hdev, &cbwcb, 0x12, &reftag);
libusb_bulk_transfer(hdev, IN_EP, (unsigned char*)&sense, 0x12, &size, USB_TIMEOUT);
return get_msc_csw(hdev, reftag);
}
static void usage(void)
{
printf("Usage: rkusbtool [options]\n");
printf("-h|--help This help message\n");
printf("-i|--info Get version string from the device\n");
printf("-d|--dfu Put device into DFU mode\n");
printf("-s|--sysdisk Open system disk\n");
printf("-c|--checkusb Check if dev is in System or Loader USB mode\n");
}
int main (int argc, char **argv)
{
libusb_device_handle *hdev;
int ret;
int i = 0, action = NONE;
uint32_t ver[3];
if (argc < 2)
{
usage();
return 1;
}
/* print banner */
fprintf(stderr,"rkusbtool " VERSION "\n");
fprintf(stderr,"(C) Marcin Bukat 2011\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");
/* arguments handling */
while (i < argc)
{
if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0))
{
action |= INFO;
}
else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--dfu")==0))
{
action |= RKUSB;
}
else if ((strcmp(argv[i],"-s")==0) || (strcmp(argv[i],"--sysdisk")==0))
{
action |= SYSDISK;
}
else if ((strcmp(argv[i],"-c")==0) || (strcmp(argv[i],"--checkusb")==0))
{
action |= CHECKUSB;
}
else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
{
usage();
return 0;
}
i++;
}
/* initialize libusb */
libusb_init(NULL);
/* usb_set_debug(2); */
hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID);
if (hdev == NULL)
{
printf("error: can't open device\n");
return -10;
}
ret = libusb_kernel_driver_active(hdev, 0);
if (ret < 0)
{
printf ("error checking kernel driver active\n");
libusb_close(hdev);
return -3;
}
else
{
if (ret)
libusb_detach_kernel_driver(hdev, 0);
}
ret = libusb_set_configuration(hdev, 1);
if (ret < 0)
{
printf("error: could not select configuration (1)\n");
libusb_close(hdev);
return -3;
}
ret = libusb_claim_interface(hdev, 0);
if (ret < 0)
{
printf("error: could not claim interface #0\n");
libusb_close(hdev);
return -11;
}
ret = libusb_set_interface_alt_setting(hdev, 0, 0);
if ( ret != LIBUSB_SUCCESS)
{
printf("error: could not set alt setting for interface #0\n");
libusb_close(hdev);
return -11;
}
/* BulkOnly reset */
//ret = libusb_control_transfer(hdev, 0x21, 0xff, 0, 0, NULL, 0, USB_TIMEOUT);
/* BulkOnly get max lun */
//ret = libusb_control_transfer(hdev, 0xa1, 0xfe, 0, 0, &maxlun, 1, USB_TIMEOUT);
/* Devices that do not support multiple LUNs may STALL this command. */
//if (ret == 0)
// maxlun = -1;
//printf("MAXLUN: %d\n", maxlun);
get_sense(hdev);
if (action & INFO)
{
ret = rk_cmd(hdev, RK_GET_VERSION, (uint8_t *)ver, 12);
if (ret)
{
printf("error sending RK_GET_VERSION command. Err 0x%0x\n", ret);
libusb_close(hdev);
return ret;
}
printf("Rockchip device info:\n");
printf("loader ver: %x.%x\n", (ver[0]>>16)&0xff, ver[0]&0xff);
printf("kernel ver: %x.%x\n", (ver[1]>>16)&0xff, ver[1]&0xff);
printf("sdk ver: %x.%x\n", (ver[2]>>16)&0xff, ver[2]&0xff);
}
if (action & CHECKUSB)
{
printf("Checking USB mode...\n");
ret = rk_cmd(hdev, RK_CHECK_USB, (uint8_t *)ver, 1);
//if (ret)
//{
// libusb_close(hdev);
// return ret;
//}
if (*(char *)ver)
printf("The device is in Loader USB mode\n");
else
printf("The device is in System USB mode\n");
}
if (action & SYSDISK)
{
printf("Opening system disk...\n");
ret = rk_cmd(hdev, RK_OPEN_SYSDISK, NULL, 0);
if (ret)
{
libusb_close(hdev);
return ret;
}
}
if (action & RKUSB)
{
printf("Switching into rk DFU mode...\n");
ret = rk_cmd(hdev, RK_SWITCH_ROCKUSB, NULL, 0);
if (ret)
{
libusb_close(hdev);
return ret;
}
}
libusb_close(hdev);
libusb_exit(NULL);
return 0;
}