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