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