1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by William Poetra Yoga Hadisoeseno and Frank Gevaerts
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
25 #include <sys/types.h>
30 #include <arpa/inet.h>
34 #define bswap_16(value) \
35 ((((value) & 0xff) << 8) | ((value) >> 8))
37 #define bswap_32(value) \
38 (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
39 (uint32_t)bswap_16((uint16_t)((value) >> 16)))
41 #define host_to_le32(_x) bswap_32(htonl(_x))
42 #define host_to_le16(_x) bswap_16(htons(_x))
46 fprintf(stderr
, "usage: meizu_dfu m3 [SST39VF800.dfu] <M3.EBN>\n");
47 fprintf(stderr
, " meizu_dfu m6 [SST39VF800.dfu] <M6.EBN>\n");
48 fprintf(stderr
, " meizu_dfu m6sl [updateNAND_BE_070831.dfu] <M6SL.EBN>\n");
52 uint32_t crc32(char *data
, int len
, uint32_t poly
, uint32_t init
)
54 uint32_t crc_table
[256];
59 for (i
= 0; i
< 256; ++i
) {
61 for (j
= 0; j
< 8; ++j
)
71 for (i
= 0; i
< len
; ++i
)
72 crc
= (crc
>> 8) ^ crc_table
[(crc
^data
[i
]) & 0xff];
95 #define BLOCK_SIZE 2048
96 #define DFU_TIMEOUT 0xa000
97 #define DFU_CRC_POLY 0xedb88320
98 #define DFU_INIT_CRC 0xffffffff
100 #define USB_VID_SAMSUNG 0x0419
101 #define USB_PID_M6SL 0x0145
102 #define USB_PID_M3_M6 0x0141
104 void init_img(image_data_t
*img
, const char *filename
, image_attr_t
*attr
)
106 int fd
, len
, i
, readlen
;
108 char buf
[BLOCK_SIZE
];
112 printf("Reading %s...", filename
);
114 if (stat(filename
, &statbuf
) < 0) {
115 printf("\nCould not stat file, exiting.\n");
118 len
= statbuf
.st_size
;
120 img
->name
= basename(strdup(filename
));
121 img
->data
= malloc(len
+ 16);
124 fd
= open(filename
, O_RDONLY
);
125 for (i
= 0; i
< len
; i
+= BLOCK_SIZE
) {
126 readlen
= ((len
- i
) < BLOCK_SIZE
) ? (len
- i
) : BLOCK_SIZE
;
127 read(fd
, buf
, readlen
);
128 memcpy(img
->data
+ i
, buf
, readlen
);
132 le_len
= host_to_le32(img
->len
);
133 // patch the data size in after the signature
134 memcpy(img
->data
+ attr
->pre_off
+ 4, &le_len
, 4);
136 /* convert to little endian */
137 attr
->suf_dev
= host_to_le16(attr
->suf_dev
);
138 attr
->suf_prod
= host_to_le16(attr
->suf_prod
);
139 attr
->suf_ven
= host_to_le16(attr
->suf_ven
);
140 attr
->suf_dfu
= host_to_le16(attr
->suf_dfu
);
142 // append the suffix (excluding the checksum)
143 memcpy(img
->data
+ len
, &attr
->suf_dev
, 2);
144 memcpy(img
->data
+ len
+ 2, &attr
->suf_prod
, 2);
145 memcpy(img
->data
+ len
+ 4, &attr
->suf_ven
, 2);
146 memcpy(img
->data
+ len
+ 6, &attr
->suf_dfu
, 2);
147 memcpy(img
->data
+ len
+ 8, &attr
->suf_sig
, 3);
148 memcpy(img
->data
+ len
+ 11, &attr
->suf_len
, 1);
150 dfu_crc
= host_to_le32(crc32(img
->data
, len
+ 12, DFU_CRC_POLY
, DFU_INIT_CRC
));
151 memcpy(img
->data
+ len
+ 12, &dfu_crc
, 4);
154 FILE *f
= fopen(img
->name
, "w");
155 fwrite(img
->data
, len
+ 16, 1, f
);
162 usb_dev_handle
*usb_dev_open(uint16_t dfu_vid
, uint16_t dfu_pid
)
165 struct usb_device
*dev
;
166 usb_dev_handle
*device
;
168 printf("USB initialization...");
174 for (bus
= usb_get_busses(); bus
!= NULL
; bus
= bus
->next
)
175 for (dev
= bus
->devices
; dev
!= NULL
; dev
= dev
->next
)
176 if (dev
->descriptor
.idVendor
== dfu_vid
177 && dev
->descriptor
.idProduct
== dfu_pid
)
180 printf("\nNo device found, exiting.\n");
184 printf(" Device found.\n");
185 device
= usb_open(dev
);
186 usb_claim_interface(device
, 0);
190 void usb_mimic_windows(usb_dev_handle
*device
)
194 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0012, DFU_TIMEOUT
);
195 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x0009, DFU_TIMEOUT
);
196 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x001b, DFU_TIMEOUT
);
197 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0040, DFU_TIMEOUT
);
198 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0012, DFU_TIMEOUT
);
199 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x0009, DFU_TIMEOUT
);
200 usb_control_msg(device
, 0x80, 0x06, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
201 usb_control_msg(device
, 0x80, 0x06, 0x0303, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
202 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
203 usb_control_msg(device
, 0x80, 0x06, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
204 usb_control_msg(device
, 0x80, 0x06, 0x0302, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
205 usb_control_msg(device
, 0x80, 0x06, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
206 usb_control_msg(device
, 0x80, 0x06, 0x0302, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
207 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0012, DFU_TIMEOUT
);
208 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x0209, DFU_TIMEOUT
);
211 void usb_dev_close(usb_dev_handle
*device
)
213 printf("Releasing interface...");
215 usb_release_interface(device
, 0);
230 void get_cpu(usb_dev_handle
*device
)
233 int req_out_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
238 // check for "S5L8700 Rev.1"
239 len
= usb_control_msg(device
, req_out_if
, 0xff, 0x0002, 0, data
, 0x003f, DFU_TIMEOUT
);
241 printf("\nError trying to get CPU model, exiting.\n");
245 memset(data
+ len
, 0, 64 - len
);
246 printf(", got: %s\n", data
);
249 void send_file(usb_dev_handle
*device
, image_data_t
*img
)
253 int req_out_if
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
254 int req_in_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
255 int len
, idx
, writelen
, i
;
257 printf("Sending %s... ", img
->name
);
263 for (i
= 0, idx
= 0; i
< len
; i
+= BLOCK_SIZE
, ++idx
) {
264 writelen
= ((len
- i
) < BLOCK_SIZE
) ? (len
- i
) : BLOCK_SIZE
;
265 usb_control_msg(device
, req_out_if
, DFU_DOWNLOAD
, idx
, 0, data
+ i
, writelen
, DFU_TIMEOUT
);
267 while (dfu_ret
[4] != 0x05)
268 usb_control_msg(device
, req_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
272 usb_control_msg(device
, req_out_if
, DFU_DOWNLOAD
, idx
, 0, NULL
, 0, DFU_TIMEOUT
);
274 while (dfu_ret
[4] != 0x07)
275 usb_control_msg(device
, req_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
280 void clear_status(usb_dev_handle
*device
)
283 int usb_in_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
284 int usb_out_if
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
286 printf("Clearing status...");
289 while (dfu_ret
[4] != 0x08)
290 usb_control_msg(device
, usb_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
291 usb_control_msg(device
, usb_out_if
, DFU_CLRSTATUS
, 0, 0, NULL
, 0, DFU_TIMEOUT
);
296 void dfu_detach(usb_dev_handle
*device
)
299 int usb_in_oth
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_OTHER
;
300 int usb_out_oth
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_OTHER
;
302 printf("Detaching...");
304 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
305 usb_control_msg(device
, usb_out_oth
, DFU_DOWNLOAD
, 0x0010, 3, NULL
, 0, DFU_TIMEOUT
);
306 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
307 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
308 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
309 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
310 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
315 void dfu_m3_m6(char *file1
, char *file2
)
317 image_data_t img1
, img2
;
318 image_attr_t attr1
, attr2
;
319 usb_dev_handle
*device
;
322 attr1
.pre_off
= 0x20;
323 attr1
.pre_sig
= 0x44465543;
324 attr1
.suf_dev
= 0x0100;
325 attr1
.suf_prod
= 0x0140;
326 attr1
.suf_ven
= 0x0419;
327 attr1
.suf_dfu
= 0x0100;
328 memcpy(attr1
.suf_sig
, "RON", 3);
329 attr1
.suf_len
= 0x10;
331 init_img(&img1
, file1
, &attr1
);
335 attr2
.pre_off
= 0x20;
336 attr2
.pre_sig
= 0x44465543;
337 attr2
.suf_dev
= 0x0100;
338 attr2
.suf_prod
= 0x0140;
339 attr2
.suf_ven
= 0x0419;
340 attr2
.suf_dfu
= 0x0100;
341 memcpy(attr2
.suf_sig
, "UFD", 3);
342 attr2
.suf_len
= 0x10;
344 init_img(&img2
, file2
, &attr2
);
347 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M3_M6
);
348 // usb_mimic_windows();
351 send_file(device
, &img1
);
354 printf("Wait a sec (literally)...");
358 clear_status(device
);
360 send_file(device
, &img2
);
364 usb_dev_close(device
);
367 void dfu_m6sl(char *file1
, char *file2
)
369 image_data_t img1
, img2
;
370 image_attr_t attr1
, attr2
;
371 usb_dev_handle
*device
;
374 attr1
.pre_off
= 0x20;
375 attr1
.pre_sig
= 0x44465543;
376 attr1
.suf_dev
= 0x0100;
377 attr1
.suf_prod
= 0x0140;
378 attr1
.suf_ven
= 0x0419;
379 attr1
.suf_dfu
= 0x0100;
380 memcpy(attr1
.suf_sig
, "UFD", 3);
381 attr1
.suf_len
= 0x10;
383 init_img(&img1
, file1
, &attr1
);
387 attr2
.pre_off
= 0x20;
388 attr2
.pre_sig
= 0x44465543;
389 attr2
.suf_dev
= 0x0100;
390 attr2
.suf_prod
= 0x0140;
391 attr2
.suf_ven
= 0x0419;
392 attr2
.suf_dfu
= 0x0100;
393 memcpy(attr2
.suf_sig
, "UFD", 3);
394 attr2
.suf_len
= 0x10;
396 init_img(&img2
, file2
, &attr2
);
399 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M6SL
);
402 send_file(device
, &img1
);
405 printf("Wait a sec (literally)...");
408 usb_dev_close(device
);
410 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M6SL
);
413 send_file(device
, &img2
);
417 usb_dev_close(device
);
421 int main(int argc
, char **argv
)
423 if (argc
< 3 || argc
> 4)
426 setvbuf(stdout
, NULL
, _IONBF
, 0);
428 char *second_file
= (argc
== 4) ? argv
[3] : NULL
;
430 if (!strcmp(argv
[1], "m3"))
431 dfu_m3_m6(argv
[2], second_file
);
432 else if (!strcmp(argv
[1], "m6"))
433 dfu_m3_m6(argv
[2], second_file
);
434 else if (!strcmp(argv
[1], "m6sl"))
435 dfu_m6sl(argv
[2], second_file
);