baaf865c |
1 | /* FIXME: RAM odd */ |
8c8e818c |
2 | #include <stdio.h> |
726b85c8 |
3 | #include <string.h> |
8c8e818c |
4 | #include <usb.h> |
5 | |
6 | |
7 | typedef unsigned char u8; |
8 | typedef unsigned short u16; |
9 | typedef unsigned int u32; |
10 | #define array_size(x) (sizeof(x) / sizeof(x[0])) |
11 | |
12 | static const struct { |
13 | unsigned short vendor; |
14 | unsigned short product; |
15 | const char *name; |
16 | } g_devices[] = { |
17 | { 0x03eb, 0x202a, "16MX+U Game Device" }, |
18 | { 0x03eb, 0x202b, "32MX+U Game Device" }, |
19 | { 0x03eb, 0x202c, "16MX+US Game Device" }, |
20 | { 0x03eb, 0x202d, "32MX+UF Game Device" }, |
21 | }; |
22 | |
ed354cee |
23 | #define VERSION "0.8" |
24 | |
25 | #define IO_BLK_SIZE 0x2000 /* 8K */ |
c9d375d5 |
26 | #define IO_RAM_BLK_SIZE 256 |
8c8e818c |
27 | |
fb4ee110 |
28 | #define CMD_ATM_READY 0x22 |
a35471cd |
29 | #define CMD_SEC_GET_NAME 'G' /* filename r/w */ |
30 | #define CMD_SEC_PUT_NAME 'P' |
31 | #define CMD_SEC_DEVID 'L' /* read flash device ID */ |
32 | #define CMD_SEC_ERASE 'E' |
33 | #define CMD_SEC_READY 'C' /* is flash ready? */ |
6ddaf67a |
34 | #define CMD_SEC_READ 'R' |
ed354cee |
35 | #define CMD_SEC_WRITE 'W' |
baaf865c |
36 | #define CMD_SEC_RAM_READ 'D' /* not implemented? */ |
c9d375d5 |
37 | #define CMD_SEC_RAM_WRITE 'U' |
baaf865c |
38 | #define CMD_SEC_COMPAT '$' /* set RAM mode */ |
726b85c8 |
39 | |
fb4ee110 |
40 | /* bus controllers */ |
41 | #define CTL_DATA_BUS 0x55 |
42 | #define CTL_ADDR_BUS 0xAA |
43 | |
a35471cd |
44 | #define W_COUNTER 0xA0 |
45 | #define W_CNT_WRITE 0x01 |
46 | #define W_CNT_READ 0x00 |
47 | |
fb4ee110 |
48 | #define FILENAME_ROM0 0 |
49 | #define FILENAME_ROM1 1 |
50 | #define FILENAME_RAM 2 |
726b85c8 |
51 | |
baaf865c |
52 | /* windows app sets to 0x80 on init |
53 | * checkboxes use 0x41 0x42 0x43 (?) |
54 | * r,w Ram/ROM uses 0x23/0x21 |
55 | */ |
95122097 |
56 | #define C_MODE_4M_NORAM 0x41 /* RAM always off */ |
57 | #define C_MODE_4M_RAM 0x42 /* RAM switched by game */ |
58 | #define C_MODE_2M_RAM 0x43 |
92cfb386 |
59 | #define C_RAM_TMP_OFF 0x21 |
60 | #define C_RAM_TMP_ON 0x23 |
baaf865c |
61 | |
726b85c8 |
62 | typedef struct { |
8c8e818c |
63 | u8 magic[4]; |
a35471cd |
64 | u8 reserved[8]; |
65 | u8 write_flag; |
66 | u8 reserved2[2]; |
8c8e818c |
67 | u8 magic2; |
68 | u8 mx_cmd; |
6ddaf67a |
69 | union { /* 0x11 */ |
8c8e818c |
70 | struct { |
71 | u8 which_device; |
8c8e818c |
72 | } dev_info; |
73 | struct { |
ed354cee |
74 | u8 addrb2; /* most significant (BE) */ |
8c8e818c |
75 | u8 addrb1; |
76 | u8 addrb0; |
ed354cee |
77 | u8 param; /* 64 byte usb packets for i/o */ |
78 | u8 param2; |
8c8e818c |
79 | } rom_rw; |
80 | struct { |
fb4ee110 |
81 | u8 which; |
baaf865c |
82 | } filename, mode; |
8c8e818c |
83 | struct { |
a35471cd |
84 | u8 cmd; |
8c8e818c |
85 | u8 action; |
ed354cee |
86 | u8 b0; /* LE */ |
a35471cd |
87 | u8 b1; |
88 | u8 b2; |
89 | u8 b3; |
90 | } write_cnt; |
91 | struct { |
92 | u8 which; |
93 | u8 dev_id; |
94 | } rom_id; |
8c8e818c |
95 | }; |
96 | u8 pad[8]; |
726b85c8 |
97 | } dev_cmd_t; |
98 | |
99 | typedef struct { |
100 | u8 firmware_ver[4]; |
101 | u8 bootloader_ver[4]; |
102 | char names[56]; |
103 | } dev_info_t; |
104 | |
a35471cd |
105 | typedef struct { |
106 | u32 start_addr; |
107 | u32 end_addr; |
108 | u32 page_size; |
109 | } page_table_t; |
110 | |
111 | static const page_table_t p_AM29LV320DB[] = |
112 | { |
113 | { 0x000000, 0x00ffff, 0x002000 }, |
114 | { 0x010000, 0x3fffff, 0x010000 }, |
115 | { 0x000000, 0x000000, 0x000000 }, |
116 | }; |
117 | |
118 | static const page_table_t p_AM29LV320DT[] = |
119 | { |
120 | { 0x000000, 0x3effff, 0x010000 }, |
121 | { 0x3f0000, 0x3fffff, 0x002000 }, |
122 | { 0x000000, 0x000000, 0x000000 }, |
123 | }; |
124 | |
6ddaf67a |
125 | static const page_table_t p_2x_16[] = |
126 | { |
127 | { 0x000000, 0x003fff, 0x004000 }, |
128 | { 0x004000, 0x007fff, 0x002000 }, |
129 | { 0x008000, 0x00ffff, 0x008000 }, |
130 | { 0x010000, 0x1fffff, 0x010000 }, |
131 | { 0x200000, 0x203fff, 0x004000 }, |
132 | { 0x204000, 0x207fff, 0x002000 }, |
133 | { 0x208000, 0x20ffff, 0x008000 }, |
134 | { 0x210000, 0x3fffff, 0x010000 }, |
135 | { 0x000000, 0x000000, 0x000000 }, |
136 | }; |
137 | |
a35471cd |
138 | /*****************************************************************************/ |
139 | |
726b85c8 |
140 | static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd) |
141 | { |
142 | memset(dev_cmd, 0, sizeof(*dev_cmd)); |
143 | |
144 | memcpy(dev_cmd->magic, "USBC", 4); |
fb4ee110 |
145 | dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */ |
726b85c8 |
146 | dev_cmd->mx_cmd = cmd; |
147 | } |
148 | |
a35471cd |
149 | static int write_data(struct usb_dev_handle *dev, void *data, int len) |
726b85c8 |
150 | { |
a35471cd |
151 | int ret = usb_bulk_write(dev, 0x03, data, len, 2000); |
726b85c8 |
152 | if (ret < 0) { |
153 | fprintf(stderr, "failed to write:\n"); |
154 | fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); |
a35471cd |
155 | } else if (ret != len) |
156 | printf("write_cmd: wrote only %d of %d bytes\n", ret, len); |
726b85c8 |
157 | |
158 | return ret; |
159 | } |
160 | |
a35471cd |
161 | static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd) |
162 | { |
163 | return write_data(dev, cmd, sizeof(*cmd)); |
164 | } |
165 | |
166 | static int read_data(struct usb_dev_handle *dev, void *buff, int size) |
726b85c8 |
167 | { |
168 | int ret = usb_bulk_read(dev, 0x82, buff, size, 2000); |
169 | if (ret < 0) { |
170 | fprintf(stderr, "failed to read:\n"); |
171 | fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); |
ed354cee |
172 | } |
173 | /* |
174 | else if (ret != size) |
a35471cd |
175 | printf("read_data: read only %d of %d bytes\n", ret, size); |
ed354cee |
176 | */ |
726b85c8 |
177 | return ret; |
178 | } |
8c8e818c |
179 | |
6ddaf67a |
180 | static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info) |
fb4ee110 |
181 | { |
182 | dev_cmd_t cmd; |
fb4ee110 |
183 | int ret; |
184 | |
185 | prepare_cmd(&cmd, CMD_ATM_READY); |
186 | cmd.dev_info.which_device = ctl_id; |
6ddaf67a |
187 | memset(info, 0, sizeof(*info)); |
fb4ee110 |
188 | |
189 | ret = write_cmd(device, &cmd); |
190 | if (ret < 0) |
191 | return ret; |
192 | |
6ddaf67a |
193 | ret = read_data(device, info, sizeof(*info)); |
fb4ee110 |
194 | if (ret < 0) |
195 | return ret; |
196 | |
fb4ee110 |
197 | return 0; |
198 | } |
199 | |
6ddaf67a |
200 | static void printf_info(dev_info_t *info) |
201 | { |
202 | printf(" firmware version: %X.%X.%X%c\n", info->firmware_ver[0], |
203 | info->firmware_ver[1], info->firmware_ver[2], info->firmware_ver[3]); |
204 | printf(" bootloader version: %X.%X.%X%c\n", info->bootloader_ver[0], |
205 | info->bootloader_ver[1], info->bootloader_ver[2], info->bootloader_ver[3]); |
206 | info->names[sizeof(info->names) - 1] = 0; |
207 | printf(" device name: %s\n", info->names); |
208 | } |
209 | |
210 | static void print_progress(u32 done, u32 total) |
211 | { |
212 | int i, step; |
213 | |
214 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); |
215 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */ |
216 | printf("\b\b\b\b\b\b"); |
217 | printf("%06x/%06x |", done, total); |
218 | |
219 | step = total / 20; |
220 | for (i = step; i <= total; i += step) |
221 | printf("%c", done >= i ? '=' : '-'); |
222 | printf("| %3d%%", done * 100 / total); |
223 | fflush(stdout); |
224 | } |
225 | |
a35471cd |
226 | static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which) |
fb4ee110 |
227 | { |
228 | char buff[65]; |
229 | dev_cmd_t cmd; |
230 | int ret; |
231 | |
232 | prepare_cmd(&cmd, CMD_SEC_GET_NAME); |
233 | cmd.filename.which = which; |
234 | memset(buff, 0, sizeof(buff)); |
235 | |
236 | ret = write_cmd(dev, &cmd); |
237 | if (ret < 0) |
238 | return ret; |
239 | |
a35471cd |
240 | ret = read_data(dev, buff, 64); |
fb4ee110 |
241 | if (ret < 0) |
242 | return ret; |
243 | |
244 | strncpy(dst, buff, len); |
245 | dst[len - 1] = 0; |
246 | |
247 | return 0; |
248 | } |
249 | |
a35471cd |
250 | static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which) |
251 | { |
252 | dev_cmd_t cmd; |
253 | char buff[64]; |
254 | int ret, len; |
255 | |
256 | len = strlen(fname); |
257 | if (len > 63) |
258 | len = 63; |
259 | strncpy(buff, fname, len); |
260 | buff[len] = 0; |
261 | |
262 | prepare_cmd(&cmd, CMD_SEC_PUT_NAME); |
263 | cmd.filename.which = which; |
264 | |
265 | ret = write_cmd(dev, &cmd); |
266 | if (ret < 0) |
267 | return ret; |
268 | |
269 | return write_data(dev, buff, len + 1); |
270 | } |
271 | |
ed354cee |
272 | static int read_erase_counter(struct usb_dev_handle *dev, u32 *val) |
a35471cd |
273 | { |
6ddaf67a |
274 | dev_info_t dummy_info; |
a35471cd |
275 | dev_cmd_t cmd; |
6ddaf67a |
276 | u8 buff[4]; |
a35471cd |
277 | int ret; |
278 | |
6ddaf67a |
279 | /* must perform dummy info read here, |
280 | * or else device hangs after close (firmware bug?) */ |
281 | ret = read_info(dev, CTL_DATA_BUS, &dummy_info); |
282 | if (ret < 0) |
283 | return ret; |
284 | |
a35471cd |
285 | prepare_cmd(&cmd, CMD_ATM_READY); |
286 | cmd.write_cnt.cmd = W_COUNTER; |
287 | cmd.write_cnt.action = W_CNT_READ; |
288 | |
289 | ret = write_cmd(dev, &cmd); |
290 | if (ret < 0) |
291 | return ret; |
292 | |
293 | ret = read_data(dev, buff, sizeof(buff)); |
294 | if (ret < 0) |
295 | return ret; |
6ddaf67a |
296 | |
a35471cd |
297 | *val = *(u32 *)buff; |
298 | return 0; |
299 | } |
300 | |
6ddaf67a |
301 | static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val) |
a35471cd |
302 | { |
303 | dev_cmd_t cmd; |
304 | u8 buff[2]; |
305 | int ret; |
306 | |
307 | prepare_cmd(&cmd, CMD_SEC_DEVID); |
6ddaf67a |
308 | cmd.rom_id.which = is_second ? 0x10 : 0; |
309 | cmd.rom_id.dev_id = 0; |
a35471cd |
310 | |
311 | ret = write_cmd(dev, &cmd); |
312 | if (ret < 0) |
313 | return ret; |
314 | |
315 | ret = read_data(dev, buff, sizeof(buff)); |
316 | if (ret < 0) |
317 | return ret; |
318 | |
319 | *val = *(u16 *)buff << 16; |
320 | |
6ddaf67a |
321 | cmd.rom_id.dev_id = 1; |
a35471cd |
322 | ret = write_cmd(dev, &cmd); |
323 | if (ret < 0) |
324 | return ret; |
325 | |
326 | ret = read_data(dev, buff, sizeof(buff)); |
327 | if (ret < 0) |
328 | return ret; |
329 | |
330 | *val |= *(u16 *)buff; |
331 | return 0; |
332 | } |
333 | |
334 | static const page_table_t *get_page_table(u32 rom_id) |
335 | { |
336 | switch (rom_id) { |
337 | case 0x0100F922: |
338 | return p_AM29LV320DB; |
339 | case 0x0100F422: |
340 | return p_AM29LV320DT; |
6ddaf67a |
341 | case 0x01004922: |
342 | case 0xC2004922: |
343 | return p_2x_16; |
a35471cd |
344 | default: |
345 | fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id); |
346 | } |
347 | |
348 | return NULL; |
349 | } |
350 | |
351 | static int get_page_size(const page_table_t *table, u32 addr, u32 *size) |
352 | { |
353 | const page_table_t *t; |
354 | |
355 | for (t = table; t->end_addr != 0; t++) { |
356 | if (addr >= t->start_addr && addr <= t->end_addr) { |
357 | *size = t->page_size; |
358 | return 0; |
359 | } |
360 | } |
361 | |
362 | if (addr == t[-1].end_addr + 1) |
ed354cee |
363 | return 1; /* no more */ |
a35471cd |
364 | |
365 | fprintf(stderr, "get_page_size: failed on addr %06x\n", addr); |
366 | return -1; |
367 | } |
368 | |
baaf865c |
369 | static int set_ram_mode(struct usb_dev_handle *dev, u8 mode) |
370 | { |
371 | dev_cmd_t cmd; |
372 | u8 buff[2]; |
373 | int ret; |
374 | |
375 | prepare_cmd(&cmd, CMD_SEC_COMPAT); |
376 | cmd.write_flag = 1; |
377 | cmd.mode.which = mode; |
378 | |
379 | ret = write_cmd(dev, &cmd); |
380 | if (ret < 0) |
381 | goto end; |
382 | |
383 | ret = read_data(dev, buff, sizeof(buff)); |
384 | |
385 | end: |
386 | if (ret < 0) |
387 | fprintf(stderr, "warning: failed to set RAM mode\n"); |
388 | return ret; |
389 | } |
390 | |
ed354cee |
391 | /* limitations: |
392 | * - bytes must be multiple of 64 |
393 | * - bytes must be less than 16k |
394 | * - must perform even number of reads, or dev hangs on exit (firmware bug?) */ |
c9d375d5 |
395 | static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd) |
ed354cee |
396 | { |
397 | dev_cmd_t cmd; |
398 | int ret; |
399 | |
c9d375d5 |
400 | prepare_cmd(&cmd, mx_cmd); |
401 | if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) |
402 | cmd.write_flag = 1; |
ed354cee |
403 | cmd.rom_rw.addrb2 = addr >> (16 + 1); |
404 | cmd.rom_rw.addrb1 = addr >> (8 + 1); |
405 | cmd.rom_rw.addrb0 = addr >> 1; |
406 | cmd.rom_rw.param = bytes / 64; |
c9d375d5 |
407 | if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) |
408 | cmd.rom_rw.param2 = 1; /* ? */ |
ed354cee |
409 | |
410 | ret = write_cmd(dev, &cmd); |
411 | if (ret < 0) |
412 | return ret; |
413 | |
414 | bytes &= ~63; |
415 | |
c9d375d5 |
416 | if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) |
ed354cee |
417 | ret = write_data(dev, buffer, bytes); |
418 | else |
419 | ret = read_data(dev, buffer, bytes); |
420 | if (ret < 0) |
421 | return ret; |
422 | |
423 | if (ret != bytes) |
c9d375d5 |
424 | fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes); |
ed354cee |
425 | |
426 | return ret; |
427 | } |
428 | |
429 | static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write) |
430 | { |
c9d375d5 |
431 | int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ; |
ed354cee |
432 | int total_bytes = bytes; |
433 | u8 *buff = buffer; |
434 | u8 dummy[64 * 4]; |
435 | int count, ret; |
436 | |
437 | if (addr & 1) |
438 | fprintf(stderr, "read_write_rom: can't handle odd address %06x, " |
439 | "LSb will be ignored\n", addr); |
440 | if (bytes & 63) |
441 | fprintf(stderr, "read_write_rom: byte count must be multiple of 64, " |
442 | "last %d bytes will not be handled\n", bytes & 63); |
443 | |
92cfb386 |
444 | set_ram_mode(dev, C_RAM_TMP_OFF); |
baaf865c |
445 | |
ed354cee |
446 | printf("%s flash ROM...\n", is_write ? "writing to" : "reading"); |
447 | |
448 | /* do i/o in blocks */ |
449 | for (count = 0; bytes >= IO_BLK_SIZE; count++) { |
450 | print_progress(buff - (u8 *)buffer, total_bytes); |
451 | |
c9d375d5 |
452 | ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd); |
ed354cee |
453 | if (ret < 0) |
454 | return ret; |
455 | buff += IO_BLK_SIZE; |
456 | addr += IO_BLK_SIZE; |
457 | bytes -= IO_BLK_SIZE; |
458 | } |
459 | print_progress(buff - (u8 *)buffer, total_bytes); |
460 | |
461 | ret = 0; |
462 | if (bytes != 0) { |
c9d375d5 |
463 | ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd); |
ed354cee |
464 | count++; |
465 | print_progress(total_bytes, total_bytes); |
466 | } |
467 | |
468 | if (count & 1) |
c9d375d5 |
469 | /* work around rw_dev_block() limitation 3 (works for reads only?) */ |
470 | rw_dev_block(dev, 0, dummy, sizeof(dummy), 0); |
ed354cee |
471 | |
472 | printf("\n"); |
473 | return ret; |
474 | } |
475 | |
c9d375d5 |
476 | static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write) |
477 | { |
baaf865c |
478 | int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ; |
c9d375d5 |
479 | int total_bytes = bytes; |
480 | u8 *buff = buffer; |
481 | u32 addr = 0x200000; |
92cfb386 |
482 | int i, ret = 0; |
c9d375d5 |
483 | |
484 | if (bytes % IO_RAM_BLK_SIZE) |
485 | fprintf(stderr, "read_write_ram: byte count must be multiple of %d, " |
486 | "last %d bytes will not be handled\n", IO_RAM_BLK_SIZE, |
487 | bytes % IO_RAM_BLK_SIZE); |
488 | |
92cfb386 |
489 | set_ram_mode(dev, C_RAM_TMP_ON); |
baaf865c |
490 | |
c9d375d5 |
491 | printf("%s RAM...\n", is_write ? "writing to" : "reading"); |
492 | |
493 | /* do i/o in blocks */ |
494 | while (bytes >= IO_RAM_BLK_SIZE) { |
495 | print_progress(buff - (u8 *)buffer, total_bytes); |
496 | |
497 | ret = rw_dev_block(dev, addr, buff, IO_RAM_BLK_SIZE, mx_cmd); |
498 | if (ret < 0) |
499 | return ret; |
500 | buff += IO_RAM_BLK_SIZE; |
501 | addr += IO_RAM_BLK_SIZE; |
502 | bytes -= IO_RAM_BLK_SIZE; |
503 | } |
504 | print_progress(buff - (u8 *)buffer, total_bytes); |
505 | |
92cfb386 |
506 | /* only D0-D7 connected.. */ |
507 | for (i = 0; i < total_bytes; i += 2) |
508 | ((u8 *)buffer)[i] = 0; |
509 | |
c9d375d5 |
510 | printf("\n"); |
511 | return ret; |
512 | |
513 | } |
514 | |
ed354cee |
515 | static int increment_erase_cnt(struct usb_dev_handle *dev) |
516 | { |
517 | dev_cmd_t cmd; |
518 | u8 buff[4]; |
519 | u32 cnt; |
520 | int ret; |
521 | |
522 | ret = read_erase_counter(dev, &cnt); |
523 | if (ret != 0) |
524 | return ret; |
525 | |
526 | if (cnt == (u32)-1) { |
527 | fprintf(stderr, "flash erase counter maxed out!\n"); |
528 | fprintf(stderr, "(wow, did you really erase so many times?)\n"); |
529 | return -1; |
530 | } |
531 | |
532 | cnt++; |
533 | |
534 | prepare_cmd(&cmd, CMD_ATM_READY); |
535 | cmd.write_cnt.cmd = W_COUNTER; |
536 | cmd.write_cnt.action = W_CNT_WRITE; |
537 | cmd.write_cnt.b3 = cnt >> 24; |
538 | cmd.write_cnt.b2 = cnt >> 16; |
539 | cmd.write_cnt.b1 = cnt >> 8; |
540 | cmd.write_cnt.b0 = cnt; |
541 | |
542 | ret = write_cmd(dev, &cmd); |
543 | if (ret < 0) |
544 | return ret; |
545 | |
546 | ret = read_data(dev, buff, sizeof(buff)); |
547 | if (ret < 0) |
548 | return ret; |
549 | |
92cfb386 |
550 | return cnt; |
ed354cee |
551 | } |
552 | |
553 | static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole) |
a35471cd |
554 | { |
555 | dev_cmd_t cmd; |
ed354cee |
556 | u8 buff[5]; |
a35471cd |
557 | int i, ret; |
558 | |
559 | prepare_cmd(&cmd, CMD_SEC_ERASE); |
560 | cmd.write_flag = 1; |
ed354cee |
561 | cmd.rom_rw.addrb2 = addr >> (16 + 1); |
562 | cmd.rom_rw.addrb1 = addr >> (8 + 1); |
563 | cmd.rom_rw.addrb0 = addr >> 1; |
564 | cmd.rom_rw.param = whole ? 0x10 : 0; |
a35471cd |
565 | |
566 | ret = write_cmd(dev, &cmd); |
567 | if (ret < 0) |
568 | return ret; |
569 | |
570 | ret = read_data(dev, buff, sizeof(buff)); |
571 | if (ret < 0) |
572 | return ret; |
573 | |
574 | prepare_cmd(&cmd, CMD_SEC_READY); |
ed354cee |
575 | cmd.rom_rw.addrb2 = addr >> (16 + 1); |
576 | cmd.rom_rw.addrb1 = addr >> (8 + 1); |
577 | cmd.rom_rw.addrb0 = addr >> 1; |
a35471cd |
578 | |
579 | for (i = 0; i < 100; i++) { |
580 | ret = write_cmd(dev, &cmd); |
581 | if (ret < 0) |
582 | return ret; |
583 | |
584 | ret = read_data(dev, buff, sizeof(buff)); |
585 | if (ret < 0) |
586 | return ret; |
587 | |
588 | if (ret > 4 && buff[4] == 1) |
589 | break; |
590 | |
ed354cee |
591 | usleep((whole ? 600 : 20) * 1000); |
592 | } |
593 | |
594 | if (i == 100) { |
595 | fprintf(stderr, "\ntimeout waiting for erase to complete\n"); |
596 | return -1; |
a35471cd |
597 | } |
598 | |
a35471cd |
599 | return 0; |
600 | } |
601 | |
ed354cee |
602 | static int erase_seq(struct usb_dev_handle *dev, u32 size) |
6ddaf67a |
603 | { |
ed354cee |
604 | const page_table_t *table; |
605 | u32 addr, page_size = 0; |
606 | u32 rom0_id, rom1_id; |
607 | int count, ret; |
6ddaf67a |
608 | |
ed354cee |
609 | ret = read_flash_rom_id(dev, 0, &rom0_id); |
6ddaf67a |
610 | if (ret < 0) |
611 | return ret; |
612 | |
ed354cee |
613 | ret = read_flash_rom_id(dev, 1, &rom1_id); |
6ddaf67a |
614 | if (ret < 0) |
615 | return ret; |
6ddaf67a |
616 | |
ed354cee |
617 | if (rom0_id != rom1_id) |
618 | fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n", |
619 | rom0_id, rom1_id); |
6ddaf67a |
620 | |
ed354cee |
621 | table = get_page_table(rom0_id); |
622 | if (table == NULL) |
623 | return -1; |
6ddaf67a |
624 | |
ed354cee |
625 | ret = increment_erase_cnt(dev); |
92cfb386 |
626 | if (ret < 0) |
ed354cee |
627 | fprintf(stderr, "warning: coun't increase erase counter\n"); |
6ddaf67a |
628 | |
92cfb386 |
629 | printf("erasing flash... (erase count=%u)\n", ret); |
630 | |
ed354cee |
631 | for (addr = 0, count = 0; addr < size; addr += page_size, count++) { |
632 | print_progress(addr, size); |
6ddaf67a |
633 | |
ed354cee |
634 | ret = erase_page(dev, addr, 0); |
6ddaf67a |
635 | if (ret < 0) |
636 | return ret; |
6ddaf67a |
637 | |
ed354cee |
638 | ret = get_page_size(table, addr, &page_size); |
639 | if (ret != 0) |
640 | break; |
6ddaf67a |
641 | } |
642 | |
643 | if (count & 1) |
ed354cee |
644 | /* ??? */ |
645 | /* must submit even number of erase commands (fw bug?) */ |
646 | erase_page(dev, 0, 0); |
6ddaf67a |
647 | |
ed354cee |
648 | print_progress(addr, size); |
6ddaf67a |
649 | printf("\n"); |
ed354cee |
650 | |
651 | return ret; |
652 | } |
653 | |
654 | static int erase_all(struct usb_dev_handle *dev, u32 size) |
655 | { |
656 | int ret; |
657 | |
ed354cee |
658 | ret = increment_erase_cnt(dev); |
92cfb386 |
659 | if (ret < 0) |
ed354cee |
660 | fprintf(stderr, "warning: couldn't increase erase counter\n"); |
661 | |
92cfb386 |
662 | printf("erasing flash0, count=%u ...", ret); |
663 | fflush(stdout); |
664 | |
ed354cee |
665 | ret = erase_page(dev, 0xaaa, 1); |
666 | if (ret != 0) |
667 | return ret; |
668 | |
669 | if (size > 0x200000) { |
670 | printf(" done.\n"); |
671 | printf("erasing flash1..."); |
672 | fflush(stdout); |
673 | |
674 | ret = erase_page(dev, 0x200aaa, 1); |
675 | } |
676 | |
677 | printf(" done.\n"); |
6ddaf67a |
678 | return ret; |
679 | } |
680 | |
ed354cee |
681 | static int print_device_info(struct usb_dev_handle *dev) |
682 | { |
683 | u32 counter, rom0_id, rom1_id; |
684 | dev_info_t info; |
685 | int ret; |
686 | |
687 | printf("data bus controller:\n"); |
688 | ret = read_info(dev, CTL_DATA_BUS, &info); |
689 | if (ret < 0) |
690 | return ret; |
691 | printf_info(&info); |
692 | |
693 | printf("address bus controller:\n"); |
694 | ret = read_info(dev, CTL_ADDR_BUS, &info); |
695 | if (ret < 0) |
696 | return ret; |
697 | printf_info(&info); |
698 | |
699 | ret = read_erase_counter(dev, &counter); |
700 | if (ret < 0) |
701 | return ret; |
702 | printf("flash erase count: %u\n", counter); |
703 | |
704 | ret = read_flash_rom_id(dev, 0, &rom0_id); |
705 | if (ret < 0) |
706 | return ret; |
707 | printf("flash rom0 id: %08x\n", rom0_id); |
708 | |
709 | ret = read_flash_rom_id(dev, 1, &rom1_id); |
710 | if (ret < 0) |
711 | return ret; |
712 | printf("flash rom1 id: %08x\n", rom1_id); |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static int print_game_info(struct usb_dev_handle *dev) |
718 | { |
719 | char fname[65]; |
720 | int ret; |
721 | |
722 | ret = read_filename(dev, fname, sizeof(fname), FILENAME_ROM0); |
723 | if (ret < 0) |
724 | return ret; |
725 | printf("ROM filename: %s\n", fname); |
726 | |
727 | ret = read_filename(dev, fname, sizeof(fname), FILENAME_RAM); |
728 | if (ret < 0) |
729 | return ret; |
730 | printf("SRAM filename: %s\n", fname); |
731 | |
732 | return 0; |
733 | } |
734 | |
c9d375d5 |
735 | static int read_file(const char *fname, void **buff_out, int *size, int limit) |
736 | { |
737 | int file_size, ret; |
738 | void *data; |
739 | FILE *file; |
740 | |
741 | file = fopen(fname, "rb"); |
742 | if (file == NULL) { |
743 | fprintf(stderr, "can't open file: %s\n", fname); |
744 | return -1; |
745 | } |
746 | |
747 | fseek(file, 0, SEEK_END); |
748 | file_size = ftell(file); |
749 | fseek(file, 0, SEEK_SET); |
750 | if (file_size > limit) |
751 | fprintf(stderr, "warning: input file \"%s\" too large\n", fname); |
752 | if (file_size < 0) { |
753 | fprintf(stderr, "bad/empty file: %s\n", fname); |
754 | goto fail; |
755 | } |
756 | |
757 | data = malloc(file_size); |
758 | if (data == NULL) { |
759 | fprintf(stderr, "low memory\n"); |
760 | goto fail; |
761 | } |
762 | |
763 | ret = fread(data, 1, file_size, file); |
764 | if (ret != file_size) { |
baaf865c |
765 | fprintf(stderr, "failed to read file: %s", fname); |
766 | perror(""); |
c9d375d5 |
767 | goto fail; |
768 | } |
769 | |
770 | *buff_out = data; |
771 | *size = file_size; |
772 | fclose(file); |
773 | return 0; |
774 | |
775 | fail: |
776 | fclose(file); |
777 | return -1; |
778 | } |
779 | |
780 | static int write_file(const char *fname, void *buff, int size) |
781 | { |
782 | FILE *file; |
783 | int ret; |
784 | |
785 | file = fopen(fname, "wb"); |
786 | if (file == NULL) { |
787 | fprintf(stderr, "can't open for writing: %s\n", fname); |
788 | return -1; |
789 | } |
790 | |
baaf865c |
791 | ret = fwrite(buff, 1, size, file); |
792 | if (ret != size) { |
793 | fprintf(stderr, "write failed to %s", fname); |
794 | perror(""); |
795 | } else |
92cfb386 |
796 | printf("saved to \"%s\".\n", fname); |
baaf865c |
797 | fclose(file); |
c9d375d5 |
798 | |
799 | return 0; |
800 | } |
801 | |
8c8e818c |
802 | static usb_dev_handle *get_device(void) |
803 | { |
804 | struct usb_dev_handle *handle; |
805 | struct usb_device *dev; |
806 | struct usb_bus *bus; |
807 | int i, ret; |
808 | |
809 | ret = usb_find_busses(); |
810 | if (ret <= 0) { |
811 | fprintf(stderr, "Can't find USB busses\n"); |
812 | return NULL; |
813 | } |
814 | |
815 | ret = usb_find_devices(); |
816 | if (ret <= 0) { |
817 | fprintf(stderr, "Can't find USB devices\n"); |
818 | return NULL; |
819 | } |
820 | |
821 | bus = usb_get_busses(); |
822 | for (; bus; bus = bus->next) |
823 | { |
824 | for (dev = bus->devices; dev; dev = dev->next) |
825 | { |
826 | for (i = 0; i < array_size(g_devices); i++) |
827 | { |
828 | if (dev->descriptor.idVendor == g_devices[i].vendor && |
829 | dev->descriptor.idProduct == g_devices[i].product) |
830 | goto found; |
831 | } |
832 | } |
833 | } |
834 | |
835 | fprintf(stderr, "device not found.\n"); |
836 | return NULL; |
837 | |
838 | found: |
839 | printf("found %s.\n", g_devices[i].name); |
840 | |
841 | handle = usb_open(dev); |
842 | if (handle == NULL) { |
843 | fprintf(stderr, "failed to open device:\n"); |
844 | fprintf(stderr, "%s\n", usb_strerror()); |
845 | return NULL; |
846 | } |
847 | |
848 | ret = usb_set_configuration(handle, 1); |
849 | if (ret != 0) { |
850 | fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n", |
851 | bus->dirname, dev->filename); |
726b85c8 |
852 | fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); |
8c8e818c |
853 | return NULL; |
854 | } |
855 | |
856 | ret = usb_claim_interface(handle, 0); |
857 | if (ret != 0) { |
858 | fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n", |
859 | bus->dirname, dev->filename); |
860 | fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); |
861 | return NULL; |
862 | } |
863 | |
864 | return handle; |
865 | } |
866 | |
867 | static void release_device(struct usb_dev_handle *device) |
868 | { |
869 | usb_release_interface(device, 0); |
870 | usb_close(device); |
871 | } |
872 | |
ed354cee |
873 | static void usage(const char *app_name) |
874 | { |
875 | printf("Flasher tool for MX game devices\n" |
876 | "written by Grazvydas \"notaz\" Ignotas\n"); |
877 | printf("v" VERSION " (" __DATE__ ")\n\n"); |
878 | printf("Usage:\n" |
c9d375d5 |
879 | "%s [-i] [-g] [-e] [-r [file]] [-w <file>] ...\n" |
ed354cee |
880 | " -i print some info about connected device\n" |
881 | " -g print some info about game ROM inside device\n" |
c9d375d5 |
882 | " -e[1] erase whole flash ROM in device, '1' uses different erase method\n" |
95122097 |
883 | " -m[1-3] set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n" |
c9d375d5 |
884 | " -f skip file check\n" |
ed354cee |
885 | " -r [file] copy game image from device to file; can autodetect filename\n" |
c9d375d5 |
886 | " -w <file> write file to device; also does erase\n" |
887 | " -sr [file] read save RAM to file\n" |
888 | " -sw <file> write save RAM file to device\n" |
889 | " -sc clear save RAM\n" |
890 | " -v with -w or -sw: verify written file\n", |
ed354cee |
891 | app_name); |
892 | } |
893 | |
8c8e818c |
894 | int main(int argc, char *argv[]) |
895 | { |
c9d375d5 |
896 | char *r_fname = NULL, *w_fname = NULL, *sr_fname = NULL, *sw_fname = NULL; |
897 | void *r_fdata = NULL, *w_fdata = NULL, *sr_fdata = NULL, *sw_fdata = NULL; |
898 | int do_read_ram = 0, do_clear_ram = 0, do_verify = 0, do_check = 1; |
95122097 |
899 | int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0; |
c9d375d5 |
900 | int erase_method = 0, do_erase_size = 0; |
901 | int w_fsize = 0, sw_fsize = 0; |
8c8e818c |
902 | struct usb_dev_handle *device; |
c9d375d5 |
903 | char fname_buff[65]; |
ed354cee |
904 | int i, ret = 0; |
905 | |
906 | for (i = 1; i < argc; i++) |
907 | { |
908 | if (argv[i][0] != '-') |
909 | break; |
910 | |
911 | switch (argv[i][1]) { |
912 | case 'i': |
913 | pr_dev_info = 1; |
914 | break; |
915 | case 'g': |
916 | pr_rom_info = 1; |
917 | break; |
918 | case 'e': |
919 | do_erase_size = 0x400000; |
c9d375d5 |
920 | if (argv[i][2] == '1') |
921 | erase_method = 1; |
ed354cee |
922 | break; |
923 | case 'f': |
c9d375d5 |
924 | do_check = 0; |
ed354cee |
925 | break; |
926 | case 'v': |
927 | do_verify = 1; |
928 | break; |
95122097 |
929 | case 'm': |
930 | mx_mode = argv[i][2]; |
931 | break; |
ed354cee |
932 | case 'r': |
933 | do_read = 1; |
c9d375d5 |
934 | if (argv[i+1] && argv[i+1][0] != '-') |
ed354cee |
935 | r_fname = argv[++i]; |
936 | break; |
937 | case 'w': |
c9d375d5 |
938 | if (argv[i+1] && argv[i+1][0] != '-') |
ed354cee |
939 | w_fname = argv[++i]; |
940 | else |
941 | goto breakloop; |
942 | break; |
c9d375d5 |
943 | case 's': |
944 | switch (argv[i][2]) { |
945 | case 'r': |
946 | do_read_ram = 1; |
947 | if (argv[i+1] && argv[i+1][0] != '-') |
948 | sr_fname = argv[++i]; |
949 | break; |
950 | case 'w': |
951 | if (argv[i+1] && argv[i+1][0] != '-') |
952 | sw_fname = argv[++i]; |
953 | else |
954 | goto breakloop; |
955 | break; |
956 | case 'c': |
957 | do_clear_ram = 1; |
958 | break; |
959 | default: |
baaf865c |
960 | goto breakloop; |
c9d375d5 |
961 | } |
baaf865c |
962 | break; |
ed354cee |
963 | default: |
964 | goto breakloop; |
965 | } |
966 | } |
967 | |
968 | breakloop: |
969 | if (i <= 1 || i < argc) { |
970 | usage(argv[0]); |
971 | return 1; |
972 | } |
973 | |
c9d375d5 |
974 | /* preparations */ |
ed354cee |
975 | if (w_fname != NULL) { |
c9d375d5 |
976 | /* check extension */ |
977 | ret = strlen(w_fname); |
978 | if (do_check && (w_fname[ret - 4] == '.' || w_fname[ret - 3] == '.' || |
979 | w_fname[ret - 2] == '.') && |
980 | strcasecmp(&w_fname[ret - 4], ".gen") != 0 && |
981 | strcasecmp(&w_fname[ret - 4], ".bin") != 0) { |
982 | fprintf(stderr, "\"%s\" doesn't look like a game ROM, aborting " |
983 | "(use -f to disable this check)\n", w_fname); |
ed354cee |
984 | return 1; |
985 | } |
986 | |
c9d375d5 |
987 | ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000); |
988 | if (ret < 0) |
ed354cee |
989 | return 1; |
ed354cee |
990 | |
c9d375d5 |
991 | if (do_erase_size < w_fsize) |
992 | do_erase_size = w_fsize; |
993 | } |
994 | if (sw_fname != NULL) { |
92cfb386 |
995 | ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2); |
c9d375d5 |
996 | if (ret < 0) |
ed354cee |
997 | return 1; |
c9d375d5 |
998 | } |
999 | if (sw_fdata != NULL || do_clear_ram) { |
92cfb386 |
1000 | if (sw_fsize < 0x8000*2) { |
1001 | sw_fdata = realloc(sw_fdata, 0x8000*2); |
c9d375d5 |
1002 | if (sw_fdata == NULL) { |
1003 | fprintf(stderr, "low mem\n"); |
1004 | return 1; |
1005 | } |
92cfb386 |
1006 | memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize); |
ed354cee |
1007 | } |
92cfb386 |
1008 | sw_fsize = 0x8000*2; |
c9d375d5 |
1009 | } |
1010 | if (w_fname == NULL && sw_fname == NULL && do_verify) { |
1011 | fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n"); |
ed354cee |
1012 | do_verify = 0; |
1013 | } |
8c8e818c |
1014 | |
c9d375d5 |
1015 | /* init */ |
8c8e818c |
1016 | usb_init(); |
1017 | |
1018 | device = get_device(); |
1019 | if (device == NULL) |
1020 | return 1; |
1021 | |
c9d375d5 |
1022 | /* info */ |
ed354cee |
1023 | if (pr_dev_info) { |
1024 | ret = print_device_info(device); |
1025 | if (ret < 0) |
1026 | goto end; |
1027 | } |
726b85c8 |
1028 | |
ed354cee |
1029 | if (pr_rom_info) { |
1030 | ret = print_game_info(device); |
1031 | if (ret < 0) |
1032 | goto end; |
1033 | } |
8c8e818c |
1034 | |
95122097 |
1035 | /* set mode */ |
1036 | if (mx_mode || w_fsize > 0x200000) { |
1037 | if (mx_mode == 0) |
1038 | mx_mode = '3'; |
1039 | printf("MX mode set to "); |
1040 | switch (mx_mode) { |
1041 | case '1': |
1042 | printf("2M with RAM.\n"); |
1043 | mx_mode = C_MODE_2M_RAM; |
1044 | break; |
1045 | case '2': |
1046 | printf("4M, no RAM.\n"); |
1047 | mx_mode = C_MODE_4M_NORAM; |
1048 | break; |
1049 | default: |
1050 | printf("4M with RAM.\n"); |
1051 | mx_mode = C_MODE_4M_RAM; |
1052 | break; |
1053 | } |
1054 | set_ram_mode(device, mx_mode); |
1055 | } |
1056 | |
ed354cee |
1057 | /* erase */ |
1058 | if (do_erase_size != 0) { |
1059 | if (erase_method) |
1060 | ret = erase_all(device, do_erase_size); |
1061 | else |
1062 | ret = erase_seq(device, do_erase_size); |
1063 | if (ret < 0) |
1064 | goto end; |
1065 | } |
fb4ee110 |
1066 | |
c9d375d5 |
1067 | /* write flash */ |
ed354cee |
1068 | if (w_fdata != NULL) { |
1069 | char *p; |
fb4ee110 |
1070 | |
c9d375d5 |
1071 | ret = read_write_rom(device, 0, w_fdata, w_fsize, 1); |
ed354cee |
1072 | if (ret < 0) |
1073 | goto end; |
fb4ee110 |
1074 | |
ed354cee |
1075 | p = strrchr(w_fname, '/'); |
c9d375d5 |
1076 | p = (p == NULL) ? w_fname : p + 1; |
6ddaf67a |
1077 | |
ed354cee |
1078 | ret = write_filename(device, p, FILENAME_ROM0); |
1079 | if (ret < 0) |
1080 | fprintf(stderr, "warning: failed to save ROM filename\n"); |
1081 | } |
6ddaf67a |
1082 | |
c9d375d5 |
1083 | /* write ram */ |
1084 | if (sw_fdata != NULL) { |
1085 | char *p, *t; |
1086 | |
1087 | ret = read_write_ram(device, sw_fdata, sw_fsize, 1); |
1088 | if (ret < 0) |
1089 | goto end; |
1090 | |
1091 | memset(fname_buff, 0, sizeof(fname_buff)); |
1092 | p = fname_buff; |
1093 | if (sw_fname != NULL) { |
1094 | p = strrchr(sw_fname, '/'); |
1095 | p = (p == NULL) ? sw_fname : p + 1; |
1096 | } else if (w_fname != NULL) { |
1097 | t = strrchr(w_fname, '/'); |
1098 | t = (t == NULL) ? w_fname : t + 1; |
1099 | |
1100 | strncpy(fname_buff, t, sizeof(fname_buff)); |
1101 | fname_buff[sizeof(fname_buff) - 1] = 0; |
1102 | ret = strlen(fname_buff); |
1103 | if (ret > 4 && fname_buff[ret - 4] == '.') |
1104 | strcpy(&fname_buff[ret - 4], ".srm"); |
1105 | } |
1106 | |
1107 | ret = write_filename(device, p, FILENAME_RAM); |
1108 | if (ret < 0) |
1109 | fprintf(stderr, "warning: failed to save RAM filename\n"); |
1110 | } |
1111 | |
1112 | /* read flash */ |
ed354cee |
1113 | if (do_read && r_fname == NULL) { |
c9d375d5 |
1114 | ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0); |
ed354cee |
1115 | if (ret < 0) |
1116 | return ret; |
c9d375d5 |
1117 | r_fname = fname_buff; |
ed354cee |
1118 | if (r_fname[0] == 0) |
1119 | r_fname = "rom.gen"; |
6ddaf67a |
1120 | } |
1121 | |
ed354cee |
1122 | if (r_fname != NULL || do_verify) { |
1123 | r_fdata = malloc(0x400000); |
1124 | if (r_fdata == NULL) { |
1125 | fprintf(stderr, "low mem\n"); |
1126 | goto end; |
1127 | } |
1128 | |
1129 | ret = read_write_rom(device, 0, r_fdata, 0x400000, 0); |
1130 | if (ret < 0) |
1131 | goto end; |
1132 | } |
1133 | |
c9d375d5 |
1134 | if (r_fname != NULL) |
1135 | write_file(r_fname, r_fdata, 0x400000); |
1136 | |
1137 | /* read ram */ |
1138 | if (do_read_ram && sr_fname == NULL) { |
1139 | ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_RAM); |
1140 | if (ret < 0) |
1141 | return ret; |
1142 | sr_fname = fname_buff; |
1143 | if (sr_fname[0] == 0) |
1144 | sr_fname = "rom.srm"; |
ed354cee |
1145 | } |
1146 | |
c9d375d5 |
1147 | if (sr_fname != NULL || do_verify) { |
92cfb386 |
1148 | sr_fdata = malloc(0x8000*2); |
c9d375d5 |
1149 | if (sr_fdata == NULL) { |
1150 | fprintf(stderr, "low mem\n"); |
ed354cee |
1151 | goto end; |
1152 | } |
c9d375d5 |
1153 | |
92cfb386 |
1154 | ret = read_write_ram(device, sr_fdata, 0x8000*2, 0); |
c9d375d5 |
1155 | if (ret < 0) |
1156 | goto end; |
1157 | } |
1158 | |
1159 | if (sr_fname != NULL) |
92cfb386 |
1160 | write_file(sr_fname, sr_fdata, 0x8000*2); |
c9d375d5 |
1161 | |
1162 | /* verify */ |
1163 | if (do_verify && w_fdata != NULL && r_fdata != NULL) { |
1164 | ret = memcmp(w_fdata, r_fdata, w_fsize); |
1165 | if (ret == 0) |
1166 | printf("flash verification passed.\n"); |
1167 | else |
1168 | printf("flash verification FAILED!\n"); |
1169 | } |
1170 | |
1171 | if (do_verify && sw_fdata != NULL && sr_fdata != NULL) { |
92cfb386 |
1172 | ret = memcmp(sw_fdata, sr_fdata, 0x8000*2); |
c9d375d5 |
1173 | if (ret == 0) |
1174 | printf("RAM verification passed.\n"); |
ed354cee |
1175 | else |
c9d375d5 |
1176 | printf("RAM verification FAILED!\n"); |
ed354cee |
1177 | } |
8c8e818c |
1178 | |
c9d375d5 |
1179 | printf("all done.\n"); |
1180 | ret = 0; |
1181 | |
726b85c8 |
1182 | end: |
ed354cee |
1183 | if (w_fdata != NULL) |
1184 | free(w_fdata); |
1185 | if (r_fdata != NULL) |
1186 | free(r_fdata); |
1187 | |
8c8e818c |
1188 | release_device(device); |
1189 | |
726b85c8 |
1190 | return ret; |
8c8e818c |
1191 | } |
1192 | |