diff options
Diffstat (limited to 'utils/meizu_dfu/meizu_dfu.c')
-rw-r--r-- | utils/meizu_dfu/meizu_dfu.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/utils/meizu_dfu/meizu_dfu.c b/utils/meizu_dfu/meizu_dfu.c new file mode 100644 index 0000000000..67a5065384 --- /dev/null +++ b/utils/meizu_dfu/meizu_dfu.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | Copyright 2008 William Poetra Yoga Hadisoeseno <williampoetra@gmail.com> | ||
3 | Frank Gevaerts <frank@gevaerts.be> | ||
4 | This file is licensed under GPL v2. | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <stdint.h> | ||
10 | #include <string.h> | ||
11 | #include <sys/types.h> | ||
12 | #include <sys/stat.h> | ||
13 | #include <fcntl.h> | ||
14 | #include <unistd.h> | ||
15 | #include <libgen.h> | ||
16 | |||
17 | #include <usb.h> | ||
18 | |||
19 | void usage() | ||
20 | { | ||
21 | fprintf(stderr, "usage: meizu_dfu m3 <SST39VF800.dfu> <M3.EBN>\n"); | ||
22 | fprintf(stderr, " meizu_dfu m6 <SST39VF800.dfu> <M6.EBN>\n"); | ||
23 | fprintf(stderr, " meizu_dfu m6sl <updateNAND_BE_070831.dfu> <M6SL.EBN>\n"); | ||
24 | exit(1); | ||
25 | } | ||
26 | |||
27 | uint32_t crc32(char *data, int len, uint32_t poly, uint32_t init) | ||
28 | { | ||
29 | uint32_t crc_table[256]; | ||
30 | uint32_t crc, t; | ||
31 | int i, j; | ||
32 | |||
33 | // generate the table | ||
34 | for (i = 0; i < 256; ++i) { | ||
35 | t = i; | ||
36 | for (j = 0; j < 8; ++j) | ||
37 | if (t & 1) | ||
38 | t = (t >> 1) ^ poly; | ||
39 | else | ||
40 | t >>= 1; | ||
41 | crc_table[i] = t; | ||
42 | } | ||
43 | |||
44 | // calculate the crc | ||
45 | crc = init; | ||
46 | for (i = 0; i < len; ++i) | ||
47 | crc = (crc >> 8) ^ crc_table[(crc^data[i]) & 0xff]; | ||
48 | |||
49 | return crc; | ||
50 | } | ||
51 | |||
52 | #define BLOCK_SIZE 2048 | ||
53 | |||
54 | typedef struct { | ||
55 | char *name; | ||
56 | char *data; | ||
57 | int len; | ||
58 | } image_data_t; | ||
59 | |||
60 | typedef struct { | ||
61 | int delay; | ||
62 | int pre_off; | ||
63 | uint32_t pre_sig; | ||
64 | uint16_t suf_dev; | ||
65 | uint16_t suf_prod; | ||
66 | uint16_t suf_ven; | ||
67 | uint16_t suf_dfu; | ||
68 | char suf_sig[3]; | ||
69 | uint8_t suf_len; | ||
70 | } image_attr_t; | ||
71 | |||
72 | #define DFU_CRC_POLY 0xedb88320 | ||
73 | #define DFU_INIT_CRC 0xffffffff | ||
74 | |||
75 | void init_img(image_data_t *img, const char *filename, image_attr_t *attr) | ||
76 | { | ||
77 | int fd, len, i, readlen; | ||
78 | struct stat statbuf; | ||
79 | char buf[BLOCK_SIZE]; | ||
80 | uint32_t dfu_crc; | ||
81 | |||
82 | printf("Reading %s...", filename); | ||
83 | |||
84 | stat(filename, &statbuf); | ||
85 | len = statbuf.st_size; | ||
86 | |||
87 | img->name = basename(strdup(filename)); | ||
88 | img->data = malloc(len + 16); | ||
89 | img->len = len + 16; | ||
90 | |||
91 | fd = open(filename, O_RDONLY); | ||
92 | for (i = 0; i < len; i += BLOCK_SIZE) { | ||
93 | readlen = ((len - i) < BLOCK_SIZE) ? (len - i) : BLOCK_SIZE; | ||
94 | read(fd, buf, readlen); | ||
95 | memcpy(img->data + i, buf, readlen); | ||
96 | } | ||
97 | close(fd); | ||
98 | |||
99 | // patch the data size in after the signature | ||
100 | memcpy(img->data + attr->pre_off + 4, &img->len, 4); | ||
101 | |||
102 | // append the suffix (excluding the checksum) | ||
103 | memcpy(img->data + len, &attr->suf_dev, 2); | ||
104 | memcpy(img->data + len + 2, &attr->suf_prod, 2); | ||
105 | memcpy(img->data + len + 4, &attr->suf_ven, 2); | ||
106 | memcpy(img->data + len + 6, &attr->suf_dfu, 2); | ||
107 | memcpy(img->data + len + 8, &attr->suf_sig, 3); | ||
108 | memcpy(img->data + len + 11, &attr->suf_len, 1); | ||
109 | |||
110 | dfu_crc = crc32(img->data, len + 12, DFU_CRC_POLY, DFU_INIT_CRC); | ||
111 | memcpy(img->data + len + 12, &dfu_crc, 4); | ||
112 | |||
113 | #if 0 | ||
114 | FILE *f = fopen(img->name, "w"); | ||
115 | fwrite(img->data, len + 16, 1, f); | ||
116 | fclose(f); | ||
117 | #endif | ||
118 | |||
119 | printf("OK\n"); | ||
120 | } | ||
121 | |||
122 | #define DFU_VEN 0x0419 | ||
123 | #define DFU_DEV 0x0141 | ||
124 | usb_dev_handle *device; | ||
125 | int timeout = 0xa0000; | ||
126 | |||
127 | void usb_dev_open() | ||
128 | { | ||
129 | struct usb_bus *bus; | ||
130 | struct usb_device *dev; | ||
131 | |||
132 | printf("USB initialization..."); | ||
133 | fflush(stdout); | ||
134 | |||
135 | usb_init(); | ||
136 | usb_find_busses(); | ||
137 | usb_find_devices(); | ||
138 | |||
139 | for (bus = usb_get_busses(); bus != NULL; bus = bus->next) | ||
140 | for (dev = bus->devices; dev != NULL; dev = dev->next) | ||
141 | if (dev->descriptor.idVendor == DFU_VEN | ||
142 | || dev->descriptor.idProduct == DFU_DEV) | ||
143 | goto found; | ||
144 | |||
145 | printf("\nNo device found, exiting.\n"); | ||
146 | exit(1); | ||
147 | |||
148 | found: | ||
149 | printf(" Device found.\n"); | ||
150 | device = usb_open(dev); | ||
151 | usb_claim_interface(device, 0); | ||
152 | } | ||
153 | |||
154 | void usb_mimic_windows() | ||
155 | { | ||
156 | char data[1024]; | ||
157 | |||
158 | usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, timeout); | ||
159 | usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0009, timeout); | ||
160 | usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x001b, timeout); | ||
161 | usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0040, timeout); | ||
162 | usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, timeout); | ||
163 | usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0009, timeout); | ||
164 | usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, timeout); | ||
165 | usb_control_msg(device, 0x80, 0x06, 0x0303, 0x0409, data, 0x00ff, timeout); | ||
166 | usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x00ff, timeout); | ||
167 | usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, timeout); | ||
168 | usb_control_msg(device, 0x80, 0x06, 0x0302, 0x0409, data, 0x00ff, timeout); | ||
169 | usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, timeout); | ||
170 | usb_control_msg(device, 0x80, 0x06, 0x0302, 0x0409, data, 0x00ff, timeout); | ||
171 | usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, timeout); | ||
172 | usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0209, timeout); | ||
173 | } | ||
174 | |||
175 | void usb_dev_close() | ||
176 | { | ||
177 | printf("Releasing interface..."); | ||
178 | fflush(stdout); | ||
179 | |||
180 | usb_release_interface(device, 0); | ||
181 | |||
182 | printf(" OK\n"); | ||
183 | } | ||
184 | |||
185 | #define DFU_DETACH 0 | ||
186 | #define DFU_DOWNLOAD 1 | ||
187 | #define DFU_UPLOAD 2 | ||
188 | #define DFU_GETSTATUS 3 | ||
189 | #define DFU_CLRSTATUS 4 | ||
190 | #define DFU_GETSTATE 5 | ||
191 | #define DFU_ABORT 6 | ||
192 | |||
193 | void get_cpu() | ||
194 | { | ||
195 | char data[64]; | ||
196 | int req_out_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
197 | int len; | ||
198 | |||
199 | printf("GET CPU"); | ||
200 | fflush(stdout); | ||
201 | |||
202 | // check for "S5L8700 Rev.1" | ||
203 | len = usb_control_msg(device, req_out_if, 0xff, 0x0002, 0, data, 0x003f, timeout); | ||
204 | if (len < 0) { | ||
205 | printf("\nError trying to get CPU model, exiting.\n"); | ||
206 | exit(1); | ||
207 | } | ||
208 | |||
209 | memset(data + len, 0, 64 - len); | ||
210 | printf(", got: %s\n", data); | ||
211 | } | ||
212 | |||
213 | void send_file(image_data_t *img) | ||
214 | { | ||
215 | char dfu_ret[6]; | ||
216 | char *data; | ||
217 | int req_out_if = USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
218 | int req_in_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
219 | int len, idx, writelen, i; | ||
220 | |||
221 | printf("Sending %s... ", img->name); | ||
222 | fflush(stdout); | ||
223 | |||
224 | len = img->len; | ||
225 | data = img->data; | ||
226 | |||
227 | // loop for the file | ||
228 | for (i = 0, idx = 0; i < len; i += BLOCK_SIZE, ++idx) { | ||
229 | writelen = ((len - i) < BLOCK_SIZE) ? (len - i) : BLOCK_SIZE; | ||
230 | usb_control_msg(device, req_out_if, DFU_DOWNLOAD, idx, 0, data + i, writelen, timeout); | ||
231 | dfu_ret[4] = 0x00; | ||
232 | while (dfu_ret[4] != 0x05) | ||
233 | usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, timeout); | ||
234 | printf("#"); | ||
235 | fflush(stdout); | ||
236 | } | ||
237 | |||
238 | usb_control_msg(device, req_out_if, DFU_DOWNLOAD, idx, 0, NULL, 0, timeout); | ||
239 | dfu_ret[4] = 0x00; | ||
240 | while (dfu_ret[4] != 0x07) | ||
241 | usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, timeout); | ||
242 | |||
243 | printf(" OK\n"); | ||
244 | fflush(stdout); | ||
245 | } | ||
246 | |||
247 | void clear_status() | ||
248 | { | ||
249 | char dfu_ret[6]; | ||
250 | int usb_in_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
251 | int usb_out_if = USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
252 | |||
253 | printf("Clearing status..."); | ||
254 | fflush(stdout); | ||
255 | |||
256 | dfu_ret[4] = 0x00; | ||
257 | while (dfu_ret[4] != 0x08) | ||
258 | usb_control_msg(device, usb_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, timeout); | ||
259 | usb_control_msg(device, usb_out_if, DFU_CLRSTATUS, 0, 0, NULL, 0, timeout); | ||
260 | |||
261 | printf(" OK\n"); | ||
262 | } | ||
263 | |||
264 | void dfu_detach() | ||
265 | { | ||
266 | char usb_ret[4]; | ||
267 | int usb_in_oth = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_OTHER; | ||
268 | int usb_out_oth = USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; | ||
269 | |||
270 | printf("Detaching..."); | ||
271 | fflush(stdout); | ||
272 | |||
273 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
274 | usb_control_msg(device, usb_out_oth, DFU_DOWNLOAD, 0x0010, 3, NULL, 0, timeout); | ||
275 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
276 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
277 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
278 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
279 | usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, timeout); | ||
280 | |||
281 | printf(" OK\n"); | ||
282 | } | ||
283 | |||
284 | void dfu_m3_m6(char *file1, char *file2) | ||
285 | { | ||
286 | image_data_t img1, img2; | ||
287 | image_attr_t attr1, attr2; | ||
288 | |||
289 | attr1.delay = 1000; | ||
290 | attr1.pre_off = 0x20; | ||
291 | attr1.pre_sig = 0x44465543; | ||
292 | attr1.suf_dev = 0x0100; | ||
293 | attr1.suf_prod = 0x0140; | ||
294 | attr1.suf_ven = 0x0419; | ||
295 | attr1.suf_dfu = 0x0100; | ||
296 | memcpy(attr1.suf_sig, "RON", 3); | ||
297 | attr1.suf_len = 0x10; | ||
298 | |||
299 | attr2.delay = 1000; | ||
300 | attr2.pre_off = 0x20; | ||
301 | attr2.pre_sig = 0x44465543; | ||
302 | attr2.suf_dev = 0x0100; | ||
303 | attr2.suf_prod = 0x0140; | ||
304 | attr2.suf_ven = 0x0419; | ||
305 | attr2.suf_dfu = 0x0100; | ||
306 | memcpy(attr2.suf_sig, "UFD", 3); | ||
307 | attr2.suf_len = 0x10; | ||
308 | |||
309 | init_img(&img1, file1, &attr1); | ||
310 | init_img(&img2, file2, &attr2); | ||
311 | |||
312 | usb_dev_open(); | ||
313 | // usb_mimic_windows(); | ||
314 | get_cpu(); | ||
315 | get_cpu(); | ||
316 | send_file(&img1); | ||
317 | |||
318 | printf("Wait a sec (literally)..."); | ||
319 | fflush(stdout); | ||
320 | sleep(1); | ||
321 | printf(" OK\n"); | ||
322 | |||
323 | clear_status(); | ||
324 | get_cpu(); | ||
325 | send_file(&img2); | ||
326 | dfu_detach(); | ||
327 | usb_dev_close(); | ||
328 | } | ||
329 | |||
330 | void dfu_m6sl(char *file1, char *file2) | ||
331 | { | ||
332 | image_data_t img1, img2; | ||
333 | image_attr_t attr1, attr2; | ||
334 | |||
335 | attr1.delay = 1000; | ||
336 | attr1.pre_off = 0x20; | ||
337 | attr1.pre_sig = 0x44465543; | ||
338 | attr1.suf_dev = 0x0100; | ||
339 | attr1.suf_prod = 0x0140; | ||
340 | attr1.suf_ven = 0x0419; | ||
341 | attr1.suf_dfu = 0x0100; | ||
342 | memcpy(attr1.suf_sig, "UFD", 3); | ||
343 | attr1.suf_len = 0x10; | ||
344 | |||
345 | attr2.delay = 1000; | ||
346 | attr2.pre_off = 0x20; | ||
347 | attr2.pre_sig = 0x44465543; | ||
348 | attr2.suf_dev = 0x0100; | ||
349 | attr2.suf_prod = 0x0140; | ||
350 | attr2.suf_ven = 0x0419; | ||
351 | attr2.suf_dfu = 0x0100; | ||
352 | memcpy(attr2.suf_sig, "UFD", 3); | ||
353 | attr2.suf_len = 0x10; | ||
354 | |||
355 | init_img(&img1, file1, &attr1); | ||
356 | init_img(&img2, file2, &attr2); | ||
357 | |||
358 | usb_dev_open(); | ||
359 | get_cpu(); | ||
360 | get_cpu(); | ||
361 | send_file(&img1); | ||
362 | |||
363 | printf("Wait a sec (literally)..."); | ||
364 | fflush(stdout); | ||
365 | sleep(1); | ||
366 | printf(" OK\n"); | ||
367 | usb_dev_close(); | ||
368 | |||
369 | usb_dev_open(); | ||
370 | get_cpu(); | ||
371 | get_cpu(); | ||
372 | send_file(&img2); | ||
373 | dfu_detach(); | ||
374 | usb_dev_close(); | ||
375 | } | ||
376 | |||
377 | |||
378 | int main(int argc, char **argv) | ||
379 | { | ||
380 | if (argc != 4) | ||
381 | usage(); | ||
382 | |||
383 | if (!strcmp(argv[1], "m3")) | ||
384 | dfu_m3_m6(argv[2], argv[3]); | ||
385 | else if (!strcmp(argv[1], "m6")) | ||
386 | dfu_m3_m6(argv[2], argv[3]); | ||
387 | else if (!strcmp(argv[1], "m6sl")) | ||
388 | dfu_m6sl(argv[2], argv[3]); | ||
389 | else | ||
390 | usage(); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||