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>
33 #define bswap_16(value) \
34 ((((value) & 0xff) << 8) | ((value) >> 8))
36 #define bswap_32(value) \
37 (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
38 (uint32_t)bswap_16((uint16_t)((value) >> 16)))
40 #define host_to_le32(_x) bswap_32(htonl(_x))
41 #define host_to_le16(_x) bswap_16(htons(_x))
45 fprintf(stderr
, "usage: meizu_dfu m3 <SST39VF800.dfu> <M3.EBN>\n");
46 fprintf(stderr
, " meizu_dfu m6 <SST39VF800.dfu> <M6.EBN>\n");
47 fprintf(stderr
, " meizu_dfu m6sl <updateNAND_BE_070831.dfu> <M6SL.EBN>\n");
51 uint32_t crc32(char *data
, int len
, uint32_t poly
, uint32_t init
)
53 uint32_t crc_table
[256];
58 for (i
= 0; i
< 256; ++i
) {
60 for (j
= 0; j
< 8; ++j
)
70 for (i
= 0; i
< len
; ++i
)
71 crc
= (crc
>> 8) ^ crc_table
[(crc
^data
[i
]) & 0xff];
94 #define BLOCK_SIZE 2048
95 #define DFU_TIMEOUT 0xa000
96 #define DFU_CRC_POLY 0xedb88320
97 #define DFU_INIT_CRC 0xffffffff
99 #define USB_VID_SAMSUNG 0x0419
100 #define USB_PID_M6SL 0x0145
101 #define USB_PID_M3_M6 0x0141
103 void init_img(image_data_t
*img
, const char *filename
, image_attr_t
*attr
)
105 int fd
, len
, i
, readlen
;
107 char buf
[BLOCK_SIZE
];
111 printf("Reading %s...", filename
);
113 stat(filename
, &statbuf
);
114 len
= statbuf
.st_size
;
116 img
->name
= basename(strdup(filename
));
117 img
->data
= malloc(len
+ 16);
120 fd
= open(filename
, O_RDONLY
);
121 for (i
= 0; i
< len
; i
+= BLOCK_SIZE
) {
122 readlen
= ((len
- i
) < BLOCK_SIZE
) ? (len
- i
) : BLOCK_SIZE
;
123 read(fd
, buf
, readlen
);
124 memcpy(img
->data
+ i
, buf
, readlen
);
128 le_len
= host_to_le32(img
->len
);
129 // patch the data size in after the signature
130 memcpy(img
->data
+ attr
->pre_off
+ 4, &le_len
, 4);
132 /* convert to little endian */
133 attr
->suf_dev
= host_to_le16(attr
->suf_dev
);
134 attr
->suf_prod
= host_to_le16(attr
->suf_prod
);
135 attr
->suf_ven
= host_to_le16(attr
->suf_ven
);
136 attr
->suf_dfu
= host_to_le16(attr
->suf_dfu
);
138 // append the suffix (excluding the checksum)
139 memcpy(img
->data
+ len
, &attr
->suf_dev
, 2);
140 memcpy(img
->data
+ len
+ 2, &attr
->suf_prod
, 2);
141 memcpy(img
->data
+ len
+ 4, &attr
->suf_ven
, 2);
142 memcpy(img
->data
+ len
+ 6, &attr
->suf_dfu
, 2);
143 memcpy(img
->data
+ len
+ 8, &attr
->suf_sig
, 3);
144 memcpy(img
->data
+ len
+ 11, &attr
->suf_len
, 1);
146 dfu_crc
= host_to_le32(crc32(img
->data
, len
+ 12, DFU_CRC_POLY
, DFU_INIT_CRC
));
147 memcpy(img
->data
+ len
+ 12, &dfu_crc
, 4);
150 FILE *f
= fopen(img
->name
, "w");
151 fwrite(img
->data
, len
+ 16, 1, f
);
158 usb_dev_handle
*usb_dev_open(uint16_t dfu_vid
, uint16_t dfu_pid
)
161 struct usb_device
*dev
;
162 usb_dev_handle
*device
;
164 printf("USB initialization...");
170 for (bus
= usb_get_busses(); bus
!= NULL
; bus
= bus
->next
)
171 for (dev
= bus
->devices
; dev
!= NULL
; dev
= dev
->next
)
172 if (dev
->descriptor
.idVendor
== dfu_vid
173 && dev
->descriptor
.idProduct
== dfu_pid
)
176 printf("\nNo device found, exiting.\n");
180 printf(" Device found.\n");
181 device
= usb_open(dev
);
182 usb_claim_interface(device
, 0);
186 void usb_mimic_windows(usb_dev_handle
*device
)
190 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0012, DFU_TIMEOUT
);
191 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x0009, DFU_TIMEOUT
);
192 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x001b, DFU_TIMEOUT
);
193 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0040, DFU_TIMEOUT
);
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, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
197 usb_control_msg(device
, 0x80, 0x06, 0x0303, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
198 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
199 usb_control_msg(device
, 0x80, 0x06, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
200 usb_control_msg(device
, 0x80, 0x06, 0x0302, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
201 usb_control_msg(device
, 0x80, 0x06, 0x0300, 0x0000, data
, 0x00ff, DFU_TIMEOUT
);
202 usb_control_msg(device
, 0x80, 0x06, 0x0302, 0x0409, data
, 0x00ff, DFU_TIMEOUT
);
203 usb_control_msg(device
, 0x80, 0x06, 0x0100, 0x0000, data
, 0x0012, DFU_TIMEOUT
);
204 usb_control_msg(device
, 0x80, 0x06, 0x0200, 0x0000, data
, 0x0209, DFU_TIMEOUT
);
207 void usb_dev_close(usb_dev_handle
*device
)
209 printf("Releasing interface...");
211 usb_release_interface(device
, 0);
226 void get_cpu(usb_dev_handle
*device
)
229 int req_out_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
234 // check for "S5L8700 Rev.1"
235 len
= usb_control_msg(device
, req_out_if
, 0xff, 0x0002, 0, data
, 0x003f, DFU_TIMEOUT
);
237 printf("\nError trying to get CPU model, exiting.\n");
241 memset(data
+ len
, 0, 64 - len
);
242 printf(", got: %s\n", data
);
245 void send_file(usb_dev_handle
*device
, image_data_t
*img
)
249 int req_out_if
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
250 int req_in_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
251 int len
, idx
, writelen
, i
;
253 printf("Sending %s... ", img
->name
);
259 for (i
= 0, idx
= 0; i
< len
; i
+= BLOCK_SIZE
, ++idx
) {
260 writelen
= ((len
- i
) < BLOCK_SIZE
) ? (len
- i
) : BLOCK_SIZE
;
261 usb_control_msg(device
, req_out_if
, DFU_DOWNLOAD
, idx
, 0, data
+ i
, writelen
, DFU_TIMEOUT
);
263 while (dfu_ret
[4] != 0x05)
264 usb_control_msg(device
, req_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
268 usb_control_msg(device
, req_out_if
, DFU_DOWNLOAD
, idx
, 0, NULL
, 0, DFU_TIMEOUT
);
270 while (dfu_ret
[4] != 0x07)
271 usb_control_msg(device
, req_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
276 void clear_status(usb_dev_handle
*device
)
279 int usb_in_if
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
280 int usb_out_if
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
;
282 printf("Clearing status...");
285 while (dfu_ret
[4] != 0x08)
286 usb_control_msg(device
, usb_in_if
, DFU_GETSTATUS
, 0, 0, dfu_ret
, 6, DFU_TIMEOUT
);
287 usb_control_msg(device
, usb_out_if
, DFU_CLRSTATUS
, 0, 0, NULL
, 0, DFU_TIMEOUT
);
292 void dfu_detach(usb_dev_handle
*device
)
295 int usb_in_oth
= USB_ENDPOINT_IN
| USB_TYPE_CLASS
| USB_RECIP_OTHER
;
296 int usb_out_oth
= USB_ENDPOINT_OUT
| USB_TYPE_CLASS
| USB_RECIP_OTHER
;
298 printf("Detaching...");
300 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
301 usb_control_msg(device
, usb_out_oth
, DFU_DOWNLOAD
, 0x0010, 3, NULL
, 0, DFU_TIMEOUT
);
302 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
303 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
304 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
305 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
306 usb_control_msg(device
, usb_in_oth
, DFU_DETACH
, 0x0000, 3, usb_ret
, 4, DFU_TIMEOUT
);
311 void dfu_m3_m6(char *file1
, char *file2
)
313 image_data_t img1
, img2
;
314 image_attr_t attr1
, attr2
;
315 usb_dev_handle
*device
;
318 attr1
.pre_off
= 0x20;
319 attr1
.pre_sig
= 0x44465543;
320 attr1
.suf_dev
= 0x0100;
321 attr1
.suf_prod
= 0x0140;
322 attr1
.suf_ven
= 0x0419;
323 attr1
.suf_dfu
= 0x0100;
324 memcpy(attr1
.suf_sig
, "RON", 3);
325 attr1
.suf_len
= 0x10;
328 attr2
.pre_off
= 0x20;
329 attr2
.pre_sig
= 0x44465543;
330 attr2
.suf_dev
= 0x0100;
331 attr2
.suf_prod
= 0x0140;
332 attr2
.suf_ven
= 0x0419;
333 attr2
.suf_dfu
= 0x0100;
334 memcpy(attr2
.suf_sig
, "UFD", 3);
335 attr2
.suf_len
= 0x10;
337 init_img(&img1
, file1
, &attr1
);
338 init_img(&img2
, file2
, &attr2
);
340 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M3_M6
);
341 // usb_mimic_windows();
344 send_file(device
, &img1
);
346 printf("Wait a sec (literally)...");
350 clear_status(device
);
352 send_file(device
, &img2
);
354 usb_dev_close(device
);
357 void dfu_m6sl(char *file1
, char *file2
)
359 image_data_t img1
, img2
;
360 image_attr_t attr1
, attr2
;
361 usb_dev_handle
*device
;
364 attr1
.pre_off
= 0x20;
365 attr1
.pre_sig
= 0x44465543;
366 attr1
.suf_dev
= 0x0100;
367 attr1
.suf_prod
= 0x0140;
368 attr1
.suf_ven
= 0x0419;
369 attr1
.suf_dfu
= 0x0100;
370 memcpy(attr1
.suf_sig
, "UFD", 3);
371 attr1
.suf_len
= 0x10;
374 attr2
.pre_off
= 0x20;
375 attr2
.pre_sig
= 0x44465543;
376 attr2
.suf_dev
= 0x0100;
377 attr2
.suf_prod
= 0x0140;
378 attr2
.suf_ven
= 0x0419;
379 attr2
.suf_dfu
= 0x0100;
380 memcpy(attr2
.suf_sig
, "UFD", 3);
381 attr2
.suf_len
= 0x10;
383 init_img(&img1
, file1
, &attr1
);
384 init_img(&img2
, file2
, &attr2
);
386 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M6SL
);
389 send_file(device
, &img1
);
391 printf("Wait a sec (literally)...");
394 usb_dev_close(device
);
396 device
= usb_dev_open(USB_VID_SAMSUNG
, USB_PID_M6SL
);
399 send_file(device
, &img2
);
401 usb_dev_close(device
);
405 int main(int argc
, char **argv
)
410 setvbuf(stdout
, NULL
, _IONBF
, 0);
412 if (!strcmp(argv
[1], "m3"))
413 dfu_m3_m6(argv
[2], argv
[3]);
414 else if (!strcmp(argv
[1], "m6"))
415 dfu_m3_m6(argv
[2], argv
[3]);
416 else if (!strcmp(argv
[1], "m6sl"))
417 dfu_m6sl(argv
[2], argv
[3]);