Cleaner solution to plugin-included core files.
[kugel-rb.git] / utils / meizu_dfu / meizu_dfu.c
blob0e32ea8d35190ac6c764adf770eca9b1cf3307a3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <libgen.h>
31 #include <usb.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))
43 void usage()
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");
48 exit(1);
51 uint32_t crc32(char *data, int len, uint32_t poly, uint32_t init)
53 uint32_t crc_table[256];
54 uint32_t crc, t;
55 int i, j;
57 // generate the table
58 for (i = 0; i < 256; ++i) {
59 t = i;
60 for (j = 0; j < 8; ++j)
61 if (t & 1)
62 t = (t >> 1) ^ poly;
63 else
64 t >>= 1;
65 crc_table[i] = t;
68 // calculate the crc
69 crc = init;
70 for (i = 0; i < len; ++i)
71 crc = (crc >> 8) ^ crc_table[(crc^data[i]) & 0xff];
73 return crc;
76 typedef struct {
77 char *name;
78 char *data;
79 int len;
80 } image_data_t;
82 typedef struct {
83 int delay;
84 int pre_off;
85 uint32_t pre_sig;
86 uint16_t suf_dev;
87 uint16_t suf_prod;
88 uint16_t suf_ven;
89 uint16_t suf_dfu;
90 char suf_sig[3];
91 uint8_t suf_len;
92 } image_attr_t;
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;
106 struct stat statbuf;
107 char buf[BLOCK_SIZE];
108 uint32_t dfu_crc;
109 uint32_t le_len;
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);
118 img->len = 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);
126 close(fd);
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);
149 #if 0
150 FILE *f = fopen(img->name, "w");
151 fwrite(img->data, len + 16, 1, f);
152 fclose(f);
153 #endif
155 printf("OK\n");
158 usb_dev_handle *usb_dev_open(uint16_t dfu_vid, uint16_t dfu_pid)
160 struct usb_bus *bus;
161 struct usb_device *dev;
162 usb_dev_handle *device;
164 printf("USB initialization...");
166 usb_init();
167 usb_find_busses();
168 usb_find_devices();
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)
174 goto found;
176 printf("\nNo device found, exiting.\n");
177 exit(1);
179 found:
180 printf(" Device found.\n");
181 device = usb_open(dev);
182 usb_claim_interface(device, 0);
183 return device;
186 void usb_mimic_windows(usb_dev_handle *device)
188 char data[1024];
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);
213 printf(" OK\n");
216 enum DFU_REQUEST {
217 DFU_DETACH = 0,
218 DFU_DOWNLOAD,
219 DFU_UPLOAD,
220 DFU_GETSTATUS,
221 DFU_CLRSTATUS,
222 DFU_GETSTATE,
223 DFU_ABORT
226 void get_cpu(usb_dev_handle *device)
228 char data[64];
229 int req_out_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
230 int len;
232 printf("GET CPU");
234 // check for "S5L8700 Rev.1"
235 len = usb_control_msg(device, req_out_if, 0xff, 0x0002, 0, data, 0x003f, DFU_TIMEOUT);
236 if (len < 0) {
237 printf("\nError trying to get CPU model, exiting.\n");
238 exit(1);
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)
247 char dfu_ret[6];
248 char *data;
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);
255 len = img->len;
256 data = img->data;
258 // loop for the file
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);
262 dfu_ret[4] = 0x00;
263 while (dfu_ret[4] != 0x05)
264 usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, DFU_TIMEOUT);
265 printf("#");
268 usb_control_msg(device, req_out_if, DFU_DOWNLOAD, idx, 0, NULL, 0, DFU_TIMEOUT);
269 dfu_ret[4] = 0x00;
270 while (dfu_ret[4] != 0x07)
271 usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, DFU_TIMEOUT);
273 printf(" OK\n");
276 void clear_status(usb_dev_handle *device)
278 char dfu_ret[6];
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...");
284 dfu_ret[4] = 0x00;
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);
289 printf(" OK\n");
292 void dfu_detach(usb_dev_handle *device)
294 char usb_ret[4];
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);
308 printf(" OK\n");
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;
317 attr1.delay = 1000;
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;
327 attr2.delay = 1000;
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();
342 get_cpu(device);
343 get_cpu(device);
344 send_file(device, &img1);
346 printf("Wait a sec (literally)...");
347 sleep(1);
348 printf(" OK\n");
350 clear_status(device);
351 get_cpu(device);
352 send_file(device, &img2);
353 dfu_detach(device);
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;
363 attr1.delay = 1000;
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;
373 attr2.delay = 1000;
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);
387 get_cpu(device);
388 get_cpu(device);
389 send_file(device, &img1);
391 printf("Wait a sec (literally)...");
392 sleep(1);
393 printf(" OK\n");
394 usb_dev_close(device);
396 device = usb_dev_open(USB_VID_SAMSUNG, USB_PID_M6SL);
397 get_cpu(device);
398 get_cpu(device);
399 send_file(device, &img2);
400 dfu_detach(device);
401 usb_dev_close(device);
405 int main(int argc, char **argv)
407 if (argc != 4)
408 usage();
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]);
418 else
419 usage();
421 return 0;