cleanups by William Poetra Yoga Hadisoeseno
[kugel-rb.git] / utils / meizu_dfu / meizu_dfu.c
blobb7b1c43ef78501a758da6dc14b1bbf93c77a6fcc
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 */
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>
17 #include <usb.h>
19 void usage()
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);
27 uint32_t crc32(char *data, int len, uint32_t poly, uint32_t init)
29 uint32_t crc_table[256];
30 uint32_t crc, t;
31 int i, j;
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;
44 // calculate the crc
45 crc = init;
46 for (i = 0; i < len; ++i)
47 crc = (crc >> 8) ^ crc_table[(crc^data[i]) & 0xff];
49 return crc;
52 typedef struct {
53 char *name;
54 char *data;
55 int len;
56 } image_data_t;
58 typedef struct {
59 int delay;
60 int pre_off;
61 uint32_t pre_sig;
62 uint16_t suf_dev;
63 uint16_t suf_prod;
64 uint16_t suf_ven;
65 uint16_t suf_dfu;
66 char suf_sig[3];
67 uint8_t suf_len;
68 } image_attr_t;
70 #define BLOCK_SIZE 2048
71 #define DFU_TIMEOUT 0xa000
72 #define DFU_CRC_POLY 0xedb88320
73 #define DFU_INIT_CRC 0xffffffff
75 #define USB_VID_SAMSUNG 0x0419
76 #define USB_PID_M6SL 0x0145
77 #define USB_PID_M3_M6 0x0141
79 void init_img(image_data_t *img, const char *filename, image_attr_t *attr)
81 int fd, len, i, readlen;
82 struct stat statbuf;
83 char buf[BLOCK_SIZE];
84 uint32_t dfu_crc;
86 printf("Reading %s...", filename);
88 stat(filename, &statbuf);
89 len = statbuf.st_size;
91 img->name = basename(strdup(filename));
92 img->data = malloc(len + 16);
93 img->len = len + 16;
95 fd = open(filename, O_RDONLY);
96 for (i = 0; i < len; i += BLOCK_SIZE) {
97 readlen = ((len - i) < BLOCK_SIZE) ? (len - i) : BLOCK_SIZE;
98 read(fd, buf, readlen);
99 memcpy(img->data + i, buf, readlen);
101 close(fd);
103 // patch the data size in after the signature
104 memcpy(img->data + attr->pre_off + 4, &img->len, 4);
106 // append the suffix (excluding the checksum)
107 memcpy(img->data + len, &attr->suf_dev, 2);
108 memcpy(img->data + len + 2, &attr->suf_prod, 2);
109 memcpy(img->data + len + 4, &attr->suf_ven, 2);
110 memcpy(img->data + len + 6, &attr->suf_dfu, 2);
111 memcpy(img->data + len + 8, &attr->suf_sig, 3);
112 memcpy(img->data + len + 11, &attr->suf_len, 1);
114 dfu_crc = crc32(img->data, len + 12, DFU_CRC_POLY, DFU_INIT_CRC);
115 memcpy(img->data + len + 12, &dfu_crc, 4);
117 #if 0
118 FILE *f = fopen(img->name, "w");
119 fwrite(img->data, len + 16, 1, f);
120 fclose(f);
121 #endif
123 printf("OK\n");
126 usb_dev_handle *usb_dev_open(uint16_t dfu_vid, uint16_t dfu_pid)
128 struct usb_bus *bus;
129 struct usb_device *dev;
130 usb_dev_handle *device;
132 printf("USB initialization...");
134 usb_init();
135 usb_find_busses();
136 usb_find_devices();
138 for (bus = usb_get_busses(); bus != NULL; bus = bus->next)
139 for (dev = bus->devices; dev != NULL; dev = dev->next)
140 if (dev->descriptor.idVendor == dfu_vid
141 && dev->descriptor.idProduct == dfu_pid)
142 goto found;
144 printf("\nNo device found, exiting.\n");
145 exit(1);
147 found:
148 printf(" Device found.\n");
149 device = usb_open(dev);
150 usb_claim_interface(device, 0);
151 return device;
154 void usb_mimic_windows(usb_dev_handle *device)
156 char data[1024];
158 usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, DFU_TIMEOUT);
159 usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0009, DFU_TIMEOUT);
160 usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x001b, DFU_TIMEOUT);
161 usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0040, DFU_TIMEOUT);
162 usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, DFU_TIMEOUT);
163 usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0009, DFU_TIMEOUT);
164 usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, DFU_TIMEOUT);
165 usb_control_msg(device, 0x80, 0x06, 0x0303, 0x0409, data, 0x00ff, DFU_TIMEOUT);
166 usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x00ff, DFU_TIMEOUT);
167 usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, DFU_TIMEOUT);
168 usb_control_msg(device, 0x80, 0x06, 0x0302, 0x0409, data, 0x00ff, DFU_TIMEOUT);
169 usb_control_msg(device, 0x80, 0x06, 0x0300, 0x0000, data, 0x00ff, DFU_TIMEOUT);
170 usb_control_msg(device, 0x80, 0x06, 0x0302, 0x0409, data, 0x00ff, DFU_TIMEOUT);
171 usb_control_msg(device, 0x80, 0x06, 0x0100, 0x0000, data, 0x0012, DFU_TIMEOUT);
172 usb_control_msg(device, 0x80, 0x06, 0x0200, 0x0000, data, 0x0209, DFU_TIMEOUT);
175 void usb_dev_close(usb_dev_handle *device)
177 printf("Releasing interface...");
179 usb_release_interface(device, 0);
181 printf(" OK\n");
184 enum DFU_REQUEST {
185 DFU_DETACH = 0,
186 DFU_DOWNLOAD,
187 DFU_UPLOAD,
188 DFU_GETSTATUS,
189 DFU_CLRSTATUS,
190 DFU_GETSTATE,
191 DFU_ABORT
194 void get_cpu(usb_dev_handle *device)
196 char data[64];
197 int req_out_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
198 int len;
200 printf("GET CPU");
202 // check for "S5L8700 Rev.1"
203 len = usb_control_msg(device, req_out_if, 0xff, 0x0002, 0, data, 0x003f, DFU_TIMEOUT);
204 if (len < 0) {
205 printf("\nError trying to get CPU model, exiting.\n");
206 exit(1);
209 memset(data + len, 0, 64 - len);
210 printf(", got: %s\n", data);
213 void send_file(usb_dev_handle *device, image_data_t *img)
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;
221 printf("Sending %s... ", img->name);
223 len = img->len;
224 data = img->data;
226 // loop for the file
227 for (i = 0, idx = 0; i < len; i += BLOCK_SIZE, ++idx) {
228 writelen = ((len - i) < BLOCK_SIZE) ? (len - i) : BLOCK_SIZE;
229 usb_control_msg(device, req_out_if, DFU_DOWNLOAD, idx, 0, data + i, writelen, DFU_TIMEOUT);
230 dfu_ret[4] = 0x00;
231 while (dfu_ret[4] != 0x05)
232 usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, DFU_TIMEOUT);
233 printf("#");
236 usb_control_msg(device, req_out_if, DFU_DOWNLOAD, idx, 0, NULL, 0, DFU_TIMEOUT);
237 dfu_ret[4] = 0x00;
238 while (dfu_ret[4] != 0x07)
239 usb_control_msg(device, req_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, DFU_TIMEOUT);
241 printf(" OK\n");
244 void clear_status(usb_dev_handle *device)
246 char dfu_ret[6];
247 int usb_in_if = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
248 int usb_out_if = USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
250 printf("Clearing status...");
252 dfu_ret[4] = 0x00;
253 while (dfu_ret[4] != 0x08)
254 usb_control_msg(device, usb_in_if, DFU_GETSTATUS, 0, 0, dfu_ret, 6, DFU_TIMEOUT);
255 usb_control_msg(device, usb_out_if, DFU_CLRSTATUS, 0, 0, NULL, 0, DFU_TIMEOUT);
257 printf(" OK\n");
260 void dfu_detach(usb_dev_handle *device)
262 char usb_ret[4];
263 int usb_in_oth = USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
264 int usb_out_oth = USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
266 printf("Detaching...");
268 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
269 usb_control_msg(device, usb_out_oth, DFU_DOWNLOAD, 0x0010, 3, NULL, 0, DFU_TIMEOUT);
270 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
271 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
272 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
273 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
274 usb_control_msg(device, usb_in_oth, DFU_DETACH, 0x0000, 3, usb_ret, 4, DFU_TIMEOUT);
276 printf(" OK\n");
279 void dfu_m3_m6(char *file1, char *file2)
281 image_data_t img1, img2;
282 image_attr_t attr1, attr2;
283 usb_dev_handle *device;
285 attr1.delay = 1000;
286 attr1.pre_off = 0x20;
287 attr1.pre_sig = 0x44465543;
288 attr1.suf_dev = 0x0100;
289 attr1.suf_prod = 0x0140;
290 attr1.suf_ven = 0x0419;
291 attr1.suf_dfu = 0x0100;
292 memcpy(attr1.suf_sig, "RON", 3);
293 attr1.suf_len = 0x10;
295 attr2.delay = 1000;
296 attr2.pre_off = 0x20;
297 attr2.pre_sig = 0x44465543;
298 attr2.suf_dev = 0x0100;
299 attr2.suf_prod = 0x0140;
300 attr2.suf_ven = 0x0419;
301 attr2.suf_dfu = 0x0100;
302 memcpy(attr2.suf_sig, "UFD", 3);
303 attr2.suf_len = 0x10;
305 init_img(&img1, file1, &attr1);
306 init_img(&img2, file2, &attr2);
308 device = usb_dev_open(USB_VID_SAMSUNG, USB_PID_M3_M6);
309 // usb_mimic_windows();
310 get_cpu(device);
311 get_cpu(device);
312 send_file(device, &img1);
314 printf("Wait a sec (literally)...");
315 sleep(1);
316 printf(" OK\n");
318 clear_status(device);
319 get_cpu(device);
320 send_file(device, &img2);
321 dfu_detach(device);
322 usb_dev_close(device);
325 void dfu_m6sl(char *file1, char *file2)
327 image_data_t img1, img2;
328 image_attr_t attr1, attr2;
329 usb_dev_handle *device;
331 attr1.delay = 1000;
332 attr1.pre_off = 0x20;
333 attr1.pre_sig = 0x44465543;
334 attr1.suf_dev = 0x0100;
335 attr1.suf_prod = 0x0140;
336 attr1.suf_ven = 0x0419;
337 attr1.suf_dfu = 0x0100;
338 memcpy(attr1.suf_sig, "UFD", 3);
339 attr1.suf_len = 0x10;
341 attr2.delay = 1000;
342 attr2.pre_off = 0x20;
343 attr2.pre_sig = 0x44465543;
344 attr2.suf_dev = 0x0100;
345 attr2.suf_prod = 0x0140;
346 attr2.suf_ven = 0x0419;
347 attr2.suf_dfu = 0x0100;
348 memcpy(attr2.suf_sig, "UFD", 3);
349 attr2.suf_len = 0x10;
351 init_img(&img1, file1, &attr1);
352 init_img(&img2, file2, &attr2);
354 device = usb_dev_open(USB_VID_SAMSUNG, USB_PID_M6SL);
355 get_cpu(device);
356 get_cpu(device);
357 send_file(device, &img1);
359 printf("Wait a sec (literally)...");
360 sleep(1);
361 printf(" OK\n");
362 usb_dev_close(device);
364 device = usb_dev_open(USB_VID_SAMSUNG, USB_PID_M6SL);
365 get_cpu(device);
366 get_cpu(device);
367 send_file(device, &img2);
368 dfu_detach(device);
369 usb_dev_close(device);
373 int main(int argc, char **argv)
375 if (argc != 4)
376 usage();
378 setvbuf(stdout, NULL, _IONBF, 0);
380 if (!strcmp(argv[1], "m3"))
381 dfu_m3_m6(argv[2], argv[3]);
382 else if (!strcmp(argv[1], "m6"))
383 dfu_m3_m6(argv[2], argv[3]);
384 else if (!strcmp(argv[1], "m6sl"))
385 dfu_m6sl(argv[2], argv[3]);
386 else
387 usage();
389 return 0;