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