flash just some files from update
[android-command-line.git] / rkflashtool / rkflashtool.c
1 /* rkflashtool - for RK2808, RK2818 and RK2918 based tablets
2  *
3  * Copyright (C) 2011 Ivo van Poorten   (complete rewrite for libusb)
4  * Copyright (C) 2010 FUKAUMI Naoki     (reverse engineering of protocol)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Build with:
27  *
28  *      gcc -o rkflashtool rkflashtool.c -lusb-1.0 -O2 -W -Wall -s
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <stdint.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <libusb-1.0/libusb.h>
38
39 #define RKFLASHTOOL_VERSION     2
40
41 #define RKFT_BLOCKSIZE  0x4000                  /* must be multiple of 512 */
42 #define RKFT_OFF_INCR   (RKFT_BLOCKSIZE>>9)
43
44 #define RKFT_CID        4
45 #define RKFT_FLAG       12
46 #define RKFT_COMMAND    13
47 #define RKFT_OFFSET     17
48 #define RKFT_SIZE       23
49
50 #define SETBE32(a, v) ((uint8_t*)a)[3] =  v      & 0xff; \
51                       ((uint8_t*)a)[2] = (v>>8 ) & 0xff; \
52                       ((uint8_t*)a)[1] = (v>>16) & 0xff; \
53                       ((uint8_t*)a)[0] = (v>>24) & 0xff
54
55 static uint8_t cmd[31] = { 'U', 'S', 'B', 'C', };
56 static uint8_t res[13];
57
58 static uint8_t buf[RKFT_BLOCKSIZE], cid;
59 static int tmp;
60
61 static const char *const strings[2] = { "info", "fatal" };
62
63 static void info_and_fatal(const int s, char *f, ...) {
64     va_list ap;
65     va_start(ap,f);
66     fprintf(stderr, "rkflashtool: %s: ", strings[s]);
67     vfprintf(stderr, f, ap);
68     va_end(ap);
69     if (s) exit(s);
70 }
71
72 #define info(...)   info_and_fatal(0, __VA_ARGS__)
73 #define fatal(...)  info_and_fatal(1, __VA_ARGS__)
74
75 static void usage(void) {
76     fatal("usage:\n"
77           "\trkflashtool b                   \treboot device\n"
78           "\trkflashtool r offset size >file \tread flash\n"
79           "\trkflashtool w offset size <file \twrite flash\n\n"
80           "\toffset and size are in units of 512 bytes\n");
81 }
82
83 static void send_cmd(libusb_device_handle *h, int e, uint8_t flag,
84                      uint32_t command, uint32_t offset, uint8_t size) {
85     cmd[RKFT_CID ] = cid++;
86     cmd[RKFT_FLAG] = flag;
87     cmd[RKFT_SIZE] = size;
88
89     SETBE32(&cmd[RKFT_COMMAND], command);
90     SETBE32(&cmd[RKFT_OFFSET ], offset );
91
92     libusb_bulk_transfer(h, e|LIBUSB_ENDPOINT_OUT, cmd, sizeof(cmd), &tmp, 0);
93 }
94
95 #define send_buf(h,e,s) libusb_bulk_transfer(h, e|LIBUSB_ENDPOINT_OUT, \
96                                              buf, s, &tmp, 0)
97
98 #define recv_res(h,e) libusb_bulk_transfer(h, e|LIBUSB_ENDPOINT_IN, \
99                                            res, sizeof(res), &tmp, 0)
100
101 #define recv_buf(h,e,s) libusb_bulk_transfer(h, e|LIBUSB_ENDPOINT_IN, \
102                                              buf, s, &tmp, 0)
103
104 #define NEXT do { argc--;argv++; }while(0)
105
106 int main(int argc, char **argv) {
107     libusb_context *c;
108     libusb_device_handle *h;
109     int offset = 0, size = 0;
110     char action;
111
112     NEXT; if (!argc) usage();
113
114     action = **argv; NEXT;
115
116     switch(action) {
117     case 'b':           if (argc   ) usage(); break;
118     case 'r': case 'w': if (argc!=2) usage();
119         offset = strtoul(argv[0], NULL, 0);
120         size   = strtoul(argv[1], NULL, 0);
121         break;
122     default:
123         usage();
124     }
125
126     if (libusb_init(&c)) fatal("cannot init libusb\n");
127
128     libusb_set_debug(c, 3);
129
130     if (!(h = libusb_open_device_with_vid_pid(c, 0x2207, 0x290a)))
131         if (!(h = libusb_open_device_with_vid_pid(c, 0x2207, 0x281a)))
132         if (!(h = libusb_open_device_with_vid_pid(c, 0x2207, 0x300a)))
133             fatal("cannot open device\n");
134
135     if (libusb_kernel_driver_active(h, 0) == 1) {
136         info("kernel driver active\n");
137         if (!libusb_detach_kernel_driver(h, 0))
138             info("driver detached\n");
139     }
140
141     if (libusb_claim_interface(h, 0)<0) fatal("cannot claim interface\n");
142     info("interface claimed\n");
143
144     send_cmd(h, 2, 0x80, 0x00060000, 0x00000000, 0x00);        // INIT
145     recv_res(h, 1);
146     usleep(20*1000);
147
148     switch(action) {
149     case 'b':
150         info("rebooting device...\n");
151         send_cmd(h, 2, 0x00, 0x0006ff00, 0x00000000, 0x00);
152         recv_res(h, 1);
153         break;
154     case 'r':
155         while (size>0) {
156             info("reading flash memory at offset 0x%08x\n", offset);
157
158             send_cmd(h, 2, 0x80, 0x000a1400, offset, RKFT_OFF_INCR);
159             recv_buf(h, 1, RKFT_BLOCKSIZE);
160             recv_res(h, 1);
161
162             write(1, buf, RKFT_BLOCKSIZE);
163             offset += RKFT_OFF_INCR;
164             size   -= RKFT_OFF_INCR;
165         }
166         break;
167     case 'w':
168         while (size>0) {
169             info("writing flash memory at offset 0x%08x\n", offset);
170
171             memset(buf, 0, RKFT_BLOCKSIZE);
172             read(0, buf, RKFT_BLOCKSIZE);
173
174             send_cmd(h, 2, 0x80, 0x000a1500, offset, RKFT_OFF_INCR);
175             send_buf(h, 2, RKFT_BLOCKSIZE);
176             recv_res(h, 1);
177
178             offset += RKFT_OFF_INCR;
179             size   -= RKFT_OFF_INCR;
180         }
181         break;
182     default:
183         break;
184     }
185
186     libusb_release_interface(h, 0);
187     libusb_close(h);
188     libusb_exit(c);
189     return 0;
190 }